powernow-k7 acpi support.
PATCH 1/1 powernow-k7 acpi support.
Hi Dave, Dominik, list,
Since now linux-2.6 bk tree do have necessary patches from Dominik for, this is a possible version in order to get the powernow table from ACPI, if the legacy method fail, or if the laptop is blacklisted. The following patch do only include the static function powernow_acpi_init() that have to be called in order to get the config stuff from acpi.
By now, there are different ways to use it. The present patch do not include any of them.
1- Include the powernow_acpi_init() as the first call in powernow_decode_bios(), so that ACPI is used first, then if it failed, the legacy method is used,
or
2- Include the powernow_acpi_init() at powernow_decode_bios() just before the 3 printk's stating to write that you should see
http://www.codemonkey.org.uk/projects/cpufreq/...
I guess 2- is 'better', but I would like to get some thought, though.
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +120 -0
@@ -27,6 +27,11 @@#include <asm/io.h> #include <asm/system.h> +#ifdef CONFIG_ACPI_PROCESSOR +#include <linux/acpi.h> +#include <acpi/processor.h> +#endif +#include "powernow-k7.h" #define DEBUG
@@ -57,6 +62,17 @@u8 numpstates; }; +#ifdef CONFIG_ACPI_PROCESSOR +union powernow_acpi_control_t { +struct { +unsigned long fid:5 , + vid:5 , + sgtc:20 , + res1:2 ; + } bits; +unsigned long val; +}; +#endif /* divide by 1000 to get VID. */ static int mobile_vid_table[32 ] = {
@@ -309,6 +325,110 @@return 0 ; } +#ifdef CONFIG_ACPI_PROCESSOR + +static int powernow_acpi_init (void ) +{ +int i; +int retval =0 ; +struct acpi_pct_register *r; +struct acpi_processor_performance p; + +memset (&p,0 ,sizeof (p)); + +if (powernow_table !=NULL ) +return -EINVAL ; + +printk ("1\n" ); +if (acpi_processor_register_performance (&p,0 )) +return -EIO ; +printk ("2\n" ); + + r = &p.control_register; +if (r->space_id !=ACPI_ADR_SPACE_FIXED_HARDWARE ) { + retval = -ENODEV ; + goto out; + } + r = &p.status_register; +if (r->space_id !=ACPI_ADR_SPACE_FIXED_HARDWARE ) { + retval = -ENODEV ; + goto out; + } + + number_scales = p.state_count; + +if (number_scales <2 ) { + retval = -ENODEV ; + goto out; + } + + powernow_table =kmalloc ((number_scales +1 ) * (sizeof (struct cpufreq_frequency_table )),GFP_KERNEL ); +if (!powernow_table) { + retval = -ENOMEM ; + goto out; + } + +memset (powernow_table,0 , ((number_scales +1 ) *sizeof (struct cpufreq_frequency_table ))); + + fsb =100 ;/* XXX fix me */ + latency =10000 ;/* XXX don't trust bios writers.. */ + +for (i =0 ; i < number_scales; i++) { +union powernow_acpi_control_t pc; +u8 fid, vid; +unsigned int speed; + + pc.val = (unsigned long ) p.states[i].control; + dprintk (KERN_INFO PFX "acpi: P%d: %d MHz, %d mW, %d uS, control %08x, status %08x, vid: %02x fid: %02x SGTC: %d\n", + i, + (u32 ) p.states[i].core_frequency, + (u32 ) p.states[i].power, + (u32 ) p.states[i].transition_latency, + (u32 ) p.states[i].control, + (u32 ) p.states[i].status, + pc.bits.vid, + pc.bits.fid, + pc.bits.sgtc); + + vid = pc.bits.vid; + fid = pc.bits.fid; + + powernow_table[i].frequency = fsb * fid_codes[fid] *100 ; + powernow_table[i].index = fid;/* lower 8 bits */ + powernow_table[i].index |= (vid <<8 );/* upper 8 bits */ + + speed = fsb * (fid_codes[fid]/10 ); +if ((fid_codes[fid] %10 )==5 ) { + speed += fsb/2 ; +if (have_a0 ==1 ) + powernow_table[i].frequency =CPUFREQ_ENTRY_INVALID ; + } + + dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, + fid_codes[fid] / 10, fid_codes[fid] % 10, speed); +dprintk ("VID: 0x%x (%d.%03dV)\n" , vid, mobile_vid_table[vid]/1000 , + mobile_vid_table[vid]%1000 ); + +if (speed < minimum_speed) + minimum_speed = speed; +if (speed > maximum_speed) + maximum_speed = speed; + } + powernow_table[i].frequency =CPUFREQ_TABLE_END ; + powernow_table[i].index =0 ; + +/* +* We don't need no more acpi. +* XXX is that true? +*/ + +out: +acpi_processor_unregister_performance (&p,0 ); + +return retval; +} +#endif +static int powernow_decode_bios (int maxfid,int startvid) {struct psb_s *psb;
Signature · 4 lines
Bruno Ducrot -- Which is worse: ignorance or apathy? -- Don't know. Don't care.
Quoted 9 lines
1- Include the
powernow_acpi_init()as the first call inpowernow_decode_bios(), so that ACPI is used first, then if it failed, the legacy method is used,
or
2- Include thepowernow_acpi_init()atpowernow_decode_bios()just before the 3 printk's stating to write that you should see
http://www.codemonkey.org.uk/projects/cpufreq/...I guess 2- is 'better', but I would like to get some thought, though.
Hm. That's difficult to decide, also for the speedstep-centrino case... I'd like to hear some opinions from ACPI and AMD guys first before we decide...
arch/i386/kernel/cpu/cpufreq/powernow-k7.c line 348
Quoted 7 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +7
-0+printk ("1\n" ); +if (acpi_processor_register_performance (&p,0 )) +return -EIO ; +printk ("2\n" ); + + r = &p.control_register; +if (r->space_id !=ACPI_ADR_SPACE_FIXED_HARDWARE ) {
How about
if (p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) {?
arch/i386/kernel/cpu/cpufreq/powernow-k7.c line 353
Quoted 5 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +5
-0+ retval = -ENODEV ; + goto out; + } + r = &p.status_register; +if (r->space_id !=ACPI_ADR_SPACE_FIXED_HARDWARE ) {
same here...
arch/i386/kernel/cpu/cpufreq/powernow-k7.c line 373
Quoted 1 line
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +1
-0+ fsb =100 ;/* XXX fix me */
Any idea on how to determine the FSB?
arch/i386/kernel/cpu/cpufreq/powernow-k7.c line 374
Quoted 1 line
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +1
-0+ latency =10000 ;/* XXX don't trust bios writers.. */
heh...
arch/i386/kernel/cpu/cpufreq/powernow-k7.c line 423
Quoted 4 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +4
-0+/* +* We don't need no more acpi. +* XXX is that true? +*/
No, it's not true. If we use ACPI, we need to keep it registered until we stop using it. Reasons:
- keep buggy drivers from interfering [e.g. other cpufreq drivers which register with ACPI first and with cpufreq later, or avoid registering with cpufreq because of being proprietary...]
- honor _PPC limits
- allow for ACPI interface (additions):
This includes the /proc/acpi/processor/./performance interface which people still tend to use, and additions to /sys/devices/system/cpu/cpu0/cpufreq/ still to be written.
Dominik
_______________________________________________
Cpufreq mailing list
[email protected]
http://www.linux.org.uk/mailman/listinfo/cpufreq
Quoted 8 lines · Dominik Brodowski
Quoted 8 lines
1- Include the
powernow_acpi_init()as the first call inpowernow_decode_bios(), so that ACPI is used first, then if it failed, the legacy method is used,
or
2- Include thepowernow_acpi_init()atpowernow_decode_bios()just before the 3 printk's stating to write that you should see
http://www.codemonkey.org.uk/projects/cpufreq/...
Quoted 4 lines
Quoted 1 line
I guess 2- is 'better', but I would like to get some thought, though.
Hm. That's difficult to decide, also for the speedstep-centrino case... I'd like to hear some opinions from ACPI and AMD guys first before we decide...
Well, ACPI guys would say you to use ACPI for, but I prefer the legacy method because otherwise I loose 3 power states ;)
Quoted 2 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c line 342
Quoted 2 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +1
-0+printk ("1\n" );
Sound like I forgot to remove that, sorry..
Quoted 9 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c line 348
Quoted 6 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +6
-0+if (acpi_processor_register_performance (&p,0 )) +return -EIO ; +printk ("2\n" ); + + r = &p.control_register; +if (r->space_id !=ACPI_ADR_SPACE_FIXED_HARDWARE ) {How about
if (p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) {
because I use p.control_register at least 2 times, and when that happens I prefer to introduce another variable, because it's more easier to read IMHO.
Quoted 8 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c line 353
Quoted 6 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +5
-0+ retval = -ENODEV ; + goto out; + } + r = &p.status_register; +if (r->space_id !=ACPI_ADR_SPACE_FIXED_HARDWARE ) {same here...
and that the second one ;)
Quoted 4 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c line 373
Quoted 2 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +1
-0+ fsb =100 ;/* XXX fix me */ Any idea on how to determine the FSB?
Unfortunately no. I don't have all the AMD processor specification for this.
Quoted 4 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c line 374
Quoted 2 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +1
-0+ latency =10000 ;/* XXX don't trust bios writers.. */ heh...
OK, I'm perhaps a little bit rude here. I will rewrite that.
Quoted 17 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c line 423
Quoted 5 lines
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +4
-0+/* +* We don't need no more acpi. +* XXX is that true? +*/ No, it's not true. If we use ACPI, we need to keep it registered until we stop using it. Reasons:
- keep buggy drivers from interfering [e.g. other cpufreq drivers which register with ACPI first and with cpufreq later, or avoid registering with cpufreq because of being proprietary...]
- honor_PPClimits
- allow for ACPI interface (additions):
This includes the/proc/acpi/processor/./performanceinterface which people still tend to use, and additions to/sys/devices/system/cpu/cpu0/cpufreq/still to be written.
Ok (actually, I don't think _PPC is supported on most K7 mobo, since it return 0 in almost all DSDT, but well, I should consider though in order to be fully ACPI compliant).
Thanks,
Signature · 4 lines
Bruno Ducrot -- Which is worse: ignorance or apathy? -- Don't know. Don't care.
Quoted 5 lines · Bruno Ducrot
Quoted 2 lines
How about
if (p.control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) {because I use p.control_register at least 2 times, and when that happens I prefer to introduce another variable, because it's more easier to read IMHO.
Actually, what I wrotte is stupid in that case, and that obfuscate more. I will do what you suggest.
Signature · 4 lines
Bruno Ducrot -- Which is worse: ignorance or apathy? -- Don't know. Don't care.
How about that one? By now, I'm a little puzzled with the fsb stuff, though. A first idea may be to look into what say ACPI about the frequency, and deduce the fsb from, but I don't like it.
arch/i386/kernel/cpu/cpufreq/powernow-k7.c renamed from powernow-k7.c +146 -0
@@ -27,6 +27,11 @@#include <asm/io.h> #include <asm/system.h> +#ifdef CONFIG_ACPI_PROCESSOR +#include <linux/acpi.h> +#include <acpi/processor.h> +#endif +#include "powernow-k7.h" #define DEBUG
@@ -57,6 +62,17 @@u8 numpstates; }; +#ifdef CONFIG_ACPI_PROCESSOR +union powernow_acpi_control_t { +struct { +unsigned long fid:5 , + vid:5 , + sgtc:20 , + res1:2 ; + } bits; +unsigned long val; +}; +#endif /* divide by 1000 to get VID. */ static int mobile_vid_table[32 ] = {
@@ -308,6 +325,132 @@return 0 ; } +#ifdef CONFIG_ACPI_PROCESSOR + +struct acpi_processor_performance *acpi_processor_perf; + +static int powernow_acpi_init (void ) +{ +int i; +int retval =0 ; + +if (acpi_processor_perf !=NULL ) +return -EINVAL ; + +if (powernow_table !=NULL ) +return -EINVAL ; + + acpi_processor_perf =kmalloc (sizeof (struct acpi_processor_performance ), +GFP_KERNEL ); + +if (!acpi_processor_perf) +return -ENOMEM ; + +memset (acpi_processor_perf,0 ,sizeof (struct acpi_processor_performance )); + +if (acpi_processor_register_performance (acpi_processor_perf,0 )) { + retval = -EIO ; + goto err1; + } + +if (acpi_processor_perf->control_register.space_id !=ACPI_ADR_SPACE_FIXED_HARDWARE ) { + retval = -ENODEV ; + goto err2; + } + +if (acpi_processor_perf->status_register.space_id !=ACPI_ADR_SPACE_FIXED_HARDWARE ) { + retval = -ENODEV ; + goto err2; + } + + number_scales = acpi_processor_perf->state_count; + +if (number_scales <2 ) { + retval = -ENODEV ; + goto err2; + } + + powernow_table =kmalloc ((number_scales +1 ) * (sizeof (struct cpufreq_frequency_table )),GFP_KERNEL ); +if (!powernow_table) { + retval = -ENOMEM ; + goto err2; + } + +memset (powernow_table,0 , ((number_scales +1 ) *sizeof (struct cpufreq_frequency_table ))); + + fsb =100 ;/* XXX fix me */ + latency =0 ; + +for (i =0 ; i < number_scales; i++) { +u8 fid, vid; +union powernow_acpi_control_t pc; +unsigned int speed; + + pc.val = (unsigned long ) acpi_processor_perf->states[i].control; + dprintk (KERN_INFO PFX "acpi: P%d: %d MHz, %d mW, %d uS, control %08x, status %08x, vid: %02x fid: %02x SGTC: %d\n", + i, + (u32 ) acpi_processor_perf->states[i].core_frequency, + (u32 ) acpi_processor_perf->states[i].power, + (u32 ) acpi_processor_perf->states[i].transition_latency, + (u32 ) acpi_processor_perf->states[i].control, + (u32 ) acpi_processor_perf->states[i].status, + pc.bits.vid, + pc.bits.fid, + pc.bits.sgtc); + + vid = pc.bits.vid; + fid = pc.bits.fid; + + powernow_table[i].frequency = fsb * fid_codes[fid] *100 ; + powernow_table[i].index = fid;/* lower 8 bits */ + powernow_table[i].index |= (vid <<8 );/* upper 8 bits */ + + speed = fsb * (fid_codes[fid]/10 ); +if ((fid_codes[fid] %10 )==5 ) { + speed += fsb/2 ; +if (have_a0 ==1 ) + powernow_table[i].frequency =CPUFREQ_ENTRY_INVALID ; + } + + dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, + fid_codes[fid] / 10, fid_codes[fid] % 10, speed); +dprintk ("VID: 0x%x (%d.%03dV)\n" , vid, mobile_vid_table[vid]/1000 , + mobile_vid_table[vid]%1000 ); + +if (latency < pc.bits.sgtc) + latency = pc.bits.sgtc; + +if (speed < minimum_speed) + minimum_speed = speed; +if (speed > maximum_speed) + maximum_speed = speed; + } + +/* Validate latency. The latency should be at least +* 10000 and must fit in a 20 bit register. +*/ +if ((latency & ((~((~0u ) <<20 )))) <10000 ) { + printk(KERN_WARNING PFX "broken latency in ACPI table.\n"); + printk(KERN_INFO PFX "ACPI set settling time to %d.%02d microseconds. " +"Should be at least 100. Correcting.\n" , + latency/100 , + latency%100); + latency =10000 ; + } + powernow_table[i].frequency =CPUFREQ_TABLE_END ; + powernow_table[i].index =0 ; + +return 0 ; + +err2: +acpi_processor_unregister_performance (acpi_processor_perf,0 ); +err1: +kfree (acpi_processor_perf); + acpi_processor_perf =NULL ; +return retval; +} +#endif +static int powernow_decode_bios (int maxfid,int startvid) {struct psb_s *psb;
@@ -640,6 +804,10 @@ static void __exit powernow_exit (void) { +if (acpi_processor_perf) { +acpi_processor_unregister_performance (acpi_processor_perf,0 ); +kfree (acpi_processor_perf); + }cpufreq_unregister_driver (&powernow_driver);if (powernow_table)kfree (powernow_table);
Signature · 4 lines
Bruno Ducrot -- Which is worse: ignorance or apathy? -- Don't know. Don't care.
Quoted 2 lines · Bruno Ducrot
How about that one?
Looks much better, IMO.
Quoted 3 lines
By now, I'm a little puzzled with the fsb stuff,
though. A first idea may be to look into what say ACPI about the frequency, and deduce the fsb from, but I don't like it.
So you wouldn't like
fsb = (acpi_processor_perf->states[i].core_frequency * 10) / fid_codes[fid]
? Why?
Dominik
_______________________________________________
Cpufreq mailing list
[email protected]
http://www.linux.org.uk/mailman/listinfo/cpufreq
Quoted 5 lines · Dominik Brodowski
Quoted 2 lines · Bruno Ducrot
How about that one?
Looks much better, IMO.
Thanks.
Quoted 10 lines
Quoted 4 lines
By now, I'm a little puzzled with the fsb stuff,
though. A first idea may be to look into what say ACPI about the frequency, and deduce the fsb from, but I don't like it.So you wouldn't like
fsb = (acpi_processor_perf->states[i].core_frequency * 10) / fid_codes[fid]? Why?
Because I would much prefer a generic function get_amd_fsb(), independant from bios.
Signature · 4 lines
Bruno Ducrot -- Which is worse: ignorance or apathy? -- Don't know. Don't care.
Quoted 1 line · Bruno Ducrot
Ok, you win. That one is ok ?
Looks good as well. All we have to decide is where to call these functions, though... and Davej has to decide whether he likes it, too :-)
Dominik
_______________________________________________
Cpufreq mailing list
[email protected]
http://www.linux.org.uk/mailman/listinfo/cpufreq
Quoted 5 lines · Dominik Brodowski
Quoted 1 line · Bruno Ducrot
Ok, you win. That one is ok ?
Looks good as well. All we have to decide is where to call these functions, though... and Davej has to decide whether he likes it, too :-)
Looks good to me, though I'm missing the part where you wire this up to the rest of the code. I see two possibilities.
- fallback to acpi when we detect bad PST's.
- module parameter to force usage of acpi (override PST)
Dave
Quoted 9 lines · Dave Jones
Quoted 5 lines · Dominik Brodowski
Quoted 1 line · Bruno Ducrot
Ok, you win. That one is ok ?
Looks good as well. All we have to decide is where to call these functions, though... and Davej has to decide whether he likes it, too :-)
Looks good to me, though I'm missing the part where you wire this up to the rest of the code. I see two possibilities.
Well, that need to be decided at first. I'm acually testing it by calling that function in powernow_decode_bios() with something like that:
arch/i386/kernel/cpu/cpufreq/powernow-k7.c +3 -0
@@ -426,6 +426,9 @@unsigned int etuple;unsigned int ret; +if (powernow_acpi_init () ==0 ) +return 0 ; + etuple =cpuid_eax (0x80000001 ); etuple &=0xf00 ; etuple |= (c->x86_model<<4 )|(c->x86_mask);
but I guess this is not what people want probably, especially if there are good PST's.
Quoted 1 line
- fallback to acpi when we detect bad PST's.
That sound good.
Quoted 1 line
- module parameter to force usage of acpi (override PST)
Yes, or check if the laptop is blacklisted.
Signature · 4 lines
Bruno Ducrot -- Which is worse: ignorance or apathy? -- Don't know. Don't care.
Quoted 6 lines · Dominik Brodowski
Quoted 2 lines · Bruno Ducrot
How about that one?
Looks much better, IMO.
Quoted 8 lines
Quoted 3 lines
By now, I'm a little puzzled with the fsb stuff,
though. A first idea may be to look into what say ACPI about the frequency, and deduce the fsb from, but I don't like it.So you wouldn't like
fsb = (acpi_processor_perf->states[i].core_frequency * 10) / fid_codes[fid]
Ok, you win. That one is ok ?
arch/i386/kernel/cpu/cpufreq/powernow-k7.c renamed from arch/i386/kernel/cpu/cpufreq/powernow-k7.c.orig +13 -2
@@ -333,6 +333,7 @@ {int i;int retval =0 ; +union powernow_acpi_control_t pc;if (acpi_processor_perf !=NULL )return -EINVAL ;
@@ -378,12 +379,22 @@memset (powernow_table,0 , ((number_scales +1 ) *sizeof (struct cpufreq_frequency_table ))); - fsb =100 ;/* XXX fix me */ + pc.val = (unsigned long ) acpi_processor_perf->states[0 ].control; + fsb = (10 * (u32 ) acpi_processor_perf->states[0 ].core_frequency) / (fid_codes[pc.bits.fid]); +if (fsb >133 ) + fsb =133 ; +if (fsb <100 ) + fsb =100 ; + +if (100 +133 <2 *fsb) + fsb =133 ; +else + fsb =100 ; + latency =0 ;for (i =0 ; i < number_scales; i++) {u8 fid, vid; -union powernow_acpi_control_t pc;unsigned int speed; pc.val = (unsigned long ) acpi_processor_perf->states[i].control;
Signature · 4 lines
Bruno Ducrot -- Which is worse: ignorance or apathy? -- Don't know. Don't care.