diff options
-rw-r--r-- | drivers/acpi/acpica/evgpe.c | 57 |
1 files changed, 45 insertions, 12 deletions
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 3fb621eec2fa..c25999546c8c 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c | |||
@@ -52,6 +52,8 @@ ACPI_MODULE_NAME("evgpe") | |||
52 | /* Local prototypes */ | 52 | /* Local prototypes */ |
53 | static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context); | 53 | static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context); |
54 | 54 | ||
55 | static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context); | ||
56 | |||
55 | /******************************************************************************* | 57 | /******************************************************************************* |
56 | * | 58 | * |
57 | * FUNCTION: acpi_ev_update_gpe_enable_mask | 59 | * FUNCTION: acpi_ev_update_gpe_enable_mask |
@@ -441,17 +443,25 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) | |||
441 | * an interrupt handler. | 443 | * an interrupt handler. |
442 | * | 444 | * |
443 | ******************************************************************************/ | 445 | ******************************************************************************/ |
444 | static void acpi_ev_asynch_enable_gpe(void *context); | ||
445 | 446 | ||
446 | static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | 447 | static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) |
447 | { | 448 | { |
448 | struct acpi_gpe_event_info *gpe_event_info = (void *)context; | 449 | struct acpi_gpe_event_info *gpe_event_info = context; |
449 | acpi_status status; | 450 | acpi_status status; |
450 | struct acpi_gpe_event_info local_gpe_event_info; | 451 | struct acpi_gpe_event_info *local_gpe_event_info; |
451 | struct acpi_evaluate_info *info; | 452 | struct acpi_evaluate_info *info; |
452 | 453 | ||
453 | ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); | 454 | ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); |
454 | 455 | ||
456 | /* Allocate a local GPE block */ | ||
457 | |||
458 | local_gpe_event_info = | ||
459 | ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_event_info)); | ||
460 | if (!local_gpe_event_info) { | ||
461 | ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "while handling a GPE")); | ||
462 | return_VOID; | ||
463 | } | ||
464 | |||
455 | status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); | 465 | status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
456 | if (ACPI_FAILURE(status)) { | 466 | if (ACPI_FAILURE(status)) { |
457 | return_VOID; | 467 | return_VOID; |
@@ -468,7 +478,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | |||
468 | * Take a snapshot of the GPE info for this level - we copy the info to | 478 | * Take a snapshot of the GPE info for this level - we copy the info to |
469 | * prevent a race condition with remove_handler/remove_block. | 479 | * prevent a race condition with remove_handler/remove_block. |
470 | */ | 480 | */ |
471 | ACPI_MEMCPY(&local_gpe_event_info, gpe_event_info, | 481 | ACPI_MEMCPY(local_gpe_event_info, gpe_event_info, |
472 | sizeof(struct acpi_gpe_event_info)); | 482 | sizeof(struct acpi_gpe_event_info)); |
473 | 483 | ||
474 | status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); | 484 | status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
@@ -480,7 +490,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | |||
480 | * Must check for control method type dispatch one more time to avoid a | 490 | * Must check for control method type dispatch one more time to avoid a |
481 | * race with ev_gpe_install_handler | 491 | * race with ev_gpe_install_handler |
482 | */ | 492 | */ |
483 | if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == | 493 | if ((local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == |
484 | ACPI_GPE_DISPATCH_METHOD) { | 494 | ACPI_GPE_DISPATCH_METHOD) { |
485 | 495 | ||
486 | /* Allocate the evaluation information block */ | 496 | /* Allocate the evaluation information block */ |
@@ -494,7 +504,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | |||
494 | * control method that corresponds to this GPE | 504 | * control method that corresponds to this GPE |
495 | */ | 505 | */ |
496 | info->prefix_node = | 506 | info->prefix_node = |
497 | local_gpe_event_info.dispatch.method_node; | 507 | local_gpe_event_info->dispatch.method_node; |
498 | info->flags = ACPI_IGNORE_RETURN_VALUE; | 508 | info->flags = ACPI_IGNORE_RETURN_VALUE; |
499 | 509 | ||
500 | status = acpi_ns_evaluate(info); | 510 | status = acpi_ns_evaluate(info); |
@@ -505,20 +515,41 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | |||
505 | ACPI_EXCEPTION((AE_INFO, status, | 515 | ACPI_EXCEPTION((AE_INFO, status, |
506 | "while evaluating GPE method [%4.4s]", | 516 | "while evaluating GPE method [%4.4s]", |
507 | acpi_ut_get_node_name | 517 | acpi_ut_get_node_name |
508 | (local_gpe_event_info.dispatch. | 518 | (local_gpe_event_info->dispatch. |
509 | method_node))); | 519 | method_node))); |
510 | } | 520 | } |
511 | } | 521 | } |
522 | |||
512 | /* Defer enabling of GPE until all notify handlers are done */ | 523 | /* Defer enabling of GPE until all notify handlers are done */ |
513 | acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe, | 524 | |
514 | gpe_event_info); | 525 | status = acpi_os_execute(OSL_NOTIFY_HANDLER, |
526 | acpi_ev_asynch_enable_gpe, | ||
527 | local_gpe_event_info); | ||
528 | if (ACPI_FAILURE(status)) { | ||
529 | ACPI_FREE(local_gpe_event_info); | ||
530 | } | ||
515 | return_VOID; | 531 | return_VOID; |
516 | } | 532 | } |
517 | 533 | ||
518 | static void acpi_ev_asynch_enable_gpe(void *context) | 534 | /******************************************************************************* |
535 | * | ||
536 | * FUNCTION: acpi_ev_asynch_enable_gpe | ||
537 | * | ||
538 | * PARAMETERS: Context (gpe_event_info) - Info for this GPE | ||
539 | * Callback from acpi_os_execute | ||
540 | * | ||
541 | * RETURN: None | ||
542 | * | ||
543 | * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to | ||
544 | * complete. | ||
545 | * | ||
546 | ******************************************************************************/ | ||
547 | |||
548 | static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context) | ||
519 | { | 549 | { |
520 | struct acpi_gpe_event_info *gpe_event_info = context; | 550 | struct acpi_gpe_event_info *gpe_event_info = context; |
521 | acpi_status status; | 551 | acpi_status status; |
552 | |||
522 | if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == | 553 | if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == |
523 | ACPI_GPE_LEVEL_TRIGGERED) { | 554 | ACPI_GPE_LEVEL_TRIGGERED) { |
524 | /* | 555 | /* |
@@ -527,7 +558,7 @@ static void acpi_ev_asynch_enable_gpe(void *context) | |||
527 | */ | 558 | */ |
528 | status = acpi_hw_clear_gpe(gpe_event_info); | 559 | status = acpi_hw_clear_gpe(gpe_event_info); |
529 | if (ACPI_FAILURE(status)) { | 560 | if (ACPI_FAILURE(status)) { |
530 | return_VOID; | 561 | goto exit; |
531 | } | 562 | } |
532 | } | 563 | } |
533 | 564 | ||
@@ -537,7 +568,9 @@ static void acpi_ev_asynch_enable_gpe(void *context) | |||
537 | */ | 568 | */ |
538 | (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE); | 569 | (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE); |
539 | 570 | ||
540 | return_VOID; | 571 | exit: |
572 | ACPI_FREE(gpe_event_info); | ||
573 | return; | ||
541 | } | 574 | } |
542 | 575 | ||
543 | /******************************************************************************* | 576 | /******************************************************************************* |