Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / acpi / dispatcher / dsmethod.c
index 9f0456c..c475546 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2005, R. Byron Moore
+ * Copyright (C) 2000 - 2006, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * POSSIBILITY OF SUCH DAMAGES.
  */
 
-
 #include <acpi/acpi.h>
 #include <acpi/acparser.h>
 #include <acpi/amlcode.h>
 #include <acpi/acdispat.h>
 #include <acpi/acinterp.h>
 #include <acpi/acnamesp.h>
-
+#include <acpi/acdisasm.h>
 
 #define _COMPONENT          ACPI_DISPATCHER
-        ACPI_MODULE_NAME    ("dsmethod")
-
+ACPI_MODULE_NAME("dsmethod")
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ds_parse_method
+ * FUNCTION:    acpi_ds_method_error
  *
- * PARAMETERS:  obj_handle      - Method node
+ * PARAMETERS:  Status          - Execution status
+ *              walk_state      - Current state
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Call the parser and parse the AML that is associated with the
- *              method.
+ * DESCRIPTION: Called on method error. Invoke the global exception handler if
+ *              present, dump the method data if the disassembler is configured
  *
- * MUTEX:       Assumes parser is locked
+ *              Note: Allows the exception handler to change the status code
  *
  ******************************************************************************/
-
 acpi_status
-acpi_ds_parse_method (
-       acpi_handle                     obj_handle)
+acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
 {
-       acpi_status                     status;
-       union acpi_operand_object       *obj_desc;
-       union acpi_parse_object         *op;
-       struct acpi_namespace_node      *node;
-       acpi_owner_id                   owner_id;
-       struct acpi_walk_state          *walk_state;
-
-
-       ACPI_FUNCTION_TRACE_PTR ("ds_parse_method", obj_handle);
-
-
-       /* Parameter Validation */
+       ACPI_FUNCTION_ENTRY();
 
-       if (!obj_handle) {
-               return_ACPI_STATUS (AE_NULL_ENTRY);
-       }
-
-       ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Parsing [%4.4s] **** named_obj=%p\n",
-               acpi_ut_get_node_name (obj_handle), obj_handle));
-
-       /* Extract the method object from the method Node */
-
-       node = (struct acpi_namespace_node *) obj_handle;
-       obj_desc = acpi_ns_get_attached_object (node);
-       if (!obj_desc) {
-               return_ACPI_STATUS (AE_NULL_OBJECT);
-       }
-
-       /* Create a mutex for the method if there is a concurrency limit */
-
-       if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) &&
-               (!obj_desc->method.semaphore)) {
-               status = acpi_os_create_semaphore (obj_desc->method.concurrency,
-                                  obj_desc->method.concurrency,
-                                  &obj_desc->method.semaphore);
-               if (ACPI_FAILURE (status)) {
-                       return_ACPI_STATUS (status);
-               }
-       }
+       /* Ignore AE_OK and control exception codes */
 
-       /*
-        * Allocate a new parser op to be the root of the parsed
-        * method tree
-        */
-       op = acpi_ps_alloc_op (AML_METHOD_OP);
-       if (!op) {
-               return_ACPI_STATUS (AE_NO_MEMORY);
+       if (ACPI_SUCCESS(status) || (status & AE_CODE_CONTROL)) {
+               return (status);
        }
 
-       /* Init new op with the method name and pointer back to the Node */
+       /* Invoke the global exception handler */
 
-       acpi_ps_set_name (op, node->name.integer);
-       op->common.node = node;
-
-       /*
-        * Get a new owner_id for objects created by this method. Namespace
-        * objects (such as Operation Regions) can be created during the
-        * first pass parse.
-        */
-       owner_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD);
-       obj_desc->method.owning_id = owner_id;
+       if (acpi_gbl_exception_handler) {
+               /* Exit the interpreter, allow handler to execute methods */
 
-       /* Create and initialize a new walk state */
+               acpi_ex_exit_interpreter();
 
-       walk_state = acpi_ds_create_walk_state (owner_id, NULL, NULL, NULL);
-       if (!walk_state) {
-               return_ACPI_STATUS (AE_NO_MEMORY);
+               /*
+                * Handler can map the exception code to anything it wants, including
+                * AE_OK, in which case the executing method will not be aborted.
+                */
+               status = acpi_gbl_exception_handler(status,
+                                                   walk_state->method_node ?
+                                                   walk_state->method_node->
+                                                   name.integer : 0,
+                                                   walk_state->opcode,
+                                                   walk_state->aml_offset,
+                                                   NULL);
+               (void)acpi_ex_enter_interpreter();
        }
+#ifdef ACPI_DISASSEMBLER
+       if (ACPI_FAILURE(status)) {
+               /* Display method locals/args if disassembler is present */
 
-       status = acpi_ds_init_aml_walk (walk_state, op, node,
-                         obj_desc->method.aml_start,
-                         obj_desc->method.aml_length, NULL, 1);
-       if (ACPI_FAILURE (status)) {
-               acpi_ds_delete_walk_state (walk_state);
-               return_ACPI_STATUS (status);
+               acpi_dm_dump_method_info(status, walk_state, walk_state->op);
        }
+#endif
 
-       /*
-        * Parse the method, first pass
-        *
-        * The first pass load is where newly declared named objects are
-        * added into the namespace.  Actual evaluation of
-        * the named objects (what would be called a "second
-        * pass") happens during the actual execution of the
-        * method so that operands to the named objects can
-        * take on dynamic run-time values.
-        */
-       status = acpi_ps_parse_aml (walk_state);
-       if (ACPI_FAILURE (status)) {
-               return_ACPI_STATUS (status);
-       }
-
-       ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
-               "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n",
-               acpi_ut_get_node_name (obj_handle), obj_handle, op));
-
-       acpi_ps_delete_parse_tree (op);
-       return_ACPI_STATUS (status);
+       return (status);
 }
 
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ds_begin_method_execution
@@ -191,19 +126,24 @@ acpi_ds_parse_method (
  ******************************************************************************/
 
 acpi_status
-acpi_ds_begin_method_execution (
-       struct acpi_namespace_node      *method_node,
-       union acpi_operand_object       *obj_desc,
-       struct acpi_namespace_node      *calling_method_node)
+acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node,
+                              union acpi_operand_object * obj_desc,
+                              struct acpi_namespace_node * calling_method_node)
 {
-       acpi_status                     status = AE_OK;
+       acpi_status status = AE_OK;
 
+       ACPI_FUNCTION_TRACE_PTR("ds_begin_method_execution", method_node);
 
-       ACPI_FUNCTION_TRACE_PTR ("ds_begin_method_execution", method_node);
+       if (!method_node) {
+               return_ACPI_STATUS(AE_NULL_ENTRY);
+       }
 
+       /* Prevent wraparound of thread count */
 
-       if (!method_node) {
-               return_ACPI_STATUS (AE_NULL_ENTRY);
+       if (obj_desc->method.thread_count == ACPI_UINT8_MAX) {
+               ACPI_ERROR((AE_INFO,
+                           "Method reached maximum reentrancy limit (255)"));
+               return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
        }
 
        /*
@@ -220,8 +160,9 @@ acpi_ds_begin_method_execution (
                 * thread that is making recursive method calls.
                 */
                if (method_node == calling_method_node) {
-                       if (obj_desc->method.thread_count >= obj_desc->method.concurrency) {
-                               return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
+                       if (obj_desc->method.thread_count >=
+                           obj_desc->method.concurrency) {
+                               return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
                        }
                }
 
@@ -229,8 +170,21 @@ acpi_ds_begin_method_execution (
                 * Get a unit from the method semaphore. This releases the
                 * interpreter if we block
                 */
-               status = acpi_ex_system_wait_semaphore (obj_desc->method.semaphore,
-                                ACPI_WAIT_FOREVER);
+               status =
+                   acpi_ex_system_wait_semaphore(obj_desc->method.semaphore,
+                                                 ACPI_WAIT_FOREVER);
+       }
+
+       /*
+        * Allocate an Owner ID for this method, only if this is the first thread
+        * to begin concurrent execution. We only need one owner_id, even if the
+        * method is invoked recursively.
+        */
+       if (!obj_desc->method.owner_id) {
+               status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
+               if (ACPI_FAILURE(status)) {
+                       return_ACPI_STATUS(status);
+               }
        }
 
        /*
@@ -238,10 +192,9 @@ acpi_ds_begin_method_execution (
         * reentered one more time (even if it is the same thread)
         */
        obj_desc->method.thread_count++;
-       return_ACPI_STATUS (status);
+       return_ACPI_STATUS(status);
 }
 
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ds_call_control_method
@@ -257,101 +210,99 @@ acpi_ds_begin_method_execution (
  ******************************************************************************/
 
 acpi_status
-acpi_ds_call_control_method (
-       struct acpi_thread_state        *thread,
-       struct acpi_walk_state          *this_walk_state,
-       union acpi_parse_object         *op)
+acpi_ds_call_control_method(struct acpi_thread_state *thread,
+                           struct acpi_walk_state *this_walk_state,
+                           union acpi_parse_object *op)
 {
-       acpi_status                     status;
-       struct acpi_namespace_node      *method_node;
-       struct acpi_walk_state          *next_walk_state;
-       union acpi_operand_object       *obj_desc;
-       struct acpi_parameter_info      info;
-       u32                             i;
+       acpi_status status;
+       struct acpi_namespace_node *method_node;
+       struct acpi_walk_state *next_walk_state = NULL;
+       union acpi_operand_object *obj_desc;
+       struct acpi_parameter_info info;
+       u32 i;
 
+       ACPI_FUNCTION_TRACE_PTR("ds_call_control_method", this_walk_state);
 
-       ACPI_FUNCTION_TRACE_PTR ("ds_call_control_method", this_walk_state);
-
-       ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Execute method %p, currentstate=%p\n",
-               this_walk_state->prev_op, this_walk_state));
+       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                         "Execute method %p, currentstate=%p\n",
+                         this_walk_state->prev_op, this_walk_state));
 
        /*
         * Get the namespace entry for the control method we are about to call
         */
        method_node = this_walk_state->method_call_node;
        if (!method_node) {
-               return_ACPI_STATUS (AE_NULL_ENTRY);
+               return_ACPI_STATUS(AE_NULL_ENTRY);
        }
 
