drm/nouveau: expose pstate selection per-power source in sysfs
authorBen Skeggs <bskeggs@redhat.com>
Fri, 13 Jun 2014 04:17:09 +0000 (14:17 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Sat, 9 Aug 2014 19:11:08 +0000 (05:11 +1000)
echo ac:id >> pstate # select mode when on mains power
echo dc:id >> pstate # select mode when on battery
echo id >> pstate # select mode for both

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/core/engine/device/ctrl.c
drivers/gpu/drm/nouveau/core/include/core/class.h
drivers/gpu/drm/nouveau/nouveau_sysfs.c

index 754fc1d..fb546f3 100644 (file)
@@ -40,15 +40,16 @@ nouveau_control_mthd_pstate_info(struct nouveau_object *object, u32 mthd,
                return -EINVAL;
 
        if (clk) {
-               args->count  = clk->state_nr;
-               if (clk->pwrsrc)
-                       args->ustate = clk->ustate_ac;
-               else
-                       args->ustate = clk->ustate_dc;
+               args->count = clk->state_nr;
+               args->ustate_ac = clk->ustate_ac;
+               args->ustate_dc = clk->ustate_dc;
+               args->pwrsrc = clk->pwrsrc;
                args->pstate = clk->pstate;
        } else {
-               args->count  = 0;
-               args->ustate = NV_CONTROL_PSTATE_INFO_USTATE_DISABLE;
+               args->count = 0;
+               args->ustate_ac = NV_CONTROL_PSTATE_INFO_USTATE_DISABLE;
+               args->ustate_dc = NV_CONTROL_PSTATE_INFO_USTATE_DISABLE;
+               args->pwrsrc = -ENOSYS;
                args->pstate = NV_CONTROL_PSTATE_INFO_PSTATE_UNKNOWN;
        }
 
@@ -122,11 +123,19 @@ nouveau_control_mthd_pstate_user(struct nouveau_object *object, u32 mthd,
 {
        struct nouveau_clock *clk = nouveau_clock(object);
        struct nv_control_pstate_user *args = data;
+       int ret = 0;
 
        if (size < sizeof(*args) || !clk)
                return -EINVAL;
 
-       return nouveau_clock_ustate(clk, args->state, clk->pwrsrc);
+       if (args->pwrsrc >= 0) {
+               ret |= nouveau_clock_ustate(clk, args->ustate, args->pwrsrc);
+       } else {
+               ret |= nouveau_clock_ustate(clk, args->ustate, 0);
+               ret |= nouveau_clock_ustate(clk, args->ustate, 1);
+       }
+
+       return ret;
 }
 
 struct nouveau_oclass
index e0c812b..d6fd2cb 100644 (file)
@@ -148,7 +148,9 @@ struct nv_perfctr_read {
 
 struct nv_control_pstate_info {
        u32 count; /* out: number of power states */
-       s32 ustate; /* out: current target pstate index */
+       s32 ustate_ac; /* out: target pstate index */
+       s32 ustate_dc; /* out: target pstate index */
+       s32 pwrsrc; /* out: current power source */
        u32 pstate; /* out: current pstate index */
 };
 
@@ -166,7 +168,8 @@ struct nv_control_pstate_attr {
 };
 
 struct nv_control_pstate_user {
-       s32 state; /*  in: pstate identifier */
+       s32 ustate; /*  in: pstate identifier */
+       s32 pwrsrc; /*  in: target power source */
 };
 
 /* DMA FIFO channel classes
index 75dda2b..ab5afc5 100644 (file)
@@ -68,7 +68,9 @@ nouveau_sysfs_pstate_get(struct device *d, struct device_attribute *a, char *b)
                if (i < info.count)
                        snappendf(buf, cnt, "%02x:", attr.state);
                else
-                       snappendf(buf, cnt, "--:");
+                       snappendf(buf, cnt, "%s:", info.pwrsrc == 0 ? "DC" :
+                                                  info.pwrsrc == 1 ? "AC" :
+                                                  "--");
 
                attr.index = 0;
                do {
@@ -84,9 +86,20 @@ nouveau_sysfs_pstate_get(struct device *d, struct device_attribute *a, char *b)
                        snappendf(buf, cnt, " %s", attr.unit);
                } while (attr.index);
 
-               if ((state >= 0 && info.pstate == state) ||
-                   (state <  0 && info.ustate < 0))
-                       snappendf(buf, cnt, " *");
+               if (state >= 0) {
+                       if (info.ustate_ac == state)
+                               snappendf(buf, cnt, " AC");
+                       if (info.ustate_dc == state)
+                               snappendf(buf, cnt, " DC");
+                       if (info.pstate == state)
+                               snappendf(buf, cnt, " *");
+               } else {
+                       if (info.ustate_ac < -1)
+                               snappendf(buf, cnt, " AC");
+                       if (info.ustate_dc < -1)
+                               snappendf(buf, cnt, " DC");
+               }
+
                snappendf(buf, cnt, "\n");
        }
 
@@ -98,23 +111,32 @@ nouveau_sysfs_pstate_set(struct device *d, struct device_attribute *a,
                         const char *buf, size_t count)
 {
        struct nouveau_sysfs *sysfs = nouveau_sysfs(drm_device(d));
-       struct nv_control_pstate_user args;
+       struct nv_control_pstate_user args = { .pwrsrc = -EINVAL };
        long value, ret;
        char *tmp;
 
        if ((tmp = strchr(buf, '\n')))
                *tmp = '\0';
 
+       if (!strncasecmp(buf, "dc:", 3)) {
+               args.pwrsrc = 0;
+               buf += 3;
+       } else
+       if (!strncasecmp(buf, "ac:", 3)) {
+               args.pwrsrc = 1;
+               buf += 3;
+       }
+
        if (!strcasecmp(buf, "none"))
-               args.state = NV_CONTROL_PSTATE_USER_STATE_UNKNOWN;
+               args.ustate = NV_CONTROL_PSTATE_USER_STATE_UNKNOWN;
        else
        if (!strcasecmp(buf, "auto"))
-               args.state = NV_CONTROL_PSTATE_USER_STATE_PERFMON;
+               args.ustate = NV_CONTROL_PSTATE_USER_STATE_PERFMON;
        else {
                ret = kstrtol(buf, 16, &value);
                if (ret)
                        return ret;
-               args.state = value;
+               args.ustate = value;
        }
 
        ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_USER, &args, sizeof(args));