Amd64 cpufreq driver patch to override a buggy BIOS table with current running values as max value, and 800MHz as the low value. Allows the driver to work on buggy BIOSes, such as m680x laptops. This patch contains updates to the following files: ./b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c Thu Mar 11 20:30:05 2004 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c Thu Mar 11 20:30:05 2004 @@ -36,6 +36,8 @@ #define VERSION "version 1.00.08a" #include "powernow-k8.h" +#define MAX_NR_PST 16 + static u32 vstable; /* voltage stabalization time, from PSB, units 20 us */ static u32 plllock; /* pll lock time, from PSB, units 1 us */ static u32 numps; /* number of p-states, from PSB */ @@ -495,6 +497,23 @@ return 1; } +/* + * This is the place to override the buggy BIOS values + */ +static int override_pst_table(struct pst_s *pst) { + printk(KERN_INFO PFX "BIOS error: overriding frequency table\n"); + + /* Use a safe minimum speed 800MHz */ + pst[0].fid = 0x00; + pst[0].vid = 0x12; + + /* Use current speed as the maximum speed */ + pst[1].fid = currfid; + pst[1].vid = currvid; + + return 2; +} + static int check_pst_table(struct pst_s *pst, u8 maxvid) { unsigned int j; @@ -544,6 +563,7 @@ { struct psb_s *psb; struct pst_s *pst; + struct pst_s *pst_tmp; unsigned int i, j; u32 mvs; u8 maxvid; @@ -587,8 +607,8 @@ dprintk(KERN_DEBUG PFX "numpst: 0x%x\n", psb->numpst); if (psb->numpst != 1) { - printk(KERN_ERR BFX "numpst must be 1\n"); - return -ENODEV; + printk(KERN_WARNING BFX "numpst listed as %i " + "should be 1. Ignoring it.\n", psb->numpst); } dprintk(KERN_DEBUG PFX "cpuid: 0x%x\n", psb->cpuid); @@ -624,24 +644,36 @@ return -ENODEV; } + /* Must have the current values for override_pst_table() */ + if (query_current_values_with_pending_wait()) + return -EIO; + pst = (struct pst_s *) (psb + 1); - if (check_pst_table(pst, maxvid)) - return -EINVAL; + + /* Copy the BIOS table into a temporary table for editing */ + pst_tmp = kmalloc(sizeof(struct pst_s) * MAX_NR_PST, GFP_KERNEL); + if (!pst_tmp) { + printk(KERN_ERR PFX "pst_tmp memory alloc failure\n"); + return -ENOMEM; + } + memset(pst_tmp, 0, sizeof(struct pst_s) * MAX_NR_PST); + memcpy(pst_tmp, pst, sizeof(struct pst_s) * numps); + + if (check_pst_table(pst_tmp, maxvid)) + numps = override_pst_table(pst_tmp); powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) * (numps + 1)), GFP_KERNEL); if (!powernow_table) { printk(KERN_ERR PFX "powernow_table memory alloc failure\n"); + kfree(pst_tmp); return -ENOMEM; } for (j = 0; j < psb->numpstates; j++) { - powernow_table[j].index = pst[j].fid; /* lower 8 bits */ - powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */ + powernow_table[j].index = pst_tmp[j].fid; /* lower 8 bits */ + powernow_table[j].index |= (pst_tmp[j].vid << 8); /* upper 8 bits */ } - /* If you want to override your frequency tables, this - is right place. */ - for (j = 0; j < numps; j++) { powernow_table[j].frequency = find_freq_from_fid(powernow_table[j].index & 0xff)*1000; printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x\n", j, @@ -653,19 +685,17 @@ powernow_table[numps].frequency = CPUFREQ_TABLE_END; powernow_table[numps].index = 0; - if (query_current_values_with_pending_wait()) { - kfree(powernow_table); - return -EIO; - } - printk(KERN_INFO PFX "currfid 0x%x (%d MHz), currvid 0x%x\n", currfid, find_freq_from_fid(currfid), currvid); for (j = 0; j < numps; j++) - if ((pst[j].fid==currfid) && (pst[j].vid==currvid)) - return 0; + if ((pst_tmp[j].fid==currfid) && (pst_tmp[j].vid==currvid)) + goto out_ok; printk(KERN_ERR BFX "currfid/vid do not match PST, ignoring\n"); + + out_ok: + kfree(pst_tmp); return 0; }