diff -urN oldtree/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c newtree/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c --- oldtree/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c 2006-03-27 13:28:15.000000000 -0500 +++ newtree/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c 2006-03-27 18:01:01.326779000 -0500 @@ -507,6 +507,148 @@ static inline int centrino_cpu_early_init_acpi(void) { return 0; } #endif +static int centrino_target (struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation); + +/************************** sysfs interface for user defined voltage table ************************/ +static ssize_t show_user_voltage (struct cpufreq_policy *policy, char *buf) +{ + ssize_t bytes_written = 0; + unsigned int cpu = policy->cpu; + unsigned int op_index = 0; + unsigned int voltage = 0; + + //dprintk("showing user voltage table in sysfs\n"); + + while (centrino_model[cpu]->op_points[op_index].frequency != CPUFREQ_TABLE_END) + { + //dprintk("getting state %i \n", i); + voltage = centrino_model[cpu]->op_points[op_index].index; + voltage = 700 + ((voltage & 0xFF) << 4); + //dprintk("writing voltage %i: %u mV \n", i, voltage); + bytes_written += snprintf (&buf[bytes_written],PAGE_SIZE, "%u",voltage); + op_index++; + if (centrino_model[cpu]->op_points[op_index].frequency != CPUFREQ_TABLE_END) + bytes_written += snprintf (&buf[bytes_written],PAGE_SIZE, ","); + else + bytes_written += snprintf (&buf[bytes_written],PAGE_SIZE, "\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) +{ + unsigned int cpu; + const char *curr_buf; + unsigned int curr_freq; + unsigned int op_index; + int i; + int isok; + char *next_buf; + unsigned int op_point; + ssize_t retval; + unsigned int voltage; + + static struct cpufreq_frequency_table **original_table = NULL; + + if (!policy) + return -ENODEV; + cpu = policy->cpu; + if (!centrino_model[cpu] || !centrino_model[cpu]->op_points) + 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]) + { + /* Count number of frequencies and allocate memory for a copy */ + for (i=0; centrino_model[cpu]->op_points[i].frequency != CPUFREQ_TABLE_END; i++); + /* Allocate memory to store the copy */ + original_table[cpu] = (struct cpufreq_frequency_table*) kmalloc(sizeof(struct cpufreq_frequency_table)*(i+1), G$+ /* Make copy of frequency/voltage pairs */ + for (i=0; centrino_model[cpu]->op_points[i].frequency != CPUFREQ_TABLE_END; i++) + { + original_table[cpu][i].frequency = centrino_model[cpu]->op_points[i].frequency; + original_table[cpu][i].index = centrino_model[cpu]->op_points[i].index; + } + original_table[cpu][i].frequency = CPUFREQ_TABLE_END; + } + + op_index = 0; + curr_buf = buf; + next_buf = NULL; + isok = 1; + + while ((centrino_model[cpu]->op_points[op_index].frequency != CPUFREQ_TABLE_END) + && (isok)) + { + voltage = simple_strtoul(curr_buf, &next_buf, 10); + if ((next_buf != curr_buf) && (next_buf != NULL)) + { + if ((voltage >= 700) && (voltage<=1600)) + { + voltage = ((voltage - 700) >> 4) & 0xFF; + op_point = (original_table[cpu])[op_index].index; + if (voltage <= (op_point & 0xFF)) + { + //dprintk("setting control value %i to %04x\n", op_index, op_point); + op_point = (op_point & 0xFFFFFF00) | voltage; + centrino_model[cpu]->op_points[op_index].index = op_point; + } + else + { + op_point = (op_point & 0xFFFFFF00) | voltage; + dprintk("not setting control value %i to %04x because requested voltage is not lower th$+ //isok = 0; + } + } + else + { + dprintk("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 + { + dprintk("failed to parse voltage value %i\n", op_index); + isok = 0; + } + op_index++; + } + + if (isok) + { + retval = count; + curr_freq = cpufreq_get(policy->cpu); + centrino_target(policy, curr_freq, CPUFREQ_RELATION_L); + } + else + { + retval = -EINVAL; + } + + return retval; +} + +static struct freq_attr centrino_freq_attr_voltage_table = +{ + .attr = { .name = "voltage_table", .mode = 0644, .owner = THIS_MODULE }, + .show = show_user_voltage, + .store = store_user_voltage, +}; + static int centrino_cpu_init(struct cpufreq_policy *policy) { struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu]; @@ -758,6 +900,7 @@ static struct freq_attr* centrino_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, + ¢rino_freq_attr_voltage_table, NULL, };