--- linux-2.6.36/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c	2010-12-10 11:40:18.000000000 +0200
+++ linux-2.6.36-teknohog/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c	2010-12-10 11:20:10.000000000 +0200
@@ -25,6 +25,10 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
+/* This file has been patched with Linux PHC: www.linux-phc.org
+* Patch version: linux-phc-0.3.2
+*/
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -61,12 +65,17 @@
 };
 
 #define INTEL_MSR_RANGE		(0xffff)
+#define INTEL_MSR_VID_MASK	(0x00ff)
+#define INTEL_MSR_FID_MASK	(0xff00)
+#define INTEL_MSR_FID_SHIFT	(0x8)
+#define PHC_VERSION_STRING	"0.3.2:2"
 
 struct acpi_cpufreq_data {
 	struct acpi_processor_performance *acpi_data;
 	struct cpufreq_frequency_table *freq_table;
 	unsigned int resume;
 	unsigned int cpu_feature;
+	acpi_integer *original_controls;
 };
 
 static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data);
@@ -102,13 +111,14 @@
 static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
 {
 	int i;
+	u32 fid;
 	struct acpi_processor_performance *perf;
 
-	msr &= INTEL_MSR_RANGE;
+	fid = msr & INTEL_MSR_FID_MASK;
 	perf = data->acpi_data;
 
 	for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
-		if (msr == perf->states[data->freq_table[i].index].status)
+		if (fid == (perf->states[data->freq_table[i].index].status & INTEL_MSR_FID_MASK))
 			return data->freq_table[i].frequency;
 	}
 	return data->freq_table[0].frequency;
@@ -701,6 +711,8 @@
 		per_cpu(acfreq_data, policy->cpu) = NULL;
 		acpi_processor_unregister_performance(data->acpi_data,
 						      policy->cpu);
+		if (data->original_controls)
+		        kfree(data->original_controls);
 		kfree(data->freq_table);
 		kfree(data);
 	}
@@ -719,8 +731,470 @@
 	return 0;
 }
 
