195b482a8SLen Brown /****************************************************************************** 295b482a8SLen Brown * 395b482a8SLen Brown * Module Name: exmutex - ASL Mutex Acquire/Release functions 495b482a8SLen Brown * 595b482a8SLen Brown *****************************************************************************/ 695b482a8SLen Brown 795b482a8SLen Brown /* 877848130SBob Moore * Copyright (C) 2000 - 2012, Intel Corp. 995b482a8SLen Brown * All rights reserved. 1095b482a8SLen Brown * 1195b482a8SLen Brown * Redistribution and use in source and binary forms, with or without 1295b482a8SLen Brown * modification, are permitted provided that the following conditions 1395b482a8SLen Brown * are met: 1495b482a8SLen Brown * 1. Redistributions of source code must retain the above copyright 1595b482a8SLen Brown * notice, this list of conditions, and the following disclaimer, 1695b482a8SLen Brown * without modification. 1795b482a8SLen Brown * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1895b482a8SLen Brown * substantially similar to the "NO WARRANTY" disclaimer below 1995b482a8SLen Brown * ("Disclaimer") and any redistribution must be conditioned upon 2095b482a8SLen Brown * including a substantially similar Disclaimer requirement for further 2195b482a8SLen Brown * binary redistribution. 2295b482a8SLen Brown * 3. Neither the names of the above-listed copyright holders nor the names 2395b482a8SLen Brown * of any contributors may be used to endorse or promote products derived 2495b482a8SLen Brown * from this software without specific prior written permission. 2595b482a8SLen Brown * 2695b482a8SLen Brown * Alternatively, this software may be distributed under the terms of the 2795b482a8SLen Brown * GNU General Public License ("GPL") version 2 as published by the Free 2895b482a8SLen Brown * Software Foundation. 2995b482a8SLen Brown * 3095b482a8SLen Brown * NO WARRANTY 3195b482a8SLen Brown * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3295b482a8SLen Brown * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3395b482a8SLen Brown * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3495b482a8SLen Brown * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3595b482a8SLen Brown * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3695b482a8SLen Brown * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3795b482a8SLen Brown * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3895b482a8SLen Brown * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3995b482a8SLen Brown * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4095b482a8SLen Brown * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4195b482a8SLen Brown * POSSIBILITY OF SUCH DAMAGES. 4295b482a8SLen Brown */ 4395b482a8SLen Brown 4495b482a8SLen Brown #include <acpi/acpi.h> 45e2f7a777SLen Brown #include "accommon.h" 46e2f7a777SLen Brown #include "acinterp.h" 47e2f7a777SLen Brown #include "acevents.h" 4895b482a8SLen Brown 4995b482a8SLen Brown #define _COMPONENT ACPI_EXECUTER 5095b482a8SLen Brown ACPI_MODULE_NAME("exmutex") 5195b482a8SLen Brown 5295b482a8SLen Brown /* Local prototypes */ 5395b482a8SLen Brown static void 5495b482a8SLen Brown acpi_ex_link_mutex(union acpi_operand_object *obj_desc, 5595b482a8SLen Brown struct acpi_thread_state *thread); 5695b482a8SLen Brown 5795b482a8SLen Brown /******************************************************************************* 5895b482a8SLen Brown * 5995b482a8SLen Brown * FUNCTION: acpi_ex_unlink_mutex 6095b482a8SLen Brown * 6195b482a8SLen Brown * PARAMETERS: obj_desc - The mutex to be unlinked 6295b482a8SLen Brown * 6395b482a8SLen Brown * RETURN: None 6495b482a8SLen Brown * 6595b482a8SLen Brown * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list 6695b482a8SLen Brown * 6795b482a8SLen Brown ******************************************************************************/ 6895b482a8SLen Brown 6995b482a8SLen Brown void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc) 7095b482a8SLen Brown { 7195b482a8SLen Brown struct acpi_thread_state *thread = obj_desc->mutex.owner_thread; 7295b482a8SLen Brown 7395b482a8SLen Brown if (!thread) { 7495b482a8SLen Brown return; 7595b482a8SLen Brown } 7695b482a8SLen Brown 7795b482a8SLen Brown /* Doubly linked list */ 7895b482a8SLen Brown 7995b482a8SLen Brown if (obj_desc->mutex.next) { 8095b482a8SLen Brown (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev; 8195b482a8SLen Brown } 8295b482a8SLen Brown 8395b482a8SLen Brown if (obj_desc->mutex.prev) { 8495b482a8SLen Brown (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next; 8510a3b461SBob Moore 8610a3b461SBob Moore /* 87a7499bc8SBob Moore * Migrate the previous sync level associated with this mutex to 88a7499bc8SBob Moore * the previous mutex on the list so that it may be preserved. 89a7499bc8SBob Moore * This handles the case where several mutexes have been acquired 90a7499bc8SBob Moore * at the same level, but are not released in opposite order. 9110a3b461SBob Moore */ 9210a3b461SBob Moore (obj_desc->mutex.prev)->mutex.original_sync_level = 9310a3b461SBob Moore obj_desc->mutex.original_sync_level; 9495b482a8SLen Brown } else { 9595b482a8SLen Brown thread->acquired_mutex_list = obj_desc->mutex.next; 9695b482a8SLen Brown } 9795b482a8SLen Brown } 9895b482a8SLen Brown 9995b482a8SLen Brown /******************************************************************************* 10095b482a8SLen Brown * 10195b482a8SLen Brown * FUNCTION: acpi_ex_link_mutex 10295b482a8SLen Brown * 10395b482a8SLen Brown * PARAMETERS: obj_desc - The mutex to be linked 104ba494beeSBob Moore * thread - Current executing thread object 10595b482a8SLen Brown * 10695b482a8SLen Brown * RETURN: None 10795b482a8SLen Brown * 10895b482a8SLen Brown * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk 10995b482a8SLen Brown * 11095b482a8SLen Brown ******************************************************************************/ 11195b482a8SLen Brown 11295b482a8SLen Brown static void 11395b482a8SLen Brown acpi_ex_link_mutex(union acpi_operand_object *obj_desc, 11495b482a8SLen Brown struct acpi_thread_state *thread) 11595b482a8SLen Brown { 11695b482a8SLen Brown union acpi_operand_object *list_head; 11795b482a8SLen Brown 11895b482a8SLen Brown list_head = thread->acquired_mutex_list; 11995b482a8SLen Brown 12095b482a8SLen Brown /* This object will be the first object in the list */ 12195b482a8SLen Brown 12295b482a8SLen Brown obj_desc->mutex.prev = NULL; 12395b482a8SLen Brown obj_desc->mutex.next = list_head; 12495b482a8SLen Brown 12595b482a8SLen Brown /* Update old first object to point back to this object */ 12695b482a8SLen Brown 12795b482a8SLen Brown if (list_head) { 12895b482a8SLen Brown list_head->mutex.prev = obj_desc; 12995b482a8SLen Brown } 13095b482a8SLen Brown 13195b482a8SLen Brown /* Update list head */ 13295b482a8SLen Brown 13395b482a8SLen Brown thread->acquired_mutex_list = obj_desc; 13495b482a8SLen Brown } 13595b482a8SLen Brown 13695b482a8SLen Brown /******************************************************************************* 13795b482a8SLen Brown * 13895b482a8SLen Brown * FUNCTION: acpi_ex_acquire_mutex_object 13995b482a8SLen Brown * 140ba494beeSBob Moore * PARAMETERS: timeout - Timeout in milliseconds 14195b482a8SLen Brown * obj_desc - Mutex object 142a7499bc8SBob Moore * thread_id - Current thread state 14395b482a8SLen Brown * 14495b482a8SLen Brown * RETURN: Status 14595b482a8SLen Brown * 14695b482a8SLen Brown * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common 14795b482a8SLen Brown * path that supports multiple acquires by the same thread. 14895b482a8SLen Brown * 14995b482a8SLen Brown * MUTEX: Interpreter must be locked 15095b482a8SLen Brown * 15195b482a8SLen Brown * NOTE: This interface is called from three places: 15295b482a8SLen Brown * 1) From acpi_ex_acquire_mutex, via an AML Acquire() operator 15395b482a8SLen Brown * 2) From acpi_ex_acquire_global_lock when an AML Field access requires the 15495b482a8SLen Brown * global lock 15595b482a8SLen Brown * 3) From the external interface, acpi_acquire_global_lock 15695b482a8SLen Brown * 15795b482a8SLen Brown ******************************************************************************/ 15895b482a8SLen Brown 15995b482a8SLen Brown acpi_status 16095b482a8SLen Brown acpi_ex_acquire_mutex_object(u16 timeout, 16195b482a8SLen Brown union acpi_operand_object *obj_desc, 16295b482a8SLen Brown acpi_thread_id thread_id) 16395b482a8SLen Brown { 16495b482a8SLen Brown acpi_status status; 16595b482a8SLen Brown 16695b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex_object, obj_desc); 16795b482a8SLen Brown 16895b482a8SLen Brown if (!obj_desc) { 16995b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 17095b482a8SLen Brown } 17195b482a8SLen Brown 17295b482a8SLen Brown /* Support for multiple acquires by the owning thread */ 17395b482a8SLen Brown 17495b482a8SLen Brown if (obj_desc->mutex.thread_id == thread_id) { 17595b482a8SLen Brown /* 17695b482a8SLen Brown * The mutex is already owned by this thread, just increment the 17795b482a8SLen Brown * acquisition depth 17895b482a8SLen Brown */ 17995b482a8SLen Brown obj_desc->mutex.acquisition_depth++; 18095b482a8SLen Brown return_ACPI_STATUS(AE_OK); 18195b482a8SLen Brown } 18295b482a8SLen Brown 18395b482a8SLen Brown /* Acquire the mutex, wait if necessary. Special case for Global Lock */ 18495b482a8SLen Brown 18595b482a8SLen Brown if (obj_desc == acpi_gbl_global_lock_mutex) { 18695b482a8SLen Brown status = acpi_ev_acquire_global_lock(timeout); 18795b482a8SLen Brown } else { 18895b482a8SLen Brown status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex, 18995b482a8SLen Brown timeout); 19095b482a8SLen Brown } 19195b482a8SLen Brown 19295b482a8SLen Brown if (ACPI_FAILURE(status)) { 19395b482a8SLen Brown 19495b482a8SLen Brown /* Includes failure from a timeout on time_desc */ 19595b482a8SLen Brown 19695b482a8SLen Brown return_ACPI_STATUS(status); 19795b482a8SLen Brown } 19895b482a8SLen Brown 19995b482a8SLen Brown /* Acquired the mutex: update mutex object */ 20095b482a8SLen Brown 20195b482a8SLen Brown obj_desc->mutex.thread_id = thread_id; 20295b482a8SLen Brown obj_desc->mutex.acquisition_depth = 1; 20395b482a8SLen Brown obj_desc->mutex.original_sync_level = 0; 20495b482a8SLen Brown obj_desc->mutex.owner_thread = NULL; /* Used only for AML Acquire() */ 20595b482a8SLen Brown 20695b482a8SLen Brown return_ACPI_STATUS(AE_OK); 20795b482a8SLen Brown } 20895b482a8SLen Brown 20995b482a8SLen Brown /******************************************************************************* 21095b482a8SLen Brown * 21195b482a8SLen Brown * FUNCTION: acpi_ex_acquire_mutex 21295b482a8SLen Brown * 21395b482a8SLen Brown * PARAMETERS: time_desc - Timeout integer 21495b482a8SLen Brown * obj_desc - Mutex object 21595b482a8SLen Brown * walk_state - Current method execution state 21695b482a8SLen Brown * 21795b482a8SLen Brown * RETURN: Status 21895b482a8SLen Brown * 21995b482a8SLen Brown * DESCRIPTION: Acquire an AML mutex 22095b482a8SLen Brown * 22195b482a8SLen Brown ******************************************************************************/ 22295b482a8SLen Brown 22395b482a8SLen Brown acpi_status 22495b482a8SLen Brown acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, 22595b482a8SLen Brown union acpi_operand_object *obj_desc, 22695b482a8SLen Brown struct acpi_walk_state *walk_state) 22795b482a8SLen Brown { 22895b482a8SLen Brown acpi_status status; 22995b482a8SLen Brown 23095b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex, obj_desc); 23195b482a8SLen Brown 23295b482a8SLen Brown if (!obj_desc) { 23395b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 23495b482a8SLen Brown } 23595b482a8SLen Brown 236a7499bc8SBob Moore /* Must have a valid thread state struct */ 23795b482a8SLen Brown 23895b482a8SLen Brown if (!walk_state->thread) { 23995b482a8SLen Brown ACPI_ERROR((AE_INFO, 24095b482a8SLen Brown "Cannot acquire Mutex [%4.4s], null thread info", 24195b482a8SLen Brown acpi_ut_get_node_name(obj_desc->mutex.node))); 24295b482a8SLen Brown return_ACPI_STATUS(AE_AML_INTERNAL); 24395b482a8SLen Brown } 24495b482a8SLen Brown 24595b482a8SLen Brown /* 24695b482a8SLen Brown * Current sync level must be less than or equal to the sync level of the 24795b482a8SLen Brown * mutex. This mechanism provides some deadlock prevention 24895b482a8SLen Brown */ 24995b482a8SLen Brown if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) { 25095b482a8SLen Brown ACPI_ERROR((AE_INFO, 251f6a22b0bSBob Moore "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%u)", 25295b482a8SLen Brown acpi_ut_get_node_name(obj_desc->mutex.node), 25395b482a8SLen Brown walk_state->thread->current_sync_level)); 25495b482a8SLen Brown return_ACPI_STATUS(AE_AML_MUTEX_ORDER); 25595b482a8SLen Brown } 25695b482a8SLen Brown 25795b482a8SLen Brown status = acpi_ex_acquire_mutex_object((u16) time_desc->integer.value, 25895b482a8SLen Brown obj_desc, 25995b482a8SLen Brown walk_state->thread->thread_id); 26095b482a8SLen Brown if (ACPI_SUCCESS(status) && obj_desc->mutex.acquisition_depth == 1) { 26195b482a8SLen Brown 26295b482a8SLen Brown /* Save Thread object, original/current sync levels */ 26395b482a8SLen Brown 26495b482a8SLen Brown obj_desc->mutex.owner_thread = walk_state->thread; 26595b482a8SLen Brown obj_desc->mutex.original_sync_level = 26695b482a8SLen Brown walk_state->thread->current_sync_level; 26795b482a8SLen Brown walk_state->thread->current_sync_level = 26895b482a8SLen Brown obj_desc->mutex.sync_level; 26995b482a8SLen Brown 27095b482a8SLen Brown /* Link the mutex to the current thread for force-unlock at method exit */ 27195b482a8SLen Brown 27295b482a8SLen Brown acpi_ex_link_mutex(obj_desc, walk_state->thread); 27395b482a8SLen Brown } 27495b482a8SLen Brown 27595b482a8SLen Brown return_ACPI_STATUS(status); 27695b482a8SLen Brown } 27795b482a8SLen Brown 27895b482a8SLen Brown /******************************************************************************* 27995b482a8SLen Brown * 28095b482a8SLen Brown * FUNCTION: acpi_ex_release_mutex_object 28195b482a8SLen Brown * 28295b482a8SLen Brown * PARAMETERS: obj_desc - The object descriptor for this op 28395b482a8SLen Brown * 28495b482a8SLen Brown * RETURN: Status 28595b482a8SLen Brown * 28695b482a8SLen Brown * DESCRIPTION: Release a previously acquired Mutex, low level interface. 28795b482a8SLen Brown * Provides a common path that supports multiple releases (after 28895b482a8SLen Brown * previous multiple acquires) by the same thread. 28995b482a8SLen Brown * 29095b482a8SLen Brown * MUTEX: Interpreter must be locked 29195b482a8SLen Brown * 29295b482a8SLen Brown * NOTE: This interface is called from three places: 29395b482a8SLen Brown * 1) From acpi_ex_release_mutex, via an AML Acquire() operator 29495b482a8SLen Brown * 2) From acpi_ex_release_global_lock when an AML Field access requires the 29595b482a8SLen Brown * global lock 29695b482a8SLen Brown * 3) From the external interface, acpi_release_global_lock 29795b482a8SLen Brown * 29895b482a8SLen Brown ******************************************************************************/ 29995b482a8SLen Brown 30095b482a8SLen Brown acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc) 30195b482a8SLen Brown { 30295b482a8SLen Brown acpi_status status = AE_OK; 30395b482a8SLen Brown 30495b482a8SLen Brown ACPI_FUNCTION_TRACE(ex_release_mutex_object); 30595b482a8SLen Brown 30695b482a8SLen Brown if (obj_desc->mutex.acquisition_depth == 0) { 30768aafc35SBob Moore return_ACPI_STATUS(AE_NOT_ACQUIRED); 30895b482a8SLen Brown } 30995b482a8SLen Brown 31095b482a8SLen Brown /* Match multiple Acquires with multiple Releases */ 31195b482a8SLen Brown 31295b482a8SLen Brown obj_desc->mutex.acquisition_depth--; 31395b482a8SLen Brown if (obj_desc->mutex.acquisition_depth != 0) { 31495b482a8SLen Brown 31595b482a8SLen Brown /* Just decrement the depth and return */ 31695b482a8SLen Brown 31795b482a8SLen Brown return_ACPI_STATUS(AE_OK); 31895b482a8SLen Brown } 31995b482a8SLen Brown 32095b482a8SLen Brown if (obj_desc->mutex.owner_thread) { 32195b482a8SLen Brown 32295b482a8SLen Brown /* Unlink the mutex from the owner's list */ 32395b482a8SLen Brown 32495b482a8SLen Brown acpi_ex_unlink_mutex(obj_desc); 32595b482a8SLen Brown obj_desc->mutex.owner_thread = NULL; 32695b482a8SLen Brown } 32795b482a8SLen Brown 32895b482a8SLen Brown /* Release the mutex, special case for Global Lock */ 32995b482a8SLen Brown 33095b482a8SLen Brown if (obj_desc == acpi_gbl_global_lock_mutex) { 33195b482a8SLen Brown status = acpi_ev_release_global_lock(); 33295b482a8SLen Brown } else { 33395b482a8SLen Brown acpi_os_release_mutex(obj_desc->mutex.os_mutex); 33495b482a8SLen Brown } 33595b482a8SLen Brown 33695b482a8SLen Brown /* Clear mutex info */ 33795b482a8SLen Brown 33828eb3fcfSLin Ming obj_desc->mutex.thread_id = 0; 33995b482a8SLen Brown return_ACPI_STATUS(status); 34095b482a8SLen Brown } 34195b482a8SLen Brown 34295b482a8SLen Brown /******************************************************************************* 34395b482a8SLen Brown * 34495b482a8SLen Brown * FUNCTION: acpi_ex_release_mutex 34595b482a8SLen Brown * 34695b482a8SLen Brown * PARAMETERS: obj_desc - The object descriptor for this op 34795b482a8SLen Brown * walk_state - Current method execution state 34895b482a8SLen Brown * 34995b482a8SLen Brown * RETURN: Status 35095b482a8SLen Brown * 35195b482a8SLen Brown * DESCRIPTION: Release a previously acquired Mutex. 35295b482a8SLen Brown * 35395b482a8SLen Brown ******************************************************************************/ 35495b482a8SLen Brown 35595b482a8SLen Brown acpi_status 35695b482a8SLen Brown acpi_ex_release_mutex(union acpi_operand_object *obj_desc, 35795b482a8SLen Brown struct acpi_walk_state *walk_state) 35895b482a8SLen Brown { 35995b482a8SLen Brown acpi_status status = AE_OK; 36010a3b461SBob Moore u8 previous_sync_level; 361e0f40281SLin Ming struct acpi_thread_state *owner_thread; 36295b482a8SLen Brown 36395b482a8SLen Brown ACPI_FUNCTION_TRACE(ex_release_mutex); 36495b482a8SLen Brown 36595b482a8SLen Brown if (!obj_desc) { 36695b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 36795b482a8SLen Brown } 36895b482a8SLen Brown 369e0f40281SLin Ming owner_thread = obj_desc->mutex.owner_thread; 370e0f40281SLin Ming 37195b482a8SLen Brown /* The mutex must have been previously acquired in order to release it */ 37295b482a8SLen Brown 373e0f40281SLin Ming if (!owner_thread) { 37495b482a8SLen Brown ACPI_ERROR((AE_INFO, 37595b482a8SLen Brown "Cannot release Mutex [%4.4s], not acquired", 37695b482a8SLen Brown acpi_ut_get_node_name(obj_desc->mutex.node))); 37795b482a8SLen Brown return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); 37895b482a8SLen Brown } 37995b482a8SLen Brown 38038bcb37aSBartlomiej Zolnierkiewicz /* Must have a valid thread. */ 381fbc3be2aSDan Carpenter if (!walk_state->thread) { 382fbc3be2aSDan Carpenter ACPI_ERROR((AE_INFO, 383fbc3be2aSDan Carpenter "Cannot release Mutex [%4.4s], null thread info", 384fbc3be2aSDan Carpenter acpi_ut_get_node_name(obj_desc->mutex.node))); 385fbc3be2aSDan Carpenter return_ACPI_STATUS(AE_AML_INTERNAL); 386fbc3be2aSDan Carpenter } 387fbc3be2aSDan Carpenter 38895b482a8SLen Brown /* 38995b482a8SLen Brown * The Mutex is owned, but this thread must be the owner. 39095b482a8SLen Brown * Special case for Global Lock, any thread can release 39195b482a8SLen Brown */ 392e0f40281SLin Ming if ((owner_thread->thread_id != walk_state->thread->thread_id) && 393e0f40281SLin Ming (obj_desc != acpi_gbl_global_lock_mutex)) { 39495b482a8SLen Brown ACPI_ERROR((AE_INFO, 39528eb3fcfSLin Ming "Thread %u cannot release Mutex [%4.4s] acquired by thread %u", 39628eb3fcfSLin Ming (u32)walk_state->thread->thread_id, 39795b482a8SLen Brown acpi_ut_get_node_name(obj_desc->mutex.node), 39828eb3fcfSLin Ming (u32)owner_thread->thread_id)); 39995b482a8SLen Brown return_ACPI_STATUS(AE_AML_NOT_OWNER); 40095b482a8SLen Brown } 40195b482a8SLen Brown 40295b482a8SLen Brown /* 403315c7288SBob Moore * The sync level of the mutex must be equal to the current sync level. In 404315c7288SBob Moore * other words, the current level means that at least one mutex at that 405315c7288SBob Moore * level is currently being held. Attempting to release a mutex of a 406315c7288SBob Moore * different level can only mean that the mutex ordering rule is being 407315c7288SBob Moore * violated. This behavior is clarified in ACPI 4.0 specification. 40895b482a8SLen Brown */ 409e0f40281SLin Ming if (obj_desc->mutex.sync_level != owner_thread->current_sync_level) { 41095b482a8SLen Brown ACPI_ERROR((AE_INFO, 411f6a22b0bSBob Moore "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %u current %u", 41295b482a8SLen Brown acpi_ut_get_node_name(obj_desc->mutex.node), 41395b482a8SLen Brown obj_desc->mutex.sync_level, 41495b482a8SLen Brown walk_state->thread->current_sync_level)); 41595b482a8SLen Brown return_ACPI_STATUS(AE_AML_MUTEX_ORDER); 41695b482a8SLen Brown } 41795b482a8SLen Brown 41810a3b461SBob Moore /* 41910a3b461SBob Moore * Get the previous sync_level from the head of the acquired mutex list. 42010a3b461SBob Moore * This handles the case where several mutexes at the same level have been 42110a3b461SBob Moore * acquired, but are not released in reverse order. 42210a3b461SBob Moore */ 42310a3b461SBob Moore previous_sync_level = 424e0f40281SLin Ming owner_thread->acquired_mutex_list->mutex.original_sync_level; 42510a3b461SBob Moore 42695b482a8SLen Brown status = acpi_ex_release_mutex_object(obj_desc); 427315c7288SBob Moore if (ACPI_FAILURE(status)) { 428315c7288SBob Moore return_ACPI_STATUS(status); 429315c7288SBob Moore } 43095b482a8SLen Brown 43195b482a8SLen Brown if (obj_desc->mutex.acquisition_depth == 0) { 43295b482a8SLen Brown 433315c7288SBob Moore /* Restore the previous sync_level */ 43495b482a8SLen Brown 435e0f40281SLin Ming owner_thread->current_sync_level = previous_sync_level; 43695b482a8SLen Brown } 437a7499bc8SBob Moore 43895b482a8SLen Brown return_ACPI_STATUS(status); 43995b482a8SLen Brown } 44095b482a8SLen Brown 44195b482a8SLen Brown /******************************************************************************* 44295b482a8SLen Brown * 44395b482a8SLen Brown * FUNCTION: acpi_ex_release_all_mutexes 44495b482a8SLen Brown * 445ba494beeSBob Moore * PARAMETERS: thread - Current executing thread object 44695b482a8SLen Brown * 44795b482a8SLen Brown * RETURN: Status 44895b482a8SLen Brown * 44995b482a8SLen Brown * DESCRIPTION: Release all mutexes held by this thread 45095b482a8SLen Brown * 45195b482a8SLen Brown * NOTE: This function is called as the thread is exiting the interpreter. 45295b482a8SLen Brown * Mutexes are not released when an individual control method is exited, but 45395b482a8SLen Brown * only when the parent thread actually exits the interpreter. This allows one 45495b482a8SLen Brown * method to acquire a mutex, and a different method to release it, as long as 45595b482a8SLen Brown * this is performed underneath a single parent control method. 45695b482a8SLen Brown * 45795b482a8SLen Brown ******************************************************************************/ 45895b482a8SLen Brown 45995b482a8SLen Brown void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) 46095b482a8SLen Brown { 46195b482a8SLen Brown union acpi_operand_object *next = thread->acquired_mutex_list; 46295b482a8SLen Brown union acpi_operand_object *obj_desc; 46395b482a8SLen Brown 464*2489ef01SBob Moore ACPI_FUNCTION_NAME(ex_release_all_mutexes); 46595b482a8SLen Brown 46695b482a8SLen Brown /* Traverse the list of owned mutexes, releasing each one */ 46795b482a8SLen Brown 46895b482a8SLen Brown while (next) { 46995b482a8SLen Brown obj_desc = next; 47095b482a8SLen Brown next = obj_desc->mutex.next; 47195b482a8SLen Brown 47295b482a8SLen Brown obj_desc->mutex.prev = NULL; 47395b482a8SLen Brown obj_desc->mutex.next = NULL; 47495b482a8SLen Brown obj_desc->mutex.acquisition_depth = 0; 47595b482a8SLen Brown 476*2489ef01SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 477*2489ef01SBob Moore "Force-releasing held mutex: %p\n", 478*2489ef01SBob Moore obj_desc)); 479*2489ef01SBob Moore 48095b482a8SLen Brown /* Release the mutex, special case for Global Lock */ 48195b482a8SLen Brown 48295b482a8SLen Brown if (obj_desc == acpi_gbl_global_lock_mutex) { 48395b482a8SLen Brown 48495b482a8SLen Brown /* Ignore errors */ 48595b482a8SLen Brown 48695b482a8SLen Brown (void)acpi_ev_release_global_lock(); 48795b482a8SLen Brown } else { 48895b482a8SLen Brown acpi_os_release_mutex(obj_desc->mutex.os_mutex); 48995b482a8SLen Brown } 49095b482a8SLen Brown 49195b482a8SLen Brown /* Mark mutex unowned */ 49295b482a8SLen Brown 49395b482a8SLen Brown obj_desc->mutex.owner_thread = NULL; 49428eb3fcfSLin Ming obj_desc->mutex.thread_id = 0; 49595b482a8SLen Brown 49695b482a8SLen Brown /* Update Thread sync_level (Last mutex is the important one) */ 49795b482a8SLen Brown 49895b482a8SLen Brown thread->current_sync_level = 49995b482a8SLen Brown obj_desc->mutex.original_sync_level; 50095b482a8SLen Brown } 50195b482a8SLen Brown } 502