diff options
| -rw-r--r-- | drivers/acpi/ec.c | 55 |
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 | ||
| 78 | enum { | 78 | enum { |
| 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 | ||
| 253 | static inline void acpi_ec_clear_gpe(struct acpi_ec *ec) | 258 | static 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 | ||
| 298 | static 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 | |||
| 307 | static 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 | } |
| 410 | out: | 438 | out: |
| 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); |
| 532 | unlock: | 549 | unlock: |
