diff options
| -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 | ||