+
+/* sysfs interface to change operating points voltages */
+
+static unsigned int extract_fid_from_control(unsigned int control)
+{
+	return ((control & INTEL_MSR_FID_MASK) >> INTEL_MSR_FID_SHIFT);
+}
+
+static unsigned int extract_vid_from_control(unsigned int control)
+{
+	return (control & INTEL_MSR_VID_MASK);
+}
+
+
+static bool check_cpu_control_capability(struct acpi_cpufreq_data *data) {
+ /* check if the cpu we are running on is capable of setting new control data
+  * 
+  */
+	if (unlikely(data == NULL || 
+	             data->acpi_data == NULL || 
+	             data->freq_table == NULL ||
+	             data->cpu_feature != SYSTEM_INTEL_MSR_CAPABLE)) {
+		return false;
+	} else {
+		return true;
+	};
+}
+
+
+static ssize_t check_origial_table (struct acpi_cpufreq_data *data)
+{
+
+	struct acpi_processor_performance *acpi_data;
+	struct cpufreq_frequency_table *freq_table;
+	unsigned int state_index;
+
+	acpi_data = data->acpi_data;
+	freq_table = data->freq_table;
+
+	if (data->original_controls == NULL) {
+		// Backup original control values
+		data->original_controls = kcalloc(acpi_data->state_count,
+		                                  sizeof(acpi_integer), GFP_KERNEL);
+		if (data->original_controls == NULL) {
+			printk("failed to allocate memory for original control values\n");
+			return -ENOMEM;
+		}
+		for (state_index = 0; state_index < acpi_data->state_count; state_index++) {
+			data->original_controls[state_index] = acpi_data->states[state_index].control;
+		}
+	}
+	return 0;
+}
+
+static ssize_t show_freq_attr_vids(struct cpufreq_policy *policy, char *buf)
+ /* display phc's voltage id's
+  * 
+  */
+{
+	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_processor_performance *acpi_data;
+	struct cpufreq_frequency_table *freq_table;
+	unsigned int i;
+	unsigned int vid;
+	ssize_t count = 0;
+
+	if (!check_cpu_control_capability(data)) return -ENODEV; //check if CPU is capable of changing controls
+
+	acpi_data = data->acpi_data;
+	freq_table = data->freq_table;
+
+	for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+		vid = extract_vid_from_control(acpi_data->states[freq_table[i].index].control);
+		count += sprintf(&buf[count], "%u ", vid);
+	}
+	count += sprintf(&buf[count], "\n");
+
+	return count;
+}
+
+static ssize_t show_freq_attr_default_vids(struct cpufreq_policy *policy, char *buf)
+ /* display acpi's default voltage id's
+  * 
+  */
+{
+	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct cpufreq_frequency_table *freq_table;
+	unsigned int i;
+	unsigned int vid;
+	ssize_t count = 0;
+	ssize_t retval;
+
+	if (!check_cpu_control_capability(data)) return -ENODEV; //check if CPU is capable of changing controls
+
+	retval = check_origial_table(data);
+        if (0 != retval)
+		return retval; 
+
+	freq_table = data->freq_table;
+
+	for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+		vid = extract_vid_from_control(data->original_controls[freq_table[i].index]);
+		count += sprintf(&buf[count], "%u ", vid);
+	}
+	count += sprintf(&buf[count], "\n");
+
+	return count;
+}
+
+static ssize_t show_freq_attr_fids(struct cpufreq_policy *policy, char *buf)
+ /* display phc's frequeny id's
+  * 
+  */
+{
+	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_processor_performance *acpi_data;
+	struct cpufreq_frequency_table *freq_table;
+	unsigned int i;
+	unsigned int fid;
+	ssize_t count = 0;
+
+	if (!check_cpu_control_capability(data)) return -ENODEV; //check if CPU is capable of changing controls
+
+	acpi_data = data->acpi_data;
+	freq_table = data->freq_table;
+
+	for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+		fid = extract_fid_from_control(acpi_data->states[freq_table[i].index].control);
+		count += sprintf(&buf[count], "%u ", fid);
+	}
+	count += sprintf(&buf[count], "\n");
+
+	return count;
+}
+
+static ssize_t show_freq_attr_controls(struct cpufreq_policy *policy, char *buf)
+ /* display phc's controls for the cpu (frequency id's and related voltage id's)
+  * 
+  */
+{
+	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_processor_performance *acpi_data;
+	struct cpufreq_frequency_table *freq_table;
+	unsigned int i;
+	unsigned int fid;
+	unsigned int vid;
+	ssize_t count = 0;
+
+	if (!check_cpu_control_capability(data)) return -ENODEV; //check if CPU is capable of changing controls
+
+	acpi_data = data->acpi_data;
+	freq_table = data->freq_table;
+
+	for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+		fid = extract_fid_from_control(acpi_data->states[freq_table[i].index].control);
+		vid = extract_vid_from_control(acpi_data->states[freq_table[i].index].control);
+		count += sprintf(&buf[count], "%u:%u ", fid, vid);
+	}
+	count += sprintf(&buf[count], "\n");
+
+	return count;
+}
+
+static ssize_t show_freq_attr_default_controls(struct cpufreq_policy *policy, char *buf)
+ /* display acpi's default controls for the cpu (frequency id's and related voltage id's)
+  * 
+  */
+{
+	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct cpufreq_frequency_table *freq_table;
+	unsigned int i;
+	unsigned int fid;
+	unsigned int vid;
+	ssize_t count = 0;
+	ssize_t retval;
+
+	if (!check_cpu_control_capability(data)) return -ENODEV; //check if CPU is capable of changing controls
+
+	retval = check_origial_table(data);
+        if (0 != retval)
+		return retval; 
+
+	freq_table = data->freq_table;
+
+	for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+		fid = extract_fid_from_control(data->original_controls[freq_table[i].index]);
+		vid = extract_vid_from_control(data->original_controls[freq_table[i].index]);
+		count += sprintf(&buf[count], "%u:%u ", fid, vid);
+	}
+	count += sprintf(&buf[count], "\n");
+
+	return count;
+}
+
+
+static ssize_t store_freq_attr_vids(struct cpufreq_policy *policy, const char *buf, size_t count)
+ /* store the voltage id's for the related frequency
+  * We are going to do some sanity checks here to prevent users 
+  * from setting higher voltages than the default one.
+  */
+{
+	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_processor_performance *acpi_data;
+	struct cpufreq_frequency_table *freq_table;
+	unsigned int freq_index;
+	unsigned int state_index;
+	unsigned int new_vid;
+	unsigned int original_vid;
+	unsigned int new_control;
+	unsigned int original_control;
+	const char *curr_buf = buf;
+	char *next_buf;
+	ssize_t retval;
+
+	if (!check_cpu_control_capability(data)) return -ENODEV; //check if CPU is capable of changing controls
+
+	retval = check_origial_table(data);
+        if (0 != retval)
+		return retval; 
+
+	acpi_data = data->acpi_data;
+	freq_table = data->freq_table;
+
+	/* for each value taken from the sysfs interfalce (phc_vids) get entrys and convert them to unsigned long integers*/
+	for (freq_index = 0; freq_table[freq_index].frequency != CPUFREQ_TABLE_END; freq_index++) {
+		new_vid = simple_strtoul(curr_buf, &next_buf, 10);
+		if (next_buf == curr_buf) {
+			if ((curr_buf - buf == count - 1) && (*curr_buf == '\n')) {   //end of line?
+				curr_buf++;
+				break;
+			}
+			//if we didn't got end of line but there is nothing more to read something went wrong...
+			printk("failed to parse vid value at %i (%s)\n", freq_index, curr_buf);
+			return -EINVAL;
+		}
+
+		state_index = freq_table[freq_index].index;
+		original_control = data->original_controls[state_index];
+		original_vid = original_control & INTEL_MSR_VID_MASK;
+		
+		/* before we store the values we do some checks to prevent 
+		 * users to set up values higher than the default one
+		 */
+		if (new_vid <= original_vid) {
+			new_control = (original_control & ~INTEL_MSR_VID_MASK) | new_vid;
+			dprintk("setting control at %i to %x (default is %x)\n",
+			        freq_index, new_control, original_control);
+			acpi_data->states[state_index].control = new_control;
+
+		} else {
+			printk("skipping vid at %i, %u is greater than default %u\n",
+			       freq_index, new_vid, original_vid);
+		}
+
+		curr_buf = next_buf;
+		/* jump over value seperators (space or comma).
+		 * There could be more than one space or comma character
+		 * to separate two values so we better do it using a loop.
+		 */
+		while ((curr_buf - buf < count) && ((*curr_buf == ' ') || (*curr_buf == ','))) {
+			curr_buf++;
+		}
+	}
+
+	/* set new voltage for current frequency */
+	data->resume = 1;
+	acpi_cpufreq_target(policy, get_cur_freq_on_cpu(policy->cpu), CPUFREQ_RELATION_L);
+
+	return curr_buf - buf;
+}
+
+static ssize_t store_freq_attr_controls(struct cpufreq_policy *policy, const char *buf, size_t count)
+ /* store the controls (frequency id's and related voltage id's)
+  * We are going to do some sanity checks here to prevent users 
+  * from setting higher voltages than the default one.
+  */
+{
+	struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+	struct acpi_processor_performance *acpi_data;
+	struct cpufreq_frequency_table *freq_table;
+	const char   *curr_buf;
+	unsigned int  op_count;
+	unsigned int  state_index;
+	int           isok;
+	char         *next_buf;
+	ssize_t       retval;
+	unsigned int  new_vid;
+	unsigned int  original_vid;
+	unsigned int  new_fid;
+	unsigned int  old_fid;
+	unsigned int  original_control;
+	unsigned int  old_control;
+	unsigned int  new_control;
+	int           found;
+
+	if (!check_cpu_control_capability(data)) return -ENODEV;
+
+	retval = check_origial_table(data);
+        if (0 != retval)
+		return retval;
+
+	acpi_data = data->acpi_data;
+	freq_table = data->freq_table;
+
+	op_count = 0;
+	curr_buf = buf;
+	next_buf = NULL;
+	isok     = 1;
+	
+	while ( (isok) && (curr_buf != NULL) )
+	{
+		op_count++;
+		// Parse fid
+		new_fid = simple_strtoul(curr_buf, &next_buf, 10);
+		if ((next_buf != curr_buf) && (next_buf != NULL))
+		{
+			// Parse separator between frequency and voltage 
+			curr_buf = next_buf;
+			next_buf = NULL;
+			if (*curr_buf==':')
+			{
+				curr_buf++;
+				// Parse vid
+				new_vid = simple_strtoul(curr_buf, &next_buf, 10);
+				if ((next_buf != curr_buf) && (next_buf != NULL))
+				{
+					found = 0;
+					for (state_index = 0; state_index < acpi_data->state_count; state_index++) {
+						old_control = acpi_data->states[state_index].control;
+						old_fid = extract_fid_from_control(old_control);
+						if (new_fid == old_fid)
+						{
+							found = 1;
+							original_control = data->original_controls[state_index];
+							original_vid = extract_vid_from_control(original_control);
+							if (new_vid <= original_vid)
+							{
+								new_control = (original_control & ~INTEL_MSR_VID_MASK) | new_vid;
+								dprintk("setting control at %i to %x (default is %x)\n",
+								        state_index, new_control, original_control);
+								acpi_data->states[state_index].control = new_control;
+
+							} else {
+								printk("skipping vid at %i, %u is greater than default %u\n",
+								       state_index, new_vid, original_vid);
+							}
+						}
+					}
+
+					if (found == 0)
+					{
+						printk("operating point # %u not found (FID = %u)\n", op_count, new_fid);
+						isok = 0;
+					}
+
+					// Parse seprator before next operating point, if any
+					curr_buf = next_buf;
+					next_buf = NULL;
+					if ((*curr_buf == ',') || (*curr_buf == ' '))
+						curr_buf++;
+					else
+						curr_buf = NULL;
+				}
+				else
+				{
+					printk("failed to parse VID of operating point # %u (%s)\n", op_count, curr_buf);
+					isok = 0;
+				}
+			}
+			else
+			{
+				printk("failed to parse operating point # %u (%s)\n", op_count, curr_buf);
+				isok = 0;
+			}
+		}
+		else
+		{
+			printk("failed to parse FID of operating point # %u (%s)\n", op_count, curr_buf);
+			isok = 0;
+		}
+	}
+
+	if (isok)
+	{
+		retval = count;
+		/* set new voltage at current frequency */
+		data->resume = 1;
+		acpi_cpufreq_target(policy, get_cur_freq_on_cpu(policy->cpu), CPUFREQ_RELATION_L);
+	}
+	else
+	{
+		retval = -EINVAL;
+	}
+
+	return retval;
+}
+
+static ssize_t show_freq_attr_phc_version(struct cpufreq_policy *policy, char *buf)
+ /* print out the phc version string set at the beginning of that file
+  */
+{
+	ssize_t count = 0;
+	count += sprintf(&buf[count], "%s\n", PHC_VERSION_STRING);
+	return count;
+}
+
+
+
+static struct freq_attr cpufreq_freq_attr_phc_version =
+{
+	/*display phc's version string*/
+       .attr = { .name = "phc_version", .mode = 0444/*, .owner = THIS_MODULE */},
+       .show = show_freq_attr_phc_version,
+       .store = NULL,
+};
+
+static struct freq_attr cpufreq_freq_attr_vids =
+{
+	/*display phc's voltage id's for the cpu*/
+       .attr = { .name = "phc_vids", .mode = 0644/*, .owner = THIS_MODULE */},
+       .show = show_freq_attr_vids,
+       .store = store_freq_attr_vids,
+};
+
+static struct freq_attr cpufreq_freq_attr_default_vids =
+{
+	/*display acpi's default frequency id's for the cpu*/
+       .attr = { .name = "phc_default_vids", .mode = 0444/*, .owner = THIS_MODULE */},
+       .show = show_freq_attr_default_vids,
+       .store = NULL,
+};
+
+static struct freq_attr cpufreq_freq_attr_fids =
+{
+	/*display phc's default frequency id's for the cpu*/
+       .attr = { .name = "phc_fids", .mode = 0444/*, .owner = THIS_MODULE */},
+       .show = show_freq_attr_fids,
+       .store = NULL,
+};
+
+static struct freq_attr cpufreq_freq_attr_controls =
+{
+	/*display phc's current voltage/frequency controls for the cpu*/
+       .attr = { .name = "phc_controls", .mode = 0644/*, .owner = THIS_MODULE */},
+       .show = show_freq_attr_controls,
+       .store = store_freq_attr_controls,
+};
+
+static struct freq_attr cpufreq_freq_attr_default_controls =
+{
+	/*display acpi's default voltage/frequency controls for the cpu*/
+       .attr = { .name = "phc_default_controls", .mode = 0444/*, .owner = THIS_MODULE */},
+       .show = show_freq_attr_default_controls,
+       .store = NULL,
+};
+
 static struct freq_attr *acpi_cpufreq_attr[] = {
-	&cpufreq_freq_attr_scaling_available_freqs,
+ 	&cpufreq_freq_attr_scaling_available_freqs,
+	&cpufreq_freq_attr_phc_version,
+	&cpufreq_freq_attr_vids,
+	&cpufreq_freq_attr_default_vids,
+	&cpufreq_freq_attr_fids,
+	&cpufreq_freq_attr_controls,
+	&cpufreq_freq_attr_default_controls,
 	NULL,
 };
 
