diff options
Diffstat (limited to 'drivers/cpufreq/cppc_cpufreq.c')
-rw-r--r-- | drivers/cpufreq/cppc_cpufreq.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index a9d3eec32795..30f302149730 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c | |||
@@ -296,10 +296,62 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) | |||
296 | return ret; | 296 | return ret; |
297 | } | 297 | } |
298 | 298 | ||
299 | static inline u64 get_delta(u64 t1, u64 t0) | ||
300 | { | ||
301 | if (t1 > t0 || t0 > ~(u32)0) | ||
302 | return t1 - t0; | ||
303 | |||
304 | return (u32)t1 - (u32)t0; | ||
305 | } | ||
306 | |||
307 | static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu, | ||
308 | struct cppc_perf_fb_ctrs fb_ctrs_t0, | ||
309 | struct cppc_perf_fb_ctrs fb_ctrs_t1) | ||
310 | { | ||
311 | u64 delta_reference, delta_delivered; | ||
312 | u64 reference_perf, delivered_perf; | ||
313 | |||
314 | reference_perf = fb_ctrs_t0.reference_perf; | ||
315 | |||
316 | delta_reference = get_delta(fb_ctrs_t1.reference, | ||
317 | fb_ctrs_t0.reference); | ||
318 | delta_delivered = get_delta(fb_ctrs_t1.delivered, | ||
319 | fb_ctrs_t0.delivered); | ||
320 | |||
321 | /* Check to avoid divide-by zero */ | ||
322 | if (delta_reference || delta_delivered) | ||
323 | delivered_perf = (reference_perf * delta_delivered) / | ||
324 | delta_reference; | ||
325 | else | ||
326 | delivered_perf = cpu->perf_ctrls.desired_perf; | ||
327 | |||
328 | return cppc_cpufreq_perf_to_khz(cpu, delivered_perf); | ||
329 | } | ||
330 | |||
331 | static unsigned int cppc_cpufreq_get_rate(unsigned int cpunum) | ||
332 | { | ||
333 | struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0}; | ||
334 | struct cppc_cpudata *cpu = all_cpu_data[cpunum]; | ||
335 | int ret; | ||
336 | |||
337 | ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t0); | ||
338 | if (ret) | ||
339 | return ret; | ||
340 | |||
341 | udelay(2); /* 2usec delay between sampling */ | ||
342 | |||
343 | ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t1); | ||
344 | if (ret) | ||
345 | return ret; | ||
346 | |||
347 | return cppc_get_rate_from_fbctrs(cpu, fb_ctrs_t0, fb_ctrs_t1); | ||
348 | } | ||
349 | |||
299 | static struct cpufreq_driver cppc_cpufreq_driver = { | 350 | static struct cpufreq_driver cppc_cpufreq_driver = { |
300 | .flags = CPUFREQ_CONST_LOOPS, | 351 | .flags = CPUFREQ_CONST_LOOPS, |
301 | .verify = cppc_verify_policy, | 352 | .verify = cppc_verify_policy, |
302 | .target = cppc_cpufreq_set_target, | 353 | .target = cppc_cpufreq_set_target, |
354 | .get = cppc_cpufreq_get_rate, | ||
303 | .init = cppc_cpufreq_cpu_init, | 355 | .init = cppc_cpufreq_cpu_init, |
304 | .stop_cpu = cppc_cpufreq_stop_cpu, | 356 | .stop_cpu = cppc_cpufreq_stop_cpu, |
305 | .name = "cppc_cpufreq", | 357 | .name = "cppc_cpufreq", |