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: Alexey Starikovskiy <astarikovskiy@suse.de> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
2f44bbb495
commit
2c81ce4c9c
1 changed files with 11 additions and 0 deletions
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue