* [PATCH 2/5] acpi-cpufreq: Add support for disabling dynamic overclocking
2011-05-17 17:03 [PATCH 1/5] acpi-cpufreq: Add support for modern AMD CPUs Matthew Garrett
@ 2011-05-17 17:03 ` Matthew Garrett
2011-08-02 20:21 ` Len Brown
2011-05-17 17:03 ` [PATCH 3/5] ACPI: Add fixups for AMD P-state figures Matthew Garrett
` (5 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Matthew Garrett @ 2011-05-17 17:03 UTC (permalink / raw)
To: linux-kernel
Cc: borislav.petkov, davej, mark.langsdorf, cpufreq, Matthew Garrett
One feature present in powernow-k8 that isn't present in acpi-cpufreq is
support for enabling or disabling AMD's core performance boost technology.
This patch adds that support to acpi-cpufreq, but also extends it to allow
Intel's dynamic acceleration to be disabled via the same interface. The
sysfs entry retains the cpb name for compatibility purposes.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
---
arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | 160 ++++++++++++++++++++++++++++
1 files changed, 160 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index f3dd3b1..f55e082 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -79,6 +79,86 @@ static struct acpi_processor_performance __percpu *acpi_perf_data;
static struct cpufreq_driver acpi_cpufreq_driver;
static unsigned int acpi_pstate_strict;
+static bool cpb_enabled, cpb_supported;
+static struct msr __percpu *msrs;
+
+static void _cpb_toggle_msrs(unsigned int cpu, bool t)
+{
+ struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu);
+
+ get_online_cpus();
+
+ switch (data->cpu_feature) {
+ case SYSTEM_INTEL_MSR_CAPABLE:
+ rdmsr_on_cpus(cpu_online_mask, MSR_IA32_MISC_ENABLE, msrs);
+
+ for_each_cpu(cpu, cpu_online_mask) {
+ struct msr *reg = per_cpu_ptr(msrs, cpu);
+ if (t)
+ reg->q &= ~MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
+ else
+ reg->q |= MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
+ }
+
+ wrmsr_on_cpus(cpu_online_mask, MSR_IA32_MISC_ENABLE, msrs);
+ break;
+ case SYSTEM_AMD_MSR_CAPABLE:
+ rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
+
+ for_each_cpu(cpu, cpu_online_mask) {
+ struct msr *reg = per_cpu_ptr(msrs, cpu);
+ if (t)
+ reg->l &= ~BIT(25);
+ else
+ reg->l |= BIT(25);
+ }
+
+ wrmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
+ break;
+ }
+
+ put_online_cpus();
+}
+
+static void cpb_toggle(unsigned int cpu, bool t)
+{
+ if (t && !cpb_enabled) {
+ cpb_enabled = true;
+ _cpb_toggle_msrs(cpu, t);
+ dprintk("Core Boosting enabled.\n");
+ } else if (!t && cpb_enabled) {
+ cpb_enabled = false;
+ _cpb_toggle_msrs(cpu, t);
+ dprintk("Core Boosting disabled.\n");
+ }
+}
+
+static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
+ size_t count)
+{
+ int ret = -EINVAL;
+ unsigned long val = 0;
+ unsigned int cpu = policy->cpu;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (!ret && (val == 0 || val == 1) && cpb_supported)
+ cpb_toggle(cpu, val);
+ else
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
+{
+ return sprintf(buf, "%u\n", cpb_enabled);
+}
+
+#define define_one_rw(_name) \
+static struct freq_attr _name = \
+ __ATTR(_name, 0644, show_##_name, store_##_name)
+
+define_one_rw(cpb);
static int check_est_cpu(unsigned int cpuid)
{
@@ -449,6 +529,63 @@ static void free_acpi_perf_data(void)
free_percpu(acpi_perf_data);
}
+static int cpb_notify(struct notifier_block *nb, unsigned long action,
+ void *hcpu)
+{
+ unsigned cpu = (long)hcpu;
+ u32 lo, hi;
+ struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu);
+ int msr;
+ u64 bit;
+
+ switch (data->cpu_feature) {
+ case SYSTEM_INTEL_MSR_CAPABLE:
+ msr = MSR_IA32_MISC_ENABLE;
+ bit = MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
+ break;
+ case SYSTEM_AMD_MSR_CAPABLE:
+ msr = MSR_K7_HWCR;
+ bit = BIT(25);
+ break;
+ default:
+ return NOTIFY_OK;
+ }
+
+ switch (action) {
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ if (!cpb_enabled) {
+ rdmsr_on_cpu(cpu, msr, &lo, &hi);
+ if (bit < BIT(32))
+ lo |= bit;
+ else
+ hi |= (bit >> 32);
+ wrmsr_on_cpu(cpu, msr, lo, hi);
+ }
+ break;
+
+ case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
+ rdmsr_on_cpu(cpu, msr, &lo, &hi);
+ if (bit < BIT(32))
+ lo &= ~bit;
+ else
+ hi &= ~(bit >> 32);
+ wrmsr_on_cpu(cpu, msr, lo, hi);
+ break;
+
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+
+static struct notifier_block cpb_nb = {
+ .notifier_call = cpb_notify,
+};
+
/*
* acpi_cpufreq_early_init - initialize ACPI P-States library
*
@@ -669,6 +806,21 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
if (result)
goto err_freqfree;
+ if (boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA)) {
+ msrs = msrs_alloc();
+
+ if (!msrs) {
+ result = -ENOMEM;
+ goto err_freqfree;
+ }
+
+ cpb_supported = true;
+
+ register_cpu_notifier(&cpb_nb);
+
+ cpb_toggle(0, true);
+ }
+
if (perf->states[0].core_frequency * 1000 != policy->cpuinfo.max_freq)
printk(KERN_WARNING FW_WARN "P-state 0 is not max freq\n");
@@ -752,6 +904,7 @@ static int acpi_cpufreq_resume(struct cpufreq_policy *policy)
static struct freq_attr *acpi_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+ &cpb,
NULL,
};
@@ -791,6 +944,13 @@ static void __exit acpi_cpufreq_exit(void)
{
dprintk("acpi_cpufreq_exit\n");
+ if (msrs) {
+ unregister_cpu_notifier(&cpb_nb);
+
+ msrs_free(msrs);
+ msrs = NULL;
+ }
+
cpufreq_unregister_driver(&acpi_cpufreq_driver);
free_percpu(acpi_perf_data);
--
1.7.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 5/5] cpufreq: Remove support for hardware P-state chips from powernow-k8
2011-05-17 17:03 [PATCH 1/5] acpi-cpufreq: Add support for modern AMD CPUs Matthew Garrett
` (2 preceding siblings ...)
2011-05-17 17:03 ` [PATCH 4/5] cpufreq: Add compatibility hack to powernow-k8 Matthew Garrett
@ 2011-05-17 17:03 ` Matthew Garrett
2011-05-17 17:35 ` [PATCH 1/5] acpi-cpufreq: Add support for modern AMD CPUs Borislav Petkov
` (2 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Matthew Garrett @ 2011-05-17 17:03 UTC (permalink / raw)
To: linux-kernel
Cc: borislav.petkov, davej, mark.langsdorf, cpufreq, Matthew Garrett
These chips are now supported by acpi-cpufreq, so we can delete all the
code handling them.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
---
arch/x86/kernel/cpu/cpufreq/Makefile | 2 +-
arch/x86/kernel/cpu/cpufreq/powernow-k8.c | 371 ++---------------------------
arch/x86/kernel/cpu/cpufreq/powernow-k8.h | 32 ---
3 files changed, 25 insertions(+), 380 deletions(-)
diff --git a/arch/x86/kernel/cpu/cpufreq/Makefile b/arch/x86/kernel/cpu/cpufreq/Makefile
index bd54bf6..ca3a13b 100644
--- a/arch/x86/kernel/cpu/cpufreq/Makefile
+++ b/arch/x86/kernel/cpu/cpufreq/Makefile
@@ -2,7 +2,7 @@
# K8 systems. ACPI is preferred to all other hardware-specific drivers.
# speedstep-* is preferred over p4-clockmod.
-obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o mperf.o
+obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o mperf.o
obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o
obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
index 619733e..2066bd5 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
@@ -45,19 +45,12 @@
#define PFX "powernow-k8: "
#define VERSION "version 2.20.00"
#include "powernow-k8.h"
-#include "mperf.h"
/* serialize freq changes */
static DEFINE_MUTEX(fidvid_mutex);
static DEFINE_PER_CPU(struct powernow_k8_data *, powernow_data);
-static int cpu_family = CPU_OPTERON;
-
-/* core performance boost */
-static bool cpb_capable, cpb_enabled;
-static struct msr __percpu *msrs;
-
static struct cpufreq_driver cpufreq_amd64_driver;
#ifndef CONFIG_SMP
@@ -79,12 +72,6 @@ static u32 find_khz_freq_from_fid(u32 fid)
return 1000 * find_freq_from_fid(fid);
}
-static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data,
- u32 pstate)
-{
- return data[pstate].frequency;
-}
-
/* Return the vco fid for an input fid
*
* Each "low" fid has corresponding "high" fid, and you can get to "low" fids
@@ -107,9 +94,6 @@ static int pending_bit_stuck(void)
{
u32 lo, hi;
- if (cpu_family == CPU_HW_PSTATE)
- return 0;
-
rdmsr(MSR_FIDVID_STATUS, lo, hi);
return lo & MSR_S_LO_CHANGE_PENDING ? 1 : 0;
}
@@ -123,20 +107,6 @@ static int query_current_values_with_pending_wait(struct powernow_k8_data *data)
u32 lo, hi;
u32 i = 0;
- if (cpu_family == CPU_HW_PSTATE) {
- rdmsr(MSR_PSTATE_STATUS, lo, hi);
- i = lo & HW_PSTATE_MASK;
- data->currpstate = i;
-
- /*
- * a workaround for family 11h erratum 311 might cause
- * an "out-of-range Pstate if the core is in Pstate-0
- */
- if ((boot_cpu_data.x86 == 0x11) && (i >= data->numps))
- data->currpstate = HW_PSTATE_0;
-
- return 0;
- }
do {
if (i++ > 10000) {
dprintk("detected change pending stuck\n");
@@ -293,14 +263,6 @@ static int decrease_vid_code_by_step(struct powernow_k8_data *data,
return 0;
}
-/* Change hardware pstate by single MSR write */
-static int transition_pstate(struct powernow_k8_data *data, u32 pstate)
-{
- wrmsr(MSR_PSTATE_CTRL, pstate, 0);
- data->currpstate = pstate;
- return 0;
-}
-
/* Change Opteron/Athlon64 fid and vid, by the 3 phases. */
static int transition_fid_vid(struct powernow_k8_data *data,
u32 reqfid, u32 reqvid)
@@ -551,15 +513,8 @@ static void check_supported_cpu(void *_rc)
"Power state transitions not supported\n");
return;
}
- } else { /* must be a HW Pstate capable processor */
- cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
- if ((edx & USE_HW_PSTATE) == USE_HW_PSTATE)
- cpu_family = CPU_HW_PSTATE;
- else
- return;
+ *rc = 0;
}
-
- *rc = 0;
}
static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst,
@@ -623,18 +578,11 @@ static void print_basics(struct powernow_k8_data *data)
for (j = 0; j < data->numps; j++) {
if (data->powernow_table[j].frequency !=
CPUFREQ_ENTRY_INVALID) {
- if (cpu_family == CPU_HW_PSTATE) {
- printk(KERN_INFO PFX
- " %d : pstate %d (%d MHz)\n", j,
- data->powernow_table[j].index,
- data->powernow_table[j].frequency/1000);
- } else {
printk(KERN_INFO PFX
"fid 0x%x (%d MHz), vid 0x%x\n",
data->powernow_table[j].index & 0xff,
data->powernow_table[j].frequency/1000,
data->powernow_table[j].index >> 8);
- }
}
}
if (data->batps)
@@ -642,20 +590,6 @@ static void print_basics(struct powernow_k8_data *data)
data->batps);
}
-static u32 freq_from_fid_did(u32 fid, u32 did)
-{
- u32 mhz = 0;
-
- if (boot_cpu_data.x86 == 0x10)
- mhz = (100 * (fid + 0x10)) >> did;
- else if (boot_cpu_data.x86 == 0x11)
- mhz = (100 * (fid + 8)) >> did;
- else
- BUG();
-
- return mhz * 1000;
-}
-
static int fill_powernow_table(struct powernow_k8_data *data,
struct pst_s *pst, u8 maxvid)
{
@@ -815,7 +749,7 @@ static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data,
{
u64 control;
- if (!data->acpi_data.state_count || (cpu_family == CPU_HW_PSTATE))
+ if (!data->acpi_data.state_count)
return;
control = data->acpi_data.states[index].control;
@@ -866,10 +800,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
data->numps = data->acpi_data.state_count;
powernow_k8_acpi_pst_values(data, 0);
- if (cpu_family == CPU_HW_PSTATE)
- ret_val = fill_powernow_table_pstate(data, powernow_table);
- else
- ret_val = fill_powernow_table_fidvid(data, powernow_table);
+ ret_val = fill_powernow_table_fidvid(data, powernow_table);
if (ret_val)
goto err_out_mem;
@@ -906,47 +837,6 @@ err_out:
return ret_val;
}
-static int fill_powernow_table_pstate(struct powernow_k8_data *data,
- struct cpufreq_frequency_table *powernow_table)
-{
- int i;
- u32 hi = 0, lo = 0;
- rdmsr(MSR_PSTATE_CUR_LIMIT, lo, hi);
- data->max_hw_pstate = (lo & HW_PSTATE_MAX_MASK) >> HW_PSTATE_MAX_SHIFT;
-
- for (i = 0; i < data->acpi_data.state_count; i++) {
- u32 index;
-
- index = data->acpi_data.states[i].control & HW_PSTATE_MASK;
- if (index > data->max_hw_pstate) {
- printk(KERN_ERR PFX "invalid pstate %d - "
- "bad value %d.\n", i, index);
- printk(KERN_ERR PFX "Please report to BIOS "
- "manufacturer\n");
- invalidate_entry(powernow_table, i);
- continue;
- }
- rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
- if (!(hi & HW_PSTATE_VALID_MASK)) {
- dprintk("invalid pstate %d, ignoring\n", index);
- invalidate_entry(powernow_table, i);
- continue;
- }
-
- powernow_table[i].index = index;
-
- /* Frequency may be rounded for these */
- if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10)
- || boot_cpu_data.x86 == 0x11) {
- powernow_table[i].frequency =
- freq_from_fid_did(lo & 0x3f, (lo >> 6) & 7);
- } else
- powernow_table[i].frequency =
- data->acpi_data.states[i].core_frequency * 1000;
- }
- return 0;
-}
-
static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
struct cpufreq_frequency_table *powernow_table)
{
@@ -1023,15 +913,8 @@ static int get_transition_latency(struct powernow_k8_data *data)
max_latency = cur_latency;
}
if (max_latency == 0) {
- /*
- * Fam 11h and later may return 0 as transition latency. This
- * is intended and means "very fast". While cpufreq core and
- * governors currently can handle that gracefully, better set it
- * to 1 to avoid problems in the future.
- */
- if (boot_cpu_data.x86 < 0x11)
- printk(KERN_ERR FW_WARN PFX "Invalid zero transition "
- "latency\n");
+ printk(KERN_ERR FW_WARN PFX "Invalid zero transition "
+ "latency\n");
max_latency = 1;
}
/* value in usecs, needs to be in nanoseconds */
@@ -1088,39 +971,6 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
return res;
}
-/* Take a frequency, and issue the hardware pstate transition command */
-static int transition_frequency_pstate(struct powernow_k8_data *data,
- unsigned int index)
-{
- u32 pstate = 0;
- int res, i;
- struct cpufreq_freqs freqs;
-
- dprintk("cpu %d transition to index %u\n", smp_processor_id(), index);
-
- /* get MSR index for hardware pstate transition */
- pstate = index & HW_PSTATE_MASK;
- if (pstate > data->max_hw_pstate)
- return 0;
- freqs.old = find_khz_freq_from_pstate(data->powernow_table,
- data->currpstate);
- freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate);
-
- for_each_cpu(i, data->available_cores) {
- freqs.cpu = i;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- }
-
- res = transition_pstate(data, pstate);
- freqs.new = find_khz_freq_from_pstate(data->powernow_table, pstate);
-
- for_each_cpu(i, data->available_cores) {
- freqs.cpu = i;
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- }
- return res;
-}
-
/* Driver entry point to switch to the target frequency */
static int powernowk8_target(struct cpufreq_policy *pol,
unsigned targfreq, unsigned relation)
@@ -1162,18 +1012,16 @@ static int powernowk8_target(struct cpufreq_policy *pol,
if (query_current_values_with_pending_wait(data))
goto err_out;
- if (cpu_family != CPU_HW_PSTATE) {
- dprintk("targ: curr fid 0x%x, vid 0x%x\n",
+ dprintk("targ: curr fid 0x%x, vid 0x%x\n",
data->currfid, data->currvid);
- if ((checkvid != data->currvid) ||
- (checkfid != data->currfid)) {
- printk(KERN_INFO PFX
- "error - out of sync, fix 0x%x 0x%x, "
- "vid 0x%x 0x%x\n",
- checkfid, data->currfid,
- checkvid, data->currvid);
- }
+ if ((checkvid != data->currvid) ||
+ (checkfid != data->currfid)) {
+ printk(KERN_INFO PFX
+ "error - out of sync, fix 0x%x 0x%x, "
+ "vid 0x%x 0x%x\n",
+ checkfid, data->currfid,
+ checkvid, data->currvid);
}
if (cpufreq_frequency_table_target(pol, data->powernow_table,
@@ -1184,10 +1032,8 @@ static int powernowk8_target(struct cpufreq_policy *pol,
powernow_k8_acpi_pst_values(data, newstate);
- if (cpu_family == CPU_HW_PSTATE)
- ret = transition_frequency_pstate(data, newstate);
- else
- ret = transition_frequency_fidvid(data, newstate);
+ ret = transition_frequency_fidvid(data, newstate);
+
if (ret) {
printk(KERN_ERR PFX "transition frequency failed\n");
ret = 1;
@@ -1196,11 +1042,7 @@ static int powernowk8_target(struct cpufreq_policy *pol,
}
mutex_unlock(&fidvid_mutex);
- if (cpu_family == CPU_HW_PSTATE)
- pol->cur = find_khz_freq_from_pstate(data->powernow_table,
- newstate);
- else
- pol->cur = find_khz_freq_from_fid(data->currfid);
+ pol->cur = find_khz_freq_from_fid(data->currfid);
ret = 0;
err_out:
@@ -1240,8 +1082,7 @@ static void __cpuinit powernowk8_cpu_init_on_cpu(void *_init_on_cpu)
return;
}
- if (cpu_family == CPU_OPTERON)
- fidvid_msr_init();
+ fidvid_msr_init();
init_on_cpu->rc = 0;
}
@@ -1271,7 +1112,6 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
}
data->cpu = pol->cpu;
- data->currpstate = HW_PSTATE_INVALID;
if (powernow_k8_cpu_init_acpi(data)) {
/*
@@ -1308,17 +1148,10 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
if (rc != 0)
goto err_out_exit_acpi;
- if (cpu_family == CPU_HW_PSTATE)
- cpumask_copy(pol->cpus, cpumask_of(pol->cpu));
- else
- cpumask_copy(pol->cpus, cpu_core_mask(pol->cpu));
+ cpumask_copy(pol->cpus, cpu_core_mask(pol->cpu));
data->available_cores = pol->cpus;
- if (cpu_family == CPU_HW_PSTATE)
- pol->cur = find_khz_freq_from_pstate(data->powernow_table,
- data->currpstate);
- else
- pol->cur = find_khz_freq_from_fid(data->currfid);
+ pol->cur = find_khz_freq_from_fid(data->currfid);
dprintk("policy current frequency %d kHz\n", pol->cur);
/* min/max the cpu is capable of */
@@ -1330,18 +1163,10 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
return -EINVAL;
}
- /* Check for APERF/MPERF support in hardware */
- if (cpu_has(c, X86_FEATURE_APERFMPERF))
- cpufreq_amd64_driver.getavg = cpufreq_get_measured_perf;
-
cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu);
- if (cpu_family == CPU_HW_PSTATE)
- dprintk("cpu_init done, current pstate 0x%x\n",
- data->currpstate);
- else
- dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n",
- data->currfid, data->currvid);
+ dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n",
+ data->currfid, data->currvid);
per_cpu(powernow_data, pol->cpu) = data;
@@ -1394,88 +1219,15 @@ static unsigned int powernowk8_get(unsigned int cpu)
if (err)
goto out;
- if (cpu_family == CPU_HW_PSTATE)
- khz = find_khz_freq_from_pstate(data->powernow_table,
- data->currpstate);
- else
- khz = find_khz_freq_from_fid(data->currfid);
+ khz = find_khz_freq_from_fid(data->currfid);
out:
return khz;
}
-static void _cpb_toggle_msrs(bool t)
-{
- int cpu;
-
- get_online_cpus();
-
- rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
-
- for_each_cpu(cpu, cpu_online_mask) {
- struct msr *reg = per_cpu_ptr(msrs, cpu);
- if (t)
- reg->l &= ~BIT(25);
- else
- reg->l |= BIT(25);
- }
- wrmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
-
- put_online_cpus();
-}
-
-/*
- * Switch on/off core performance boosting.
- *
- * 0=disable
- * 1=enable.
- */
-static void cpb_toggle(bool t)
-{
- if (!cpb_capable)
- return;
-
- if (t && !cpb_enabled) {
- cpb_enabled = true;
- _cpb_toggle_msrs(t);
- printk(KERN_INFO PFX "Core Boosting enabled.\n");
- } else if (!t && cpb_enabled) {
- cpb_enabled = false;
- _cpb_toggle_msrs(t);
- printk(KERN_INFO PFX "Core Boosting disabled.\n");
- }
-}
-
-static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
- size_t count)
-{
- int ret = -EINVAL;
- unsigned long val = 0;
-
- ret = strict_strtoul(buf, 10, &val);
- if (!ret && (val == 0 || val == 1) && cpb_capable)
- cpb_toggle(val);
- else
- return -EINVAL;
-
- return count;
-}
-
-static ssize_t show_cpb(struct cpufreq_policy *policy, char *buf)
-{
- return sprintf(buf, "%u\n", cpb_enabled);
-}
-
-#define define_one_rw(_name) \
-static struct freq_attr _name = \
-__ATTR(_name, 0644, show_##_name, store_##_name)
-
-define_one_rw(cpb);
-
static struct freq_attr *powernow_k8_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
- &cpb,
NULL,
};
@@ -1491,51 +1243,10 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
.attr = powernow_k8_attr,
};
-/*
- * Clear the boost-disable flag on the CPU_DOWN path so that this cpu
- * cannot block the remaining ones from boosting. On the CPU_UP path we
- * simply keep the boost-disable flag in sync with the current global
- * state.
- */
-static int cpb_notify(struct notifier_block *nb, unsigned long action,
- void *hcpu)
-{
- unsigned cpu = (long)hcpu;
- u32 lo, hi;
-
- switch (action) {
- case CPU_UP_PREPARE:
- case CPU_UP_PREPARE_FROZEN:
-
- if (!cpb_enabled) {
- rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi);
- lo |= BIT(25);
- wrmsr_on_cpu(cpu, MSR_K7_HWCR, lo, hi);
- }
- break;
-
- case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
- rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi);
- lo &= ~BIT(25);
- wrmsr_on_cpu(cpu, MSR_K7_HWCR, lo, hi);
- break;
-
- default:
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block cpb_nb = {
- .notifier_call = cpb_notify,
-};
-
/* driver entry point for init */
static int __cpuinit powernowk8_init(void)
{
- unsigned int i, supported_cpus = 0, cpu;
+ unsigned int i, supported_cpus = 0;
int rv;
request_module("acpi_cpufreq");
@@ -1553,35 +1264,8 @@ static int __cpuinit powernowk8_init(void)
printk(KERN_INFO PFX "Found %d %s (%d cpu cores) (" VERSION ")\n",
num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus);
- if (boot_cpu_has(X86_FEATURE_CPB)) {
-
- cpb_capable = true;
-
- msrs = msrs_alloc();
- if (!msrs) {
- printk(KERN_ERR "%s: Error allocating msrs!\n", __func__);
- return -ENOMEM;
- }
-
- register_cpu_notifier(&cpb_nb);
-
- rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
-
- for_each_cpu(cpu, cpu_online_mask) {
- struct msr *reg = per_cpu_ptr(msrs, cpu);
- cpb_enabled |= !(!!(reg->l & BIT(25)));
- }
-
- printk(KERN_INFO PFX "Core Performance Boosting: %s.\n",
- (cpb_enabled ? "on" : "off"));
- }
-
rv = cpufreq_register_driver(&cpufreq_amd64_driver);
- if (rv < 0 && boot_cpu_has(X86_FEATURE_CPB)) {
- unregister_cpu_notifier(&cpb_nb);
- msrs_free(msrs);
- msrs = NULL;
- }
+
return rv;
}
@@ -1590,13 +1274,6 @@ static void __exit powernowk8_exit(void)
{
dprintk("exit\n");
- if (boot_cpu_has(X86_FEATURE_CPB)) {
- msrs_free(msrs);
- msrs = NULL;
-
- unregister_cpu_notifier(&cpb_nb);
- }
-
cpufreq_unregister_driver(&cpufreq_amd64_driver);
}
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h b/arch/x86/kernel/cpu/cpufreq/powernow-k8.h
index df3529b..4e53123 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.h
@@ -5,24 +5,11 @@
* http://www.gnu.org/licenses/gpl.html
*/
-enum pstate {
- HW_PSTATE_INVALID = 0xff,
- HW_PSTATE_0 = 0,
- HW_PSTATE_1 = 1,
- HW_PSTATE_2 = 2,
- HW_PSTATE_3 = 3,
- HW_PSTATE_4 = 4,
- HW_PSTATE_5 = 5,
- HW_PSTATE_6 = 6,
- HW_PSTATE_7 = 7,
-};
-
struct powernow_k8_data {
unsigned int cpu;
u32 numps; /* number of p-states */
u32 batps; /* number of p-states supported on battery */
- u32 max_hw_pstate; /* maximum legal hardware pstate */
/* these values are constant when the PSB is used to determine
* vid/fid pairings, but are modified during the ->target() call
@@ -37,7 +24,6 @@ struct powernow_k8_data {
/* keep track of the current fid / vid or pstate */
u32 currvid;
u32 currfid;
- enum pstate currpstate;
/* the powernow_table includes all frequency and vid/fid pairings:
* fid are the lower 8 bits of the index, vid are the upper 8 bits.
@@ -97,23 +83,6 @@ struct powernow_k8_data {
#define MSR_S_HI_CURRENT_VID 0x0000003f
#define MSR_C_HI_STP_GNT_BENIGN 0x00000001
-
-/* Hardware Pstate _PSS and MSR definitions */
-#define USE_HW_PSTATE 0x00000080
-#define HW_PSTATE_MASK 0x00000007
-#define HW_PSTATE_VALID_MASK 0x80000000
-#define HW_PSTATE_MAX_MASK 0x000000f0
-#define HW_PSTATE_MAX_SHIFT 4
-#define MSR_PSTATE_DEF_BASE 0xc0010064 /* base of Pstate MSRs */
-#define MSR_PSTATE_STATUS 0xc0010063 /* Pstate Status MSR */
-#define MSR_PSTATE_CTRL 0xc0010062 /* Pstate control MSR */
-#define MSR_PSTATE_CUR_LIMIT 0xc0010061 /* pstate current limit MSR */
-
-/* define the two driver architectures */
-#define CPU_OPTERON 0
-#define CPU_HW_PSTATE 1
-
-
/*
* There are restrictions frequencies have to follow:
* - only 1 entry in the low fid table ( <=1.4GHz )
@@ -220,5 +189,4 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid);
static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index);
-static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table);
static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table);
--
1.7.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH 1/5] acpi-cpufreq: Add support for modern AMD CPUs
2011-05-17 17:03 [PATCH 1/5] acpi-cpufreq: Add support for modern AMD CPUs Matthew Garrett
` (3 preceding siblings ...)
2011-05-17 17:03 ` [PATCH 5/5] cpufreq: Remove support for hardware P-state chips from powernow-k8 Matthew Garrett
@ 2011-05-17 17:35 ` Borislav Petkov
2011-05-17 17:42 ` Matthew Garrett
2011-05-19 7:26 ` Andreas Herrmann
2011-08-02 20:18 ` Len Brown
6 siblings, 1 reply; 13+ messages in thread
From: Borislav Petkov @ 2011-05-17 17:35 UTC (permalink / raw)
To: Matthew Garrett
Cc: linux-kernel@vger.kernel.org, davej@redhat.com, Langsdorf, Mark,
cpufreq@vger.kernel.org
On Tue, May 17, 2011 at 01:03:35PM -0400, Matthew Garrett wrote:
> 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.
Ok, I'm a bit confused here but maybe because I don't know the whole
cpufreq subsystem that well. Is the purpose here to add hw pstates
support to acpi-cpufreq so that it is used on AMD but leave the old
Fid/Vid method to powernow-k8, thus phasing it out...?
Hmm.
Some nitpicks below.
> Signed-off-by: Matthew Garrett <mjg@redhat.com>
> ---
> arch/x86/include/asm/cpufeature.h | 1 +
> arch/x86/include/asm/msr-index.h | 2 +
> arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | 43 ++++++++++++++++++++++++----
> arch/x86/kernel/cpu/scattered.c | 1 +
> 4 files changed, 41 insertions(+), 6 deletions(-)
>
> diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
> index 91f3e087..fee7089 100644
> --- a/arch/x86/include/asm/cpufeature.h
> +++ b/arch/x86/include/asm/cpufeature.h
> @@ -174,6 +174,7 @@
> #define X86_FEATURE_PLN (7*32+ 5) /* Intel Power Limit Notification */
> #define X86_FEATURE_PTS (7*32+ 6) /* Intel Package Thermal Status */
> #define X86_FEATURE_DTS (7*32+ 7) /* Digital Thermal Sensor */
> +#define X86_FEATURE_POWERNOW (7*32+ 8) /* AMD frequency scaling */
>
> /* Virtualization flags: Linux defined, word 8 */
> #define X86_FEATURE_TPR_SHADOW (8*32+ 0) /* Intel TPR Shadow */
> diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
> index 3cce714..d6f3e1f 100644
> --- a/arch/x86/include/asm/msr-index.h
> +++ b/arch/x86/include/asm/msr-index.h
> @@ -233,6 +233,8 @@
>
> #define MSR_IA32_PERF_STATUS 0x00000198
> #define MSR_IA32_PERF_CTL 0x00000199
> +#define MSR_AMD_PERF_STATUS 0xc0010063
> +#define MSR_AMD_PERF_CTL 0xc0010062
Yeah, there are defines for those in
<arch/x86/kernel/cpu/cpufreq/powernow-k8.h>:
#define MSR_PSTATE_STATUS 0xc0010063 /* Pstate Status MSR */
#define MSR_PSTATE_CTRL 0xc0010062 /* Pstate control MSR */
can you remove them from there for consistency so that we can use only
the msr-index.h definitions.
>
> #define MSR_IA32_MPERF 0x000000e7
> #define MSR_IA32_APERF 0x000000e8
> diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
> index a2baafb..f3dd3b1 100644
> --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
> +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
> @@ -57,10 +57,12 @@ MODULE_LICENSE("GPL");
> enum {
> UNDEFINED_CAPABLE = 0,
> SYSTEM_INTEL_MSR_CAPABLE,
> + SYSTEM_AMD_MSR_CAPABLE,
> SYSTEM_IO_CAPABLE,
> };
>
> #define INTEL_MSR_RANGE (0xffff)
> +#define AMD_MSR_RANGE (0x7)
>
> struct acpi_cpufreq_data {
> struct acpi_processor_performance *acpi_data;
> @@ -85,6 +87,13 @@ static int check_est_cpu(unsigned int cpuid)
> return cpu_has(cpu, X86_FEATURE_EST);
> }
>
> +static int check_powernow_cpu(unsigned int cpuid)
> +{
> + struct cpuinfo_x86 *cpu = &cpu_data(cpuid);
> +
> + return cpu_has(cpu, X86_FEATURE_POWERNOW);
> +}
This could be static_cpu_has() since all the CPUs, including the boot
CPU, will have the HwPstate thing set. Thus, you can ignore the "cpuid"
parameter.
> +
> static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
> {
> struct acpi_processor_performance *perf;
> @@ -104,7 +113,11 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
> int i;
> struct acpi_processor_performance *perf;
>
> - msr &= INTEL_MSR_RANGE;
> + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
> + msr &= AMD_MSR_RANGE;
> + else
> + msr &= INTEL_MSR_RANGE;
> +
> perf = data->acpi_data;
>
> for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
> @@ -118,6 +131,7 @@ static unsigned extract_freq(u32 val, struct acpi_cpufreq_data *data)
> {
> switch (data->cpu_feature) {
> case SYSTEM_INTEL_MSR_CAPABLE:
> + case SYSTEM_AMD_MSR_CAPABLE:
> return extract_msr(val, data);
> case SYSTEM_IO_CAPABLE:
> return extract_io(val, data);
> @@ -153,6 +167,7 @@ static void do_drv_read(void *_cmd)
>
> switch (cmd->type) {
> case SYSTEM_INTEL_MSR_CAPABLE:
> + case SYSTEM_AMD_MSR_CAPABLE:
> rdmsr(cmd->addr.msr.reg, cmd->val, h);
> break;
> case SYSTEM_IO_CAPABLE:
> @@ -177,6 +192,9 @@ static void do_drv_write(void *_cmd)
> lo = (lo & ~INTEL_MSR_RANGE) | (cmd->val & INTEL_MSR_RANGE);
> wrmsr(cmd->addr.msr.reg, lo, hi);
> break;
> + case SYSTEM_AMD_MSR_CAPABLE:
> + wrmsr(cmd->addr.msr.reg, cmd->val, 0);
> + break;
> case SYSTEM_IO_CAPABLE:
> acpi_os_write_port((acpi_io_address)cmd->addr.io.port,
> cmd->val,
> @@ -220,6 +238,10 @@ static u32 get_cur_val(const struct cpumask *mask)
> cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
> cmd.addr.msr.reg = MSR_IA32_PERF_STATUS;
> break;
> + case SYSTEM_AMD_MSR_CAPABLE:
> + cmd.type = SYSTEM_AMD_MSR_CAPABLE;
> + cmd.addr.msr.reg = MSR_AMD_PERF_STATUS;
> + break;
> case SYSTEM_IO_CAPABLE:
> cmd.type = SYSTEM_IO_CAPABLE;
> perf = per_cpu(acfreq_data, cpumask_first(mask))->acpi_data;
> @@ -329,6 +351,11 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
> cmd.addr.msr.reg = MSR_IA32_PERF_CTL;
> cmd.val = (u32) perf->states[next_perf_state].control;
> break;
> + case SYSTEM_AMD_MSR_CAPABLE:
> + cmd.type = SYSTEM_AMD_MSR_CAPABLE;
> + cmd.addr.msr.reg = MSR_AMD_PERF_CTL;
> + cmd.val = (u32) perf->states[next_perf_state].control;
> + break;
> case SYSTEM_IO_CAPABLE:
> cmd.type = SYSTEM_IO_CAPABLE;
> cmd.addr.io.port = perf->control_register.address;
> @@ -583,12 +610,16 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
> break;
> case ACPI_ADR_SPACE_FIXED_HARDWARE:
> dprintk("HARDWARE addr space\n");
> - if (!check_est_cpu(cpu)) {
> - result = -ENODEV;
> - goto err_unreg;
> + if (check_est_cpu(cpu)) {
> + data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE;
> + break;
> }
> - data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE;
> - break;
> + if (check_powernow_cpu(cpu)) {
> + data->cpu_feature = SYSTEM_AMD_MSR_CAPABLE;
> + break;
> + }
> + result = -ENODEV;
> + goto err_unreg;
> default:
> dprintk("Unknown addr space %d\n",
> (u32) (perf->control_register.space_id));
> diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
> index c7f64e6..d5086af 100644
> --- a/arch/x86/kernel/cpu/scattered.c
> +++ b/arch/x86/kernel/cpu/scattered.c
> @@ -39,6 +39,7 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
> { X86_FEATURE_APERFMPERF, CR_ECX, 0, 0x00000006, 0 },
> { X86_FEATURE_EPB, CR_ECX, 3, 0x00000006, 0 },
> { X86_FEATURE_XSAVEOPT, CR_EAX, 0, 0x0000000d, 1 },
> + { X86_FEATURE_POWERNOW, CR_EDX, 7, 0x80000007, 0 },
> { X86_FEATURE_CPB, CR_EDX, 9, 0x80000007, 0 },
> { X86_FEATURE_NPT, CR_EDX, 0, 0x8000000a, 0 },
> { X86_FEATURE_LBRV, CR_EDX, 1, 0x8000000a, 0 },
It might make sense to split out the cpuid changes to a different patch,
IMHO.
Thanks.
--
Regards/Gruss,
Boris.
Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
General Managers: Alberto Bozzo, Andrew Bowd
Registration: Dornach, Gemeinde Aschheim, Landkreis Muenchen
Registergericht Muenchen, HRB Nr. 43632
^ permalink raw reply [flat|nested] 13+ messages in thread