]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/contrib/dev/acpica/components/executer/exmutex.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / contrib / dev / acpica / components / executer / exmutex.c
1 /******************************************************************************
2  *
3  * Module Name: exmutex - ASL Mutex Acquire/Release functions
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2013, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43
44 #define __EXMUTEX_C__
45
46 #include <contrib/dev/acpica/include/acpi.h>
47 #include <contrib/dev/acpica/include/accommon.h>
48 #include <contrib/dev/acpica/include/acinterp.h>
49 #include <contrib/dev/acpica/include/acevents.h>
50
51 #define _COMPONENT          ACPI_EXECUTER
52         ACPI_MODULE_NAME    ("exmutex")
53
54 /* Local prototypes */
55
56 static void
57 AcpiExLinkMutex (
58     ACPI_OPERAND_OBJECT     *ObjDesc,
59     ACPI_THREAD_STATE       *Thread);
60
61
62 /*******************************************************************************
63  *
64  * FUNCTION:    AcpiExUnlinkMutex
65  *
66  * PARAMETERS:  ObjDesc             - The mutex to be unlinked
67  *
68  * RETURN:      None
69  *
70  * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list
71  *
72  ******************************************************************************/
73
74 void
75 AcpiExUnlinkMutex (
76     ACPI_OPERAND_OBJECT     *ObjDesc)
77 {
78     ACPI_THREAD_STATE       *Thread = ObjDesc->Mutex.OwnerThread;
79
80
81     if (!Thread)
82     {
83         return;
84     }
85
86     /* Doubly linked list */
87
88     if (ObjDesc->Mutex.Next)
89     {
90         (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev;
91     }
92
93     if (ObjDesc->Mutex.Prev)
94     {
95         (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next;
96
97         /*
98          * Migrate the previous sync level associated with this mutex to
99          * the previous mutex on the list so that it may be preserved.
100          * This handles the case where several mutexes have been acquired
101          * at the same level, but are not released in opposite order.
102          */
103         (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel =
104             ObjDesc->Mutex.OriginalSyncLevel;
105     }
106     else
107     {
108         Thread->AcquiredMutexList = ObjDesc->Mutex.Next;
109     }
110 }
111
112
113 /*******************************************************************************
114  *
115  * FUNCTION:    AcpiExLinkMutex
116  *
117  * PARAMETERS:  ObjDesc             - The mutex to be linked
118  *              Thread              - Current executing thread object
119  *
120  * RETURN:      None
121  *
122  * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk
123  *
124  ******************************************************************************/
125
126 static void
127 AcpiExLinkMutex (
128     ACPI_OPERAND_OBJECT     *ObjDesc,
129     ACPI_THREAD_STATE       *Thread)
130 {
131     ACPI_OPERAND_OBJECT     *ListHead;
132
133
134     ListHead = Thread->AcquiredMutexList;
135
136     /* This object will be the first object in the list */
137
138     ObjDesc->Mutex.Prev = NULL;
139     ObjDesc->Mutex.Next = ListHead;
140
141     /* Update old first object to point back to this object */
142
143     if (ListHead)
144     {
145         ListHead->Mutex.Prev = ObjDesc;
146     }
147
148     /* Update list head */
149
150     Thread->AcquiredMutexList = ObjDesc;
151 }
152
153
154 /*******************************************************************************
155  *
156  * FUNCTION:    AcpiExAcquireMutexObject
157  *
158  * PARAMETERS:  Timeout             - Timeout in milliseconds
159  *              ObjDesc             - Mutex object
160  *              ThreadId            - Current thread state
161  *
162  * RETURN:      Status
163  *
164  * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
165  *              path that supports multiple acquires by the same thread.
166  *
167  * MUTEX:       Interpreter must be locked
168  *
169  * NOTE: This interface is called from three places:
170  * 1) From AcpiExAcquireMutex, via an AML Acquire() operator
171  * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the
172  *    global lock
173  * 3) From the external interface, AcpiAcquireGlobalLock
174  *
175  ******************************************************************************/
176
177 ACPI_STATUS
178 AcpiExAcquireMutexObject (
179     UINT16                  Timeout,
180     ACPI_OPERAND_OBJECT     *ObjDesc,
181     ACPI_THREAD_ID          ThreadId)
182 {
183     ACPI_STATUS             Status;
184
185
186     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc);
187
188
189     if (!ObjDesc)
190     {
191         return_ACPI_STATUS (AE_BAD_PARAMETER);
192     }
193
194     /* Support for multiple acquires by the owning thread */
195
196     if (ObjDesc->Mutex.ThreadId == ThreadId)
197     {
198         /*
199          * The mutex is already owned by this thread, just increment the
200          * acquisition depth
201          */
202         ObjDesc->Mutex.AcquisitionDepth++;
203         return_ACPI_STATUS (AE_OK);
204     }
205
206     /* Acquire the mutex, wait if necessary. Special case for Global Lock */
207
208     if (ObjDesc == AcpiGbl_GlobalLockMutex)
209     {
210         Status = AcpiEvAcquireGlobalLock (Timeout);
211     }
212     else
213     {
214         Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex,
215                     Timeout);
216     }
217
218     if (ACPI_FAILURE (Status))
219     {
220         /* Includes failure from a timeout on TimeDesc */
221
222         return_ACPI_STATUS (Status);
223     }
224
225     /* Acquired the mutex: update mutex object */
226
227     ObjDesc->Mutex.ThreadId = ThreadId;
228     ObjDesc->Mutex.AcquisitionDepth = 1;
229     ObjDesc->Mutex.OriginalSyncLevel = 0;
230     ObjDesc->Mutex.OwnerThread = NULL;      /* Used only for AML Acquire() */
231
232     return_ACPI_STATUS (AE_OK);
233 }
234
235
236 /*******************************************************************************
237  *
238  * FUNCTION:    AcpiExAcquireMutex
239  *
240  * PARAMETERS:  TimeDesc            - Timeout integer
241  *              ObjDesc             - Mutex object
242  *              WalkState           - Current method execution state
243  *
244  * RETURN:      Status
245  *
246  * DESCRIPTION: Acquire an AML mutex
247  *
248  ******************************************************************************/
249
250 ACPI_STATUS
251 AcpiExAcquireMutex (
252     ACPI_OPERAND_OBJECT     *TimeDesc,
253     ACPI_OPERAND_OBJECT     *ObjDesc,
254     ACPI_WALK_STATE         *WalkState)
255 {
256     ACPI_STATUS             Status;
257
258
259     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc);
260
261
262     if (!ObjDesc)
263     {
264         return_ACPI_STATUS (AE_BAD_PARAMETER);
265     }
266
267     /* Must have a valid thread state struct */
268
269     if (!WalkState->Thread)
270     {
271         ACPI_ERROR ((AE_INFO,
272             "Cannot acquire Mutex [%4.4s], null thread info",
273             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
274         return_ACPI_STATUS (AE_AML_INTERNAL);
275     }
276
277     /*
278      * Current sync level must be less than or equal to the sync level of the
279      * mutex. This mechanism provides some deadlock prevention
280      */
281     if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel)
282     {
283         ACPI_ERROR ((AE_INFO,
284             "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%u)",
285             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
286             WalkState->Thread->CurrentSyncLevel));
287         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
288     }
289
290     Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value,
291                 ObjDesc, WalkState->Thread->ThreadId);
292     if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1)
293     {
294         /* Save Thread object, original/current sync levels */
295
296         ObjDesc->Mutex.OwnerThread = WalkState->Thread;
297         ObjDesc->Mutex.OriginalSyncLevel = WalkState->Thread->CurrentSyncLevel;
298         WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.SyncLevel;
299
300         /* Link the mutex to the current thread for force-unlock at method exit */
301
302         AcpiExLinkMutex (ObjDesc, WalkState->Thread);
303     }
304
305     return_ACPI_STATUS (Status);
306 }
307
308
309 /*******************************************************************************
310  *
311  * FUNCTION:    AcpiExReleaseMutexObject
312  *
313  * PARAMETERS:  ObjDesc             - The object descriptor for this op
314  *
315  * RETURN:      Status
316  *
317  * DESCRIPTION: Release a previously acquired Mutex, low level interface.
318  *              Provides a common path that supports multiple releases (after
319  *              previous multiple acquires) by the same thread.
320  *
321  * MUTEX:       Interpreter must be locked
322  *
323  * NOTE: This interface is called from three places:
324  * 1) From AcpiExReleaseMutex, via an AML Acquire() operator
325  * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the
326  *    global lock
327  * 3) From the external interface, AcpiReleaseGlobalLock
328  *
329  ******************************************************************************/
330
331 ACPI_STATUS
332 AcpiExReleaseMutexObject (
333     ACPI_OPERAND_OBJECT     *ObjDesc)
334 {
335     ACPI_STATUS             Status = AE_OK;
336
337
338     ACPI_FUNCTION_TRACE (ExReleaseMutexObject);
339
340
341     if (ObjDesc->Mutex.AcquisitionDepth == 0)
342     {
343         return_ACPI_STATUS (AE_NOT_ACQUIRED);
344     }
345
346     /* Match multiple Acquires with multiple Releases */
347
348     ObjDesc->Mutex.AcquisitionDepth--;
349     if (ObjDesc->Mutex.AcquisitionDepth != 0)
350     {
351         /* Just decrement the depth and return */
352
353         return_ACPI_STATUS (AE_OK);
354     }
355
356     if (ObjDesc->Mutex.OwnerThread)
357     {
358         /* Unlink the mutex from the owner's list */
359
360         AcpiExUnlinkMutex (ObjDesc);
361         ObjDesc->Mutex.OwnerThread = NULL;
362     }
363
364     /* Release the mutex, special case for Global Lock */
365
366     if (ObjDesc == AcpiGbl_GlobalLockMutex)
367     {
368         Status = AcpiEvReleaseGlobalLock ();
369     }
370     else
371     {
372         AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
373     }
374
375     /* Clear mutex info */
376
377     ObjDesc->Mutex.ThreadId = 0;
378     return_ACPI_STATUS (Status);
379 }
380
381
382 /*******************************************************************************
383  *
384  * FUNCTION:    AcpiExReleaseMutex
385  *
386  * PARAMETERS:  ObjDesc             - The object descriptor for this op
387  *              WalkState           - Current method execution state
388  *
389  * RETURN:      Status
390  *
391  * DESCRIPTION: Release a previously acquired Mutex.
392  *
393  ******************************************************************************/
394
395 ACPI_STATUS
396 AcpiExReleaseMutex (
397     ACPI_OPERAND_OBJECT     *ObjDesc,
398     ACPI_WALK_STATE         *WalkState)
399 {
400     ACPI_STATUS             Status = AE_OK;
401     UINT8                   PreviousSyncLevel;
402     ACPI_THREAD_STATE       *OwnerThread;
403
404
405     ACPI_FUNCTION_TRACE (ExReleaseMutex);
406
407
408     if (!ObjDesc)
409     {
410         return_ACPI_STATUS (AE_BAD_PARAMETER);
411     }
412
413     OwnerThread = ObjDesc->Mutex.OwnerThread;
414
415     /* The mutex must have been previously acquired in order to release it */
416
417     if (!OwnerThread)
418     {
419         ACPI_ERROR ((AE_INFO,
420             "Cannot release Mutex [%4.4s], not acquired",
421             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
422         return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
423     }
424
425     /* Must have a valid thread ID */
426
427     if (!WalkState->Thread)
428     {
429         ACPI_ERROR ((AE_INFO,
430             "Cannot release Mutex [%4.4s], null thread info",
431             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
432         return_ACPI_STATUS (AE_AML_INTERNAL);
433     }
434
435     /*
436      * The Mutex is owned, but this thread must be the owner.
437      * Special case for Global Lock, any thread can release
438      */
439     if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) &&
440         (ObjDesc != AcpiGbl_GlobalLockMutex))
441     {
442         ACPI_ERROR ((AE_INFO,
443             "Thread %u cannot release Mutex [%4.4s] acquired by thread %u",
444             (UINT32) WalkState->Thread->ThreadId,
445             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
446             (UINT32) OwnerThread->ThreadId));
447         return_ACPI_STATUS (AE_AML_NOT_OWNER);
448     }
449
450     /*
451      * The sync level of the mutex must be equal to the current sync level. In
452      * other words, the current level means that at least one mutex at that
453      * level is currently being held. Attempting to release a mutex of a
454      * different level can only mean that the mutex ordering rule is being
455      * violated. This behavior is clarified in ACPI 4.0 specification.
456      */
457     if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel)
458     {
459         ACPI_ERROR ((AE_INFO,
460             "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %u current %u",
461             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
462             ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel));
463         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
464     }
465
466     /*
467      * Get the previous SyncLevel from the head of the acquired mutex list.
468      * This handles the case where several mutexes at the same level have been
469      * acquired, but are not released in reverse order.
470      */
471     PreviousSyncLevel =
472         OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel;
473
474     Status = AcpiExReleaseMutexObject (ObjDesc);
475     if (ACPI_FAILURE (Status))
476     {
477         return_ACPI_STATUS (Status);
478     }
479
480     if (ObjDesc->Mutex.AcquisitionDepth == 0)
481     {
482         /* Restore the previous SyncLevel */
483
484         OwnerThread->CurrentSyncLevel = PreviousSyncLevel;
485     }
486
487     return_ACPI_STATUS (Status);
488 }
489
490
491 /*******************************************************************************
492  *
493  * FUNCTION:    AcpiExReleaseAllMutexes
494  *
495  * PARAMETERS:  Thread              - Current executing thread object
496  *
497  * RETURN:      Status
498  *
499  * DESCRIPTION: Release all mutexes held by this thread
500  *
501  * NOTE: This function is called as the thread is exiting the interpreter.
502  * Mutexes are not released when an individual control method is exited, but
503  * only when the parent thread actually exits the interpreter. This allows one
504  * method to acquire a mutex, and a different method to release it, as long as
505  * this is performed underneath a single parent control method.
506  *
507  ******************************************************************************/
508
509 void
510 AcpiExReleaseAllMutexes (
511     ACPI_THREAD_STATE       *Thread)
512 {
513     ACPI_OPERAND_OBJECT     *Next = Thread->AcquiredMutexList;
514     ACPI_OPERAND_OBJECT     *ObjDesc;
515
516
517     ACPI_FUNCTION_NAME (ExReleaseAllMutexes);
518
519
520     /* Traverse the list of owned mutexes, releasing each one */
521
522     while (Next)
523     {
524         ObjDesc = Next;
525         Next = ObjDesc->Mutex.Next;
526
527         ObjDesc->Mutex.Prev = NULL;
528         ObjDesc->Mutex.Next = NULL;
529         ObjDesc->Mutex.AcquisitionDepth = 0;
530
531         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
532             "Force-releasing held mutex: %p\n", ObjDesc));
533
534         /* Release the mutex, special case for Global Lock */
535
536         if (ObjDesc == AcpiGbl_GlobalLockMutex)
537         {
538             /* Ignore errors */
539
540             (void) AcpiEvReleaseGlobalLock ();
541         }
542         else
543         {
544             AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
545         }
546
547         /* Mark mutex unowned */
548
549         ObjDesc->Mutex.OwnerThread = NULL;
550         ObjDesc->Mutex.ThreadId = 0;
551
552         /* Update Thread SyncLevel (Last mutex is the important one) */
553
554         Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;
555     }
556 }