diff options
Diffstat (limited to 'drivers/acpi/acpica/evgpe.c')
-rw-r--r-- | drivers/acpi/acpica/evgpe.c | 164 |
1 files changed, 83 insertions, 81 deletions
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index aa70154cf4fa..5ed064e8673c 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c | |||
@@ -5,7 +5,7 @@ | |||
5 | *****************************************************************************/ | 5 | *****************************************************************************/ |
6 | 6 | ||
7 | /* | 7 | /* |
8 | * Copyright (C) 2000 - 2014, Intel Corp. | 8 | * Copyright (C) 2000 - 2015, Intel Corp. |
9 | * All rights reserved. | 9 | * All rights reserved. |
10 | * | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | 11 | * Redistribution and use in source and binary forms, with or without |
@@ -114,17 +114,6 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) | |||
114 | 114 | ||
115 | ACPI_FUNCTION_TRACE(ev_enable_gpe); | 115 | ACPI_FUNCTION_TRACE(ev_enable_gpe); |
116 | 116 | ||
117 | /* | ||
118 | * We will only allow a GPE to be enabled if it has either an associated | ||
119 | * method (_Lxx/_Exx) or a handler, or is using the implicit notify | ||
120 | * feature. Otherwise, the GPE will be immediately disabled by | ||
121 | * acpi_ev_gpe_dispatch the first time it fires. | ||
122 | */ | ||
123 | if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == | ||
124 | ACPI_GPE_DISPATCH_NONE) { | ||
125 | return_ACPI_STATUS(AE_NO_HANDLER); | ||
126 | } | ||
127 | |||
128 | /* Clear the GPE (of stale events) */ | 117 | /* Clear the GPE (of stale events) */ |
129 | 118 | ||
130 | status = acpi_hw_clear_gpe(gpe_event_info); | 119 | status = acpi_hw_clear_gpe(gpe_event_info); |
@@ -339,7 +328,11 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) | |||
339 | { | 328 | { |
340 | acpi_status status; | 329 | acpi_status status; |
341 | struct acpi_gpe_block_info *gpe_block; | 330 | struct acpi_gpe_block_info *gpe_block; |
331 | struct acpi_namespace_node *gpe_device; | ||
342 | struct acpi_gpe_register_info *gpe_register_info; | 332 | struct acpi_gpe_register_info *gpe_register_info; |
333 | struct acpi_gpe_event_info *gpe_event_info; | ||
334 | u32 gpe_number; | ||
335 | struct acpi_gpe_handler_info *gpe_handler_info; | ||
343 | u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; | 336 | u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; |
344 | u8 enabled_status_byte; | 337 | u8 enabled_status_byte; |
345 | u32 status_reg; | 338 | u32 status_reg; |
@@ -367,6 +360,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) | |||
367 | 360 | ||
368 | gpe_block = gpe_xrupt_list->gpe_block_list_head; | 361 | gpe_block = gpe_xrupt_list->gpe_block_list_head; |
369 | while (gpe_block) { | 362 | while (gpe_block) { |
363 | gpe_device = gpe_block->node; | ||
364 | |||
370 | /* | 365 | /* |
371 | * Read all of the 8-bit GPE status and enable registers in this GPE | 366 | * Read all of the 8-bit GPE status and enable registers in this GPE |
372 | * block, saving all of them. Find all currently active GP events. | 367 | * block, saving all of them. Find all currently active GP events. |
@@ -442,16 +437,68 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list) | |||
442 | 437 | ||
443 | /* Examine one GPE bit */ | 438 | /* Examine one GPE bit */ |
444 | 439 | ||
440 | gpe_event_info = | ||
441 | &gpe_block-> | ||
442 | event_info[((acpi_size) i * | ||
443 | ACPI_GPE_REGISTER_WIDTH) + j]; | ||
444 | gpe_number = | ||
445 | j + gpe_register_info->base_gpe_number; | ||
446 | |||
445 | if (enabled_status_byte & (1 << j)) { | 447 | if (enabled_status_byte & (1 << j)) { |
446 | /* | 448 | |
447 | * Found an active GPE. Dispatch the event to a handler | 449 | /* Invoke global event handler if present */ |
448 | * or method. | 450 | |
449 | */ | 451 | acpi_gpe_count++; |
450 | int_status |= | 452 | if (acpi_gbl_global_event_handler) { |
451 | acpi_ev_gpe_dispatch(gpe_block-> | 453 | acpi_gbl_global_event_handler |
452 | node, | 454 | (ACPI_EVENT_TYPE_GPE, |
453 | &gpe_block-> | 455 | gpe_device, gpe_number, |
454 | event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number); | 456 | acpi_gbl_global_event_handler_context); |
457 | } | ||
458 | |||
459 | /* Found an active GPE */ | ||
460 | |||
461 | if (ACPI_GPE_DISPATCH_TYPE | ||
462 | (gpe_event_info->flags) == | ||
463 | ACPI_GPE_DISPATCH_RAW_HANDLER) { | ||
464 | |||
465 | /* Dispatch the event to a raw handler */ | ||
466 | |||
467 | gpe_handler_info = | ||
468 | gpe_event_info->dispatch. | ||
469 | handler; | ||
470 | |||
471 | /* | ||
472 | * There is no protection around the namespace node | ||
473 | * and the GPE handler to ensure a safe destruction | ||
474 | * because: | ||
475 | * 1. The namespace node is expected to always | ||
476 | * exist after loading a table. | ||
477 | * 2. The GPE handler is expected to be flushed by | ||
478 | * acpi_os_wait_events_complete() before the | ||
479 | * destruction. | ||
480 | */ | ||
481 | acpi_os_release_lock | ||
482 | (acpi_gbl_gpe_lock, flags); | ||
483 | int_status |= | ||
484 | gpe_handler_info-> | ||
485 | address(gpe_device, | ||
486 | gpe_number, | ||
487 | gpe_handler_info-> | ||
488 | context); | ||
489 | flags = | ||
490 | acpi_os_acquire_lock | ||
491 | (acpi_gbl_gpe_lock); | ||
492 | } else { | ||
493 | /* | ||
494 | * Dispatch the event to a standard handler or | ||
495 | * method. | ||
496 | */ | ||
497 | int_status |= | ||
498 | acpi_ev_gpe_dispatch | ||
499 | (gpe_device, gpe_event_info, | ||
500 | gpe_number); | ||
501 | } | ||
455 | } | 502 | } |
456 | } | 503 | } |
457 | } | 504 | } |
@@ -484,52 +531,15 @@ unlock_and_exit: | |||
484 | static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | 531 | static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) |
485 | { | 532 | { |
486 | struct acpi_gpe_event_info *gpe_event_info = context; | 533 | struct acpi_gpe_event_info *gpe_event_info = context; |
487 | acpi_status status; | 534 | acpi_status status = AE_OK; |
488 | struct acpi_gpe_event_info *local_gpe_event_info; | ||
489 | struct acpi_evaluate_info *info; | 535 | struct acpi_evaluate_info *info; |
490 | struct acpi_gpe_notify_info *notify; | 536 | struct acpi_gpe_notify_info *notify; |
491 | 537 | ||
492 | ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); | 538 | ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); |
493 | 539 | ||
494 | /* Allocate a local GPE block */ | ||
495 | |||
496 | local_gpe_event_info = | ||
497 | ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_event_info)); | ||
498 | if (!local_gpe_event_info) { | ||
499 | ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "while handling a GPE")); | ||
500 | return_VOID; | ||
501 | } | ||
502 | |||
503 | status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); | ||
504 | if (ACPI_FAILURE(status)) { | ||
505 | ACPI_FREE(local_gpe_event_info); | ||
506 | return_VOID; | ||
507 | } | ||
508 | |||
509 | /* Must revalidate the gpe_number/gpe_block */ | ||
510 | |||
511 | if (!acpi_ev_valid_gpe_event(gpe_event_info)) { | ||
512 | status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); | ||
513 | ACPI_FREE(local_gpe_event_info); | ||
514 | return_VOID; | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * Take a snapshot of the GPE info for this level - we copy the info to | ||
519 | * prevent a race condition with remove_handler/remove_block. | ||
520 | */ | ||
521 | ACPI_MEMCPY(local_gpe_event_info, gpe_event_info, | ||
522 | sizeof(struct acpi_gpe_event_info)); | ||
523 | |||
524 | status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); | ||
525 | if (ACPI_FAILURE(status)) { | ||
526 | ACPI_FREE(local_gpe_event_info); | ||
527 | return_VOID; | ||
528 | } | ||
529 | |||
530 | /* Do the correct dispatch - normal method or implicit notify */ | 540 | /* Do the correct dispatch - normal method or implicit notify */ |
531 | 541 | ||
532 | switch (local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { | 542 | switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) { |
533 | case ACPI_GPE_DISPATCH_NOTIFY: | 543 | case ACPI_GPE_DISPATCH_NOTIFY: |
534 | /* | 544 | /* |
535 | * Implicit notify. | 545 | * Implicit notify. |
@@ -542,7 +552,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | |||
542 | * June 2012: Expand implicit notify mechanism to support | 552 | * June 2012: Expand implicit notify mechanism to support |
543 | * notifies on multiple device objects. | 553 | * notifies on multiple device objects. |
544 | */ | 554 | */ |
545 | notify = local_gpe_event_info->dispatch.notify_list; | 555 | notify = gpe_event_info->dispatch.notify_list; |
546 | while (ACPI_SUCCESS(status) && notify) { | 556 | while (ACPI_SUCCESS(status) && notify) { |
547 | status = | 557 | status = |
548 | acpi_ev_queue_notify_request(notify->device_node, | 558 | acpi_ev_queue_notify_request(notify->device_node, |
@@ -566,7 +576,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | |||
566 | * _Lxx/_Exx control method that corresponds to this GPE | 576 | * _Lxx/_Exx control method that corresponds to this GPE |
567 | */ | 577 | */ |
568 | info->prefix_node = | 578 | info->prefix_node = |
569 | local_gpe_event_info->dispatch.method_node; | 579 | gpe_event_info->dispatch.method_node; |
570 | info->flags = ACPI_IGNORE_RETURN_VALUE; | 580 | info->flags = ACPI_IGNORE_RETURN_VALUE; |
571 | 581 | ||
572 | status = acpi_ns_evaluate(info); | 582 | status = acpi_ns_evaluate(info); |
@@ -576,25 +586,27 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | |||
576 | if (ACPI_FAILURE(status)) { | 586 | if (ACPI_FAILURE(status)) { |
577 | ACPI_EXCEPTION((AE_INFO, status, | 587 | ACPI_EXCEPTION((AE_INFO, status, |
578 | "while evaluating GPE method [%4.4s]", | 588 | "while evaluating GPE method [%4.4s]", |
579 | acpi_ut_get_node_name | 589 | acpi_ut_get_node_name(gpe_event_info-> |
580 | (local_gpe_event_info->dispatch. | 590 | dispatch. |
581 | method_node))); | 591 | method_node))); |
582 | } | 592 | } |
583 | break; | 593 | break; |
584 | 594 | ||
585 | default: | 595 | default: |
586 | 596 | ||
587 | return_VOID; /* Should never happen */ | 597 | goto error_exit; /* Should never happen */ |
588 | } | 598 | } |
589 | 599 | ||
590 | /* Defer enabling of GPE until all notify handlers are done */ | 600 | /* Defer enabling of GPE until all notify handlers are done */ |
591 | 601 | ||
592 | status = acpi_os_execute(OSL_NOTIFY_HANDLER, | 602 | status = acpi_os_execute(OSL_NOTIFY_HANDLER, |
593 | acpi_ev_asynch_enable_gpe, | 603 | acpi_ev_asynch_enable_gpe, gpe_event_info); |
594 | local_gpe_event_info); | 604 | if (ACPI_SUCCESS(status)) { |
595 | if (ACPI_FAILURE(status)) { | 605 | return_VOID; |
596 | ACPI_FREE(local_gpe_event_info); | ||
597 | } | 606 | } |
607 | |||
608 | error_exit: | ||
609 | acpi_ev_asynch_enable_gpe(gpe_event_info); | ||
598 | return_VOID; | 610 | return_VOID; |
599 | } | 611 | } |
600 | 612 | ||
@@ -622,7 +634,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context) | |||
622 | (void)acpi_ev_finish_gpe(gpe_event_info); | 634 | (void)acpi_ev_finish_gpe(gpe_event_info); |
623 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | 635 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); |
624 | 636 | ||
625 | ACPI_FREE(gpe_event_info); | ||
626 | return; | 637 | return; |
627 | } | 638 | } |
628 | 639 | ||
@@ -692,15 +703,6 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, | |||
692 | 703 | ||
693 | ACPI_FUNCTION_TRACE(ev_gpe_dispatch); | 704 | ACPI_FUNCTION_TRACE(ev_gpe_dispatch); |
694 | 705 | ||
695 | /* Invoke global event handler if present */ | ||
696 | |||
697 | acpi_gpe_count++; | ||
698 | if (acpi_gbl_global_event_handler) { | ||
699 | acpi_gbl_global_event_handler(ACPI_EVENT_TYPE_GPE, gpe_device, | ||
700 | gpe_number, | ||
701 | acpi_gbl_global_event_handler_context); | ||
702 | } | ||
703 | |||
704 | /* | 706 | /* |
705 | * Always disable the GPE so that it does not keep firing before | 707 | * Always disable the GPE so that it does not keep firing before |
706 | * any asynchronous activity completes (either from the execution | 708 | * any asynchronous activity completes (either from the execution |
@@ -741,7 +743,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device, | |||
741 | * If there is neither a handler nor a method, leave the GPE | 743 | * If there is neither a handler nor a method, leave the GPE |
742 | * disabled. | 744 | * disabled. |
743 | */ | 745 | */ |
744 | switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { | 746 | switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) { |
745 | case ACPI_GPE_DISPATCH_HANDLER: | 747 | case ACPI_GPE_DISPATCH_HANDLER: |
746 | 748 | ||
747 | /* Invoke the installed handler (at interrupt level) */ | 749 | /* Invoke the installed handler (at interrupt level) */ |