Message ID | 20160914141949.27402-8-robert@sixbynine.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 14 September 2016 at 15:19, Robert Bragg <robert@sixbynine.org> wrote: > Each metric set is given a sysfs entry like: > > /sys/class/drm/card0/metrics/<guid>/id > > This allows userspace to enumerate the specific sets that are available > for the current system. The 'id' file contains an unsigned integer that > can be used to open the associated metric set via > DRM_IOCTL_I915_PERF_OPEN. The <guid> is a globally unique ID for a > specific OA unit register configuration that can be reliably used by > userspace as a key to lookup corresponding counter meta data and > normalization equations. > > The guid registry is currently maintained as part of gputop along with > the XML metric set descriptions and code generation scripts, ref: > > https://github.com/rib/gputop > > gputop-data/guids.xml > > scripts/update-guids.py > > gputop-data/oa-*.xml > > scripts/i915-perf-kernelgen.py > > $ make -C gputop-data -f Makefile.xml SYSFS=1 WHITELIST=RenderBasic > > Signed-off-by: Robert Bragg <robert@sixbynine.org> > --- > drivers/gpu/drm/i915/i915_drv.c | 5 ++++ > drivers/gpu/drm/i915/i915_drv.h | 4 +++ > drivers/gpu/drm/i915/i915_oa_hsw.c | 51 +++++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/i915/i915_oa_hsw.h | 4 +++ > drivers/gpu/drm/i915/i915_perf.c | 52 ++++++++++++++++++++++++++++++++++++++ > 5 files changed, 116 insertions(+) > > diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c > index 14f22fc..8965df2 100644 > --- a/drivers/gpu/drm/i915/i915_drv.c > +++ b/drivers/gpu/drm/i915/i915_drv.c > @@ -1125,6 +1125,9 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) > if (drm_dev_register(dev, 0) == 0) { > i915_debugfs_register(dev_priv); > i915_setup_sysfs(dev_priv); > + > + /* Depends on sysfs having been initialized */ > + i915_perf_register(dev_priv); > } else > DRM_ERROR("Failed to register driver for userspace access!\n"); > > @@ -1161,6 +1164,8 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) > acpi_video_unregister(); > intel_opregion_unregister(dev_priv); > > + i915_perf_unregister(dev_priv); > + > i915_teardown_sysfs(dev_priv); > i915_debugfs_unregister(dev_priv); > drm_dev_unregister(&dev_priv->drm); > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index 551f078..f5ddf70 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -2141,6 +2141,8 @@ struct drm_i915_private { > struct { > bool initialized; > > + struct kobject *metrics_kobj; > + > struct mutex lock; > struct list_head streams; > > @@ -3711,6 +3713,8 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine, > /* i915_perf.c */ > extern void i915_perf_init(struct drm_i915_private *dev_priv); > extern void i915_perf_fini(struct drm_i915_private *dev_priv); > +extern void i915_perf_register(struct drm_i915_private *dev_priv); > +extern void i915_perf_unregister(struct drm_i915_private *dev_priv); > > /* i915_suspend.c */ > extern int i915_save_state(struct drm_device *dev); > diff --git a/drivers/gpu/drm/i915/i915_oa_hsw.c b/drivers/gpu/drm/i915/i915_oa_hsw.c > index eb5ceca..656334d 100644 > --- a/drivers/gpu/drm/i915/i915_oa_hsw.c > +++ b/drivers/gpu/drm/i915/i915_oa_hsw.c > @@ -24,6 +24,8 @@ > * > */ > > +#include <linux/sysfs.h> > + > #include "i915_drv.h" > > enum metric_set_id { > @@ -141,3 +143,52 @@ int i915_oa_select_metric_set_hsw(struct drm_i915_private *dev_priv) > return -ENODEV; > } > } > + > +static ssize_t > +show_render_basic_id(struct device *kdev, struct device_attribute *attr, char *buf) > +{ > + return sprintf(buf, "%d\n", METRIC_SET_ID_RENDER_BASIC); > +} > + > +static struct device_attribute dev_attr_render_basic_id = { > + .attr = { .name = "id", .mode = S_IRUGO }, > + .show = show_render_basic_id, > + .store = NULL, > +}; > + > +static struct attribute *attrs_render_basic[] = { > + &dev_attr_render_basic_id.attr, > + NULL, > +}; > + > +static struct attribute_group group_render_basic = { > + .name = "403d8832-1a27-4aa6-a64e-f5389ce7b212", > + .attrs = attrs_render_basic, > +}; > + > +int > +i915_perf_register_sysfs_hsw(struct drm_i915_private *dev_priv) > +{ > + int mux_len; > + int ret = 0; > + > + if (get_render_basic_mux_config(dev_priv, &mux_len)) { > + ret = sysfs_create_group(dev_priv->perf.metrics_kobj, &group_render_basic); > + if (ret) > + goto error_render_basic; > + } > + > + return 0; > + > +error_render_basic: > + return ret; > +} > + > +void > +i915_perf_unregister_sysfs_hsw(struct drm_i915_private *dev_priv) > +{ > + int mux_len; > + > + if (get_render_basic_mux_config(dev_priv, &mux_len)) > + sysfs_remove_group(dev_priv->perf.metrics_kobj, &group_render_basic); > +} > diff --git a/drivers/gpu/drm/i915/i915_oa_hsw.h b/drivers/gpu/drm/i915/i915_oa_hsw.h > index b618a1f..429a229 100644 > --- a/drivers/gpu/drm/i915/i915_oa_hsw.h > +++ b/drivers/gpu/drm/i915/i915_oa_hsw.h > @@ -31,4 +31,8 @@ extern int i915_oa_n_builtin_metric_sets_hsw; > > extern int i915_oa_select_metric_set_hsw(struct drm_i915_private *dev_priv); > > +extern int i915_perf_register_sysfs_hsw(struct drm_i915_private *dev_priv); > + > +extern void i915_perf_unregister_sysfs_hsw(struct drm_i915_private *dev_priv); > + > #endif > diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c > index 5305982..e890c38 100644 > --- a/drivers/gpu/drm/i915/i915_perf.c > +++ b/drivers/gpu/drm/i915/i915_perf.c > @@ -743,6 +743,15 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, > int format_size; > int ret; > > + /* If the sysfs metrics/ directory wasn't registered for some > + * reason then don't let userspace try their luck with config > + * IDs > + */ > + if (!dev_priv->perf.metrics_kobj) { > + DRM_ERROR("OA metrics weren't advertised via sysfs\n"); > + return -EINVAL; > + } > + > if (!(props->sample_flags & SAMPLE_OA_REPORT)) { > DRM_ERROR("Only OA report sampling supported\n"); > return -EINVAL; > @@ -1365,6 +1374,49 @@ int i915_perf_open_ioctl(struct drm_device *dev, void *data, > return ret; > } > > +void i915_perf_register(struct drm_i915_private *dev_priv) > +{ > + if (!IS_HASWELL(dev_priv)) > + return; > + > + if (!dev_priv->perf.initialized) > + return; > + > + /* To be sure we're synchronized with an attempted > + * i915_perf_open_ioctl(); considering that we register after > + * being exposed to userspace. > + */ > + mutex_lock(&dev_priv->perf.lock); > + > + dev_priv->perf.metrics_kobj = > + kobject_create_and_add("metrics", > + &dev_priv->drm.primary->kdev->kobj); > + if (!dev_priv->perf.metrics_kobj) > + goto exit; > + > + if (i915_perf_register_sysfs_hsw(dev_priv)) { > + kobject_put(dev_priv->perf.metrics_kobj); > + dev_priv->perf.metrics_kobj = NULL; > + } > + > +exit: > + mutex_unlock(&dev_priv->perf.lock); > +} > + > +void i915_perf_unregister(struct drm_i915_private *dev_priv) > +{ > + if (!IS_HASWELL(dev_priv)) > + return; Probably no need for this check. Reviewed-by: Matthew Auld <matthew.auld@intel.com>
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 14f22fc..8965df2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1125,6 +1125,9 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) if (drm_dev_register(dev, 0) == 0) { i915_debugfs_register(dev_priv); i915_setup_sysfs(dev_priv); + + /* Depends on sysfs having been initialized */ + i915_perf_register(dev_priv); } else DRM_ERROR("Failed to register driver for userspace access!\n"); @@ -1161,6 +1164,8 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) acpi_video_unregister(); intel_opregion_unregister(dev_priv); + i915_perf_unregister(dev_priv); + i915_teardown_sysfs(dev_priv); i915_debugfs_unregister(dev_priv); drm_dev_unregister(&dev_priv->drm); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 551f078..f5ddf70 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2141,6 +2141,8 @@ struct drm_i915_private { struct { bool initialized; + struct kobject *metrics_kobj; + struct mutex lock; struct list_head streams; @@ -3711,6 +3713,8 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine, /* i915_perf.c */ extern void i915_perf_init(struct drm_i915_private *dev_priv); extern void i915_perf_fini(struct drm_i915_private *dev_priv); +extern void i915_perf_register(struct drm_i915_private *dev_priv); +extern void i915_perf_unregister(struct drm_i915_private *dev_priv); /* i915_suspend.c */ extern int i915_save_state(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_oa_hsw.c b/drivers/gpu/drm/i915/i915_oa_hsw.c index eb5ceca..656334d 100644 --- a/drivers/gpu/drm/i915/i915_oa_hsw.c +++ b/drivers/gpu/drm/i915/i915_oa_hsw.c @@ -24,6 +24,8 @@ * */ +#include <linux/sysfs.h> + #include "i915_drv.h" enum metric_set_id { @@ -141,3 +143,52 @@ int i915_oa_select_metric_set_hsw(struct drm_i915_private *dev_priv) return -ENODEV; } } + +static ssize_t +show_render_basic_id(struct device *kdev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", METRIC_SET_ID_RENDER_BASIC); +} + +static struct device_attribute dev_attr_render_basic_id = { + .attr = { .name = "id", .mode = S_IRUGO }, + .show = show_render_basic_id, + .store = NULL, +}; + +static struct attribute *attrs_render_basic[] = { + &dev_attr_render_basic_id.attr, + NULL, +}; + +static struct attribute_group group_render_basic = { + .name = "403d8832-1a27-4aa6-a64e-f5389ce7b212", + .attrs = attrs_render_basic, +}; + +int +i915_perf_register_sysfs_hsw(struct drm_i915_private *dev_priv) +{ + int mux_len; + int ret = 0; + + if (get_render_basic_mux_config(dev_priv, &mux_len)) { + ret = sysfs_create_group(dev_priv->perf.metrics_kobj, &group_render_basic); + if (ret) + goto error_render_basic; + } + + return 0; + +error_render_basic: + return ret; +} + +void +i915_perf_unregister_sysfs_hsw(struct drm_i915_private *dev_priv) +{ + int mux_len; + + if (get_render_basic_mux_config(dev_priv, &mux_len)) + sysfs_remove_group(dev_priv->perf.metrics_kobj, &group_render_basic); +} diff --git a/drivers/gpu/drm/i915/i915_oa_hsw.h b/drivers/gpu/drm/i915/i915_oa_hsw.h index b618a1f..429a229 100644 --- a/drivers/gpu/drm/i915/i915_oa_hsw.h +++ b/drivers/gpu/drm/i915/i915_oa_hsw.h @@ -31,4 +31,8 @@ extern int i915_oa_n_builtin_metric_sets_hsw; extern int i915_oa_select_metric_set_hsw(struct drm_i915_private *dev_priv); +extern int i915_perf_register_sysfs_hsw(struct drm_i915_private *dev_priv); + +extern void i915_perf_unregister_sysfs_hsw(struct drm_i915_private *dev_priv); + #endif diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 5305982..e890c38 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -743,6 +743,15 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream, int format_size; int ret; + /* If the sysfs metrics/ directory wasn't registered for some + * reason then don't let userspace try their luck with config + * IDs + */ + if (!dev_priv->perf.metrics_kobj) { + DRM_ERROR("OA metrics weren't advertised via sysfs\n"); + return -EINVAL; + } + if (!(props->sample_flags & SAMPLE_OA_REPORT)) { DRM_ERROR("Only OA report sampling supported\n"); return -EINVAL; @@ -1365,6 +1374,49 @@ int i915_perf_open_ioctl(struct drm_device *dev, void *data, return ret; } +void i915_perf_register(struct drm_i915_private *dev_priv) +{ + if (!IS_HASWELL(dev_priv)) + return; + + if (!dev_priv->perf.initialized) + return; + + /* To be sure we're synchronized with an attempted + * i915_perf_open_ioctl(); considering that we register after + * being exposed to userspace. + */ + mutex_lock(&dev_priv->perf.lock); + + dev_priv->perf.metrics_kobj = + kobject_create_and_add("metrics", + &dev_priv->drm.primary->kdev->kobj); + if (!dev_priv->perf.metrics_kobj) + goto exit; + + if (i915_perf_register_sysfs_hsw(dev_priv)) { + kobject_put(dev_priv->perf.metrics_kobj); + dev_priv->perf.metrics_kobj = NULL; + } + +exit: + mutex_unlock(&dev_priv->perf.lock); +} + +void i915_perf_unregister(struct drm_i915_private *dev_priv) +{ + if (!IS_HASWELL(dev_priv)) + return; + + if (!dev_priv->perf.metrics_kobj) + return; + + i915_perf_unregister_sysfs_hsw(dev_priv); + + kobject_put(dev_priv->perf.metrics_kobj); + dev_priv->perf.metrics_kobj = NULL; +} + void i915_perf_init(struct drm_i915_private *dev_priv) { if (!IS_HASWELL(dev_priv))