diff options
author | Alexey Starikovskiy <astarikovskiy@suse.de> | 2008-03-21 12:36:02 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-03-24 20:50:59 -0400 |
commit | fa95ba04e6ba11d71e1b87becd054b38faf546c8 (patch) | |
tree | 42bd9c980d4ef6b4c509daa4bf01ebb761ab119d | |
parent | 223883b7aafa02410ed2e571d6032c876d0b23b8 (diff) |
ACPI: EC: Detect irq storm
Problem seems to be that hw fails to clear GPE after we service it and write 1
into corresponding bit. Thus, as soon as we get interrupts enabled again, we
receive a new one. Google gives too many results for "acer interrupt storm" for
this being one-broken-machine case.
Reference: http://bugzilla.kernel.org/show_bug.cgi?id=9998
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/acpi/ec.c | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index da67d228c9ea..f0e82166bb5c 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -106,6 +106,7 @@ static struct acpi_ec { | |||
106 | wait_queue_head_t wait; | 106 | wait_queue_head_t wait; |
107 | struct list_head list; | 107 | struct list_head list; |
108 | struct delayed_work work; | 108 | struct delayed_work work; |
109 | atomic_t irq_count; | ||
109 | u8 handlers_installed; | 110 | u8 handlers_installed; |
110 | } *boot_ec, *first_ec; | 111 | } *boot_ec, *first_ec; |
111 | 112 | ||
@@ -171,6 +172,7 @@ static void ec_switch_to_poll_mode(struct acpi_ec *ec) | |||
171 | 172 | ||
172 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) | 173 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) |
173 | { | 174 | { |
175 | atomic_set(&ec->irq_count, 0); | ||
174 | if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && | 176 | if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && |
175 | likely(!force_poll)) { | 177 | likely(!force_poll)) { |
176 | if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), | 178 | if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), |
@@ -489,6 +491,12 @@ static u32 acpi_ec_gpe_handler(void *data) | |||
489 | u8 state = acpi_ec_read_status(ec); | 491 | u8 state = acpi_ec_read_status(ec); |
490 | 492 | ||
491 | pr_debug(PREFIX "~~~> interrupt\n"); | 493 | pr_debug(PREFIX "~~~> interrupt\n"); |
494 | atomic_inc(&ec->irq_count); | ||
495 | if (atomic_read(&ec->irq_count) > 5) { | ||
496 | pr_err(PREFIX "GPE storm detected, disabling EC GPE\n"); | ||
497 | ec_switch_to_poll_mode(ec); | ||
498 | goto end; | ||
499 | } | ||
492 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | 500 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
493 | if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) | 501 | if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) |
494 | wake_up(&ec->wait); | 502 | wake_up(&ec->wait); |
@@ -507,6 +515,7 @@ static u32 acpi_ec_gpe_handler(void *data) | |||
507 | set_bit(EC_FLAGS_GPE_MODE, &ec->flags); | 515 | set_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
508 | clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); | 516 | clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags); |
509 | } | 517 | } |
518 | end: | ||
510 | ec_schedule_ec_poll(ec); | 519 | ec_schedule_ec_poll(ec); |
511 | return ACPI_SUCCESS(status) ? | 520 | return ACPI_SUCCESS(status) ? |
512 | ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; | 521 | ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; |
@@ -515,6 +524,7 @@ static u32 acpi_ec_gpe_handler(void *data) | |||
515 | static void do_ec_poll(struct work_struct *work) | 524 | static void do_ec_poll(struct work_struct *work) |
516 | { | 525 | { |
517 | struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work); | 526 | struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work); |
527 | atomic_set(&ec->irq_count, 0); | ||
518 | (void)acpi_ec_gpe_handler(ec); | 528 | (void)acpi_ec_gpe_handler(ec); |
519 | } | 529 | } |
520 | 530 | ||
@@ -679,6 +689,7 @@ static struct acpi_ec *make_acpi_ec(void) | |||
679 | init_waitqueue_head(&ec->wait); | 689 | init_waitqueue_head(&ec->wait); |
680 | INIT_LIST_HEAD(&ec->list); | 690 | INIT_LIST_HEAD(&ec->list); |
681 | INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll); | 691 | INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll); |
692 | atomic_set(&ec->irq_count, 0); | ||
682 | return ec; | 693 | return ec; |
683 | } | 694 | } |
684 | 695 | ||