aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2012-09-04 04:28:02 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-09-09 16:04:26 -0400
commit3dc9a633f8a65b39c5897874138027328bfb0a94 (patch)
treeec7eef140b97f5885f7e99842688eabdc8520524
parent56835e6cc053c29bf1a15a07dbeb78f219a15214 (diff)
acpi-cpufreq: Add support for modern AMD CPUs
The programming model for P-states on modern AMD CPUs is very similar to that of Intel and VIA. It makes sense to consolidate this support into one driver rather than duplicating functionality between two of them. This patch adds support for AMDs with hardware P-state control to acpi-cpufreq. Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Andre Przywara <andre.przywara@amd.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r--arch/x86/include/asm/msr-index.h2
-rw-r--r--drivers/cpufreq/Kconfig.x863
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c43
3 files changed, 41 insertions, 7 deletions
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 957ec87385af..1e1f3eb58638 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -248,6 +248,8 @@
248 248
249#define MSR_IA32_PERF_STATUS 0x00000198 249#define MSR_IA32_PERF_STATUS 0x00000198
250#define MSR_IA32_PERF_CTL 0x00000199 250#define MSR_IA32_PERF_CTL 0x00000199
251#define MSR_AMD_PERF_STATUS 0xc0010063
252#define MSR_AMD_PERF_CTL 0xc0010062
251 253
252#define MSR_IA32_MPERF 0x000000e7 254#define MSR_IA32_MPERF 0x000000e7
253#define MSR_IA32_APERF 0x000000e8 255#define MSR_IA32_APERF 0x000000e8
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index 78ff7ee48951..8d12e378a7ef 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -23,7 +23,8 @@ config X86_ACPI_CPUFREQ
23 help 23 help
24 This driver adds a CPUFreq driver which utilizes the ACPI 24 This driver adds a CPUFreq driver which utilizes the ACPI
25 Processor Performance States. 25 Processor Performance States.
26 This driver also supports Intel Enhanced Speedstep. 26 This driver also supports Intel Enhanced Speedstep and newer
27 AMD CPUs.
27 28
28 To compile this driver as a module, choose M here: the 29 To compile this driver as a module, choose M here: the
29 module will be called acpi-cpufreq. 30 module will be called acpi-cpufreq.
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 56c6c6b4eb4d..067a61f06bb5 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -54,10 +54,12 @@ MODULE_LICENSE("GPL");
54enum { 54enum {
55 UNDEFINED_CAPABLE = 0, 55 UNDEFINED_CAPABLE = 0,
56 SYSTEM_INTEL_MSR_CAPABLE, 56 SYSTEM_INTEL_MSR_CAPABLE,
57 SYSTEM_AMD_MSR_CAPABLE,
57 SYSTEM_IO_CAPABLE, 58 SYSTEM_IO_CAPABLE,
58}; 59};
59 60
60#define INTEL_MSR_RANGE (0xffff) 61#define INTEL_MSR_RANGE (0xffff)
62#define AMD_MSR_RANGE (0x7)
61 63
62struct acpi_cpufreq_data { 64struct acpi_cpufreq_data {
63 struct acpi_processor_performance *acpi_data; 65 struct acpi_processor_performance *acpi_data;
@@ -82,6 +84,13 @@ static int check_est_cpu(unsigned int cpuid)
82 return cpu_has(cpu, X86_FEATURE_EST); 84 return cpu_has(cpu, X86_FEATURE_EST);
83} 85}
84 86
87static int check_amd_hwpstate_cpu(unsigned int cpuid)
88{
89 struct cpuinfo_x86 *cpu = &cpu_data(cpuid);
90
91 return cpu_has(cpu, X86_FEATURE_HW_PSTATE);
92}
93
85static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data) 94static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
86{ 95{
87 struct acpi_processor_performance *perf; 96 struct acpi_processor_performance *perf;
@@ -101,7 +110,11 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
101 int i; 110 int i;
102 struct acpi_processor_performance *perf; 111 struct acpi_processor_performance *perf;
103 112
104 msr &= INTEL_MSR_RANGE; 113 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
114 msr &= AMD_MSR_RANGE;
115 else
116 msr &= INTEL_MSR_RANGE;
117
105 perf = data->acpi_data; 118 perf = data->acpi_data;
106 119
107 for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { 120 for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
@@ -115,6 +128,7 @@ static unsigned extract_freq(u32 val, struct acpi_cpufreq_data *data)
115{ 128{
116 switch (data->cpu_feature) { 129 switch (data->cpu_feature) {
117 case SYSTEM_INTEL_MSR_CAPABLE: 130 case SYSTEM_INTEL_MSR_CAPABLE:
131 case SYSTEM_AMD_MSR_CAPABLE:
118 return extract_msr(val, data); 132 return extract_msr(val, data);
119 case SYSTEM_IO_CAPABLE: 133 case SYSTEM_IO_CAPABLE:
120 return extract_io(val, data); 134 return extract_io(val, data);
@@ -150,6 +164,7 @@ static void do_drv_read(void *_cmd)
150 164
151 switch (cmd->type) { 165 switch (cmd->type) {
152 case SYSTEM_INTEL_MSR_CAPABLE: 166 case SYSTEM_INTEL_MSR_CAPABLE:
167 case SYSTEM_AMD_MSR_CAPABLE:
153 rdmsr(cmd->addr.msr.reg, cmd->val, h); 168 rdmsr(cmd->addr.msr.reg, cmd->val, h);
154 break; 169 break;
155 case SYSTEM_IO_CAPABLE: 170 case SYSTEM_IO_CAPABLE:
@@ -174,6 +189,9 @@ static void do_drv_write(void *_cmd)
174 lo = (lo & ~INTEL_MSR_RANGE) | (cmd->val & INTEL_MSR_RANGE); 189 lo = (lo & ~INTEL_MSR_RANGE) | (cmd->val & INTEL_MSR_RANGE);
175 wrmsr(cmd->addr.msr.reg, lo, hi); 190 wrmsr(cmd->addr.msr.reg, lo, hi);
176 break; 191 break;
192 case SYSTEM_AMD_MSR_CAPABLE:
193 wrmsr(cmd->addr.msr.reg, cmd->val, 0);
194 break;
177 case SYSTEM_IO_CAPABLE: 195 case SYSTEM_IO_CAPABLE:
178 acpi_os_write_port((acpi_io_address)cmd->addr.io.port, 196 acpi_os_write_port((acpi_io_address)cmd->addr.io.port,
179 cmd->val, 197 cmd->val,
@@ -217,6 +235,10 @@ static u32 get_cur_val(const struct cpumask *mask)
217 cmd.type = SYSTEM_INTEL_MSR_CAPABLE; 235 cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
218 cmd.addr.msr.reg = MSR_IA32_PERF_STATUS; 236 cmd.addr.msr.reg = MSR_IA32_PERF_STATUS;
219 break; 237 break;
238 case SYSTEM_AMD_MSR_CAPABLE:
239 cmd.type = SYSTEM_AMD_MSR_CAPABLE;
240 cmd.addr.msr.reg = MSR_AMD_PERF_STATUS;
241 break;
220 case SYSTEM_IO_CAPABLE: 242 case SYSTEM_IO_CAPABLE:
221 cmd.type = SYSTEM_IO_CAPABLE; 243 cmd.type = SYSTEM_IO_CAPABLE;
222 perf = per_cpu(acfreq_data, cpumask_first(mask))->acpi_data; 244 perf = per_cpu(acfreq_data, cpumask_first(mask))->acpi_data;
@@ -326,6 +348,11 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
326 cmd.addr.msr.reg = MSR_IA32_PERF_CTL; 348 cmd.addr.msr.reg = MSR_IA32_PERF_CTL;
327 cmd.val = (u32) perf->states[next_perf_state].control; 349 cmd.val = (u32) perf->states[next_perf_state].control;
328 break; 350 break;
351 case SYSTEM_AMD_MSR_CAPABLE:
352 cmd.type = SYSTEM_AMD_MSR_CAPABLE;
353 cmd.addr.msr.reg = MSR_AMD_PERF_CTL;
354 cmd.val = (u32) perf->states[next_perf_state].control;
355 break;
329 case SYSTEM_IO_CAPABLE: 356 case SYSTEM_IO_CAPABLE:
330 cmd.type = SYSTEM_IO_CAPABLE; 357 cmd.type = SYSTEM_IO_CAPABLE;
331 cmd.addr.io.port = perf->control_register.address; 358 cmd.addr.io.port = perf->control_register.address;
@@ -580,12 +607,16 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
580 break; 607 break;
581 case ACPI_ADR_SPACE_FIXED_HARDWARE: 608 case ACPI_ADR_SPACE_FIXED_HARDWARE:
582 pr_debug("HARDWARE addr space\n"); 609 pr_debug("HARDWARE addr space\n");
583 if (!check_est_cpu(cpu)) { 610 if (check_est_cpu(cpu)) {
584 result = -ENODEV; 611 data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE;
585 goto err_unreg; 612 break;
586 } 613 }
587 data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE; 614 if (check_amd_hwpstate_cpu(cpu)) {
588 break; 615 data->cpu_feature = SYSTEM_AMD_MSR_CAPABLE;
616 break;
617 }
618 result = -ENODEV;
619 goto err_unreg;
589 default: 620 default:
590 pr_debug("Unknown addr space %d\n", 621 pr_debug("Unknown addr space %d\n",
591 (u32) (perf->control_register.space_id)); 622 (u32) (perf->control_register.space_id));