-       obj_desc = acpi_ns_get_attached_object (method_node);
+       obj_desc = acpi_ns_get_attached_object(method_node);
        if (!obj_desc) {
-               return_ACPI_STATUS (AE_NULL_OBJECT);
+               return_ACPI_STATUS(AE_NULL_OBJECT);
        }
 
-       obj_desc->method.owning_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD);
-
        /* Init for new method, wait on concurrency semaphore */
 
-       status = acpi_ds_begin_method_execution (method_node, obj_desc,
-                         this_walk_state->method_node);
-       if (ACPI_FAILURE (status)) {
-               return_ACPI_STATUS (status);
+       status = acpi_ds_begin_method_execution(method_node, obj_desc,
+                                               this_walk_state->method_node);
+       if (ACPI_FAILURE(status)) {
+               goto cleanup;
        }
 
        if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
                /* 1) Parse: Create a new walk state for the preempting walk */
 
-               next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
-                                 op, obj_desc, NULL);
+               next_walk_state =
+                   acpi_ds_create_walk_state(obj_desc->method.owner_id, op,
+                                             obj_desc, NULL);
                if (!next_walk_state) {
-                       return_ACPI_STATUS (AE_NO_MEMORY);
+                       return_ACPI_STATUS(AE_NO_MEMORY);
                }
 
                /* Create and init a Root Node */
 
-               op = acpi_ps_create_scope_op ();
+               op = acpi_ps_create_scope_op();
                if (!op) {
                        status = AE_NO_MEMORY;
                        goto cleanup;
                }
 
