diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-09-14 19:29:43 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-09-14 19:29:43 -0400 |
commit | 4184a8fc57a43faa2625988cc87031db77af9d98 (patch) | |
tree | e092eaeeb2ee7c88915dac17446d08c19ab0e5e7 | |
parent | 6ff33f3902c3b1c5d0db6b1e2c70b6d76fba357f (diff) | |
parent | 5f25f066f75a67835abb5e400471a27abd09395b (diff) |
Merge branch 'for-rafael' of https://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq into pm-devfreq
Pull devfreq updates for v4.3 from MyungJoo Ham.
* 'for-rafael' of https://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq:
PM / devfreq: Fix incorrect type issue.
PM / devfreq: tegra: Update governor to use devfreq_update_stats()
PM / devfreq: comments for get_dev_status usage updated
PM / devfreq: drop comment about thermal setting max_freq
PM / devfreq: cache the last call to get_dev_status()
PM / devfreq: Drop unlikely before IS_ERR(_OR_NULL)
PM / devfreq: exynos-ppmu: bit-wise operation bugfix.
PM / devfreq: exynos-ppmu: Update documentation to support PPMUv2
PM / devfreq: exynos-ppmu: Add the support of PPMUv2 for Exynos5433
PM / devfreq: event: Remove incorrect property in exynos-ppmu DT binding
Conflicts:
drivers/devfreq/event/exynos-ppmu.c
-rw-r--r-- | drivers/devfreq/devfreq.c | 12 | ||||
-rw-r--r-- | drivers/devfreq/event/exynos-ppmu.c | 3 | ||||
-rw-r--r-- | drivers/devfreq/governor_simpleondemand.c | 33 | ||||
-rw-r--r-- | drivers/devfreq/tegra-devfreq.c | 8 | ||||
-rw-r--r-- | include/linux/devfreq.h | 24 |
5 files changed, 54 insertions, 26 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index ca1b362d77e2..3927ed9fdbd5 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c | |||
@@ -53,7 +53,7 @@ static struct devfreq *find_device_devfreq(struct device *dev) | |||
53 | { | 53 | { |
54 | struct devfreq *tmp_devfreq; | 54 | struct devfreq *tmp_devfreq; |
55 | 55 | ||
56 | if (unlikely(IS_ERR_OR_NULL(dev))) { | 56 | if (IS_ERR_OR_NULL(dev)) { |
57 | pr_err("DEVFREQ: %s: Invalid parameters\n", __func__); | 57 | pr_err("DEVFREQ: %s: Invalid parameters\n", __func__); |
58 | return ERR_PTR(-EINVAL); | 58 | return ERR_PTR(-EINVAL); |
59 | } | 59 | } |
@@ -133,7 +133,7 @@ static struct devfreq_governor *find_devfreq_governor(const char *name) | |||
133 | { | 133 | { |
134 | struct devfreq_governor *tmp_governor; | 134 | struct devfreq_governor *tmp_governor; |
135 | 135 | ||
136 | if (unlikely(IS_ERR_OR_NULL(name))) { | 136 | if (IS_ERR_OR_NULL(name)) { |
137 | pr_err("DEVFREQ: %s: Invalid parameters\n", __func__); | 137 | pr_err("DEVFREQ: %s: Invalid parameters\n", __func__); |
138 | return ERR_PTR(-EINVAL); | 138 | return ERR_PTR(-EINVAL); |
139 | } | 139 | } |
@@ -177,10 +177,10 @@ int update_devfreq(struct devfreq *devfreq) | |||
177 | return err; | 177 | return err; |
178 | 178 | ||
179 | /* | 179 | /* |
180 | * Adjust the freuqency with user freq and QoS. | 180 | * Adjust the frequency with user freq and QoS. |
181 | * | 181 | * |
182 | * List from the highest proiority | 182 | * List from the highest priority |
183 | * max_freq (probably called by thermal when it's too hot) | 183 | * max_freq |
184 | * min_freq | 184 | * min_freq |
185 | */ | 185 | */ |
186 | 186 | ||
@@ -482,7 +482,7 @@ struct devfreq *devfreq_add_device(struct device *dev, | |||
482 | devfreq->profile->max_state * | 482 | devfreq->profile->max_state * |
483 | devfreq->profile->max_state, | 483 | devfreq->profile->max_state, |
484 | GFP_KERNEL); | 484 | GFP_KERNEL); |
485 | devfreq->time_in_state = devm_kzalloc(dev, sizeof(unsigned int) * | 485 | devfreq->time_in_state = devm_kzalloc(dev, sizeof(unsigned long) * |
486 | devfreq->profile->max_state, | 486 | devfreq->profile->max_state, |
487 | GFP_KERNEL); | 487 | GFP_KERNEL); |
488 | devfreq->last_stat_updated = jiffies; | 488 | devfreq->last_stat_updated = jiffies; |
diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c index f9901f52a225..f312485f1451 100644 --- a/drivers/devfreq/event/exynos-ppmu.c +++ b/drivers/devfreq/event/exynos-ppmu.c | |||
@@ -319,7 +319,8 @@ static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev, | |||
319 | case PPMU_PMNCNT3: | 319 | case PPMU_PMNCNT3: |
320 | pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH); | 320 | pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH); |
321 | pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW); | 321 | pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW); |
322 | load_count = (u64)((pmcnt_high & 0xff) << 32) + (u64)pmcnt_low; | 322 | load_count = ((u64)((pmcnt_high & 0xff)) << 32) |
323 | + (u64)pmcnt_low; | ||
323 | break; | 324 | break; |
324 | } | 325 | } |
325 | edata->load_count = load_count; | 326 | edata->load_count = load_count; |
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index 0720ba84ca92..ae72ba5e78df 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c | |||
@@ -21,17 +21,20 @@ | |||
21 | static int devfreq_simple_ondemand_func(struct devfreq *df, | 21 | static int devfreq_simple_ondemand_func(struct devfreq *df, |
22 | unsigned long *freq) | 22 | unsigned long *freq) |
23 | { | 23 | { |
24 | struct devfreq_dev_status stat; | 24 | int err; |
25 | int err = df->profile->get_dev_status(df->dev.parent, &stat); | 25 | struct devfreq_dev_status *stat; |
26 | unsigned long long a, b; | 26 | unsigned long long a, b; |
27 | unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; | 27 | unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; |
28 | unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; | 28 | unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; |
29 | struct devfreq_simple_ondemand_data *data = df->data; | 29 | struct devfreq_simple_ondemand_data *data = df->data; |
30 | unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; | 30 | unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; |
31 | 31 | ||
32 | err = devfreq_update_stats(df); | ||
32 | if (err) | 33 | if (err) |
33 | return err; | 34 | return err; |
34 | 35 | ||
36 | stat = &df->last_status; | ||
37 | |||
35 | if (data) { | 38 | if (data) { |
36 | if (data->upthreshold) | 39 | if (data->upthreshold) |
37 | dfso_upthreshold = data->upthreshold; | 40 | dfso_upthreshold = data->upthreshold; |
@@ -43,41 +46,41 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, | |||
43 | return -EINVAL; | 46 | return -EINVAL; |
44 | 47 | ||
45 | /* Assume MAX if it is going to be divided by zero */ | 48 | /* Assume MAX if it is going to be divided by zero */ |
46 | if (stat.total_time == 0) { | 49 | if (stat->total_time == 0) { |
47 | *freq = max; | 50 | *freq = max; |
48 | return 0; | 51 | return 0; |
49 | } | 52 | } |
50 | 53 | ||
51 | /* Prevent overflow */ | 54 | /* Prevent overflow */ |
52 | if (stat.busy_time >= (1 << 24) || stat.total_time >= (1 << 24)) { | 55 | if (stat->busy_time >= (1 << 24) || stat->total_time >= (1 << 24)) { |
53 | stat.busy_time >>= 7; | 56 | stat->busy_time >>= 7; |
54 | stat.total_time >>= 7; | 57 | stat->total_time >>= 7; |
55 | } | 58 | } |
56 | 59 | ||
57 | /* Set MAX if it's busy enough */ | 60 | /* Set MAX if it's busy enough */ |
58 | if (stat.busy_time * 100 > | 61 | if (stat->busy_time * 100 > |
59 | stat.total_time * dfso_upthreshold) { | 62 | stat->total_time * dfso_upthreshold) { |
60 | *freq = max; | 63 | *freq = max; |
61 | return 0; | 64 | return 0; |
62 | } | 65 | } |
63 | 66 | ||
64 | /* Set MAX if we do not know the initial frequency */ | 67 | /* Set MAX if we do not know the initial frequency */ |
65 | if (stat.current_frequency == 0) { | 68 | if (stat->current_frequency == 0) { |
66 | *freq = max; | 69 | *freq = max; |
67 | return 0; | 70 | return 0; |
68 | } | 71 | } |
69 | 72 | ||
70 | /* Keep the current frequency */ | 73 | /* Keep the current frequency */ |
71 | if (stat.busy_time * 100 > | 74 | if (stat->busy_time * 100 > |
72 | stat.total_time * (dfso_upthreshold - dfso_downdifferential)) { | 75 | stat->total_time * (dfso_upthreshold - dfso_downdifferential)) { |
73 | *freq = stat.current_frequency; | 76 | *freq = stat->current_frequency; |
74 | return 0; | 77 | return 0; |
75 | } | 78 | } |
76 | 79 | ||
77 | /* Set the desired frequency based on the load */ | 80 | /* Set the desired frequency based on the load */ |
78 | a = stat.busy_time; | 81 | a = stat->busy_time; |
79 | a *= stat.current_frequency; | 82 | a *= stat->current_frequency; |
80 | b = div_u64(a, stat.total_time); | 83 | b = div_u64(a, stat->total_time); |
81 | b *= 100; | 84 | b *= 100; |
82 | b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); | 85 | b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); |
83 | *freq = (unsigned long) b; | 86 | *freq = (unsigned long) b; |
diff --git a/drivers/devfreq/tegra-devfreq.c b/drivers/devfreq/tegra-devfreq.c index 13a1a6e8108c..848b93ee930f 100644 --- a/drivers/devfreq/tegra-devfreq.c +++ b/drivers/devfreq/tegra-devfreq.c | |||
@@ -541,18 +541,20 @@ static struct devfreq_dev_profile tegra_devfreq_profile = { | |||
541 | static int tegra_governor_get_target(struct devfreq *devfreq, | 541 | static int tegra_governor_get_target(struct devfreq *devfreq, |
542 | unsigned long *freq) | 542 | unsigned long *freq) |
543 | { | 543 | { |
544 | struct devfreq_dev_status stat; | 544 | struct devfreq_dev_status *stat; |
545 | struct tegra_devfreq *tegra; | 545 | struct tegra_devfreq *tegra; |
546 | struct tegra_devfreq_device *dev; | 546 | struct tegra_devfreq_device *dev; |
547 | unsigned long target_freq = 0; | 547 | unsigned long target_freq = 0; |
548 | unsigned int i; | 548 | unsigned int i; |
549 | int err; | 549 | int err; |
550 | 550 | ||
551 | err = devfreq->profile->get_dev_status(devfreq->dev.parent, &stat); | 551 | err = devfreq_update_stats(devfreq); |
552 | if (err) | 552 | if (err) |
553 | return err; | 553 | return err; |
554 | 554 | ||
555 | tegra = stat.private_data; | 555 | stat = &devfreq->last_status; |
556 | |||
557 | tegra = stat->private_data; | ||
556 | 558 | ||
557 | for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { | 559 | for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) { |
558 | dev = &tegra->devices[i]; | 560 | dev = &tegra->devices[i]; |
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index ce447f0f1bad..68030e22af35 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h | |||
@@ -65,7 +65,10 @@ struct devfreq_dev_status { | |||
65 | * The "flags" parameter's possible values are | 65 | * The "flags" parameter's possible values are |
66 | * explained above with "DEVFREQ_FLAG_*" macros. | 66 | * explained above with "DEVFREQ_FLAG_*" macros. |
67 | * @get_dev_status: The device should provide the current performance | 67 | * @get_dev_status: The device should provide the current performance |
68 | * status to devfreq, which is used by governors. | 68 | * status to devfreq. Governors are recommended not to |
69 | * use this directly. Instead, governors are recommended | ||
70 | * to use devfreq_update_stats() along with | ||
71 | * devfreq.last_status. | ||
69 | * @get_cur_freq: The device should provide the current frequency | 72 | * @get_cur_freq: The device should provide the current frequency |
70 | * at which it is operating. | 73 | * at which it is operating. |
71 | * @exit: An optional callback that is called when devfreq | 74 | * @exit: An optional callback that is called when devfreq |
@@ -161,6 +164,7 @@ struct devfreq { | |||
161 | struct delayed_work work; | 164 | struct delayed_work work; |
162 | 165 | ||
163 | unsigned long previous_freq; | 166 | unsigned long previous_freq; |
167 | struct devfreq_dev_status last_status; | ||
164 | 168 | ||
165 | void *data; /* private data for governors */ | 169 | void *data; /* private data for governors */ |
166 | 170 | ||
@@ -204,6 +208,19 @@ extern int devm_devfreq_register_opp_notifier(struct device *dev, | |||
204 | extern void devm_devfreq_unregister_opp_notifier(struct device *dev, | 208 | extern void devm_devfreq_unregister_opp_notifier(struct device *dev, |
205 | struct devfreq *devfreq); | 209 | struct devfreq *devfreq); |
206 | 210 | ||
211 | /** | ||
212 | * devfreq_update_stats() - update the last_status pointer in struct devfreq | ||
213 | * @df: the devfreq instance whose status needs updating | ||
214 | * | ||
215 | * Governors are recommended to use this function along with last_status, | ||
216 | * which allows other entities to reuse the last_status without affecting | ||
217 | * the values fetched later by governors. | ||
218 | */ | ||
219 | static inline int devfreq_update_stats(struct devfreq *df) | ||
220 | { | ||
221 | return df->profile->get_dev_status(df->dev.parent, &df->last_status); | ||
222 | } | ||
223 | |||
207 | #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) | 224 | #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) |
208 | /** | 225 | /** |
209 | * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq | 226 | * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq |
@@ -289,6 +306,11 @@ static inline void devm_devfreq_unregister_opp_notifier(struct device *dev, | |||
289 | struct devfreq *devfreq) | 306 | struct devfreq *devfreq) |
290 | { | 307 | { |
291 | } | 308 | } |
309 | |||
310 | static inline int devfreq_update_stats(struct devfreq *df) | ||
311 | { | ||
312 | return -EINVAL; | ||
313 | } | ||
292 | #endif /* CONFIG_PM_DEVFREQ */ | 314 | #endif /* CONFIG_PM_DEVFREQ */ |
293 | 315 | ||
294 | #endif /* __LINUX_DEVFREQ_H__ */ | 316 | #endif /* __LINUX_DEVFREQ_H__ */ |