drm/nouveau/debugfs: add copy of sysfs pstate interface ported to debugfs
authorKarol Herbst <nouveau@karolherbst.de>
Thu, 30 Jul 2015 09:53:31 +0000 (11:53 +0200)
committerBen Skeggs <bskeggs@redhat.com>
Mon, 11 Jan 2016 01:28:25 +0000 (11:28 +1000)
Signed-off-by: Karol Herbst <nouveau@karolherbst.de>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_debugfs.c

index fd4140be5472702f61b9db06ee4e39ee023ebf55..3d0dc199b2539f2b146fc26ea253c19ba6846657 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <linux/debugfs.h>
 #include <nvif/class.h>
+#include <nvif/if0001.h>
 #include "nouveau_debugfs.h"
 #include "nouveau_drm.h"
 
@@ -45,6 +46,140 @@ nouveau_debugfs_vbios_image(struct seq_file *m, void *data)
        return 0;
 }
 
+static int
+nouveau_debugfs_pstate_get(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct nouveau_debugfs *debugfs = nouveau_debugfs(node->minor->dev);
+       struct nvif_object *ctrl = &debugfs->ctrl;
+       struct nvif_control_pstate_info_v0 info = {};
+       int ret, i;
+
+       if (!debugfs)
+               return -ENODEV;
+
+       ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_INFO, &info, sizeof(info));
+       if (ret)
+               return ret;
+
+       for (i = 0; i < info.count + 1; i++) {
+               const s32 state = i < info.count ? i :
+                       NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT;
+               struct nvif_control_pstate_attr_v0 attr = {
+                       .state = state,
+                       .index = 0,
+               };
+
+               ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_ATTR,
+                               &attr, sizeof(attr));
+               if (ret)
+                       return ret;
+
+               if (i < info.count)
+                       seq_printf(m, "%02x:", attr.state);
+               else
+                       seq_printf(m, "%s:", info.pwrsrc == 0 ? "DC" :
+                                            info.pwrsrc == 1 ? "AC" : "--");
+
+               attr.index = 0;
+               do {
+                       attr.state = state;
+                       ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_ATTR,
+                                       &attr, sizeof(attr));
+                       if (ret)
+                               return ret;
+
+                       seq_printf(m, " %s %d", attr.name, attr.min);
+                       if (attr.min != attr.max)
+                               seq_printf(m, "-%d", attr.max);
+                       seq_printf(m, " %s", attr.unit);
+               } while (attr.index);
+
+               if (state >= 0) {
+                       if (info.ustate_ac == state)
+                               seq_printf(m, " AC");
+                       if (info.ustate_dc == state)
+                               seq_printf(m, " DC");
+                       if (info.pstate == state)
+                               seq_printf(m, " *");
+               } else {
+                       if (info.ustate_ac < -1)
+                               seq_printf(m, " AC");
+                       if (info.ustate_dc < -1)
+                               seq_printf(m, " DC");
+               }
+
+               seq_printf(m, "\n");
+       }
+
+       return 0;
+}
+
+static ssize_t
+nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf,
+                          size_t len, loff_t *offp)
+{
+       struct seq_file *m = file->private_data;
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct nouveau_debugfs *debugfs = nouveau_debugfs(node->minor->dev);
+       struct nvif_object *ctrl = &debugfs->ctrl;
+       struct nvif_control_pstate_user_v0 args = { .pwrsrc = -EINVAL };
+       char buf[32] = {}, *tmp, *cur = buf;
+       long value, ret;
+
+       if (!debugfs)
+               return -ENODEV;
+
+       if (len >= sizeof(buf))
+               return -EINVAL;
+
+       if (copy_from_user(buf, ubuf, len))
+               return -EFAULT;
+
+       if ((tmp = strchr(buf, '\n')))
+               *tmp = '\0';
+
+       if (!strncasecmp(cur, "dc:", 3)) {
+               args.pwrsrc = 0;
+               cur += 3;
+       } else
+       if (!strncasecmp(cur, "ac:", 3)) {
+               args.pwrsrc = 1;
+               cur += 3;
+       }
+
+       if (!strcasecmp(cur, "none"))
+               args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN;
+       else
+       if (!strcasecmp(cur, "auto"))
+               args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON;
+       else {
+               ret = kstrtol(cur, 16, &value);
+               if (ret)
+                       return ret;
+               args.ustate = value;
+       }
+
+       ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_USER, &args, sizeof(args));
+       if (ret < 0)
+               return ret;
+
+       return len;
+}
+
+static int
+nouveau_debugfs_pstate_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, nouveau_debugfs_pstate_get, inode->i_private);
+}
+
+static const struct file_operations nouveau_pstate_fops = {
+       .owner = THIS_MODULE,
+       .open = nouveau_debugfs_pstate_open,
+       .read = seq_read,
+       .write = nouveau_debugfs_pstate_set,
+};
+
 static struct drm_info_list nouveau_debugfs_list[] = {
        { "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },
 };
@@ -53,8 +188,9 @@ static struct drm_info_list nouveau_debugfs_list[] = {
 static const struct nouveau_debugfs_files {
        const char *name;
        const struct file_operations *fops;
-} nouveau_debugfs_files[] = {};
-
+} nouveau_debugfs_files[] = {
+       {"pstate", &nouveau_pstate_fops},
+};
 
 static int
 nouveau_debugfs_create_file(struct drm_minor *minor,