aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ec.c
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2015-02-05 19:58:05 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-02-06 09:48:09 -0500
commite1d4d90fc0313d3d58cbd7912c90f8ef24df45ff (patch)
tree9ada78f04f57cb1deadc8cc30a1efe55c396cbf0 /drivers/acpi/ec.c
parent9887d22add48f24ca3a7605c89b0a21ed337f185 (diff)
ACPI / EC: Refine command storm prevention support
This patch refines EC command storm prevention support. Current command storming code is wrong, when the storming condition is detected, it only flags the condition without doing anything for the current command but performing storming prevention for the follow-up commands. So: 1. The first command which suffers from the storming still suffers from storming. 2. The follow-up commands which may not suffer from the storming are unconditionally forced into the storming prevention mode. Ideally, we should only enable storm prevention immediately after detection for the current command so that the next command can try the power/performance efficient interrupt mode again. This patch improves the command storm prevention by disabling GPE right after the detection and re-enabling it right before completing the command transaction using the GPE storming prevention APIs. This thus deploys the following GPE handling model: 1. acpi_enable_gpe()/acpi_disable_gpe() for reference count changes: This set of APIs are used for EC usage reference counting. 2. acpi_set_gpe(ACPI_GPE_ENABLE)/acpi_set_gpe(ACPI_GPE_DISABLE): This set of APIs are used for preventing GPE storm. They must be invoked when the reference count > 0. Note that as the storming prevention should always happen when there is an outstanding request, or GPE enabling value will be messed up by the races. This patch also adds BUG_ON() to enforces this rule to prevent future bugs. The msleep(1) used after completing a transaction is useless now as this sounds like a guard time only useful for platforms that need the EC_FLAGS_MSI quirks while we have fixed GPE race issues using the previous raw handler mode enabling. It is kept to avoid regressions. A seperate patch which deletes EC_FLAGS_MSI quirks should take care of deleting it. Signed-off-by: Lv Zheng <lv.zheng@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/ec.c')
-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: