162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: exmutex - ASL Mutex Acquire/Release functions 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 "acinterp.h" 1362306a36Sopenharmony_ci#include "acevents.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define _COMPONENT ACPI_EXECUTER 1662306a36Sopenharmony_ciACPI_MODULE_NAME("exmutex") 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* Local prototypes */ 1962306a36Sopenharmony_cistatic void 2062306a36Sopenharmony_ciacpi_ex_link_mutex(union acpi_operand_object *obj_desc, 2162306a36Sopenharmony_ci struct acpi_thread_state *thread); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/******************************************************************************* 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * FUNCTION: acpi_ex_unlink_mutex 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * PARAMETERS: obj_desc - The mutex to be unlinked 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * RETURN: None 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci ******************************************************************************/ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_civoid acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct acpi_thread_state *thread = obj_desc->mutex.owner_thread; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (!thread) { 4062306a36Sopenharmony_ci return; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* Doubly linked list */ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (obj_desc->mutex.next) { 4662306a36Sopenharmony_ci (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (obj_desc->mutex.prev) { 5062306a36Sopenharmony_ci (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* 5362306a36Sopenharmony_ci * Migrate the previous sync level associated with this mutex to 5462306a36Sopenharmony_ci * the previous mutex on the list so that it may be preserved. 5562306a36Sopenharmony_ci * This handles the case where several mutexes have been acquired 5662306a36Sopenharmony_ci * at the same level, but are not released in opposite order. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci (obj_desc->mutex.prev)->mutex.original_sync_level = 5962306a36Sopenharmony_ci obj_desc->mutex.original_sync_level; 6062306a36Sopenharmony_ci } else { 6162306a36Sopenharmony_ci thread->acquired_mutex_list = obj_desc->mutex.next; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/******************************************************************************* 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * FUNCTION: acpi_ex_link_mutex 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * PARAMETERS: obj_desc - The mutex to be linked 7062306a36Sopenharmony_ci * thread - Current executing thread object 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * RETURN: None 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci ******************************************************************************/ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic void 7962306a36Sopenharmony_ciacpi_ex_link_mutex(union acpi_operand_object *obj_desc, 8062306a36Sopenharmony_ci struct acpi_thread_state *thread) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci union acpi_operand_object *list_head; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci list_head = thread->acquired_mutex_list; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* This object will be the first object in the list */ 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci obj_desc->mutex.prev = NULL; 8962306a36Sopenharmony_ci obj_desc->mutex.next = list_head; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* Update old first object to point back to this object */ 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (list_head) { 9462306a36Sopenharmony_ci list_head->mutex.prev = obj_desc; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* Update list head */ 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci thread->acquired_mutex_list = obj_desc; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/******************************************************************************* 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * FUNCTION: acpi_ex_acquire_mutex_object 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * PARAMETERS: timeout - Timeout in milliseconds 10762306a36Sopenharmony_ci * obj_desc - Mutex object 10862306a36Sopenharmony_ci * thread_id - Current thread state 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * RETURN: Status 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common 11362306a36Sopenharmony_ci * path that supports multiple acquires by the same thread. 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * MUTEX: Interpreter must be locked 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * NOTE: This interface is called from three places: 11862306a36Sopenharmony_ci * 1) From acpi_ex_acquire_mutex, via an AML Acquire() operator 11962306a36Sopenharmony_ci * 2) From acpi_ex_acquire_global_lock when an AML Field access requires the 12062306a36Sopenharmony_ci * global lock 12162306a36Sopenharmony_ci * 3) From the external interface, acpi_acquire_global_lock 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci ******************************************************************************/ 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ciacpi_status 12662306a36Sopenharmony_ciacpi_ex_acquire_mutex_object(u16 timeout, 12762306a36Sopenharmony_ci union acpi_operand_object *obj_desc, 12862306a36Sopenharmony_ci acpi_thread_id thread_id) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci acpi_status status; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex_object, obj_desc); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (!obj_desc) { 13562306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* Support for multiple acquires by the owning thread */ 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (obj_desc->mutex.thread_id == thread_id) { 14162306a36Sopenharmony_ci /* 14262306a36Sopenharmony_ci * The mutex is already owned by this thread, just increment the 14362306a36Sopenharmony_ci * acquisition depth 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci obj_desc->mutex.acquisition_depth++; 14662306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* Acquire the mutex, wait if necessary. Special case for Global Lock */ 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (obj_desc == acpi_gbl_global_lock_mutex) { 15262306a36Sopenharmony_ci status = acpi_ev_acquire_global_lock(timeout); 15362306a36Sopenharmony_ci } else { 15462306a36Sopenharmony_ci status = 15562306a36Sopenharmony_ci acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex, 15662306a36Sopenharmony_ci timeout); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Includes failure from a timeout on time_desc */ 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return_ACPI_STATUS(status); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* Acquired the mutex: update mutex object */ 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci obj_desc->mutex.thread_id = thread_id; 16962306a36Sopenharmony_ci obj_desc->mutex.acquisition_depth = 1; 17062306a36Sopenharmony_ci obj_desc->mutex.original_sync_level = 0; 17162306a36Sopenharmony_ci obj_desc->mutex.owner_thread = NULL; /* Used only for AML Acquire() */ 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/******************************************************************************* 17762306a36Sopenharmony_ci * 17862306a36Sopenharmony_ci * FUNCTION: acpi_ex_acquire_mutex 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * PARAMETERS: time_desc - Timeout integer 18162306a36Sopenharmony_ci * obj_desc - Mutex object 18262306a36Sopenharmony_ci * walk_state - Current method execution state 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci * RETURN: Status 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * DESCRIPTION: Acquire an AML mutex 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci ******************************************************************************/ 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ciacpi_status 19162306a36Sopenharmony_ciacpi_ex_acquire_mutex(union acpi_operand_object *time_desc, 19262306a36Sopenharmony_ci union acpi_operand_object *obj_desc, 19362306a36Sopenharmony_ci struct acpi_walk_state *walk_state) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci acpi_status status; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex, obj_desc); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (!obj_desc) { 20062306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Must have a valid thread state struct */ 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (!walk_state->thread) { 20662306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 20762306a36Sopenharmony_ci "Cannot acquire Mutex [%4.4s], null thread info", 20862306a36Sopenharmony_ci acpi_ut_get_node_name(obj_desc->mutex.node))); 20962306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_INTERNAL); 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* 21362306a36Sopenharmony_ci * Current sync level must be less than or equal to the sync level 21462306a36Sopenharmony_ci * of the mutex. This mechanism provides some deadlock prevention. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) { 21762306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 21862306a36Sopenharmony_ci "Cannot acquire Mutex [%4.4s], " 21962306a36Sopenharmony_ci "current SyncLevel is too large (%u)", 22062306a36Sopenharmony_ci acpi_ut_get_node_name(obj_desc->mutex.node), 22162306a36Sopenharmony_ci walk_state->thread->current_sync_level)); 22262306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_MUTEX_ORDER); 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 22662306a36Sopenharmony_ci "Acquiring: Mutex SyncLevel %u, Thread SyncLevel %u, " 22762306a36Sopenharmony_ci "Depth %u TID %p\n", 22862306a36Sopenharmony_ci obj_desc->mutex.sync_level, 22962306a36Sopenharmony_ci walk_state->thread->current_sync_level, 23062306a36Sopenharmony_ci obj_desc->mutex.acquisition_depth, 23162306a36Sopenharmony_ci walk_state->thread)); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci status = acpi_ex_acquire_mutex_object((u16)time_desc->integer.value, 23462306a36Sopenharmony_ci obj_desc, 23562306a36Sopenharmony_ci walk_state->thread->thread_id); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (ACPI_SUCCESS(status) && obj_desc->mutex.acquisition_depth == 1) { 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* Save Thread object, original/current sync levels */ 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci obj_desc->mutex.owner_thread = walk_state->thread; 24262306a36Sopenharmony_ci obj_desc->mutex.original_sync_level = 24362306a36Sopenharmony_ci walk_state->thread->current_sync_level; 24462306a36Sopenharmony_ci walk_state->thread->current_sync_level = 24562306a36Sopenharmony_ci obj_desc->mutex.sync_level; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* Link the mutex to the current thread for force-unlock at method exit */ 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci acpi_ex_link_mutex(obj_desc, walk_state->thread); 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 25362306a36Sopenharmony_ci "Acquired: Mutex SyncLevel %u, Thread SyncLevel %u, Depth %u\n", 25462306a36Sopenharmony_ci obj_desc->mutex.sync_level, 25562306a36Sopenharmony_ci walk_state->thread->current_sync_level, 25662306a36Sopenharmony_ci obj_desc->mutex.acquisition_depth)); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return_ACPI_STATUS(status); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/******************************************************************************* 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * FUNCTION: acpi_ex_release_mutex_object 26462306a36Sopenharmony_ci * 26562306a36Sopenharmony_ci * PARAMETERS: obj_desc - The object descriptor for this op 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * RETURN: Status 26862306a36Sopenharmony_ci * 26962306a36Sopenharmony_ci * DESCRIPTION: Release a previously acquired Mutex, low level interface. 27062306a36Sopenharmony_ci * Provides a common path that supports multiple releases (after 27162306a36Sopenharmony_ci * previous multiple acquires) by the same thread. 27262306a36Sopenharmony_ci * 27362306a36Sopenharmony_ci * MUTEX: Interpreter must be locked 27462306a36Sopenharmony_ci * 27562306a36Sopenharmony_ci * NOTE: This interface is called from three places: 27662306a36Sopenharmony_ci * 1) From acpi_ex_release_mutex, via an AML Acquire() operator 27762306a36Sopenharmony_ci * 2) From acpi_ex_release_global_lock when an AML Field access requires the 27862306a36Sopenharmony_ci * global lock 27962306a36Sopenharmony_ci * 3) From the external interface, acpi_release_global_lock 28062306a36Sopenharmony_ci * 28162306a36Sopenharmony_ci ******************************************************************************/ 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ciacpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci acpi_status status = AE_OK; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ex_release_mutex_object); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (obj_desc->mutex.acquisition_depth == 0) { 29062306a36Sopenharmony_ci return_ACPI_STATUS(AE_NOT_ACQUIRED); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* Match multiple Acquires with multiple Releases */ 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci obj_desc->mutex.acquisition_depth--; 29662306a36Sopenharmony_ci if (obj_desc->mutex.acquisition_depth != 0) { 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* Just decrement the depth and return */ 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (obj_desc->mutex.owner_thread) { 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* Unlink the mutex from the owner's list */ 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci acpi_ex_unlink_mutex(obj_desc); 30862306a36Sopenharmony_ci obj_desc->mutex.owner_thread = NULL; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* Release the mutex, special case for Global Lock */ 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (obj_desc == acpi_gbl_global_lock_mutex) { 31462306a36Sopenharmony_ci status = acpi_ev_release_global_lock(); 31562306a36Sopenharmony_ci } else { 31662306a36Sopenharmony_ci acpi_os_release_mutex(obj_desc->mutex.os_mutex); 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Clear mutex info */ 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci obj_desc->mutex.thread_id = 0; 32262306a36Sopenharmony_ci return_ACPI_STATUS(status); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci/******************************************************************************* 32662306a36Sopenharmony_ci * 32762306a36Sopenharmony_ci * FUNCTION: acpi_ex_release_mutex 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * PARAMETERS: obj_desc - The object descriptor for this op 33062306a36Sopenharmony_ci * walk_state - Current method execution state 33162306a36Sopenharmony_ci * 33262306a36Sopenharmony_ci * RETURN: Status 33362306a36Sopenharmony_ci * 33462306a36Sopenharmony_ci * DESCRIPTION: Release a previously acquired Mutex. 33562306a36Sopenharmony_ci * 33662306a36Sopenharmony_ci ******************************************************************************/ 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ciacpi_status 33962306a36Sopenharmony_ciacpi_ex_release_mutex(union acpi_operand_object *obj_desc, 34062306a36Sopenharmony_ci struct acpi_walk_state *walk_state) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci u8 previous_sync_level; 34362306a36Sopenharmony_ci struct acpi_thread_state *owner_thread; 34462306a36Sopenharmony_ci acpi_status status = AE_OK; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ex_release_mutex); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (!obj_desc) { 34962306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci owner_thread = obj_desc->mutex.owner_thread; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* The mutex must have been previously acquired in order to release it */ 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (!owner_thread) { 35762306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 35862306a36Sopenharmony_ci "Cannot release Mutex [%4.4s], not acquired", 35962306a36Sopenharmony_ci acpi_ut_get_node_name(obj_desc->mutex.node))); 36062306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* Must have a valid thread ID */ 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (!walk_state->thread) { 36662306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 36762306a36Sopenharmony_ci "Cannot release Mutex [%4.4s], null thread info", 36862306a36Sopenharmony_ci acpi_ut_get_node_name(obj_desc->mutex.node))); 36962306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_INTERNAL); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* 37362306a36Sopenharmony_ci * The Mutex is owned, but this thread must be the owner. 37462306a36Sopenharmony_ci * Special case for Global Lock, any thread can release 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_ci if ((owner_thread->thread_id != walk_state->thread->thread_id) && 37762306a36Sopenharmony_ci (obj_desc != acpi_gbl_global_lock_mutex)) { 37862306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 37962306a36Sopenharmony_ci "Thread %u cannot release Mutex [%4.4s] acquired by thread %u", 38062306a36Sopenharmony_ci (u32)walk_state->thread->thread_id, 38162306a36Sopenharmony_ci acpi_ut_get_node_name(obj_desc->mutex.node), 38262306a36Sopenharmony_ci (u32)owner_thread->thread_id)); 38362306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_NOT_OWNER); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* 38762306a36Sopenharmony_ci * The sync level of the mutex must be equal to the current sync level. In 38862306a36Sopenharmony_ci * other words, the current level means that at least one mutex at that 38962306a36Sopenharmony_ci * level is currently being held. Attempting to release a mutex of a 39062306a36Sopenharmony_ci * different level can only mean that the mutex ordering rule is being 39162306a36Sopenharmony_ci * violated. This behavior is clarified in ACPI 4.0 specification. 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_ci if (obj_desc->mutex.sync_level != owner_thread->current_sync_level) { 39462306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 39562306a36Sopenharmony_ci "Cannot release Mutex [%4.4s], SyncLevel mismatch: " 39662306a36Sopenharmony_ci "mutex %u current %u", 39762306a36Sopenharmony_ci acpi_ut_get_node_name(obj_desc->mutex.node), 39862306a36Sopenharmony_ci obj_desc->mutex.sync_level, 39962306a36Sopenharmony_ci walk_state->thread->current_sync_level)); 40062306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_MUTEX_ORDER); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* 40462306a36Sopenharmony_ci * Get the previous sync_level from the head of the acquired mutex list. 40562306a36Sopenharmony_ci * This handles the case where several mutexes at the same level have been 40662306a36Sopenharmony_ci * acquired, but are not released in reverse order. 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_ci previous_sync_level = 40962306a36Sopenharmony_ci owner_thread->acquired_mutex_list->mutex.original_sync_level; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 41262306a36Sopenharmony_ci "Releasing: Object SyncLevel %u, Thread SyncLevel %u, " 41362306a36Sopenharmony_ci "Prev SyncLevel %u, Depth %u TID %p\n", 41462306a36Sopenharmony_ci obj_desc->mutex.sync_level, 41562306a36Sopenharmony_ci walk_state->thread->current_sync_level, 41662306a36Sopenharmony_ci previous_sync_level, 41762306a36Sopenharmony_ci obj_desc->mutex.acquisition_depth, 41862306a36Sopenharmony_ci walk_state->thread)); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci status = acpi_ex_release_mutex_object(obj_desc); 42162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 42262306a36Sopenharmony_ci return_ACPI_STATUS(status); 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (obj_desc->mutex.acquisition_depth == 0) { 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* Restore the previous sync_level */ 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci owner_thread->current_sync_level = previous_sync_level; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 43362306a36Sopenharmony_ci "Released: Object SyncLevel %u, Thread SyncLevel, %u, " 43462306a36Sopenharmony_ci "Prev SyncLevel %u, Depth %u\n", 43562306a36Sopenharmony_ci obj_desc->mutex.sync_level, 43662306a36Sopenharmony_ci walk_state->thread->current_sync_level, 43762306a36Sopenharmony_ci previous_sync_level, 43862306a36Sopenharmony_ci obj_desc->mutex.acquisition_depth)); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return_ACPI_STATUS(status); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci/******************************************************************************* 44462306a36Sopenharmony_ci * 44562306a36Sopenharmony_ci * FUNCTION: acpi_ex_release_all_mutexes 44662306a36Sopenharmony_ci * 44762306a36Sopenharmony_ci * PARAMETERS: thread - Current executing thread object 44862306a36Sopenharmony_ci * 44962306a36Sopenharmony_ci * RETURN: Status 45062306a36Sopenharmony_ci * 45162306a36Sopenharmony_ci * DESCRIPTION: Release all mutexes held by this thread 45262306a36Sopenharmony_ci * 45362306a36Sopenharmony_ci * NOTE: This function is called as the thread is exiting the interpreter. 45462306a36Sopenharmony_ci * Mutexes are not released when an individual control method is exited, but 45562306a36Sopenharmony_ci * only when the parent thread actually exits the interpreter. This allows one 45662306a36Sopenharmony_ci * method to acquire a mutex, and a different method to release it, as long as 45762306a36Sopenharmony_ci * this is performed underneath a single parent control method. 45862306a36Sopenharmony_ci * 45962306a36Sopenharmony_ci ******************************************************************************/ 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_civoid acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci union acpi_operand_object *next = thread->acquired_mutex_list; 46462306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ex_release_all_mutexes); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* Traverse the list of owned mutexes, releasing each one */ 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci while (next) { 47162306a36Sopenharmony_ci obj_desc = next; 47262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 47362306a36Sopenharmony_ci "Mutex [%4.4s] force-release, SyncLevel %u Depth %u\n", 47462306a36Sopenharmony_ci obj_desc->mutex.node->name.ascii, 47562306a36Sopenharmony_ci obj_desc->mutex.sync_level, 47662306a36Sopenharmony_ci obj_desc->mutex.acquisition_depth)); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* Release the mutex, special case for Global Lock */ 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (obj_desc == acpi_gbl_global_lock_mutex) { 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* Ignore errors */ 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci (void)acpi_ev_release_global_lock(); 48562306a36Sopenharmony_ci } else { 48662306a36Sopenharmony_ci acpi_os_release_mutex(obj_desc->mutex.os_mutex); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* Update Thread sync_level (Last mutex is the important one) */ 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci thread->current_sync_level = 49262306a36Sopenharmony_ci obj_desc->mutex.original_sync_level; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* Mark mutex unowned */ 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci next = obj_desc->mutex.next; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci obj_desc->mutex.prev = NULL; 49962306a36Sopenharmony_ci obj_desc->mutex.next = NULL; 50062306a36Sopenharmony_ci obj_desc->mutex.acquisition_depth = 0; 50162306a36Sopenharmony_ci obj_desc->mutex.owner_thread = NULL; 50262306a36Sopenharmony_ci obj_desc->mutex.thread_id = 0; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci return_VOID; 50662306a36Sopenharmony_ci} 507