forked from Minki/linux
[CPUFREQ] Prepare powernow-k8 for future CPUs.
Forthcoming AMD products will use a different algorithm for transitioning pstates than the current generation Opteron products do. The attached patch allows the powernow-k8 driver to work with those products. Signed-off-by: Mark Langsdorf <mark.langsdorf@amd.com> Signed-off-by: Dave Jones <davej@redhat.com>
This commit is contained in:
parent
911cb74bb9
commit
1f729e0660
@ -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,7 +14,7 @@
|
||||
* 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
|
||||
@ -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 1550-vid*25;
|
||||
return 100 * (fid + 0x10) >> did;
|
||||
}
|
||||
|
||||
static u32 find_khz_freq_from_fiddid(u32 fid, u32 did)
|
||||
{
|
||||
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,19 +991,55 @@ 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);
|
||||
}
|
||||
@ -936,13 +1082,18 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
|
||||
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))
|
||||
@ -952,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);
|
||||
@ -960,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:
|
||||
@ -1005,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;
|
||||
}
|
||||
@ -1040,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 */
|
||||
@ -1067,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;
|
||||
|
||||
@ -1154,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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
@ -21,8 +21,8 @@ struct powernow_k8_data {
|
||||
u32 plllock; /* pll lock time, units 1 us */
|
||||
u32 exttype; /* extended interface = 1 */
|
||||
|
||||
/* keep track of the current fid / vid */
|
||||
u32 currvid, currfid;
|
||||
/* keep track of the current fid / vid or did */
|
||||
u32 currvid, currfid, currdid;
|
||||
|
||||
/* 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.
|
||||
@ -34,6 +34,10 @@ struct powernow_k8_data {
|
||||
* used to determine valid frequency/vid/fid states */
|
||||
struct acpi_processor_performance acpi_data;
|
||||
#endif
|
||||
/* we need to keep track of associated cores, but let cpufreq
|
||||
* handle hotplug events - so just point at cpufreq pol->cpus
|
||||
* structure */
|
||||
cpumask_t *available_cores;
|
||||
};
|
||||
|
||||
|
||||
@ -43,6 +47,7 @@ struct powernow_k8_data {
|
||||
#define CPUID_XFAM_K8 0
|
||||
#define CPUID_XMOD 0x000f0000 /* extended model */
|
||||
#define CPUID_XMOD_REV_G 0x00060000
|
||||
#define CPUID_XFAM_10H 0x00100000 /* family 0x10 */
|
||||
#define CPUID_USE_XFAM_XMOD 0x00000f00
|
||||
#define CPUID_GET_MAX_CAPABILITIES 0x80000000
|
||||
#define CPUID_FREQ_VOLT_CAPABILITIES 0x80000007
|
||||
@ -79,6 +84,32 @@ 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_FID_MASK 0x0000003f
|
||||
#define HW_PSTATE_DID_MASK 0x000001c0
|
||||
#define HW_PSTATE_DID_SHIFT 6
|
||||
#define HW_PSTATE_MASK 0x00000007
|
||||
#define HW_PSTATE_VALID_MASK 0x80000000
|
||||
#define HW_FID_INDEX_SHIFT 8
|
||||
#define HW_FID_INDEX_MASK 0x0000ff00
|
||||
#define HW_DID_INDEX_SHIFT 16
|
||||
#define HW_DID_INDEX_MASK 0x00ff0000
|
||||
#define HW_WATTS_MASK 0xff
|
||||
#define HW_PWR_DVR_MASK 0x300
|
||||
#define HW_PWR_DVR_SHIFT 8
|
||||
#define HW_PWR_MAX_MULT 3
|
||||
#define MAX_HW_PSTATE 8 /* hw pstate supports up to 8 */
|
||||
#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 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 )
|
||||
@ -182,6 +213,9 @@ 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);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[])
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user