ACPI / x86: Drop PWM2 device on Lenovo Yoga Book from always present table
[platform/kernel/linux-rpi.git] / drivers / acpi / processor_idle.c
index 45a0196..f37fba9 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/acpi.h>
 #include <linux/dmi.h>
 #include <linux/sched.h>       /* need_resched() */
+#include <linux/sort.h>
 #include <linux/tick.h>
 #include <linux/cpuidle.h>
 #include <linux/cpu.h>
@@ -384,10 +385,37 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
        return;
 }
 
+static int acpi_cst_latency_cmp(const void *a, const void *b)
+{
+       const struct acpi_processor_cx *x = a, *y = b;
+
+       if (!(x->valid && y->valid))
+               return 0;
+       if (x->latency > y->latency)
+               return 1;
+       if (x->latency < y->latency)
+               return -1;
+       return 0;
+}
+static void acpi_cst_latency_swap(void *a, void *b, int n)
+{
+       struct acpi_processor_cx *x = a, *y = b;
+       u32 tmp;
+
+       if (!(x->valid && y->valid))
+               return;
+       tmp = x->latency;
+       x->latency = y->latency;
+       y->latency = tmp;
+}
+
 static int acpi_processor_power_verify(struct acpi_processor *pr)
 {
        unsigned int i;
        unsigned int working = 0;
+       unsigned int last_latency = 0;
+       unsigned int last_type = 0;
+       bool buggy_latency = false;
 
        pr->power.timer_broadcast_on_state = INT_MAX;
 
@@ -411,12 +439,24 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
                }
                if (!cx->valid)
                        continue;
+               if (cx->type >= last_type && cx->latency < last_latency)
+                       buggy_latency = true;
+               last_latency = cx->latency;
+               last_type = cx->type;
 
                lapic_timer_check_state(i, pr, cx);
                tsc_check_state(cx->type);
                working++;
        }
 
+       if (buggy_latency) {
+               pr_notice("FW issue: working around C-state latencies out of order\n");
+               sort(&pr->power.states[1], max_cstate,
+                    sizeof(struct acpi_processor_cx),
+                    acpi_cst_latency_cmp,
+                    acpi_cst_latency_swap);
+       }
+
        lapic_timer_propagate_broadcast(pr);
 
        return (working);
@@ -1261,7 +1301,7 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
        if (pr->id == 0 && cpuidle_get_driver() == &acpi_idle_driver) {
 
                /* Protect against cpu-hotplug */
-               get_online_cpus();
+               cpus_read_lock();
                cpuidle_pause_and_lock();
 
                /* Disable all cpuidle devices */
@@ -1290,7 +1330,7 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
                        }
                }
                cpuidle_resume_and_unlock();
-               put_online_cpus();
+               cpus_read_unlock();
        }
 
        return 0;