Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff -u a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
- --- a/drivers/cpufreq/acpi-cpufreq.c 2011-07-22 04:17:23.000000000 +0200
- +++ b/drivers/cpufreq/acpi-cpufreq.c 2011-10-22 19:28:27.000000000 +0200
- @@ -23,6 +23,11 @@
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- + *
- + * This file has been patched with Linux PHC: www.linux-phc.org
- + * Patch version: linux-phc-0.3.2
- + *
- + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
- #include <linux/kernel.h>
- @@ -58,12 +63,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);
- @@ -99,13 +109,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;
- @@ -699,6 +710,8 @@
- acpi_processor_unregister_performance(data->acpi_data,
- policy->cpu);
- kfree(data->freq_table);
- + if (data->original_controls)
- + kfree(data->original_controls);
- kfree(data);
- }
- @@ -716,8 +729,501 @@
- 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);
- +}
- +
- +/**
- + * check if the cpu we are running on is capable of setting new control data
- + */
- +static bool check_cpu_control_capability(struct acpi_cpufreq_data *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;
- +}
- +
- +/**
- + * display phc's voltage id's
- + */
- +static ssize_t show_freq_attr_vids(struct cpufreq_policy *policy, char *buf)
- +{
- + 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;
- +}
- +
- +/**
- + * display acpi's default voltage id's
- + */
- +static ssize_t show_freq_attr_default_vids(struct cpufreq_policy *policy, char *buf)
- +{
- + 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;
- +}
- +
- +/**
- + * display phc's frequeny id's
- + */
- +static ssize_t show_freq_attr_fids(struct cpufreq_policy *policy, char *buf)
- +{
- + 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;
- +}
- +
- +/**
- + * display phc's controls for the cpu (frequency id's and related voltage id's)
- + */
- +static ssize_t show_freq_attr_controls(struct cpufreq_policy *policy, char *buf)
- +{
- + 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;
- +}
- +
- +/**
- + * display acpi's default controls for the cpu (frequency id's and related voltage id's)
- + */
- +static ssize_t show_freq_attr_default_controls(struct cpufreq_policy *policy, char *buf)
- +{
- + 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;
- +}
- +
- +/**
- + * 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.
- + */
- +static ssize_t store_freq_attr_vids(struct cpufreq_policy *policy, const char *buf, size_t count)
- +
- +{
- + 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;
- + pr_debug("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;
- +}
- +
- +/**
- + * 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.
- + */
- +static ssize_t store_freq_attr_controls(struct cpufreq_policy *policy, const char *buf, size_t count)
- +{
- + 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;
- + pr_debug("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;
- +}
- +
- +/**
- + * print out the phc version string set at the beginning of that file
- + */
- +static ssize_t show_freq_attr_phc_version(struct cpufreq_policy *policy, char *buf)
- +{
- + ssize_t count = 0;
- + count += sprintf(&buf[count], "%s\n", PHC_VERSION_STRING);
- + return count;
- +}
- +
- +/**
- + * display phc's version string
- + */
- +static struct freq_attr cpufreq_freq_attr_phc_version =
- +{
- + .attr = { .name = "phc_version",
- + .mode = 0444,
- +// .owner = THIS_MODULE
- + },
- + .show = show_freq_attr_phc_version,
- + .store = NULL,
- +};
- +
- +/**
- + * display phc's voltage id's for the cpu
- + */
- +static struct freq_attr cpufreq_freq_attr_vids =
- +{
- + .attr = { .name = "phc_vids",
- + .mode = 0644,
- +// .owner = THIS_MODULE
- + },
- + .show = show_freq_attr_vids,
- + .store = store_freq_attr_vids,
- +};
- +
- +/**
- + * display acpi's default frequency id's for the cpu
- + */
- +static struct freq_attr cpufreq_freq_attr_default_vids =
- +{
- + .attr = { .name = "phc_default_vids",
- + .mode = 0444,
- +// .owner = THIS_MODULE
- + },
- + .show = show_freq_attr_default_vids,
- + .store = NULL,
- +};
- +
- +/**
- + * display phc's default frequency id's for the cpu
- + */
- +static struct freq_attr cpufreq_freq_attr_fids =
- +{
- + .attr = { .name = "phc_fids",
- + .mode = 0444,
- +// .owner = THIS_MODULE
- + },
- + .show = show_freq_attr_fids,
- + .store = NULL,
- +};
- +
- +/**
- + * display phc's current voltage/frequency controls for the cpu
- + */
- +static struct freq_attr cpufreq_freq_attr_controls =
- +{
- + .attr = { .name = "phc_controls",
- + .mode = 0644,
- +// .owner = THIS_MODULE
- + },
- + .show = show_freq_attr_controls,
- + .store = store_freq_attr_controls,
- +};
- +
- +/**
- + * display acpi's default voltage/frequency controls for the cpu
- + */
- +static struct freq_attr cpufreq_freq_attr_default_controls =
- +{
- + .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_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,
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement