diff --new-file -a --unified=5 --recursive --exclude-from=diff.excludes linux.org/arch/i386/kernel/cpu/cpufreq/powernow-k8.c linux.phc/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
--- linux.org/arch/i386/kernel/cpu/cpufreq/powernow-k8.c	2006-07-16 18:51:05.000000000 +0200
+++ linux.phc/arch/i386/kernel/cpu/cpufreq/powernow-k8.c	2006-07-16 20:31:38.000000000 +0200
@@ -64,11 +64,10 @@
 static u32 find_freq_from_fid(u32 fid)
 {
 	return 800 + (fid * 100);
 }
 
-
 /* Return a frequency in KHz, given an input fid */
 static u32 find_khz_freq_from_fid(u32 fid)
 {
 	return 1000 * find_freq_from_fid(fid);
 }
@@ -96,10 +95,22 @@
 	u32 hi, lo;
 	rdmsr(MSR_PSTATE_DEF_BASE + pstate, lo, hi);
 	return (lo & HW_PSTATE_DID_MASK) >> HW_PSTATE_DID_SHIFT;
 }
 
+/* Return a voltage in miliVolts, given an input vid */
+static u32 find_millivolts_from_vid(struct powernow_k8_data *data, u32 vid)
+{
+	return 1550-vid*25;
+}
+  
+/* Return vid, given an input voltage in mV */
+static u32 find_vid_from_millivolts(u32 voltage)
+{
+	return (1550-voltage)/25;
+}
+
 /* Return the vco fid for an input fid
  *
  * Each "low" fid has corresponding "high" fid, and you can get to "low" fids
  * only from corresponding high fids. This returns "high" fid corresponding to
  * "low" one.
@@ -377,20 +388,21 @@
 /* Phase 2 - core frequency transition */
 static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
 {
 	u32 vcoreqfid, vcocurrfid, vcofiddiff, fid_interval, savevid = data->currvid;
 
+	if (data->currfid == reqfid) {
+		printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n", data->currfid);
+		return 0;
+	}
+
 	if ((reqfid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) {
 		printk(KERN_ERR PFX "ph2: illegal lo-lo transition 0x%x 0x%x\n",
 			reqfid, data->currfid);
 		return 1;
 	}
 
-	if (data->currfid == reqfid) {
-		printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n", data->currfid);
-		return 0;
-	}
 
 	dprintk("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, reqfid 0x%x\n",
 		smp_processor_id(),
 		data->currfid, data->currvid, reqfid);
 
@@ -980,11 +992,11 @@
 		dprintk("target matches current values (fid 0x%x, vid 0x%x)\n",
 			fid, vid);
 		return 0;
 	}
 
-	if ((fid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) {
+	if ((fid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM) && (data->currfid != fid)) {
 		printk(KERN_ERR PFX
 		       "ignoring illegal change in lo freq table-%x to 0x%x\n",
 		       data->currfid, fid);
 		return 1;
 	}
@@ -1294,12 +1306,144 @@
 out:
 	set_cpus_allowed(current, oldmask);
 	return khz;
 }
 
+/************************** sysfs interface for user defined voltage table ************************/
+static ssize_t show_user_voltage (struct cpufreq_policy *policy, char *buf)
+{
+	ssize_t       bytes_written = 0;
+	struct powernow_k8_data *data = powernow_data[policy->cpu];
+	int j;
+	for (j = 0; j < data->numps; j++) {
+		if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID)
+		{
+		    bytes_written += snprintf (&buf[bytes_written],PAGE_SIZE - bytes_written, "%u",find_millivolts_from_vid(data, data->powernow_table[j].index >> 8));
+		    if (j < data->numps - 1)
+			bytes_written += snprintf (&buf[bytes_written],2,",");
+		    else
+		        bytes_written += snprintf (&buf[bytes_written],2,"\n");
+		}
+	}
+
+	buf[PAGE_SIZE-1] = 0;
+	return bytes_written;
+}
+
+static ssize_t 
+store_user_voltage (struct cpufreq_policy *policy, const char *buf, size_t count) 
+{
+	const char   *curr_buf;
+	u32  curr_freq;
+	u32  op_index;
+	int           isok;
+	unsigned int cpu;
+	int i;
+	static struct cpufreq_frequency_table **original_table = NULL;
+	struct powernow_k8_data *data = powernow_data[policy->cpu];
+	char         *next_buf;
+	u32  op_point;
+	ssize_t       retval;
+	u32  voltage;
+
+	if (!policy)
+	    return -ENODEV;
+
+	cpu = policy->cpu;
+
+	if (!data || !data->powernow_table)
+	    return -ENODEV;
+
+	if (!original_table) 
+	{
+		original_table = kmalloc(sizeof(struct cpufreq_frequency_table *)*NR_CPUS, GFP_KERNEL);
+		for (i=0; i < NR_CPUS; i++)
+		{
+			original_table[i] = NULL;
+		}
+	}
+
+	if (!original_table[cpu]) 
+	{
+		/* Allocate memory to store the copy */
+		original_table[cpu] = (struct cpufreq_frequency_table*) kmalloc(sizeof(struct cpufreq_frequency_table)*(data->numps+1), GFP_KERNEL);
+		/* Make copy of frequency/voltage pairs */
+		for (i=0; i < data->numps; i++) 
+		{
+			original_table[cpu][i].frequency = data->powernow_table[i].frequency;
+			original_table[cpu][i].index = data->powernow_table[i].index;
+		}
+		original_table[cpu][i].frequency = CPUFREQ_TABLE_END;
+	}
+	op_index = 0;
+	curr_buf = buf;
+	next_buf = NULL;
+	isok     = 1;
+	
+	while ((data->numps  > op_index) 
+		&& (isok))
+	{
+		voltage = simple_strtoul(curr_buf, &next_buf, 10);
+		if ((next_buf != curr_buf) && (next_buf != NULL))
+		{
+			if ((voltage >= 700) && (voltage<=1600))
+			{
+				op_point = (original_table[cpu])[op_index].index;
+				if (voltage <= find_millivolts_from_vid(data,op_point >> 8))
+				{
+					op_point = (op_point & 0xFFFF00FF) | (find_vid_from_millivolts(voltage) << 8);
+					data->powernow_table[op_index].index = op_point;
+				}
+				else
+				{
+					op_point = (op_point & 0xFFFF00FF) | (find_vid_from_millivolts(voltage) << 8);
+					printk(KERN_ERR PFX"not setting control value %i to %04x because requested voltage is not lower than the default value\n", op_index, op_point);
+					// isok = 0;
+				}
+			}
+			else
+			{
+				printk(KERN_ERR PFX"voltage value %i is out of bounds: %u mV\n", op_index, voltage);
+				isok = 0;
+			}
+			curr_buf = next_buf;
+			if (*curr_buf==',')
+				curr_buf++;
+			next_buf = NULL;
+		}
+		else
+		{
+			printk(KERN_ERR PFX"failed to parse voltage value %i\n", op_index);
+			isok = 0;
+		}
+		op_index++;
+	}
+	if (isok)
+	{
+		retval = count;
+		curr_freq = cpufreq_get(policy->cpu);
+		powernowk8_target(policy, curr_freq, CPUFREQ_RELATION_L);
+	}
+	else
+	{
+		retval = -EINVAL;
+	}
+
+    return retval;
+}
+
+
+static struct freq_attr powernow_freq_attr_voltage_table = 
+{
+	.attr = { .name = "voltage_table", .mode = 0644, .owner = THIS_MODULE },
+	.show = show_user_voltage,
+	.store = store_user_voltage,
+};
+
 static struct freq_attr* powernow_k8_attr[] = {
 	&cpufreq_freq_attr_scaling_available_freqs,
+	&powernow_freq_attr_voltage_table,
 	NULL,
 };
 
 static struct cpufreq_driver cpufreq_amd64_driver = {
 	.verify = powernowk8_verify,

