[ltp] Re: 2.6.21 / whoopie patches / undervolting patch problem
Whoopie
linux-thinkpad@linux-thinkpad.org
Sat, 12 May 2007 19:23:44 +0200
This is a multi-part message in MIME format.
--------------010303000405040207050803
Content-Type: text/plain; charset=ISO-8859-15
Content-Transfer-Encoding: 7bit
Hi,
you're right. The undervolt patch makes problems atm. I asked on
##linux-phc at irc.freenode.net and the developer is looking at it
(although he's quite busy). Btw, they search new developers for linux-phc.
But I was pointed to another patch for acpi-cpufreq as
speedstep-centrino is deprecated. I attach the patch.
It comes from http://forums.gentoo.org/viewtopic-p-3803393.html#3803393
Keep in mind that the usage has changed. The path for the frequency
table is "/sys/devices/system/cpu/cpu0/cpufreq/cpufreq_freq_voltages"
and you need to only echo the voltages like
echo "1100 1020 940 860 796" >
/sys/devices/system/cpu/cpu0/cpufreq/cpufreq_freq_voltages
The first voltage is for the highest CPU frequency.
Best regards,
Whoopie
Fionn Behrens schrieb:
> Finally, after almost a year, I decided I need a new kernel. I took
> vanilla 2.6.21 and patched it with everything considered useful, mainly
> most of the http://whoopie.gmxhome.de/linux/patches/2.6.21/ patches.
>
> The kernel boots and the computer runs all fine, but as soon as I try to
> feed any undervolting data to the voltage_table oder to the
> op_points_table, sysfs freezes and does never come back! Any subsequent
> access to sysfs results in a permanent freeze of the accessing process.
> I'd rather not fall back to the hardcoding-my-voltages-in-the-kernel
> solution since I'll need the deb for several similar machines with
> slightly different undervolting specs.
>
> Does anyone of you know who wrote the patch and what could be done for a
> solution?
>
> kind regards,
> Fionn
--------------010303000405040207050803
Content-Type: text/x-patch;
name="acpi-cpufreq-undervolt.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="acpi-cpufreq-undervolt.patch"
--- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -57,6 +57,8 @@ enum {
};
#define INTEL_MSR_RANGE (0xffff)
+#define INTEL_MSR_FREQUENCY (0xff00)
+#define INTEL_MSR_VOLTAGE (0x00ff)
#define CPUID_6_ECX_APERFMPERF_CAPABILITY (0x1)
struct acpi_cpufreq_data {
@@ -69,6 +71,7 @@ struct acpi_cpufreq_data {
static struct acpi_cpufreq_data *drv_data[NR_CPUS];
static struct acpi_processor_performance *acpi_perf_data[NR_CPUS];
+static acpi_integer *original_acpi_data_control[NR_CPUS];
static struct cpufreq_driver acpi_cpufreq_driver;
@@ -104,11 +107,12 @@ static unsigned extract_msr(u32 msr, str
int i;
struct acpi_processor_performance *perf;
- msr &= INTEL_MSR_RANGE;
+ msr &= INTEL_MSR_FREQUENCY;
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 (msr == (perf->states[data->freq_table[i].index].status &
+ INTEL_MSR_FREQUENCY))
return data->freq_table[i].frequency;
}
return data->freq_table[0].frequency;
@@ -668,7 +672,7 @@ static int acpi_cpufreq_cpu_init(struct
data->max_freq = perf->states[0].core_frequency * 1000;
/* table init */
for (i=0; i<perf->state_count; i++) {
- if (i>0 && perf->states[i].core_frequency ==
+ if (i>0 && perf->states[i].core_frequency >=
perf->states[i-1].core_frequency)
continue;
@@ -749,6 +753,8 @@ static int acpi_cpufreq_cpu_exit(struct
acpi_processor_unregister_performance(data->acpi_data,
policy->cpu);
kfree(data);
+ kfree(original_acpi_data_control[policy->cpu]);
+ original_acpi_data_control[policy->cpu] = NULL;
}
return 0;
@@ -765,8 +771,119 @@ static int acpi_cpufreq_resume(struct cp
return 0;
}
+static ssize_t show_freq_voltages(struct cpufreq_policy *policy, char *buf)
+{
+ struct acpi_cpufreq_data *data = drv_data[policy->cpu];
+ struct acpi_processor_performance *perf;
+ unsigned int i;
+ unsigned int voltage;
+ ssize_t count = 0;
+
+ if (unlikely(data == NULL ||
+ data->acpi_data == NULL || data->freq_table == NULL)) {
+ return -ENODEV;
+ }
+
+ perf = data->acpi_data;
+
+ /* show space separated list of current voltages */
+ for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ voltage = perf->states[data->freq_table[i].index].control;
+ voltage = 700 + ((voltage & INTEL_MSR_VOLTAGE) << 4);
+ count += sprintf(&buf[count], "%u ", voltage);
+ }
+ count += sprintf(&buf[count], "\n");
+
+ return count;
+}
+
+static ssize_t store_freq_voltages(struct cpufreq_policy *policy, const char *buf, size_t count)
+{
+ unsigned int cpu = policy->cpu;
+ struct acpi_cpufreq_data *data = drv_data[cpu];
+ struct acpi_processor_performance *perf;
+ unsigned int i, j;
+ unsigned int voltage;
+ unsigned int voltage_index, original_index;
+ const char *curr_buf = buf;
+ char *next_buf;
+ acpi_integer control;
+
+ if (unlikely(data == NULL ||
+ data->acpi_data == NULL || data->freq_table == NULL)) {
+ return -ENODEV;
+ }
+
+ perf = data->acpi_data;
+
+
+ /* save original control values to disallow overvolting */
+ if (!original_acpi_data_control[cpu]) {
+ original_acpi_data_control[cpu] = kmalloc(sizeof(acpi_integer) *
+ perf->state_count, GFP_KERNEL);
+ if (!original_acpi_data_control[cpu]) {
+ dprintk("failed to allocate memory for old control values\n");
+ return -ENOMEM;
+ }
+ for (i = 0; i < perf->state_count; i++)
+ original_acpi_data_control[cpu][i] = perf->states[i].control;
+ }
+
+ /* set new voltages from user space */
+ for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ voltage = simple_strtoul(curr_buf, &next_buf, 10);
+ if (next_buf == curr_buf) {
+ if ((curr_buf - buf == count - 1) && (*curr_buf == '\n')) {
+ curr_buf++;
+ break;
+ }
+ dprintk("failed to parse voltage value at %i (%s)\n", i, curr_buf);
+ return -EINVAL;
+ }
+ if (voltage < 700) {
+ dprintk("skipping voltage at %i, "
+ "%u is below the minimum of 700 mV\n", i, voltage);
+ } else {
+ voltage_index = ((voltage - 700) >> 4) & INTEL_MSR_VOLTAGE;
+ j = data->freq_table[i].index;
+ original_index = original_acpi_data_control[cpu][j] &
+ INTEL_MSR_VOLTAGE;
+ if (voltage_index <= original_index) {
+ control = (original_acpi_data_control[cpu][j] &
+ INTEL_MSR_FREQUENCY) | voltage_index;
+ dprintk("setting control %x at %i, default is %x\n",
+ (unsigned int) control, i,
+ (unsigned int) original_acpi_data_control[cpu][j]);
+ perf->states[j].control = control;
+ } else {
+ dprintk("skipping voltage at %i, "
+ "%u is greater than the default %u\n",
+ i, voltage,
+ 700 + (original_index << 4));
+ }
+ }
+ curr_buf = next_buf;
+ while ((curr_buf - buf < count) && (*curr_buf == ' '))
+ curr_buf++;
+ }
+
+ /* set new voltage at current frequency */
+ data->resume = 1;
+ acpi_cpufreq_target(policy, get_cur_freq_on_cpu(cpu), CPUFREQ_RELATION_L);
+
+ return curr_buf - buf;
+}
+
+static struct freq_attr cpufreq_freq_attr_freq_voltages =
+{
+ .attr = { .name = "cpufreq_freq_voltages", .mode = 0644, .owner = THIS_MODULE },
+ .show = show_freq_voltages,
+ .store = store_freq_voltages,
+};
+
static struct freq_attr *acpi_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+ &cpufreq_freq_attr_freq_voltages,
NULL,
};
@@ -800,6 +917,8 @@ static void __exit acpi_cpufreq_exit(voi
for_each_possible_cpu(i) {
kfree(acpi_perf_data[i]);
acpi_perf_data[i] = NULL;
+ kfree(original_acpi_data_control[i]);
+ original_acpi_data_control[i] = NULL;
}
return;
}
--------------010303000405040207050803--