-               status = acpi_ds_init_aml_walk (next_walk_state, op, method_node,
-                                 obj_desc->method.aml_start, obj_desc->method.aml_length,
-                                 NULL, 1);
-               if (ACPI_FAILURE (status)) {
-                       acpi_ds_delete_walk_state (next_walk_state);
+               status = acpi_ds_init_aml_walk(next_walk_state, op, method_node,
+                                              obj_desc->method.aml_start,
+                                              obj_desc->method.aml_length,
+                                              NULL, 1);
+               if (ACPI_FAILURE(status)) {
+                       acpi_ds_delete_walk_state(next_walk_state);
                        goto cleanup;
                }
 
                /* Begin AML parse */
 
-               status = acpi_ps_parse_aml (next_walk_state);
-               acpi_ps_delete_parse_tree (op);
+               status = acpi_ps_parse_aml(next_walk_state);
+               acpi_ps_delete_parse_tree(op);
        }
 
        /* 2) Execute: Create a new state for the preempting walk */
 
-       next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
-                         NULL, obj_desc, thread);
+       next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id,
+                                                   NULL, obj_desc, thread);
        if (!next_walk_state) {
                status = AE_NO_MEMORY;
                goto cleanup;
        }
        /*
         * The resolved arguments were put on the previous walk state's operand
-        * stack.  Operands on the previous walk state stack always
-        * start at index 0.
-        * Null terminate the list of arguments
+        * stack. Operands on the previous walk state stack always
+        * start at index 0. Also, null terminate the list of arguments
         */
-       this_walk_state->operands [this_walk_state->num_operands] = NULL;
+       this_walk_state->operands[this_walk_state->num_operands] = NULL;
 
        info.parameters = &this_walk_state->operands[0];
        info.parameter_type = ACPI_PARAM_ARGS;
 
-       status = acpi_ds_init_aml_walk (next_walk_state, NULL, method_node,
-                         obj_desc->method.aml_start, obj_desc->method.aml_length,
-                         &info, 3);
-       if (ACPI_FAILURE (status)) {
+       status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
+                                      obj_desc->method.aml_start,
+                                      obj_desc->method.aml_length, &info, 3);
+       if (ACPI_FAILURE(status)) {
                goto cleanup;
        }
 
@@ -360,38 +311,37 @@ acpi_ds_call_control_method (
         * (they were copied to new objects)
         */
        for (i = 0; i < obj_desc->method.param_count; i++) {
-               acpi_ut_remove_reference (this_walk_state->operands [i]);
-               this_walk_state->operands [i] = NULL;
+               acpi_ut_remove_reference(this_walk_state->operands[i]);
+               this_walk_state->operands[i] = NULL;
        }
 
        /* Clear the operand stack */
 
        this_walk_state->num_operands = 0;
 
-       ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
-               "Starting nested execution, newstate=%p\n", next_walk_state));
+       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                         "Starting nested execution, newstate=%p\n",
+                         next_walk_state));
 
        if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
-               status = obj_desc->method.implementation (next_walk_state);
-               return_ACPI_STATUS (status);
+               status = obj_desc->method.implementation(next_walk_state);
        }
 
-       return_ACPI_STATUS (AE_OK);
+       return_ACPI_STATUS(status);
 
+      cleanup:
+       /* Decrement the thread count on the method parse tree */
 
-       /* On error, we must delete the new walk state */
-
-cleanup:
        if (next_walk_state && (next_walk_state->method_desc)) {
-               /* Decrement the thread count on the method parse tree */
-
-          next_walk_state->method_desc->method.thread_count--;
+               next_walk_state->method_desc->method.thread_count--;
        }
-       (void) acpi_ds_terminate_control_method (next_walk_state);
-       acpi_ds_delete_walk_state (next_walk_state);
-       return_ACPI_STATUS (status);
-}
 
+       /* On error, we must delete the new walk state */
+
+       acpi_ds_terminate_control_method(next_walk_state);
+       acpi_ds_delete_walk_state(next_walk_state);
+       return_ACPI_STATUS(status);
+}
 
 /*******************************************************************************
  *
@@ -408,25 +358,22 @@ cleanup:
  ******************************************************************************/
 
 acpi_status
-acpi_ds_restart_control_method (
-       struct acpi_walk_state          *walk_state,
-       union acpi_operand_object       *return_desc)
+acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
+                              union acpi_operand_object *return_desc)
 {
-       acpi_status                     status;
-
+       acpi_status status;
 
-       ACPI_FUNCTION_TRACE_PTR ("ds_restart_control_method", walk_state);
+       ACPI_FUNCTION_TRACE_PTR("ds_restart_control_method", walk_state);
 
+       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                         "****Restart [%4.4s] Op %p return_value_from_callee %p\n",
+                         (char *)&walk_state->method_node->name,
+                         walk_state->method_call_op, return_desc));
 
-       ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
-               "****Restart [%4.4s] Op %p return_value_from_callee %p\n",
-               (char *) &walk_state->method_node->name, walk_state->method_call_op,
-               return_desc));
-
-       ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
-               "    return_from_this_method_used?=%X res_stack %p Walk %p\n",
-               walk_state->return_used,
-               walk_state->results, walk_state));
+       ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                         "    return_from_this_method_used?=%X res_stack %p Walk %p\n",
+                         walk_state->return_used,
+                         walk_state->results, walk_state));
 
        /* Did the called method return a value? */
 
@@ -436,10 +383,10 @@ acpi_ds_restart_control_method (
                if (walk_state->return_used) {
                        /* Save the return value from the previous method */
 
-                       status = acpi_ds_result_push (return_desc, walk_state);
-                       if (ACPI_FAILURE (status)) {
-                               acpi_ut_remove_reference (return_desc);
-                               return_ACPI_STATUS (status);
+                       status = acpi_ds_result_push(return_desc, walk_state);
+                       if (ACPI_FAILURE(status)) {
+                               acpi_ut_remove_reference(return_desc);
+                               return_ACPI_STATUS(status);
                        }
 
                        /*
@@ -457,26 +404,26 @@ acpi_ds_restart_control_method (
                 * NOTE: this is optional because the ASL language does not actually
                 * support this behavior.
                 */
-               else if (!acpi_ds_do_implicit_return (return_desc, walk_state, FALSE)) {
+               else if (!acpi_ds_do_implicit_return
+                        (return_desc, walk_state, FALSE)) {
                        /*
                         * Delete the return value if it will not be used by the
                         * calling method
                         */
-                       acpi_ut_remove_reference (return_desc);
+                       acpi_ut_remove_reference(return_desc);
                }
        }
 
-       return_ACPI_STATUS (AE_OK);
+       return_ACPI_STATUS(AE_OK);
 }
 
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ds_terminate_control_method
  *
  * PARAMETERS:  walk_state          - State of the method
  *
- * RETURN:      Status
+ * RETURN:      None
  *
  * DESCRIPTION: Terminate a control method.  Delete everything that the method
  *              created, delete all locals and arguments, and delete the parse
@@ -484,66 +431,101 @@ acpi_ds_restart_control_method (
  *
  ******************************************************************************/
 
-acpi_status
-acpi_ds_terminate_control_method (
-       struct acpi_walk_state          *walk_state)
+void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state)
 {
-       union acpi_operand_object       *obj_desc;
-       struct acpi_namespace_node      *method_node;
-       acpi_status                     status;
-
-
-       ACPI_FUNCTION_TRACE_PTR ("ds_terminate_control_method", walk_state);
+       union acpi_operand_object *obj_desc;
+       struct acpi_namespace_node *method_node;
+       acpi_status status;
 
+       ACPI_FUNCTION_TRACE_PTR("ds_terminate_control_method", walk_state);
 
        if (!walk_state) {
-               return (AE_BAD_PARAMETER);
+               return_VOID;
        }
 
        /* The current method object was saved in the walk state */
 
        obj_desc = walk_state->method_desc;
        if (!obj_desc) {
-               return_ACPI_STATUS (AE_OK);
+               return_VOID;
        }
 
        /* Delete all arguments and locals */
 
-       acpi_ds_method_data_delete_all (walk_state);
+       acpi_ds_method_data_delete_all(walk_state);
 
        /*
         * Lock the parser while we terminate this method.
         * If this is the last thread executing the method,
         * we have additional cleanup to perform
         */
-       status = acpi_ut_acquire_mutex (ACPI_MTX_PARSER);
-       if (ACPI_FAILURE (status)) {
-               return_ACPI_STATUS (status);
+       status = acpi_ut_acquire_mutex(ACPI_MTX_PARSER);
+       if (ACPI_FAILURE(status)) {
+               return_VOID;
        }
 
        /* Signal completion of the execution of this method if necessary */
 
        if (walk_state->method_desc->method.semaphore) {
-               status = acpi_os_signal_semaphore (
-                                 walk_state->method_desc->method.semaphore, 1);
-               if (ACPI_FAILURE (status)) {
-                       ACPI_REPORT_ERROR (("Could not signal method semaphore\n"));
-                       status = AE_OK;
+               status =
+                   acpi_os_signal_semaphore(walk_state->method_desc->method.
+                                            semaphore, 1);
+               if (ACPI_FAILURE(status)) {
+                       ACPI_ERROR((AE_INFO,
+                                   "Could not signal method semaphore"));
 
                        /* Ignore error and continue cleanup */
                }
        }
 
-       if (walk_state->method_desc->method.thread_count) {
-               ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
-                       "*** Not deleting method namespace, there are still %d threads\n",
-                       walk_state->method_desc->method.thread_count));
+       /*
+        * There are no more threads executing this method.  Perform
+        * additional cleanup.
+        *
+        * The method Node is stored in the walk state
+        */
+       method_node = walk_state->method_node;
+
+       /* Lock namespace for possible update */
+
+       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+       if (ACPI_FAILURE(status)) {
+               goto exit;
+       }
+
+       /*
+        * Delete any namespace entries created immediately underneath
+        * the method
+        */
+       if (method_node->child) {
+               acpi_ns_delete_namespace_subtree(method_node);
        }
 
-       if (!walk_state->method_desc->method.thread_count) {
+       /*
+        * Delete any namespace entries created anywhere else within
+        * the namespace by the execution of this method
+        */
+       acpi_ns_delete_namespace_by_owner(walk_state->method_desc->method.
+                                         owner_id);
+       status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+
+       /* Are there any other threads currently executing this method? */
+
+       if (walk_state->method_desc->method.thread_count) {
+               /*
+                * Additional threads. Do not release the owner_id in this case,
+                * we immediately reuse it for the next thread executing this method
+                */
+               ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+                                 "*** Completed execution of one thread, %d threads remaining\n",
+                                 walk_state->method_desc->method.
+                                 thread_count));
+       } else {
+               /* This is the only executing thread for this method */
+
                /*
                 * Support to dynamically change a method from not_serialized to
-                * Serialized if it appears that the method is written foolishly and
+                * Serialized if it appears that the method is incorrectly written and
                 * does not support multiple thread execution.  The best example of this
                 * is if such a method creates namespace objects and blocks.  A second
                 * thread will fail with an AE_ALREADY_EXISTS exception
@@ -552,46 +534,157 @@ acpi_ds_terminate_control_method (
                 * before creating the synchronization semaphore.
                 */
                if ((walk_state->method_desc->method.concurrency == 1) &&
-                       (!walk_state->method_desc->method.semaphore)) {
-                       status = acpi_os_create_semaphore (1,
-                                        1,
-                                        &walk_state->method_desc->method.semaphore);
+                   (!walk_state->method_desc->method.semaphore)) {
+                       status = acpi_os_create_semaphore(1, 1,
+                                                         &walk_state->
+                                                         method_desc->method.
+                                                         semaphore);
                }
 
-               /*
-                * There are no more threads executing this method.  Perform
-                * additional cleanup.
-                *
-                * The method Node is stored in the walk state
-                */
-               method_node = walk_state->method_node;
+               /* No more threads, we can free the owner_id */
 
-               /*
-                * Delete any namespace entries created immediately underneath
-                * the method
-                */
-               status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
-               if (ACPI_FAILURE (status)) {
-                       return_ACPI_STATUS (status);
-               }
+               acpi_ut_release_owner_id(&walk_state->method_desc->method.
+                                        owner_id);
+       }
 
-               if (method_node->child) {
-                       acpi_ns_delete_namespace_subtree (method_node);
-               }
+      exit:
+       (void)acpi_ut_release_mutex(ACPI_MTX_PARSER);
+       return_VOID;
+}
 
-               /*
-                * Delete any namespace entries created anywhere else within
-                * the namespace
-                */
-               acpi_ns_delete_namespace_by_owner (walk_state->method_desc->method.owning_id);
-               status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
-               if (ACPI_FAILURE (status)) {
-                       return_ACPI_STATUS (status);
+#ifdef ACPI_INIT_PARSE_METHODS
+       /*
+        * Note 11/2005: Removed this code to parse all methods during table
+        * load because it causes problems if there are any errors during the
+        * parse. Also, it seems like overkill and we probably don't want to
+        * abort a table load because of an issue with a single method.
+        */
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ds_parse_method
+ *
+ * PARAMETERS:  Node        - Method node
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Parse the AML that is associated with the method.
+ *
+ * MUTEX:       Assumes parser is locked
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node)
+{
+       acpi_status status;
+       union acpi_operand_object *obj_desc;
+       union acpi_parse_object *op;
+       struct acpi_walk_state *walk_state;
+
+       ACPI_FUNCTION_TRACE_PTR("ds_parse_method", node);
+
+       /* Parameter Validation */
+
+       if (!node) {
+               return_ACPI_STATUS(AE_NULL_ENTRY);
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+                         "**** Parsing [%4.4s] **** named_obj=%p\n",
+                         acpi_ut_get_node_name(node), node));
+
+       /* Extract the method object from the method Node */
+
+       obj_desc = acpi_ns_get_attached_object(node);
+       if (!obj_desc) {
+               return_ACPI_STATUS(AE_NULL_OBJECT);
+       }
+
+       /* Create a mutex for the method if there is a concurrency limit */
+
+       if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) &&
+           (!obj_desc->method.semaphore)) {
+               status = acpi_os_create_semaphore(obj_desc->method.concurrency,
+                                                 obj_desc->method.concurrency,
+                                                 &obj_desc->method.semaphore);
+               if (ACPI_FAILURE(status)) {
+                       return_ACPI_STATUS(status);
                }
        }
 
