]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/acpi/ec.c
ACPI: EC: Handle IRQ storm on Acer laptops
[linux-2.6.git] / drivers / acpi / ec.c
index caf873c14bfb244a89ba9c322ada05c3c2b3c04e..2c77359dbdc968a242044562ea8e411527bb4ec5 100644 (file)
@@ -129,6 +129,7 @@ static struct acpi_ec {
        struct mutex lock;
        wait_queue_head_t wait;
        struct list_head list;
+       atomic_t irq_count;
        u8 handlers_installed;
 } *boot_ec, *first_ec;
 
@@ -181,6 +182,8 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
 {
        int ret = 0;
 
+       atomic_set(&ec->irq_count, 0);
+
        if (unlikely(event == ACPI_EC_EVENT_OBF_1 &&
                     test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags)))
                force_poll = 1;
@@ -227,6 +230,7 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
                while (time_before(jiffies, delay)) {
                        if (acpi_ec_check_status(ec, event))
                                goto end;
+                       msleep(5);
                }
        }
        pr_err(PREFIX "acpi_ec_wait timeout,"
@@ -529,6 +533,13 @@ static u32 acpi_ec_gpe_handler(void *data)
        struct acpi_ec *ec = data;
 
        pr_debug(PREFIX "~~~> interrupt\n");
+       atomic_inc(&ec->irq_count);
+       if (atomic_read(&ec->irq_count) > 5) {
+               pr_err(PREFIX "GPE storm detected, disabling EC GPE\n");
+               acpi_disable_gpe(NULL, ec->gpe, ACPI_ISR);
+               clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+               return ACPI_INTERRUPT_HANDLED;
+       }
        clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
        if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
                wake_up(&ec->wait);