PM / devfreq: Fix available_governor sysfs
authorChanwoo Choi <cw00.choi@samsung.com>
Tue, 31 Jan 2017 06:38:16 +0000 (15:38 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Tue, 31 Jan 2017 06:46:49 +0000 (15:46 +0900)
The devfreq using passive governor is not able to change the governor.
So, the user can not change the governor through 'available_governor' sysfs
entry. Also, the devfreq which don't use the passive governor is not able to
change to 'passive' governor on the fly.

Fixes: 996133119f57 ("PM / devfreq: Add new passive governor")
Cc: stable@vger.kernel.org
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
drivers/devfreq/devfreq.c
drivers/devfreq/governor_passive.c
include/linux/devfreq.h

index 8e5938c9c7d688f7ccd9ce46956f4dadc234925e..ade279d29f1e2b65c1db437a4a26460812f461db 100644 (file)
@@ -940,6 +940,9 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
        if (df->governor == governor) {
                ret = 0;
                goto out;
+       } else if (df->governor->immutable || governor->immutable) {
+               ret = -EINVAL;
+               goto out;
        }
 
        if (df->governor) {
@@ -969,13 +972,33 @@ static ssize_t available_governors_show(struct device *d,
                                        struct device_attribute *attr,
                                        char *buf)
 {
-       struct devfreq_governor *tmp_governor;
+       struct devfreq *df = to_devfreq(d);
        ssize_t count = 0;
 
        mutex_lock(&devfreq_list_lock);
-       list_for_each_entry(tmp_governor, &devfreq_governor_list, node)
-               count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
-                                  "%s ", tmp_governor->name);
+
+       /*
+        * The devfreq with immutable governor (e.g., passive) shows
+        * only own governor.
+        */
+       if (df->governor->immutable) {
+               count = scnprintf(&buf[count], DEVFREQ_NAME_LEN,
+                                  "%s ", df->governor_name);
+       /*
+        * The devfreq device shows the registered governor except for
+        * immutable governors such as passive governor .
+        */
+       } else {
+               struct devfreq_governor *governor;
+
+               list_for_each_entry(governor, &devfreq_governor_list, node) {
+                       if (governor->immutable)
+                               continue;
+                       count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
+                                          "%s ", governor->name);
+               }
+       }
+
        mutex_unlock(&devfreq_list_lock);
 
        /* Truncate the trailing space */
index 9ef46e2592c45616cb59471c7cb2698155b56b7e..93795b32dc09b1b0af746fc5cdfccf414ad0f209 100644 (file)
@@ -179,6 +179,7 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq,
 
 static struct devfreq_governor devfreq_passive = {
        .name = "passive",
+       .immutable = 1,
        .get_target_freq = devfreq_passive_get_target_freq,
        .event_handler = devfreq_passive_event_handler,
 };
index 2de4e2eea180d133898980f87c659f86a7fb922b..e0acb0e5243b49552480ed8cfac2d037226f4304 100644 (file)
@@ -104,6 +104,8 @@ struct devfreq_dev_profile {
  * struct devfreq_governor - Devfreq policy governor
  * @node:              list node - contains registered devfreq governors
  * @name:              Governor's name
+ * @immutable:         Immutable flag for governor. If the value is 1,
+ *                     this govenror is never changeable to other governor.
  * @get_target_freq:   Returns desired operating frequency for the device.
  *                     Basically, get_target_freq will run
  *                     devfreq_dev_profile.get_dev_status() to get the
@@ -121,6 +123,7 @@ struct devfreq_governor {
        struct list_head node;
 
        const char name[DEVFREQ_NAME_LEN];
+       const unsigned int immutable;
        int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
        int (*event_handler)(struct devfreq *devfreq,
                                unsigned int event, void *data);