PM / devfreq: Introduce get_freq_range helper
authorLeonard Crestez <leonard.crestez@nxp.com>
Thu, 31 Oct 2019 21:34:26 +0000 (23:34 +0200)
committerChanwoo Choi <cw00.choi@samsung.com>
Mon, 9 Dec 2019 03:19:16 +0000 (12:19 +0900)
Moving handling of min/max freq to a single function and call it from
update_devfreq and for printing min/max freq values in sysfs.

This changes the behavior of out-of-range min_freq/max_freq: clamping
is now done at evaluation time. This means that if an out-of-range
constraint is imposed by sysfs and it later becomes valid then it will
be enforced.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
drivers/devfreq/devfreq.c

index 66f0a79..65a4b6c 100644 (file)
@@ -99,6 +99,47 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
 }
 
 /**
+ * get_freq_range() - Get the current freq range
+ * @devfreq:   the devfreq instance
+ * @min_freq:  the min frequency
+ * @max_freq:  the max frequency
+ *
+ * This takes into consideration all constraints.
+ */
+static void get_freq_range(struct devfreq *devfreq,
+                          unsigned long *min_freq,
+                          unsigned long *max_freq)
+{
+       unsigned long *freq_table = devfreq->profile->freq_table;
+
+       lockdep_assert_held(&devfreq->lock);
+
+       /*
+        * Initialize minimum/maximum frequency from freq table.
+        * The devfreq drivers can initialize this in either ascending or
+        * descending order and devfreq core supports both.
+        */
+       if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
+               *min_freq = freq_table[0];
+               *max_freq = freq_table[devfreq->profile->max_state - 1];
+       } else {
+               *min_freq = freq_table[devfreq->profile->max_state - 1];
+               *max_freq = freq_table[0];
+       }
+
+       /* Apply constraints from sysfs */
+       *min_freq = max(*min_freq, devfreq->min_freq);
+       *max_freq = min(*max_freq, devfreq->max_freq);
+
+       /* Apply constraints from OPP interface */
+       *min_freq = max(*min_freq, devfreq->scaling_min_freq);
+       *max_freq = min(*max_freq, devfreq->scaling_max_freq);
+
+       if (*min_freq > *max_freq)
+               *min_freq = *max_freq;
+}
+
+/**
  * devfreq_get_freq_level() - Lookup freq_table for the frequency
  * @devfreq:   the devfreq instance
  * @freq:      the target frequency
@@ -351,16 +392,7 @@ int update_devfreq(struct devfreq *devfreq)
        err = devfreq->governor->get_target_freq(devfreq, &freq);
        if (err)
                return err;
-
-       /*
-        * Adjust the frequency with user freq, QoS and available freq.
-        *
-        * List from the highest priority
-        * max_freq
-        * min_freq
-        */
-       max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
-       min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
+       get_freq_range(devfreq, &min_freq, &max_freq);
 
        if (freq < min_freq) {
                freq = min_freq;
@@ -1312,36 +1344,24 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        mutex_lock(&df->lock);
-
-       if (value) {
-               if (value > df->max_freq) {
-                       ret = -EINVAL;
-                       goto unlock;
-               }
-       } else {
-               unsigned long *freq_table = df->profile->freq_table;
-
-               /* Get minimum frequency according to sorting order */
-               if (freq_table[0] < freq_table[df->profile->max_state - 1])
-                       value = freq_table[0];
-               else
-                       value = freq_table[df->profile->max_state - 1];
-       }
-
        df->min_freq = value;
        update_devfreq(df);
-       ret = count;
-unlock:
        mutex_unlock(&df->lock);
-       return ret;
+
+       return count;
 }
 
 static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
        struct devfreq *df = to_devfreq(dev);
+       unsigned long min_freq, max_freq;
+
+       mutex_lock(&df->lock);
+       get_freq_range(df, &min_freq, &max_freq);
+       mutex_unlock(&df->lock);
 
-       return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
+       return sprintf(buf, "%lu\n", min_freq);
 }
 
 static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
@@ -1357,27 +1377,14 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
 
        mutex_lock(&df->lock);
 
-       if (value) {
-               if (value < df->min_freq) {
-                       ret = -EINVAL;
-                       goto unlock;
-               }
-       } else {
-               unsigned long *freq_table = df->profile->freq_table;
-
-               /* Get maximum frequency according to sorting order */
-               if (freq_table[0] < freq_table[df->profile->max_state - 1])
-                       value = freq_table[df->profile->max_state - 1];
-               else
-                       value = freq_table[0];
-       }
+       if (!value)
+               value = ULONG_MAX;
 
        df->max_freq = value;
        update_devfreq(df);
-       ret = count;
-unlock:
        mutex_unlock(&df->lock);
-       return ret;
+
+       return count;
 }
 static DEVICE_ATTR_RW(min_freq);
 
@@ -1385,8 +1392,13 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
        struct devfreq *df = to_devfreq(dev);
+       unsigned long min_freq, max_freq;
+
+       mutex_lock(&df->lock);
+       get_freq_range(df, &min_freq, &max_freq);
+       mutex_unlock(&df->lock);
 
-       return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
+       return sprintf(buf, "%lu\n", max_freq);
 }
 static DEVICE_ATTR_RW(max_freq);