--- linux-2.6.15/arch/i386/kernel/cpu/cpufreq/powernow-k8.c 2006-03-14 23:10:35.000000000 +0100 +++ linux-2.6.15/arch/i386/kernel/cpu/cpufreq/powernow-k8.c 2006-03-16 19:03:17.000000000 +0100 @@ -277,7 +277,7 @@ static int transition_fid_vid(struct pow return 1; } - dprintk("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n", + printk(KERN_INFO PFX "transitioned (cpu%d): new fid 0x%x, vid 0x%x\n", smp_processor_id(), data->currfid, data->currvid); return 0; @@ -552,6 +552,113 @@ static void print_basics(struct powernow printk(KERN_INFO PFX "Only %d pstates on battery\n", data->batps); } +/* pnforce version 0.01a + The pnforce_setup() and get_forced_vid() functions have been + written by Flavio Chierichetti (flavio -at- lightless -dot- org) + and have been released under the GPL2. + + BE AWARE THAT THESE FUNCTIONS COME WITH ABSOLUTELY NO WARRANTY. + THEY MAY MELT YOUR CPU AND/OR YOUR SYSTEM. + I CAN'T PROVIDE SUPPORT FOR THEIR USE OR THEIR MISUSE. + + Be aware that I'm not an hardware or a kernel expert. + + That said, they seem to work for my cpu. + + -- + + To force the use of some "vid"s, you have to pass the + "pnforce=" option at the kernel boot. + + The option format is + pnforce=fid1,forced_vid1[:fid2,forced_vid2[...]] + All numbers should be written in decimal. + + You can't add new fid/vid couples to the pst table - you can only + change existing ones. + + For example, to set 1250mV for 1800MHz, 1150mV for 1600MHz and + 900mV for 800MHz, the option to pass is: + pnforce=10,12:8,16:0,26 +*/ + +#define OVERRIDEPST_MAXLEN 16 +struct pst_s overridePST[OVERRIDEPST_MAXLEN]; +int overridePST_len = 0; +static int __init pnforce_setup(char *str) +{ + char err = 0; + int i, j; + unsigned long t; + + printk(KERN_INFO PFX "pnforce=%s\n", str); + + overridePST_len = 1; + for ( i = 0 ; str[i] != '\0' ; i++ ) + if ( str[i] == ':' ) + overridePST_len++; + + if ( overridePST_len > OVERRIDEPST_MAXLEN ) { + printk(KERN_INFO PFX "Too many fid/vid couples (max: %d)!\n", OVERRIDEPST_MAXLEN - 1); + err = 1; + } else + for ( i = 0 ; i < overridePST_len ; i++ ) { + t = simple_strtoul(str, &str, 10); + if ( *str != ',' ) { + printk(KERN_INFO PFX "Can't parse pnforce option!\n"); + err = 1; break; + } + str++; + if ( t & INVALID_FID_MASK ) { + printk(KERN_INFO PFX "Invalid fid in pnforce!\n"); + err = 1; break; + } + for ( j = 0 ; j < i ; j++ ) + if ( overridePST[j].fid == t ) { + printk(KERN_INFO PFX "Repeated fid in pnforce!\n"); + err = 1; break; + } + if ( err ) + break; + + overridePST[i].fid = t & FID_MASK; + + t = simple_strtoul(str, &str, 10); + if ( (i < overridePST_len - 1 && *str != ':') || (i == overridePST_len - 1 && *str != '\0') ) { + printk(KERN_INFO PFX "Can't parse pnforce option!\n"); + err = 1; break; + } + str++; + if ( t & INVALID_VID_MASK ) { + printk(KERN_INFO PFX "Invalid vid in pnforce!\n"); + err = 1; break; + } + + overridePST[i].vid = t & VID_MASK; + } + + if ( err ) { + printk(KERN_INFO PFX "Ignoring the whole \"pnforce\" option.\n"); + overridePST_len = 0; + } + + return 0; +} +__setup("pnforce=", pnforce_setup); + + +static u8 get_forced_vid(u8 fid, u8 vid) { + int i; + + for ( i = 0 ; i < overridePST_len ; i++ ) + if ( fid == overridePST[i].fid ) { + printk(KERN_INFO PFX "fid %x: overriding vid (was %x; is %x)\n", fid, vid, overridePST[i].vid); + return overridePST[i].vid; + } + + return vid; +} + static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid) { struct cpufreq_frequency_table *powernow_table; @@ -585,6 +692,8 @@ static int fill_powernow_table(struct po } for (j = 0; j < data->numps; j++) { + pst[j].vid = get_forced_vid(pst[j].fid, pst[j].vid); + powernow_table[j].index = pst[j].fid; /* lower 8 bits */ powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */ powernow_table[j].frequency = find_khz_freq_from_fid(pst[j].fid); @@ -752,6 +861,8 @@ static int powernow_k8_cpu_init_acpi(str vid = (data->acpi_data.states[i].control >> VID_SHIFT) & VID_MASK; } + vid = get_forced_vid(fid, vid); + dprintk(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid); powernow_table[i].index = fid; /* lower 8 bits */