1/******************************************************************************
2 *
3 * Module Name: exmutex - ASL Mutex Acquire/Release functions
4 *
5 *****************************************************************************/
6
7/******************************************************************************
8 *
9 * 1. Copyright Notice
10 *
11 * Some or all of this work - Copyright (c) 1999 - 2012, Intel Corp.
12 * All rights reserved.
13 *
14 * 2. License
15 *
16 * 2.1. This is your license from Intel Corp. under its intellectual property
17 * rights. You may have additional license terms from the party that provided
18 * you this software, covering your right to use that party's intellectual
19 * property rights.
20 *
21 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
22 * copy of the source code appearing in this file ("Covered Code") an
23 * irrevocable, perpetual, worldwide license under Intel's copyrights in the
24 * base code distributed originally by Intel ("Original Intel Code") to copy,
25 * make derivatives, distribute, use and display any portion of the Covered
26 * Code in any form, with the right to sublicense such rights; and
27 *
28 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
29 * license (with the right to sublicense), under only those claims of Intel
30 * patents that are infringed by the Original Intel Code, to make, use, sell,
31 * offer to sell, and import the Covered Code and derivative works thereof
32 * solely to the minimum extent necessary to exercise the above copyright
33 * license, and in no event shall the patent license extend to any additions
34 * to or modifications of the Original Intel Code. No other license or right
35 * is granted directly or by implication, estoppel or otherwise;
36 *
37 * The above copyright and patent license is granted only if the following
38 * conditions are met:
39 *
40 * 3. Conditions
41 *
42 * 3.1. Redistribution of Source with Rights to Further Distribute Source.
43 * Redistribution of source code of any substantial portion of the Covered
44 * Code or modification with rights to further distribute source must include
45 * the above Copyright Notice, the above License, this list of Conditions,
46 * and the following Disclaimer and Export Compliance provision. In addition,
47 * Licensee must cause all Covered Code to which Licensee contributes to
48 * contain a file documenting the changes Licensee made to create that Covered
49 * Code and the date of any change. Licensee must include in that file the
50 * documentation of any changes made by any predecessor Licensee. Licensee
51 * must include a prominent statement that the modification is derived,
52 * directly or indirectly, from Original Intel Code.
53 *
54 * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
55 * Redistribution of source code of any substantial portion of the Covered
56 * Code or modification without rights to further distribute source must
57 * include the following Disclaimer and Export Compliance provision in the
58 * documentation and/or other materials provided with distribution. In
59 * addition, Licensee may not authorize further sublicense of source of any
60 * portion of the Covered Code, and must include terms to the effect that the
61 * license from Licensee to its licensee is limited to the intellectual
62 * property embodied in the software Licensee provides to its licensee, and
63 * not to intellectual property embodied in modifications its licensee may
64 * make.
65 *
66 * 3.3. Redistribution of Executable. Redistribution in executable form of any
67 * substantial portion of the Covered Code or modification must reproduce the
68 * above Copyright Notice, and the following Disclaimer and Export Compliance
69 * provision in the documentation and/or other materials provided with the
70 * distribution.
71 *
72 * 3.4. Intel retains all right, title, and interest in and to the Original
73 * Intel Code.
74 *
75 * 3.5. Neither the name Intel nor any other trademark owned or controlled by
76 * Intel shall be used in advertising or otherwise to promote the sale, use or
77 * other dealings in products derived from or relating to the Covered Code
78 * without prior written authorization from Intel.
79 *
80 * 4. Disclaimer and Export Compliance
81 *
82 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
83 * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
84 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
85 * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
86 * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
87 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
88 * PARTICULAR PURPOSE.
89 *
90 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
91 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
92 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
93 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
94 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
95 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
96 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
97 * LIMITED REMEDY.
98 *
99 * 4.3. Licensee shall not export, either directly or indirectly, any of this
100 * software or system incorporating such software without first obtaining any
101 * required license or other approval from the U. S. Department of Commerce or
102 * any other agency or department of the United States Government. In the
103 * event Licensee exports any such software from the United States or
104 * re-exports any such software from a foreign destination, Licensee shall
105 * ensure that the distribution and export/re-export of the software is in
106 * compliance with all laws, regulations, orders, or other restrictions of the
107 * U.S. Export Administration Regulations. Licensee agrees that neither it nor
108 * any of its subsidiaries will export/re-export any technical data, process,
109 * software, or service, directly or indirectly, to any country for which the
110 * United States government or any agency thereof requires an export license,
111 * other governmental approval, or letter of assurance, without first obtaining
112 * such license, approval or letter.
113 *
114 *****************************************************************************/
115
116#define __EXMUTEX_C__
117
118#include "acpi.h"
119#include "accommon.h"
120#include "acinterp.h"
121#include "acevents.h"
122
123#define _COMPONENT          ACPI_EXECUTER
124        ACPI_MODULE_NAME    ("exmutex")
125
126/* Local prototypes */
127
128static void
129AcpiExLinkMutex (
130    ACPI_OPERAND_OBJECT     *ObjDesc,
131    ACPI_THREAD_STATE       *Thread);
132
133
134/*******************************************************************************
135 *
136 * FUNCTION:    AcpiExUnlinkMutex
137 *
138 * PARAMETERS:  ObjDesc             - The mutex to be unlinked
139 *
140 * RETURN:      None
141 *
142 * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list
143 *
144 ******************************************************************************/
145
146void
147AcpiExUnlinkMutex (
148    ACPI_OPERAND_OBJECT     *ObjDesc)
149{
150    ACPI_THREAD_STATE       *Thread = ObjDesc->Mutex.OwnerThread;
151
152
153    if (!Thread)
154    {
155        return;
156    }
157
158    /* Doubly linked list */
159
160    if (ObjDesc->Mutex.Next)
161    {
162        (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev;
163    }
164
165    if (ObjDesc->Mutex.Prev)
166    {
167        (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next;
168
169        /*
170         * Migrate the previous sync level associated with this mutex to
171         * the previous mutex on the list so that it may be preserved.
172         * This handles the case where several mutexes have been acquired
173         * at the same level, but are not released in opposite order.
174         */
175        (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel =
176            ObjDesc->Mutex.OriginalSyncLevel;
177    }
178    else
179    {
180        Thread->AcquiredMutexList = ObjDesc->Mutex.Next;
181    }
182}
183
184
185/*******************************************************************************
186 *
187 * FUNCTION:    AcpiExLinkMutex
188 *
189 * PARAMETERS:  ObjDesc             - The mutex to be linked
190 *              Thread              - Current executing thread object
191 *
192 * RETURN:      None
193 *
194 * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk
195 *
196 ******************************************************************************/
197
198static void
199AcpiExLinkMutex (
200    ACPI_OPERAND_OBJECT     *ObjDesc,
201    ACPI_THREAD_STATE       *Thread)
202{
203    ACPI_OPERAND_OBJECT     *ListHead;
204
205
206    ListHead = Thread->AcquiredMutexList;
207
208    /* This object will be the first object in the list */
209
210    ObjDesc->Mutex.Prev = NULL;
211    ObjDesc->Mutex.Next = ListHead;
212
213    /* Update old first object to point back to this object */
214
215    if (ListHead)
216    {
217        ListHead->Mutex.Prev = ObjDesc;
218    }
219
220    /* Update list head */
221
222    Thread->AcquiredMutexList = ObjDesc;
223}
224
225
226/*******************************************************************************
227 *
228 * FUNCTION:    AcpiExAcquireMutexObject
229 *
230 * PARAMETERS:  Timeout             - Timeout in milliseconds
231 *              ObjDesc             - Mutex object
232 *              ThreadId            - Current thread state
233 *
234 * RETURN:      Status
235 *
236 * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
237 *              path that supports multiple acquires by the same thread.
238 *
239 * MUTEX:       Interpreter must be locked
240 *
241 * NOTE: This interface is called from three places:
242 * 1) From AcpiExAcquireMutex, via an AML Acquire() operator
243 * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the
244 *    global lock
245 * 3) From the external interface, AcpiAcquireGlobalLock
246 *
247 ******************************************************************************/
248
249ACPI_STATUS
250AcpiExAcquireMutexObject (
251    UINT16                  Timeout,
252    ACPI_OPERAND_OBJECT     *ObjDesc,
253    ACPI_THREAD_ID          ThreadId)
254{
255    ACPI_STATUS             Status;
256
257
258    ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc);
259
260
261    if (!ObjDesc)
262    {
263        return_ACPI_STATUS (AE_BAD_PARAMETER);
264    }
265
266    /* Support for multiple acquires by the owning thread */
267
268    if (ObjDesc->Mutex.ThreadId == ThreadId)
269    {
270        /*
271         * The mutex is already owned by this thread, just increment the
272         * acquisition depth
273         */
274        ObjDesc->Mutex.AcquisitionDepth++;
275        return_ACPI_STATUS (AE_OK);
276    }
277
278    /* Acquire the mutex, wait if necessary. Special case for Global Lock */
279
280    if (ObjDesc == AcpiGbl_GlobalLockMutex)
281    {
282        Status = AcpiEvAcquireGlobalLock (Timeout);
283    }
284    else
285    {
286        Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex,
287                    Timeout);
288    }
289
290    if (ACPI_FAILURE (Status))
291    {
292        /* Includes failure from a timeout on TimeDesc */
293
294        return_ACPI_STATUS (Status);
295    }
296
297    /* Acquired the mutex: update mutex object */
298
299    ObjDesc->Mutex.ThreadId = ThreadId;
300    ObjDesc->Mutex.AcquisitionDepth = 1;
301    ObjDesc->Mutex.OriginalSyncLevel = 0;
302    ObjDesc->Mutex.OwnerThread = NULL;      /* Used only for AML Acquire() */
303
304    return_ACPI_STATUS (AE_OK);
305}
306
307
308/*******************************************************************************
309 *
310 * FUNCTION:    AcpiExAcquireMutex
311 *
312 * PARAMETERS:  TimeDesc            - Timeout integer
313 *              ObjDesc             - Mutex object
314 *              WalkState           - Current method execution state
315 *
316 * RETURN:      Status
317 *
318 * DESCRIPTION: Acquire an AML mutex
319 *
320 ******************************************************************************/
321
322ACPI_STATUS
323AcpiExAcquireMutex (
324    ACPI_OPERAND_OBJECT     *TimeDesc,
325    ACPI_OPERAND_OBJECT     *ObjDesc,
326    ACPI_WALK_STATE         *WalkState)
327{
328    ACPI_STATUS             Status;
329
330
331    ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc);
332
333
334    if (!ObjDesc)
335    {
336        return_ACPI_STATUS (AE_BAD_PARAMETER);
337    }
338
339    /* Must have a valid thread state struct */
340
341    if (!WalkState->Thread)
342    {
343        ACPI_ERROR ((AE_INFO,
344            "Cannot acquire Mutex [%4.4s], null thread info",
345            AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
346        return_ACPI_STATUS (AE_AML_INTERNAL);
347    }
348
349    /*
350     * Current sync level must be less than or equal to the sync level of the
351     * mutex. This mechanism provides some deadlock prevention
352     */
353    if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel)
354    {
355        ACPI_ERROR ((AE_INFO,
356            "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%u)",
357            AcpiUtGetNodeName (ObjDesc->Mutex.Node),
358            WalkState->Thread->CurrentSyncLevel));
359        return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
360    }
361
362    Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value,
363                ObjDesc, WalkState->Thread->ThreadId);
364    if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1)
365    {
366        /* Save Thread object, original/current sync levels */
367
368        ObjDesc->Mutex.OwnerThread = WalkState->Thread;
369        ObjDesc->Mutex.OriginalSyncLevel = WalkState->Thread->CurrentSyncLevel;
370        WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.SyncLevel;
371
372        /* Link the mutex to the current thread for force-unlock at method exit */
373
374        AcpiExLinkMutex (ObjDesc, WalkState->Thread);
375    }
376
377    return_ACPI_STATUS (Status);
378}
379
380
381/*******************************************************************************
382 *
383 * FUNCTION:    AcpiExReleaseMutexObject
384 *
385 * PARAMETERS:  ObjDesc             - The object descriptor for this op
386 *
387 * RETURN:      Status
388 *
389 * DESCRIPTION: Release a previously acquired Mutex, low level interface.
390 *              Provides a common path that supports multiple releases (after
391 *              previous multiple acquires) by the same thread.
392 *
393 * MUTEX:       Interpreter must be locked
394 *
395 * NOTE: This interface is called from three places:
396 * 1) From AcpiExReleaseMutex, via an AML Acquire() operator
397 * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the
398 *    global lock
399 * 3) From the external interface, AcpiReleaseGlobalLock
400 *
401 ******************************************************************************/
402
403ACPI_STATUS
404AcpiExReleaseMutexObject (
405    ACPI_OPERAND_OBJECT     *ObjDesc)
406{
407    ACPI_STATUS             Status = AE_OK;
408
409
410    ACPI_FUNCTION_TRACE (ExReleaseMutexObject);
411
412
413    if (ObjDesc->Mutex.AcquisitionDepth == 0)
414    {
415        return_ACPI_STATUS (AE_NOT_ACQUIRED);
416    }
417
418    /* Match multiple Acquires with multiple Releases */
419
420    ObjDesc->Mutex.AcquisitionDepth--;
421    if (ObjDesc->Mutex.AcquisitionDepth != 0)
422    {
423        /* Just decrement the depth and return */
424
425        return_ACPI_STATUS (AE_OK);
426    }
427
428    if (ObjDesc->Mutex.OwnerThread)
429    {
430        /* Unlink the mutex from the owner's list */
431
432        AcpiExUnlinkMutex (ObjDesc);
433        ObjDesc->Mutex.OwnerThread = NULL;
434    }
435
436    /* Release the mutex, special case for Global Lock */
437
438    if (ObjDesc == AcpiGbl_GlobalLockMutex)
439    {
440        Status = AcpiEvReleaseGlobalLock ();
441    }
442    else
443    {
444        AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
445    }
446
447    /* Clear mutex info */
448
449    ObjDesc->Mutex.ThreadId = 0;
450    return_ACPI_STATUS (Status);
451}
452
453
454/*******************************************************************************
455 *
456 * FUNCTION:    AcpiExReleaseMutex
457 *
458 * PARAMETERS:  ObjDesc             - The object descriptor for this op
459 *              WalkState           - Current method execution state
460 *
461 * RETURN:      Status
462 *
463 * DESCRIPTION: Release a previously acquired Mutex.
464 *
465 ******************************************************************************/
466
467ACPI_STATUS
468AcpiExReleaseMutex (
469    ACPI_OPERAND_OBJECT     *ObjDesc,
470    ACPI_WALK_STATE         *WalkState)
471{
472    ACPI_STATUS             Status = AE_OK;
473    UINT8                   PreviousSyncLevel;
474    ACPI_THREAD_STATE       *OwnerThread;
475
476
477    ACPI_FUNCTION_TRACE (ExReleaseMutex);
478
479
480    if (!ObjDesc)
481    {
482        return_ACPI_STATUS (AE_BAD_PARAMETER);
483    }
484
485    OwnerThread = ObjDesc->Mutex.OwnerThread;
486
487    /* The mutex must have been previously acquired in order to release it */
488
489    if (!OwnerThread)
490    {
491        ACPI_ERROR ((AE_INFO,
492            "Cannot release Mutex [%4.4s], not acquired",
493            AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
494        return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
495    }
496
497    /* Must have a valid thread ID */
498
499    if (!WalkState->Thread)
500    {
501        ACPI_ERROR ((AE_INFO,
502            "Cannot release Mutex [%4.4s], null thread info",
503            AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
504        return_ACPI_STATUS (AE_AML_INTERNAL);
505    }
506
507    /*
508     * The Mutex is owned, but this thread must be the owner.
509     * Special case for Global Lock, any thread can release
510     */
511    if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) &&
512        (ObjDesc != AcpiGbl_GlobalLockMutex))
513    {
514        ACPI_ERROR ((AE_INFO,
515            "Thread %u cannot release Mutex [%4.4s] acquired by thread %u",
516            (UINT32) WalkState->Thread->ThreadId,
517            AcpiUtGetNodeName (ObjDesc->Mutex.Node),
518            (UINT32) OwnerThread->ThreadId));
519        return_ACPI_STATUS (AE_AML_NOT_OWNER);
520    }
521
522    /*
523     * The sync level of the mutex must be equal to the current sync level. In
524     * other words, the current level means that at least one mutex at that
525     * level is currently being held. Attempting to release a mutex of a
526     * different level can only mean that the mutex ordering rule is being
527     * violated. This behavior is clarified in ACPI 4.0 specification.
528     */
529    if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel)
530    {
531        ACPI_ERROR ((AE_INFO,
532            "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %u current %u",
533            AcpiUtGetNodeName (ObjDesc->Mutex.Node),
534            ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel));
535        return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
536    }
537
538    /*
539     * Get the previous SyncLevel from the head of the acquired mutex list.
540     * This handles the case where several mutexes at the same level have been
541     * acquired, but are not released in reverse order.
542     */
543    PreviousSyncLevel =
544        OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel;
545
546    Status = AcpiExReleaseMutexObject (ObjDesc);
547    if (ACPI_FAILURE (Status))
548    {
549        return_ACPI_STATUS (Status);
550    }
551
552    if (ObjDesc->Mutex.AcquisitionDepth == 0)
553    {
554        /* Restore the previous SyncLevel */
555
556        OwnerThread->CurrentSyncLevel = PreviousSyncLevel;
557    }
558
559    return_ACPI_STATUS (Status);
560}
561
562
563/*******************************************************************************
564 *
565 * FUNCTION:    AcpiExReleaseAllMutexes
566 *
567 * PARAMETERS:  Thread              - Current executing thread object
568 *
569 * RETURN:      Status
570 *
571 * DESCRIPTION: Release all mutexes held by this thread
572 *
573 * NOTE: This function is called as the thread is exiting the interpreter.
574 * Mutexes are not released when an individual control method is exited, but
575 * only when the parent thread actually exits the interpreter. This allows one
576 * method to acquire a mutex, and a different method to release it, as long as
577 * this is performed underneath a single parent control method.
578 *
579 ******************************************************************************/
580
581void
582AcpiExReleaseAllMutexes (
583    ACPI_THREAD_STATE       *Thread)
584{
585    ACPI_OPERAND_OBJECT     *Next = Thread->AcquiredMutexList;
586    ACPI_OPERAND_OBJECT     *ObjDesc;
587
588
589    ACPI_FUNCTION_NAME (ExReleaseAllMutexes);
590
591
592    /* Traverse the list of owned mutexes, releasing each one */
593
594    while (Next)
595    {
596        ObjDesc = Next;
597        Next = ObjDesc->Mutex.Next;
598
599        ObjDesc->Mutex.Prev = NULL;
600        ObjDesc->Mutex.Next = NULL;
601        ObjDesc->Mutex.AcquisitionDepth = 0;
602
603        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
604            "Force-releasing held mutex: %p\n", ObjDesc));
605
606        /* Release the mutex, special case for Global Lock */
607
608        if (ObjDesc == AcpiGbl_GlobalLockMutex)
609        {
610            /* Ignore errors */
611
612            (void) AcpiEvReleaseGlobalLock ();
613        }
614        else
615        {
616            AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
617        }
618
619        /* Mark mutex unowned */
620
621        ObjDesc->Mutex.OwnerThread = NULL;
622        ObjDesc->Mutex.ThreadId = 0;
623
624        /* Update Thread SyncLevel (Last mutex is the important one) */
625
626        Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;
627    }
628}
629