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", |
