Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PM / devfreq: cache the last call to get_dev_status()

The return value of get_dev_status() can be reused. Cache it so that
other parts of the kernel can reuse it instead of having to call the
same function again.

Cc: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Javi Merino <javi.merino@arm.com>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>

authored by

Javi Merino and committed by
MyungJoo Ham
08e75e75 9348da2f

+33 -15
+18 -15
drivers/devfreq/governor_simpleondemand.c
··· 21 21 static int devfreq_simple_ondemand_func(struct devfreq *df, 22 22 unsigned long *freq) 23 23 { 24 - struct devfreq_dev_status stat; 25 - int err = df->profile->get_dev_status(df->dev.parent, &stat); 24 + int err; 25 + struct devfreq_dev_status *stat; 26 26 unsigned long long a, b; 27 27 unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; 28 28 unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; 29 29 struct devfreq_simple_ondemand_data *data = df->data; 30 30 unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; 31 31 32 + err = devfreq_update_stats(df); 32 33 if (err) 33 34 return err; 35 + 36 + stat = &df->last_status; 34 37 35 38 if (data) { 36 39 if (data->upthreshold) ··· 46 43 return -EINVAL; 47 44 48 45 /* Assume MAX if it is going to be divided by zero */ 49 - if (stat.total_time == 0) { 46 + if (stat->total_time == 0) { 50 47 *freq = max; 51 48 return 0; 52 49 } 53 50 54 51 /* Prevent overflow */ 55 - if (stat.busy_time >= (1 << 24) || stat.total_time >= (1 << 24)) { 56 - stat.busy_time >>= 7; 57 - stat.total_time >>= 7; 52 + if (stat->busy_time >= (1 << 24) || stat->total_time >= (1 << 24)) { 53 + stat->busy_time >>= 7; 54 + stat->total_time >>= 7; 58 55 } 59 56 60 57 /* Set MAX if it's busy enough */ 61 - if (stat.busy_time * 100 > 62 - stat.total_time * dfso_upthreshold) { 58 + if (stat->busy_time * 100 > 59 + stat->total_time * dfso_upthreshold) { 63 60 *freq = max; 64 61 return 0; 65 62 } 66 63 67 64 /* Set MAX if we do not know the initial frequency */ 68 - if (stat.current_frequency == 0) { 65 + if (stat->current_frequency == 0) { 69 66 *freq = max; 70 67 return 0; 71 68 } 72 69 73 70 /* Keep the current frequency */ 74 - if (stat.busy_time * 100 > 75 - stat.total_time * (dfso_upthreshold - dfso_downdifferential)) { 76 - *freq = stat.current_frequency; 71 + if (stat->busy_time * 100 > 72 + stat->total_time * (dfso_upthreshold - dfso_downdifferential)) { 73 + *freq = stat->current_frequency; 77 74 return 0; 78 75 } 79 76 80 77 /* Set the desired frequency based on the load */ 81 - a = stat.busy_time; 82 - a *= stat.current_frequency; 83 - b = div_u64(a, stat.total_time); 78 + a = stat->busy_time; 79 + a *= stat->current_frequency; 80 + b = div_u64(a, stat->total_time); 84 81 b *= 100; 85 82 b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); 86 83 *freq = (unsigned long) b;
+15
include/linux/devfreq.h
··· 161 161 struct delayed_work work; 162 162 163 163 unsigned long previous_freq; 164 + struct devfreq_dev_status last_status; 164 165 165 166 void *data; /* private data for governors */ 166 167 ··· 204 203 struct devfreq *devfreq); 205 204 extern void devm_devfreq_unregister_opp_notifier(struct device *dev, 206 205 struct devfreq *devfreq); 206 + 207 + /** 208 + * devfreq_update_stats() - update the last_status pointer in struct devfreq 209 + * @df: the devfreq instance whose status needs updating 210 + */ 211 + static inline int devfreq_update_stats(struct devfreq *df) 212 + { 213 + return df->profile->get_dev_status(df->dev.parent, &df->last_status); 214 + } 207 215 208 216 #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) 209 217 /** ··· 298 288 static inline void devm_devfreq_unregister_opp_notifier(struct device *dev, 299 289 struct devfreq *devfreq) 300 290 { 291 + } 292 + 293 + static inline int devfreq_update_stats(struct devfreq *df) 294 + { 295 + return -EINVAL; 301 296 } 302 297 #endif /* CONFIG_PM_DEVFREQ */ 303 298