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