Commit 46cecc0b authored by Leonard Crestez's avatar Leonard Crestez Committed by Chanwoo Choi

PM / devfreq: Introduce get_freq_range helper

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: default avatarLeonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: default avatarMatthias Kaehlcke <mka@chromium.org>
Reviewed-by: default avatarChanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: default avatarChanwoo Choi <cw00.choi@samsung.com>
parent e7cc792d
...@@ -98,6 +98,47 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq) ...@@ -98,6 +98,47 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
return max_freq; return max_freq;
} }
/**
* 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_get_freq_level() - Lookup freq_table for the frequency
* @devfreq: the devfreq instance * @devfreq: the devfreq instance
...@@ -351,16 +392,7 @@ int update_devfreq(struct devfreq *devfreq) ...@@ -351,16 +392,7 @@ int update_devfreq(struct devfreq *devfreq)
err = devfreq->governor->get_target_freq(devfreq, &freq); err = devfreq->governor->get_target_freq(devfreq, &freq);
if (err) if (err)
return err; return err;
get_freq_range(devfreq, &min_freq, &max_freq);
/*
* 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);
if (freq < min_freq) { if (freq < min_freq) {
freq = min_freq; freq = min_freq;
...@@ -1312,36 +1344,24 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr, ...@@ -1312,36 +1344,24 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
return -EINVAL; return -EINVAL;
mutex_lock(&df->lock); 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; df->min_freq = value;
update_devfreq(df); update_devfreq(df);
ret = count;
unlock:
mutex_unlock(&df->lock); mutex_unlock(&df->lock);
return ret;
return count;
} }
static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr, static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct devfreq *df = to_devfreq(dev); 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, 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, ...@@ -1357,27 +1377,14 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
mutex_lock(&df->lock); mutex_lock(&df->lock);
if (value) { if (!value)
if (value < df->min_freq) { value = ULONG_MAX;
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];
}
df->max_freq = value; df->max_freq = value;
update_devfreq(df); update_devfreq(df);
ret = count;
unlock:
mutex_unlock(&df->lock); mutex_unlock(&df->lock);
return ret;
return count;
} }
static DEVICE_ATTR_RW(min_freq); static DEVICE_ATTR_RW(min_freq);
...@@ -1385,8 +1392,13 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr, ...@@ -1385,8 +1392,13 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct devfreq *df = to_devfreq(dev); 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); static DEVICE_ATTR_RW(max_freq);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment