xref: /openbmc/linux/drivers/acpi/acpica/dsmethod.c (revision 612c2932)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
595b482a8SLen Brown  *
6*612c2932SBob Moore  * Copyright (C) 2000 - 2023, Intel Corp.
795b482a8SLen Brown  *
895857638SErik Schmauss  *****************************************************************************/
995b482a8SLen Brown 
1095b482a8SLen Brown #include <acpi/acpi.h>
11e2f7a777SLen Brown #include "accommon.h"
12e2f7a777SLen Brown #include "acdispat.h"
13e2f7a777SLen Brown #include "acinterp.h"
14e2f7a777SLen Brown #include "acnamesp.h"
1522b5afceSBob Moore #include "acparser.h"
1622b5afceSBob Moore #include "amlcode.h"
17fdd8d831SLv Zheng #include "acdebug.h"
1895b482a8SLen Brown 
1995b482a8SLen Brown #define _COMPONENT          ACPI_DISPATCHER
2095b482a8SLen Brown ACPI_MODULE_NAME("dsmethod")
2195b482a8SLen Brown 
2295b482a8SLen Brown /* Local prototypes */
2395b482a8SLen Brown static acpi_status
2422b5afceSBob Moore acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state,
2522b5afceSBob Moore 			     union acpi_parse_object **out_op);
2622b5afceSBob Moore 
2722b5afceSBob Moore static acpi_status
2895b482a8SLen Brown acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);
2995b482a8SLen Brown 
3095b482a8SLen Brown /*******************************************************************************
3195b482a8SLen Brown  *
3222b5afceSBob Moore  * FUNCTION:    acpi_ds_auto_serialize_method
3322b5afceSBob Moore  *
3422b5afceSBob Moore  * PARAMETERS:  node                        - Namespace Node of the method
3522b5afceSBob Moore  *              obj_desc                    - Method object attached to node
3622b5afceSBob Moore  *
3722b5afceSBob Moore  * RETURN:      Status
3822b5afceSBob Moore  *
3922b5afceSBob Moore  * DESCRIPTION: Parse a control method AML to scan for control methods that
4022b5afceSBob Moore  *              need serialization due to the creation of named objects.
4122b5afceSBob Moore  *
4222b5afceSBob Moore  * NOTE: It is a bit of overkill to mark all such methods serialized, since
4322b5afceSBob Moore  * there is only a problem if the method actually blocks during execution.
4422b5afceSBob Moore  * A blocking operation is, for example, a Sleep() operation, or any access
4522b5afceSBob Moore  * to an operation region. However, it is probably not possible to easily
4622b5afceSBob Moore  * detect whether a method will block or not, so we simply mark all suspicious
4722b5afceSBob Moore  * methods as serialized.
4822b5afceSBob Moore  *
4922b5afceSBob Moore  * NOTE2: This code is essentially a generic routine for parsing a single
5022b5afceSBob Moore  * control method.
5122b5afceSBob Moore  *
5222b5afceSBob Moore  ******************************************************************************/
5322b5afceSBob Moore 
5422b5afceSBob Moore acpi_status
acpi_ds_auto_serialize_method(struct acpi_namespace_node * node,union acpi_operand_object * obj_desc)5522b5afceSBob Moore acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
5622b5afceSBob Moore 			      union acpi_operand_object *obj_desc)
5722b5afceSBob Moore {
5822b5afceSBob Moore 	acpi_status status;
5922b5afceSBob Moore 	union acpi_parse_object *op = NULL;
6022b5afceSBob Moore 	struct acpi_walk_state *walk_state;
6122b5afceSBob Moore 
6222b5afceSBob Moore 	ACPI_FUNCTION_TRACE_PTR(ds_auto_serialize_method, node);
6322b5afceSBob Moore 
6422b5afceSBob Moore 	ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
6522b5afceSBob Moore 			  "Method auto-serialization parse [%4.4s] %p\n",
6622b5afceSBob Moore 			  acpi_ut_get_node_name(node), node));
6722b5afceSBob Moore 
6822b5afceSBob Moore 	/* Create/Init a root op for the method parse tree */
6922b5afceSBob Moore 
7062eb935bSLv Zheng 	op = acpi_ps_alloc_op(AML_METHOD_OP, obj_desc->method.aml_start);
7122b5afceSBob Moore 	if (!op) {
728633db6bSLv Zheng 		return_ACPI_STATUS(AE_NO_MEMORY);
7322b5afceSBob Moore 	}
7422b5afceSBob Moore 
7522b5afceSBob Moore 	acpi_ps_set_name(op, node->name.integer);
7622b5afceSBob Moore 	op->common.node = node;
7722b5afceSBob Moore 
7822b5afceSBob Moore 	/* Create and initialize a new walk state */
7922b5afceSBob Moore 
8022b5afceSBob Moore 	walk_state =
8122b5afceSBob Moore 	    acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL);
8222b5afceSBob Moore 	if (!walk_state) {
83c8dec745SLv Zheng 		acpi_ps_free_op(op);
848633db6bSLv Zheng 		return_ACPI_STATUS(AE_NO_MEMORY);
8522b5afceSBob Moore 	}
8622b5afceSBob Moore 
871fad8738SBob Moore 	status = acpi_ds_init_aml_walk(walk_state, op, node,
8822b5afceSBob Moore 				       obj_desc->method.aml_start,
8922b5afceSBob Moore 				       obj_desc->method.aml_length, NULL, 0);
9022b5afceSBob Moore 	if (ACPI_FAILURE(status)) {
9122b5afceSBob Moore 		acpi_ds_delete_walk_state(walk_state);
92c8dec745SLv Zheng 		acpi_ps_free_op(op);
938633db6bSLv Zheng 		return_ACPI_STATUS(status);
9422b5afceSBob Moore 	}
9522b5afceSBob Moore 
9622b5afceSBob Moore 	walk_state->descending_callback = acpi_ds_detect_named_opcodes;
9722b5afceSBob Moore 
9822b5afceSBob Moore 	/* Parse the method, scan for creation of named objects */
9922b5afceSBob Moore 
10022b5afceSBob Moore 	status = acpi_ps_parse_aml(walk_state);
10122b5afceSBob Moore 
10222b5afceSBob Moore 	acpi_ps_delete_parse_tree(op);
10322b5afceSBob Moore 	return_ACPI_STATUS(status);
10422b5afceSBob Moore }
10522b5afceSBob Moore 
10622b5afceSBob Moore /*******************************************************************************
10722b5afceSBob Moore  *
10822b5afceSBob Moore  * FUNCTION:    acpi_ds_detect_named_opcodes
10922b5afceSBob Moore  *
11022b5afceSBob Moore  * PARAMETERS:  walk_state      - Current state of the parse tree walk
11122b5afceSBob Moore  *              out_op          - Unused, required for parser interface
11222b5afceSBob Moore  *
11322b5afceSBob Moore  * RETURN:      Status
11422b5afceSBob Moore  *
11522b5afceSBob Moore  * DESCRIPTION: Descending callback used during the loading of ACPI tables.
11622b5afceSBob Moore  *              Currently used to detect methods that must be marked serialized
11722b5afceSBob Moore  *              in order to avoid problems with the creation of named objects.
11822b5afceSBob Moore  *
11922b5afceSBob Moore  ******************************************************************************/
12022b5afceSBob Moore 
12122b5afceSBob Moore static acpi_status
acpi_ds_detect_named_opcodes(struct acpi_walk_state * walk_state,union acpi_parse_object ** out_op)12222b5afceSBob Moore acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state,
12322b5afceSBob Moore 			     union acpi_parse_object **out_op)
12422b5afceSBob Moore {
12522b5afceSBob Moore 
12622b5afceSBob Moore 	ACPI_FUNCTION_NAME(acpi_ds_detect_named_opcodes);
12722b5afceSBob Moore 
12821bd7e61SLv Zheng 	/* We are only interested in opcodes that create a new name */
12922b5afceSBob Moore 
13021bd7e61SLv Zheng 	if (!
13121bd7e61SLv Zheng 	    (walk_state->op_info->
13221bd7e61SLv Zheng 	     flags & (AML_NAMED | AML_CREATE | AML_FIELD))) {
13322b5afceSBob Moore 		return (AE_OK);
13422b5afceSBob Moore 	}
13522b5afceSBob Moore 
13622b5afceSBob Moore 	/*
13722b5afceSBob Moore 	 * At this point, we know we have a Named object opcode.
13822b5afceSBob Moore 	 * Mark the method as serialized. Later code will create a mutex for
13922b5afceSBob Moore 	 * this method to enforce serialization.
140d1825579SBob Moore 	 *
141d1825579SBob Moore 	 * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the
142d1825579SBob Moore 	 * Sync Level mechanism for this method, even though it is now serialized.
143d1825579SBob Moore 	 * Otherwise, there can be conflicts with existing ASL code that actually
144d1825579SBob Moore 	 * uses sync levels.
14522b5afceSBob Moore 	 */
146d1825579SBob Moore 	walk_state->method_desc->method.sync_level = 0;
147d1825579SBob Moore 	walk_state->method_desc->method.info_flags |=
148d1825579SBob Moore 	    (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
14922b5afceSBob Moore 
15022b5afceSBob Moore 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
15122b5afceSBob Moore 			  "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
15222b5afceSBob Moore 			  walk_state->method_node->name.ascii,
15322b5afceSBob Moore 			  walk_state->method_node, walk_state->op_info->name,
15422b5afceSBob Moore 			  walk_state->opcode));
15522b5afceSBob Moore 
15622b5afceSBob Moore 	/* Abort the parse, no need to examine this method any further */
15722b5afceSBob Moore 
15822b5afceSBob Moore 	return (AE_CTRL_TERMINATE);
15922b5afceSBob Moore }
16022b5afceSBob Moore 
16122b5afceSBob Moore /*******************************************************************************
16222b5afceSBob Moore  *
16395b482a8SLen Brown  * FUNCTION:    acpi_ds_method_error
16495b482a8SLen Brown  *
165ba494beeSBob Moore  * PARAMETERS:  status          - Execution status
16695b482a8SLen Brown  *              walk_state      - Current state
16795b482a8SLen Brown  *
16895b482a8SLen Brown  * RETURN:      Status
16995b482a8SLen Brown  *
17095b482a8SLen Brown  * DESCRIPTION: Called on method error. Invoke the global exception handler if
171fdd8d831SLv Zheng  *              present, dump the method data if the debugger is configured
17295b482a8SLen Brown  *
17395b482a8SLen Brown  *              Note: Allows the exception handler to change the status code
17495b482a8SLen Brown  *
17595b482a8SLen Brown  ******************************************************************************/
17695b482a8SLen Brown 
17795b482a8SLen Brown acpi_status
acpi_ds_method_error(acpi_status status,struct acpi_walk_state * walk_state)17895b482a8SLen Brown acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
17995b482a8SLen Brown {
18083482f75SLv Zheng 	u32 aml_offset;
181fd13aaa8SBob Moore 	acpi_name name = 0;
18283482f75SLv Zheng 
18395b482a8SLen Brown 	ACPI_FUNCTION_ENTRY();
18495b482a8SLen Brown 
18595b482a8SLen Brown 	/* Ignore AE_OK and control exception codes */
18695b482a8SLen Brown 
18795b482a8SLen Brown 	if (ACPI_SUCCESS(status) || (status & AE_CODE_CONTROL)) {
18895b482a8SLen Brown 		return (status);
18995b482a8SLen Brown 	}
19095b482a8SLen Brown 
19195b482a8SLen Brown 	/* Invoke the global exception handler */
19295b482a8SLen Brown 
19395b482a8SLen Brown 	if (acpi_gbl_exception_handler) {
19495b482a8SLen Brown 
19595b482a8SLen Brown 		/* Exit the interpreter, allow handler to execute methods */
19695b482a8SLen Brown 
19795b482a8SLen Brown 		acpi_ex_exit_interpreter();
19895b482a8SLen Brown 
19995b482a8SLen Brown 		/*
20095b482a8SLen Brown 		 * Handler can map the exception code to anything it wants, including
20195b482a8SLen Brown 		 * AE_OK, in which case the executing method will not be aborted.
20295b482a8SLen Brown 		 */
20383482f75SLv Zheng 		aml_offset = (u32)ACPI_PTR_DIFF(walk_state->aml,
20483482f75SLv Zheng 						walk_state->parser_state.
20583482f75SLv Zheng 						aml_start);
20683482f75SLv Zheng 
207fd13aaa8SBob Moore 		if (walk_state->method_node) {
208fd13aaa8SBob Moore 			name = walk_state->method_node->name.integer;
209fd13aaa8SBob Moore 		} else if (walk_state->deferred_node) {
210fd13aaa8SBob Moore 			name = walk_state->deferred_node->name.integer;
211fd13aaa8SBob Moore 		}
212fd13aaa8SBob Moore 
213fd13aaa8SBob Moore 		status = acpi_gbl_exception_handler(status, name,
21495b482a8SLen Brown 						    walk_state->opcode,
21583482f75SLv Zheng 						    aml_offset, NULL);
21695b482a8SLen Brown 		acpi_ex_enter_interpreter();
21795b482a8SLen Brown 	}
21895b482a8SLen Brown 
21995b482a8SLen Brown 	acpi_ds_clear_implicit_return(walk_state);
22095b482a8SLen Brown 
22195b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
2220bac4295SLv Zheng 		acpi_ds_dump_method_stack(status, walk_state, walk_state->op);
22395b482a8SLen Brown 
224fdd8d831SLv Zheng 		/* Display method locals/args if debugger is present */
22595b482a8SLen Brown 
226fdd8d831SLv Zheng #ifdef ACPI_DEBUGGER
227fdd8d831SLv Zheng 		acpi_db_dump_method_info(status, walk_state);
22895b482a8SLen Brown #endif
2290bac4295SLv Zheng 	}
23095b482a8SLen Brown 
23195b482a8SLen Brown 	return (status);
23295b482a8SLen Brown }
23395b482a8SLen Brown 
23495b482a8SLen Brown /*******************************************************************************
23595b482a8SLen Brown  *
23695b482a8SLen Brown  * FUNCTION:    acpi_ds_create_method_mutex
23795b482a8SLen Brown  *
23895b482a8SLen Brown  * PARAMETERS:  obj_desc            - The method object
23995b482a8SLen Brown  *
24095b482a8SLen Brown  * RETURN:      Status
24195b482a8SLen Brown  *
24295b482a8SLen Brown  * DESCRIPTION: Create a mutex object for a serialized control method
24395b482a8SLen Brown  *
24495b482a8SLen Brown  ******************************************************************************/
24595b482a8SLen Brown 
24695b482a8SLen Brown static acpi_status
acpi_ds_create_method_mutex(union acpi_operand_object * method_desc)24795b482a8SLen Brown acpi_ds_create_method_mutex(union acpi_operand_object *method_desc)
24895b482a8SLen Brown {
24995b482a8SLen Brown 	union acpi_operand_object *mutex_desc;
25095b482a8SLen Brown 	acpi_status status;
25195b482a8SLen Brown 
25295b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ds_create_method_mutex);
25395b482a8SLen Brown 
25495b482a8SLen Brown 	/* Create the new mutex object */
25595b482a8SLen Brown 
25695b482a8SLen Brown 	mutex_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX);
25795b482a8SLen Brown 	if (!mutex_desc) {
25895b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
25995b482a8SLen Brown 	}
26095b482a8SLen Brown 
26195b482a8SLen Brown 	/* Create the actual OS Mutex */
26295b482a8SLen Brown 
26395b482a8SLen Brown 	status = acpi_os_create_mutex(&mutex_desc->mutex.os_mutex);
26495b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
26578d025e2STim Gardner 		acpi_ut_delete_object_desc(mutex_desc);
26695b482a8SLen Brown 		return_ACPI_STATUS(status);
26795b482a8SLen Brown 	}
26895b482a8SLen Brown 
26995b482a8SLen Brown 	mutex_desc->mutex.sync_level = method_desc->method.sync_level;
27095b482a8SLen Brown 	method_desc->method.mutex = mutex_desc;
27195b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
27295b482a8SLen Brown }
27395b482a8SLen Brown 
27495b482a8SLen Brown /*******************************************************************************
27595b482a8SLen Brown  *
27695b482a8SLen Brown  * FUNCTION:    acpi_ds_begin_method_execution
27795b482a8SLen Brown  *
27895b482a8SLen Brown  * PARAMETERS:  method_node         - Node of the method
27995b482a8SLen Brown  *              obj_desc            - The method object
28095b482a8SLen Brown  *              walk_state          - current state, NULL if not yet executing
28195b482a8SLen Brown  *                                    a method.
28295b482a8SLen Brown  *
28395b482a8SLen Brown  * RETURN:      Status
28495b482a8SLen Brown  *
28595b482a8SLen Brown  * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
28695b482a8SLen Brown  *              increments the thread count, and waits at the method semaphore
28795b482a8SLen Brown  *              for clearance to execute.
28895b482a8SLen Brown  *
28995b482a8SLen Brown  ******************************************************************************/
29095b482a8SLen Brown 
29195b482a8SLen Brown acpi_status
acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node,union acpi_operand_object * obj_desc,struct acpi_walk_state * walk_state)29295b482a8SLen Brown acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
29395b482a8SLen Brown 			       union acpi_operand_object *obj_desc,
29495b482a8SLen Brown 			       struct acpi_walk_state *walk_state)
29595b482a8SLen Brown {
29695b482a8SLen Brown 	acpi_status status = AE_OK;
29795b482a8SLen Brown 
29895b482a8SLen Brown 	ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node);
29995b482a8SLen Brown 
30095b482a8SLen Brown 	if (!method_node) {
30195b482a8SLen Brown 		return_ACPI_STATUS(AE_NULL_ENTRY);
30295b482a8SLen Brown 	}
30395b482a8SLen Brown 
304ab6c5733SLv Zheng 	acpi_ex_start_trace_method(method_node, obj_desc, walk_state);
305a616dc2fSLv Zheng 
30695b482a8SLen Brown 	/* Prevent wraparound of thread count */
30795b482a8SLen Brown 
30895b482a8SLen Brown 	if (obj_desc->method.thread_count == ACPI_UINT8_MAX) {
30995b482a8SLen Brown 		ACPI_ERROR((AE_INFO,
31095b482a8SLen Brown 			    "Method reached maximum reentrancy limit (255)"));
31195b482a8SLen Brown 		return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
31295b482a8SLen Brown 	}
31395b482a8SLen Brown 
31495b482a8SLen Brown 	/*
31595b482a8SLen Brown 	 * If this method is serialized, we need to acquire the method mutex.
31695b482a8SLen Brown 	 */
31726294842SLin Ming 	if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) {
31895b482a8SLen Brown 		/*
31995b482a8SLen Brown 		 * Create a mutex for the method if it is defined to be Serialized
32095b482a8SLen Brown 		 * and a mutex has not already been created. We defer the mutex creation
32195b482a8SLen Brown 		 * until a method is actually executed, to minimize the object count
32295b482a8SLen Brown 		 */
32395b482a8SLen Brown 		if (!obj_desc->method.mutex) {
32495b482a8SLen Brown 			status = acpi_ds_create_method_mutex(obj_desc);
32595b482a8SLen Brown 			if (ACPI_FAILURE(status)) {
32695b482a8SLen Brown 				return_ACPI_STATUS(status);
32795b482a8SLen Brown 			}
32895b482a8SLen Brown 		}
32995b482a8SLen Brown 
33095b482a8SLen Brown 		/*
33195b482a8SLen Brown 		 * The current_sync_level (per-thread) must be less than or equal to
33295b482a8SLen Brown 		 * the sync level of the method. This mechanism provides some
333d1825579SBob Moore 		 * deadlock prevention.
334d1825579SBob Moore 		 *
335d1825579SBob Moore 		 * If the method was auto-serialized, we just ignore the sync level
336d1825579SBob Moore 		 * mechanism, because auto-serialization of methods can interfere
337d1825579SBob Moore 		 * with ASL code that actually uses sync levels.
33895b482a8SLen Brown 		 *
33995b482a8SLen Brown 		 * Top-level method invocation has no walk state at this point
34095b482a8SLen Brown 		 */
34195b482a8SLen Brown 		if (walk_state &&
342d1825579SBob Moore 		    (!(obj_desc->method.
343d1825579SBob Moore 		       info_flags & ACPI_METHOD_IGNORE_SYNC_LEVEL))
344d1825579SBob Moore 		    && (walk_state->thread->current_sync_level >
34595b482a8SLen Brown 			obj_desc->method.mutex->mutex.sync_level)) {
34695b482a8SLen Brown 			ACPI_ERROR((AE_INFO,
3471fad8738SBob Moore 				    "Cannot acquire Mutex for method [%4.4s]"
3481fad8738SBob Moore 				    ", current SyncLevel is too large (%u)",
34995b482a8SLen Brown 				    acpi_ut_get_node_name(method_node),
35095b482a8SLen Brown 				    walk_state->thread->current_sync_level));
35195b482a8SLen Brown 
35295b482a8SLen Brown 			return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
35395b482a8SLen Brown 		}
35495b482a8SLen Brown 
35595b482a8SLen Brown 		/*
35695b482a8SLen Brown 		 * Obtain the method mutex if necessary. Do not acquire mutex for a
35795b482a8SLen Brown 		 * recursive call.
35895b482a8SLen Brown 		 */
35995b482a8SLen Brown 		if (!walk_state ||
36095b482a8SLen Brown 		    !obj_desc->method.mutex->mutex.thread_id ||
36195b482a8SLen Brown 		    (walk_state->thread->thread_id !=
36295b482a8SLen Brown 		     obj_desc->method.mutex->mutex.thread_id)) {
36395b482a8SLen Brown 			/*
36495b482a8SLen Brown 			 * Acquire the method mutex. This releases the interpreter if we
36595b482a8SLen Brown 			 * block (and reacquires it before it returns)
36695b482a8SLen Brown 			 */
36795b482a8SLen Brown 			status =
36895b482a8SLen Brown 			    acpi_ex_system_wait_mutex(obj_desc->method.mutex->
36995b482a8SLen Brown 						      mutex.os_mutex,
37095b482a8SLen Brown 						      ACPI_WAIT_FOREVER);
37195b482a8SLen Brown 			if (ACPI_FAILURE(status)) {
37295b482a8SLen Brown 				return_ACPI_STATUS(status);
37395b482a8SLen Brown 			}
37495b482a8SLen Brown 
37595b482a8SLen Brown 			/* Update the mutex and walk info and save the original sync_level */
37695b482a8SLen Brown 
37795b482a8SLen Brown 			if (walk_state) {
37895b482a8SLen Brown 				obj_desc->method.mutex->mutex.
37995b482a8SLen Brown 				    original_sync_level =
38095b482a8SLen Brown 				    walk_state->thread->current_sync_level;
38195b482a8SLen Brown 
38295b482a8SLen Brown 				obj_desc->method.mutex->mutex.thread_id =
38395b482a8SLen Brown 				    walk_state->thread->thread_id;
38433d3a2abSDavid E. Box 
38533d3a2abSDavid E. Box 				/*
38633d3a2abSDavid E. Box 				 * Update the current sync_level only if this is not an auto-
38733d3a2abSDavid E. Box 				 * serialized method. In the auto case, we have to ignore
38833d3a2abSDavid E. Box 				 * the sync level for the method mutex (created for the
38933d3a2abSDavid E. Box 				 * auto-serialization) because we have no idea of what the
39033d3a2abSDavid E. Box 				 * sync level should be. Therefore, just ignore it.
39133d3a2abSDavid E. Box 				 */
39233d3a2abSDavid E. Box 				if (!(obj_desc->method.info_flags &
39333d3a2abSDavid E. Box 				      ACPI_METHOD_IGNORE_SYNC_LEVEL)) {
39495b482a8SLen Brown 					walk_state->thread->current_sync_level =
39595b482a8SLen Brown 					    obj_desc->method.sync_level;
39633d3a2abSDavid E. Box 				}
39795b482a8SLen Brown 			} else {
39895b482a8SLen Brown 				obj_desc->method.mutex->mutex.
39995b482a8SLen Brown 				    original_sync_level =
40095b482a8SLen Brown 				    obj_desc->method.mutex->mutex.sync_level;
40193d68841SPrarit Bhargava 
40293d68841SPrarit Bhargava 				obj_desc->method.mutex->mutex.thread_id =
40393d68841SPrarit Bhargava 				    acpi_os_get_thread_id();
40495b482a8SLen Brown 			}
40595b482a8SLen Brown 		}
40695b482a8SLen Brown 
40795b482a8SLen Brown 		/* Always increase acquisition depth */
40895b482a8SLen Brown 
40995b482a8SLen Brown 		obj_desc->method.mutex->mutex.acquisition_depth++;
41095b482a8SLen Brown 	}
41195b482a8SLen Brown 
41295b482a8SLen Brown 	/*
41395b482a8SLen Brown 	 * Allocate an Owner ID for this method, only if this is the first thread
41495b482a8SLen Brown 	 * to begin concurrent execution. We only need one owner_id, even if the
41595b482a8SLen Brown 	 * method is invoked recursively.
41695b482a8SLen Brown 	 */
41795b482a8SLen Brown 	if (!obj_desc->method.owner_id) {
41895b482a8SLen Brown 		status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
41995b482a8SLen Brown 		if (ACPI_FAILURE(status)) {
42095b482a8SLen Brown 			goto cleanup;
42195b482a8SLen Brown 		}
42295b482a8SLen Brown 	}
42395b482a8SLen Brown 
42495b482a8SLen Brown 	/*
42595b482a8SLen Brown 	 * Increment the method parse tree thread count since it has been
42695b482a8SLen Brown 	 * reentered one more time (even if it is the same thread)
42795b482a8SLen Brown 	 */
42895b482a8SLen Brown 	obj_desc->method.thread_count++;
4299187a415SLv Zheng 	acpi_method_count++;
43095b482a8SLen Brown 	return_ACPI_STATUS(status);
43195b482a8SLen Brown 
43295b482a8SLen Brown cleanup:
43395b482a8SLen Brown 	/* On error, must release the method mutex (if present) */
43495b482a8SLen Brown 
43595b482a8SLen Brown 	if (obj_desc->method.mutex) {
43695b482a8SLen Brown 		acpi_os_release_mutex(obj_desc->method.mutex->mutex.os_mutex);
43795b482a8SLen Brown 	}
43895b482a8SLen Brown 	return_ACPI_STATUS(status);
43995b482a8SLen Brown }
44095b482a8SLen Brown 
44195b482a8SLen Brown /*******************************************************************************
44295b482a8SLen Brown  *
44395b482a8SLen Brown  * FUNCTION:    acpi_ds_call_control_method
44495b482a8SLen Brown  *
445ba494beeSBob Moore  * PARAMETERS:  thread              - Info for this thread
44695b482a8SLen Brown  *              this_walk_state     - Current walk state
447ba494beeSBob Moore  *              op                  - Current Op to be walked
44895b482a8SLen Brown  *
44995b482a8SLen Brown  * RETURN:      Status
45095b482a8SLen Brown  *
45195b482a8SLen Brown  * DESCRIPTION: Transfer execution to a called control method
45295b482a8SLen Brown  *
45395b482a8SLen Brown  ******************************************************************************/
45495b482a8SLen Brown 
45595b482a8SLen Brown acpi_status
acpi_ds_call_control_method(struct acpi_thread_state * thread,struct acpi_walk_state * this_walk_state,union acpi_parse_object * op)45695b482a8SLen Brown acpi_ds_call_control_method(struct acpi_thread_state *thread,
45795b482a8SLen Brown 			    struct acpi_walk_state *this_walk_state,
45895b482a8SLen Brown 			    union acpi_parse_object *op)
45995b482a8SLen Brown {
46095b482a8SLen Brown 	acpi_status status;
46195b482a8SLen Brown 	struct acpi_namespace_node *method_node;
46295b482a8SLen Brown 	struct acpi_walk_state *next_walk_state = NULL;
46395b482a8SLen Brown 	union acpi_operand_object *obj_desc;
46495b482a8SLen Brown 	struct acpi_evaluate_info *info;
46595b482a8SLen Brown 	u32 i;
46695b482a8SLen Brown 
46795b482a8SLen Brown 	ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
46895b482a8SLen Brown 
46995b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
47095b482a8SLen Brown 			  "Calling method %p, currentstate=%p\n",
47195b482a8SLen Brown 			  this_walk_state->prev_op, this_walk_state));
47295b482a8SLen Brown 
47395b482a8SLen Brown 	/*
47495b482a8SLen Brown 	 * Get the namespace entry for the control method we are about to call
47595b482a8SLen Brown 	 */
47695b482a8SLen Brown 	method_node = this_walk_state->method_call_node;
47795b482a8SLen Brown 	if (!method_node) {
47895b482a8SLen Brown 		return_ACPI_STATUS(AE_NULL_ENTRY);
47995b482a8SLen Brown 	}
48095b482a8SLen Brown 
48195b482a8SLen Brown 	obj_desc = acpi_ns_get_attached_object(method_node);
48295b482a8SLen Brown 	if (!obj_desc) {
48395b482a8SLen Brown 		return_ACPI_STATUS(AE_NULL_OBJECT);
48495b482a8SLen Brown 	}
48595b482a8SLen Brown 
48695b482a8SLen Brown 	/* Init for new method, possibly wait on method mutex */
48795b482a8SLen Brown 
4881fad8738SBob Moore 	status =
4891fad8738SBob Moore 	    acpi_ds_begin_method_execution(method_node, obj_desc,
49095b482a8SLen Brown 					   this_walk_state);
49195b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
49295b482a8SLen Brown 		return_ACPI_STATUS(status);
49395b482a8SLen Brown 	}
49495b482a8SLen Brown 
49595b482a8SLen Brown 	/* Begin method parse/execution. Create a new walk state */
49695b482a8SLen Brown 
4971fad8738SBob Moore 	next_walk_state =
4981fad8738SBob Moore 	    acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, obj_desc,
4991fad8738SBob Moore 				      thread);
50095b482a8SLen Brown 	if (!next_walk_state) {
50195b482a8SLen Brown 		status = AE_NO_MEMORY;
50295b482a8SLen Brown 		goto cleanup;
50395b482a8SLen Brown 	}
50495b482a8SLen Brown 
50595b482a8SLen Brown 	/*
50695b482a8SLen Brown 	 * The resolved arguments were put on the previous walk state's operand
50795b482a8SLen Brown 	 * stack. Operands on the previous walk state stack always
50895b482a8SLen Brown 	 * start at index 0. Also, null terminate the list of arguments
50995b482a8SLen Brown 	 */
51095b482a8SLen Brown 	this_walk_state->operands[this_walk_state->num_operands] = NULL;
51195b482a8SLen Brown 
51295b482a8SLen Brown 	/*
51395b482a8SLen Brown 	 * Allocate and initialize the evaluation information block
51495b482a8SLen Brown 	 * TBD: this is somewhat inefficient, should change interface to
51595b482a8SLen Brown 	 * ds_init_aml_walk. For now, keeps this struct off the CPU stack
51695b482a8SLen Brown 	 */
51795b482a8SLen Brown 	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
51895b482a8SLen Brown 	if (!info) {
51922715821SJesper Juhl 		status = AE_NO_MEMORY;
520404ec604SRafael J. Wysocki 		goto pop_walk_state;
52195b482a8SLen Brown 	}
52295b482a8SLen Brown 
52395b482a8SLen Brown 	info->parameters = &this_walk_state->operands[0];
52495b482a8SLen Brown 
52595b482a8SLen Brown 	status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
52695b482a8SLen Brown 				       obj_desc->method.aml_start,
52795b482a8SLen Brown 				       obj_desc->method.aml_length, info,
52895b482a8SLen Brown 				       ACPI_IMODE_EXECUTE);
52995b482a8SLen Brown 
53095b482a8SLen Brown 	ACPI_FREE(info);
53195b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
532404ec604SRafael J. Wysocki 		goto pop_walk_state;
53395b482a8SLen Brown 	}
53495b482a8SLen Brown 
5354c1379d7SBob Moore 	next_walk_state->method_nesting_depth =
5364c1379d7SBob Moore 	    this_walk_state->method_nesting_depth + 1;
5374c1379d7SBob Moore 
53895b482a8SLen Brown 	/*
53995b482a8SLen Brown 	 * Delete the operands on the previous walkstate operand stack
54095b482a8SLen Brown 	 * (they were copied to new objects)
54195b482a8SLen Brown 	 */
54295b482a8SLen Brown 	for (i = 0; i < obj_desc->method.param_count; i++) {
54395b482a8SLen Brown 		acpi_ut_remove_reference(this_walk_state->operands[i]);
54495b482a8SLen Brown 		this_walk_state->operands[i] = NULL;
54595b482a8SLen Brown 	}
54695b482a8SLen Brown 
54795b482a8SLen Brown 	/* Clear the operand stack */
54895b482a8SLen Brown 
54995b482a8SLen Brown 	this_walk_state->num_operands = 0;
55095b482a8SLen Brown 
55195b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
55295b482a8SLen Brown 			  "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
55395b482a8SLen Brown 			  method_node->name.ascii, next_walk_state));
55495b482a8SLen Brown 
5554c1379d7SBob Moore 	this_walk_state->method_pathname =
5564c1379d7SBob Moore 	    acpi_ns_get_normalized_pathname(method_node, TRUE);
5574c1379d7SBob Moore 	this_walk_state->method_is_nested = TRUE;
5584c1379d7SBob Moore 
5594c1379d7SBob Moore 	/* Optional object evaluation log */
5604c1379d7SBob Moore 
5614c1379d7SBob Moore 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
5624c1379d7SBob Moore 			      "%-26s:  %*s%s\n", "   Nested method call",
5634c1379d7SBob Moore 			      next_walk_state->method_nesting_depth * 3, " ",
5644c1379d7SBob Moore 			      &this_walk_state->method_pathname[1]));
5654c1379d7SBob Moore 
56695b482a8SLen Brown 	/* Invoke an internal method if necessary */
56795b482a8SLen Brown 
56826294842SLin Ming 	if (obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) {
56926294842SLin Ming 		status =
57026294842SLin Ming 		    obj_desc->method.dispatch.implementation(next_walk_state);
57195b482a8SLen Brown 		if (status == AE_OK) {
57295b482a8SLen Brown 			status = AE_CTRL_TERMINATE;
57395b482a8SLen Brown 		}
57495b482a8SLen Brown 	}
57595b482a8SLen Brown 
57695b482a8SLen Brown 	return_ACPI_STATUS(status);
57795b482a8SLen Brown 
578404ec604SRafael J. Wysocki pop_walk_state:
579404ec604SRafael J. Wysocki 
580404ec604SRafael J. Wysocki 	/* On error, pop the walk state to be deleted from thread */
581404ec604SRafael J. Wysocki 
582404ec604SRafael J. Wysocki 	acpi_ds_pop_walk_state(thread);
583404ec604SRafael J. Wysocki 
58495b482a8SLen Brown cleanup:
58595b482a8SLen Brown 
58695b482a8SLen Brown 	/* On error, we must terminate the method properly */
58795b482a8SLen Brown 
58895b482a8SLen Brown 	acpi_ds_terminate_control_method(obj_desc, next_walk_state);
58995b482a8SLen Brown 	acpi_ds_delete_walk_state(next_walk_state);
59095b482a8SLen Brown 
59195b482a8SLen Brown 	return_ACPI_STATUS(status);
59295b482a8SLen Brown }
59395b482a8SLen Brown 
59495b482a8SLen Brown /*******************************************************************************
59595b482a8SLen Brown  *
59695b482a8SLen Brown  * FUNCTION:    acpi_ds_restart_control_method
59795b482a8SLen Brown  *
59895b482a8SLen Brown  * PARAMETERS:  walk_state          - State for preempted method (caller)
59995b482a8SLen Brown  *              return_desc         - Return value from the called method
60095b482a8SLen Brown  *
60195b482a8SLen Brown  * RETURN:      Status
60295b482a8SLen Brown  *
60395b482a8SLen Brown  * DESCRIPTION: Restart a method that was preempted by another (nested) method
60495b482a8SLen Brown  *              invocation. Handle the return value (if any) from the callee.
60595b482a8SLen Brown  *
60695b482a8SLen Brown  ******************************************************************************/
60795b482a8SLen Brown 
60895b482a8SLen Brown acpi_status
acpi_ds_restart_control_method(struct acpi_walk_state * walk_state,union acpi_operand_object * return_desc)60995b482a8SLen Brown acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
61095b482a8SLen Brown 			       union acpi_operand_object *return_desc)
61195b482a8SLen Brown {
61295b482a8SLen Brown 	acpi_status status;
61395b482a8SLen Brown 	int same_as_implicit_return;
61495b482a8SLen Brown 
61595b482a8SLen Brown 	ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state);
61695b482a8SLen Brown 
61795b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
61895b482a8SLen Brown 			  "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
61995b482a8SLen Brown 			  acpi_ut_get_node_name(walk_state->method_node),
62095b482a8SLen Brown 			  walk_state->method_call_op, return_desc));
62195b482a8SLen Brown 
62295b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
62395b482a8SLen Brown 			  "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
62495b482a8SLen Brown 			  walk_state->return_used,
62595b482a8SLen Brown 			  walk_state->results, walk_state));
62695b482a8SLen Brown 
62795b482a8SLen Brown 	/* Did the called method return a value? */
62895b482a8SLen Brown 
62995b482a8SLen Brown 	if (return_desc) {
63095b482a8SLen Brown 
63195b482a8SLen Brown 		/* Is the implicit return object the same as the return desc? */
63295b482a8SLen Brown 
63395b482a8SLen Brown 		same_as_implicit_return =
63495b482a8SLen Brown 		    (walk_state->implicit_return_obj == return_desc);
63595b482a8SLen Brown 
63695b482a8SLen Brown 		/* Are we actually going to use the return value? */
63795b482a8SLen Brown 
63895b482a8SLen Brown 		if (walk_state->return_used) {
63995b482a8SLen Brown 
64095b482a8SLen Brown 			/* Save the return value from the previous method */
64195b482a8SLen Brown 
64295b482a8SLen Brown 			status = acpi_ds_result_push(return_desc, walk_state);
64395b482a8SLen Brown 			if (ACPI_FAILURE(status)) {
64495b482a8SLen Brown 				acpi_ut_remove_reference(return_desc);
64595b482a8SLen Brown 				return_ACPI_STATUS(status);
64695b482a8SLen Brown 			}
64795b482a8SLen Brown 
64895b482a8SLen Brown 			/*
64995b482a8SLen Brown 			 * Save as THIS method's return value in case it is returned
65095b482a8SLen Brown 			 * immediately to yet another method
65195b482a8SLen Brown 			 */
65295b482a8SLen Brown 			walk_state->return_desc = return_desc;
65395b482a8SLen Brown 		}
65495b482a8SLen Brown 
65595b482a8SLen Brown 		/*
65695b482a8SLen Brown 		 * The following code is the optional support for the so-called
65795b482a8SLen Brown 		 * "implicit return". Some AML code assumes that the last value of the
65895b482a8SLen Brown 		 * method is "implicitly" returned to the caller, in the absence of an
65995b482a8SLen Brown 		 * explicit return value.
66095b482a8SLen Brown 		 *
66195b482a8SLen Brown 		 * Just save the last result of the method as the return value.
66295b482a8SLen Brown 		 *
66395b482a8SLen Brown 		 * NOTE: this is optional because the ASL language does not actually
66495b482a8SLen Brown 		 * support this behavior.
66595b482a8SLen Brown 		 */
66695b482a8SLen Brown 		else if (!acpi_ds_do_implicit_return
66795b482a8SLen Brown 			 (return_desc, walk_state, FALSE)
66895b482a8SLen Brown 			 || same_as_implicit_return) {
66995b482a8SLen Brown 			/*
67095b482a8SLen Brown 			 * Delete the return value if it will not be used by the
67195b482a8SLen Brown 			 * calling method or remove one reference if the explicit return
67295b482a8SLen Brown 			 * is the same as the implicit return value.
67395b482a8SLen Brown 			 */
67495b482a8SLen Brown 			acpi_ut_remove_reference(return_desc);
67595b482a8SLen Brown 		}
67695b482a8SLen Brown 	}
67795b482a8SLen Brown 
67895b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
67995b482a8SLen Brown }
68095b482a8SLen Brown 
68195b482a8SLen Brown /*******************************************************************************
68295b482a8SLen Brown  *
68395b482a8SLen Brown  * FUNCTION:    acpi_ds_terminate_control_method
68495b482a8SLen Brown  *
68595b482a8SLen Brown  * PARAMETERS:  method_desc         - Method object
68695b482a8SLen Brown  *              walk_state          - State associated with the method
68795b482a8SLen Brown  *
68895b482a8SLen Brown  * RETURN:      None
68995b482a8SLen Brown  *
69095b482a8SLen Brown  * DESCRIPTION: Terminate a control method. Delete everything that the method
69195b482a8SLen Brown  *              created, delete all locals and arguments, and delete the parse
69295b482a8SLen Brown  *              tree if requested.
69395b482a8SLen Brown  *
69495b482a8SLen Brown  * MUTEX:       Interpreter is locked
69595b482a8SLen Brown  *
69695b482a8SLen Brown  ******************************************************************************/
69795b482a8SLen Brown 
69895b482a8SLen Brown void
acpi_ds_terminate_control_method(union acpi_operand_object * method_desc,struct acpi_walk_state * walk_state)69995b482a8SLen Brown acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
70095b482a8SLen Brown 				 struct acpi_walk_state *walk_state)
70195b482a8SLen Brown {
70295b482a8SLen Brown 
70395b482a8SLen Brown 	ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state);
70495b482a8SLen Brown 
70595b482a8SLen Brown 	/* method_desc is required, walk_state is optional */
70695b482a8SLen Brown 
70795b482a8SLen Brown 	if (!method_desc) {
70895b482a8SLen Brown 		return_VOID;
70995b482a8SLen Brown 	}
71095b482a8SLen Brown 
71195b482a8SLen Brown 	if (walk_state) {
71295b482a8SLen Brown 
71395b482a8SLen Brown 		/* Delete all arguments and locals */
71495b482a8SLen Brown 
71595b482a8SLen Brown 		acpi_ds_method_data_delete_all(walk_state);
71695b482a8SLen Brown 
71795b482a8SLen Brown 		/*
7187f0c826aSLin Ming 		 * Delete any namespace objects created anywhere within the
71926294842SLin Ming 		 * namespace by the execution of this method. Unless:
72026294842SLin Ming 		 * 1) This method is a module-level executable code method, in which
72126294842SLin Ming 		 *    case we want make the objects permanent.
72226294842SLin Ming 		 * 2) There are other threads executing the method, in which case we
72326294842SLin Ming 		 *    will wait until the last thread has completed.
72495b482a8SLen Brown 		 */
72526294842SLin Ming 		if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL)
72626294842SLin Ming 		    && (method_desc->method.thread_count == 1)) {
727a9fc0312SAlexey Starikovskiy 
728a9fc0312SAlexey Starikovskiy 			/* Delete any direct children of (created by) this method */
729a9fc0312SAlexey Starikovskiy 
73074f51b80SLv Zheng 			(void)acpi_ex_exit_interpreter();
731a9fc0312SAlexey Starikovskiy 			acpi_ns_delete_namespace_subtree(walk_state->
732a9fc0312SAlexey Starikovskiy 							 method_node);
73374f51b80SLv Zheng 			(void)acpi_ex_enter_interpreter();
734a9fc0312SAlexey Starikovskiy 
735a9fc0312SAlexey Starikovskiy 			/*
736a9fc0312SAlexey Starikovskiy 			 * Delete any objects that were created by this method
737a9fc0312SAlexey Starikovskiy 			 * elsewhere in the namespace (if any were created).
73826294842SLin Ming 			 * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
73926294842SLin Ming 			 * deletion such that we don't have to perform an entire
74026294842SLin Ming 			 * namespace walk for every control method execution.
741a9fc0312SAlexey Starikovskiy 			 */
742a9fc0312SAlexey Starikovskiy 			if (method_desc->method.
74326294842SLin Ming 			    info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) {
74474f51b80SLv Zheng 				(void)acpi_ex_exit_interpreter();
745a9fc0312SAlexey Starikovskiy 				acpi_ns_delete_namespace_by_owner(method_desc->
746a9fc0312SAlexey Starikovskiy 								  method.
7477f0c826aSLin Ming 								  owner_id);
74874f51b80SLv Zheng 				(void)acpi_ex_enter_interpreter();
74926294842SLin Ming 				method_desc->method.info_flags &=
75026294842SLin Ming 				    ~ACPI_METHOD_MODIFIED_NAMESPACE;
7517f0c826aSLin Ming 			}
75295b482a8SLen Brown 		}
75325ccd242SLv Zheng 
75425ccd242SLv Zheng 		/*
75525ccd242SLv Zheng 		 * If method is serialized, release the mutex and restore the
75625ccd242SLv Zheng 		 * current sync level for this thread
75725ccd242SLv Zheng 		 */
75825ccd242SLv Zheng 		if (method_desc->method.mutex) {
75925ccd242SLv Zheng 
76025ccd242SLv Zheng 			/* Acquisition Depth handles recursive calls */
76125ccd242SLv Zheng 
76225ccd242SLv Zheng 			method_desc->method.mutex->mutex.acquisition_depth--;
76325ccd242SLv Zheng 			if (!method_desc->method.mutex->mutex.acquisition_depth) {
76425ccd242SLv Zheng 				walk_state->thread->current_sync_level =
76525ccd242SLv Zheng 				    method_desc->method.mutex->mutex.
76625ccd242SLv Zheng 				    original_sync_level;
76725ccd242SLv Zheng 
76825ccd242SLv Zheng 				acpi_os_release_mutex(method_desc->method.
76925ccd242SLv Zheng 						      mutex->mutex.os_mutex);
77025ccd242SLv Zheng 				method_desc->method.mutex->mutex.thread_id = 0;
77125ccd242SLv Zheng 			}
77225ccd242SLv Zheng 		}
773a9fc0312SAlexey Starikovskiy 	}
77495b482a8SLen Brown 
77595b482a8SLen Brown 	/* Decrement the thread count on the method */
77695b482a8SLen Brown 
77795b482a8SLen Brown 	if (method_desc->method.thread_count) {
77895b482a8SLen Brown 		method_desc->method.thread_count--;
77995b482a8SLen Brown 	} else {
78095b482a8SLen Brown 		ACPI_ERROR((AE_INFO, "Invalid zero thread count in method"));
78195b482a8SLen Brown 	}
78295b482a8SLen Brown 
78395b482a8SLen Brown 	/* Are there any other threads currently executing this method? */
78495b482a8SLen Brown 
78595b482a8SLen Brown 	if (method_desc->method.thread_count) {
78695b482a8SLen Brown 		/*
78795b482a8SLen Brown 		 * Additional threads. Do not release the owner_id in this case,
78895b482a8SLen Brown 		 * we immediately reuse it for the next thread executing this method
78995b482a8SLen Brown 		 */
79095b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
791b27d6597SBob Moore 				  "*** Completed execution of one thread, %u threads remaining\n",
79295b482a8SLen Brown 				  method_desc->method.thread_count));
79395b482a8SLen Brown 	} else {
79495b482a8SLen Brown 		/* This is the only executing thread for this method */
79595b482a8SLen Brown 
79695b482a8SLen Brown 		/*
79795b482a8SLen Brown 		 * Support to dynamically change a method from not_serialized to
79895b482a8SLen Brown 		 * Serialized if it appears that the method is incorrectly written and
79995b482a8SLen Brown 		 * does not support multiple thread execution. The best example of this
80095b482a8SLen Brown 		 * is if such a method creates namespace objects and blocks. A second
80126294842SLin Ming 		 * thread will fail with an AE_ALREADY_EXISTS exception.
80295b482a8SLen Brown 		 *
80395b482a8SLen Brown 		 * This code is here because we must wait until the last thread exits
80426294842SLin Ming 		 * before marking the method as serialized.
80595b482a8SLen Brown 		 */
80626294842SLin Ming 		if (method_desc->method.
80726294842SLin Ming 		    info_flags & ACPI_METHOD_SERIALIZED_PENDING) {
80826294842SLin Ming 			if (walk_state) {
80905fb04b5SBob Moore 				ACPI_INFO(("Marking method %4.4s as Serialized "
8101fad8738SBob Moore 					   "because of AE_ALREADY_EXISTS error",
81126294842SLin Ming 					   walk_state->method_node->name.
81226294842SLin Ming 					   ascii));
81326294842SLin Ming 			}
81426294842SLin Ming 
81526294842SLin Ming 			/*
81626294842SLin Ming 			 * Method tried to create an object twice and was marked as
81726294842SLin Ming 			 * "pending serialized". The probable cause is that the method
81826294842SLin Ming 			 * cannot handle reentrancy.
81926294842SLin Ming 			 *
82026294842SLin Ming 			 * The method was created as not_serialized, but it tried to create
82126294842SLin Ming 			 * a named object and then blocked, causing the second thread
82226294842SLin Ming 			 * entrance to begin and then fail. Workaround this problem by
82326294842SLin Ming 			 * marking the method permanently as Serialized when the last
82426294842SLin Ming 			 * thread exits here.
82526294842SLin Ming 			 */
82626294842SLin Ming 			method_desc->method.info_flags &=
82726294842SLin Ming 			    ~ACPI_METHOD_SERIALIZED_PENDING;
8281fad8738SBob Moore 
82926294842SLin Ming 			method_desc->method.info_flags |=
830d1825579SBob Moore 			    (ACPI_METHOD_SERIALIZED |
831d1825579SBob Moore 			     ACPI_METHOD_IGNORE_SYNC_LEVEL);
83226294842SLin Ming 			method_desc->method.sync_level = 0;
83395b482a8SLen Brown 		}
83495b482a8SLen Brown 
83595b482a8SLen Brown 		/* No more threads, we can free the owner_id */
83695b482a8SLen Brown 
83726294842SLin Ming 		if (!
83826294842SLin Ming 		    (method_desc->method.
83926294842SLin Ming 		     info_flags & ACPI_METHOD_MODULE_LEVEL)) {
84095b482a8SLen Brown 			acpi_ut_release_owner_id(&method_desc->method.owner_id);
84195b482a8SLen Brown 		}
8427f0c826aSLin Ming 	}
84395b482a8SLen Brown 
844ab6c5733SLv Zheng 	acpi_ex_stop_trace_method((struct acpi_namespace_node *)method_desc->
845ab6c5733SLv Zheng 				  method.node, method_desc, walk_state);
846a616dc2fSLv Zheng 
84795b482a8SLen Brown 	return_VOID;
84895b482a8SLen Brown }
849