177422Smsmith/******************************************************************************
277422Smsmith *
377422Smsmith * Module Name: exmutex - ASL Mutex Acquire/Release functions
477422Smsmith *
577422Smsmith *****************************************************************************/
677422Smsmith
7217365Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp.
977422Smsmith * All rights reserved.
1077422Smsmith *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
2577422Smsmith *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
2977422Smsmith *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
4377422Smsmith
44193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
45193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
46193341Sjkim#include <contrib/dev/acpica/include/acinterp.h>
47193341Sjkim#include <contrib/dev/acpica/include/acevents.h>
4877422Smsmith
4977422Smsmith#define _COMPONENT          ACPI_EXECUTER
5091116Smsmith        ACPI_MODULE_NAME    ("exmutex")
5177422Smsmith
52151937Sjkim/* Local prototypes */
5377422Smsmith
54151937Sjkimstatic void
55151937SjkimAcpiExLinkMutex (
56151937Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
57151937Sjkim    ACPI_THREAD_STATE       *Thread);
58151937Sjkim
59151937Sjkim
6077422Smsmith/*******************************************************************************
6177422Smsmith *
6277422Smsmith * FUNCTION:    AcpiExUnlinkMutex
6377422Smsmith *
64129684Snjl * PARAMETERS:  ObjDesc             - The mutex to be unlinked
6577422Smsmith *
66151937Sjkim * RETURN:      None
6777422Smsmith *
6877422Smsmith * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list
6977422Smsmith *
7077422Smsmith ******************************************************************************/
7177422Smsmith
7277422Smsmithvoid
7377422SmsmithAcpiExUnlinkMutex (
7477422Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc)
7577422Smsmith{
7687031Smsmith    ACPI_THREAD_STATE       *Thread = ObjDesc->Mutex.OwnerThread;
7777422Smsmith
7887031Smsmith
7987031Smsmith    if (!Thread)
8087031Smsmith    {
8187031Smsmith        return;
8287031Smsmith    }
8387031Smsmith
84129684Snjl    /* Doubly linked list */
85129684Snjl
8677422Smsmith    if (ObjDesc->Mutex.Next)
8777422Smsmith    {
8877422Smsmith        (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev;
8977422Smsmith    }
9087031Smsmith
9177422Smsmith    if (ObjDesc->Mutex.Prev)
9277422Smsmith    {
9377422Smsmith        (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next;
94193267Sjkim
95193267Sjkim        /*
96206117Sjkim         * Migrate the previous sync level associated with this mutex to
97206117Sjkim         * the previous mutex on the list so that it may be preserved.
98206117Sjkim         * This handles the case where several mutexes have been acquired
99206117Sjkim         * at the same level, but are not released in opposite order.
100193267Sjkim         */
101193267Sjkim        (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel =
102193267Sjkim            ObjDesc->Mutex.OriginalSyncLevel;
10377422Smsmith    }
10487031Smsmith    else
10587031Smsmith    {
10687031Smsmith        Thread->AcquiredMutexList = ObjDesc->Mutex.Next;
10787031Smsmith    }
10877422Smsmith}
10977422Smsmith
11077422Smsmith
11177422Smsmith/*******************************************************************************
11277422Smsmith *
11377422Smsmith * FUNCTION:    AcpiExLinkMutex
11477422Smsmith *
115206117Sjkim * PARAMETERS:  ObjDesc             - The mutex to be linked
116206117Sjkim *              Thread              - Current executing thread object
11777422Smsmith *
118151937Sjkim * RETURN:      None
11977422Smsmith *
12077422Smsmith * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk
12177422Smsmith *
12277422Smsmith ******************************************************************************/
12377422Smsmith
124151937Sjkimstatic void
12577422SmsmithAcpiExLinkMutex (
12677422Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
12787031Smsmith    ACPI_THREAD_STATE       *Thread)
12877422Smsmith{
12987031Smsmith    ACPI_OPERAND_OBJECT     *ListHead;
13077422Smsmith
13187031Smsmith
13287031Smsmith    ListHead = Thread->AcquiredMutexList;
13387031Smsmith
13477422Smsmith    /* This object will be the first object in the list */
13577422Smsmith
13687031Smsmith    ObjDesc->Mutex.Prev = NULL;
13787031Smsmith    ObjDesc->Mutex.Next = ListHead;
13877422Smsmith
13977422Smsmith    /* Update old first object to point back to this object */
14077422Smsmith
14187031Smsmith    if (ListHead)
14277422Smsmith    {
14387031Smsmith        ListHead->Mutex.Prev = ObjDesc;
14477422Smsmith    }
14577422Smsmith
14677422Smsmith    /* Update list head */
14777422Smsmith
14887031Smsmith    Thread->AcquiredMutexList = ObjDesc;
14977422Smsmith}
15077422Smsmith
15177422Smsmith
15277422Smsmith/*******************************************************************************
15377422Smsmith *
154167802Sjkim * FUNCTION:    AcpiExAcquireMutexObject
155167802Sjkim *
156206117Sjkim * PARAMETERS:  Timeout             - Timeout in milliseconds
157167802Sjkim *              ObjDesc             - Mutex object
158206117Sjkim *              ThreadId            - Current thread state
159167802Sjkim *
160167802Sjkim * RETURN:      Status
161167802Sjkim *
162167802Sjkim * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
163167802Sjkim *              path that supports multiple acquires by the same thread.
164167802Sjkim *
165167802Sjkim * MUTEX:       Interpreter must be locked
166167802Sjkim *
167167802Sjkim * NOTE: This interface is called from three places:
168167802Sjkim * 1) From AcpiExAcquireMutex, via an AML Acquire() operator
169167802Sjkim * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the
170167802Sjkim *    global lock
171167802Sjkim * 3) From the external interface, AcpiAcquireGlobalLock
172167802Sjkim *
173167802Sjkim ******************************************************************************/
174167802Sjkim
175167802SjkimACPI_STATUS
176167802SjkimAcpiExAcquireMutexObject (
177167802Sjkim    UINT16                  Timeout,
178167802Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
179167802Sjkim    ACPI_THREAD_ID          ThreadId)
180167802Sjkim{
181167802Sjkim    ACPI_STATUS             Status;
182167802Sjkim
183167802Sjkim
184167802Sjkim    ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc);
185167802Sjkim
186167802Sjkim
187167802Sjkim    if (!ObjDesc)
188167802Sjkim    {
189167802Sjkim        return_ACPI_STATUS (AE_BAD_PARAMETER);
190167802Sjkim    }
191167802Sjkim
192167802Sjkim    /* Support for multiple acquires by the owning thread */
193167802Sjkim
194167802Sjkim    if (ObjDesc->Mutex.ThreadId == ThreadId)
195167802Sjkim    {
196167802Sjkim        /*
197167802Sjkim         * The mutex is already owned by this thread, just increment the
198167802Sjkim         * acquisition depth
199167802Sjkim         */
200167802Sjkim        ObjDesc->Mutex.AcquisitionDepth++;
201167802Sjkim        return_ACPI_STATUS (AE_OK);
202167802Sjkim    }
203167802Sjkim
204167802Sjkim    /* Acquire the mutex, wait if necessary. Special case for Global Lock */
205167802Sjkim
206167802Sjkim    if (ObjDesc == AcpiGbl_GlobalLockMutex)
207167802Sjkim    {
208167802Sjkim        Status = AcpiEvAcquireGlobalLock (Timeout);
209167802Sjkim    }
210167802Sjkim    else
211167802Sjkim    {
212306536Sjkim        Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex, Timeout);
213167802Sjkim    }
214167802Sjkim
215167802Sjkim    if (ACPI_FAILURE (Status))
216167802Sjkim    {
217167802Sjkim        /* Includes failure from a timeout on TimeDesc */
218167802Sjkim
219167802Sjkim        return_ACPI_STATUS (Status);
220167802Sjkim    }
221167802Sjkim
222167802Sjkim    /* Acquired the mutex: update mutex object */
223167802Sjkim
224167802Sjkim    ObjDesc->Mutex.ThreadId = ThreadId;
225167802Sjkim    ObjDesc->Mutex.AcquisitionDepth = 1;
226167802Sjkim    ObjDesc->Mutex.OriginalSyncLevel = 0;
227167802Sjkim    ObjDesc->Mutex.OwnerThread = NULL;      /* Used only for AML Acquire() */
228167802Sjkim
229167802Sjkim    return_ACPI_STATUS (AE_OK);
230167802Sjkim}
231167802Sjkim
232167802Sjkim
233167802Sjkim/*******************************************************************************
234167802Sjkim *
23577422Smsmith * FUNCTION:    AcpiExAcquireMutex
23677422Smsmith *
237151937Sjkim * PARAMETERS:  TimeDesc            - Timeout integer
238151937Sjkim *              ObjDesc             - Mutex object
239151937Sjkim *              WalkState           - Current method execution state
24077422Smsmith *
24177422Smsmith * RETURN:      Status
24277422Smsmith *
24377422Smsmith * DESCRIPTION: Acquire an AML mutex
24477422Smsmith *
24577422Smsmith ******************************************************************************/
24677422Smsmith
24777422SmsmithACPI_STATUS
24877422SmsmithAcpiExAcquireMutex (
24977422Smsmith    ACPI_OPERAND_OBJECT     *TimeDesc,
25077422Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
25177422Smsmith    ACPI_WALK_STATE         *WalkState)
25277422Smsmith{
25377422Smsmith    ACPI_STATUS             Status;
25477422Smsmith
25577422Smsmith
256167802Sjkim    ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc);
25777422Smsmith
258107325Siwasaki
25977422Smsmith    if (!ObjDesc)
26077422Smsmith    {
26177422Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
26277422Smsmith    }
26377422Smsmith
264206117Sjkim    /* Must have a valid thread state struct */
265107325Siwasaki
266107325Siwasaki    if (!WalkState->Thread)
267107325Siwasaki    {
268206117Sjkim        ACPI_ERROR ((AE_INFO,
269206117Sjkim            "Cannot acquire Mutex [%4.4s], null thread info",
270151937Sjkim            AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
271107325Siwasaki        return_ACPI_STATUS (AE_AML_INTERNAL);
272107325Siwasaki    }
273107325Siwasaki
27477422Smsmith    /*
275306536Sjkim     * Current sync level must be less than or equal to the sync level
276306536Sjkim     * of the mutex. This mechanism provides some deadlock prevention.
27777422Smsmith     */
27887031Smsmith    if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel)
27977422Smsmith    {
280167802Sjkim        ACPI_ERROR ((AE_INFO,
281306536Sjkim            "Cannot acquire Mutex [%4.4s], "
282306536Sjkim            "current SyncLevel is too large (%u)",
283167802Sjkim            AcpiUtGetNodeName (ObjDesc->Mutex.Node),
284167802Sjkim            WalkState->Thread->CurrentSyncLevel));
28577422Smsmith        return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
28677422Smsmith    }
28777422Smsmith
288306536Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
289306536Sjkim        "Acquiring: Mutex SyncLevel %u, Thread SyncLevel %u, "
290306536Sjkim        "Depth %u TID %p\n",
291306536Sjkim        ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel,
292306536Sjkim        ObjDesc->Mutex.AcquisitionDepth, WalkState->Thread));
293306536Sjkim
294167802Sjkim    Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value,
295306536Sjkim        ObjDesc, WalkState->Thread->ThreadId);
296306536Sjkim
297167802Sjkim    if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1)
298127175Snjl    {
299167802Sjkim        /* Save Thread object, original/current sync levels */
300107325Siwasaki
301167802Sjkim        ObjDesc->Mutex.OwnerThread = WalkState->Thread;
302306536Sjkim        ObjDesc->Mutex.OriginalSyncLevel =
303306536Sjkim            WalkState->Thread->CurrentSyncLevel;
304306536Sjkim        WalkState->Thread->CurrentSyncLevel =
305306536Sjkim            ObjDesc->Mutex.SyncLevel;
306167802Sjkim
307167802Sjkim        /* Link the mutex to the current thread for force-unlock at method exit */
308167802Sjkim
309167802Sjkim        AcpiExLinkMutex (ObjDesc, WalkState->Thread);
31077422Smsmith    }
31177422Smsmith
312306536Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
313306536Sjkim        "Acquired: Mutex SyncLevel %u, Thread SyncLevel %u, Depth %u\n",
314306536Sjkim        ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel,
315306536Sjkim        ObjDesc->Mutex.AcquisitionDepth));
316306536Sjkim
317167802Sjkim    return_ACPI_STATUS (Status);
318167802Sjkim}
31977422Smsmith
320167802Sjkim
321167802Sjkim/*******************************************************************************
322167802Sjkim *
323167802Sjkim * FUNCTION:    AcpiExReleaseMutexObject
324167802Sjkim *
325167802Sjkim * PARAMETERS:  ObjDesc             - The object descriptor for this op
326167802Sjkim *
327167802Sjkim * RETURN:      Status
328167802Sjkim *
329167802Sjkim * DESCRIPTION: Release a previously acquired Mutex, low level interface.
330167802Sjkim *              Provides a common path that supports multiple releases (after
331167802Sjkim *              previous multiple acquires) by the same thread.
332167802Sjkim *
333167802Sjkim * MUTEX:       Interpreter must be locked
334167802Sjkim *
335167802Sjkim * NOTE: This interface is called from three places:
336167802Sjkim * 1) From AcpiExReleaseMutex, via an AML Acquire() operator
337167802Sjkim * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the
338167802Sjkim *    global lock
339167802Sjkim * 3) From the external interface, AcpiReleaseGlobalLock
340167802Sjkim *
341167802Sjkim ******************************************************************************/
342167802Sjkim
343167802SjkimACPI_STATUS
344167802SjkimAcpiExReleaseMutexObject (
345167802Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc)
346167802Sjkim{
347167802Sjkim    ACPI_STATUS             Status = AE_OK;
348167802Sjkim
349167802Sjkim
350167802Sjkim    ACPI_FUNCTION_TRACE (ExReleaseMutexObject);
351167802Sjkim
352167802Sjkim
353167802Sjkim    if (ObjDesc->Mutex.AcquisitionDepth == 0)
35477422Smsmith    {
355241973Sjkim        return_ACPI_STATUS (AE_NOT_ACQUIRED);
356167802Sjkim    }
35777422Smsmith
358167802Sjkim    /* Match multiple Acquires with multiple Releases */
359167802Sjkim
360167802Sjkim    ObjDesc->Mutex.AcquisitionDepth--;
361167802Sjkim    if (ObjDesc->Mutex.AcquisitionDepth != 0)
362167802Sjkim    {
363167802Sjkim        /* Just decrement the depth and return */
364167802Sjkim
365167802Sjkim        return_ACPI_STATUS (AE_OK);
36677422Smsmith    }
36777422Smsmith
368167802Sjkim    if (ObjDesc->Mutex.OwnerThread)
369167802Sjkim    {
370167802Sjkim        /* Unlink the mutex from the owner's list */
37177422Smsmith
372167802Sjkim        AcpiExUnlinkMutex (ObjDesc);
373167802Sjkim        ObjDesc->Mutex.OwnerThread = NULL;
374167802Sjkim    }
37577422Smsmith
376167802Sjkim    /* Release the mutex, special case for Global Lock */
37777422Smsmith
378167802Sjkim    if (ObjDesc == AcpiGbl_GlobalLockMutex)
379167802Sjkim    {
380167802Sjkim        Status = AcpiEvReleaseGlobalLock ();
381167802Sjkim    }
382167802Sjkim    else
383167802Sjkim    {
384167802Sjkim        AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
385167802Sjkim    }
38677422Smsmith
387167802Sjkim    /* Clear mutex info */
38887031Smsmith
389167802Sjkim    ObjDesc->Mutex.ThreadId = 0;
390167802Sjkim    return_ACPI_STATUS (Status);
39177422Smsmith}
39277422Smsmith
39377422Smsmith
39477422Smsmith/*******************************************************************************
39577422Smsmith *
39677422Smsmith * FUNCTION:    AcpiExReleaseMutex
39777422Smsmith *
398129684Snjl * PARAMETERS:  ObjDesc             - The object descriptor for this op
399151937Sjkim *              WalkState           - Current method execution state
40077422Smsmith *
40177422Smsmith * RETURN:      Status
40277422Smsmith *
40377422Smsmith * DESCRIPTION: Release a previously acquired Mutex.
40477422Smsmith *
40577422Smsmith ******************************************************************************/
40677422Smsmith
40777422SmsmithACPI_STATUS
40877422SmsmithAcpiExReleaseMutex (
40977422Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
41077422Smsmith    ACPI_WALK_STATE         *WalkState)
41177422Smsmith{
412193267Sjkim    UINT8                   PreviousSyncLevel;
413204773Sjkim    ACPI_THREAD_STATE       *OwnerThread;
414306536Sjkim    ACPI_STATUS             Status = AE_OK;
41577422Smsmith
41677422Smsmith
417167802Sjkim    ACPI_FUNCTION_TRACE (ExReleaseMutex);
41877422Smsmith
41977422Smsmith
42077422Smsmith    if (!ObjDesc)
42177422Smsmith    {
42277422Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
42377422Smsmith    }
42477422Smsmith
425204773Sjkim    OwnerThread = ObjDesc->Mutex.OwnerThread;
426204773Sjkim
42783174Smsmith    /* The mutex must have been previously acquired in order to release it */
42877422Smsmith
429204773Sjkim    if (!OwnerThread)
43077422Smsmith    {
431206117Sjkim        ACPI_ERROR ((AE_INFO,
432206117Sjkim            "Cannot release Mutex [%4.4s], not acquired",
433167802Sjkim            AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
43477422Smsmith        return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
43577422Smsmith    }
43677422Smsmith
437200553Sjkim    /* Must have a valid thread ID */
438200553Sjkim
439200553Sjkim    if (!WalkState->Thread)
440200553Sjkim    {
441206117Sjkim        ACPI_ERROR ((AE_INFO,
442206117Sjkim            "Cannot release Mutex [%4.4s], null thread info",
443200553Sjkim            AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
444200553Sjkim        return_ACPI_STATUS (AE_AML_INTERNAL);
445200553Sjkim    }
446200553Sjkim
447129684Snjl    /*
448127175Snjl     * The Mutex is owned, but this thread must be the owner.
449127175Snjl     * Special case for Global Lock, any thread can release
450127175Snjl     */
451204773Sjkim    if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) &&
452167802Sjkim        (ObjDesc != AcpiGbl_GlobalLockMutex))
45377422Smsmith    {
454167802Sjkim        ACPI_ERROR ((AE_INFO,
455212761Sjkim            "Thread %u cannot release Mutex [%4.4s] acquired by thread %u",
456212761Sjkim            (UINT32) WalkState->Thread->ThreadId,
457123315Snjl            AcpiUtGetNodeName (ObjDesc->Mutex.Node),
458212761Sjkim            (UINT32) OwnerThread->ThreadId));
45977422Smsmith        return_ACPI_STATUS (AE_AML_NOT_OWNER);
46077422Smsmith    }
46177422Smsmith
46277422Smsmith    /*
463193267Sjkim     * The sync level of the mutex must be equal to the current sync level. In
464193267Sjkim     * other words, the current level means that at least one mutex at that
465193267Sjkim     * level is currently being held. Attempting to release a mutex of a
466193267Sjkim     * different level can only mean that the mutex ordering rule is being
467193267Sjkim     * violated. This behavior is clarified in ACPI 4.0 specification.
46877422Smsmith     */
469204773Sjkim    if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel)
47077422Smsmith    {
471167802Sjkim        ACPI_ERROR ((AE_INFO,
472306536Sjkim            "Cannot release Mutex [%4.4s], SyncLevel mismatch: "
473306536Sjkim            "mutex %u current %u",
474167802Sjkim            AcpiUtGetNodeName (ObjDesc->Mutex.Node),
475167802Sjkim            ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel));
47677422Smsmith        return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
47777422Smsmith    }
47877422Smsmith
479193267Sjkim    /*
480193267Sjkim     * Get the previous SyncLevel from the head of the acquired mutex list.
481193267Sjkim     * This handles the case where several mutexes at the same level have been
482193267Sjkim     * acquired, but are not released in reverse order.
483193267Sjkim     */
484193267Sjkim    PreviousSyncLevel =
485204773Sjkim        OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel;
486193267Sjkim
487306536Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
488306536Sjkim        "Releasing: Object SyncLevel %u, Thread SyncLevel %u, "
489306536Sjkim        "Prev SyncLevel %u, Depth %u TID %p\n",
490306536Sjkim        ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel,
491306536Sjkim        PreviousSyncLevel, ObjDesc->Mutex.AcquisitionDepth,
492306536Sjkim        WalkState->Thread));
493306536Sjkim
494167802Sjkim    Status = AcpiExReleaseMutexObject (ObjDesc);
495193267Sjkim    if (ACPI_FAILURE (Status))
496193267Sjkim    {
497193267Sjkim        return_ACPI_STATUS (Status);
498193267Sjkim    }
499129684Snjl
500167802Sjkim    if (ObjDesc->Mutex.AcquisitionDepth == 0)
50177422Smsmith    {
502193267Sjkim        /* Restore the previous SyncLevel */
50377422Smsmith
504204773Sjkim        OwnerThread->CurrentSyncLevel = PreviousSyncLevel;
50577422Smsmith    }
506206117Sjkim
507306536Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
508306536Sjkim        "Released: Object SyncLevel %u, Thread SyncLevel, %u, "
509306536Sjkim        "Prev SyncLevel %u, Depth %u\n",
510306536Sjkim        ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel,
511306536Sjkim        PreviousSyncLevel, ObjDesc->Mutex.AcquisitionDepth));
512306536Sjkim
51377422Smsmith    return_ACPI_STATUS (Status);
51477422Smsmith}
51577422Smsmith
51677422Smsmith
51777422Smsmith/*******************************************************************************
51877422Smsmith *
51977422Smsmith * FUNCTION:    AcpiExReleaseAllMutexes
52077422Smsmith *
521206117Sjkim * PARAMETERS:  Thread              - Current executing thread object
52277422Smsmith *
52377422Smsmith * RETURN:      Status
52477422Smsmith *
525151937Sjkim * DESCRIPTION: Release all mutexes held by this thread
52677422Smsmith *
527167802Sjkim * NOTE: This function is called as the thread is exiting the interpreter.
528167802Sjkim * Mutexes are not released when an individual control method is exited, but
529167802Sjkim * only when the parent thread actually exits the interpreter. This allows one
530167802Sjkim * method to acquire a mutex, and a different method to release it, as long as
531167802Sjkim * this is performed underneath a single parent control method.
532167802Sjkim *
53377422Smsmith ******************************************************************************/
53477422Smsmith
53599679Siwasakivoid
53677422SmsmithAcpiExReleaseAllMutexes (
53787031Smsmith    ACPI_THREAD_STATE       *Thread)
53877422Smsmith{
53987031Smsmith    ACPI_OPERAND_OBJECT     *Next = Thread->AcquiredMutexList;
540167802Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc;
54177422Smsmith
54277422Smsmith
543306536Sjkim    ACPI_FUNCTION_TRACE (ExReleaseAllMutexes);
54483174Smsmith
54583174Smsmith
546129684Snjl    /* Traverse the list of owned mutexes, releasing each one */
547129684Snjl
54877422Smsmith    while (Next)
54977422Smsmith    {
550167802Sjkim        ObjDesc = Next;
551241973Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
552306536Sjkim            "Mutex [%4.4s] force-release, SyncLevel %u Depth %u\n",
553306536Sjkim            ObjDesc->Mutex.Node->Name.Ascii, ObjDesc->Mutex.SyncLevel,
554306536Sjkim            ObjDesc->Mutex.AcquisitionDepth));
555241973Sjkim
556167802Sjkim        /* Release the mutex, special case for Global Lock */
55777422Smsmith
558167802Sjkim        if (ObjDesc == AcpiGbl_GlobalLockMutex)
55999679Siwasaki        {
560167802Sjkim            /* Ignore errors */
561167802Sjkim
562167802Sjkim            (void) AcpiEvReleaseGlobalLock ();
56399679Siwasaki        }
564167802Sjkim        else
565167802Sjkim        {
566167802Sjkim            AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
567167802Sjkim        }
56887031Smsmith
569306536Sjkim        /* Update Thread SyncLevel (Last mutex is the important one) */
570306536Sjkim
571306536Sjkim        Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;
572306536Sjkim
57387031Smsmith        /* Mark mutex unowned */
57487031Smsmith
575306536Sjkim        Next = ObjDesc->Mutex.Next;
576306536Sjkim
577306536Sjkim        ObjDesc->Mutex.Prev = NULL;
578306536Sjkim        ObjDesc->Mutex.Next = NULL;
579306536Sjkim        ObjDesc->Mutex.AcquisitionDepth = 0;
580167802Sjkim        ObjDesc->Mutex.OwnerThread = NULL;
581167802Sjkim        ObjDesc->Mutex.ThreadId = 0;
582306536Sjkim    }
583129684Snjl
584306536Sjkim    return_VOID;
58577422Smsmith}
586