177422Smsmith/******************************************************************************
277422Smsmith *
377422Smsmith * Module Name: exmutex - ASL Mutex Acquire/Release functions
477422Smsmith *
577422Smsmith *****************************************************************************/
677422Smsmith
7316303Sjkim/******************************************************************************
8316303Sjkim *
9316303Sjkim * 1. Copyright Notice
10316303Sjkim *
11316303Sjkim * Some or all of this work - Copyright (c) 1999 - 2017, Intel Corp.
1277422Smsmith * All rights reserved.
1377422Smsmith *
14316303Sjkim * 2. License
15316303Sjkim *
16316303Sjkim * 2.1. This is your license from Intel Corp. under its intellectual property
17316303Sjkim * rights. You may have additional license terms from the party that provided
18316303Sjkim * you this software, covering your right to use that party's intellectual
19316303Sjkim * property rights.
20316303Sjkim *
21316303Sjkim * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
22316303Sjkim * copy of the source code appearing in this file ("Covered Code") an
23316303Sjkim * irrevocable, perpetual, worldwide license under Intel's copyrights in the
24316303Sjkim * base code distributed originally by Intel ("Original Intel Code") to copy,
25316303Sjkim * make derivatives, distribute, use and display any portion of the Covered
26316303Sjkim * Code in any form, with the right to sublicense such rights; and
27316303Sjkim *
28316303Sjkim * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
29316303Sjkim * license (with the right to sublicense), under only those claims of Intel
30316303Sjkim * patents that are infringed by the Original Intel Code, to make, use, sell,
31316303Sjkim * offer to sell, and import the Covered Code and derivative works thereof
32316303Sjkim * solely to the minimum extent necessary to exercise the above copyright
33316303Sjkim * license, and in no event shall the patent license extend to any additions
34316303Sjkim * to or modifications of the Original Intel Code. No other license or right
35316303Sjkim * is granted directly or by implication, estoppel or otherwise;
36316303Sjkim *
37316303Sjkim * The above copyright and patent license is granted only if the following
38316303Sjkim * conditions are met:
39316303Sjkim *
40316303Sjkim * 3. Conditions
41316303Sjkim *
42316303Sjkim * 3.1. Redistribution of Source with Rights to Further Distribute Source.
43316303Sjkim * Redistribution of source code of any substantial portion of the Covered
44316303Sjkim * Code or modification with rights to further distribute source must include
45316303Sjkim * the above Copyright Notice, the above License, this list of Conditions,
46316303Sjkim * and the following Disclaimer and Export Compliance provision. In addition,
47316303Sjkim * Licensee must cause all Covered Code to which Licensee contributes to
48316303Sjkim * contain a file documenting the changes Licensee made to create that Covered
49316303Sjkim * Code and the date of any change. Licensee must include in that file the
50316303Sjkim * documentation of any changes made by any predecessor Licensee. Licensee
51316303Sjkim * must include a prominent statement that the modification is derived,
52316303Sjkim * directly or indirectly, from Original Intel Code.
53316303Sjkim *
54316303Sjkim * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
55316303Sjkim * Redistribution of source code of any substantial portion of the Covered
56316303Sjkim * Code or modification without rights to further distribute source must
57316303Sjkim * include the following Disclaimer and Export Compliance provision in the
58316303Sjkim * documentation and/or other materials provided with distribution. In
59316303Sjkim * addition, Licensee may not authorize further sublicense of source of any
60316303Sjkim * portion of the Covered Code, and must include terms to the effect that the
61316303Sjkim * license from Licensee to its licensee is limited to the intellectual
62316303Sjkim * property embodied in the software Licensee provides to its licensee, and
63316303Sjkim * not to intellectual property embodied in modifications its licensee may
64316303Sjkim * make.
65316303Sjkim *
66316303Sjkim * 3.3. Redistribution of Executable. Redistribution in executable form of any
67316303Sjkim * substantial portion of the Covered Code or modification must reproduce the
68316303Sjkim * above Copyright Notice, and the following Disclaimer and Export Compliance
69316303Sjkim * provision in the documentation and/or other materials provided with the
70316303Sjkim * distribution.
71316303Sjkim *
72316303Sjkim * 3.4. Intel retains all right, title, and interest in and to the Original
73316303Sjkim * Intel Code.
74316303Sjkim *
75316303Sjkim * 3.5. Neither the name Intel nor any other trademark owned or controlled by
76316303Sjkim * Intel shall be used in advertising or otherwise to promote the sale, use or
77316303Sjkim * other dealings in products derived from or relating to the Covered Code
78316303Sjkim * without prior written authorization from Intel.
79316303Sjkim *
80316303Sjkim * 4. Disclaimer and Export Compliance
81316303Sjkim *
82316303Sjkim * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
83316303Sjkim * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
84316303Sjkim * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
85316303Sjkim * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
86316303Sjkim * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
87316303Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
88316303Sjkim * PARTICULAR PURPOSE.
89316303Sjkim *
90316303Sjkim * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
91316303Sjkim * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
92316303Sjkim * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
93316303Sjkim * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
94316303Sjkim * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
95316303Sjkim * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
96316303Sjkim * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
97316303Sjkim * LIMITED REMEDY.
98316303Sjkim *
99316303Sjkim * 4.3. Licensee shall not export, either directly or indirectly, any of this
100316303Sjkim * software or system incorporating such software without first obtaining any
101316303Sjkim * required license or other approval from the U. S. Department of Commerce or
102316303Sjkim * any other agency or department of the United States Government. In the
103316303Sjkim * event Licensee exports any such software from the United States or
104316303Sjkim * re-exports any such software from a foreign destination, Licensee shall
105316303Sjkim * ensure that the distribution and export/re-export of the software is in
106316303Sjkim * compliance with all laws, regulations, orders, or other restrictions of the
107316303Sjkim * U.S. Export Administration Regulations. Licensee agrees that neither it nor
108316303Sjkim * any of its subsidiaries will export/re-export any technical data, process,
109316303Sjkim * software, or service, directly or indirectly, to any country for which the
110316303Sjkim * United States government or any agency thereof requires an export license,
111316303Sjkim * other governmental approval, or letter of assurance, without first obtaining
112316303Sjkim * such license, approval or letter.
113316303Sjkim *
114316303Sjkim *****************************************************************************
115316303Sjkim *
116316303Sjkim * Alternatively, you may choose to be licensed under the terms of the
117316303Sjkim * following license:
118316303Sjkim *
119217365Sjkim * Redistribution and use in source and binary forms, with or without
120217365Sjkim * modification, are permitted provided that the following conditions
121217365Sjkim * are met:
122217365Sjkim * 1. Redistributions of source code must retain the above copyright
123217365Sjkim *    notice, this list of conditions, and the following disclaimer,
124217365Sjkim *    without modification.
125217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
126217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
127217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
128217365Sjkim *    including a substantially similar Disclaimer requirement for further
129217365Sjkim *    binary redistribution.
130217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
131217365Sjkim *    of any contributors may be used to endorse or promote products derived
132217365Sjkim *    from this software without specific prior written permission.
13377422Smsmith *
134316303Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
135316303Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
136316303Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
137316303Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
138316303Sjkim * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
139316303Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
140316303Sjkim * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
141316303Sjkim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
142316303Sjkim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
143316303Sjkim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
144316303Sjkim * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
145316303Sjkim *
146316303Sjkim * Alternatively, you may choose to be licensed under the terms of the
147217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
148217365Sjkim * Software Foundation.
14977422Smsmith *
150316303Sjkim *****************************************************************************/
15177422Smsmith
152193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
153193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
154193341Sjkim#include <contrib/dev/acpica/include/acinterp.h>
155193341Sjkim#include <contrib/dev/acpica/include/acevents.h>
15677422Smsmith
15777422Smsmith#define _COMPONENT          ACPI_EXECUTER
15891116Smsmith        ACPI_MODULE_NAME    ("exmutex")
15977422Smsmith
160151937Sjkim/* Local prototypes */
16177422Smsmith
162151937Sjkimstatic void
163151937SjkimAcpiExLinkMutex (
164151937Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
165151937Sjkim    ACPI_THREAD_STATE       *Thread);
166151937Sjkim
167151937Sjkim
16877422Smsmith/*******************************************************************************
16977422Smsmith *
17077422Smsmith * FUNCTION:    AcpiExUnlinkMutex
17177422Smsmith *
172129684Snjl * PARAMETERS:  ObjDesc             - The mutex to be unlinked
17377422Smsmith *
174151937Sjkim * RETURN:      None
17577422Smsmith *
17677422Smsmith * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list
17777422Smsmith *
17877422Smsmith ******************************************************************************/
17977422Smsmith
18077422Smsmithvoid
18177422SmsmithAcpiExUnlinkMutex (
18277422Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc)
18377422Smsmith{
18487031Smsmith    ACPI_THREAD_STATE       *Thread = ObjDesc->Mutex.OwnerThread;
18577422Smsmith
18687031Smsmith
18787031Smsmith    if (!Thread)
18887031Smsmith    {
18987031Smsmith        return;
19087031Smsmith    }
19187031Smsmith
192129684Snjl    /* Doubly linked list */
193129684Snjl
19477422Smsmith    if (ObjDesc->Mutex.Next)
19577422Smsmith    {
19677422Smsmith        (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev;
19777422Smsmith    }
19887031Smsmith
19977422Smsmith    if (ObjDesc->Mutex.Prev)
20077422Smsmith    {
20177422Smsmith        (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next;
202193267Sjkim
203193267Sjkim        /*
204206117Sjkim         * Migrate the previous sync level associated with this mutex to
205206117Sjkim         * the previous mutex on the list so that it may be preserved.
206206117Sjkim         * This handles the case where several mutexes have been acquired
207206117Sjkim         * at the same level, but are not released in opposite order.
208193267Sjkim         */
209193267Sjkim        (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel =
210193267Sjkim            ObjDesc->Mutex.OriginalSyncLevel;
21177422Smsmith    }
21287031Smsmith    else
21387031Smsmith    {
21487031Smsmith        Thread->AcquiredMutexList = ObjDesc->Mutex.Next;
21587031Smsmith    }
21677422Smsmith}
21777422Smsmith
21877422Smsmith
21977422Smsmith/*******************************************************************************
22077422Smsmith *
22177422Smsmith * FUNCTION:    AcpiExLinkMutex
22277422Smsmith *
223206117Sjkim * PARAMETERS:  ObjDesc             - The mutex to be linked
224206117Sjkim *              Thread              - Current executing thread object
22577422Smsmith *
226151937Sjkim * RETURN:      None
22777422Smsmith *
22877422Smsmith * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk
22977422Smsmith *
23077422Smsmith ******************************************************************************/
23177422Smsmith
232151937Sjkimstatic void
23377422SmsmithAcpiExLinkMutex (
23477422Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
23587031Smsmith    ACPI_THREAD_STATE       *Thread)
23677422Smsmith{
23787031Smsmith    ACPI_OPERAND_OBJECT     *ListHead;
23877422Smsmith
23987031Smsmith
24087031Smsmith    ListHead = Thread->AcquiredMutexList;
24187031Smsmith
24277422Smsmith    /* This object will be the first object in the list */
24377422Smsmith
24487031Smsmith    ObjDesc->Mutex.Prev = NULL;
24587031Smsmith    ObjDesc->Mutex.Next = ListHead;
24677422Smsmith
24777422Smsmith    /* Update old first object to point back to this object */
24877422Smsmith
24987031Smsmith    if (ListHead)
25077422Smsmith    {
25187031Smsmith        ListHead->Mutex.Prev = ObjDesc;
25277422Smsmith    }
25377422Smsmith
25477422Smsmith    /* Update list head */
25577422Smsmith
25687031Smsmith    Thread->AcquiredMutexList = ObjDesc;
25777422Smsmith}
25877422Smsmith
25977422Smsmith
26077422Smsmith/*******************************************************************************
26177422Smsmith *
262167802Sjkim * FUNCTION:    AcpiExAcquireMutexObject
263167802Sjkim *
264206117Sjkim * PARAMETERS:  Timeout             - Timeout in milliseconds
265167802Sjkim *              ObjDesc             - Mutex object
266206117Sjkim *              ThreadId            - Current thread state
267167802Sjkim *
268167802Sjkim * RETURN:      Status
269167802Sjkim *
270167802Sjkim * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
271167802Sjkim *              path that supports multiple acquires by the same thread.
272167802Sjkim *
273167802Sjkim * MUTEX:       Interpreter must be locked
274167802Sjkim *
275167802Sjkim * NOTE: This interface is called from three places:
276167802Sjkim * 1) From AcpiExAcquireMutex, via an AML Acquire() operator
277167802Sjkim * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the
278167802Sjkim *    global lock
279167802Sjkim * 3) From the external interface, AcpiAcquireGlobalLock
280167802Sjkim *
281167802Sjkim ******************************************************************************/
282167802Sjkim
283167802SjkimACPI_STATUS
284167802SjkimAcpiExAcquireMutexObject (
285167802Sjkim    UINT16                  Timeout,
286167802Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
287167802Sjkim    ACPI_THREAD_ID          ThreadId)
288167802Sjkim{
289167802Sjkim    ACPI_STATUS             Status;
290167802Sjkim
291167802Sjkim
292167802Sjkim    ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc);
293167802Sjkim
294167802Sjkim
295167802Sjkim    if (!ObjDesc)
296167802Sjkim    {
297167802Sjkim        return_ACPI_STATUS (AE_BAD_PARAMETER);
298167802Sjkim    }
299167802Sjkim
300167802Sjkim    /* Support for multiple acquires by the owning thread */
301167802Sjkim
302167802Sjkim    if (ObjDesc->Mutex.ThreadId == ThreadId)
303167802Sjkim    {
304167802Sjkim        /*
305167802Sjkim         * The mutex is already owned by this thread, just increment the
306167802Sjkim         * acquisition depth
307167802Sjkim         */
308167802Sjkim        ObjDesc->Mutex.AcquisitionDepth++;
309167802Sjkim        return_ACPI_STATUS (AE_OK);
310167802Sjkim    }
311167802Sjkim
312167802Sjkim    /* Acquire the mutex, wait if necessary. Special case for Global Lock */
313167802Sjkim
314167802Sjkim    if (ObjDesc == AcpiGbl_GlobalLockMutex)
315167802Sjkim    {
316167802Sjkim        Status = AcpiEvAcquireGlobalLock (Timeout);
317167802Sjkim    }
318167802Sjkim    else
319167802Sjkim    {
320298714Sjkim        Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex, Timeout);
321167802Sjkim    }
322167802Sjkim
323167802Sjkim    if (ACPI_FAILURE (Status))
324167802Sjkim    {
325167802Sjkim        /* Includes failure from a timeout on TimeDesc */
326167802Sjkim
327167802Sjkim        return_ACPI_STATUS (Status);
328167802Sjkim    }
329167802Sjkim
330167802Sjkim    /* Acquired the mutex: update mutex object */
331167802Sjkim
332167802Sjkim    ObjDesc->Mutex.ThreadId = ThreadId;
333167802Sjkim    ObjDesc->Mutex.AcquisitionDepth = 1;
334167802Sjkim    ObjDesc->Mutex.OriginalSyncLevel = 0;
335167802Sjkim    ObjDesc->Mutex.OwnerThread = NULL;      /* Used only for AML Acquire() */
336167802Sjkim
337167802Sjkim    return_ACPI_STATUS (AE_OK);
338167802Sjkim}
339167802Sjkim
340167802Sjkim
341167802Sjkim/*******************************************************************************
342167802Sjkim *
34377422Smsmith * FUNCTION:    AcpiExAcquireMutex
34477422Smsmith *
345151937Sjkim * PARAMETERS:  TimeDesc            - Timeout integer
346151937Sjkim *              ObjDesc             - Mutex object
347151937Sjkim *              WalkState           - Current method execution state
34877422Smsmith *
34977422Smsmith * RETURN:      Status
35077422Smsmith *
35177422Smsmith * DESCRIPTION: Acquire an AML mutex
35277422Smsmith *
35377422Smsmith ******************************************************************************/
35477422Smsmith
35577422SmsmithACPI_STATUS
35677422SmsmithAcpiExAcquireMutex (
35777422Smsmith    ACPI_OPERAND_OBJECT     *TimeDesc,
35877422Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
35977422Smsmith    ACPI_WALK_STATE         *WalkState)
36077422Smsmith{
36177422Smsmith    ACPI_STATUS             Status;
36277422Smsmith
36377422Smsmith
364167802Sjkim    ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc);
36577422Smsmith
366107325Siwasaki
36777422Smsmith    if (!ObjDesc)
36877422Smsmith    {
36977422Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
37077422Smsmith    }
37177422Smsmith
372206117Sjkim    /* Must have a valid thread state struct */
373107325Siwasaki
374107325Siwasaki    if (!WalkState->Thread)
375107325Siwasaki    {
376206117Sjkim        ACPI_ERROR ((AE_INFO,
377206117Sjkim            "Cannot acquire Mutex [%4.4s], null thread info",
378151937Sjkim            AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
379107325Siwasaki        return_ACPI_STATUS (AE_AML_INTERNAL);
380107325Siwasaki    }
381107325Siwasaki
38277422Smsmith    /*
383298714Sjkim     * Current sync level must be less than or equal to the sync level
384298714Sjkim     * of the mutex. This mechanism provides some deadlock prevention.
38577422Smsmith     */
38687031Smsmith    if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel)
38777422Smsmith    {
388167802Sjkim        ACPI_ERROR ((AE_INFO,
389298714Sjkim            "Cannot acquire Mutex [%4.4s], "
390298714Sjkim            "current SyncLevel is too large (%u)",
391167802Sjkim            AcpiUtGetNodeName (ObjDesc->Mutex.Node),
392167802Sjkim            WalkState->Thread->CurrentSyncLevel));
39377422Smsmith        return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
39477422Smsmith    }
39577422Smsmith
396298714Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
397298714Sjkim        "Acquiring: Mutex SyncLevel %u, Thread SyncLevel %u, "
398298714Sjkim        "Depth %u TID %p\n",
399298714Sjkim        ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel,
400298714Sjkim        ObjDesc->Mutex.AcquisitionDepth, WalkState->Thread));
401298714Sjkim
402167802Sjkim    Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value,
403298714Sjkim        ObjDesc, WalkState->Thread->ThreadId);
404298714Sjkim
405167802Sjkim    if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1)
406127175Snjl    {
407167802Sjkim        /* Save Thread object, original/current sync levels */
408107325Siwasaki
409167802Sjkim        ObjDesc->Mutex.OwnerThread = WalkState->Thread;
410298714Sjkim        ObjDesc->Mutex.OriginalSyncLevel =
411298714Sjkim            WalkState->Thread->CurrentSyncLevel;
412298714Sjkim        WalkState->Thread->CurrentSyncLevel =
413298714Sjkim            ObjDesc->Mutex.SyncLevel;
414167802Sjkim
415167802Sjkim        /* Link the mutex to the current thread for force-unlock at method exit */
416167802Sjkim
417167802Sjkim        AcpiExLinkMutex (ObjDesc, WalkState->Thread);
41877422Smsmith    }
41977422Smsmith
420298714Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
421298714Sjkim        "Acquired: Mutex SyncLevel %u, Thread SyncLevel %u, Depth %u\n",
422298714Sjkim        ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel,
423298714Sjkim        ObjDesc->Mutex.AcquisitionDepth));
424298714Sjkim
425167802Sjkim    return_ACPI_STATUS (Status);
426167802Sjkim}
42777422Smsmith
428167802Sjkim
429167802Sjkim/*******************************************************************************
430167802Sjkim *
431167802Sjkim * FUNCTION:    AcpiExReleaseMutexObject
432167802Sjkim *
433167802Sjkim * PARAMETERS:  ObjDesc             - The object descriptor for this op
434167802Sjkim *
435167802Sjkim * RETURN:      Status
436167802Sjkim *
437167802Sjkim * DESCRIPTION: Release a previously acquired Mutex, low level interface.
438167802Sjkim *              Provides a common path that supports multiple releases (after
439167802Sjkim *              previous multiple acquires) by the same thread.
440167802Sjkim *
441167802Sjkim * MUTEX:       Interpreter must be locked
442167802Sjkim *
443167802Sjkim * NOTE: This interface is called from three places:
444167802Sjkim * 1) From AcpiExReleaseMutex, via an AML Acquire() operator
445167802Sjkim * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the
446167802Sjkim *    global lock
447167802Sjkim * 3) From the external interface, AcpiReleaseGlobalLock
448167802Sjkim *
449167802Sjkim ******************************************************************************/
450167802Sjkim
451167802SjkimACPI_STATUS
452167802SjkimAcpiExReleaseMutexObject (
453167802Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc)
454167802Sjkim{
455167802Sjkim    ACPI_STATUS             Status = AE_OK;
456167802Sjkim
457167802Sjkim
458167802Sjkim    ACPI_FUNCTION_TRACE (ExReleaseMutexObject);
459167802Sjkim
460167802Sjkim
461167802Sjkim    if (ObjDesc->Mutex.AcquisitionDepth == 0)
46277422Smsmith    {
463241973Sjkim        return_ACPI_STATUS (AE_NOT_ACQUIRED);
464167802Sjkim    }
46577422Smsmith
466167802Sjkim    /* Match multiple Acquires with multiple Releases */
467167802Sjkim
468167802Sjkim    ObjDesc->Mutex.AcquisitionDepth--;
469167802Sjkim    if (ObjDesc->Mutex.AcquisitionDepth != 0)
470167802Sjkim    {
471167802Sjkim        /* Just decrement the depth and return */
472167802Sjkim
473167802Sjkim        return_ACPI_STATUS (AE_OK);
47477422Smsmith    }
47577422Smsmith
476167802Sjkim    if (ObjDesc->Mutex.OwnerThread)
477167802Sjkim    {
478167802Sjkim        /* Unlink the mutex from the owner's list */
47977422Smsmith
480167802Sjkim        AcpiExUnlinkMutex (ObjDesc);
481167802Sjkim        ObjDesc->Mutex.OwnerThread = NULL;
482167802Sjkim    }
48377422Smsmith
484167802Sjkim    /* Release the mutex, special case for Global Lock */
48577422Smsmith
486167802Sjkim    if (ObjDesc == AcpiGbl_GlobalLockMutex)
487167802Sjkim    {
488167802Sjkim        Status = AcpiEvReleaseGlobalLock ();
489167802Sjkim    }
490167802Sjkim    else
491167802Sjkim    {
492167802Sjkim        AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
493167802Sjkim    }
49477422Smsmith
495167802Sjkim    /* Clear mutex info */
49687031Smsmith
497167802Sjkim    ObjDesc->Mutex.ThreadId = 0;
498167802Sjkim    return_ACPI_STATUS (Status);
49977422Smsmith}
50077422Smsmith
50177422Smsmith
50277422Smsmith/*******************************************************************************
50377422Smsmith *
50477422Smsmith * FUNCTION:    AcpiExReleaseMutex
50577422Smsmith *
506129684Snjl * PARAMETERS:  ObjDesc             - The object descriptor for this op
507151937Sjkim *              WalkState           - Current method execution state
50877422Smsmith *
50977422Smsmith * RETURN:      Status
51077422Smsmith *
51177422Smsmith * DESCRIPTION: Release a previously acquired Mutex.
51277422Smsmith *
51377422Smsmith ******************************************************************************/
51477422Smsmith
51577422SmsmithACPI_STATUS
51677422SmsmithAcpiExReleaseMutex (
51777422Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
51877422Smsmith    ACPI_WALK_STATE         *WalkState)
51977422Smsmith{
520193267Sjkim    UINT8                   PreviousSyncLevel;
521204773Sjkim    ACPI_THREAD_STATE       *OwnerThread;
522298714Sjkim    ACPI_STATUS             Status = AE_OK;
52377422Smsmith
52477422Smsmith
525167802Sjkim    ACPI_FUNCTION_TRACE (ExReleaseMutex);
52677422Smsmith
52777422Smsmith
52877422Smsmith    if (!ObjDesc)
52977422Smsmith    {
53077422Smsmith        return_ACPI_STATUS (AE_BAD_PARAMETER);
53177422Smsmith    }
53277422Smsmith
533204773Sjkim    OwnerThread = ObjDesc->Mutex.OwnerThread;
534204773Sjkim
53583174Smsmith    /* The mutex must have been previously acquired in order to release it */
53677422Smsmith
537204773Sjkim    if (!OwnerThread)
53877422Smsmith    {
539206117Sjkim        ACPI_ERROR ((AE_INFO,
540206117Sjkim            "Cannot release Mutex [%4.4s], not acquired",
541167802Sjkim            AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
54277422Smsmith        return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
54377422Smsmith    }
54477422Smsmith
545200553Sjkim    /* Must have a valid thread ID */
546200553Sjkim
547200553Sjkim    if (!WalkState->Thread)
548200553Sjkim    {
549206117Sjkim        ACPI_ERROR ((AE_INFO,
550206117Sjkim            "Cannot release Mutex [%4.4s], null thread info",
551200553Sjkim            AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
552200553Sjkim        return_ACPI_STATUS (AE_AML_INTERNAL);
553200553Sjkim    }
554200553Sjkim
555129684Snjl    /*
556127175Snjl     * The Mutex is owned, but this thread must be the owner.
557127175Snjl     * Special case for Global Lock, any thread can release
558127175Snjl     */
559204773Sjkim    if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) &&
560167802Sjkim        (ObjDesc != AcpiGbl_GlobalLockMutex))
56177422Smsmith    {
562167802Sjkim        ACPI_ERROR ((AE_INFO,
563212761Sjkim            "Thread %u cannot release Mutex [%4.4s] acquired by thread %u",
564212761Sjkim            (UINT32) WalkState->Thread->ThreadId,
565123315Snjl            AcpiUtGetNodeName (ObjDesc->Mutex.Node),
566212761Sjkim            (UINT32) OwnerThread->ThreadId));
56777422Smsmith        return_ACPI_STATUS (AE_AML_NOT_OWNER);
56877422Smsmith    }
56977422Smsmith
57077422Smsmith    /*
571193267Sjkim     * The sync level of the mutex must be equal to the current sync level. In
572193267Sjkim     * other words, the current level means that at least one mutex at that
573193267Sjkim     * level is currently being held. Attempting to release a mutex of a
574193267Sjkim     * different level can only mean that the mutex ordering rule is being
575193267Sjkim     * violated. This behavior is clarified in ACPI 4.0 specification.
57677422Smsmith     */
577204773Sjkim    if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel)
57877422Smsmith    {
579167802Sjkim        ACPI_ERROR ((AE_INFO,
580298714Sjkim            "Cannot release Mutex [%4.4s], SyncLevel mismatch: "
581298714Sjkim            "mutex %u current %u",
582167802Sjkim            AcpiUtGetNodeName (ObjDesc->Mutex.Node),
583167802Sjkim            ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel));
58477422Smsmith        return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
58577422Smsmith    }
58677422Smsmith
587193267Sjkim    /*
588193267Sjkim     * Get the previous SyncLevel from the head of the acquired mutex list.
589193267Sjkim     * This handles the case where several mutexes at the same level have been
590193267Sjkim     * acquired, but are not released in reverse order.
591193267Sjkim     */
592193267Sjkim    PreviousSyncLevel =
593204773Sjkim        OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel;
594193267Sjkim
595298714Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
596298714Sjkim        "Releasing: Object SyncLevel %u, Thread SyncLevel %u, "
597298714Sjkim        "Prev SyncLevel %u, Depth %u TID %p\n",
598298714Sjkim        ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel,
599298714Sjkim        PreviousSyncLevel, ObjDesc->Mutex.AcquisitionDepth,
600298714Sjkim        WalkState->Thread));
601298714Sjkim
602167802Sjkim    Status = AcpiExReleaseMutexObject (ObjDesc);
603193267Sjkim    if (ACPI_FAILURE (Status))
604193267Sjkim    {
605193267Sjkim        return_ACPI_STATUS (Status);
606193267Sjkim    }
607129684Snjl
608167802Sjkim    if (ObjDesc->Mutex.AcquisitionDepth == 0)
60977422Smsmith    {
610193267Sjkim        /* Restore the previous SyncLevel */
61177422Smsmith
612204773Sjkim        OwnerThread->CurrentSyncLevel = PreviousSyncLevel;
61377422Smsmith    }
614206117Sjkim
615298714Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
616298714Sjkim        "Released: Object SyncLevel %u, Thread SyncLevel, %u, "
617298714Sjkim        "Prev SyncLevel %u, Depth %u\n",
618298714Sjkim        ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel,
619298714Sjkim        PreviousSyncLevel, ObjDesc->Mutex.AcquisitionDepth));
620298714Sjkim
62177422Smsmith    return_ACPI_STATUS (Status);
62277422Smsmith}
62377422Smsmith
62477422Smsmith
62577422Smsmith/*******************************************************************************
62677422Smsmith *
62777422Smsmith * FUNCTION:    AcpiExReleaseAllMutexes
62877422Smsmith *
629206117Sjkim * PARAMETERS:  Thread              - Current executing thread object
63077422Smsmith *
63177422Smsmith * RETURN:      Status
63277422Smsmith *
633151937Sjkim * DESCRIPTION: Release all mutexes held by this thread
63477422Smsmith *
635167802Sjkim * NOTE: This function is called as the thread is exiting the interpreter.
636167802Sjkim * Mutexes are not released when an individual control method is exited, but
637167802Sjkim * only when the parent thread actually exits the interpreter. This allows one
638167802Sjkim * method to acquire a mutex, and a different method to release it, as long as
639167802Sjkim * this is performed underneath a single parent control method.
640167802Sjkim *
64177422Smsmith ******************************************************************************/
64277422Smsmith
64399679Siwasakivoid
64477422SmsmithAcpiExReleaseAllMutexes (
64587031Smsmith    ACPI_THREAD_STATE       *Thread)
64677422Smsmith{
64787031Smsmith    ACPI_OPERAND_OBJECT     *Next = Thread->AcquiredMutexList;
648167802Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc;
64977422Smsmith
65077422Smsmith
651298714Sjkim    ACPI_FUNCTION_TRACE (ExReleaseAllMutexes);
65283174Smsmith
65383174Smsmith
654129684Snjl    /* Traverse the list of owned mutexes, releasing each one */
655129684Snjl
65677422Smsmith    while (Next)
65777422Smsmith    {
658167802Sjkim        ObjDesc = Next;
659241973Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
660298714Sjkim            "Mutex [%4.4s] force-release, SyncLevel %u Depth %u\n",
661298714Sjkim            ObjDesc->Mutex.Node->Name.Ascii, ObjDesc->Mutex.SyncLevel,
662298714Sjkim            ObjDesc->Mutex.AcquisitionDepth));
663241973Sjkim
664167802Sjkim        /* Release the mutex, special case for Global Lock */
66577422Smsmith
666167802Sjkim        if (ObjDesc == AcpiGbl_GlobalLockMutex)
66799679Siwasaki        {
668167802Sjkim            /* Ignore errors */
669167802Sjkim
670167802Sjkim            (void) AcpiEvReleaseGlobalLock ();
67199679Siwasaki        }
672167802Sjkim        else
673167802Sjkim        {
674167802Sjkim            AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
675167802Sjkim        }
67687031Smsmith
677298714Sjkim        /* Update Thread SyncLevel (Last mutex is the important one) */
678298714Sjkim
679298714Sjkim        Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;
680298714Sjkim
68187031Smsmith        /* Mark mutex unowned */
68287031Smsmith
683298714Sjkim        Next = ObjDesc->Mutex.Next;
684298714Sjkim
685298714Sjkim        ObjDesc->Mutex.Prev = NULL;
686298714Sjkim        ObjDesc->Mutex.Next = NULL;
687298714Sjkim        ObjDesc->Mutex.AcquisitionDepth = 0;
688167802Sjkim        ObjDesc->Mutex.OwnerThread = NULL;
689167802Sjkim        ObjDesc->Mutex.ThreadId = 0;
690298714Sjkim    }
691129684Snjl
692298714Sjkim    return_VOID;
69377422Smsmith}
694