diff options
Diffstat (limited to 'drivers/acpi/parser/psparse.c')
-rw-r--r-- | drivers/acpi/parser/psparse.c | 55 |
1 files changed, 35 insertions, 20 deletions
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c index 76d4d640d83c..a9f3229f4106 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/parser/psparse.c | |||
@@ -5,7 +5,7 @@ | |||
5 | *****************************************************************************/ | 5 | *****************************************************************************/ |
6 | 6 | ||
7 | /* | 7 | /* |
8 | * Copyright (C) 2000 - 2005, R. Byron Moore | 8 | * Copyright (C) 2000 - 2006, R. Byron Moore |
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 |
@@ -333,7 +333,6 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state, | |||
333 | 333 | ||
334 | switch (callback_status) { | 334 | switch (callback_status) { |
335 | case AE_CTRL_TERMINATE: | 335 | case AE_CTRL_TERMINATE: |
336 | |||
337 | /* | 336 | /* |
338 | * A control method was terminated via a RETURN statement. | 337 | * A control method was terminated via a RETURN statement. |
339 | * The walk of this method is complete. | 338 | * The walk of this method is complete. |
@@ -346,13 +345,19 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state, | |||
346 | 345 | ||
347 | parser_state->aml = walk_state->aml_last_while; | 346 | parser_state->aml = walk_state->aml_last_while; |
348 | walk_state->control_state->common.value = FALSE; | 347 | walk_state->control_state->common.value = FALSE; |
349 | status = AE_CTRL_BREAK; | 348 | status = acpi_ds_result_stack_pop(walk_state); |
349 | if (ACPI_SUCCESS(status)) { | ||
350 | status = AE_CTRL_BREAK; | ||
351 | } | ||
350 | break; | 352 | break; |
351 | 353 | ||
352 | case AE_CTRL_CONTINUE: | 354 | case AE_CTRL_CONTINUE: |
353 | 355 | ||
354 | parser_state->aml = walk_state->aml_last_while; | 356 | parser_state->aml = walk_state->aml_last_while; |
355 | status = AE_CTRL_CONTINUE; | 357 | status = acpi_ds_result_stack_pop(walk_state); |
358 | if (ACPI_SUCCESS(status)) { | ||
359 | status = AE_CTRL_CONTINUE; | ||
360 | } | ||
356 | break; | 361 | break; |
357 | 362 | ||
358 | case AE_CTRL_PENDING: | 363 | case AE_CTRL_PENDING: |
@@ -369,16 +374,18 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state, | |||
369 | #endif | 374 | #endif |
370 | 375 | ||
371 | case AE_CTRL_TRUE: | 376 | case AE_CTRL_TRUE: |
372 | |||
373 | /* | 377 | /* |
374 | * Predicate of an IF was true, and we are at the matching ELSE. | 378 | * Predicate of an IF was true, and we are at the matching ELSE. |
375 | * Just close out this package | 379 | * Just close out this package |
376 | */ | 380 | */ |
377 | parser_state->aml = acpi_ps_get_next_package_end(parser_state); | 381 | parser_state->aml = acpi_ps_get_next_package_end(parser_state); |
382 | status = acpi_ds_result_stack_pop(walk_state); | ||
383 | if (ACPI_SUCCESS(status)) { | ||
384 | status = AE_CTRL_PENDING; | ||
385 | } | ||
378 | break; | 386 | break; |
379 | 387 | ||
380 | case AE_CTRL_FALSE: | 388 | case AE_CTRL_FALSE: |
381 | |||
382 | /* | 389 | /* |
383 | * Either an IF/WHILE Predicate was false or we encountered a BREAK | 390 | * Either an IF/WHILE Predicate was false or we encountered a BREAK |
384 | * opcode. In both cases, we do not execute the rest of the | 391 | * opcode. In both cases, we do not execute the rest of the |
@@ -503,22 +510,23 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) | |||
503 | } else if (status == AE_CTRL_TERMINATE) { | 510 | } else if (status == AE_CTRL_TERMINATE) { |
504 | status = AE_OK; | 511 | status = AE_OK; |
505 | } else if ((status != AE_OK) && (walk_state->method_desc)) { | 512 | } else if ((status != AE_OK) && (walk_state->method_desc)) { |
506 | ACPI_REPORT_METHOD_ERROR("Method execution failed", | 513 | /* Either the method parse or actual execution failed */ |
507 | walk_state->method_node, NULL, | ||
508 | status); | ||
509 | |||
510 | /* Ensure proper cleanup */ | ||
511 | 514 | ||
512 | walk_state->parse_flags |= ACPI_PARSE_EXECUTE; | 515 | ACPI_ERROR_METHOD("Method parse/execution failed", |
516 | walk_state->method_node, NULL, | ||
517 | status); | ||
513 | 518 | ||
514 | /* Check for possible multi-thread reentrancy problem */ | 519 | /* Check for possible multi-thread reentrancy problem */ |
515 | 520 | ||
516 | if ((status == AE_ALREADY_EXISTS) && | 521 | if ((status == AE_ALREADY_EXISTS) && |
517 | (!walk_state->method_desc->method.semaphore)) { | 522 | (!walk_state->method_desc->method.semaphore)) { |
518 | /* | 523 | /* |
519 | * This method is marked not_serialized, but it tried to create | 524 | * Method tried to create an object twice. The probable cause is |
525 | * that the method cannot handle reentrancy. | ||
526 | * | ||
527 | * The method is marked not_serialized, but it tried to create | ||
520 | * a named object, causing the second thread entrance to fail. | 528 | * a named object, causing the second thread entrance to fail. |
521 | * We will workaround this by marking the method permanently | 529 | * Workaround this problem by marking the method permanently |
522 | * as Serialized. | 530 | * as Serialized. |
523 | */ | 531 | */ |
524 | walk_state->method_desc->method.method_flags |= | 532 | walk_state->method_desc->method.method_flags |= |
@@ -536,15 +544,23 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) | |||
536 | acpi_ds_scope_stack_clear(walk_state); | 544 | acpi_ds_scope_stack_clear(walk_state); |
537 | 545 | ||
538 | /* | 546 | /* |
539 | * If we just returned from the execution of a control method, | 547 | * If we just returned from the execution of a control method or if we |
540 | * there's lots of cleanup to do | 548 | * encountered an error during the method parse phase, there's lots of |
549 | * cleanup to do | ||
541 | */ | 550 | */ |
542 | if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == | 551 | if (((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == |
543 | ACPI_PARSE_EXECUTE) { | 552 | ACPI_PARSE_EXECUTE) || (ACPI_FAILURE(status))) { |
544 | if (walk_state->method_desc) { | 553 | if (walk_state->method_desc) { |
545 | /* Decrement the thread count on the method parse tree */ | 554 | /* Decrement the thread count on the method parse tree */ |
546 | 555 | ||
547 | walk_state->method_desc->method.thread_count--; | 556 | if (walk_state->method_desc->method. |
557 | thread_count) { | ||
558 | walk_state->method_desc->method. | ||
559 | thread_count--; | ||
560 | } else { | ||
561 | ACPI_ERROR((AE_INFO, | ||
562 | "Invalid zero thread count in method")); | ||
563 | } | ||
548 | } | 564 | } |
549 | 565 | ||
550 | acpi_ds_terminate_control_method(walk_state); | 566 | acpi_ds_terminate_control_method(walk_state); |
@@ -553,7 +569,6 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) | |||
553 | /* Delete this walk state and all linked control states */ | 569 | /* Delete this walk state and all linked control states */ |
554 | 570 | ||
555 | acpi_ps_cleanup_scope(&walk_state->parser_state); | 571 | acpi_ps_cleanup_scope(&walk_state->parser_state); |
556 | |||
557 | previous_walk_state = walk_state; | 572 | previous_walk_state = walk_state; |
558 | 573 | ||
559 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, | 574 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |