[Intel-gfx] [PATCH 4/9] drm/i915: add support for perf configuration queries

2019-10-09 Thread Chris Wilson
From: Lionel Landwerlin 

Listing configurations at the moment is supported only through sysfs.
This might cause issues for applications wanting to list
configurations from a container where sysfs isn't available.

This change adds a way to query the number of configurations and their
content through the i915 query uAPI.

v2: Fix sparse warnings (Lionel)
Add support to query configuration using uuid (Lionel)

v3: Fix some inconsistency in uapi header (Lionel)
Fix unlocking when not locked issue (Lionel)
Add debug messages (Lionel)

v4: Fix missing unlock (Dan)

v5: Drop lock when copying config content to userspace (Chris)

v6: Drop lock when copying config list to userspace (Chris)
Fix deadlock when calling i915_perf_get_oa_config() under
perf.metrics_lock (Lionel)
Add i915_oa_config_get() (Chris)

Signed-off-by: Lionel Landwerlin 
Reviewed-by: Chris Wilson 
---
 drivers/gpu/drm/i915/i915_perf.c  |   3 +-
 drivers/gpu/drm/i915/i915_query.c | 295 ++
 include/uapi/drm/i915_drm.h   |  62 ++-
 3 files changed, 357 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
index f087a81a6b30..d79da167b6f0 100644
--- a/drivers/gpu/drm/i915/i915_perf.c
+++ b/drivers/gpu/drm/i915/i915_perf.c
@@ -3473,8 +3473,7 @@ int i915_perf_remove_config_ioctl(struct drm_device *dev, 
void *data,
 
GEM_BUG_ON(*arg != oa_config->id);
 
-   sysfs_remove_group(perf->metrics_kobj,
-  &oa_config->sysfs_metric);
+   sysfs_remove_group(perf->metrics_kobj, &oa_config->sysfs_metric);
 
idr_remove(&perf->metrics_idr, *arg);
 
diff --git a/drivers/gpu/drm/i915/i915_query.c 
b/drivers/gpu/drm/i915/i915_query.c
index abac5042da2b..6a68ecc7bb5f 100644
--- a/drivers/gpu/drm/i915/i915_query.c
+++ b/drivers/gpu/drm/i915/i915_query.c
@@ -7,6 +7,7 @@
 #include 
 
 #include "i915_drv.h"
+#include "i915_perf.h"
 #include "i915_query.h"
 #include 
 
@@ -140,10 +141,304 @@ query_engine_info(struct drm_i915_private *i915,
return len;
 }
 
+static int can_copy_perf_config_registers_or_number(u32 user_n_regs,
+   u64 user_regs_ptr,
+   u32 kernel_n_regs)
+{
+   /*
+* We'll just put the number of registers, and won't copy the
+* register.
+*/
+   if (user_n_regs == 0)
+   return 0;
+
+   if (user_n_regs < kernel_n_regs)
+   return -EINVAL;
+
+   if (!access_ok(u64_to_user_ptr(user_regs_ptr),
+  2 * sizeof(u32) * kernel_n_regs))
+   return -EFAULT;
+
+   return 0;
+}
+
+static int copy_perf_config_registers_or_number(const struct i915_oa_reg 
*kernel_regs,
+   u32 kernel_n_regs,
+   u64 user_regs_ptr,
+   u32 *user_n_regs)
+{
+   u32 r;
+
+   if (*user_n_regs == 0) {
+   *user_n_regs = kernel_n_regs;
+   return 0;
+   }
+
+   *user_n_regs = kernel_n_regs;
+
+   for (r = 0; r < kernel_n_regs; r++) {
+   u32 __user *user_reg_ptr =
+   u64_to_user_ptr(user_regs_ptr + sizeof(u32) * r * 2);
+   u32 __user *user_val_ptr =
+   u64_to_user_ptr(user_regs_ptr + sizeof(u32) * r * 2 +
+   sizeof(u32));
+   int ret;
+
+   ret = __put_user(i915_mmio_reg_offset(kernel_regs[r].addr),
+user_reg_ptr);
+   if (ret)
+   return -EFAULT;
+
+   ret = __put_user(kernel_regs[r].value, user_val_ptr);
+   if (ret)
+   return -EFAULT;
+   }
+
+   return 0;
+}
+
+static int query_perf_config_data(struct drm_i915_private *i915,
+ struct drm_i915_query_item *query_item,
+ bool use_uuid)
+{
+   struct drm_i915_query_perf_config __user *user_query_config_ptr =
+   u64_to_user_ptr(query_item->data_ptr);
+   struct drm_i915_perf_oa_config __user *user_config_ptr =
+   u64_to_user_ptr(query_item->data_ptr +
+   sizeof(struct drm_i915_query_perf_config));
+   struct drm_i915_perf_oa_config user_config;
+   struct i915_perf *perf = &i915->perf;
+   struct i915_oa_config *oa_config;
+   char uuid[UUID_STRING_LEN + 1];
+   u64 config_id;
+   u32 flags, total_size;
+   int ret;
+
+   if (!perf->i915)
+   return -ENODEV;
+
+   total_size =
+   sizeof(struct drm_i915_query_perf_config) +
+   sizeof(struct drm_i915_perf_oa_config);
+
+   if (query_item->length == 0)
+   return total_size;
+
+   if (query_item->length < 

[Intel-gfx] [PATCH 4/9] drm/i915: add support for perf configuration queries

2019-10-08 Thread Chris Wilson
From: Lionel Landwerlin 

Listing configurations at the moment is supported only through sysfs.
This might cause issues for applications wanting to list
configurations from a container where sysfs isn't available.

This change adds a way to query the number of configurations and their
content through the i915 query uAPI.

v2: Fix sparse warnings (Lionel)
Add support to query configuration using uuid (Lionel)

v3: Fix some inconsistency in uapi header (Lionel)
Fix unlocking when not locked issue (Lionel)
Add debug messages (Lionel)

v4: Fix missing unlock (Dan)

v5: Drop lock when copying config content to userspace (Chris)

v6: Drop lock when copying config list to userspace (Chris)
Fix deadlock when calling i915_perf_get_oa_config() under
perf.metrics_lock (Lionel)
Add i915_oa_config_get() (Chris)

Signed-off-by: Lionel Landwerlin 
Reviewed-by: Chris Wilson 
---
 drivers/gpu/drm/i915/i915_perf.c  |   3 +-
 drivers/gpu/drm/i915/i915_query.c | 295 ++
 include/uapi/drm/i915_drm.h   |  62 ++-
 3 files changed, 357 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
index 5bd912c01db8..183f1ac31e36 100644
--- a/drivers/gpu/drm/i915/i915_perf.c
+++ b/drivers/gpu/drm/i915/i915_perf.c
@@ -3644,8 +3644,7 @@ int i915_perf_remove_config_ioctl(struct drm_device *dev, 
void *data,
 
GEM_BUG_ON(*arg != oa_config->id);
 
-   sysfs_remove_group(perf->metrics_kobj,
-  &oa_config->sysfs_metric);
+   sysfs_remove_group(perf->metrics_kobj, &oa_config->sysfs_metric);
 
idr_remove(&perf->metrics_idr, *arg);
 
diff --git a/drivers/gpu/drm/i915/i915_query.c 
b/drivers/gpu/drm/i915/i915_query.c
index abac5042da2b..6a68ecc7bb5f 100644
--- a/drivers/gpu/drm/i915/i915_query.c
+++ b/drivers/gpu/drm/i915/i915_query.c
@@ -7,6 +7,7 @@
 #include 
 
 #include "i915_drv.h"
+#include "i915_perf.h"
 #include "i915_query.h"
 #include 
 
@@ -140,10 +141,304 @@ query_engine_info(struct drm_i915_private *i915,
return len;
 }
 
+static int can_copy_perf_config_registers_or_number(u32 user_n_regs,
+   u64 user_regs_ptr,
+   u32 kernel_n_regs)
+{
+   /*
+* We'll just put the number of registers, and won't copy the
+* register.
+*/
+   if (user_n_regs == 0)
+   return 0;
+
+   if (user_n_regs < kernel_n_regs)
+   return -EINVAL;
+
+   if (!access_ok(u64_to_user_ptr(user_regs_ptr),
+  2 * sizeof(u32) * kernel_n_regs))
+   return -EFAULT;
+
+   return 0;
+}
+
+static int copy_perf_config_registers_or_number(const struct i915_oa_reg 
*kernel_regs,
+   u32 kernel_n_regs,
+   u64 user_regs_ptr,
+   u32 *user_n_regs)
+{
+   u32 r;
+
+   if (*user_n_regs == 0) {
+   *user_n_regs = kernel_n_regs;
+   return 0;
+   }
+
+   *user_n_regs = kernel_n_regs;
+
+   for (r = 0; r < kernel_n_regs; r++) {
+   u32 __user *user_reg_ptr =
+   u64_to_user_ptr(user_regs_ptr + sizeof(u32) * r * 2);
+   u32 __user *user_val_ptr =
+   u64_to_user_ptr(user_regs_ptr + sizeof(u32) * r * 2 +
+   sizeof(u32));
+   int ret;
+
+   ret = __put_user(i915_mmio_reg_offset(kernel_regs[r].addr),
+user_reg_ptr);
+   if (ret)
+   return -EFAULT;
+
+   ret = __put_user(kernel_regs[r].value, user_val_ptr);
+   if (ret)
+   return -EFAULT;
+   }
+
+   return 0;
+}
+
+static int query_perf_config_data(struct drm_i915_private *i915,
+ struct drm_i915_query_item *query_item,
+ bool use_uuid)
+{
+   struct drm_i915_query_perf_config __user *user_query_config_ptr =
+   u64_to_user_ptr(query_item->data_ptr);
+   struct drm_i915_perf_oa_config __user *user_config_ptr =
+   u64_to_user_ptr(query_item->data_ptr +
+   sizeof(struct drm_i915_query_perf_config));
+   struct drm_i915_perf_oa_config user_config;
+   struct i915_perf *perf = &i915->perf;
+   struct i915_oa_config *oa_config;
+   char uuid[UUID_STRING_LEN + 1];
+   u64 config_id;
+   u32 flags, total_size;
+   int ret;
+
+   if (!perf->i915)
+   return -ENODEV;
+
+   total_size =
+   sizeof(struct drm_i915_query_perf_config) +
+   sizeof(struct drm_i915_perf_oa_config);
+
+   if (query_item->length == 0)
+   return total_size;
+
+   if (query_item->length <