1db2bae30SDana Myers /****************************************************************************** 2db2bae30SDana Myers * 3db2bae30SDana Myers * Module Name: exmutex - ASL Mutex Acquire/Release functions 4db2bae30SDana Myers * 5db2bae30SDana Myers *****************************************************************************/ 6db2bae30SDana Myers 726f3cdf0SGordon Ross /* 8*385cc6b4SJerry Jelinek * Copyright (C) 2000 - 2016, Intel Corp. 9db2bae30SDana Myers * All rights reserved. 10db2bae30SDana Myers * 1126f3cdf0SGordon Ross * Redistribution and use in source and binary forms, with or without 1226f3cdf0SGordon Ross * modification, are permitted provided that the following conditions 1326f3cdf0SGordon Ross * are met: 1426f3cdf0SGordon Ross * 1. Redistributions of source code must retain the above copyright 1526f3cdf0SGordon Ross * notice, this list of conditions, and the following disclaimer, 1626f3cdf0SGordon Ross * without modification. 1726f3cdf0SGordon Ross * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1826f3cdf0SGordon Ross * substantially similar to the "NO WARRANTY" disclaimer below 1926f3cdf0SGordon Ross * ("Disclaimer") and any redistribution must be conditioned upon 2026f3cdf0SGordon Ross * including a substantially similar Disclaimer requirement for further 2126f3cdf0SGordon Ross * binary redistribution. 2226f3cdf0SGordon Ross * 3. Neither the names of the above-listed copyright holders nor the names 2326f3cdf0SGordon Ross * of any contributors may be used to endorse or promote products derived 2426f3cdf0SGordon Ross * from this software without specific prior written permission. 25db2bae30SDana Myers * 2626f3cdf0SGordon Ross * Alternatively, this software may be distributed under the terms of the 2726f3cdf0SGordon Ross * GNU General Public License ("GPL") version 2 as published by the Free 2826f3cdf0SGordon Ross * Software Foundation. 29db2bae30SDana Myers * 3026f3cdf0SGordon Ross * NO WARRANTY 3126f3cdf0SGordon Ross * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3226f3cdf0SGordon Ross * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3326f3cdf0SGordon Ross * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3426f3cdf0SGordon Ross * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3526f3cdf0SGordon Ross * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3626f3cdf0SGordon Ross * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3726f3cdf0SGordon Ross * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3826f3cdf0SGordon Ross * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3926f3cdf0SGordon Ross * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4026f3cdf0SGordon Ross * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4126f3cdf0SGordon Ross * POSSIBILITY OF SUCH DAMAGES. 4226f3cdf0SGordon Ross */ 43db2bae30SDana Myers 44db2bae30SDana Myers #include "acpi.h" 45aa2aa9a6SDana Myers #include "accommon.h" 46db2bae30SDana Myers #include "acinterp.h" 47db2bae30SDana Myers #include "acevents.h" 48db2bae30SDana Myers 49db2bae30SDana Myers #define _COMPONENT ACPI_EXECUTER 50db2bae30SDana Myers ACPI_MODULE_NAME ("exmutex") 51db2bae30SDana Myers 52db2bae30SDana Myers /* Local prototypes */ 53db2bae30SDana Myers 54db2bae30SDana Myers static void 55db2bae30SDana Myers AcpiExLinkMutex ( 56db2bae30SDana Myers ACPI_OPERAND_OBJECT *ObjDesc, 57db2bae30SDana Myers ACPI_THREAD_STATE *Thread); 58db2bae30SDana Myers 59db2bae30SDana Myers 60db2bae30SDana Myers /******************************************************************************* 61db2bae30SDana Myers * 62db2bae30SDana Myers * FUNCTION: AcpiExUnlinkMutex 63db2bae30SDana Myers * 64db2bae30SDana Myers * PARAMETERS: ObjDesc - The mutex to be unlinked 65db2bae30SDana Myers * 66db2bae30SDana Myers * RETURN: None 67db2bae30SDana Myers * 68db2bae30SDana Myers * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list 69db2bae30SDana Myers * 70db2bae30SDana Myers ******************************************************************************/ 71db2bae30SDana Myers 72db2bae30SDana Myers void 73db2bae30SDana Myers AcpiExUnlinkMutex ( 74db2bae30SDana Myers ACPI_OPERAND_OBJECT *ObjDesc) 75db2bae30SDana Myers { 76db2bae30SDana Myers ACPI_THREAD_STATE *Thread = ObjDesc->Mutex.OwnerThread; 77db2bae30SDana Myers 78db2bae30SDana Myers 79db2bae30SDana Myers if (!Thread) 80db2bae30SDana Myers { 81db2bae30SDana Myers return; 82db2bae30SDana Myers } 83db2bae30SDana Myers 84db2bae30SDana Myers /* Doubly linked list */ 85db2bae30SDana Myers 86db2bae30SDana Myers if (ObjDesc->Mutex.Next) 87db2bae30SDana Myers { 88db2bae30SDana Myers (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev; 89db2bae30SDana Myers } 90db2bae30SDana Myers 91db2bae30SDana Myers if (ObjDesc->Mutex.Prev) 92db2bae30SDana Myers { 93db2bae30SDana Myers (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next; 94aa2aa9a6SDana Myers 95aa2aa9a6SDana Myers /* 9626f3cdf0SGordon Ross * Migrate the previous sync level associated with this mutex to 9726f3cdf0SGordon Ross * the previous mutex on the list so that it may be preserved. 9826f3cdf0SGordon Ross * This handles the case where several mutexes have been acquired 9926f3cdf0SGordon Ross * at the same level, but are not released in opposite order. 100aa2aa9a6SDana Myers */ 101aa2aa9a6SDana Myers (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel = 102aa2aa9a6SDana Myers ObjDesc->Mutex.OriginalSyncLevel; 103db2bae30SDana Myers } 104db2bae30SDana Myers else 105db2bae30SDana Myers { 106db2bae30SDana Myers Thread->AcquiredMutexList = ObjDesc->Mutex.Next; 107db2bae30SDana Myers } 108db2bae30SDana Myers } 109db2bae30SDana Myers 110db2bae30SDana Myers 111db2bae30SDana Myers /******************************************************************************* 112db2bae30SDana Myers * 113db2bae30SDana Myers * FUNCTION: AcpiExLinkMutex 114db2bae30SDana Myers * 115db2bae30SDana Myers * PARAMETERS: ObjDesc - The mutex to be linked 116db2bae30SDana Myers * Thread - Current executing thread object 117db2bae30SDana Myers * 118db2bae30SDana Myers * RETURN: None 119db2bae30SDana Myers * 120db2bae30SDana Myers * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk 121db2bae30SDana Myers * 122db2bae30SDana Myers ******************************************************************************/ 123db2bae30SDana Myers 124db2bae30SDana Myers static void 125db2bae30SDana Myers AcpiExLinkMutex ( 126db2bae30SDana Myers ACPI_OPERAND_OBJECT *ObjDesc, 127db2bae30SDana Myers ACPI_THREAD_STATE *Thread) 128db2bae30SDana Myers { 129db2bae30SDana Myers ACPI_OPERAND_OBJECT *ListHead; 130db2bae30SDana Myers 131db2bae30SDana Myers 132db2bae30SDana Myers ListHead = Thread->AcquiredMutexList; 133db2bae30SDana Myers 134db2bae30SDana Myers /* This object will be the first object in the list */ 135db2bae30SDana Myers 136db2bae30SDana Myers ObjDesc->Mutex.Prev = NULL; 137db2bae30SDana Myers ObjDesc->Mutex.Next = ListHead; 138db2bae30SDana Myers 139db2bae30SDana Myers /* Update old first object to point back to this object */ 140db2bae30SDana Myers 141db2bae30SDana Myers if (ListHead) 142db2bae30SDana Myers { 143db2bae30SDana Myers ListHead->Mutex.Prev = ObjDesc; 144db2bae30SDana Myers } 145db2bae30SDana Myers 146db2bae30SDana Myers /* Update list head */ 147db2bae30SDana Myers 148db2bae30SDana Myers Thread->AcquiredMutexList = ObjDesc; 149db2bae30SDana Myers } 150db2bae30SDana Myers 151db2bae30SDana Myers 152db2bae30SDana Myers /******************************************************************************* 153db2bae30SDana Myers * 154db2bae30SDana Myers * FUNCTION: AcpiExAcquireMutexObject 155db2bae30SDana Myers * 15626f3cdf0SGordon Ross * PARAMETERS: Timeout - Timeout in milliseconds 157db2bae30SDana Myers * ObjDesc - Mutex object 15826f3cdf0SGordon Ross * ThreadId - Current thread state 159db2bae30SDana Myers * 160db2bae30SDana Myers * RETURN: Status 161db2bae30SDana Myers * 162db2bae30SDana Myers * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common 163db2bae30SDana Myers * path that supports multiple acquires by the same thread. 164db2bae30SDana Myers * 165db2bae30SDana Myers * MUTEX: Interpreter must be locked 166db2bae30SDana Myers * 167db2bae30SDana Myers * NOTE: This interface is called from three places: 168db2bae30SDana Myers * 1) From AcpiExAcquireMutex, via an AML Acquire() operator 169db2bae30SDana Myers * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the 170db2bae30SDana Myers * global lock 171db2bae30SDana Myers * 3) From the external interface, AcpiAcquireGlobalLock 172db2bae30SDana Myers * 173db2bae30SDana Myers ******************************************************************************/ 174db2bae30SDana Myers 175db2bae30SDana Myers ACPI_STATUS 176db2bae30SDana Myers AcpiExAcquireMutexObject ( 177db2bae30SDana Myers UINT16 Timeout, 178db2bae30SDana Myers ACPI_OPERAND_OBJECT *ObjDesc, 179db2bae30SDana Myers ACPI_THREAD_ID ThreadId) 180db2bae30SDana Myers { 181db2bae30SDana Myers ACPI_STATUS Status; 182db2bae30SDana Myers 183db2bae30SDana Myers 184db2bae30SDana Myers ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc); 185db2bae30SDana Myers 186db2bae30SDana Myers 187db2bae30SDana Myers if (!ObjDesc) 188db2bae30SDana Myers { 189db2bae30SDana Myers return_ACPI_STATUS (AE_BAD_PARAMETER); 190db2bae30SDana Myers } 191db2bae30SDana Myers 192db2bae30SDana Myers /* Support for multiple acquires by the owning thread */ 193db2bae30SDana Myers 194db2bae30SDana Myers if (ObjDesc->Mutex.ThreadId == ThreadId) 195db2bae30SDana Myers { 196db2bae30SDana Myers /* 197db2bae30SDana Myers * The mutex is already owned by this thread, just increment the 198db2bae30SDana Myers * acquisition depth 199db2bae30SDana Myers */ 200db2bae30SDana Myers ObjDesc->Mutex.AcquisitionDepth++; 201db2bae30SDana Myers return_ACPI_STATUS (AE_OK); 202db2bae30SDana Myers } 203db2bae30SDana Myers 204db2bae30SDana Myers /* Acquire the mutex, wait if necessary. Special case for Global Lock */ 205db2bae30SDana Myers 206db2bae30SDana Myers if (ObjDesc == AcpiGbl_GlobalLockMutex) 207db2bae30SDana Myers { 208db2bae30SDana Myers Status = AcpiEvAcquireGlobalLock (Timeout); 209db2bae30SDana Myers } 210db2bae30SDana Myers else 211db2bae30SDana Myers { 212*385cc6b4SJerry Jelinek Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex, Timeout); 213db2bae30SDana Myers } 214db2bae30SDana Myers 215db2bae30SDana Myers if (ACPI_FAILURE (Status)) 216db2bae30SDana Myers { 217db2bae30SDana Myers /* Includes failure from a timeout on TimeDesc */ 218db2bae30SDana Myers 219db2bae30SDana Myers return_ACPI_STATUS (Status); 220db2bae30SDana Myers } 221db2bae30SDana Myers 222db2bae30SDana Myers /* Acquired the mutex: update mutex object */ 223db2bae30SDana Myers 224db2bae30SDana Myers ObjDesc->Mutex.ThreadId = ThreadId; 225db2bae30SDana Myers ObjDesc->Mutex.AcquisitionDepth = 1; 226db2bae30SDana Myers ObjDesc->Mutex.OriginalSyncLevel = 0; 227db2bae30SDana Myers ObjDesc->Mutex.OwnerThread = NULL; /* Used only for AML Acquire() */ 228db2bae30SDana Myers 229db2bae30SDana Myers return_ACPI_STATUS (AE_OK); 230db2bae30SDana Myers } 231db2bae30SDana Myers 232db2bae30SDana Myers 233db2bae30SDana Myers /******************************************************************************* 234db2bae30SDana Myers * 235db2bae30SDana Myers * FUNCTION: AcpiExAcquireMutex 236db2bae30SDana Myers * 237db2bae30SDana Myers * PARAMETERS: TimeDesc - Timeout integer 238db2bae30SDana Myers * ObjDesc - Mutex object 239db2bae30SDana Myers * WalkState - Current method execution state 240db2bae30SDana Myers * 241db2bae30SDana Myers * RETURN: Status 242db2bae30SDana Myers * 243db2bae30SDana Myers * DESCRIPTION: Acquire an AML mutex 244db2bae30SDana Myers * 245db2bae30SDana Myers ******************************************************************************/ 246db2bae30SDana Myers 247db2bae30SDana Myers ACPI_STATUS 248db2bae30SDana Myers AcpiExAcquireMutex ( 249db2bae30SDana Myers ACPI_OPERAND_OBJECT *TimeDesc, 250db2bae30SDana Myers ACPI_OPERAND_OBJECT *ObjDesc, 251db2bae30SDana Myers ACPI_WALK_STATE *WalkState) 252db2bae30SDana Myers { 253db2bae30SDana Myers ACPI_STATUS Status; 254db2bae30SDana Myers 255db2bae30SDana Myers 256db2bae30SDana Myers ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc); 257db2bae30SDana Myers 258db2bae30SDana Myers 259db2bae30SDana Myers if (!ObjDesc) 260db2bae30SDana Myers { 261db2bae30SDana Myers return_ACPI_STATUS (AE_BAD_PARAMETER); 262db2bae30SDana Myers } 263db2bae30SDana Myers 26426f3cdf0SGordon Ross /* Must have a valid thread state struct */ 265db2bae30SDana Myers 266db2bae30SDana Myers if (!WalkState->Thread) 267db2bae30SDana Myers { 26826f3cdf0SGordon Ross ACPI_ERROR ((AE_INFO, 26926f3cdf0SGordon Ross "Cannot acquire Mutex [%4.4s], null thread info", 270db2bae30SDana Myers AcpiUtGetNodeName (ObjDesc->Mutex.Node))); 271db2bae30SDana Myers return_ACPI_STATUS (AE_AML_INTERNAL); 272db2bae30SDana Myers } 273db2bae30SDana Myers 274db2bae30SDana Myers /* 275*385cc6b4SJerry Jelinek * Current sync level must be less than or equal to the sync level 276*385cc6b4SJerry Jelinek * of the mutex. This mechanism provides some deadlock prevention. 277db2bae30SDana Myers */ 278db2bae30SDana Myers if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel) 279db2bae30SDana Myers { 280db2bae30SDana Myers ACPI_ERROR ((AE_INFO, 281*385cc6b4SJerry Jelinek "Cannot acquire Mutex [%4.4s], " 282*385cc6b4SJerry Jelinek "current SyncLevel is too large (%u)", 283db2bae30SDana Myers AcpiUtGetNodeName (ObjDesc->Mutex.Node), 284db2bae30SDana Myers WalkState->Thread->CurrentSyncLevel)); 285db2bae30SDana Myers return_ACPI_STATUS (AE_AML_MUTEX_ORDER); 286db2bae30SDana Myers } 287db2bae30SDana Myers 288*385cc6b4SJerry Jelinek ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 289*385cc6b4SJerry Jelinek "Acquiring: Mutex SyncLevel %u, Thread SyncLevel %u, " 290*385cc6b4SJerry Jelinek "Depth %u TID %p\n", 291*385cc6b4SJerry Jelinek ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel, 292*385cc6b4SJerry Jelinek ObjDesc->Mutex.AcquisitionDepth, WalkState->Thread)); 293*385cc6b4SJerry Jelinek 294db2bae30SDana Myers Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value, 295db2bae30SDana Myers ObjDesc, WalkState->Thread->ThreadId); 296*385cc6b4SJerry Jelinek 297db2bae30SDana Myers if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1) 298db2bae30SDana Myers { 299db2bae30SDana Myers /* Save Thread object, original/current sync levels */ 300db2bae30SDana Myers 301db2bae30SDana Myers ObjDesc->Mutex.OwnerThread = WalkState->Thread; 302*385cc6b4SJerry Jelinek ObjDesc->Mutex.OriginalSyncLevel = 303*385cc6b4SJerry Jelinek WalkState->Thread->CurrentSyncLevel; 304*385cc6b4SJerry Jelinek WalkState->Thread->CurrentSyncLevel = 305*385cc6b4SJerry Jelinek ObjDesc->Mutex.SyncLevel; 306db2bae30SDana Myers 307db2bae30SDana Myers /* Link the mutex to the current thread for force-unlock at method exit */ 308db2bae30SDana Myers 309db2bae30SDana Myers AcpiExLinkMutex (ObjDesc, WalkState->Thread); 310db2bae30SDana Myers } 311db2bae30SDana Myers 312*385cc6b4SJerry Jelinek ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 313*385cc6b4SJerry Jelinek "Acquired: Mutex SyncLevel %u, Thread SyncLevel %u, Depth %u\n", 314*385cc6b4SJerry Jelinek ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel, 315*385cc6b4SJerry Jelinek ObjDesc->Mutex.AcquisitionDepth)); 316*385cc6b4SJerry Jelinek 317db2bae30SDana Myers return_ACPI_STATUS (Status); 318db2bae30SDana Myers } 319db2bae30SDana Myers 320db2bae30SDana Myers 321db2bae30SDana Myers /******************************************************************************* 322db2bae30SDana Myers * 323db2bae30SDana Myers * FUNCTION: AcpiExReleaseMutexObject 324db2bae30SDana Myers * 325db2bae30SDana Myers * PARAMETERS: ObjDesc - The object descriptor for this op 326db2bae30SDana Myers * 327db2bae30SDana Myers * RETURN: Status 328db2bae30SDana Myers * 329db2bae30SDana Myers * DESCRIPTION: Release a previously acquired Mutex, low level interface. 330db2bae30SDana Myers * Provides a common path that supports multiple releases (after 331db2bae30SDana Myers * previous multiple acquires) by the same thread. 332db2bae30SDana Myers * 333db2bae30SDana Myers * MUTEX: Interpreter must be locked 334db2bae30SDana Myers * 335db2bae30SDana Myers * NOTE: This interface is called from three places: 336db2bae30SDana Myers * 1) From AcpiExReleaseMutex, via an AML Acquire() operator 337db2bae30SDana Myers * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the 338db2bae30SDana Myers * global lock 339db2bae30SDana Myers * 3) From the external interface, AcpiReleaseGlobalLock 340db2bae30SDana Myers * 341db2bae30SDana Myers ******************************************************************************/ 342db2bae30SDana Myers 343db2bae30SDana Myers ACPI_STATUS 344db2bae30SDana Myers AcpiExReleaseMutexObject ( 345db2bae30SDana Myers ACPI_OPERAND_OBJECT *ObjDesc) 346db2bae30SDana Myers { 347db2bae30SDana Myers ACPI_STATUS Status = AE_OK; 348db2bae30SDana Myers 349db2bae30SDana Myers 350db2bae30SDana Myers ACPI_FUNCTION_TRACE (ExReleaseMutexObject); 351db2bae30SDana Myers 352db2bae30SDana Myers 353db2bae30SDana Myers if (ObjDesc->Mutex.AcquisitionDepth == 0) 354db2bae30SDana Myers { 355*385cc6b4SJerry Jelinek return_ACPI_STATUS (AE_NOT_ACQUIRED); 356db2bae30SDana Myers } 357db2bae30SDana Myers 358db2bae30SDana Myers /* Match multiple Acquires with multiple Releases */ 359db2bae30SDana Myers 360db2bae30SDana Myers ObjDesc->Mutex.AcquisitionDepth--; 361db2bae30SDana Myers if (ObjDesc->Mutex.AcquisitionDepth != 0) 362db2bae30SDana Myers { 363db2bae30SDana Myers /* Just decrement the depth and return */ 364db2bae30SDana Myers 365db2bae30SDana Myers return_ACPI_STATUS (AE_OK); 366db2bae30SDana Myers } 367db2bae30SDana Myers 368db2bae30SDana Myers if (ObjDesc->Mutex.OwnerThread) 369db2bae30SDana Myers { 370db2bae30SDana Myers /* Unlink the mutex from the owner's list */ 371db2bae30SDana Myers 372db2bae30SDana Myers AcpiExUnlinkMutex (ObjDesc); 373db2bae30SDana Myers ObjDesc->Mutex.OwnerThread = NULL; 374db2bae30SDana Myers } 375db2bae30SDana Myers 376db2bae30SDana Myers /* Release the mutex, special case for Global Lock */ 377db2bae30SDana Myers 378db2bae30SDana Myers if (ObjDesc == AcpiGbl_GlobalLockMutex) 379db2bae30SDana Myers { 380db2bae30SDana Myers Status = AcpiEvReleaseGlobalLock (); 381db2bae30SDana Myers } 382db2bae30SDana Myers else 383db2bae30SDana Myers { 384db2bae30SDana Myers AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex); 385db2bae30SDana Myers } 386db2bae30SDana Myers 387db2bae30SDana Myers /* Clear mutex info */ 388db2bae30SDana Myers 389db2bae30SDana Myers ObjDesc->Mutex.ThreadId = 0; 390db2bae30SDana Myers return_ACPI_STATUS (Status); 391db2bae30SDana Myers } 392db2bae30SDana Myers 393db2bae30SDana Myers 394db2bae30SDana Myers /******************************************************************************* 395db2bae30SDana Myers * 396db2bae30SDana Myers * FUNCTION: AcpiExReleaseMutex 397db2bae30SDana Myers * 398db2bae30SDana Myers * PARAMETERS: ObjDesc - The object descriptor for this op 399db2bae30SDana Myers * WalkState - Current method execution state 400db2bae30SDana Myers * 401db2bae30SDana Myers * RETURN: Status 402db2bae30SDana Myers * 403db2bae30SDana Myers * DESCRIPTION: Release a previously acquired Mutex. 404db2bae30SDana Myers * 405db2bae30SDana Myers ******************************************************************************/ 406db2bae30SDana Myers 407db2bae30SDana Myers ACPI_STATUS 408db2bae30SDana Myers AcpiExReleaseMutex ( 409db2bae30SDana Myers ACPI_OPERAND_OBJECT *ObjDesc, 410db2bae30SDana Myers ACPI_WALK_STATE *WalkState) 411db2bae30SDana Myers { 412aa2aa9a6SDana Myers UINT8 PreviousSyncLevel; 41326f3cdf0SGordon Ross ACPI_THREAD_STATE *OwnerThread; 414*385cc6b4SJerry Jelinek ACPI_STATUS Status = AE_OK; 415db2bae30SDana Myers 416db2bae30SDana Myers 417db2bae30SDana Myers ACPI_FUNCTION_TRACE (ExReleaseMutex); 418db2bae30SDana Myers 419db2bae30SDana Myers 420db2bae30SDana Myers if (!ObjDesc) 421db2bae30SDana Myers { 422db2bae30SDana Myers return_ACPI_STATUS (AE_BAD_PARAMETER); 423db2bae30SDana Myers } 424db2bae30SDana Myers 42526f3cdf0SGordon Ross OwnerThread = ObjDesc->Mutex.OwnerThread; 42626f3cdf0SGordon Ross 427db2bae30SDana Myers /* The mutex must have been previously acquired in order to release it */ 428db2bae30SDana Myers 42926f3cdf0SGordon Ross if (!OwnerThread) 430db2bae30SDana Myers { 431db2bae30SDana Myers ACPI_ERROR ((AE_INFO, 43226f3cdf0SGordon Ross "Cannot release Mutex [%4.4s], not acquired", 43326f3cdf0SGordon Ross AcpiUtGetNodeName (ObjDesc->Mutex.Node))); 43426f3cdf0SGordon Ross return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED); 435db2bae30SDana Myers } 436db2bae30SDana Myers 437db2bae30SDana Myers /* Must have a valid thread ID */ 438db2bae30SDana Myers 439db2bae30SDana Myers if (!WalkState->Thread) 440db2bae30SDana Myers { 44126f3cdf0SGordon Ross ACPI_ERROR ((AE_INFO, 44226f3cdf0SGordon Ross "Cannot release Mutex [%4.4s], null thread info", 443db2bae30SDana Myers AcpiUtGetNodeName (ObjDesc->Mutex.Node))); 444db2bae30SDana Myers return_ACPI_STATUS (AE_AML_INTERNAL); 445db2bae30SDana Myers } 446db2bae30SDana Myers 447db2bae30SDana Myers /* 44826f3cdf0SGordon Ross * The Mutex is owned, but this thread must be the owner. 44926f3cdf0SGordon Ross * Special case for Global Lock, any thread can release 45026f3cdf0SGordon Ross */ 45126f3cdf0SGordon Ross if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) && 45226f3cdf0SGordon Ross (ObjDesc != AcpiGbl_GlobalLockMutex)) 45326f3cdf0SGordon Ross { 45426f3cdf0SGordon Ross ACPI_ERROR ((AE_INFO, 45526f3cdf0SGordon Ross "Thread %u cannot release Mutex [%4.4s] acquired by thread %u", 45626f3cdf0SGordon Ross (UINT32) WalkState->Thread->ThreadId, 45726f3cdf0SGordon Ross AcpiUtGetNodeName (ObjDesc->Mutex.Node), 45826f3cdf0SGordon Ross (UINT32) OwnerThread->ThreadId)); 45926f3cdf0SGordon Ross return_ACPI_STATUS (AE_AML_NOT_OWNER); 46026f3cdf0SGordon Ross } 46126f3cdf0SGordon Ross 46226f3cdf0SGordon Ross /* 463aa2aa9a6SDana Myers * The sync level of the mutex must be equal to the current sync level. In 464aa2aa9a6SDana Myers * other words, the current level means that at least one mutex at that 465aa2aa9a6SDana Myers * level is currently being held. Attempting to release a mutex of a 466aa2aa9a6SDana Myers * different level can only mean that the mutex ordering rule is being 467aa2aa9a6SDana Myers * violated. This behavior is clarified in ACPI 4.0 specification. 468db2bae30SDana Myers */ 46926f3cdf0SGordon Ross if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel) 470db2bae30SDana Myers { 471db2bae30SDana Myers ACPI_ERROR ((AE_INFO, 472*385cc6b4SJerry Jelinek "Cannot release Mutex [%4.4s], SyncLevel mismatch: " 473*385cc6b4SJerry Jelinek "mutex %u current %u", 474db2bae30SDana Myers AcpiUtGetNodeName (ObjDesc->Mutex.Node), 475db2bae30SDana Myers ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel)); 476db2bae30SDana Myers return_ACPI_STATUS (AE_AML_MUTEX_ORDER); 477db2bae30SDana Myers } 478db2bae30SDana Myers 479aa2aa9a6SDana Myers /* 480aa2aa9a6SDana Myers * Get the previous SyncLevel from the head of the acquired mutex list. 481aa2aa9a6SDana Myers * This handles the case where several mutexes at the same level have been 482aa2aa9a6SDana Myers * acquired, but are not released in reverse order. 483aa2aa9a6SDana Myers */ 484aa2aa9a6SDana Myers PreviousSyncLevel = 48526f3cdf0SGordon Ross OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel; 486aa2aa9a6SDana Myers 487*385cc6b4SJerry Jelinek ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 488*385cc6b4SJerry Jelinek "Releasing: Object SyncLevel %u, Thread SyncLevel %u, " 489*385cc6b4SJerry Jelinek "Prev SyncLevel %u, Depth %u TID %p\n", 490*385cc6b4SJerry Jelinek ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel, 491*385cc6b4SJerry Jelinek PreviousSyncLevel, ObjDesc->Mutex.AcquisitionDepth, 492*385cc6b4SJerry Jelinek WalkState->Thread)); 493*385cc6b4SJerry Jelinek 494db2bae30SDana Myers Status = AcpiExReleaseMutexObject (ObjDesc); 495aa2aa9a6SDana Myers if (ACPI_FAILURE (Status)) 496aa2aa9a6SDana Myers { 497aa2aa9a6SDana Myers return_ACPI_STATUS (Status); 498aa2aa9a6SDana Myers } 499db2bae30SDana Myers 500db2bae30SDana Myers if (ObjDesc->Mutex.AcquisitionDepth == 0) 501db2bae30SDana Myers { 502aa2aa9a6SDana Myers /* Restore the previous SyncLevel */ 503db2bae30SDana Myers 50426f3cdf0SGordon Ross OwnerThread->CurrentSyncLevel = PreviousSyncLevel; 505db2bae30SDana Myers } 50626f3cdf0SGordon Ross 507*385cc6b4SJerry Jelinek ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 508*385cc6b4SJerry Jelinek "Released: Object SyncLevel %u, Thread SyncLevel, %u, " 509*385cc6b4SJerry Jelinek "Prev SyncLevel %u, Depth %u\n", 510*385cc6b4SJerry Jelinek ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel, 511*385cc6b4SJerry Jelinek PreviousSyncLevel, ObjDesc->Mutex.AcquisitionDepth)); 512*385cc6b4SJerry Jelinek 513db2bae30SDana Myers return_ACPI_STATUS (Status); 514db2bae30SDana Myers } 515db2bae30SDana Myers 516db2bae30SDana Myers 517db2bae30SDana Myers /******************************************************************************* 518db2bae30SDana Myers * 519db2bae30SDana Myers * FUNCTION: AcpiExReleaseAllMutexes 520db2bae30SDana Myers * 521db2bae30SDana Myers * PARAMETERS: Thread - Current executing thread object 522db2bae30SDana Myers * 523db2bae30SDana Myers * RETURN: Status 524db2bae30SDana Myers * 525db2bae30SDana Myers * DESCRIPTION: Release all mutexes held by this thread 526db2bae30SDana Myers * 527db2bae30SDana Myers * NOTE: This function is called as the thread is exiting the interpreter. 528db2bae30SDana Myers * Mutexes are not released when an individual control method is exited, but 529db2bae30SDana Myers * only when the parent thread actually exits the interpreter. This allows one 530db2bae30SDana Myers * method to acquire a mutex, and a different method to release it, as long as 531db2bae30SDana Myers * this is performed underneath a single parent control method. 532db2bae30SDana Myers * 533db2bae30SDana Myers ******************************************************************************/ 534db2bae30SDana Myers 535db2bae30SDana Myers void 536db2bae30SDana Myers AcpiExReleaseAllMutexes ( 537db2bae30SDana Myers ACPI_THREAD_STATE *Thread) 538db2bae30SDana Myers { 539db2bae30SDana Myers ACPI_OPERAND_OBJECT *Next = Thread->AcquiredMutexList; 540db2bae30SDana Myers ACPI_OPERAND_OBJECT *ObjDesc; 541db2bae30SDana Myers 542db2bae30SDana Myers 543*385cc6b4SJerry Jelinek ACPI_FUNCTION_TRACE (ExReleaseAllMutexes); 544db2bae30SDana Myers 545db2bae30SDana Myers 546db2bae30SDana Myers /* Traverse the list of owned mutexes, releasing each one */ 547db2bae30SDana Myers 548db2bae30SDana Myers while (Next) 549db2bae30SDana Myers { 550db2bae30SDana Myers ObjDesc = Next; 551*385cc6b4SJerry Jelinek ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 552*385cc6b4SJerry Jelinek "Mutex [%4.4s] force-release, SyncLevel %u Depth %u\n", 553*385cc6b4SJerry Jelinek ObjDesc->Mutex.Node->Name.Ascii, ObjDesc->Mutex.SyncLevel, 554*385cc6b4SJerry Jelinek ObjDesc->Mutex.AcquisitionDepth)); 555db2bae30SDana Myers 556db2bae30SDana Myers /* Release the mutex, special case for Global Lock */ 557db2bae30SDana Myers 558db2bae30SDana Myers if (ObjDesc == AcpiGbl_GlobalLockMutex) 559db2bae30SDana Myers { 560db2bae30SDana Myers /* Ignore errors */ 561db2bae30SDana Myers 562db2bae30SDana Myers (void) AcpiEvReleaseGlobalLock (); 563db2bae30SDana Myers } 564db2bae30SDana Myers else 565db2bae30SDana Myers { 566db2bae30SDana Myers AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex); 567db2bae30SDana Myers } 568db2bae30SDana Myers 569db2bae30SDana Myers /* Update Thread SyncLevel (Last mutex is the important one) */ 570db2bae30SDana Myers 571db2bae30SDana Myers Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel; 572*385cc6b4SJerry Jelinek 573*385cc6b4SJerry Jelinek /* Mark mutex unowned */ 574*385cc6b4SJerry Jelinek 575*385cc6b4SJerry Jelinek Next = ObjDesc->Mutex.Next; 576*385cc6b4SJerry Jelinek 577*385cc6b4SJerry Jelinek ObjDesc->Mutex.Prev = NULL; 578*385cc6b4SJerry Jelinek ObjDesc->Mutex.Next = NULL; 579*385cc6b4SJerry Jelinek ObjDesc->Mutex.AcquisitionDepth = 0; 580*385cc6b4SJerry Jelinek ObjDesc->Mutex.OwnerThread = NULL; 581*385cc6b4SJerry Jelinek ObjDesc->Mutex.ThreadId = 0; 582db2bae30SDana Myers } 583*385cc6b4SJerry Jelinek 584*385cc6b4SJerry Jelinek return_VOID; 585db2bae30SDana Myers } 586