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