
From: Tony Lindgren <tony@atomide.com>

Following is the updated patch to make the powernow-k8 driver work on
machines with buggy BIOS, such as emachines m6805.

The patch overrides the PST table only if check_pst_table() fails.

The minimum value for the override is 800MHz, which is the lowest value on
all x86_64 systems AFAIK.  The max value is the current running value.

This patch should be safe to apply, even if Pavel's ACPI table check is
added to the driver.


---

 25-akpm/arch/i386/kernel/cpu/cpufreq/powernow-k8.c |   56 ++++++++++++++++-----
 1 files changed, 43 insertions(+), 13 deletions(-)

diff -puN arch/i386/kernel/cpu/cpufreq/powernow-k8.c~powernow-k8-buggy-bios-override-for-266 arch/i386/kernel/cpu/cpufreq/powernow-k8.c
--- 25/arch/i386/kernel/cpu/cpufreq/powernow-k8.c~powernow-k8-buggy-bios-override-for-266	2004-05-12 21:06:38.917144056 -0700
+++ 25-akpm/arch/i386/kernel/cpu/cpufreq/powernow-k8.c	2004-05-12 21:06:38.922143296 -0700
@@ -42,6 +42,8 @@
 #define VERSION "version 1.00.09b"
 #include "powernow-k8.h"
 
+#define MAX_NR_PST	16
+
 /* serialize freq changes  */
 static DECLARE_MUTEX(fidvid_sem);
 
@@ -479,6 +481,23 @@ out:
 
 }
 
+/*
+ * This is the place to override the buggy BIOS values
+ */
+static int override_pst_table(struct powernow_k8_data *data, 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 = data->currfid;
+	pst[1].vid = data->currvid;
+
+	return 2;
+}
+
 static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid)
 {
 	unsigned int j;
@@ -536,6 +555,7 @@ static int fill_powernow_table(struct po
 {
 	struct cpufreq_frequency_table *powernow_table;
 	unsigned int j;
+	struct pst_s *pst_tmp;
 
 	if (data->batps) {    /* use ACPI support to get full speed on mains power */
 		printk(KERN_WARNING PFX "Only %d pstates usable (use ACPI driver for full range\n", data->batps);
@@ -553,39 +573,49 @@ static int fill_powernow_table(struct po
 		printk(KERN_ERR PFX "no p states to transition\n");
 		return -ENODEV;
 	}
-                                                                                                    
+
+	/* Must have the current values early in case of override_pst_table() */
+	if (query_current_values_with_pending_wait(data))
+		return -EIO;
+
+	/* Copy the BIOS table into a temporary table in case it needs override */
+	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) * data->numps);
+
 	if (check_pst_table(data, pst, maxvid))
-		return -EINVAL;
+		data->numps = override_pst_table(data, pst_tmp);
 
 	powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)
 		* (data->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 < data->numps; 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].frequency = find_khz_freq_from_fid(pst[j].fid);
+		powernow_table[j].index = pst_tmp[j].fid; /* lower 8 bits */
+		powernow_table[j].index |= (pst_tmp[j].vid << 8); /* upper 8 bits */
+		powernow_table[j].frequency = find_khz_freq_from_fid(pst_tmp[j].fid);
 	}
 	powernow_table[data->numps].frequency = CPUFREQ_TABLE_END;
 	powernow_table[data->numps].index = 0;
 
-	if (query_current_values_with_pending_wait(data)) {
-		kfree(powernow_table);
-		return -EIO;
-	}
-
 	dprintk(KERN_INFO PFX "cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid);
 	data->powernow_table = powernow_table;
 	print_basics(data);
 
 	for (j = 0; j < data->numps; j++)
-		if ((pst[j].fid==data->currfid) && (pst[j].vid==data->currvid))
+		if ((pst_tmp[j].fid==data->currfid) && (pst_tmp[j].vid==data->currvid))
 			return 0;
 
 	dprintk(KERN_ERR PFX "currfid/vid do not match PST, ignoring\n");
+	kfree(pst_tmp);
 	return 0;
 }
 
@@ -635,8 +665,8 @@ static int find_psb_table(struct powerno
 
 		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);
 		}
 
 		data->plllock = psb->plllocktime;

_
