195b482a8SLen Brown /****************************************************************************** 295b482a8SLen Brown * 395b482a8SLen Brown * Module Name: exmutex - ASL Mutex Acquire/Release functions 495b482a8SLen Brown * 595b482a8SLen Brown *****************************************************************************/ 695b482a8SLen Brown 795b482a8SLen Brown /* 882a80941SDavid E. Box * Copyright (C) 2000 - 2015, 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 { 188*cd162b35SBob Moore status = 189*cd162b35SBob Moore acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex, 19095b482a8SLen Brown timeout); 19195b482a8SLen Brown } 19295b482a8SLen Brown 19395b482a8SLen Brown if (ACPI_FAILURE(status)) { 19495b482a8SLen Brown 19595b482a8SLen Brown /* Includes failure from a timeout on time_desc */ 19695b482a8SLen Brown 19795b482a8SLen Brown return_ACPI_STATUS(status); 19895b482a8SLen Brown } 19995b482a8SLen Brown 20095b482a8SLen Brown /* Acquired the mutex: update mutex object */ 20195b482a8SLen Brown 20295b482a8SLen Brown obj_desc->mutex.thread_id = thread_id; 20395b482a8SLen Brown obj_desc->mutex.acquisition_depth = 1; 20495b482a8SLen Brown obj_desc->mutex.original_sync_level = 0; 20595b482a8SLen Brown obj_desc->mutex.owner_thread = NULL; /* Used only for AML Acquire() */ 20695b482a8SLen Brown 20795b482a8SLen Brown return_ACPI_STATUS(AE_OK); 20895b482a8SLen Brown } 20995b482a8SLen Brown 21095b482a8SLen Brown /******************************************************************************* 21195b482a8SLen Brown * 21295b482a8SLen Brown * FUNCTION: acpi_ex_acquire_mutex 21395b482a8SLen Brown * 21495b482a8SLen Brown * PARAMETERS: time_desc - Timeout integer 21595b482a8SLen Brown * obj_desc - Mutex object 21695b482a8SLen Brown * walk_state - Current method execution state 21795b482a8SLen Brown * 21895b482a8SLen Brown * RETURN: Status 21995b482a8SLen Brown * 22095b482a8SLen Brown * DESCRIPTION: Acquire an AML mutex 22195b482a8SLen Brown * 22295b482a8SLen Brown ******************************************************************************/ 22395b482a8SLen Brown 22495b482a8SLen Brown acpi_status 22595b482a8SLen Brown acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, 22695b482a8SLen Brown union acpi_operand_object *obj_desc, 22795b482a8SLen Brown struct acpi_walk_state *walk_state) 22895b482a8SLen Brown { 22995b482a8SLen Brown acpi_status status; 23095b482a8SLen Brown 23195b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex, obj_desc); 23295b482a8SLen Brown 23395b482a8SLen Brown if (!obj_desc) { 23495b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 23595b482a8SLen Brown } 23695b482a8SLen Brown 237a7499bc8SBob Moore /* Must have a valid thread state struct */ 23895b482a8SLen Brown 23995b482a8SLen Brown if (!walk_state->thread) { 24095b482a8SLen Brown ACPI_ERROR((AE_INFO, 24195b482a8SLen Brown "Cannot acquire Mutex [%4.4s], null thread info", 24295b482a8SLen Brown acpi_ut_get_node_name(obj_desc->mutex.node))); 24395b482a8SLen Brown return_ACPI_STATUS(AE_AML_INTERNAL); 24495b482a8SLen Brown } 24595b482a8SLen Brown 24695b482a8SLen Brown /* 247*cd162b35SBob Moore * Current sync level must be less than or equal to the sync level 248*cd162b35SBob Moore * of the mutex. This mechanism provides some deadlock prevention. 24995b482a8SLen Brown */ 25095b482a8SLen Brown if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) { 25195b482a8SLen Brown ACPI_ERROR((AE_INFO, 252*cd162b35SBob Moore "Cannot acquire Mutex [%4.4s], " 253*cd162b35SBob Moore "current SyncLevel is too large (%u)", 25495b482a8SLen Brown acpi_ut_get_node_name(obj_desc->mutex.node), 25595b482a8SLen Brown walk_state->thread->current_sync_level)); 25695b482a8SLen Brown return_ACPI_STATUS(AE_AML_MUTEX_ORDER); 25795b482a8SLen Brown } 25895b482a8SLen Brown 259*cd162b35SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 260*cd162b35SBob Moore "Acquiring: Mutex SyncLevel %u, Thread SyncLevel %u, " 261*cd162b35SBob Moore "Depth %u TID %p\n", 262*cd162b35SBob Moore obj_desc->mutex.sync_level, 263*cd162b35SBob Moore walk_state->thread->current_sync_level, 264*cd162b35SBob Moore obj_desc->mutex.acquisition_depth, 265*cd162b35SBob Moore walk_state->thread)); 266*cd162b35SBob Moore 26795b482a8SLen Brown status = acpi_ex_acquire_mutex_object((u16)time_desc->integer.value, 26895b482a8SLen Brown obj_desc, 26995b482a8SLen Brown walk_state->thread->thread_id); 270*cd162b35SBob Moore 27195b482a8SLen Brown if (ACPI_SUCCESS(status) && obj_desc->mutex.acquisition_depth == 1) { 27295b482a8SLen Brown 27395b482a8SLen Brown /* Save Thread object, original/current sync levels */ 27495b482a8SLen Brown 27595b482a8SLen Brown obj_desc->mutex.owner_thread = walk_state->thread; 27695b482a8SLen Brown obj_desc->mutex.original_sync_level = 27795b482a8SLen Brown walk_state->thread->current_sync_level; 27895b482a8SLen Brown walk_state->thread->current_sync_level = 27995b482a8SLen Brown obj_desc->mutex.sync_level; 28095b482a8SLen Brown 28195b482a8SLen Brown /* Link the mutex to the current thread for force-unlock at method exit */ 28295b482a8SLen Brown 28395b482a8SLen Brown acpi_ex_link_mutex(obj_desc, walk_state->thread); 28495b482a8SLen Brown } 28595b482a8SLen Brown 286*cd162b35SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 287*cd162b35SBob Moore "Acquired: Mutex SyncLevel %u, Thread SyncLevel %u, Depth %u\n", 288*cd162b35SBob Moore obj_desc->mutex.sync_level, 289*cd162b35SBob Moore walk_state->thread->current_sync_level, 290*cd162b35SBob Moore obj_desc->mutex.acquisition_depth)); 291*cd162b35SBob Moore 29295b482a8SLen Brown return_ACPI_STATUS(status); 29395b482a8SLen Brown } 29495b482a8SLen Brown 29595b482a8SLen Brown /******************************************************************************* 29695b482a8SLen Brown * 29795b482a8SLen Brown * FUNCTION: acpi_ex_release_mutex_object 29895b482a8SLen Brown * 29995b482a8SLen Brown * PARAMETERS: obj_desc - The object descriptor for this op 30095b482a8SLen Brown * 30195b482a8SLen Brown * RETURN: Status 30295b482a8SLen Brown * 30395b482a8SLen Brown * DESCRIPTION: Release a previously acquired Mutex, low level interface. 30495b482a8SLen Brown * Provides a common path that supports multiple releases (after 30595b482a8SLen Brown * previous multiple acquires) by the same thread. 30695b482a8SLen Brown * 30795b482a8SLen Brown * MUTEX: Interpreter must be locked 30895b482a8SLen Brown * 30995b482a8SLen Brown * NOTE: This interface is called from three places: 31095b482a8SLen Brown * 1) From acpi_ex_release_mutex, via an AML Acquire() operator 31195b482a8SLen Brown * 2) From acpi_ex_release_global_lock when an AML Field access requires the 31295b482a8SLen Brown * global lock 31395b482a8SLen Brown * 3) From the external interface, acpi_release_global_lock 31495b482a8SLen Brown * 31595b482a8SLen Brown ******************************************************************************/ 31695b482a8SLen Brown 31795b482a8SLen Brown acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc) 31895b482a8SLen Brown { 31995b482a8SLen Brown acpi_status status = AE_OK; 32095b482a8SLen Brown 32195b482a8SLen Brown ACPI_FUNCTION_TRACE(ex_release_mutex_object); 32295b482a8SLen Brown 32395b482a8SLen Brown if (obj_desc->mutex.acquisition_depth == 0) { 32468aafc35SBob Moore return_ACPI_STATUS(AE_NOT_ACQUIRED); 32595b482a8SLen Brown } 32695b482a8SLen Brown 32795b482a8SLen Brown /* Match multiple Acquires with multiple Releases */ 32895b482a8SLen Brown 32995b482a8SLen Brown obj_desc->mutex.acquisition_depth--; 33095b482a8SLen Brown if (obj_desc->mutex.acquisition_depth != 0) { 33195b482a8SLen Brown 33295b482a8SLen Brown /* Just decrement the depth and return */ 33395b482a8SLen Brown 33495b482a8SLen Brown return_ACPI_STATUS(AE_OK); 33595b482a8SLen Brown } 33695b482a8SLen Brown 33795b482a8SLen Brown if (obj_desc->mutex.owner_thread) { 33895b482a8SLen Brown 33995b482a8SLen Brown /* Unlink the mutex from the owner's list */ 34095b482a8SLen Brown 34195b482a8SLen Brown acpi_ex_unlink_mutex(obj_desc); 34295b482a8SLen Brown obj_desc->mutex.owner_thread = NULL; 34395b482a8SLen Brown } 34495b482a8SLen Brown 34595b482a8SLen Brown /* Release the mutex, special case for Global Lock */ 34695b482a8SLen Brown 34795b482a8SLen Brown if (obj_desc == acpi_gbl_global_lock_mutex) { 34895b482a8SLen Brown status = acpi_ev_release_global_lock(); 34995b482a8SLen Brown } else { 35095b482a8SLen Brown acpi_os_release_mutex(obj_desc->mutex.os_mutex); 35195b482a8SLen Brown } 35295b482a8SLen Brown 35395b482a8SLen Brown /* Clear mutex info */ 35495b482a8SLen Brown 35528eb3fcfSLin Ming obj_desc->mutex.thread_id = 0; 35695b482a8SLen Brown return_ACPI_STATUS(status); 35795b482a8SLen Brown } 35895b482a8SLen Brown 35995b482a8SLen Brown /******************************************************************************* 36095b482a8SLen Brown * 36195b482a8SLen Brown * FUNCTION: acpi_ex_release_mutex 36295b482a8SLen Brown * 36395b482a8SLen Brown * PARAMETERS: obj_desc - The object descriptor for this op 36495b482a8SLen Brown * walk_state - Current method execution state 36595b482a8SLen Brown * 36695b482a8SLen Brown * RETURN: Status 36795b482a8SLen Brown * 36895b482a8SLen Brown * DESCRIPTION: Release a previously acquired Mutex. 36995b482a8SLen Brown * 37095b482a8SLen Brown ******************************************************************************/ 37195b482a8SLen Brown 37295b482a8SLen Brown acpi_status 37395b482a8SLen Brown acpi_ex_release_mutex(union acpi_operand_object *obj_desc, 37495b482a8SLen Brown struct acpi_walk_state *walk_state) 37595b482a8SLen Brown { 37610a3b461SBob Moore u8 previous_sync_level; 377e0f40281SLin Ming struct acpi_thread_state *owner_thread; 378*cd162b35SBob Moore acpi_status status = AE_OK; 37995b482a8SLen Brown 38095b482a8SLen Brown ACPI_FUNCTION_TRACE(ex_release_mutex); 38195b482a8SLen Brown 38295b482a8SLen Brown if (!obj_desc) { 38395b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 38495b482a8SLen Brown } 38595b482a8SLen Brown 386e0f40281SLin Ming owner_thread = obj_desc->mutex.owner_thread; 387e0f40281SLin Ming 38895b482a8SLen Brown /* The mutex must have been previously acquired in order to release it */ 38995b482a8SLen Brown 390e0f40281SLin Ming if (!owner_thread) { 39195b482a8SLen Brown ACPI_ERROR((AE_INFO, 39295b482a8SLen Brown "Cannot release Mutex [%4.4s], not acquired", 39395b482a8SLen Brown acpi_ut_get_node_name(obj_desc->mutex.node))); 39495b482a8SLen Brown return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); 39595b482a8SLen Brown } 39695b482a8SLen Brown 39775c8044fSLv Zheng /* Must have a valid thread ID */ 3983e8214e5SLv Zheng 399fbc3be2aSDan Carpenter if (!walk_state->thread) { 400fbc3be2aSDan Carpenter ACPI_ERROR((AE_INFO, 401fbc3be2aSDan Carpenter "Cannot release Mutex [%4.4s], null thread info", 402fbc3be2aSDan Carpenter acpi_ut_get_node_name(obj_desc->mutex.node))); 403fbc3be2aSDan Carpenter return_ACPI_STATUS(AE_AML_INTERNAL); 404fbc3be2aSDan Carpenter } 405fbc3be2aSDan Carpenter 40695b482a8SLen Brown /* 40795b482a8SLen Brown * The Mutex is owned, but this thread must be the owner. 40895b482a8SLen Brown * Special case for Global Lock, any thread can release 40995b482a8SLen Brown */ 410e0f40281SLin Ming if ((owner_thread->thread_id != walk_state->thread->thread_id) && 411e0f40281SLin Ming (obj_desc != acpi_gbl_global_lock_mutex)) { 41295b482a8SLen Brown ACPI_ERROR((AE_INFO, 41328eb3fcfSLin Ming "Thread %u cannot release Mutex [%4.4s] acquired by thread %u", 41428eb3fcfSLin Ming (u32)walk_state->thread->thread_id, 41595b482a8SLen Brown acpi_ut_get_node_name(obj_desc->mutex.node), 41628eb3fcfSLin Ming (u32)owner_thread->thread_id)); 41795b482a8SLen Brown return_ACPI_STATUS(AE_AML_NOT_OWNER); 41895b482a8SLen Brown } 41995b482a8SLen Brown 42095b482a8SLen Brown /* 421315c7288SBob Moore * The sync level of the mutex must be equal to the current sync level. In 422315c7288SBob Moore * other words, the current level means that at least one mutex at that 423315c7288SBob Moore * level is currently being held. Attempting to release a mutex of a 424315c7288SBob Moore * different level can only mean that the mutex ordering rule is being 425315c7288SBob Moore * violated. This behavior is clarified in ACPI 4.0 specification. 42695b482a8SLen Brown */ 427e0f40281SLin Ming if (obj_desc->mutex.sync_level != owner_thread->current_sync_level) { 42895b482a8SLen Brown ACPI_ERROR((AE_INFO, 429*cd162b35SBob Moore "Cannot release Mutex [%4.4s], SyncLevel mismatch: " 430*cd162b35SBob Moore "mutex %u current %u", 43195b482a8SLen Brown acpi_ut_get_node_name(obj_desc->mutex.node), 43295b482a8SLen Brown obj_desc->mutex.sync_level, 43395b482a8SLen Brown walk_state->thread->current_sync_level)); 43495b482a8SLen Brown return_ACPI_STATUS(AE_AML_MUTEX_ORDER); 43595b482a8SLen Brown } 43695b482a8SLen Brown 43710a3b461SBob Moore /* 43810a3b461SBob Moore * Get the previous sync_level from the head of the acquired mutex list. 43910a3b461SBob Moore * This handles the case where several mutexes at the same level have been 44010a3b461SBob Moore * acquired, but are not released in reverse order. 44110a3b461SBob Moore */ 44210a3b461SBob Moore previous_sync_level = 443e0f40281SLin Ming owner_thread->acquired_mutex_list->mutex.original_sync_level; 44410a3b461SBob Moore 445*cd162b35SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 446*cd162b35SBob Moore "Releasing: Object SyncLevel %u, Thread SyncLevel %u, " 447*cd162b35SBob Moore "Prev SyncLevel %u, Depth %u TID %p\n", 448*cd162b35SBob Moore obj_desc->mutex.sync_level, 449*cd162b35SBob Moore walk_state->thread->current_sync_level, 450*cd162b35SBob Moore previous_sync_level, 451*cd162b35SBob Moore obj_desc->mutex.acquisition_depth, 452*cd162b35SBob Moore walk_state->thread)); 453*cd162b35SBob Moore 45495b482a8SLen Brown status = acpi_ex_release_mutex_object(obj_desc); 455315c7288SBob Moore if (ACPI_FAILURE(status)) { 456315c7288SBob Moore return_ACPI_STATUS(status); 457315c7288SBob Moore } 45895b482a8SLen Brown 45995b482a8SLen Brown if (obj_desc->mutex.acquisition_depth == 0) { 46095b482a8SLen Brown 461315c7288SBob Moore /* Restore the previous sync_level */ 46295b482a8SLen Brown 463e0f40281SLin Ming owner_thread->current_sync_level = previous_sync_level; 46495b482a8SLen Brown } 465a7499bc8SBob Moore 466*cd162b35SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 467*cd162b35SBob Moore "Released: Object SyncLevel %u, Thread SyncLevel, %u, " 468*cd162b35SBob Moore "Prev SyncLevel %u, Depth %u\n", 469*cd162b35SBob Moore obj_desc->mutex.sync_level, 470*cd162b35SBob Moore walk_state->thread->current_sync_level, 471*cd162b35SBob Moore previous_sync_level, 472*cd162b35SBob Moore obj_desc->mutex.acquisition_depth)); 473*cd162b35SBob Moore 47495b482a8SLen Brown return_ACPI_STATUS(status); 47595b482a8SLen Brown } 47695b482a8SLen Brown 47795b482a8SLen Brown /******************************************************************************* 47895b482a8SLen Brown * 47995b482a8SLen Brown * FUNCTION: acpi_ex_release_all_mutexes 48095b482a8SLen Brown * 481ba494beeSBob Moore * PARAMETERS: thread - Current executing thread object 48295b482a8SLen Brown * 48395b482a8SLen Brown * RETURN: Status 48495b482a8SLen Brown * 48595b482a8SLen Brown * DESCRIPTION: Release all mutexes held by this thread 48695b482a8SLen Brown * 48795b482a8SLen Brown * NOTE: This function is called as the thread is exiting the interpreter. 48895b482a8SLen Brown * Mutexes are not released when an individual control method is exited, but 48995b482a8SLen Brown * only when the parent thread actually exits the interpreter. This allows one 49095b482a8SLen Brown * method to acquire a mutex, and a different method to release it, as long as 49195b482a8SLen Brown * this is performed underneath a single parent control method. 49295b482a8SLen Brown * 49395b482a8SLen Brown ******************************************************************************/ 49495b482a8SLen Brown 49595b482a8SLen Brown void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) 49695b482a8SLen Brown { 49795b482a8SLen Brown union acpi_operand_object *next = thread->acquired_mutex_list; 49895b482a8SLen Brown union acpi_operand_object *obj_desc; 49995b482a8SLen Brown 500*cd162b35SBob Moore ACPI_FUNCTION_TRACE(ex_release_all_mutexes); 50195b482a8SLen Brown 50295b482a8SLen Brown /* Traverse the list of owned mutexes, releasing each one */ 50395b482a8SLen Brown 50495b482a8SLen Brown while (next) { 50595b482a8SLen Brown obj_desc = next; 5062489ef01SBob Moore ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 507*cd162b35SBob Moore "Mutex [%4.4s] force-release, SyncLevel %u Depth %u\n", 508*cd162b35SBob Moore obj_desc->mutex.node->name.ascii, 509*cd162b35SBob Moore obj_desc->mutex.sync_level, 510*cd162b35SBob Moore obj_desc->mutex.acquisition_depth)); 5112489ef01SBob Moore 51295b482a8SLen Brown /* Release the mutex, special case for Global Lock */ 51395b482a8SLen Brown 51495b482a8SLen Brown if (obj_desc == acpi_gbl_global_lock_mutex) { 51595b482a8SLen Brown 51695b482a8SLen Brown /* Ignore errors */ 51795b482a8SLen Brown 51895b482a8SLen Brown (void)acpi_ev_release_global_lock(); 51995b482a8SLen Brown } else { 52095b482a8SLen Brown acpi_os_release_mutex(obj_desc->mutex.os_mutex); 52195b482a8SLen Brown } 52295b482a8SLen Brown 52395b482a8SLen Brown /* Update Thread sync_level (Last mutex is the important one) */ 52495b482a8SLen Brown 52595b482a8SLen Brown thread->current_sync_level = 52695b482a8SLen Brown obj_desc->mutex.original_sync_level; 527*cd162b35SBob Moore 528*cd162b35SBob Moore /* Mark mutex unowned */ 529*cd162b35SBob Moore 530*cd162b35SBob Moore next = obj_desc->mutex.next; 531*cd162b35SBob Moore 532*cd162b35SBob Moore obj_desc->mutex.prev = NULL; 533*cd162b35SBob Moore obj_desc->mutex.next = NULL; 534*cd162b35SBob Moore obj_desc->mutex.acquisition_depth = 0; 535*cd162b35SBob Moore obj_desc->mutex.owner_thread = NULL; 536*cd162b35SBob Moore obj_desc->mutex.thread_id = 0; 53795b482a8SLen Brown } 538*cd162b35SBob Moore 539*cd162b35SBob Moore return_VOID; 54095b482a8SLen Brown } 541