aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/ec.c55
1 files changed, 36 insertions, 19 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 1fa14634c3f6..982b67faaaf3 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -77,11 +77,12 @@ enum ec_command {
77 77
78enum { 78enum {
79 EC_FLAGS_QUERY_PENDING, /* Query is pending */ 79 EC_FLAGS_QUERY_PENDING, /* Query is pending */
80 EC_FLAGS_GPE_STORM, /* GPE storm detected */
81 EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and 80 EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and
82 * OpReg are installed */ 81 * OpReg are installed */
83 EC_FLAGS_STARTED, /* Driver is started */ 82 EC_FLAGS_STARTED, /* Driver is started */
84 EC_FLAGS_STOPPED, /* Driver is stopped */ 83 EC_FLAGS_STOPPED, /* Driver is stopped */
84 EC_FLAGS_COMMAND_STORM, /* GPE storms occurred to the
85 * current command processing */
85}; 86};
86 87
87#define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ 88#define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */
@@ -229,8 +230,10 @@ static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open)
229{ 230{
230 if (open) 231 if (open)
231 acpi_enable_gpe(NULL, ec->gpe); 232 acpi_enable_gpe(NULL, ec->gpe);
232 else 233 else {
234 BUG_ON(ec->reference_count < 1);
233 acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE); 235 acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
236 }
234 if (acpi_ec_is_gpe_raised(ec)) { 237 if (acpi_ec_is_gpe_raised(ec)) {
235 /* 238 /*
236 * On some platforms, EN=1 writes cannot trigger GPE. So 239 * On some platforms, EN=1 writes cannot trigger GPE. So
@@ -246,8 +249,10 @@ static inline void acpi_ec_disable_gpe(struct acpi_ec *ec, bool close)
246{ 249{
247 if (close) 250 if (close)
248 acpi_disable_gpe(NULL, ec->gpe); 251 acpi_disable_gpe(NULL, ec->gpe);
249 else 252 else {
253 BUG_ON(ec->reference_count < 1);
250 acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE); 254 acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
255 }
251} 256}
252 257
253static inline void acpi_ec_clear_gpe(struct acpi_ec *ec) 258static inline void acpi_ec_clear_gpe(struct acpi_ec *ec)
@@ -290,6 +295,24 @@ static void acpi_ec_complete_request(struct acpi_ec *ec)
290 wake_up(&ec->wait); 295 wake_up(&ec->wait);
291} 296}
292 297
298static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag)
299{
300 if (!test_bit(flag, &ec->flags)) {
301 acpi_ec_disable_gpe(ec, false);
302 pr_debug("+++++ Polling enabled +++++\n");
303 set_bit(flag, &ec->flags);
304 }
305}
306
307static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag)
308{
309 if (test_bit(flag, &ec->flags)) {
310 clear_bit(flag, &ec->flags);
311 acpi_ec_enable_gpe(ec, false);
312 pr_debug("+++++ Polling disabled +++++\n");
313 }
314}
315
293/* 316/*
294 * acpi_ec_submit_flushable_request() - Increase the reference count unless 317 * acpi_ec_submit_flushable_request() - Increase the reference count unless
295 * the flush operation is not in 318 * the flush operation is not in
@@ -404,8 +427,13 @@ err:
404 * otherwise will take a not handled IRQ as a false one. 427 * otherwise will take a not handled IRQ as a false one.
405 */ 428 */
406 if (!(status & ACPI_EC_FLAG_SCI)) { 429 if (!(status & ACPI_EC_FLAG_SCI)) {
407 if (in_interrupt() && t) 430 if (in_interrupt() && t) {
408 ++t->irq_count; 431 if (t->irq_count < ec_storm_threshold)
432 ++t->irq_count;
433 /* Allow triggering on 0 threshold */
434 if (t->irq_count == ec_storm_threshold)
435 acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
436 }
409 } 437 }
410out: 438out:
411 if (status & ACPI_EC_FLAG_SCI) 439 if (status & ACPI_EC_FLAG_SCI)
@@ -482,6 +510,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
482 spin_unlock_irqrestore(&ec->lock, tmp); 510 spin_unlock_irqrestore(&ec->lock, tmp);
483 ret = ec_poll(ec); 511 ret = ec_poll(ec);
484 spin_lock_irqsave(&ec->lock, tmp); 512 spin_lock_irqsave(&ec->lock, tmp);
513 if (t->irq_count == ec_storm_threshold)
514 acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
485 pr_debug("***** Command(%s) stopped *****\n", 515 pr_debug("***** Command(%s) stopped *****\n",
486 acpi_ec_cmd_string(t->command)); 516 acpi_ec_cmd_string(t->command));
487 ec->curr = NULL; 517 ec->curr = NULL;
@@ -509,24 +539,11 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
509 goto unlock; 539 goto unlock;
510 } 540 }
511 } 541 }
512 /* disable GPE during transaction if storm is detected */
513 if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
514 /* It has to be disabled, so that it doesn't trigger. */
515 acpi_ec_disable_gpe(ec, false);
516 }
517 542
518 status = acpi_ec_transaction_unlocked(ec, t); 543 status = acpi_ec_transaction_unlocked(ec, t);
519 544
520 if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { 545 if (test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags))
521 msleep(1); 546 msleep(1);
522 /* It is safe to enable the GPE outside of the transaction. */
523 acpi_ec_enable_gpe(ec, false);
524 } else if (t->irq_count > ec_storm_threshold) {
525 pr_info("GPE storm detected(%d GPEs), "
526 "transactions will use polling mode\n",
527 t->irq_count);
528 set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
529 }
530 if (ec->global_lock) 547 if (ec->global_lock)
531 acpi_release_global_lock(glk); 548 acpi_release_global_lock(glk);
532unlock: 549unlock: