i386/identcpu.c: Add VIA Nano support
[dragonfly.git] / sys / contrib / dev / acpica-unix-20061109 / interpreter / executer / exmutex.c
1
2 /******************************************************************************
3  *
4  * Module Name: exmutex - ASL Mutex Acquire/Release functions
5  *              $Revision: 1.35 $
6  *
7  *****************************************************************************/
8
9 /******************************************************************************
10  *
11  * 1. Copyright Notice
12  *
13  * Some or all of this work - Copyright (c) 1999 - 2006, 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:    AcpiExAcquireMutex
221  *
222  * PARAMETERS:  TimeDesc            - Timeout integer
223  *              ObjDesc             - Mutex object
224  *              WalkState           - Current method execution state
225  *
226  * RETURN:      Status
227  *
228  * DESCRIPTION: Acquire an AML mutex
229  *
230  ******************************************************************************/
231
232 ACPI_STATUS
233 AcpiExAcquireMutex (
234     ACPI_OPERAND_OBJECT     *TimeDesc,
235     ACPI_OPERAND_OBJECT     *ObjDesc,
236     ACPI_WALK_STATE         *WalkState)
237 {
238     ACPI_STATUS             Status;
239
240
241     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc);
242
243
244     if (!ObjDesc)
245     {
246         return_ACPI_STATUS (AE_BAD_PARAMETER);
247     }
248
249     /* Sanity check: we must have a valid thread ID */
250
251     if (!WalkState->Thread)
252     {
253         ACPI_ERROR ((AE_INFO, "Cannot acquire Mutex [%4.4s], null thread info",
254             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
255         return_ACPI_STATUS (AE_AML_INTERNAL);
256     }
257
258     /*
259      * Current Sync must be less than or equal to the sync level of the
260      * mutex. This mechanism provides some deadlock prevention
261      */
262     if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel)
263     {
264         ACPI_ERROR ((AE_INFO,
265             "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%d)",
266             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
267             WalkState->Thread->CurrentSyncLevel));
268         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
269     }
270
271     /* Support for multiple acquires by the owning thread */
272
273     if (ObjDesc->Mutex.OwnerThread)
274     {
275         if (ObjDesc->Mutex.OwnerThread->ThreadId ==
276             WalkState->Thread->ThreadId)
277         {
278             /*
279              * The mutex is already owned by this thread, just increment the
280              * acquisition depth
281              */
282             ObjDesc->Mutex.AcquisitionDepth++;
283             return_ACPI_STATUS (AE_OK);
284         }
285     }
286
287     /* Acquire the mutex, wait if necessary. Special case for Global Lock */
288
289     if (ObjDesc->Mutex.OsMutex == AcpiGbl_GlobalLockMutex)
290     {
291         Status = AcpiEvAcquireGlobalLock ((UINT16) TimeDesc->Integer.Value);
292     }
293     else
294     {
295         Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex,
296                     (UINT16) TimeDesc->Integer.Value);
297     }
298
299     if (ACPI_FAILURE (Status))
300     {
301         /* Includes failure from a timeout on TimeDesc */
302
303         return_ACPI_STATUS (Status);
304     }
305
306     /* Have the mutex: update mutex and walk info and save the SyncLevel */
307
308     ObjDesc->Mutex.OwnerThread = WalkState->Thread;
309     ObjDesc->Mutex.AcquisitionDepth = 1;
310     ObjDesc->Mutex.OriginalSyncLevel = WalkState->Thread->CurrentSyncLevel;
311
312     WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.SyncLevel;
313
314     /* Link the mutex to the current thread for force-unlock at method exit */
315
316     AcpiExLinkMutex (ObjDesc, WalkState->Thread);
317     return_ACPI_STATUS (AE_OK);
318 }
319
320
321 /*******************************************************************************
322  *
323  * FUNCTION:    AcpiExReleaseMutex
324  *
325  * PARAMETERS:  ObjDesc             - The object descriptor for this op
326  *              WalkState           - Current method execution state
327  *
328  * RETURN:      Status
329  *
330  * DESCRIPTION: Release a previously acquired Mutex.
331  *
332  ******************************************************************************/
333
334 ACPI_STATUS
335 AcpiExReleaseMutex (
336     ACPI_OPERAND_OBJECT     *ObjDesc,
337     ACPI_WALK_STATE         *WalkState)
338 {
339     ACPI_STATUS             Status = AE_OK;
340
341
342     ACPI_FUNCTION_TRACE (ExReleaseMutex);
343
344
345     if (!ObjDesc)
346     {
347         return_ACPI_STATUS (AE_BAD_PARAMETER);
348     }
349
350     /* The mutex must have been previously acquired in order to release it */
351
352     if (!ObjDesc->Mutex.OwnerThread)
353     {
354         ACPI_ERROR ((AE_INFO, "Cannot release Mutex [%4.4s], not acquired",
355             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
356         return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
357     }
358
359     /* Sanity check: we must have a valid thread ID */
360
361     if (!WalkState->Thread)
362     {
363         ACPI_ERROR ((AE_INFO, "Cannot release Mutex [%4.4s], null thread info",
364             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
365         return_ACPI_STATUS (AE_AML_INTERNAL);
366     }
367
368     /*
369      * The Mutex is owned, but this thread must be the owner.
370      * Special case for Global Lock, any thread can release
371      */
372     if ((ObjDesc->Mutex.OwnerThread->ThreadId != WalkState->Thread->ThreadId) &&
373         (ObjDesc->Mutex.OsMutex != AcpiGbl_GlobalLockMutex))
374     {
375         ACPI_ERROR ((AE_INFO,
376             "Thread %X cannot release Mutex [%4.4s] acquired by thread %X",
377             WalkState->Thread->ThreadId,
378             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
379             ObjDesc->Mutex.OwnerThread->ThreadId));
380         return_ACPI_STATUS (AE_AML_NOT_OWNER);
381     }
382
383     /*
384      * The sync level of the mutex must be less than or equal to the current
385      * sync level
386      */
387     if (ObjDesc->Mutex.SyncLevel > WalkState->Thread->CurrentSyncLevel)
388     {
389         ACPI_ERROR ((AE_INFO,
390             "Cannot release Mutex [%4.4s], incorrect SyncLevel",
391             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
392         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
393     }
394
395     /* Match multiple Acquires with multiple Releases */
396
397     ObjDesc->Mutex.AcquisitionDepth--;
398     if (ObjDesc->Mutex.AcquisitionDepth != 0)
399     {
400         /* Just decrement the depth and return */
401
402         return_ACPI_STATUS (AE_OK);
403     }
404
405     /* Unlink the mutex from the owner's list */
406
407     AcpiExUnlinkMutex (ObjDesc);
408
409     /* Release the mutex, special case for Global Lock */
410
411     if (ObjDesc->Mutex.OsMutex == AcpiGbl_GlobalLockMutex)
412     {
413         Status = AcpiEvReleaseGlobalLock ();
414     }
415     else
416     {
417         AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
418     }
419
420     /* Update the mutex and restore SyncLevel */
421
422     ObjDesc->Mutex.OwnerThread = NULL;
423     WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;
424
425     return_ACPI_STATUS (Status);
426 }
427
428
429 /*******************************************************************************
430  *
431  * FUNCTION:    AcpiExReleaseAllMutexes
432  *
433  * PARAMETERS:  Thread          - Current executing thread object
434  *
435  * RETURN:      Status
436  *
437  * DESCRIPTION: Release all mutexes held by this thread
438  *
439  * NOTE: This function is called as the thread is exiting the interpreter.
440  * Mutexes are not released when an individual control method is exited, but
441  * only when the parent thread actually exits the interpreter. This allows one
442  * method to acquire a mutex, and a different method to release it, as long as
443  * this is performed underneath a single parent control method.
444  *
445  ******************************************************************************/
446
447 void
448 AcpiExReleaseAllMutexes (
449     ACPI_THREAD_STATE       *Thread)
450 {
451     ACPI_OPERAND_OBJECT     *Next = Thread->AcquiredMutexList;
452     ACPI_OPERAND_OBJECT     *ObjDesc;
453
454
455     ACPI_FUNCTION_ENTRY ();
456
457
458     /* Traverse the list of owned mutexes, releasing each one */
459
460     while (Next)
461     {
462         ObjDesc = Next;
463         Next = ObjDesc->Mutex.Next;
464
465         ObjDesc->Mutex.Prev = NULL;
466         ObjDesc->Mutex.Next = NULL;
467         ObjDesc->Mutex.AcquisitionDepth = 0;
468
469         /* Release the mutex, special case for Global Lock */
470
471         if (ObjDesc->Mutex.OsMutex == AcpiGbl_GlobalLockMutex)
472         {
473             /* Ignore errors */
474
475             (void) AcpiEvReleaseGlobalLock ();
476         }
477         else
478         {
479             AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
480         }
481
482         /* Mark mutex unowned */
483
484         ObjDesc->Mutex.OwnerThread = NULL;
485
486         /* Update Thread SyncLevel (Last mutex is the important one) */
487
488         Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;
489     }
490 }
491
492