[Intel-gfx] [RFC 2/7] drm/i915: Register routines for Gen perf PMU driver
sourab.gupta at intel.com
sourab.gupta at intel.com
Mon Jun 22 02:55:04 PDT 2015
From: Sourab Gupta <sourab.gupta at intel.com>
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 <sourab.gupta at intel.com>
---
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;
+}
--
1.8.5.1
More information about the Intel-gfx
mailing list