architectural pstate driver for powernow-k8
PATCH 1/1 architectural pstate driver for powernow-k8
This patch should apply cleanly to the 2.6.22.6 kernel. It changes the powernow-k8 driver code that deals with 3rd generation Opteron, Phenom, and later processors to match the architectual pstate driver described in the AMD64 Architecture Programmer's Manual Volume 2 Chapter 18. The initial implementation of the hardware pstate driver for PowerNow! used some processor-version specific features, and would not be maintainable in the long term as the processor features changed. This architectural driver should work on all future AMD processors.
-Mark Langsdorf
Operating System Research Center
AMD
arch/i386/kernel/cpu/cpufreq/powernow-k8.c +21 -60
@@ -46,7 +46,7 @@#define PFX "powernow-k8: "#define BFX PFX "BIOS error: " -#define VERSION "version 2.00.00" +#define VERSION "version 2.20.00"#include "powernow-k8.h" /* serialize freq changes */
@@ -73,29 +73,9 @@ static u32 find_khz_freq_from_fid(u32 fireturn 1000 *find_freq_from_fid (fid); } -/* Return a frequency in MHz, given an input fid and did */ -static u32 find_freq_from_fiddid (u32 fid,u32 did) +static u32 find_khz_freq_from_pstate (struct cpufreq_frequency_table *data,u32 pstate) { -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 data[pstate].frequency; }/* Return the vco fid for an input fid
@@ -139,9 +119,7 @@ static int query_current_values_with_penif (cpu_family ==CPU_HW_PSTATE ) {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 ; + data->currpstate = i;return 0 ; } do {
@@ -292,7 +270,7 @@ static int decrease_vid_code_by_step(strstatic int transition_pstate (struct powernow_k8_data *data,u32 pstate) {wrmsr (MSR_PSTATE_CTRL , pstate,0 ); - data->currfid =find_fid_from_pstate (pstate); + data->currpstate = pstate;return 0 ; }
@@ -839,17 +817,20 @@ err_out: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 , hi, lo); + data->max_hw_pstate = (hi &HW_PSTATE_MAX_MASK ) >>HW_PSTATE_MAX_SHIFT ;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 ) { +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"); + powernow_table[i].frequency =CPUFREQ_ENTRY_INVALID ; +continue ; }rdmsr (MSR_PSTATE_DEF_BASE + index, lo, hi);if (!(hi &HW_PSTATE_VALID_MASK )) {
@@ -858,22 +839,9 @@ static int fill_powernow_table_pstate(stcontinue ; } - fid = lo &HW_PSTATE_FID_MASK ; - did = (lo &HW_PSTATE_DID_MASK ) >>HW_PSTATE_DID_SHIFT ; + powernow_table[i].index = index; -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 ; - } + powernow_table[i].frequency = data->acpi_data.states[i].core_frequency *1000 ; }return 0 ; }
@@ -1014,8 +982,6 @@ static int transition_frequency_fidvid(s/* 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;
@@ -1024,12 +990,10 @@ static int transition_frequency_pstate(s/* get fid did for hardware pstate transition */ pstate = index &HW_PSTATE_MASK ; -if (pstate >MAX_HW_PSTATE ) +if (pstate > data->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); + 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_mask (i, *(data->available_cores)) { freqs.cpu = i;
@@ -1037,9 +1001,7 @@ static int transition_frequency_pstate(s } 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); + freqs.new =find_khz_freq_from_pstate (data->powernow_table, pstate);for_each_cpu_mask (i, *(data->available_cores)) { freqs.cpu = i;
@@ -1118,7 +1080,7 @@ static int powernowk8_target(struct cpufmutex_unlock (&fidvid_mutex);if (cpu_family ==CPU_HW_PSTATE ) - pol->cur =find_khz_freq_from_fiddid (data->currfid, data->currdid); + pol->cur =find_khz_freq_from_pstate (data->powernow_table, newstate);else pol->cur =find_khz_freq_from_fid (data->currfid); ret =0 ;
@@ -1218,7 +1180,7 @@ static int __cpuinit powernowk8_cpu_init + (3 * (1 << data->irt) * 10)) * 1000;if (cpu_family ==CPU_HW_PSTATE ) - pol->cur =find_khz_freq_from_fiddid (data->currfid, data->currdid); + pol->cur =find_khz_freq_from_pstate (data->powernow_table, data->currpstate);else pol->cur =find_khz_freq_from_fid (data->currfid);dprintk ("policy current frequency %d kHz\n" , pol->cur);
@@ -1235,8 +1197,7 @@ static int __cpuinit powernowk8_cpu_initcpufreq_frequency_table_get_attr (data->powernow_table, pol->cpu);if (cpu_family ==CPU_HW_PSTATE ) -dprintk ("cpu_init done, current fid 0x%x, did 0x%x\n" , - data->currfid, data->currdid); +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);
@@ -1292,7 +1253,7 @@ static unsigned int powernowk8_get (unsi goto out;if (cpu_family ==CPU_HW_PSTATE ) - khz =find_khz_freq_from_fiddid (data->currfid, data->currdid); + khz =find_khz_freq_from_pstate (data->powernow_table, data->currpstate);else khz =find_khz_freq_from_fid (data->currfid);
arch/i386/kernel/cpu/cpufreq/powernow-k8.h +6 -14
@@ -10,6 +10,7 @@ struct powernow_k8_data {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
@@ -21,8 +22,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 or did */ -u32 currvid, currfid, currdid; +/* keep track of the current fid / vid or pstate */ +u32 currvid, currfid, 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.
@@ -87,23 +88,14 @@ struct powernow_k8_data {/* 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 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
-------------------------------------------------------
arch/i386/kernel/cpu/cpufreq/powernow-k8.c +21 -60
170 lines not on this page · raw message
arch/i386/kernel/cpu/cpufreq/powernow-k8.h +6 -14
@@ -10,6 +10,7 @@ struct powernow_k8_data {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
@@ -21,8 +22,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 or did */ -u32 currvid, currfid, currdid; +/* keep track of the current fid / vid or pstate */ +u32 currvid, currfid, 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.
@@ -87,23 +88,14 @@ struct powernow_k8_data {/* 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 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
Quoted 1 line · Mark Langsdorf
This patch should apply cleanly to the 2.6.22.6 kernel.
Isn't that a little old? The earliest this could be merged is the upcomming 2.6.24 tree. Best you submit it against .23 or better -mm.
Quoted 1 line
This architectural driver should work on all future AMD processors.
That's great. Requiring new powernow drivers all the time was a little annoying in the past.
-Andi
PATCH 1/1 architectural pstate driver for powernow-k8
Quoted 7 lines · Andi Kleen
Quoted 1 line · Mark Langsdorf
This patch should apply cleanly to the 2.6.22.6 kernel.
Isn't that a little old? The earliest this could be merged is the upcomming 2.6.24 tree. Best you submit it against .23 or better -mm.
Good point.
This patch should apply cleanly to the 2.6.23-rc8-mm2 kernel. It changes the powernow-k8 driver code that deals with 3rd generation Opteron, Phenom, and later processors to match the architectual pstate driver described in the AMD64 Architecture Programmer's Manual Volume 2 Chapter 18. The initial implementation of the hardware pstate driver for PowerNow! used some processor-version specific features, and would not be maintainable in the long term as the processor features changed. This architectural driver should work on all future AMD processors.
-Mark Langsdorf
Operating System Resarch Center
AMD
Signed-off-by <[email protected]>
Acked-by <[email protected]>
arch/i386/kernel/cpu/cpufreq/powernow-k8.c +21 -62
@@ -46,7 +46,7 @@#define PFX "powernow-k8: "#define BFX PFX "BIOS error: " -#define VERSION "version 2.00.00" +#define VERSION "version 2.20.00"#include "powernow-k8.h" /* serialize freq changes */
@@ -73,33 +73,11 @@ static u32 find_khz_freq_from_fid(u32 fireturn 1000 *find_freq_from_fid (fid); } -/* Return a frequency in MHz, given an input fid and did */ -static u32 find_freq_from_fiddid (u32 fid,u32 did) +static u32 find_khz_freq_from_pstate (struct cpufreq_frequency_table *data,u32 pstate) { -if (current_cpu_data.x86 ==0x10 ) -return 100 * (fid +0x10 ) >> did; -else -return 100 * (fid +0x8 ) >> 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 ; +return data[pstate].frequency; } -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 *
@@ -142,9 +120,7 @@ static int query_current_values_with_penif (cpu_family ==CPU_HW_PSTATE ) {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 ; + data->currpstate = i;return 0 ; } do {
@@ -295,7 +271,7 @@ static int decrease_vid_code_by_step(strstatic int transition_pstate (struct powernow_k8_data *data,u32 pstate) {wrmsr (MSR_PSTATE_CTRL , pstate,0 ); - data->currfid =find_fid_from_pstate (pstate); + data->currpstate = pstate;return 0 ; }
@@ -845,17 +821,20 @@ err_out: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 , hi, lo); + data->max_hw_pstate = (hi &HW_PSTATE_MAX_MASK ) >>HW_PSTATE_MAX_SHIFT ;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 ) { +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"); + powernow_table[i].frequency =CPUFREQ_ENTRY_INVALID ; +continue ; }rdmsr (MSR_PSTATE_DEF_BASE + index, lo, hi);if (!(hi &HW_PSTATE_VALID_MASK )) {
@@ -864,22 +843,9 @@ static int fill_powernow_table_pstate(stcontinue ; } - fid = lo &HW_PSTATE_FID_MASK ; - did = (lo &HW_PSTATE_DID_MASK ) >>HW_PSTATE_DID_SHIFT ; + powernow_table[i].index = index; -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 ; - } + powernow_table[i].frequency = data->acpi_data.states[i].core_frequency *1000 ; }return 0 ; }
@@ -1020,8 +986,6 @@ static int transition_frequency_fidvid(s/* 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;
@@ -1030,12 +994,10 @@ static int transition_frequency_pstate(s/* get fid did for hardware pstate transition */ pstate = index &HW_PSTATE_MASK ; -if (pstate >MAX_HW_PSTATE ) +if (pstate > data->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); + 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_mask (i, *(data->available_cores)) { freqs.cpu = i;
@@ -1043,9 +1005,7 @@ static int transition_frequency_pstate(s } 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); + freqs.new =find_khz_freq_from_pstate (data->powernow_table, pstate);for_each_cpu_mask (i, *(data->available_cores)) { freqs.cpu = i;
@@ -1124,7 +1084,7 @@ static int powernowk8_target(struct cpufmutex_unlock (&fidvid_mutex);if (cpu_family ==CPU_HW_PSTATE ) - pol->cur =find_khz_freq_from_fiddid (data->currfid, data->currdid); + pol->cur =find_khz_freq_from_pstate (data->powernow_table, newstate);else pol->cur =find_khz_freq_from_fid (data->currfid); ret =0 ;
@@ -1223,7 +1183,7 @@ static int __cpuinit powernowk8_cpu_init + (3 * (1 << data->irt) * 10)) * 1000;if (cpu_family ==CPU_HW_PSTATE ) - pol->cur =find_khz_freq_from_fiddid (data->currfid, data->currdid); + pol->cur =find_khz_freq_from_pstate (data->powernow_table, data->currpstate);else pol->cur =find_khz_freq_from_fid (data->currfid);dprintk ("policy current frequency %d kHz\n" , pol->cur);
@@ -1240,8 +1200,7 @@ static int __cpuinit powernowk8_cpu_initcpufreq_frequency_table_get_attr (data->powernow_table, pol->cpu);if (cpu_family ==CPU_HW_PSTATE ) -dprintk ("cpu_init done, current fid 0x%x, did 0x%x\n" , - data->currfid, data->currdid); +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);
@@ -1297,7 +1256,7 @@ static unsigned int powernowk8_get (unsi goto out;if (cpu_family ==CPU_HW_PSTATE ) - khz =find_khz_freq_from_fiddid (data->currfid, data->currdid); + khz =find_khz_freq_from_pstate (data->powernow_table, data->currpstate);else khz =find_khz_freq_from_fid (data->currfid);
arch/i386/kernel/cpu/cpufreq/powernow-k8.h +6 -14
@@ -10,6 +10,7 @@ struct powernow_k8_data {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
@@ -21,8 +22,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 or did */ -u32 currvid, currfid, currdid; +/* keep track of the current fid / vid or pstate */ +u32 currvid, currfid, 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.
@@ -87,23 +88,14 @@ struct powernow_k8_data {/* 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 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
Quoted 8 lines · Mark Langsdorf
This patch should apply cleanly to the 2.6.23-rc8-mm2 kernel. It changes the powernow-k8 driver code that deals with 3rd generation Opteron, Phenom, and later processors to match the architectual pstate driver described in the AMD64 Architecture Programmer's Manual Volume 2 Chapter 18. The initial implementation of the hardware pstate driver for PowerNow! used some processor-version specific features, and would not be maintainable in the long term as the processor features changed. This architectural driver should work on all future AMD processors.
Has this been tested on older implementations of powernow yet? I'm happy to merge this and give it some time in -mm, before it goes to mainline, but if no-one is testing on those older opterons/turions etc then we're not going to know we regressed
until its too late. If it hasn't been tested yet, any chance
you can scrounge some up at AMD and give it a spin just to be sure?
Thanks,
Dave
Signature · 1 line
http://www.codemonkey.org.uk
Quoted 10 lines · Dave Jones
Quoted 8 lines · Mark Langsdorf
This patch should apply cleanly to the 2.6.23-rc8-mm2 kernel. It changes the powernow-k8 driver code that deals with 3rd generation Opteron, Phenom, and later processors to match the architectual pstate driver described in the AMD64 Architecture Programmer's Manual Volume 2 Chapter 18. The initial implementation of the hardware pstate driver for PowerNow! used some processor-version specific features, and would not be maintainable in the long term as the processor features changed. This architectural driver should work on all future AMD processors.
Quoted 6 lines
Has this been tested on older implementations of powernow yet? I'm happy to merge this and give it some time in -mm, before it goes to mainline, but if no-one is testing on those older opterons/turions etc then we're not going to know we regressed
until its too late. If it hasn't been tested yet, any chance
you can scrounge some up at AMD and give it a spin just to be sure?
I'd like to see this driver in the next kernel release.
So I have done some tests with this code - based on kernel version 2.6.23. I have tested it on Athlon 64 X2, Athlon 64, Turion X2 and some other parts (e.g.family 0x10) and with different cpufreq governors.
I did not observe any problems with this driver update. Behaviour is the same as before.
I just had to fix one minor compile error.
So please consider to add the attached patch for 2.6.24. Patch is against current Linus' git tree. This means the patch "[CPUFREQ] Support different families in fid/did to frequency conversion" which is contained in the cpufreq.git should be ommitted. The issue fixed with that patch is solved with this driver update, too.
If you need a patch against the x86 tree I can provide one as well.
Thanks and Regards,
Andreas
--
[PATCH] architectural pstate driver for powernow-k8
This changes the powernow-k8 driver code that deals with 3rd generation Opteron, Phenom, and later processors to match the architectual pstate driver described in the AMD64 Architecture Programmer's Manual Volume 2 Chapter The initial implementation of the hardware pstate driver for PowerNow! used some processor-version specific features, and would not be maintainable in the long term as the processor features changed. This architectural driver should work on all future AMD processors.
--- arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 85 ++++++++-------------------- arch/i386/kernel/cpu/cpufreq/powernow-k8.h | 20 ++----- 2 files changed, 29 insertions(+), 76 deletions(-)
arch/i386/kernel/cpu/cpufreq/powernow-k8.c +23 -62
@@ -46,7 +46,7 @@#define PFX "powernow-k8: "#define BFX PFX "BIOS error: " -#define VERSION "version 2.00.00" +#define VERSION "version 2.20.00"#include "powernow-k8.h" /* serialize freq changes */
@@ -73,29 +73,9 @@ static u32 find_khz_freq_from_fid(u32 fid)return 1000 *find_freq_from_fid (fid); } -/* Return a frequency in MHz, given an input fid and did */ -static u32 find_freq_from_fiddid (u32 fid,u32 did) +static u32 find_khz_freq_from_pstate (struct cpufreq_frequency_table *data,u32 pstate) { -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 data[pstate].frequency; }/* Return the vco fid for an input fid
@@ -139,9 +119,7 @@ static int query_current_values_with_pending_wait(struct powernow_k8_data *data)if (cpu_family ==CPU_HW_PSTATE ) {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 ; + data->currpstate = i;return 0 ; } do {
@@ -292,7 +270,7 @@ static int decrease_vid_code_by_step(struct powernow_k8_data *data, u32 reqvid,static int transition_pstate (struct powernow_k8_data *data,u32 pstate) {wrmsr (MSR_PSTATE_CTRL , pstate,0 ); - data->currfid =find_fid_from_pstate (pstate); + data->currpstate = pstate;return 0 ; }
@@ -842,17 +820,20 @@ err_out: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 , hi, lo); + data->max_hw_pstate = (hi &HW_PSTATE_MAX_MASK ) >>HW_PSTATE_MAX_SHIFT ;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 ) { +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"); + powernow_table[i].frequency =CPUFREQ_ENTRY_INVALID ; +continue ; }rdmsr (MSR_PSTATE_DEF_BASE + index, lo, hi);if (!(hi &HW_PSTATE_VALID_MASK )) {
@@ -861,22 +842,9 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufcontinue ; } - fid = lo &HW_PSTATE_FID_MASK ; - did = (lo &HW_PSTATE_DID_MASK ) >>HW_PSTATE_DID_SHIFT ; + powernow_table[i].index = index; -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 ; - } + powernow_table[i].frequency = data->acpi_data.states[i].core_frequency *1000 ; }return 0 ; }
@@ -1017,8 +985,6 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data, unsigned i/* 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;
@@ -1027,12 +993,10 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned i/* get fid did for hardware pstate transition */ pstate = index &HW_PSTATE_MASK ; -if (pstate >MAX_HW_PSTATE ) +if (pstate > data->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); + 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_mask (i, *(data->available_cores)) { freqs.cpu = i;
@@ -1040,9 +1004,7 @@ static int transition_frequency_pstate(struct powernow_k8_data *data, unsigned i } 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); + freqs.new =find_khz_freq_from_pstate (data->powernow_table, pstate);for_each_cpu_mask (i, *(data->available_cores)) { freqs.cpu = i;
@@ -1088,8 +1050,8 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi goto err_out;if (cpu_family ==CPU_HW_PSTATE ) -dprintk ("targ: curr fid 0x%x, did 0x%x\n" , - data->currfid, data->currdid); +dprintk ("cpu_init done, current pstate 0x%x\n" , + data->currpstate);else {dprintk ("targ: curr fid 0x%x, vid 0x%x\n" , data->currfid, data->currvid);
@@ -1121,7 +1083,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsimutex_unlock (&fidvid_mutex);if (cpu_family ==CPU_HW_PSTATE ) - pol->cur =find_khz_freq_from_fiddid (data->currfid, data->currdid); + pol->cur =find_khz_freq_from_pstate (data->powernow_table, newstate);else pol->cur =find_khz_freq_from_fid (data->currfid); ret =0 ;
@@ -1221,7 +1183,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) + (3 * (1 << data->irt) * 10)) * 1000;if (cpu_family ==CPU_HW_PSTATE ) - pol->cur =find_khz_freq_from_fiddid (data->currfid, data->currdid); + pol->cur =find_khz_freq_from_pstate (data->powernow_table, data->currpstate);else pol->cur =find_khz_freq_from_fid (data->currfid);dprintk ("policy current frequency %d kHz\n" , pol->cur);
@@ -1238,8 +1200,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)cpufreq_frequency_table_get_attr (data->powernow_table, pol->cpu);if (cpu_family ==CPU_HW_PSTATE ) -dprintk ("cpu_init done, current fid 0x%x, did 0x%x\n" , - data->currfid, data->currdid); +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);
@@ -1295,7 +1256,7 @@ static unsigned int powernowk8_get (unsigned int cpu) goto out;if (cpu_family ==CPU_HW_PSTATE ) - khz =find_khz_freq_from_fiddid (data->currfid, data->currdid); + khz =find_khz_freq_from_pstate (data->powernow_table, data->currpstate);else khz =find_khz_freq_from_fid (data->currfid);
arch/i386/kernel/cpu/cpufreq/powernow-k8.h +6 -14
@@ -10,6 +10,7 @@ struct powernow_k8_data {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
@@ -21,8 +22,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 or did */ -u32 currvid, currfid, currdid; +/* keep track of the current fid / vid or pstate */ +u32 currvid, currfid, 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.
@@ -87,23 +88,14 @@ struct powernow_k8_data {/* 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 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
Signature · 1 line
1.5.3.4
Quoted 9 lines
Quoted 6 lines
Has this been tested on older implementations of powernow yet? I'm happy to merge this and give it some time in -mm, before it goes to mainline, but if no-one is testing on those older opterons/turions etc then we're not going to know we regressed
until its too late. If it hasn't been tested yet, any chance
you can scrounge some up at AMD and give it a spin just to be sure?I'd like to see this driver in the next kernel release.
Thanks, Andreas.
Quoted 6 lines
So I have done some tests with this code - based on kernel version 2.6.23. I have tested it on Athlon 64 X2, Athlon 64, Turion X2 and some other parts
(e.g.family0x10) and with different cpufreq governors. I did not observe any problems with this driver update. Behaviour is the same as before.
I've also been running it on my Turion X2 laptop for a few weeks without issues. It doesn't touch the legacy code path at all.
Quoted 6 lines
So please consider to add the attached patch for 2.6.24. Patch is against current Linus' git tree. This means the patch "[CPUFREQ] Support different families in fid/did to frequency conversion" which is contained in the cpufreq.git should be ommitted. The issue fixed with that patch is solved with this driver update, too.
Either patch is acceptable; I think they're fundamentally identical anyway.
-Mark Langsdorf
Operating System Research Center
AMD
Quoted 26 lines · Mark Langsdorf
Quoted 7 lines · Andi Kleen
Quoted 1 line · Mark Langsdorf
This patch should apply cleanly to the 2.6.22.6 kernel.
Isn't that a little old? The earliest this could be merged is the upcomming 2.6.24 tree. Best you submit it against .23 or better -mm.
Good point.
This patch should apply cleanly to the 2.6.23-rc8-mm2 kernel. It changes the powernow-k8 driver code that deals with 3rd generation Opteron, Phenom, and later processors to match the architectual pstate driver described in the AMD64 Architecture Programmer's Manual Volume 2 Chapter 18. The initial implementation of the hardware pstate driver for PowerNow! used some processor-version specific features, and would not be maintainable in the long term as the processor features changed. This architectural driver should work on all future AMD processors.
-Mark Langsdorf
Operating System Resarch Center
AMDSigned-off-by <[email protected]>
Acked-by <[email protected]>
[...]
arch/i386/kernel/cpu/cpufreq/powernow-k8.c static int transition_frequency_pstate(s · line 998
Quoted 5 lines
arch/i386/kernel/cpu/cpufreq/powernow-k8.c +1
-1/* get fid did for hardware pstate transition */ pstate = index &HW_PSTATE_MASK ; -if (pstate >MAX_HW_PSTATE ) +if (pstate > data->max_hw_pstate);return 0 ;
checkpatch picked up this dodgy if. I suspect that the ';' is wrong from the context.
arch/i386/kernel/cpu/cpufreq/powernow-k8.c static int transition_frequency_pstate(s · line 1000
Quoted 6 lines
arch/i386/kernel/cpu/cpufreq/powernow-k8.c +2
-4- 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); + freqs.old =find_khz_freq_from_pstate (data->powernow_table, data->currpstate); + freqs.new =find_khz_freq_from_pstate (data->powernow_table, pstate);
-apw
Quoted 8 lines · Andy Whitcroft
arch/i386/kernel/cpu/cpufreq/powernow-k8.c static int transition_frequency_pstate(s · line 998
Quoted 5 lines
arch/i386/kernel/cpu/cpufreq/powernow-k8.c +1
-1/* get fid did for hardware pstate transition */ pstate = index &HW_PSTATE_MASK ; -if (pstate >MAX_HW_PSTATE ) +if (pstate > data->max_hw_pstate);return 0 ;checkpatch picked up this dodgy if. I suspect that the ';' is wrong from the context.
Indeed. Mark/Andreas, want to send me a new patch against latest Linus HEAD ? I didn't apply the old one yet, as it conflicted with the changes already queued for merging.
Thanks,
Dave
Signature · 1 line
http://www.codemonkey.org.uk
PATCH 1/1 architectural pstate driver for powernow-k8
Quoted 11 lines · Dave Jones
Quoted 8 lines · Andy Whitcroft
Review
Quoted 5 lines
(quoted diff) +1
-1/* get fid did for hardware pstate transition */ pstate = index & HW_PSTATE_MASK; - if (pstate > MAX_HW_PSTATE) + if (pstate > data->max_hw_pstate); return 0;checkpatch picked up this dodgy if. I suspect that the ';' is wrong from the context.
Quoted 3 lines
Indeed. Mark/Andreas, want to send me a new patch against latest Linus HEAD ? I didn't apply the old one yet, as it conflicted with the changes already queued for merging.
This is against -git7. I should think that's close enough.
This patch should apply cleanly to the 2.6.23-git7 kernel. It changes the powernow-k8 driver code that deals with 3rd generation Opteron, Phenom, and later processors to match the architectural pstate driver described in the AMD64 Architecture Programmer's Manual Volume 2 Chapter 18. The initial implementation of the hardware pstate driver for PowerNow! used some processor-version specific features, and would not be maintainable in the long term as the processor features changed. This architectural driver should work on all future AMD processors.
arch/x86/kernel/cpu/cpufreq/powernow-k8.c +22 -63
@@ -46,7 +46,7 @@#define PFX "powernow-k8: "#define BFX PFX "BIOS error: " -#define VERSION "version 2.00.00" +#define VERSION "version 2.20.00"#include "powernow-k8.h" /* serialize freq changes */
@@ -73,33 +73,11 @@ static u32 find_khz_freq_from_fid(u32 fireturn 1000 *find_freq_from_fid (fid); } -/* Return a frequency in MHz, given an input fid and did */ -static u32 find_freq_from_fiddid (u32 fid,u32 did) +static u32 find_khz_freq_from_pstate (struct cpufreq_frequency_table *data,u32 pstate) { -if (current_cpu_data.x86 ==0x10 ) -return 100 * (fid +0x10 ) >> did; -else -return 100 * (fid +0x8 ) >> 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 ; +return data[pstate].frequency; } -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 *
@@ -142,9 +120,7 @@ static int query_current_values_with_penif (cpu_family ==CPU_HW_PSTATE ) {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 ; + data->currpstate = i;return 0 ; } do {
@@ -295,7 +271,7 @@ static int decrease_vid_code_by_step(strstatic int transition_pstate (struct powernow_k8_data *data,u32 pstate) {wrmsr (MSR_PSTATE_CTRL , pstate,0 ); - data->currfid =find_fid_from_pstate (pstate); + data->currpstate = pstate;return 0 ; }
@@ -845,17 +821,20 @@ err_out: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 , hi, lo); + data->max_hw_pstate = (hi &HW_PSTATE_MAX_MASK ) >>HW_PSTATE_MAX_SHIFT ;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 ) { +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"); + powernow_table[i].frequency =CPUFREQ_ENTRY_INVALID ; +continue ; }rdmsr (MSR_PSTATE_DEF_BASE + index, lo, hi);if (!(hi &HW_PSTATE_VALID_MASK )) {
@@ -864,22 +843,9 @@ static int fill_powernow_table_pstate(stcontinue ; } - fid = lo &HW_PSTATE_FID_MASK ; - did = (lo &HW_PSTATE_DID_MASK ) >>HW_PSTATE_DID_SHIFT ; + powernow_table[i].index = index; -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 ; - } + powernow_table[i].frequency = data->acpi_data.states[i].core_frequency *1000 ; }return 0 ; }
@@ -1020,22 +986,18 @@ static int transition_frequency_fidvid(s/* 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 */ +/* get MSR index for hardware pstate transition */ pstate = index &HW_PSTATE_MASK ; -if (pstate >MAX_HW_PSTATE ) +if (pstate > data->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); + 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_mask (i, *(data->available_cores)) { freqs.cpu = i;
@@ -1043,9 +1005,7 @@ static int transition_frequency_pstate(s } 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); + freqs.new =find_khz_freq_from_pstate (data->powernow_table, pstate);for_each_cpu_mask (i, *(data->available_cores)) { freqs.cpu = i;
@@ -1124,7 +1084,7 @@ static int powernowk8_target(struct cpufmutex_unlock (&fidvid_mutex);if (cpu_family ==CPU_HW_PSTATE ) - pol->cur =find_khz_freq_from_fiddid (data->currfid, data->currdid); + pol->cur =find_khz_freq_from_pstate (data->powernow_table, newstate);else pol->cur =find_khz_freq_from_fid (data->currfid); ret =0 ;
@@ -1223,7 +1183,7 @@ static int __cpuinit powernowk8_cpu_init + (3 * (1 << data->irt) * 10)) * 1000;if (cpu_family ==CPU_HW_PSTATE ) - pol->cur =find_khz_freq_from_fiddid (data->currfid, data->currdid); + pol->cur =find_khz_freq_from_pstate (data->powernow_table, data->currpstate);else pol->cur =find_khz_freq_from_fid (data->currfid);dprintk ("policy current frequency %d kHz\n" , pol->cur);
@@ -1240,8 +1200,7 @@ static int __cpuinit powernowk8_cpu_initcpufreq_frequency_table_get_attr (data->powernow_table, pol->cpu);if (cpu_family ==CPU_HW_PSTATE ) -dprintk ("cpu_init done, current fid 0x%x, did 0x%x\n" , - data->currfid, data->currdid); +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);
@@ -1297,7 +1256,7 @@ static unsigned int powernowk8_get (unsi goto out;if (cpu_family ==CPU_HW_PSTATE ) - khz =find_khz_freq_from_fiddid (data->currfid, data->currdid); + khz =find_khz_freq_from_pstate (data->powernow_table, data->currpstate);else khz =find_khz_freq_from_fid (data->currfid);
arch/x86/kernel/cpu/cpufreq/powernow-k8.h +6 -14
@@ -10,6 +10,7 @@ struct powernow_k8_data {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
@@ -21,8 +22,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 or did */ -u32 currvid, currfid, currdid; +/* keep track of the current fid / vid or pstate */ +u32 currvid, currfid, 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.
@@ -87,23 +88,14 @@ struct powernow_k8_data {/* 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 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
Quoted 9 lines · Mark Langsdorf
Quoted 8 lines · Dave Jones
Quoted 6 lines · Andy Whitcroft
Quoted 5 lines
arch/x86/kernel/cpu/cpufreq/powernow-k8.c +1
-1/* get fid did for hardware pstate transition */ pstate = index &HW_PSTATE_MASK ; -if (pstate >MAX_HW_PSTATE ) +if (pstate > data->max_hw_pstate);return 0 ;
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
checkpatch picked up this dodgy if. I suspect that the ';' is wrong from the context.
Indeed. Mark/Andreas, want to send me a new patch against latest Linus HEAD ? I didn't apply the old one yet, as it conflicted with the changes already queued for merging.
This is against -git7. I should think that's close enough.
So close!
arch/x86/kernel/cpu/cpufreq/powernow-k8.c: In function ‘powernowk8_target’:arch/x86/kernel/cpu/cpufreq/powernow-k8.c:1054: error: ‘struct powernow_k8_data’ has no member named ‘currdid’ make[1]: *** [arch/x86/kernel/cpu/cpufreq/powernow-k8.o] Error 1
make: *** [arch/x86/kernel/cpu/cpufreq/powernow-k8.o] Error 2
Missed one of the conversions?
Dave
Signature · 1 line
http://www.codemonkey.org.uk
This patch should apply cleanly to the 2.6.23-git7 kernel. It changes the powernow-k8 driver code that deals with 3rd generation Opteron, Phenom, and later processors to match the architectural pstate driver described in the AMD64 Architecture Programmer's Manual Volume 2 Chapter 18. The initial implementation of the hardware pstate driver for PowerNow! used some processor-version specific features, and would not be maintainable in the long term as the processor features changed. This architectural driver should work on all future AMD processors.
arch/x86/kernel/cpu/cpufreq/powernow-k8.c +23 -67
@@ -46,7 +46,7 @@#define PFX "powernow-k8: "#define BFX PFX "BIOS error: " -#define VERSION "version 2.00.00" +#define VERSION "version 2.20.00"#include "powernow-k8.h" /* serialize freq changes */
@@ -73,33 +73,11 @@ static u32 find_khz_freq_from_fid(u32 fireturn 1000 *find_freq_from_fid (fid); } -/* Return a frequency in MHz, given an input fid and did */ -static u32 find_freq_from_fiddid (u32 fid,u32 did) +static u32 find_khz_freq_from_pstate (struct cpufreq_frequency_table *data,u32 pstate) { -if (current_cpu_data.x86 ==0x10 ) -return 100 * (fid +0x10 ) >> did; -else -return 100 * (fid +0x8 ) >> 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 ; +return data[pstate].frequency; } -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 *
@@ -142,9 +120,7 @@ static int query_current_values_with_penif (cpu_family ==CPU_HW_PSTATE ) {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 ; + data->currpstate = i;return 0 ; } do {
@@ -295,7 +271,7 @@ static int decrease_vid_code_by_step(strstatic int transition_pstate (struct powernow_k8_data *data,u32 pstate) {wrmsr (MSR_PSTATE_CTRL , pstate,0 ); - data->currfid =find_fid_from_pstate (pstate); + data->currpstate = pstate;return 0 ; }
@@ -845,17 +821,20 @@ err_out: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 , hi, lo); + data->max_hw_pstate = (hi &HW_PSTATE_MAX_MASK ) >>HW_PSTATE_MAX_SHIFT ;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 ) { +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"); + powernow_table[i].frequency =CPUFREQ_ENTRY_INVALID ; +continue ; }rdmsr (MSR_PSTATE_DEF_BASE + index, lo, hi);if (!(hi &HW_PSTATE_VALID_MASK )) {
@@ -864,22 +843,9 @@ static int fill_powernow_table_pstate(stcontinue ; } - fid = lo &HW_PSTATE_FID_MASK ; - did = (lo &HW_PSTATE_DID_MASK ) >>HW_PSTATE_DID_SHIFT ; + powernow_table[i].index = index; -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 ; - } + powernow_table[i].frequency = data->acpi_data.states[i].core_frequency *1000 ; }return 0 ; }
@@ -1020,22 +986,18 @@ static int transition_frequency_fidvid(s/* 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 */ +/* get MSR index for hardware pstate transition */ pstate = index &HW_PSTATE_MASK ; -if (pstate >MAX_HW_PSTATE ) +if (pstate > data->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); + 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_mask (i, *(data->available_cores)) { freqs.cpu = i;
@@ -1043,9 +1005,7 @@ static int transition_frequency_pstate(s } 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); + freqs.new =find_khz_freq_from_pstate (data->powernow_table, pstate);for_each_cpu_mask (i, *(data->available_cores)) { freqs.cpu = i;
@@ -1090,10 +1050,7 @@ static int powernowk8_target(struct cpufif (query_current_values_with_pending_wait (data)) goto err_out; -if (cpu_family ==CPU_HW_PSTATE ) -dprintk ("targ: curr fid 0x%x, did 0x%x\n" , - data->currfid, data->currdid); -else { +if (cpu_family !=CPU_HW_PSTATE ) {dprintk ("targ: curr fid 0x%x, vid 0x%x\n" , data->currfid, data->currvid);
@@ -1124,7 +1081,7 @@ static int powernowk8_target(struct cpufmutex_unlock (&fidvid_mutex);if (cpu_family ==CPU_HW_PSTATE ) - pol->cur =find_khz_freq_from_fiddid (data->currfid, data->currdid); + pol->cur =find_khz_freq_from_pstate (data->powernow_table, newstate);else pol->cur =find_khz_freq_from_fid (data->currfid); ret =0 ;
@@ -1223,7 +1180,7 @@ static int __cpuinit powernowk8_cpu_init + (3 * (1 << data->irt) * 10)) * 1000;if (cpu_family ==CPU_HW_PSTATE ) - pol->cur =find_khz_freq_from_fiddid (data->currfid, data->currdid); + pol->cur =find_khz_freq_from_pstate (data->powernow_table, data->currpstate);else pol->cur =find_khz_freq_from_fid (data->currfid);dprintk ("policy current frequency %d kHz\n" , pol->cur);
@@ -1240,8 +1197,7 @@ static int __cpuinit powernowk8_cpu_initcpufreq_frequency_table_get_attr (data->powernow_table, pol->cpu);if (cpu_family ==CPU_HW_PSTATE ) -dprintk ("cpu_init done, current fid 0x%x, did 0x%x\n" , - data->currfid, data->currdid); +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);
@@ -1297,7 +1253,7 @@ static unsigned int powernowk8_get (unsi goto out;if (cpu_family ==CPU_HW_PSTATE ) - khz =find_khz_freq_from_fiddid (data->currfid, data->currdid); + khz =find_khz_freq_from_pstate (data->powernow_table, data->currpstate);else khz =find_khz_freq_from_fid (data->currfid);
arch/x86/kernel/cpu/cpufreq/powernow-k8.h +6 -14
@@ -10,6 +10,7 @@ struct powernow_k8_data {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
@@ -21,8 +22,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 or did */ -u32 currvid, currfid, currdid; +/* keep track of the current fid / vid or pstate */ +u32 currvid, currfid, 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.
@@ -87,23 +88,14 @@ struct powernow_k8_data {/* 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 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
Quoted 11 lines · Mark Langsdorf
This patch should apply cleanly to the 2.6.23-git7 kernel. It changes the powernow-k8 driver code that deals with 3rd generation Opteron, Phenom, and later processors to match the architectural pstate driver described in the AMD64 Architecture Programmer's Manual Volume 2 Chapter 18. The initial implementation of the hardware pstate driver for PowerNow! used some processor-version specific features, and would not be maintainable in the long term as the processor features changed. This architectural driver should work on all future AMD processors.
Signed-off-by Mark Langsdorf <[email protected]>Signed-off-by Andreas Herrmann <[email protected]>
MIME damaged, can't apply.
Dave
Signature · 1 line
http://www.codemonkey.org.uk