-       status = acpi_ut_release_mutex (ACPI_MTX_PARSER);
-       return_ACPI_STATUS (status);
-}
+       /*
+        * Allocate a new parser op to be the root of the parsed
+        * method tree
+        */
+       op = acpi_ps_alloc_op(AML_METHOD_OP);
+       if (!op) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
+       }
+
+       /* Init new op with the method name and pointer back to the Node */
 
+       acpi_ps_set_name(op, node->name.integer);
+       op->common.node = node;
 
+       /*
+        * Get a new owner_id for objects created by this method. Namespace
+        * objects (such as Operation Regions) can be created during the
+        * first pass parse.
+        */
+       status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
+       if (ACPI_FAILURE(status)) {
+               goto cleanup;
+       }
+
+       /* Create and initialize a new walk state */
+
+       walk_state =
+           acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, NULL,
+                                     NULL);
+       if (!walk_state) {
+               status = AE_NO_MEMORY;
+               goto cleanup2;
+       }
+
+       status = acpi_ds_init_aml_walk(walk_state, op, node,
+                                      obj_desc->method.aml_start,
+                                      obj_desc->method.aml_length, NULL, 1);
+       if (ACPI_FAILURE(status)) {
+               acpi_ds_delete_walk_state(walk_state);
+               goto cleanup2;
+       }
+
+       /*
+        * Parse the method, first pass
+        *
+        * The first pass load is where newly declared named objects are added into
+        * the namespace.  Actual evaluation of the named objects (what would be
+        * called a "second pass") happens during the actual execution of the
+        * method so that operands to the named objects can take on dynamic
+        * run-time values.
+        */
+       status = acpi_ps_parse_aml(walk_state);
+       if (ACPI_FAILURE(status)) {
+               goto cleanup2;
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+                         "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n",
+                         acpi_ut_get_node_name(node), node, op));
+
+       /*
+        * Delete the parse tree. We simply re-parse the method for every
+        * execution since there isn't much overhead (compared to keeping lots
+        * of parse trees around)
+        */
+       acpi_ns_delete_namespace_subtree(node);
+       acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);
+
+      cleanup2:
+       acpi_ut_release_owner_id(&obj_desc->method.owner_id);
+
+      cleanup:
+       acpi_ps_delete_parse_tree(op);
+       return_ACPI_STATUS(status);
+}
+#endif