Re: [PATCH 24/31] drm/i915/slpc: Add debugfs support to read/write/revert the parameters

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





On 9/21/2017 8:37 PM, Michal Wajdeczko wrote:
On Tue, 19 Sep 2017 19:42:00 +0200, Sagar Arun Kamble <sagar.a.kamble@xxxxxxxxx> wrote:

This patch adds two debugfs interfaces:
1. i915_slpc_paramlist: List of all parameters that Host can configure.
   Currently listing id and description of each.
2. i915_slpc_param_ctl: This allows to change the parameters. Syntax is:
   echo "write <id> <value>" > i915_slpc_param_ctl.
   echo "read <id>" > i915_slpc_param_ctl; cat i915_slpc_param_ctl
   revert allows to set to default SLPC internal values. Syntax is:
   echo "revert <id>" > i915_slpc_param_ctl.

Added support to set/read parameters and unset the parameters which will
revert them to default SLPC internal values. Also added RPM ref. cover
around set/unset calls. Explicit SLPC reset is needed on setting/unsetting
some of the parameters.

Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@xxxxxxxxx>
---
 drivers/gpu/drm/i915/i915_debugfs.c |  19 +++++
 drivers/gpu/drm/i915/intel_slpc.c   | 158 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_slpc.h   |   6 ++
 3 files changed, 183 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index dbfe185..0a04f3d 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2352,6 +2352,23 @@ static int i915_huc_load_status_info(struct seq_file *m, void *data)
     return 0;
 }
+static int i915_slpc_paramlist_info(struct seq_file *m, void *data)

I'm little confused that part of the debugfs functionality is done here
while other part in slpc.c
Will pull them together. It was to allow new interfaces to make use of the functionality in slpc.c.

