diff options
author | Dirk Brandewie <dirk.j.brandewie@intel.com> | 2013-10-21 12:20:34 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-10-25 17:46:10 -0400 |
commit | 016c815084d5b89f7c1a24b1a3a0b796512a91bc (patch) | |
tree | 7ef6c7979e3011eebd1355ebc8561fdacad84170 /drivers/cpufreq | |
parent | 9c0ebcf78fde0ffa348a95a544c6d3f2dac5af65 (diff) |
intel_pstate: Refactor driver to support CPUs with different MSR layouts
Non-core processors have a different MSR layout to commumicate P state
information. Refactor the driver to use CPU dependent accessors to
P state information.
Signed-off-by: Dirk Brandewie <dirk.j.brandewie@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r-- | drivers/cpufreq/intel_pstate.c | 144 |
1 files changed, 98 insertions, 46 deletions
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index d57648989c0b..6b37c9ff1d64 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c | |||
@@ -78,7 +78,6 @@ struct cpudata { | |||
78 | 78 | ||
79 | struct timer_list timer; | 79 | struct timer_list timer; |
80 | 80 | ||
81 | struct pstate_adjust_policy *pstate_policy; | ||
82 | struct pstate_data pstate; | 81 | struct pstate_data pstate; |
83 | struct _pid pid; | 82 | struct _pid pid; |
84 | 83 | ||
@@ -100,15 +99,21 @@ struct pstate_adjust_policy { | |||
100 | int i_gain_pct; | 99 | int i_gain_pct; |
101 | }; | 100 | }; |
102 | 101 | ||
103 | static struct pstate_adjust_policy default_policy = { | 102 | struct pstate_funcs { |
104 | .sample_rate_ms = 10, | 103 | int (*get_max)(void); |
105 | .deadband = 0, | 104 | int (*get_min)(void); |
106 | .setpoint = 97, | 105 | int (*get_turbo)(void); |
107 | .p_gain_pct = 20, | 106 | void (*set)(int pstate); |
108 | .d_gain_pct = 0, | ||
109 | .i_gain_pct = 0, | ||
110 | }; | 107 | }; |
111 | 108 | ||
109 | struct cpu_defaults { | ||
110 | struct pstate_adjust_policy pid_policy; | ||
111 | struct pstate_funcs funcs; | ||
112 | }; | ||
113 | |||
114 | static struct pstate_adjust_policy pid_params; | ||
115 | static struct pstate_funcs pstate_funcs; | ||
116 | |||
112 | struct perf_limits { | 117 | struct perf_limits { |
113 | int no_turbo; | 118 | int no_turbo; |
114 | int max_perf_pct; | 119 | int max_perf_pct; |
@@ -186,14 +191,14 @@ static signed int pid_calc(struct _pid *pid, int busy) | |||
186 | 191 | ||
187 | static inline void intel_pstate_busy_pid_reset(struct cpudata *cpu) | 192 | static inline void intel_pstate_busy_pid_reset(struct cpudata *cpu) |
188 | { | 193 | { |
189 | pid_p_gain_set(&cpu->pid, cpu->pstate_policy->p_gain_pct); | 194 | pid_p_gain_set(&cpu->pid, pid_params.p_gain_pct); |
190 | pid_d_gain_set(&cpu->pid, cpu->pstate_policy->d_gain_pct); | 195 | pid_d_gain_set(&cpu->pid, pid_params.d_gain_pct); |
191 | pid_i_gain_set(&cpu->pid, cpu->pstate_policy->i_gain_pct); | 196 | pid_i_gain_set(&cpu->pid, pid_params.i_gain_pct); |
192 | 197 | ||
193 | pid_reset(&cpu->pid, | 198 | pid_reset(&cpu->pid, |
194 | cpu->pstate_policy->setpoint, | 199 | pid_params.setpoint, |
195 | 100, | 200 | 100, |
196 | cpu->pstate_policy->deadband, | 201 | pid_params.deadband, |
197 | 0); | 202 | 0); |
198 | } | 203 | } |
199 | 204 | ||
@@ -227,12 +232,12 @@ struct pid_param { | |||
227 | }; | 232 | }; |
228 | 233 | ||
229 | static struct pid_param pid_files[] = { | 234 | static struct pid_param pid_files[] = { |
230 | {"sample_rate_ms", &default_policy.sample_rate_ms}, | 235 | {"sample_rate_ms", &pid_params.sample_rate_ms}, |
231 | {"d_gain_pct", &default_policy.d_gain_pct}, | 236 | {"d_gain_pct", &pid_params.d_gain_pct}, |
232 | {"i_gain_pct", &default_policy.i_gain_pct}, | 237 | {"i_gain_pct", &pid_params.i_gain_pct}, |
233 | {"deadband", &default_policy.deadband}, | 238 | {"deadband", &pid_params.deadband}, |
234 | {"setpoint", &default_policy.setpoint}, | 239 | {"setpoint", &pid_params.setpoint}, |
235 | {"p_gain_pct", &default_policy.p_gain_pct}, | 240 | {"p_gain_pct", &pid_params.p_gain_pct}, |
236 | {NULL, NULL} | 241 | {NULL, NULL} |
237 | }; | 242 | }; |
238 | 243 | ||
@@ -337,33 +342,60 @@ static void intel_pstate_sysfs_expose_params(void) | |||
337 | } | 342 | } |
338 | 343 | ||
339 | /************************** sysfs end ************************/ | 344 | /************************** sysfs end ************************/ |
340 | 345 | static int core_get_min_pstate(void) | |
341 | static int intel_pstate_min_pstate(void) | ||
342 | { | 346 | { |
343 | u64 value; | 347 | u64 value; |
344 | rdmsrl(MSR_PLATFORM_INFO, value); | 348 | rdmsrl(MSR_PLATFORM_INFO, value); |
345 | return (value >> 40) & 0xFF; | 349 | return (value >> 40) & 0xFF; |
346 | } | 350 | } |
347 | 351 | ||
348 | static int intel_pstate_max_pstate(void) | 352 | static int core_get_max_pstate(void) |
349 | { | 353 | { |
350 | u64 value; | 354 | u64 value; |
351 | rdmsrl(MSR_PLATFORM_INFO, value); | 355 | rdmsrl(MSR_PLATFORM_INFO, value); |
352 | return (value >> 8) & 0xFF; | 356 | return (value >> 8) & 0xFF; |
353 | } | 357 | } |
354 | 358 | ||
355 | static int intel_pstate_turbo_pstate(void) | 359 | static int core_get_turbo_pstate(void) |
356 | { | 360 | { |
357 | u64 value; | 361 | u64 value; |
358 | int nont, ret; | 362 | int nont, ret; |
359 | rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value); | 363 | rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value); |
360 | nont = intel_pstate_max_pstate(); | 364 | nont = core_get_max_pstate(); |
361 | ret = ((value) & 255); | 365 | ret = ((value) & 255); |
362 | if (ret <= nont) | 366 | if (ret <= nont) |
363 | ret = nont; | 367 | ret = nont; |
364 | return ret; | 368 | return ret; |
365 | } | 369 | } |
366 | 370 | ||
371 | static void core_set_pstate(int pstate) | ||
372 | { | ||
373 | u64 val; | ||
374 | |||
375 | val = pstate << 8; | ||
376 | if (limits.no_turbo) | ||
377 | val |= (u64)1 << 32; | ||
378 | |||
379 | wrmsrl(MSR_IA32_PERF_CTL, val); | ||
380 | } | ||
381 | |||
382 | static struct cpu_defaults core_params = { | ||
383 | .pid_policy = { | ||
384 | .sample_rate_ms = 10, | ||
385 | .deadband = 0, | ||
386 | .setpoint = 97, | ||
387 | .p_gain_pct = 20, | ||
388 | .d_gain_pct = 0, | ||
389 | .i_gain_pct = 0, | ||
390 | }, | ||
391 | .funcs = { | ||
392 | .get_max = core_get_max_pstate, | ||
393 | .get_min = core_get_min_pstate, | ||
394 | .get_turbo = core_get_turbo_pstate, | ||
395 | .set = core_set_pstate, | ||
396 | }, | ||
397 | }; | ||
398 | |||
367 | static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max) | 399 | static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max) |
368 | { | 400 | { |
369 | int max_perf = cpu->pstate.turbo_pstate; | 401 | int max_perf = cpu->pstate.turbo_pstate; |
@@ -383,7 +415,6 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max) | |||
383 | static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) | 415 | static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) |
384 | { | 416 | { |
385 | int max_perf, min_perf; | 417 | int max_perf, min_perf; |
386 | u64 val; | ||
387 | 418 | ||
388 | intel_pstate_get_min_max(cpu, &min_perf, &max_perf); | 419 | intel_pstate_get_min_max(cpu, &min_perf, &max_perf); |
389 | 420 | ||
@@ -395,11 +426,8 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate) | |||
395 | trace_cpu_frequency(pstate * 100000, cpu->cpu); | 426 | trace_cpu_frequency(pstate * 100000, cpu->cpu); |
396 | 427 | ||
397 | cpu->pstate.current_pstate = pstate; | 428 | cpu->pstate.current_pstate = pstate; |
398 | val = pstate << 8; | ||
399 | if (limits.no_turbo) | ||
400 | val |= (u64)1 << 32; | ||
401 | 429 | ||
402 | wrmsrl(MSR_IA32_PERF_CTL, val); | 430 | pstate_funcs.set(pstate); |
403 | } | 431 | } |
404 | 432 | ||
405 | static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps) | 433 | static inline void intel_pstate_pstate_increase(struct cpudata *cpu, int steps) |
@@ -421,9 +449,9 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) | |||
421 | { | 449 | { |
422 | sprintf(cpu->name, "Intel 2nd generation core"); | 450 | sprintf(cpu->name, "Intel 2nd generation core"); |
423 | 451 | ||
424 | cpu->pstate.min_pstate = intel_pstate_min_pstate(); | 452 | cpu->pstate.min_pstate = pstate_funcs.get_min(); |
425 | cpu->pstate.max_pstate = intel_pstate_max_pstate(); | 453 | cpu->pstate.max_pstate = pstate_funcs.get_max(); |
426 | cpu->pstate.turbo_pstate = intel_pstate_turbo_pstate(); | 454 | cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(); |
427 | 455 | ||
428 | /* | 456 | /* |
429 | * goto max pstate so we don't slow up boot if we are built-in if we are | 457 | * goto max pstate so we don't slow up boot if we are built-in if we are |
@@ -464,7 +492,7 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu) | |||
464 | { | 492 | { |
465 | int sample_time, delay; | 493 | int sample_time, delay; |
466 | 494 | ||
467 | sample_time = cpu->pstate_policy->sample_rate_ms; | 495 | sample_time = pid_params.sample_rate_ms; |
468 | delay = msecs_to_jiffies(sample_time); | 496 | delay = msecs_to_jiffies(sample_time); |
469 | mod_timer_pinned(&cpu->timer, jiffies + delay); | 497 | mod_timer_pinned(&cpu->timer, jiffies + delay); |
470 | } | 498 | } |
@@ -523,14 +551,14 @@ static void intel_pstate_timer_func(unsigned long __data) | |||
523 | { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&policy } | 551 | { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&policy } |
524 | 552 | ||
525 | static const struct x86_cpu_id intel_pstate_cpu_ids[] = { | 553 | static const struct x86_cpu_id intel_pstate_cpu_ids[] = { |
526 | ICPU(0x2a, default_policy), | 554 | ICPU(0x2a, core_params), |
527 | ICPU(0x2d, default_policy), | 555 | ICPU(0x2d, core_params), |
528 | ICPU(0x3a, default_policy), | 556 | ICPU(0x3a, core_params), |
529 | ICPU(0x3c, default_policy), | 557 | ICPU(0x3c, core_params), |
530 | ICPU(0x3e, default_policy), | 558 | ICPU(0x3e, core_params), |
531 | ICPU(0x3f, default_policy), | 559 | ICPU(0x3f, core_params), |
532 | ICPU(0x45, default_policy), | 560 | ICPU(0x45, core_params), |
533 | ICPU(0x46, default_policy), | 561 | ICPU(0x46, core_params), |
534 | {} | 562 | {} |
535 | }; | 563 | }; |
536 | MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); | 564 | MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); |
@@ -554,8 +582,7 @@ static int intel_pstate_init_cpu(unsigned int cpunum) | |||
554 | intel_pstate_get_cpu_pstates(cpu); | 582 | intel_pstate_get_cpu_pstates(cpu); |
555 | 583 | ||
556 | cpu->cpu = cpunum; | 584 | cpu->cpu = cpunum; |
557 | cpu->pstate_policy = | 585 | |
558 | (struct pstate_adjust_policy *)id->driver_data; | ||
559 | init_timer_deferrable(&cpu->timer); | 586 | init_timer_deferrable(&cpu->timer); |
560 | cpu->timer.function = intel_pstate_timer_func; | 587 | cpu->timer.function = intel_pstate_timer_func; |
561 | cpu->timer.data = | 588 | cpu->timer.data = |
@@ -683,9 +710,9 @@ static int intel_pstate_msrs_not_valid(void) | |||
683 | rdmsrl(MSR_IA32_APERF, aperf); | 710 | rdmsrl(MSR_IA32_APERF, aperf); |
684 | rdmsrl(MSR_IA32_MPERF, mperf); | 711 | rdmsrl(MSR_IA32_MPERF, mperf); |
685 | 712 | ||
686 | if (!intel_pstate_min_pstate() || | 713 | if (!pstate_funcs.get_max() || |
687 | !intel_pstate_max_pstate() || | 714 | !pstate_funcs.get_min() || |
688 | !intel_pstate_turbo_pstate()) | 715 | !pstate_funcs.get_turbo()) |
689 | return -ENODEV; | 716 | return -ENODEV; |
690 | 717 | ||
691 | rdmsrl(MSR_IA32_APERF, tmp); | 718 | rdmsrl(MSR_IA32_APERF, tmp); |
@@ -698,10 +725,30 @@ static int intel_pstate_msrs_not_valid(void) | |||
698 | 725 | ||
699 | return 0; | 726 | return 0; |
700 | } | 727 | } |
728 | |||
729 | void copy_pid_params(struct pstate_adjust_policy *policy) | ||
730 | { | ||
731 | pid_params.sample_rate_ms = policy->sample_rate_ms; | ||
732 | pid_params.p_gain_pct = policy->p_gain_pct; | ||
733 | pid_params.i_gain_pct = policy->i_gain_pct; | ||
734 | pid_params.d_gain_pct = policy->d_gain_pct; | ||
735 | pid_params.deadband = policy->deadband; | ||
736 | pid_params.setpoint = policy->setpoint; | ||
737 | } | ||
738 | |||
739 | void copy_cpu_funcs(struct pstate_funcs *funcs) | ||
740 | { | ||
741 | pstate_funcs.get_max = funcs->get_max; | ||
742 | pstate_funcs.get_min = funcs->get_min; | ||
743 | pstate_funcs.get_turbo = funcs->get_turbo; | ||
744 | pstate_funcs.set = funcs->set; | ||
745 | } | ||
746 | |||
701 | static int __init intel_pstate_init(void) | 747 | static int __init intel_pstate_init(void) |
702 | { | 748 | { |
703 | int cpu, rc = 0; | 749 | int cpu, rc = 0; |
704 | const struct x86_cpu_id *id; | 750 | const struct x86_cpu_id *id; |
751 | struct cpu_defaults *cpu_info; | ||
705 | 752 | ||
706 | if (no_load) | 753 | if (no_load) |
707 | return -ENODEV; | 754 | return -ENODEV; |
@@ -710,6 +757,11 @@ static int __init intel_pstate_init(void) | |||
710 | if (!id) | 757 | if (!id) |
711 | return -ENODEV; | 758 | return -ENODEV; |
712 | 759 | ||
760 | cpu_info = (struct cpu_defaults *)id->driver_data; | ||
761 | |||
762 | copy_pid_params(&cpu_info->pid_policy); | ||
763 | copy_cpu_funcs(&cpu_info->funcs); | ||
764 | |||
713 | if (intel_pstate_msrs_not_valid()) | 765 | if (intel_pstate_msrs_not_valid()) |
714 | return -ENODEV; | 766 | return -ENODEV; |
715 | 767 | ||