diff options
| author | Chanwoo Choi <cw00.choi@samsung.com> | 2017-10-22 21:32:08 -0400 |
|---|---|---|
| committer | MyungJoo Ham <myungjoo.ham@samsung.com> | 2017-10-26 04:08:40 -0400 |
| commit | f1d981eaecf8ace68ec1d15bf05f28a4887ea6fb (patch) | |
| tree | 0304a9e1ca1740a05b0bc36a06de56105a6950fb /drivers | |
| parent | 1051e2c304b5cf17d4117505985f8128c5c64fd9 (diff) | |
PM / devfreq: Use the available min/max frequency
The commit a76caf55e5b35 ("thermal: Add devfreq cooling") is able
to disable OPP as a cooling device. In result, both update_devfreq()
and {min|max}_freq_show() have to consider the 'opp->available'
status of each OPP.
So, this patch adds the 'scaling_{min|max}_freq' to struct devfreq
in order to indicate the available mininum and maximum frequency
by adjusting OPP interface such as dev_pm_opp_{disable|enable}().
The 'scaling_{min|max}_freq' are used for on both update_devfreq()
and {min|max}_freq_show().
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/devfreq/devfreq.c | 40 |
1 files changed, 32 insertions, 8 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index b6ba24e5db0d..ee3e7cee30b6 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c | |||
| @@ -28,6 +28,9 @@ | |||
| 28 | #include <linux/of.h> | 28 | #include <linux/of.h> |
| 29 | #include "governor.h" | 29 | #include "governor.h" |
| 30 | 30 | ||
| 31 | #define MAX(a,b) ((a > b) ? a : b) | ||
| 32 | #define MIN(a,b) ((a < b) ? a : b) | ||
| 33 | |||
| 31 | static struct class *devfreq_class; | 34 | static struct class *devfreq_class; |
| 32 | 35 | ||
| 33 | /* | 36 | /* |
| @@ -255,7 +258,7 @@ static int devfreq_notify_transition(struct devfreq *devfreq, | |||
| 255 | int update_devfreq(struct devfreq *devfreq) | 258 | int update_devfreq(struct devfreq *devfreq) |
| 256 | { | 259 | { |
| 257 | struct devfreq_freqs freqs; | 260 | struct devfreq_freqs freqs; |
| 258 | unsigned long freq, cur_freq; | 261 | unsigned long freq, cur_freq, min_freq, max_freq; |
| 259 | int err = 0; | 262 | int err = 0; |
| 260 | u32 flags = 0; | 263 | u32 flags = 0; |
| 261 | 264 | ||
| @@ -273,19 +276,21 @@ int update_devfreq(struct devfreq *devfreq) | |||
| 273 | return err; | 276 | return err; |
| 274 | 277 | ||
| 275 | /* | 278 | /* |
| 276 | * Adjust the frequency with user freq and QoS. | 279 | * Adjust the frequency with user freq, QoS and available freq. |
| 277 | * | 280 | * |
| 278 | * List from the highest priority | 281 | * List from the highest priority |
| 279 | * max_freq | 282 | * max_freq |
| 280 | * min_freq | 283 | * min_freq |
| 281 | */ | 284 | */ |
| 285 | max_freq = MIN(devfreq->scaling_max_freq, devfreq->max_freq); | ||
| 286 | min_freq = MAX(devfreq->scaling_min_freq, devfreq->min_freq); | ||
| 282 | 287 | ||
| 283 | if (devfreq->min_freq && freq < devfreq->min_freq) { | 288 | if (min_freq && freq < min_freq) { |
| 284 | freq = devfreq->min_freq; | 289 | freq = min_freq; |
| 285 | flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */ | 290 | flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */ |
| 286 | } | 291 | } |
| 287 | if (devfreq->max_freq && freq > devfreq->max_freq) { | 292 | if (max_freq && freq > max_freq) { |
| 288 | freq = devfreq->max_freq; | 293 | freq = max_freq; |
| 289 | flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */ | 294 | flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */ |
| 290 | } | 295 | } |
| 291 | 296 | ||
| @@ -494,6 +499,19 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type, | |||
| 494 | int ret; | 499 | int ret; |
| 495 | 500 | ||
| 496 | mutex_lock(&devfreq->lock); | 501 | mutex_lock(&devfreq->lock); |
| 502 | |||
| 503 | devfreq->scaling_min_freq = find_available_min_freq(devfreq); | ||
| 504 | if (!devfreq->scaling_min_freq) { | ||
| 505 | mutex_unlock(&devfreq->lock); | ||
| 506 | return -EINVAL; | ||
| 507 | } | ||
| 508 | |||
| 509 | devfreq->scaling_max_freq = find_available_max_freq(devfreq); | ||
| 510 | if (!devfreq->scaling_max_freq) { | ||
| 511 | mutex_unlock(&devfreq->lock); | ||
| 512 | return -EINVAL; | ||
| 513 | } | ||
| 514 | |||
| 497 | ret = update_devfreq(devfreq); | 515 | ret = update_devfreq(devfreq); |
| 498 | mutex_unlock(&devfreq->lock); | 516 | mutex_unlock(&devfreq->lock); |
| 499 | 517 | ||
| @@ -593,6 +611,7 @@ struct devfreq *devfreq_add_device(struct device *dev, | |||
| 593 | err = -EINVAL; | 611 | err = -EINVAL; |
| 594 | goto err_dev; | 612 | goto err_dev; |
| 595 | } | 613 | } |
| 614 | devfreq->scaling_min_freq = devfreq->min_freq; | ||
| 596 | 615 | ||
| 597 | devfreq->max_freq = find_available_max_freq(devfreq); | 616 | devfreq->max_freq = find_available_max_freq(devfreq); |
| 598 | if (!devfreq->max_freq) { | 617 | if (!devfreq->max_freq) { |
| @@ -600,6 +619,7 @@ struct devfreq *devfreq_add_device(struct device *dev, | |||
| 600 | err = -EINVAL; | 619 | err = -EINVAL; |
| 601 | goto err_dev; | 620 | goto err_dev; |
| 602 | } | 621 | } |
| 622 | devfreq->scaling_max_freq = devfreq->max_freq; | ||
| 603 | 623 | ||
| 604 | dev_set_name(&devfreq->dev, "devfreq%d", | 624 | dev_set_name(&devfreq->dev, "devfreq%d", |
| 605 | atomic_inc_return(&devfreq_no)); | 625 | atomic_inc_return(&devfreq_no)); |
| @@ -1127,7 +1147,9 @@ unlock: | |||
| 1127 | static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr, | 1147 | static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr, |
| 1128 | char *buf) | 1148 | char *buf) |
| 1129 | { | 1149 | { |
| 1130 | return sprintf(buf, "%lu\n", to_devfreq(dev)->min_freq); | 1150 | struct devfreq *df = to_devfreq(dev); |
| 1151 | |||
| 1152 | return sprintf(buf, "%lu\n", MAX(df->scaling_min_freq, df->min_freq)); | ||
| 1131 | } | 1153 | } |
| 1132 | 1154 | ||
| 1133 | static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, | 1155 | static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, |
| @@ -1161,7 +1183,9 @@ static DEVICE_ATTR_RW(min_freq); | |||
| 1161 | static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr, | 1183 | static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr, |
| 1162 | char *buf) | 1184 | char *buf) |
| 1163 | { | 1185 | { |
| 1164 | return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq); | 1186 | struct devfreq *df = to_devfreq(dev); |
| 1187 | |||
| 1188 | return sprintf(buf, "%lu\n", MIN(df->scaling_max_freq, df->max_freq)); | ||
| 1165 | } | 1189 | } |
| 1166 | static DEVICE_ATTR_RW(max_freq); | 1190 | static DEVICE_ATTR_RW(max_freq); |
| 1167 | 1191 | ||
