aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ec.c
diff options
context:
space:
mode:
authorAlexey Starikovskiy <astarikovskiy@suse.de>2009-12-24 03:34:16 -0500
committerLen Brown <len.brown@intel.com>2009-12-24 14:52:38 -0500
commita62e8f1978f49e52f87a711ff6711b323d4b12ff (patch)
tree7d88562acb89e12cff4c2fce18a83495428ed0a3 /drivers/acpi/ec.c
parentfcb11235d3910c39afece52f6e106a9ca565d34b (diff)
ACPI: EC: Accelerate query execution
Split EC query handling into acknowledge and execution phase. This allows much smaller pending query lattency and lowers chances of EC going "wild" and losing events. Reference: http://bugzilla.kernel.org/show_bug.cgi?id=14858 Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r--drivers/acpi/ec.c122
1 files changed, 77 insertions, 45 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index fd1801bdee66..9cc38857c33b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -201,14 +201,13 @@ unlock:
201 spin_unlock_irqrestore(&ec->curr_lock, flags); 201 spin_unlock_irqrestore(&ec->curr_lock, flags);
202} 202}
203 203
204static void acpi_ec_gpe_query(void *ec_cxt); 204static int acpi_ec_sync_query(struct acpi_ec *ec);
205 205
206static int ec_check_sci(struct acpi_ec *ec, u8 state) 206static int ec_check_sci_sync(struct acpi_ec *ec, u8 state)
207{ 207{
208 if (state & ACPI_EC_FLAG_SCI) { 208 if (state & ACPI_EC_FLAG_SCI) {
209 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) 209 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
210 return acpi_os_execute(OSL_EC_BURST_HANDLER, 210 return acpi_ec_sync_query(ec);
211 acpi_ec_gpe_query, ec);
212 } 211 }
213 return 0; 212 return 0;
214} 213}
@@ -249,11 +248,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
249{ 248{
250 unsigned long tmp; 249 unsigned long tmp;
251 int ret = 0; 250 int ret = 0;
252 pr_debug(PREFIX "transaction start\n");
253 /* disable GPE during transaction if storm is detected */
254 if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
255 acpi_disable_gpe(NULL, ec->gpe);
256 }
257 if (EC_FLAGS_MSI) 251 if (EC_FLAGS_MSI)
258 udelay(ACPI_EC_MSI_UDELAY); 252 udelay(ACPI_EC_MSI_UDELAY);
259 /* start transaction */ 253 /* start transaction */
@@ -269,16 +263,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
269 spin_lock_irqsave(&ec->curr_lock, tmp); 263 spin_lock_irqsave(&ec->curr_lock, tmp);
270 ec->curr = NULL; 264 ec->curr = NULL;
271 spin_unlock_irqrestore(&ec->curr_lock, tmp); 265 spin_unlock_irqrestore(&ec->curr_lock, tmp);
272 if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
273 /* check if we received SCI during transaction */
274 ec_check_sci(ec, acpi_ec_read_status(ec));
275 /* it is safe to enable GPE outside of transaction */
276 acpi_enable_gpe(NULL, ec->gpe);
277 } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
278 pr_info(PREFIX "GPE storm detected, "
279 "transactions will use polling mode\n");
280 set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
281 }
282 return ret; 266 return ret;
283} 267}
284 268
@@ -321,7 +305,24 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
321 status = -ETIME; 305 status = -ETIME;
322 goto end; 306 goto end;
323 } 307 }
308 pr_debug(PREFIX "transaction start\n");
309 /* disable GPE during transaction if storm is detected */
310 if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
311 acpi_disable_gpe(NULL, ec->gpe);
312 }
313
324 status = acpi_ec_transaction_unlocked(ec, t); 314 status = acpi_ec_transaction_unlocked(ec, t);
315
316 /* check if we received SCI during transaction */
317 ec_check_sci_sync(ec, acpi_ec_read_status(ec));
318 if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
319 /* it is safe to enable GPE outside of transaction */
320 acpi_enable_gpe(NULL, ec->gpe);
321 } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
322 pr_info(PREFIX "GPE storm detected, "
323 "transactions will use polling mode\n");
324 set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
325 }
325end: 326end:
326 if (ec->global_lock) 327 if (ec->global_lock)
327 acpi_release_global_lock(glk); 328 acpi_release_global_lock(glk);
@@ -443,7 +444,7 @@ int ec_transaction(u8 command,
443 444
444EXPORT_SYMBOL(ec_transaction); 445EXPORT_SYMBOL(ec_transaction);
445 446
446static int acpi_ec_query(struct acpi_ec *ec, u8 * data) 447static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
447{ 448{
448 int result; 449 int result;
449 u8 d; 450 u8 d;
@@ -452,20 +453,16 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
452 .wlen = 0, .rlen = 1}; 453 .wlen = 0, .rlen = 1};
453 if (!ec || !data) 454 if (!ec || !data)
454 return -EINVAL; 455 return -EINVAL;
455
456 /* 456 /*
457 * Query the EC to find out which _Qxx method we need to evaluate. 457 * Query the EC to find out which _Qxx method we need to evaluate.
458 * Note that successful completion of the query causes the ACPI_EC_SCI 458 * Note that successful completion of the query causes the ACPI_EC_SCI
459 * bit to be cleared (and thus clearing the interrupt source). 459 * bit to be cleared (and thus clearing the interrupt source).
460 */ 460 */
461 461 result = acpi_ec_transaction_unlocked(ec, &t);
462 result = acpi_ec_transaction(ec, &t);
463 if (result) 462 if (result)
464 return result; 463 return result;
465
466 if (!d) 464 if (!d)
467 return -ENODATA; 465 return -ENODATA;
468
469 *data = d; 466 *data = d;
470 return 0; 467 return 0;
471} 468}
@@ -509,43 +506,78 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
509 506
510EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); 507EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
511 508
512static void acpi_ec_gpe_query(void *ec_cxt) 509static void acpi_ec_run(void *cxt)
513{ 510{
514 struct acpi_ec *ec = ec_cxt; 511 struct acpi_ec_query_handler *handler = cxt;
515 u8 value = 0; 512 if (!handler)
516 struct acpi_ec_query_handler *handler, copy;
517
518 if (!ec || acpi_ec_query(ec, &value))
519 return; 513 return;
520 mutex_lock(&ec->lock); 514 pr_debug(PREFIX "start query execution\n");
515 if (handler->func)
516 handler->func(handler->data);
517 else if (handler->handle)
518 acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
519 pr_debug(PREFIX "stop query execution\n");
520 kfree(handler);
521}
522
523static int acpi_ec_sync_query(struct acpi_ec *ec)
524{
525 u8 value = 0;
526 int status;
527 struct acpi_ec_query_handler *handler, *copy;
528 if ((status = acpi_ec_query_unlocked(ec, &value)))
529 return status;
521 list_for_each_entry(handler, &ec->list, node) { 530 list_for_each_entry(handler, &ec->list, node) {
522 if (value == handler->query_bit) { 531 if (value == handler->query_bit) {
523 /* have custom handler for this bit */ 532 /* have custom handler for this bit */
524 memcpy(&copy, handler, sizeof(copy)); 533 copy = kmalloc(sizeof(*handler), GFP_KERNEL);
525 mutex_unlock(&ec->lock); 534 if (!copy)
526 if (copy.func) { 535 return -ENOMEM;
527 copy.func(copy.data); 536 memcpy(copy, handler, sizeof(*copy));
528 } else if (copy.handle) { 537 pr_debug(PREFIX "push query execution (0x%2x) on queue\n", value);
529 acpi_evaluate_object(copy.handle, NULL, NULL, NULL); 538 return acpi_os_execute(OSL_GPE_HANDLER,
530 } 539 acpi_ec_run, copy);
531 return;
532 } 540 }
533 } 541 }
542 return 0;
543}
544
545static void acpi_ec_gpe_query(void *ec_cxt)
546{
547 struct acpi_ec *ec = ec_cxt;
548 if (!ec)
549 return;
550 mutex_lock(&ec->lock);
551 acpi_ec_sync_query(ec);
534 mutex_unlock(&ec->lock); 552 mutex_unlock(&ec->lock);
535} 553}
536 554
555static void acpi_ec_gpe_query(void *ec_cxt);
556
557static int ec_check_sci(struct acpi_ec *ec, u8 state)
558{
559 if (state & ACPI_EC_FLAG_SCI) {
560 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
561 pr_debug(PREFIX "push gpe query to the queue\n");
562 return acpi_os_execute(OSL_NOTIFY_HANDLER,
563 acpi_ec_gpe_query, ec);
564 }
565 }
566 return 0;
567}
568
537static u32 acpi_ec_gpe_handler(void *data) 569static u32 acpi_ec_gpe_handler(void *data)
538{ 570{
539 struct acpi_ec *ec = data; 571 struct acpi_ec *ec = data;
540 u8 status;
541 572
542 pr_debug(PREFIX "~~~> interrupt\n"); 573 pr_debug(PREFIX "~~~> interrupt\n");
543 status = acpi_ec_read_status(ec);
544 574
545 advance_transaction(ec, status); 575 advance_transaction(ec, acpi_ec_read_status(ec));
546 if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0) 576 if (ec_transaction_done(ec) &&
577 (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
547 wake_up(&ec->wait); 578 wake_up(&ec->wait);
548 ec_check_sci(ec, status); 579 ec_check_sci(ec, acpi_ec_read_status(ec));
580 }
549 return ACPI_INTERRUPT_HANDLED; 581 return ACPI_INTERRUPT_HANDLED;
550} 582}
551 583