From patchwork Mon Jun 22 09:55:04 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: sourab.gupta@intel.com X-Patchwork-Id: 6654511 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 8556F9F1C1 for ; Mon, 22 Jun 2015 09:53:19 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5F374203C0 for ; Mon, 22 Jun 2015 09:53:18 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 185EB203AE for ; Mon, 22 Jun 2015 09:53:17 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A98FE6E5D5; Mon, 22 Jun 2015 02:53:16 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTP id 87B046E5D5 for ; Mon, 22 Jun 2015 02:53:14 -0700 (PDT) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga103.fm.intel.com with ESMTP; 22 Jun 2015 02:53:15 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.13,658,1427785200"; d="scan'208";a="732124315" Received: from sourabgu-desktop.iind.intel.com ([10.223.82.35]) by fmsmga001.fm.intel.com with ESMTP; 22 Jun 2015 02:53:12 -0700 From: sourab.gupta@intel.com To: intel-gfx@lists.freedesktop.org Date: Mon, 22 Jun 2015 15:25:04 +0530 Message-Id: <1434966909-4113-3-git-send-email-sourab.gupta@intel.com> X-Mailer: git-send-email 1.8.5.1 In-Reply-To: <1434966909-4113-1-git-send-email-sourab.gupta@intel.com> References: <1434966909-4113-1-git-send-email-sourab.gupta@intel.com> Cc: Insoo Woo , Peter Zijlstra , Jabin Wu , Sourab Gupta Subject: [Intel-gfx] [RFC 2/7] drm/i915: Register routines for Gen perf PMU driver X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-5.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Sourab Gupta This patch registers the new PMU driver, whose purpose is to enable data collection of non-OA counter data for all the rings, in a generic way. The patch introduces routines for this PMU driver, which also include the allocation routines for the buffer for collecting the data. Signed-off-by: Sourab Gupta --- drivers/gpu/drm/i915/i915_dma.c | 2 + drivers/gpu/drm/i915/i915_drv.h | 4 + drivers/gpu/drm/i915/i915_oa_perf.c | 225 ++++++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f12feaa..a53aa04 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -823,6 +823,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) * spinlock, upsetting lockdep checks */ INIT_LIST_HEAD(&dev_priv->profile_cmd); i915_oa_pmu_register(dev); + i915_gen_pmu_register(dev); intel_pm_setup(dev); @@ -1073,6 +1074,7 @@ int i915_driver_unload(struct drm_device *dev) return ret; } + i915_gen_pmu_unregister(dev); i915_oa_pmu_unregister(dev); intel_power_domains_fini(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b8b5455..3491584 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3305,10 +3305,14 @@ int i915_parse_cmds(struct intel_engine_cs *ring, /* i915_oa_perf.c */ #ifdef CONFIG_PERF_EVENTS extern void i915_oa_pmu_register(struct drm_device *dev); +extern void i915_gen_pmu_register(struct drm_device *dev); extern void i915_oa_pmu_unregister(struct drm_device *dev); +extern void i915_gen_pmu_unregister(struct drm_device *dev); #else static inline void i915_oa_pmu_register(struct drm_device *dev) {} +static inline void i915_gen_pmu_register(struct drm_device *dev) {} static inline void i915_oa_pmu_unregister(struct drm_device *dev) {} +static inline void i915_gen_pmu_unregister(struct drm_device *dev) {} #endif /* i915_suspend.c */ diff --git a/drivers/gpu/drm/i915/i915_oa_perf.c b/drivers/gpu/drm/i915/i915_oa_perf.c index ab419d9..e2042b6 100644 --- a/drivers/gpu/drm/i915/i915_oa_perf.c +++ b/drivers/gpu/drm/i915/i915_oa_perf.c @@ -224,6 +224,13 @@ void forward_oa_async_snapshots_work(struct work_struct *__work) mutex_unlock(&dev_priv->dev->struct_mutex); } +static void gen_pmu_flush_snapshots(struct drm_i915_private *dev_priv) +{ + WARN_ON(!dev_priv->gen_pmu.buffer.addr); + + /* TODO: routine for forwarding snapshots to userspace */ +} + static void forward_one_oa_snapshot_to_event(struct drm_i915_private *dev_priv, u8 *snapshot, struct perf_event *event) @@ -443,6 +450,33 @@ static void i915_oa_event_destroy(struct perf_event *event) intel_runtime_pm_put(dev_priv); } +static void gen_buffer_destroy(struct drm_i915_private *i915) +{ + mutex_lock(&i915->dev->struct_mutex); + + vunmap(i915->gen_pmu.buffer.addr); + i915_gem_object_ggtt_unpin(i915->gen_pmu.buffer.obj); + drm_gem_object_unreference(&i915->gen_pmu.buffer.obj->base); + + i915->gen_pmu.buffer.obj = NULL; + i915->gen_pmu.buffer.addr = NULL; + + mutex_unlock(&i915->dev->struct_mutex); +} + +static void i915_gen_event_destroy(struct perf_event *event) +{ + struct drm_i915_private *i915 = + container_of(event->pmu, typeof(*i915), gen_pmu.pmu); + + WARN_ON(event->parent); + + gen_buffer_destroy(i915); + + BUG_ON(i915->gen_pmu.exclusive_event != event); + i915->gen_pmu.exclusive_event = NULL; +} + static void *vmap_oa_buffer(struct drm_i915_gem_object *obj) { int i; @@ -599,6 +633,32 @@ unlock: return ret; } +static int init_gen_pmu_buffer(struct perf_event *event) +{ + struct drm_i915_private *dev_priv = + container_of(event->pmu, typeof(*dev_priv), gen_pmu.pmu); + struct drm_i915_gem_object *bo; + int ret; + + BUG_ON(!IS_HASWELL(dev_priv->dev) && !IS_VALLEYVIEW(dev_priv->dev) && + !IS_BROADWELL(dev_priv->dev)); + BUG_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); + BUG_ON(dev_priv->gen_pmu.buffer.obj); + + ret = alloc_oa_obj(dev_priv, &bo); + if (ret) + return ret; + + dev_priv->gen_pmu.buffer.obj = bo; + + dev_priv->gen_pmu.buffer.addr = vmap_oa_buffer(bo); + + DRM_DEBUG_DRIVER("Gen PMU Buffer initialized, vaddr = %p", + dev_priv->gen_pmu.buffer.addr); + + return 0; +} + static enum hrtimer_restart hrtimer_sample(struct hrtimer *hrtimer) { struct drm_i915_private *i915 = @@ -610,6 +670,17 @@ static enum hrtimer_restart hrtimer_sample(struct hrtimer *hrtimer) return HRTIMER_RESTART; } +static enum hrtimer_restart hrtimer_sample_gen(struct hrtimer *hrtimer) +{ + struct drm_i915_private *i915 = + container_of(hrtimer, typeof(*i915), gen_pmu.timer); + + gen_pmu_flush_snapshots(i915); + + hrtimer_forward_now(hrtimer, ns_to_ktime(PERIOD)); + return HRTIMER_RESTART; +} + static struct intel_context * lookup_context(struct drm_i915_private *dev_priv, struct file *user_filp, @@ -1156,6 +1227,115 @@ static int i915_oa_event_event_idx(struct perf_event *event) return 0; } +static int i915_gen_event_init(struct perf_event *event) +{ + struct drm_i915_private *dev_priv = + container_of(event->pmu, typeof(*dev_priv), gen_pmu.pmu); + int ret = 0; + + if (event->attr.type != event->pmu->type) + return -ENOENT; + + /* To avoid the complexity of having to accurately filter + * data and marshal to the appropriate client + * we currently only allow exclusive access */ + if (dev_priv->gen_pmu.buffer.obj) + return -EBUSY; + + /* + * We need to check for CAP_SYS_ADMIN capability as we profile all + * the running contexts + */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + mutex_lock(&dev_priv->dev->struct_mutex); + + ret = init_gen_pmu_buffer(event); + if (ret) { + mutex_unlock(&dev_priv->dev->struct_mutex); + return ret; + } + mutex_unlock(&dev_priv->dev->struct_mutex); + + BUG_ON(dev_priv->gen_pmu.exclusive_event); + dev_priv->gen_pmu.exclusive_event = event; + + event->destroy = i915_gen_event_destroy; + + return 0; +} + +static void i915_gen_event_start(struct perf_event *event, int flags) +{ + struct drm_i915_private *dev_priv = + container_of(event->pmu, typeof(*dev_priv), gen_pmu.pmu); + unsigned long lock_flags; + + spin_lock_irqsave(&dev_priv->gen_pmu.lock, lock_flags); + + dev_priv->gen_pmu.event_active = true; + + spin_unlock_irqrestore(&dev_priv->gen_pmu.lock, lock_flags); + + __hrtimer_start_range_ns(&dev_priv->gen_pmu.timer, ns_to_ktime(PERIOD), + 0, HRTIMER_MODE_REL_PINNED, 0); + + event->hw.state = 0; +} + +static void i915_gen_event_stop(struct perf_event *event, int flags) +{ + struct drm_i915_private *dev_priv = + container_of(event->pmu, typeof(*dev_priv), gen_pmu.pmu); + unsigned long lock_flags; + + spin_lock_irqsave(&dev_priv->gen_pmu.lock, lock_flags); + dev_priv->gen_pmu.event_active = false; + + spin_unlock_irqrestore(&dev_priv->gen_pmu.lock, lock_flags); + + hrtimer_cancel(&dev_priv->gen_pmu.timer); + gen_pmu_flush_snapshots(dev_priv); + + event->hw.state = PERF_HES_STOPPED; +} + +static int i915_gen_event_add(struct perf_event *event, int flags) +{ + if (flags & PERF_EF_START) + i915_gen_event_start(event, flags); + + return 0; +} + +static void i915_gen_event_del(struct perf_event *event, int flags) +{ + i915_gen_event_stop(event, flags); +} + +static void i915_gen_event_read(struct perf_event *event) +{ + struct drm_i915_private *i915 = + container_of(event->pmu, typeof(*i915), gen_pmu.pmu); + + /* XXX: What counter would be useful here? */ + local64_set(&event->count, 0); +} + +static void i915_gen_event_flush(struct perf_event *event) +{ + struct drm_i915_private *i915 = + container_of(event->pmu, typeof(*i915), gen_pmu.pmu); + + gen_pmu_flush_snapshots(i915); +} + +static int i915_gen_event_event_idx(struct perf_event *event) +{ + return 0; +} + void i915_oa_context_pin_notify(struct drm_i915_private *dev_priv, struct intel_context *context) { @@ -1283,3 +1463,48 @@ void i915_oa_pmu_unregister(struct drm_device *dev) perf_pmu_unregister(&i915->oa_pmu.pmu); i915->oa_pmu.pmu.event_init = NULL; } + +void i915_gen_pmu_register(struct drm_device *dev) +{ + struct drm_i915_private *i915 = to_i915(dev); + + if (!(IS_HASWELL(dev) || IS_VALLEYVIEW(dev) || IS_BROADWELL(dev))) + return; + + i915->gen_pmu.dummy_regs = *task_pt_regs(current); + + hrtimer_init(&i915->gen_pmu.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + i915->gen_pmu.timer.function = hrtimer_sample_gen; + + spin_lock_init(&i915->gen_pmu.lock); + + i915->gen_pmu.pmu.capabilities = PERF_PMU_CAP_IS_DEVICE; + + /* Effectively disallow opening an event with a specific pid + * since we aren't interested in processes running on the cpu... + */ + i915->gen_pmu.pmu.task_ctx_nr = perf_invalid_context; + + i915->gen_pmu.pmu.event_init = i915_gen_event_init; + i915->gen_pmu.pmu.add = i915_gen_event_add; + i915->gen_pmu.pmu.del = i915_gen_event_del; + i915->gen_pmu.pmu.start = i915_gen_event_start; + i915->gen_pmu.pmu.stop = i915_gen_event_stop; + i915->gen_pmu.pmu.read = i915_gen_event_read; + i915->gen_pmu.pmu.flush = i915_gen_event_flush; + i915->gen_pmu.pmu.event_idx = i915_gen_event_event_idx; + + if (perf_pmu_register(&i915->gen_pmu.pmu, "i915_gen", -1)) + i915->gen_pmu.pmu.event_init = NULL; +} + +void i915_gen_pmu_unregister(struct drm_device *dev) +{ + struct drm_i915_private *i915 = to_i915(dev); + + if (i915->gen_pmu.pmu.event_init == NULL) + return; + + perf_pmu_unregister(&i915->gen_pmu.pmu); + i915->gen_pmu.pmu.event_init = NULL; +}