@@ -1172,6 +1172,9 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
* cannot run before the connectors are registered.
*/
intel_fbdev_initial_config_async(dev);
+
+ /* Depends on sysfs having been initialized */
+ i915_perf_register(dev_priv);
}
/**
@@ -1180,6 +1183,8 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
*/
static void i915_driver_unregister(struct drm_i915_private *dev_priv)
{
+ i915_perf_unregister(dev_priv);
+
i915_audio_component_cleanup(dev_priv);
intel_gpu_ips_teardown();
@@ -2115,6 +2115,8 @@ struct drm_i915_private {
struct {
bool initialized;
+ struct kobject *metrics_kobj;
+
struct mutex lock;
struct list_head streams;
@@ -3694,6 +3696,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);
@@ -24,6 +24,8 @@
*
*/
+#include <linux/sysfs.h>
+
#include "i915_drv.h"
enum metric_set_id {
@@ -130,3 +132,46 @@ 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_init_sysfs_hsw(struct drm_i915_private *dev_priv)
+{
+ int ret;
+
+ 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_deinit_sysfs_hsw(struct drm_i915_private *dev_priv)
+{
+ sysfs_remove_group(dev_priv->perf.metrics_kobj, &group_render_basic);
+}
@@ -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_init_sysfs_hsw(struct drm_i915_private *dev_priv);
+
+extern void i915_perf_deinit_sysfs_hsw(struct drm_i915_private *dev_priv);
+
#endif
@@ -731,6 +731,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;
@@ -1353,6 +1362,43 @@ int i915_perf_open_ioctl(struct drm_device *dev, void *data,
return ret;
}
+void i915_perf_register(struct drm_i915_private *dev_priv)
+{
+ 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_init_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 (!dev_priv->perf.metrics_kobj)
+ return;
+
+ i915_perf_deinit_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))