diff options
author | Matthias Kaehlcke <mka@chromium.org> | 2018-08-03 16:05:09 -0400 |
---|---|---|
committer | MyungJoo Ham <myungjoo.ham@samsung.com> | 2018-10-01 21:16:41 -0400 |
commit | df5cf4a36178c5d4f2b8b9469cb2f722e64cd102 (patch) | |
tree | 863f2447455b2e35778e3ecd0bc941b4fdcef8b1 /drivers/devfreq/devfreq.c | |
parent | d0e464205b8a1fa21357aad0bbf136500d7e688d (diff) |
PM / devfreq: Fix handling of min/max_freq == 0
Commit ab8f58ad72c4 ("PM / devfreq: Set min/max_freq when adding the
devfreq device") initializes df->min/max_freq with the min/max OPP when
the device is added. Later commit f1d981eaecf8 ("PM / devfreq: Use the
available min/max frequency") adds df->scaling_min/max_freq and the
following to the frequency adjustment code:
max_freq = MIN(devfreq->scaling_max_freq, devfreq->max_freq);
With the current handling of min/max_freq this is incorrect:
Even though df->max_freq is now initialized to a value != 0 user space
can still set it to 0, in this case max_freq would be 0 instead of
df->scaling_max_freq as intended. In consequence the frequency adjustment
is not performed:
if (max_freq && freq > max_freq) {
freq = max_freq;
To fix this set df->min/max freq to the min/max OPP in max/max_freq_store,
when the user passes a value of 0. This also prevents df->max_freq from
being set below the min OPP when df->min_freq is 0, and similar for
min_freq. Since it is now guaranteed that df->min/max_freq can't be 0 the
checks for this case can be removed.
Fixes: f1d981eaecf8 ("PM / devfreq: Use the available min/max frequency")
Signed-off-by: Matthias Kaehlcke <mka@chromium.org>
Reviewed-by: Brian Norris <briannorris@chromium.org>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Diffstat (limited to 'drivers/devfreq/devfreq.c')
-rw-r--r-- | drivers/devfreq/devfreq.c | 42 |
1 files changed, 30 insertions, 12 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 329c5e3f3338..b5e7af60723c 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c | |||
@@ -324,11 +324,11 @@ int update_devfreq(struct devfreq *devfreq) | |||
324 | max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq); | 324 | max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq); |
325 | min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq); | 325 | min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq); |
326 | 326 | ||
327 | if (min_freq && freq < min_freq) { | 327 | if (freq < min_freq) { |
328 | freq = min_freq; | 328 | freq = min_freq; |
329 | flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */ | 329 | flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */ |
330 | } | 330 | } |
331 | if (max_freq && freq > max_freq) { | 331 | if (freq > max_freq) { |
332 | freq = max_freq; | 332 | freq = max_freq; |
333 | flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */ | 333 | flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */ |
334 | } | 334 | } |
@@ -1168,17 +1168,26 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr, | |||
1168 | struct devfreq *df = to_devfreq(dev); | 1168 | struct devfreq *df = to_devfreq(dev); |
1169 | unsigned long value; | 1169 | unsigned long value; |
1170 | int ret; | 1170 | int ret; |
1171 | unsigned long max; | ||
1172 | 1171 | ||
1173 | ret = sscanf(buf, "%lu", &value); | 1172 | ret = sscanf(buf, "%lu", &value); |
1174 | if (ret != 1) | 1173 | if (ret != 1) |
1175 | return -EINVAL; | 1174 | return -EINVAL; |
1176 | 1175 | ||
1177 | mutex_lock(&df->lock); | 1176 | mutex_lock(&df->lock); |
1178 | max = df->max_freq; | 1177 | |
1179 | if (value && max && value > max) { | 1178 | if (value) { |
1180 | ret = -EINVAL; | 1179 | if (value > df->max_freq) { |
1181 | goto unlock; | 1180 | ret = -EINVAL; |
1181 | goto unlock; | ||
1182 | } | ||
1183 | } else { | ||
1184 | unsigned long *freq_table = df->profile->freq_table; | ||
1185 | |||
1186 | /* Get minimum frequency according to sorting order */ | ||
1187 | if (freq_table[0] < freq_table[df->profile->max_state - 1]) | ||
1188 | value = freq_table[0]; | ||
1189 | else | ||
1190 | value = freq_table[df->profile->max_state - 1]; | ||
1182 | } | 1191 | } |
1183 | 1192 | ||
1184 | df->min_freq = value; | 1193 | df->min_freq = value; |
@@ -1203,17 +1212,26 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, | |||
1203 | struct devfreq *df = to_devfreq(dev); | 1212 | struct devfreq *df = to_devfreq(dev); |
1204 | unsigned long value; | 1213 | unsigned long value; |
1205 | int ret; | 1214 | int ret; |
1206 | unsigned long min; | ||
1207 | 1215 | ||
1208 | ret = sscanf(buf, "%lu", &value); | 1216 | ret = sscanf(buf, "%lu", &value); |
1209 | if (ret != 1) | 1217 | if (ret != 1) |
1210 | return -EINVAL; | 1218 | return -EINVAL; |
1211 | 1219 | ||
1212 | mutex_lock(&df->lock); | 1220 | mutex_lock(&df->lock); |
1213 | min = df->min_freq; | 1221 | |
1214 | if (value && min && value < min) { | 1222 | if (value) { |
1215 | ret = -EINVAL; | 1223 | if (value < df->min_freq) { |
1216 | goto unlock; | 1224 | ret = -EINVAL; |
1225 | goto unlock; | ||
1226 | } | ||
1227 | } else { | ||
1228 | unsigned long *freq_table = df->profile->freq_table; | ||
1229 | |||
1230 | /* Get maximum frequency according to sorting order */ | ||
1231 | if (freq_table[0] < freq_table[df->profile->max_state - 1]) | ||
1232 | value = freq_table[df->profile->max_state - 1]; | ||
1233 | else | ||
1234 | value = freq_table[0]; | ||
1217 | } | 1235 | } |
1218 | 1236 | ||
1219 | df->max_freq = value; | 1237 | df->max_freq = value; |