Commit 2c81ce4c authored by Alexey Starikovskiy's avatar Alexey Starikovskiy Committed by Len Brown

ACPI: EC: Handle IRQ storm on Acer laptops

On some Acer systems, the HW fails to clear the GPE source,
causing an interrupt storm.

So in EC interrupt mode, we count how many interrupts we
receive when waiting.  If we get more than 5, we give
up on interrupt mode and revert to polling mode.

Also, for polling mode to work on Acers, we need
to insert a delay.
Signed-off-by: default avatarAlexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 2f44bbb4
...@@ -129,6 +129,7 @@ static struct acpi_ec { ...@@ -129,6 +129,7 @@ static struct acpi_ec {
struct mutex lock; struct mutex lock;
wait_queue_head_t wait; wait_queue_head_t wait;
struct list_head list; struct list_head list;
atomic_t irq_count;
u8 handlers_installed; u8 handlers_installed;
} *boot_ec, *first_ec; } *boot_ec, *first_ec;
...@@ -181,6 +182,8 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) ...@@ -181,6 +182,8 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
{ {
int ret = 0; int ret = 0;
atomic_set(&ec->irq_count, 0);
if (unlikely(event == ACPI_EC_EVENT_OBF_1 && if (unlikely(event == ACPI_EC_EVENT_OBF_1 &&
test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags))) test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags)))
force_poll = 1; force_poll = 1;
...@@ -227,6 +230,7 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) ...@@ -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)) { while (time_before(jiffies, delay)) {
if (acpi_ec_check_status(ec, event)) if (acpi_ec_check_status(ec, event))
goto end; goto end;
msleep(5);
} }
} }
pr_err(PREFIX "acpi_ec_wait timeout," pr_err(PREFIX "acpi_ec_wait timeout,"
...@@ -529,6 +533,13 @@ static u32 acpi_ec_gpe_handler(void *data) ...@@ -529,6 +533,13 @@ static u32 acpi_ec_gpe_handler(void *data)
struct acpi_ec *ec = data; struct acpi_ec *ec = data;
pr_debug(PREFIX "~~~> interrupt\n"); 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); clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
wake_up(&ec->wait); wake_up(&ec->wait);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment