Merge branches 'battery-2.6.34', 'bugzilla-10805', 'bugzilla-14668', 'bugzilla-531916...
[safe/jmp/linux-2.6] / drivers / acpi / processor_throttling.c
index d278381..29c6f57 100644 (file)
 #include <acpi/acpi_drivers.h>
 #include <acpi/processor.h>
 
+#define PREFIX "ACPI: "
+
 #define ACPI_PROCESSOR_CLASS            "processor"
 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_throttling");
 
+/* ignore_tpc:
+ *  0 -> acpi processor driver doesn't ignore _TPC values
+ *  1 -> acpi processor driver ignores _TPC values
+ */
+static int ignore_tpc;
+module_param(ignore_tpc, int, 0644);
+MODULE_PARM_DESC(ignore_tpc, "Disable broken BIOS _TPC throttling support");
+
 struct throttling_tstate {
        unsigned int cpu;               /* cpu nr */
        int target_state;               /* target T-state */
@@ -54,7 +64,8 @@ struct throttling_tstate {
 #define THROTTLING_POSTCHANGE      (2)
 
 static int acpi_processor_get_throttling(struct acpi_processor *pr);
-int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
+int acpi_processor_set_throttling(struct acpi_processor *pr,
+                                               int state, bool force);
 
 static int acpi_processor_update_tsd_coord(void)
 {
@@ -66,7 +77,7 @@ static int acpi_processor_update_tsd_coord(void)
        struct acpi_tsd_package *pdomain, *match_pdomain;
        struct acpi_processor_throttling *pthrottling, *match_pthrottling;
 
-       if (!alloc_cpumask_var(&covered_cpus, GFP_KERNEL))
+       if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
                return -ENOMEM;
 
        /*
@@ -94,7 +105,6 @@ static int acpi_processor_update_tsd_coord(void)
        if (retval)
                goto err_ret;
 
-       cpumask_clear(covered_cpus);
        for_each_possible_cpu(i) {
                pr = per_cpu(processors, i);
                if (!pr)
@@ -283,6 +293,10 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
 
        if (!pr)
                return -EINVAL;
+
+       if (ignore_tpc)
+               goto end;
+
        status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc);
        if (ACPI_FAILURE(status)) {
                if (status != AE_NOT_FOUND) {
@@ -290,6 +304,8 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
                }
                return -ENODEV;
        }
+
+end:
        pr->throttling_platform_limit = (int)tpc;
        return 0;
 }
@@ -302,6 +318,9 @@ int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
        struct acpi_processor_limit *limit;
        int target_state;
 
+       if (ignore_tpc)
+               return 0;
+
        result = acpi_processor_get_platform_limit(pr);
        if (result) {
                /* Throttling Limit is unsupported */
@@ -344,7 +363,7 @@ int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
                 */
                target_state = throttling_limit;
        }
-       return acpi_processor_set_throttling(pr, target_state);
+       return acpi_processor_set_throttling(pr, target_state, false);
 }
 
 /*
@@ -641,7 +660,7 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
 
 #ifdef CONFIG_X86
 static int acpi_throttling_rdmsr(struct acpi_processor *pr,
-                                       acpi_integer * value)
+                                       u64 *value)
 {
        struct cpuinfo_x86 *c;
        u64 msr_high, msr_low;
@@ -662,13 +681,13 @@ static int acpi_throttling_rdmsr(struct acpi_processor *pr,
                rdmsr_safe(MSR_IA32_THERM_CONTROL,
                        (u32 *)&msr_low , (u32 *) &msr_high);
                msr = (msr_high << 32) | msr_low;
-               *value = (acpi_integer) msr;
+               *value = (u64) msr;
                ret = 0;
        }
        return ret;
 }
 
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
+static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
 {
        struct cpuinfo_x86 *c;
        unsigned int cpu;
@@ -692,14 +711,14 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
 }
 #else
 static int acpi_throttling_rdmsr(struct acpi_processor *pr,
-                               acpi_integer * value)
+                               u64 *value)
 {
        printk(KERN_ERR PREFIX
                "HARDWARE addr space,NOT supported yet\n");
        return -1;
 }
 
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
+static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
 {
        printk(KERN_ERR PREFIX
                "HARDWARE addr space,NOT supported yet\n");
@@ -708,7 +727,7 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
 #endif
 
 static int acpi_read_throttling_status(struct acpi_processor *pr,
-                                       acpi_integer *value)
+                                       u64 *value)
 {
        u32 bit_width, bit_offset;
        u64 ptc_value;
@@ -727,7 +746,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,
                                  address, (u32 *) &ptc_value,
                                  (u32) (bit_width + bit_offset));
                ptc_mask = (1 << bit_width) - 1;
-               *value = (acpi_integer) ((ptc_value >> bit_offset) & ptc_mask);
+               *value = (u64) ((ptc_value >> bit_offset) & ptc_mask);
                ret = 0;
                break;
        case ACPI_ADR_SPACE_FIXED_HARDWARE:
@@ -741,7 +760,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,
 }
 
 static int acpi_write_throttling_state(struct acpi_processor *pr,
-                               acpi_integer value)
+                               u64 value)
 {
        u32 bit_width, bit_offset;
        u64 ptc_value;
@@ -774,7 +793,7 @@ static int acpi_write_throttling_state(struct acpi_processor *pr,
 }
 
 static int acpi_get_throttling_state(struct acpi_processor *pr,
-                               acpi_integer value)
+                               u64 value)
 {
        int i;
 
@@ -783,15 +802,13 @@ static int acpi_get_throttling_state(struct acpi_processor *pr,
                    (struct acpi_processor_tx_tss *)&(pr->throttling.
                                                      states_tss[i]);
                if (tx->control == value)
-                       break;
+                       return i;
        }
-       if (i > pr->throttling.state_count)
-               i = -1;
-       return i;
+       return -1;
 }
 
 static int acpi_get_throttling_value(struct acpi_processor *pr,
-                       int state, acpi_integer *value)
+                       int state, u64 *value)
 {
        int ret = -1;
 
@@ -809,7 +826,7 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
 {
        int state = 0;
        int ret;
-       acpi_integer value;
+       u64 value;
 
        if (!pr)
                return -EINVAL;
@@ -823,6 +840,14 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
        ret = acpi_read_throttling_status(pr, &value);
        if (ret >= 0) {
                state = acpi_get_throttling_state(pr, value);
+               if (state == -1) {
+                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                               "Invalid throttling state, reset\n"));
+                       state = 0;
+                       ret = acpi_processor_set_throttling(pr, state, true);
+                       if (ret)
+                               return ret;
+               }
                pr->throttling.state = state;
        }
 
@@ -892,7 +917,7 @@ static int acpi_processor_get_fadt_info(struct acpi_processor *pr)
 }
 
 static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
-                                             int state)
+                                             int state, bool force)
 {
        u32 value = 0;
        u32 duty_mask = 0;
@@ -907,7 +932,7 @@ static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
        if (!pr->flags.throttling)
                return -ENODEV;
 
-       if (state == pr->throttling.state)
+       if (!force && (state == pr->throttling.state))
                return 0;
 
        if (state < pr->throttling_platform_limit)
@@ -965,10 +990,10 @@ static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
 }
 
 static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
-                                            int state)
+                                            int state, bool force)
 {
        int ret;
-       acpi_integer value;
+       u64 value;
 
        if (!pr)
                return -EINVAL;
@@ -979,7 +1004,7 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
        if (!pr->flags.throttling)
                return -ENODEV;
 
-       if (state == pr->throttling.state)
+       if (!force && (state == pr->throttling.state))
                return 0;
 
        if (state < pr->throttling_platform_limit)
@@ -995,7 +1020,8 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
        return 0;
 }
 
-int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
+int acpi_processor_set_throttling(struct acpi_processor *pr,
+                                               int state, bool force)
 {
        cpumask_var_t saved_mask;
        int ret = 0;
@@ -1047,7 +1073,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
                /* FIXME: use work_on_cpu() */
                set_cpus_allowed_ptr(current, cpumask_of(pr->id));
                ret = p_throttling->acpi_processor_set_throttling(pr,
-                                               t_state.target_state);
+                                               t_state.target_state, force);
        } else {
                /*
                 * When the T-state coordination is SW_ALL or HW_ALL,
@@ -1080,7 +1106,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
                        set_cpus_allowed_ptr(current, cpumask_of(i));
                        ret = match_pr->throttling.
                                acpi_processor_set_throttling(
-                               match_pr, t_state.target_state);
+                               match_pr, t_state.target_state, force);
                }
        }
        /*
@@ -1113,9 +1139,6 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
                          pr->throttling.duty_offset,
                          pr->throttling.duty_width));
 
-       if (!pr)
-               return -EINVAL;
-
        /*
         * Evaluate _PTC, _TSS and _TPC
         * They must all be present or none of them can be used.
@@ -1178,7 +1201,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "Disabling throttling (was T%d)\n",
                                  pr->throttling.state));
-               result = acpi_processor_set_throttling(pr, 0);
+               result = acpi_processor_set_throttling(pr, 0, false);
                if (result)
                        goto end;
        }
@@ -1191,7 +1214,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
 }
 
 /* proc interface */
-
+#ifdef CONFIG_ACPI_PROCFS
 static int acpi_processor_throttling_seq_show(struct seq_file *seq,
                                              void *offset)
 {
@@ -1284,14 +1307,14 @@ static ssize_t acpi_processor_write_throttling(struct file *file,
        if (strcmp(tmpbuf, charp) != 0)
                return -EINVAL;
 
-       result = acpi_processor_set_throttling(pr, state_val);
+       result = acpi_processor_set_throttling(pr, state_val, false);
        if (result)
                return result;
 
        return count;
 }
 
-struct file_operations acpi_processor_throttling_fops = {
+const struct file_operations acpi_processor_throttling_fops = {
        .owner = THIS_MODULE,
        .open = acpi_processor_throttling_open_fs,
        .read = seq_read,
@@ -1299,3 +1322,4 @@ struct file_operations acpi_processor_throttling_fops = {
        .llseek = seq_lseek,
        .release = single_release,
 };
+#endif