162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: dsmethod - Parser/Interpreter interface - control method parsing 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "acdispat.h" 1362306a36Sopenharmony_ci#include "acinterp.h" 1462306a36Sopenharmony_ci#include "acnamesp.h" 1562306a36Sopenharmony_ci#include "acparser.h" 1662306a36Sopenharmony_ci#include "amlcode.h" 1762306a36Sopenharmony_ci#include "acdebug.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define _COMPONENT ACPI_DISPATCHER 2062306a36Sopenharmony_ciACPI_MODULE_NAME("dsmethod") 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Local prototypes */ 2362306a36Sopenharmony_cistatic acpi_status 2462306a36Sopenharmony_ciacpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, 2562306a36Sopenharmony_ci union acpi_parse_object **out_op); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic acpi_status 2862306a36Sopenharmony_ciacpi_ds_create_method_mutex(union acpi_operand_object *method_desc); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/******************************************************************************* 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * FUNCTION: acpi_ds_auto_serialize_method 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * PARAMETERS: node - Namespace Node of the method 3562306a36Sopenharmony_ci * obj_desc - Method object attached to node 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * RETURN: Status 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * DESCRIPTION: Parse a control method AML to scan for control methods that 4062306a36Sopenharmony_ci * need serialization due to the creation of named objects. 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * NOTE: It is a bit of overkill to mark all such methods serialized, since 4362306a36Sopenharmony_ci * there is only a problem if the method actually blocks during execution. 4462306a36Sopenharmony_ci * A blocking operation is, for example, a Sleep() operation, or any access 4562306a36Sopenharmony_ci * to an operation region. However, it is probably not possible to easily 4662306a36Sopenharmony_ci * detect whether a method will block or not, so we simply mark all suspicious 4762306a36Sopenharmony_ci * methods as serialized. 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * NOTE2: This code is essentially a generic routine for parsing a single 5062306a36Sopenharmony_ci * control method. 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci ******************************************************************************/ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciacpi_status 5562306a36Sopenharmony_ciacpi_ds_auto_serialize_method(struct acpi_namespace_node *node, 5662306a36Sopenharmony_ci union acpi_operand_object *obj_desc) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci acpi_status status; 5962306a36Sopenharmony_ci union acpi_parse_object *op = NULL; 6062306a36Sopenharmony_ci struct acpi_walk_state *walk_state; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_auto_serialize_method, node); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_PARSE, 6562306a36Sopenharmony_ci "Method auto-serialization parse [%4.4s] %p\n", 6662306a36Sopenharmony_ci acpi_ut_get_node_name(node), node)); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* Create/Init a root op for the method parse tree */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci op = acpi_ps_alloc_op(AML_METHOD_OP, obj_desc->method.aml_start); 7162306a36Sopenharmony_ci if (!op) { 7262306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci acpi_ps_set_name(op, node->name.integer); 7662306a36Sopenharmony_ci op->common.node = node; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* Create and initialize a new walk state */ 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci walk_state = 8162306a36Sopenharmony_ci acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL); 8262306a36Sopenharmony_ci if (!walk_state) { 8362306a36Sopenharmony_ci acpi_ps_free_op(op); 8462306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci status = acpi_ds_init_aml_walk(walk_state, op, node, 8862306a36Sopenharmony_ci obj_desc->method.aml_start, 8962306a36Sopenharmony_ci obj_desc->method.aml_length, NULL, 0); 9062306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 9162306a36Sopenharmony_ci acpi_ds_delete_walk_state(walk_state); 9262306a36Sopenharmony_ci acpi_ps_free_op(op); 9362306a36Sopenharmony_ci return_ACPI_STATUS(status); 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci walk_state->descending_callback = acpi_ds_detect_named_opcodes; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* Parse the method, scan for creation of named objects */ 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci status = acpi_ps_parse_aml(walk_state); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci acpi_ps_delete_parse_tree(op); 10362306a36Sopenharmony_ci return_ACPI_STATUS(status); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/******************************************************************************* 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * FUNCTION: acpi_ds_detect_named_opcodes 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * PARAMETERS: walk_state - Current state of the parse tree walk 11162306a36Sopenharmony_ci * out_op - Unused, required for parser interface 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * RETURN: Status 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * DESCRIPTION: Descending callback used during the loading of ACPI tables. 11662306a36Sopenharmony_ci * Currently used to detect methods that must be marked serialized 11762306a36Sopenharmony_ci * in order to avoid problems with the creation of named objects. 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci ******************************************************************************/ 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic acpi_status 12262306a36Sopenharmony_ciacpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, 12362306a36Sopenharmony_ci union acpi_parse_object **out_op) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci ACPI_FUNCTION_NAME(acpi_ds_detect_named_opcodes); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* We are only interested in opcodes that create a new name */ 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (! 13162306a36Sopenharmony_ci (walk_state->op_info-> 13262306a36Sopenharmony_ci flags & (AML_NAMED | AML_CREATE | AML_FIELD))) { 13362306a36Sopenharmony_ci return (AE_OK); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * At this point, we know we have a Named object opcode. 13862306a36Sopenharmony_ci * Mark the method as serialized. Later code will create a mutex for 13962306a36Sopenharmony_ci * this method to enforce serialization. 14062306a36Sopenharmony_ci * 14162306a36Sopenharmony_ci * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the 14262306a36Sopenharmony_ci * Sync Level mechanism for this method, even though it is now serialized. 14362306a36Sopenharmony_ci * Otherwise, there can be conflicts with existing ASL code that actually 14462306a36Sopenharmony_ci * uses sync levels. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci walk_state->method_desc->method.sync_level = 0; 14762306a36Sopenharmony_ci walk_state->method_desc->method.info_flags |= 14862306a36Sopenharmony_ci (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, 15162306a36Sopenharmony_ci "Method serialized [%4.4s] %p - [%s] (%4.4X)\n", 15262306a36Sopenharmony_ci walk_state->method_node->name.ascii, 15362306a36Sopenharmony_ci walk_state->method_node, walk_state->op_info->name, 15462306a36Sopenharmony_ci walk_state->opcode)); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Abort the parse, no need to examine this method any further */ 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return (AE_CTRL_TERMINATE); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/******************************************************************************* 16262306a36Sopenharmony_ci * 16362306a36Sopenharmony_ci * FUNCTION: acpi_ds_method_error 16462306a36Sopenharmony_ci * 16562306a36Sopenharmony_ci * PARAMETERS: status - Execution status 16662306a36Sopenharmony_ci * walk_state - Current state 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * RETURN: Status 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci * DESCRIPTION: Called on method error. Invoke the global exception handler if 17162306a36Sopenharmony_ci * present, dump the method data if the debugger is configured 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * Note: Allows the exception handler to change the status code 17462306a36Sopenharmony_ci * 17562306a36Sopenharmony_ci ******************************************************************************/ 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ciacpi_status 17862306a36Sopenharmony_ciacpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci u32 aml_offset; 18162306a36Sopenharmony_ci acpi_name name = 0; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci ACPI_FUNCTION_ENTRY(); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* Ignore AE_OK and control exception codes */ 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (ACPI_SUCCESS(status) || (status & AE_CODE_CONTROL)) { 18862306a36Sopenharmony_ci return (status); 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* Invoke the global exception handler */ 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (acpi_gbl_exception_handler) { 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Exit the interpreter, allow handler to execute methods */ 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci acpi_ex_exit_interpreter(); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* 20062306a36Sopenharmony_ci * Handler can map the exception code to anything it wants, including 20162306a36Sopenharmony_ci * AE_OK, in which case the executing method will not be aborted. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci aml_offset = (u32)ACPI_PTR_DIFF(walk_state->aml, 20462306a36Sopenharmony_ci walk_state->parser_state. 20562306a36Sopenharmony_ci aml_start); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (walk_state->method_node) { 20862306a36Sopenharmony_ci name = walk_state->method_node->name.integer; 20962306a36Sopenharmony_ci } else if (walk_state->deferred_node) { 21062306a36Sopenharmony_ci name = walk_state->deferred_node->name.integer; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci status = acpi_gbl_exception_handler(status, name, 21462306a36Sopenharmony_ci walk_state->opcode, 21562306a36Sopenharmony_ci aml_offset, NULL); 21662306a36Sopenharmony_ci acpi_ex_enter_interpreter(); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci acpi_ds_clear_implicit_return(walk_state); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 22262306a36Sopenharmony_ci acpi_ds_dump_method_stack(status, walk_state, walk_state->op); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* Display method locals/args if debugger is present */ 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci#ifdef ACPI_DEBUGGER 22762306a36Sopenharmony_ci acpi_db_dump_method_info(status, walk_state); 22862306a36Sopenharmony_ci#endif 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return (status); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/******************************************************************************* 23562306a36Sopenharmony_ci * 23662306a36Sopenharmony_ci * FUNCTION: acpi_ds_create_method_mutex 23762306a36Sopenharmony_ci * 23862306a36Sopenharmony_ci * PARAMETERS: obj_desc - The method object 23962306a36Sopenharmony_ci * 24062306a36Sopenharmony_ci * RETURN: Status 24162306a36Sopenharmony_ci * 24262306a36Sopenharmony_ci * DESCRIPTION: Create a mutex object for a serialized control method 24362306a36Sopenharmony_ci * 24462306a36Sopenharmony_ci ******************************************************************************/ 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic acpi_status 24762306a36Sopenharmony_ciacpi_ds_create_method_mutex(union acpi_operand_object *method_desc) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci union acpi_operand_object *mutex_desc; 25062306a36Sopenharmony_ci acpi_status status; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ds_create_method_mutex); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* Create the new mutex object */ 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci mutex_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX); 25762306a36Sopenharmony_ci if (!mutex_desc) { 25862306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* Create the actual OS Mutex */ 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci status = acpi_os_create_mutex(&mutex_desc->mutex.os_mutex); 26462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 26562306a36Sopenharmony_ci acpi_ut_delete_object_desc(mutex_desc); 26662306a36Sopenharmony_ci return_ACPI_STATUS(status); 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci mutex_desc->mutex.sync_level = method_desc->method.sync_level; 27062306a36Sopenharmony_ci method_desc->method.mutex = mutex_desc; 27162306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci/******************************************************************************* 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci * FUNCTION: acpi_ds_begin_method_execution 27762306a36Sopenharmony_ci * 27862306a36Sopenharmony_ci * PARAMETERS: method_node - Node of the method 27962306a36Sopenharmony_ci * obj_desc - The method object 28062306a36Sopenharmony_ci * walk_state - current state, NULL if not yet executing 28162306a36Sopenharmony_ci * a method. 28262306a36Sopenharmony_ci * 28362306a36Sopenharmony_ci * RETURN: Status 28462306a36Sopenharmony_ci * 28562306a36Sopenharmony_ci * DESCRIPTION: Prepare a method for execution. Parses the method if necessary, 28662306a36Sopenharmony_ci * increments the thread count, and waits at the method semaphore 28762306a36Sopenharmony_ci * for clearance to execute. 28862306a36Sopenharmony_ci * 28962306a36Sopenharmony_ci ******************************************************************************/ 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ciacpi_status 29262306a36Sopenharmony_ciacpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, 29362306a36Sopenharmony_ci union acpi_operand_object *obj_desc, 29462306a36Sopenharmony_ci struct acpi_walk_state *walk_state) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci acpi_status status = AE_OK; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (!method_node) { 30162306a36Sopenharmony_ci return_ACPI_STATUS(AE_NULL_ENTRY); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci acpi_ex_start_trace_method(method_node, obj_desc, walk_state); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* Prevent wraparound of thread count */ 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (obj_desc->method.thread_count == ACPI_UINT8_MAX) { 30962306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 31062306a36Sopenharmony_ci "Method reached maximum reentrancy limit (255)")); 31162306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_METHOD_LIMIT); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* 31562306a36Sopenharmony_ci * If this method is serialized, we need to acquire the method mutex. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_ci if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) { 31862306a36Sopenharmony_ci /* 31962306a36Sopenharmony_ci * Create a mutex for the method if it is defined to be Serialized 32062306a36Sopenharmony_ci * and a mutex has not already been created. We defer the mutex creation 32162306a36Sopenharmony_ci * until a method is actually executed, to minimize the object count 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci if (!obj_desc->method.mutex) { 32462306a36Sopenharmony_ci status = acpi_ds_create_method_mutex(obj_desc); 32562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 32662306a36Sopenharmony_ci return_ACPI_STATUS(status); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* 33162306a36Sopenharmony_ci * The current_sync_level (per-thread) must be less than or equal to 33262306a36Sopenharmony_ci * the sync level of the method. This mechanism provides some 33362306a36Sopenharmony_ci * deadlock prevention. 33462306a36Sopenharmony_ci * 33562306a36Sopenharmony_ci * If the method was auto-serialized, we just ignore the sync level 33662306a36Sopenharmony_ci * mechanism, because auto-serialization of methods can interfere 33762306a36Sopenharmony_ci * with ASL code that actually uses sync levels. 33862306a36Sopenharmony_ci * 33962306a36Sopenharmony_ci * Top-level method invocation has no walk state at this point 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci if (walk_state && 34262306a36Sopenharmony_ci (!(obj_desc->method. 34362306a36Sopenharmony_ci info_flags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) 34462306a36Sopenharmony_ci && (walk_state->thread->current_sync_level > 34562306a36Sopenharmony_ci obj_desc->method.mutex->mutex.sync_level)) { 34662306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 34762306a36Sopenharmony_ci "Cannot acquire Mutex for method [%4.4s]" 34862306a36Sopenharmony_ci ", current SyncLevel is too large (%u)", 34962306a36Sopenharmony_ci acpi_ut_get_node_name(method_node), 35062306a36Sopenharmony_ci walk_state->thread->current_sync_level)); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_MUTEX_ORDER); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* 35662306a36Sopenharmony_ci * Obtain the method mutex if necessary. Do not acquire mutex for a 35762306a36Sopenharmony_ci * recursive call. 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci if (!walk_state || 36062306a36Sopenharmony_ci !obj_desc->method.mutex->mutex.thread_id || 36162306a36Sopenharmony_ci (walk_state->thread->thread_id != 36262306a36Sopenharmony_ci obj_desc->method.mutex->mutex.thread_id)) { 36362306a36Sopenharmony_ci /* 36462306a36Sopenharmony_ci * Acquire the method mutex. This releases the interpreter if we 36562306a36Sopenharmony_ci * block (and reacquires it before it returns) 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ci status = 36862306a36Sopenharmony_ci acpi_ex_system_wait_mutex(obj_desc->method.mutex-> 36962306a36Sopenharmony_ci mutex.os_mutex, 37062306a36Sopenharmony_ci ACPI_WAIT_FOREVER); 37162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 37262306a36Sopenharmony_ci return_ACPI_STATUS(status); 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* Update the mutex and walk info and save the original sync_level */ 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (walk_state) { 37862306a36Sopenharmony_ci obj_desc->method.mutex->mutex. 37962306a36Sopenharmony_ci original_sync_level = 38062306a36Sopenharmony_ci walk_state->thread->current_sync_level; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci obj_desc->method.mutex->mutex.thread_id = 38362306a36Sopenharmony_ci walk_state->thread->thread_id; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* 38662306a36Sopenharmony_ci * Update the current sync_level only if this is not an auto- 38762306a36Sopenharmony_ci * serialized method. In the auto case, we have to ignore 38862306a36Sopenharmony_ci * the sync level for the method mutex (created for the 38962306a36Sopenharmony_ci * auto-serialization) because we have no idea of what the 39062306a36Sopenharmony_ci * sync level should be. Therefore, just ignore it. 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_ci if (!(obj_desc->method.info_flags & 39362306a36Sopenharmony_ci ACPI_METHOD_IGNORE_SYNC_LEVEL)) { 39462306a36Sopenharmony_ci walk_state->thread->current_sync_level = 39562306a36Sopenharmony_ci obj_desc->method.sync_level; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci } else { 39862306a36Sopenharmony_ci obj_desc->method.mutex->mutex. 39962306a36Sopenharmony_ci original_sync_level = 40062306a36Sopenharmony_ci obj_desc->method.mutex->mutex.sync_level; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci obj_desc->method.mutex->mutex.thread_id = 40362306a36Sopenharmony_ci acpi_os_get_thread_id(); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* Always increase acquisition depth */ 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci obj_desc->method.mutex->mutex.acquisition_depth++; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* 41362306a36Sopenharmony_ci * Allocate an Owner ID for this method, only if this is the first thread 41462306a36Sopenharmony_ci * to begin concurrent execution. We only need one owner_id, even if the 41562306a36Sopenharmony_ci * method is invoked recursively. 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_ci if (!obj_desc->method.owner_id) { 41862306a36Sopenharmony_ci status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id); 41962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 42062306a36Sopenharmony_ci goto cleanup; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* 42562306a36Sopenharmony_ci * Increment the method parse tree thread count since it has been 42662306a36Sopenharmony_ci * reentered one more time (even if it is the same thread) 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ci obj_desc->method.thread_count++; 42962306a36Sopenharmony_ci acpi_method_count++; 43062306a36Sopenharmony_ci return_ACPI_STATUS(status); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cicleanup: 43362306a36Sopenharmony_ci /* On error, must release the method mutex (if present) */ 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (obj_desc->method.mutex) { 43662306a36Sopenharmony_ci acpi_os_release_mutex(obj_desc->method.mutex->mutex.os_mutex); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci return_ACPI_STATUS(status); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/******************************************************************************* 44262306a36Sopenharmony_ci * 44362306a36Sopenharmony_ci * FUNCTION: acpi_ds_call_control_method 44462306a36Sopenharmony_ci * 44562306a36Sopenharmony_ci * PARAMETERS: thread - Info for this thread 44662306a36Sopenharmony_ci * this_walk_state - Current walk state 44762306a36Sopenharmony_ci * op - Current Op to be walked 44862306a36Sopenharmony_ci * 44962306a36Sopenharmony_ci * RETURN: Status 45062306a36Sopenharmony_ci * 45162306a36Sopenharmony_ci * DESCRIPTION: Transfer execution to a called control method 45262306a36Sopenharmony_ci * 45362306a36Sopenharmony_ci ******************************************************************************/ 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ciacpi_status 45662306a36Sopenharmony_ciacpi_ds_call_control_method(struct acpi_thread_state *thread, 45762306a36Sopenharmony_ci struct acpi_walk_state *this_walk_state, 45862306a36Sopenharmony_ci union acpi_parse_object *op) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci acpi_status status; 46162306a36Sopenharmony_ci struct acpi_namespace_node *method_node; 46262306a36Sopenharmony_ci struct acpi_walk_state *next_walk_state = NULL; 46362306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 46462306a36Sopenharmony_ci struct acpi_evaluate_info *info; 46562306a36Sopenharmony_ci u32 i; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, 47062306a36Sopenharmony_ci "Calling method %p, currentstate=%p\n", 47162306a36Sopenharmony_ci this_walk_state->prev_op, this_walk_state)); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* 47462306a36Sopenharmony_ci * Get the namespace entry for the control method we are about to call 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_ci method_node = this_walk_state->method_call_node; 47762306a36Sopenharmony_ci if (!method_node) { 47862306a36Sopenharmony_ci return_ACPI_STATUS(AE_NULL_ENTRY); 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci obj_desc = acpi_ns_get_attached_object(method_node); 48262306a36Sopenharmony_ci if (!obj_desc) { 48362306a36Sopenharmony_ci return_ACPI_STATUS(AE_NULL_OBJECT); 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* Init for new method, possibly wait on method mutex */ 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci status = 48962306a36Sopenharmony_ci acpi_ds_begin_method_execution(method_node, obj_desc, 49062306a36Sopenharmony_ci this_walk_state); 49162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 49262306a36Sopenharmony_ci return_ACPI_STATUS(status); 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci /* Begin method parse/execution. Create a new walk state */ 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci next_walk_state = 49862306a36Sopenharmony_ci acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, obj_desc, 49962306a36Sopenharmony_ci thread); 50062306a36Sopenharmony_ci if (!next_walk_state) { 50162306a36Sopenharmony_ci status = AE_NO_MEMORY; 50262306a36Sopenharmony_ci goto cleanup; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* 50662306a36Sopenharmony_ci * The resolved arguments were put on the previous walk state's operand 50762306a36Sopenharmony_ci * stack. Operands on the previous walk state stack always 50862306a36Sopenharmony_ci * start at index 0. Also, null terminate the list of arguments 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_ci this_walk_state->operands[this_walk_state->num_operands] = NULL; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci /* 51362306a36Sopenharmony_ci * Allocate and initialize the evaluation information block 51462306a36Sopenharmony_ci * TBD: this is somewhat inefficient, should change interface to 51562306a36Sopenharmony_ci * ds_init_aml_walk. For now, keeps this struct off the CPU stack 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_ci info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); 51862306a36Sopenharmony_ci if (!info) { 51962306a36Sopenharmony_ci status = AE_NO_MEMORY; 52062306a36Sopenharmony_ci goto pop_walk_state; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci info->parameters = &this_walk_state->operands[0]; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node, 52662306a36Sopenharmony_ci obj_desc->method.aml_start, 52762306a36Sopenharmony_ci obj_desc->method.aml_length, info, 52862306a36Sopenharmony_ci ACPI_IMODE_EXECUTE); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci ACPI_FREE(info); 53162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 53262306a36Sopenharmony_ci goto pop_walk_state; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci next_walk_state->method_nesting_depth = 53662306a36Sopenharmony_ci this_walk_state->method_nesting_depth + 1; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* 53962306a36Sopenharmony_ci * Delete the operands on the previous walkstate operand stack 54062306a36Sopenharmony_ci * (they were copied to new objects) 54162306a36Sopenharmony_ci */ 54262306a36Sopenharmony_ci for (i = 0; i < obj_desc->method.param_count; i++) { 54362306a36Sopenharmony_ci acpi_ut_remove_reference(this_walk_state->operands[i]); 54462306a36Sopenharmony_ci this_walk_state->operands[i] = NULL; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Clear the operand stack */ 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci this_walk_state->num_operands = 0; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, 55262306a36Sopenharmony_ci "**** Begin nested execution of [%4.4s] **** WalkState=%p\n", 55362306a36Sopenharmony_ci method_node->name.ascii, next_walk_state)); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci this_walk_state->method_pathname = 55662306a36Sopenharmony_ci acpi_ns_get_normalized_pathname(method_node, TRUE); 55762306a36Sopenharmony_ci this_walk_state->method_is_nested = TRUE; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* Optional object evaluation log */ 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION, 56262306a36Sopenharmony_ci "%-26s: %*s%s\n", " Nested method call", 56362306a36Sopenharmony_ci next_walk_state->method_nesting_depth * 3, " ", 56462306a36Sopenharmony_ci &this_walk_state->method_pathname[1])); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* Invoke an internal method if necessary */ 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) { 56962306a36Sopenharmony_ci status = 57062306a36Sopenharmony_ci obj_desc->method.dispatch.implementation(next_walk_state); 57162306a36Sopenharmony_ci if (status == AE_OK) { 57262306a36Sopenharmony_ci status = AE_CTRL_TERMINATE; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci return_ACPI_STATUS(status); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cipop_walk_state: 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* On error, pop the walk state to be deleted from thread */ 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci acpi_ds_pop_walk_state(thread); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cicleanup: 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* On error, we must terminate the method properly */ 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci acpi_ds_terminate_control_method(obj_desc, next_walk_state); 58962306a36Sopenharmony_ci acpi_ds_delete_walk_state(next_walk_state); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci return_ACPI_STATUS(status); 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci/******************************************************************************* 59562306a36Sopenharmony_ci * 59662306a36Sopenharmony_ci * FUNCTION: acpi_ds_restart_control_method 59762306a36Sopenharmony_ci * 59862306a36Sopenharmony_ci * PARAMETERS: walk_state - State for preempted method (caller) 59962306a36Sopenharmony_ci * return_desc - Return value from the called method 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * RETURN: Status 60262306a36Sopenharmony_ci * 60362306a36Sopenharmony_ci * DESCRIPTION: Restart a method that was preempted by another (nested) method 60462306a36Sopenharmony_ci * invocation. Handle the return value (if any) from the callee. 60562306a36Sopenharmony_ci * 60662306a36Sopenharmony_ci ******************************************************************************/ 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ciacpi_status 60962306a36Sopenharmony_ciacpi_ds_restart_control_method(struct acpi_walk_state *walk_state, 61062306a36Sopenharmony_ci union acpi_operand_object *return_desc) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci acpi_status status; 61362306a36Sopenharmony_ci int same_as_implicit_return; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, 61862306a36Sopenharmony_ci "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", 61962306a36Sopenharmony_ci acpi_ut_get_node_name(walk_state->method_node), 62062306a36Sopenharmony_ci walk_state->method_call_op, return_desc)); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, 62362306a36Sopenharmony_ci " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", 62462306a36Sopenharmony_ci walk_state->return_used, 62562306a36Sopenharmony_ci walk_state->results, walk_state)); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* Did the called method return a value? */ 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (return_desc) { 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* Is the implicit return object the same as the return desc? */ 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci same_as_implicit_return = 63462306a36Sopenharmony_ci (walk_state->implicit_return_obj == return_desc); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci /* Are we actually going to use the return value? */ 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (walk_state->return_used) { 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* Save the return value from the previous method */ 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci status = acpi_ds_result_push(return_desc, walk_state); 64362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 64462306a36Sopenharmony_ci acpi_ut_remove_reference(return_desc); 64562306a36Sopenharmony_ci return_ACPI_STATUS(status); 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* 64962306a36Sopenharmony_ci * Save as THIS method's return value in case it is returned 65062306a36Sopenharmony_ci * immediately to yet another method 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_ci walk_state->return_desc = return_desc; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci /* 65662306a36Sopenharmony_ci * The following code is the optional support for the so-called 65762306a36Sopenharmony_ci * "implicit return". Some AML code assumes that the last value of the 65862306a36Sopenharmony_ci * method is "implicitly" returned to the caller, in the absence of an 65962306a36Sopenharmony_ci * explicit return value. 66062306a36Sopenharmony_ci * 66162306a36Sopenharmony_ci * Just save the last result of the method as the return value. 66262306a36Sopenharmony_ci * 66362306a36Sopenharmony_ci * NOTE: this is optional because the ASL language does not actually 66462306a36Sopenharmony_ci * support this behavior. 66562306a36Sopenharmony_ci */ 66662306a36Sopenharmony_ci else if (!acpi_ds_do_implicit_return 66762306a36Sopenharmony_ci (return_desc, walk_state, FALSE) 66862306a36Sopenharmony_ci || same_as_implicit_return) { 66962306a36Sopenharmony_ci /* 67062306a36Sopenharmony_ci * Delete the return value if it will not be used by the 67162306a36Sopenharmony_ci * calling method or remove one reference if the explicit return 67262306a36Sopenharmony_ci * is the same as the implicit return value. 67362306a36Sopenharmony_ci */ 67462306a36Sopenharmony_ci acpi_ut_remove_reference(return_desc); 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci/******************************************************************************* 68262306a36Sopenharmony_ci * 68362306a36Sopenharmony_ci * FUNCTION: acpi_ds_terminate_control_method 68462306a36Sopenharmony_ci * 68562306a36Sopenharmony_ci * PARAMETERS: method_desc - Method object 68662306a36Sopenharmony_ci * walk_state - State associated with the method 68762306a36Sopenharmony_ci * 68862306a36Sopenharmony_ci * RETURN: None 68962306a36Sopenharmony_ci * 69062306a36Sopenharmony_ci * DESCRIPTION: Terminate a control method. Delete everything that the method 69162306a36Sopenharmony_ci * created, delete all locals and arguments, and delete the parse 69262306a36Sopenharmony_ci * tree if requested. 69362306a36Sopenharmony_ci * 69462306a36Sopenharmony_ci * MUTEX: Interpreter is locked 69562306a36Sopenharmony_ci * 69662306a36Sopenharmony_ci ******************************************************************************/ 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_civoid 69962306a36Sopenharmony_ciacpi_ds_terminate_control_method(union acpi_operand_object *method_desc, 70062306a36Sopenharmony_ci struct acpi_walk_state *walk_state) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* method_desc is required, walk_state is optional */ 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (!method_desc) { 70862306a36Sopenharmony_ci return_VOID; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (walk_state) { 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* Delete all arguments and locals */ 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci acpi_ds_method_data_delete_all(walk_state); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci /* 71862306a36Sopenharmony_ci * Delete any namespace objects created anywhere within the 71962306a36Sopenharmony_ci * namespace by the execution of this method. Unless: 72062306a36Sopenharmony_ci * 1) This method is a module-level executable code method, in which 72162306a36Sopenharmony_ci * case we want make the objects permanent. 72262306a36Sopenharmony_ci * 2) There are other threads executing the method, in which case we 72362306a36Sopenharmony_ci * will wait until the last thread has completed. 72462306a36Sopenharmony_ci */ 72562306a36Sopenharmony_ci if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) 72662306a36Sopenharmony_ci && (method_desc->method.thread_count == 1)) { 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* Delete any direct children of (created by) this method */ 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci (void)acpi_ex_exit_interpreter(); 73162306a36Sopenharmony_ci acpi_ns_delete_namespace_subtree(walk_state-> 73262306a36Sopenharmony_ci method_node); 73362306a36Sopenharmony_ci (void)acpi_ex_enter_interpreter(); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* 73662306a36Sopenharmony_ci * Delete any objects that were created by this method 73762306a36Sopenharmony_ci * elsewhere in the namespace (if any were created). 73862306a36Sopenharmony_ci * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the 73962306a36Sopenharmony_ci * deletion such that we don't have to perform an entire 74062306a36Sopenharmony_ci * namespace walk for every control method execution. 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_ci if (method_desc->method. 74362306a36Sopenharmony_ci info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) { 74462306a36Sopenharmony_ci (void)acpi_ex_exit_interpreter(); 74562306a36Sopenharmony_ci acpi_ns_delete_namespace_by_owner(method_desc-> 74662306a36Sopenharmony_ci method. 74762306a36Sopenharmony_ci owner_id); 74862306a36Sopenharmony_ci (void)acpi_ex_enter_interpreter(); 74962306a36Sopenharmony_ci method_desc->method.info_flags &= 75062306a36Sopenharmony_ci ~ACPI_METHOD_MODIFIED_NAMESPACE; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* 75562306a36Sopenharmony_ci * If method is serialized, release the mutex and restore the 75662306a36Sopenharmony_ci * current sync level for this thread 75762306a36Sopenharmony_ci */ 75862306a36Sopenharmony_ci if (method_desc->method.mutex) { 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* Acquisition Depth handles recursive calls */ 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci method_desc->method.mutex->mutex.acquisition_depth--; 76362306a36Sopenharmony_ci if (!method_desc->method.mutex->mutex.acquisition_depth) { 76462306a36Sopenharmony_ci walk_state->thread->current_sync_level = 76562306a36Sopenharmony_ci method_desc->method.mutex->mutex. 76662306a36Sopenharmony_ci original_sync_level; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci acpi_os_release_mutex(method_desc->method. 76962306a36Sopenharmony_ci mutex->mutex.os_mutex); 77062306a36Sopenharmony_ci method_desc->method.mutex->mutex.thread_id = 0; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci /* Decrement the thread count on the method */ 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (method_desc->method.thread_count) { 77862306a36Sopenharmony_ci method_desc->method.thread_count--; 77962306a36Sopenharmony_ci } else { 78062306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Invalid zero thread count in method")); 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci /* Are there any other threads currently executing this method? */ 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (method_desc->method.thread_count) { 78662306a36Sopenharmony_ci /* 78762306a36Sopenharmony_ci * Additional threads. Do not release the owner_id in this case, 78862306a36Sopenharmony_ci * we immediately reuse it for the next thread executing this method 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, 79162306a36Sopenharmony_ci "*** Completed execution of one thread, %u threads remaining\n", 79262306a36Sopenharmony_ci method_desc->method.thread_count)); 79362306a36Sopenharmony_ci } else { 79462306a36Sopenharmony_ci /* This is the only executing thread for this method */ 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci /* 79762306a36Sopenharmony_ci * Support to dynamically change a method from not_serialized to 79862306a36Sopenharmony_ci * Serialized if it appears that the method is incorrectly written and 79962306a36Sopenharmony_ci * does not support multiple thread execution. The best example of this 80062306a36Sopenharmony_ci * is if such a method creates namespace objects and blocks. A second 80162306a36Sopenharmony_ci * thread will fail with an AE_ALREADY_EXISTS exception. 80262306a36Sopenharmony_ci * 80362306a36Sopenharmony_ci * This code is here because we must wait until the last thread exits 80462306a36Sopenharmony_ci * before marking the method as serialized. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_ci if (method_desc->method. 80762306a36Sopenharmony_ci info_flags & ACPI_METHOD_SERIALIZED_PENDING) { 80862306a36Sopenharmony_ci if (walk_state) { 80962306a36Sopenharmony_ci ACPI_INFO(("Marking method %4.4s as Serialized " 81062306a36Sopenharmony_ci "because of AE_ALREADY_EXISTS error", 81162306a36Sopenharmony_ci walk_state->method_node->name. 81262306a36Sopenharmony_ci ascii)); 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci /* 81662306a36Sopenharmony_ci * Method tried to create an object twice and was marked as 81762306a36Sopenharmony_ci * "pending serialized". The probable cause is that the method 81862306a36Sopenharmony_ci * cannot handle reentrancy. 81962306a36Sopenharmony_ci * 82062306a36Sopenharmony_ci * The method was created as not_serialized, but it tried to create 82162306a36Sopenharmony_ci * a named object and then blocked, causing the second thread 82262306a36Sopenharmony_ci * entrance to begin and then fail. Workaround this problem by 82362306a36Sopenharmony_ci * marking the method permanently as Serialized when the last 82462306a36Sopenharmony_ci * thread exits here. 82562306a36Sopenharmony_ci */ 82662306a36Sopenharmony_ci method_desc->method.info_flags &= 82762306a36Sopenharmony_ci ~ACPI_METHOD_SERIALIZED_PENDING; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci method_desc->method.info_flags |= 83062306a36Sopenharmony_ci (ACPI_METHOD_SERIALIZED | 83162306a36Sopenharmony_ci ACPI_METHOD_IGNORE_SYNC_LEVEL); 83262306a36Sopenharmony_ci method_desc->method.sync_level = 0; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci /* No more threads, we can free the owner_id */ 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (! 83862306a36Sopenharmony_ci (method_desc->method. 83962306a36Sopenharmony_ci info_flags & ACPI_METHOD_MODULE_LEVEL)) { 84062306a36Sopenharmony_ci acpi_ut_release_owner_id(&method_desc->method.owner_id); 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci acpi_ex_stop_trace_method((struct acpi_namespace_node *)method_desc-> 84562306a36Sopenharmony_ci method.node, method_desc, walk_state); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci return_VOID; 84862306a36Sopenharmony_ci} 849