|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * (c) 2003, 2004, 2005 Advanced Micro Devices, Inc.
|
|
|
+ * (c) 2003-2006 Advanced Micro Devices, Inc.
|
|
|
* Your use of this code is subject to the terms and conditions of the
|
|
|
* GNU general public license version 2. See "COPYING" or
|
|
|
* http://www.gnu.org/licenses/gpl.html
|
|
@@ -14,13 +14,13 @@
|
|
|
* Based upon datasheets & sample CPUs kindly provided by AMD.
|
|
|
*
|
|
|
* Valuable input gratefully received from Dave Jones, Pavel Machek,
|
|
|
- * Dominik Brodowski, and others.
|
|
|
+ * Dominik Brodowski, Jacob Shin, and others.
|
|
|
* Originally developed by Paul Devriendt.
|
|
|
* Processor information obtained from Chapter 9 (Power and Thermal Management)
|
|
|
* of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD
|
|
|
* Opteron Processors" available for download from www.amd.com
|
|
|
*
|
|
|
- * Tables for specific CPUs can be infrerred from
|
|
|
+ * Tables for specific CPUs can be inferred from
|
|
|
* http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf
|
|
|
*/
|
|
|
|
|
@@ -46,7 +46,7 @@
|
|
|
|
|
|
#define PFX "powernow-k8: "
|
|
|
#define BFX PFX "BIOS error: "
|
|
|
-#define VERSION "version 1.60.2"
|
|
|
+#define VERSION "version 2.00.00"
|
|
|
#include "powernow-k8.h"
|
|
|
|
|
|
/* serialize freq changes */
|
|
@@ -54,6 +54,8 @@ static DEFINE_MUTEX(fidvid_mutex);
|
|
|
|
|
|
static struct powernow_k8_data *powernow_data[NR_CPUS];
|
|
|
|
|
|
+static int cpu_family = CPU_OPTERON;
|
|
|
+
|
|
|
#ifndef CONFIG_SMP
|
|
|
static cpumask_t cpu_core_map[1];
|
|
|
#endif
|
|
@@ -64,16 +66,36 @@ static u32 find_freq_from_fid(u32 fid)
|
|
|
return 800 + (fid * 100);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/* Return a frequency in KHz, given an input fid */
|
|
|
static u32 find_khz_freq_from_fid(u32 fid)
|
|
|
{
|
|
|
return 1000 * find_freq_from_fid(fid);
|
|
|
}
|
|
|
|
|
|
-/* Return a voltage in miliVolts, given an input vid */
|
|
|
-static u32 find_millivolts_from_vid(struct powernow_k8_data *data, u32 vid)
|
|
|
+/* Return a frequency in MHz, given an input fid and did */
|
|
|
+static u32 find_freq_from_fiddid(u32 fid, u32 did)
|
|
|
+{
|
|
|
+ return 100 * (fid + 0x10) >> did;
|
|
|
+}
|
|
|
+
|
|
|
+static u32 find_khz_freq_from_fiddid(u32 fid, u32 did)
|
|
|
{
|
|
|
- return 1550-vid*25;
|
|
|
+ return 1000 * find_freq_from_fiddid(fid, did);
|
|
|
+}
|
|
|
+
|
|
|
+static u32 find_fid_from_pstate(u32 pstate)
|
|
|
+{
|
|
|
+ u32 hi, lo;
|
|
|
+ rdmsr(MSR_PSTATE_DEF_BASE + pstate, lo, hi);
|
|
|
+ return lo & HW_PSTATE_FID_MASK;
|
|
|
+}
|
|
|
+
|
|
|
+static u32 find_did_from_pstate(u32 pstate)
|
|
|
+{
|
|
|
+ u32 hi, lo;
|
|
|
+ rdmsr(MSR_PSTATE_DEF_BASE + pstate, lo, hi);
|
|
|
+ return (lo & HW_PSTATE_DID_MASK) >> HW_PSTATE_DID_SHIFT;
|
|
|
}
|
|
|
|
|
|
/* Return the vco fid for an input fid
|
|
@@ -98,6 +120,9 @@ static int pending_bit_stuck(void)
|
|
|
{
|
|
|
u32 lo, hi;
|
|
|
|
|
|
+ if (cpu_family)
|
|
|
+ return 0;
|
|
|
+
|
|
|
rdmsr(MSR_FIDVID_STATUS, lo, hi);
|
|
|
return lo & MSR_S_LO_CHANGE_PENDING ? 1 : 0;
|
|
|
}
|
|
@@ -111,6 +136,14 @@ static int query_current_values_with_pending_wait(struct powernow_k8_data *data)
|
|
|
u32 lo, hi;
|
|
|
u32 i = 0;
|
|
|
|
|
|
+ if (cpu_family) {
|
|
|
+ rdmsr(MSR_PSTATE_STATUS, lo, hi);
|
|
|
+ i = lo & HW_PSTATE_MASK;
|
|
|
+ rdmsr(MSR_PSTATE_DEF_BASE + i, lo, hi);
|
|
|
+ data->currfid = lo & HW_PSTATE_FID_MASK;
|
|
|
+ data->currdid = (lo & HW_PSTATE_DID_MASK) >> HW_PSTATE_DID_SHIFT;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
do {
|
|
|
if (i++ > 10000) {
|
|
|
dprintk("detected change pending stuck\n");
|
|
@@ -175,7 +208,7 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
|
|
|
do {
|
|
|
wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION);
|
|
|
if (i++ > 100) {
|
|
|
- printk(KERN_ERR PFX "internal error - pending bit very stuck - no further pstate changes possible\n");
|
|
|
+ printk(KERN_ERR PFX "Hardware error - pending bit very stuck - no further pstate changes possible\n");
|
|
|
return 1;
|
|
|
}
|
|
|
} while (query_current_values_with_pending_wait(data));
|
|
@@ -255,7 +288,15 @@ static int decrease_vid_code_by_step(struct powernow_k8_data *data, u32 reqvid,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* Change the fid and vid, by the 3 phases. */
|
|
|
+/* 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->currfid = find_fid_from_pstate(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)
|
|
|
{
|
|
|
if (core_voltage_pre_transition(data, reqvid))
|
|
@@ -474,26 +515,35 @@ static int check_supported_cpu(unsigned int cpu)
|
|
|
goto out;
|
|
|
|
|
|
eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
|
|
|
- if ((eax & CPUID_XFAM) != CPUID_XFAM_K8)
|
|
|
+ if (((eax & CPUID_XFAM) != CPUID_XFAM_K8) &&
|
|
|
+ ((eax & CPUID_XFAM) < CPUID_XFAM_10H))
|
|
|
goto out;
|
|
|
|
|
|
- if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
|
|
|
- ((eax & CPUID_XMOD) > CPUID_XMOD_REV_G)) {
|
|
|
- printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax);
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
|
|
|
+ if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
|
|
|
+ ((eax & CPUID_XMOD) > CPUID_XMOD_REV_G)) {
|
|
|
+ printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
- eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES);
|
|
|
- if (eax < CPUID_FREQ_VOLT_CAPABILITIES) {
|
|
|
- printk(KERN_INFO PFX
|
|
|
- "No frequency change capabilities detected\n");
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES);
|
|
|
+ if (eax < CPUID_FREQ_VOLT_CAPABILITIES) {
|
|
|
+ printk(KERN_INFO PFX
|
|
|
+ "No frequency change capabilities detected\n");
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
- cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
|
|
|
- if ((edx & P_STATE_TRANSITION_CAPABLE) != P_STATE_TRANSITION_CAPABLE) {
|
|
|
- printk(KERN_INFO PFX "Power state transitions not supported\n");
|
|
|
- goto out;
|
|
|
+ cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
|
|
|
+ if ((edx & P_STATE_TRANSITION_CAPABLE) != P_STATE_TRANSITION_CAPABLE) {
|
|
|
+ printk(KERN_INFO PFX "Power state transitions not supported\n");
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ } 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
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
rc = 1;
|
|
@@ -547,12 +597,18 @@ static void print_basics(struct powernow_k8_data *data)
|
|
|
{
|
|
|
int j;
|
|
|
for (j = 0; j < data->numps; j++) {
|
|
|
- if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID)
|
|
|
- printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x (%d mV)\n", j,
|
|
|
+ if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID) {
|
|
|
+ if (cpu_family) {
|
|
|
+ printk(KERN_INFO PFX " %d : fid 0x%x gid 0x%x (%d MHz)\n", j, (data->powernow_table[j].index & 0xff00) >> 8,
|
|
|
+ (data->powernow_table[j].index & 0xff0000) >> 16,
|
|
|
+ data->powernow_table[j].frequency/1000);
|
|
|
+ } else {
|
|
|
+ printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x\n", j,
|
|
|
data->powernow_table[j].index & 0xff,
|
|
|
data->powernow_table[j].frequency/1000,
|
|
|
- data->powernow_table[j].index >> 8,
|
|
|
- find_millivolts_from_vid(data, data->powernow_table[j].index >> 8));
|
|
|
+ data->powernow_table[j].index >> 8);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
if (data->batps)
|
|
|
printk(KERN_INFO PFX "Only %d pstates on battery\n", data->batps);
|
|
@@ -702,7 +758,7 @@ static int find_psb_table(struct powernow_k8_data *data)
|
|
|
#ifdef CONFIG_X86_POWERNOW_K8_ACPI
|
|
|
static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index)
|
|
|
{
|
|
|
- if (!data->acpi_data.state_count)
|
|
|
+ if (!data->acpi_data.state_count || cpu_family)
|
|
|
return;
|
|
|
|
|
|
data->irt = (data->acpi_data.states[index].control >> IRT_SHIFT) & IRT_MASK;
|
|
@@ -715,9 +771,8 @@ static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned
|
|
|
|
|
|
static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
|
|
|
{
|
|
|
- int i;
|
|
|
- int cntlofreq = 0;
|
|
|
struct cpufreq_frequency_table *powernow_table;
|
|
|
+ int ret_val;
|
|
|
|
|
|
if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
|
|
|
dprintk("register performance failed: bad ACPI data\n");
|
|
@@ -746,6 +801,85 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
|
|
|
goto err_out;
|
|
|
}
|
|
|
|
|
|
+ if (cpu_family)
|
|
|
+ ret_val = fill_powernow_table_pstate(data, powernow_table);
|
|
|
+ else
|
|
|
+ ret_val = fill_powernow_table_fidvid(data, powernow_table);
|
|
|
+ if (ret_val)
|
|
|
+ goto err_out_mem;
|
|
|
+
|
|
|
+ powernow_table[data->acpi_data.state_count].frequency = CPUFREQ_TABLE_END;
|
|
|
+ powernow_table[data->acpi_data.state_count].index = 0;
|
|
|
+ data->powernow_table = powernow_table;
|
|
|
+
|
|
|
+ /* fill in data */
|
|
|
+ data->numps = data->acpi_data.state_count;
|
|
|
+ print_basics(data);
|
|
|
+ powernow_k8_acpi_pst_values(data, 0);
|
|
|
+
|
|
|
+ /* notify BIOS that we exist */
|
|
|
+ acpi_processor_notify_smm(THIS_MODULE);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err_out_mem:
|
|
|
+ kfree(powernow_table);
|
|
|
+
|
|
|
+err_out:
|
|
|
+ acpi_processor_unregister_performance(&data->acpi_data, data->cpu);
|
|
|
+
|
|
|
+ /* data->acpi_data.state_count informs us at ->exit() whether ACPI was used */
|
|
|
+ data->acpi_data.state_count = 0;
|
|
|
+
|
|
|
+ return -ENODEV;
|
|
|
+}
|
|
|
+
|
|
|
+static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < data->acpi_data.state_count; i++) {
|
|
|
+ u32 index;
|
|
|
+ u32 hi = 0, lo = 0;
|
|
|
+ u32 fid;
|
|
|
+ u32 did;
|
|
|
+
|
|
|
+ index = data->acpi_data.states[i].control & HW_PSTATE_MASK;
|
|
|
+ if (index > 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");
|
|
|
+ }
|
|
|
+ rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
|
|
|
+ if (!(hi & HW_PSTATE_VALID_MASK)) {
|
|
|
+ dprintk("invalid pstate %d, ignoring\n", index);
|
|
|
+ powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ fid = lo & HW_PSTATE_FID_MASK;
|
|
|
+ did = (lo & HW_PSTATE_DID_MASK) >> HW_PSTATE_DID_SHIFT;
|
|
|
+
|
|
|
+ dprintk(" %d : fid 0x%x, did 0x%x\n", index, fid, did);
|
|
|
+
|
|
|
+ powernow_table[i].index = index | (fid << HW_FID_INDEX_SHIFT) | (did << HW_DID_INDEX_SHIFT);
|
|
|
+
|
|
|
+ powernow_table[i].frequency = find_khz_freq_from_fiddid(fid, did);
|
|
|
+
|
|
|
+ if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) {
|
|
|
+ printk(KERN_INFO PFX "invalid freq entries %u kHz vs. %u kHz\n",
|
|
|
+ powernow_table[i].frequency,
|
|
|
+ (unsigned int) (data->acpi_data.states[i].core_frequency * 1000));
|
|
|
+ powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int cntlofreq = 0;
|
|
|
for (i = 0; i < data->acpi_data.state_count; i++) {
|
|
|
u32 fid;
|
|
|
u32 vid;
|
|
@@ -786,7 +920,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
|
|
|
if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) ||
|
|
|
(powernow_table[i].index != powernow_table[cntlofreq].index)) {
|
|
|
printk(KERN_ERR PFX "Too many lo freq table entries\n");
|
|
|
- goto err_out_mem;
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
dprintk("double low frequency table entry, ignoring it.\n");
|
|
@@ -804,31 +938,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- powernow_table[data->acpi_data.state_count].frequency = CPUFREQ_TABLE_END;
|
|
|
- powernow_table[data->acpi_data.state_count].index = 0;
|
|
|
- data->powernow_table = powernow_table;
|
|
|
-
|
|
|
- /* fill in data */
|
|
|
- data->numps = data->acpi_data.state_count;
|
|
|
- print_basics(data);
|
|
|
- powernow_k8_acpi_pst_values(data, 0);
|
|
|
-
|
|
|
- /* notify BIOS that we exist */
|
|
|
- acpi_processor_notify_smm(THIS_MODULE);
|
|
|
-
|
|
|
return 0;
|
|
|
-
|
|
|
-err_out_mem:
|
|
|
- kfree(powernow_table);
|
|
|
-
|
|
|
-err_out:
|
|
|
- acpi_processor_unregister_performance(&data->acpi_data, data->cpu);
|
|
|
-
|
|
|
- /* data->acpi_data.state_count informs us at ->exit() whether ACPI was used */
|
|
|
- data->acpi_data.state_count = 0;
|
|
|
-
|
|
|
- return -ENODEV;
|
|
|
}
|
|
|
|
|
|
static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data)
|
|
@@ -844,20 +954,20 @@ static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned
|
|
|
#endif /* CONFIG_X86_POWERNOW_K8_ACPI */
|
|
|
|
|
|
/* Take a frequency, and issue the fid/vid transition command */
|
|
|
-static int transition_frequency(struct powernow_k8_data *data, unsigned int index)
|
|
|
+static int transition_frequency_fidvid(struct powernow_k8_data *data, unsigned int index)
|
|
|
{
|
|
|
- u32 fid;
|
|
|
- u32 vid;
|
|
|
+ u32 fid = 0;
|
|
|
+ u32 vid = 0;
|
|
|
int res, i;
|
|
|
struct cpufreq_freqs freqs;
|
|
|
|
|
|
dprintk("cpu %d transition to index %u\n", smp_processor_id(), index);
|
|
|
|
|
|
+ /* fid/vid correctness check for k8 */
|
|
|
/* fid are the lower 8 bits of the index we stored into
|
|
|
- * the cpufreq frequency table in find_psb_table, vid are
|
|
|
- * the upper 8 bits.
|
|
|
+ * the cpufreq frequency table in find_psb_table, vid
|
|
|
+ * are the upper 8 bits.
|
|
|
*/
|
|
|
-
|
|
|
fid = data->powernow_table[index].index & 0xFF;
|
|
|
vid = (data->powernow_table[index].index & 0xFF00) >> 8;
|
|
|
|
|
@@ -881,22 +991,58 @@ static int transition_frequency(struct powernow_k8_data *data, unsigned int inde
|
|
|
|
|
|
dprintk("cpu %d, changing to fid 0x%x, vid 0x%x\n",
|
|
|
smp_processor_id(), fid, vid);
|
|
|
-
|
|
|
- freqs.cpu = data->cpu;
|
|
|
freqs.old = find_khz_freq_from_fid(data->currfid);
|
|
|
freqs.new = find_khz_freq_from_fid(fid);
|
|
|
- for_each_cpu_mask(i, cpu_core_map[data->cpu]) {
|
|
|
+
|
|
|
+ for_each_cpu_mask(i, *(data->available_cores)) {
|
|
|
freqs.cpu = i;
|
|
|
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
|
|
}
|
|
|
|
|
|
res = transition_fid_vid(data, fid, vid);
|
|
|
-
|
|
|
freqs.new = find_khz_freq_from_fid(data->currfid);
|
|
|
- for_each_cpu_mask(i, cpu_core_map[data->cpu]) {
|
|
|
+
|
|
|
+ for_each_cpu_mask(i, *(data->available_cores)) {
|
|
|
freqs.cpu = i;
|
|
|
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
|
|
- }
|
|
|
+ }
|
|
|
+ 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 fid = 0;
|
|
|
+ u32 did = 0;
|
|
|
+ u32 pstate = 0;
|
|
|
+ int res, i;
|
|
|
+ struct cpufreq_freqs freqs;
|
|
|
+
|
|
|
+ dprintk("cpu %d transition to index %u\n", smp_processor_id(), index);
|
|
|
+
|
|
|
+ /* get fid did for hardware pstate transition */
|
|
|
+ pstate = index & HW_PSTATE_MASK;
|
|
|
+ if (pstate > MAX_HW_PSTATE)
|
|
|
+ return 0;
|
|
|
+ fid = (index & HW_FID_INDEX_MASK) >> HW_FID_INDEX_SHIFT;
|
|
|
+ did = (index & HW_DID_INDEX_MASK) >> HW_DID_INDEX_SHIFT;
|
|
|
+ freqs.old = find_khz_freq_from_fiddid(data->currfid, data->currdid);
|
|
|
+ freqs.new = find_khz_freq_from_fiddid(fid, did);
|
|
|
+
|
|
|
+ for_each_cpu_mask(i, *(data->available_cores)) {
|
|
|
+ freqs.cpu = i;
|
|
|
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
|
|
+ }
|
|
|
+
|
|
|
+ res = transition_pstate(data, pstate);
|
|
|
+ data->currfid = find_fid_from_pstate(pstate);
|
|
|
+ data->currdid = find_did_from_pstate(pstate);
|
|
|
+ freqs.new = find_khz_freq_from_fiddid(data->currfid, data->currdid);
|
|
|
+
|
|
|
+ for_each_cpu_mask(i, *(data->available_cores)) {
|
|
|
+ freqs.cpu = i;
|
|
|
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
|
|
+ }
|
|
|
return res;
|
|
|
}
|
|
|
|
|
@@ -933,18 +1079,21 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
|
|
|
dprintk("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n",
|
|
|
pol->cpu, targfreq, pol->min, pol->max, relation);
|
|
|
|
|
|
- if (query_current_values_with_pending_wait(data)) {
|
|
|
- ret = -EIO;
|
|
|
+ if (query_current_values_with_pending_wait(data))
|
|
|
goto err_out;
|
|
|
- }
|
|
|
|
|
|
- dprintk("targ: curr fid 0x%x, vid 0x%x\n",
|
|
|
+ if (cpu_family)
|
|
|
+ dprintk("targ: curr fid 0x%x, did 0x%x\n",
|
|
|
+ data->currfid, data->currvid);
|
|
|
+ else {
|
|
|
+ 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, targfreq, relation, &newstate))
|
|
@@ -954,7 +1103,11 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
|
|
|
|
|
|
powernow_k8_acpi_pst_values(data, newstate);
|
|
|
|
|
|
- if (transition_frequency(data, newstate)) {
|
|
|
+ if (cpu_family)
|
|
|
+ ret = transition_frequency_pstate(data, newstate);
|
|
|
+ else
|
|
|
+ ret = transition_frequency_fidvid(data, newstate);
|
|
|
+ if (ret) {
|
|
|
printk(KERN_ERR PFX "transition frequency failed\n");
|
|
|
ret = 1;
|
|
|
mutex_unlock(&fidvid_mutex);
|
|
@@ -962,7 +1115,10 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
|
|
|
}
|
|
|
mutex_unlock(&fidvid_mutex);
|
|
|
|
|
|
- pol->cur = find_khz_freq_from_fid(data->currfid);
|
|
|
+ if (cpu_family)
|
|
|
+ pol->cur = find_khz_freq_from_fiddid(data->currfid, data->currdid);
|
|
|
+ else
|
|
|
+ pol->cur = find_khz_freq_from_fid(data->currfid);
|
|
|
ret = 0;
|
|
|
|
|
|
err_out:
|
|
@@ -1007,14 +1163,13 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
|
|
|
* Use the PSB BIOS structure. This is only availabe on
|
|
|
* an UP version, and is deprecated by AMD.
|
|
|
*/
|
|
|
-
|
|
|
if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) {
|
|
|
printk(KERN_ERR PFX "MP systems not supported by PSB BIOS structure\n");
|
|
|
kfree(data);
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
if (pol->cpu != 0) {
|
|
|
- printk(KERN_ERR PFX "init not cpu 0\n");
|
|
|
+ printk(KERN_ERR PFX "No _PSS objects for CPU other than CPU0\n");
|
|
|
kfree(data);
|
|
|
return -ENODEV;
|
|
|
}
|
|
@@ -1042,20 +1197,28 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
|
|
|
if (query_current_values_with_pending_wait(data))
|
|
|
goto err_out;
|
|
|
|
|
|
- fidvid_msr_init();
|
|
|
+ if (!cpu_family)
|
|
|
+ fidvid_msr_init();
|
|
|
|
|
|
/* run on any CPU again */
|
|
|
set_cpus_allowed(current, oldmask);
|
|
|
|
|
|
pol->governor = CPUFREQ_DEFAULT_GOVERNOR;
|
|
|
- pol->cpus = cpu_core_map[pol->cpu];
|
|
|
+ if (cpu_family)
|
|
|
+ pol->cpus = cpumask_of_cpu(pol->cpu);
|
|
|
+ else
|
|
|
+ pol->cpus = cpu_core_map[pol->cpu];
|
|
|
+ data->available_cores = &(pol->cpus);
|
|
|
|
|
|
/* Take a crude guess here.
|
|
|
* That guess was in microseconds, so multiply with 1000 */
|
|
|
pol->cpuinfo.transition_latency = (((data->rvo + 8) * data->vstable * VST_UNITS_20US)
|
|
|
+ (3 * (1 << data->irt) * 10)) * 1000;
|
|
|
|
|
|
- pol->cur = find_khz_freq_from_fid(data->currfid);
|
|
|
+ if (cpu_family)
|
|
|
+ pol->cur = find_khz_freq_from_fiddid(data->currfid, data->currdid);
|
|
|
+ else
|
|
|
+ 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 */
|
|
@@ -1069,8 +1232,12 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
|
|
|
|
|
|
cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu);
|
|
|
|
|
|
- printk("cpu_init done, current fid 0x%x, vid 0x%x\n",
|
|
|
- data->currfid, data->currvid);
|
|
|
+ if (cpu_family)
|
|
|
+ dprintk("cpu_init done, current fid 0x%x, did 0x%x\n",
|
|
|
+ data->currfid, data->currdid);
|
|
|
+ else
|
|
|
+ dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n",
|
|
|
+ data->currfid, data->currvid);
|
|
|
|
|
|
powernow_data[pol->cpu] = data;
|
|
|
|
|
@@ -1156,8 +1323,9 @@ static int __cpuinit powernowk8_init(void)
|
|
|
}
|
|
|
|
|
|
if (supported_cpus == num_online_cpus()) {
|
|
|
- printk(KERN_INFO PFX "Found %d AMD Athlon 64 / Opteron "
|
|
|
- "processors (" VERSION ")\n", supported_cpus);
|
|
|
+ printk(KERN_INFO PFX "Found %d %s "
|
|
|
+ "processors (" VERSION ")\n", supported_cpus,
|
|
|
+ boot_cpu_data.x86_model_id);
|
|
|
return cpufreq_register_driver(&cpufreq_amd64_driver);
|
|
|
}
|
|
|
|