+{
+    struct drm_i915_private *dev_priv = node_to_i915(m->private);
+    int i;
+
+    if (!dev_priv->guc.slpc.active) {

intel_slpc_active() ?
yes. will update.

+        seq_puts(m, "SLPC not active\n");
+        return 0;
+    }
+
+    seq_puts(m, "Param id\tParam description\n");
+    for (i = 0; i < SLPC_MAX_PARAM; i++)
+        seq_printf(m, "%8d\t%s\n", slpc_paramlist[i].id,
+                       slpc_paramlist[i].description);

What if size of slpc_paramlist[] will be smaller than i ?
will add the size checks.

+    return 0;
+}
+
 static int i915_guc_load_status_info(struct seq_file *m, void *data)
 {
     struct drm_i915_private *dev_priv = node_to_i915(m->private);
@@ -4881,6 +4898,7 @@ static int i915_hpd_storm_ctl_open(struct inode *inode, struct file *file)
     {"i915_guc_load_err_log_dump", i915_guc_log_dump, 0, (void *)1},
     {"i915_guc_stage_pool", i915_guc_stage_pool, 0},
     {"i915_huc_load_status", i915_huc_load_status_info, 0},
+    {"i915_slpc_paramlist", i915_slpc_paramlist_info, 0},
     {"i915_frequency_info", i915_frequency_info, 0},
     {"i915_hangcheck_info", i915_hangcheck_info, 0},
     {"i915_reset_info", i915_reset_info, 0},
@@ -4944,6 +4962,7 @@ static int i915_hpd_storm_ctl_open(struct inode *inode, struct file *file)
     {"i915_dp_test_type", &i915_displayport_test_type_fops},
     {"i915_dp_test_active", &i915_displayport_test_active_fops},
     {"i915_guc_log_control", &i915_guc_log_control_fops},
+    {"i915_slpc_param_ctl", &i915_slpc_param_ctl_fops},
     {"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops},
     {"i915_ipc_status", &i915_ipc_status_fops}
 };
diff --git a/drivers/gpu/drm/i915/intel_slpc.c b/drivers/gpu/drm/i915/intel_slpc.c
index d0fd402..0c094f0 100644
--- a/drivers/gpu/drm/i915/intel_slpc.c
+++ b/drivers/gpu/drm/i915/intel_slpc.c
@@ -25,6 +25,8 @@
 #include <asm/msr-index.h>
 #include "i915_drv.h"
 #include "intel_uc.h"
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
struct slpc_param slpc_paramlist[SLPC_MAX_PARAM] = {
     {SLPC_PARAM_TASK_ENABLE_GTPERF, "Enable task GTPERF"},
@@ -684,3 +686,159 @@ void intel_slpc_disable(struct intel_slpc *slpc)
    slpc->active = false;
 }
+
+static int slpc_param_ctl_show(struct seq_file *m, void *data)
+{
+    struct drm_i915_private *dev_priv = m->private;
+    struct intel_slpc *slpc = &dev_priv->guc.slpc;
+
+    if (!slpc->active) {

intel_slpc_active() ?
yes. will update.

+        seq_puts(m, "SLPC not active\n");
+        return 0;
+    }
+
+    seq_printf(m, "%s=%u, override=%s\n",
+ slpc_paramlist[slpc->debug_param_id].description,
+            slpc->debug_param_value,
+            yesno(!!slpc->debug_param_override));
+

What if slpc->debug_param_id >= SLPC_MAX_PARAM or sizeof paramlist ?
will add the check.

+    return 0;
+}
+
+static int slpc_param_ctl_open(struct inode *inode, struct file *file)
+{
+    return single_open(file, slpc_param_ctl_show, inode->i_private);
+}
+
+static const char *read_token = "read", *write_token = "write",
+          *revert_token = "revert";
+
+/*
+ * Parse SLPC parameter control strings: (Similar to Pipe CRC handling)
+ *   command: wsp* op wsp+ param id wsp+ [value] wsp*
+ *   op: "read"/"write"/"revert"
+ *   param id: slpc_param_id
+ *   value: u32 value
+ *   wsp: (#0x20 | #0x9 | #0xA)+
+ *
+ * eg.:
+ *  "read 0"        -> read SLPC_PARAM_TASK_ENABLE_GTPERF
+ *  "write 7 500"    -> set SLPC_PARAM_GLOBAL_MIN_GT_SLICE_FREQ_MHZ to 500MHz + *  "revert 7"        -> revert SLPC_PARAM_GLOBAL_MIN_GT_SLICE_FREQ_MHZ to
+ *               default value.
+ */
+static int slpc_param_ctl_parse(char *buf, size_t len, char **op,
+                u32 *id, u32 *value)
+{
+#define MAX_WORDS 3
+    int n_words;
+    char *words[MAX_WORDS];
+    ssize_t ret;
+
+    n_words = buffer_tokenize(buf, words, MAX_WORDS);

Ha! finally found the purpose of the patch 001
Please try to keep them closer.
ok. will bring that closer. Thinking was to keep all drm/i915/slpc patches together.

+    if (!(n_words == 3) && !(n_words == 2)) {
+        DRM_DEBUG_DRIVER("tokenize failed, a command is %d words\n",
+                 MAX_WORDS);
+        return -EINVAL;
+    }
+
+    if (strcmp(words[0], read_token) && strcmp(words[0], write_token) &&
+        strcmp(words[0], revert_token)) {
+        DRM_DEBUG_DRIVER("unknown operation\n");

Please add operation word into message for easier debug
It is there. :) Did you mean "unknown operation word" ?

+        return -EINVAL;
+    }
+
+    *op = words[0];

Hmm, this will cause yet another strcmp - try to convert into OP code.
Ok. will update.

+
+    ret = kstrtou32(words[1], 0, id);
+    if (ret)
+        return ret;
+
+    if (n_words == 3) {
+        ret = kstrtou32(words[2], 0, value);
+        if (ret)
+            return ret;
+    }
+
+    return 0;

Shouldn't we return n_words-1 to easier catch any missing params?
Yes. Will add this.

+}
+
+static ssize_t slpc_param_ctl_write(struct file *file, const char __user *ubuf,
+                     size_t len, loff_t *offp)
+{
+    struct seq_file *m = file->private_data;
+    struct drm_i915_private *dev_priv = m->private;
+    struct intel_slpc *slpc = &dev_priv->guc.slpc;
+    char *tmpbuf, *op = NULL;
+    u32 id, value;
+    int ret;
+
+    if (len == 0)
+        return 0;
+
+    if (len > 40) {
+        DRM_DEBUG_DRIVER("expected <40 chars into slpc_param_ctl\n");
+        return -E2BIG;
+    }
+
+    tmpbuf = kmalloc(len + 1, GFP_KERNEL);
+    if (!tmpbuf)
+        return -ENOMEM;
+
+    if (copy_from_user(tmpbuf, ubuf, len)) {
+        ret = -EFAULT;
+        goto out;
+    }
+    tmpbuf[len] = '\0';
+
+    ret = slpc_param_ctl_parse(tmpbuf, len, &op, &id, &value);

'ret' is not checked for errors
Will check now with above return fixed.

+
+    if (id >= SLPC_MAX_PARAM) {
+        ret = -EINVAL;
+        goto out;
+    }
+
+    if (!strcmp(op, read_token)) {
+        intel_slpc_get_param(slpc, id,
+                     &slpc->debug_param_override,
+                     &slpc->debug_param_value);
+        slpc->debug_param_id = id;
+    } else if (!strcmp(op, write_token) || !strcmp(op, revert_token)) {
+        if ((id >= SLPC_PARAM_TASK_ENABLE_GTPERF) &&
+            (id <= SLPC_PARAM_TASK_DISABLE_DCC)) {
+            DRM_DEBUG_DRIVER("Tasks are not controlled by "
+                     "this interface\n");
+            ret = -EINVAL;
+            goto out;
+        }
+
+        /*
+         * After updating parameters, RESET event has to be sent to GuC
+         * SLPC for ensuring parameters take effect.
+         */
+        intel_runtime_pm_get(dev_priv);
+        if (!strcmp(op, write_token))
+            intel_slpc_set_param(slpc, id, value);
+        else if (!strcmp(op, revert_token))
+            intel_slpc_unset_param(slpc, id);
+        intel_slpc_enable(slpc);
+        intel_runtime_pm_put(dev_priv);
+    }
+
+out:
+    kfree(tmpbuf);
+    if (ret < 0)
+        return ret;
+
+    *offp += len;
+    return len;
+}
+
+const struct file_operations i915_slpc_param_ctl_fops = {
+    .owner = THIS_MODULE,
+    .open = slpc_param_ctl_open,
+    .read = seq_read,
+    .llseek = seq_lseek,
+    .release = single_release,
+    .write = slpc_param_ctl_write
+};
diff --git a/drivers/gpu/drm/i915/intel_slpc.h b/drivers/gpu/drm/i915/intel_slpc.h
index ae857d3..e49c513 100644
--- a/drivers/gpu/drm/i915/intel_slpc.h
+++ b/drivers/gpu/drm/i915/intel_slpc.h
@@ -32,6 +32,10 @@ struct intel_slpc {
     /* i915 cached SLPC frequency limits */
     u32 min_unslice_freq;
     u32 max_unslice_freq;
+
+    u32 debug_param_id;
+    u32 debug_param_value;
+    u32 debug_param_override;

Group above under 'debug' sub-struct
Sure.

 };
static inline int intel_slpc_enabled(void)
@@ -251,6 +255,8 @@ struct slpc_param {
 #define SLPC_PARAM_TASK_DISABLED 2
 #define SLPC_PARAM_TASK_UNKNOWN  3
+extern const struct file_operations i915_slpc_param_ctl_fops;
+
 /* intel_slpc.c */
 void intel_slpc_set_param(struct intel_slpc *slpc, u32 id, u32 value);
 void intel_slpc_unset_param(struct intel_slpc *slpc, u32 id);

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux