kernel: Sync ACPICA with Intel's version 20140214.
[dragonfly.git] / sys / contrib / dev / acpica / source / components / dispatcher / dsmethod.c
1 /******************************************************************************
2  *
3  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2014, 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 __DSMETHOD_C__
45
46 #include "acpi.h"
47 #include "accommon.h"
48 #include "acdispat.h"
49 #include "acinterp.h"
50 #include "acnamesp.h"
51 #include "acdisasm.h"
52 #include "acparser.h"
53 #include "amlcode.h"
54
55
56 #define _COMPONENT          ACPI_DISPATCHER
57         ACPI_MODULE_NAME    ("dsmethod")
58
59 /* Local prototypes */
60
61 static ACPI_STATUS
62 AcpiDsDetectNamedOpcodes (
63     ACPI_WALK_STATE         *WalkState,
64     ACPI_PARSE_OBJECT       **OutOp);
65
66 static ACPI_STATUS
67 AcpiDsCreateMethodMutex (
68     ACPI_OPERAND_OBJECT     *MethodDesc);
69
70
71 /*******************************************************************************
72  *
73  * FUNCTION:    AcpiDsAutoSerializeMethod
74  *
75  * PARAMETERS:  Node                        - Namespace Node of the method
76  *              ObjDesc                     - Method object attached to node
77  *
78  * RETURN:      Status
79  *
80  * DESCRIPTION: Parse a control method AML to scan for control methods that
81  *              need serialization due to the creation of named objects.
82  *
83  * NOTE: It is a bit of overkill to mark all such methods serialized, since
84  * there is only a problem if the method actually blocks during execution.
85  * A blocking operation is, for example, a Sleep() operation, or any access
86  * to an operation region. However, it is probably not possible to easily
87  * detect whether a method will block or not, so we simply mark all suspicious
88  * methods as serialized.
89  *
90  * NOTE2: This code is essentially a generic routine for parsing a single
91  * control method.
92  *
93  ******************************************************************************/
94
95 ACPI_STATUS
96 AcpiDsAutoSerializeMethod (
97     ACPI_NAMESPACE_NODE     *Node,
98     ACPI_OPERAND_OBJECT     *ObjDesc)
99 {
100     ACPI_STATUS             Status;
101     ACPI_PARSE_OBJECT       *Op = NULL;
102     ACPI_WALK_STATE         *WalkState;
103
104
105     ACPI_FUNCTION_TRACE_PTR (DsAutoSerializeMethod, Node);
106
107
108     ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
109         "Method auto-serialization parse [%4.4s] %p\n",
110         AcpiUtGetNodeName (Node), Node));
111
112     /* Create/Init a root op for the method parse tree */
113
114     Op = AcpiPsAllocOp (AML_METHOD_OP);
115     if (!Op)
116     {
117         return_ACPI_STATUS (AE_NO_MEMORY);
118     }
119
120     AcpiPsSetName (Op, Node->Name.Integer);
121     Op->Common.Node = Node;
122
123     /* Create and initialize a new walk state */
124
125     WalkState = AcpiDsCreateWalkState (Node->OwnerId, NULL, NULL, NULL);
126     if (!WalkState)
127     {
128         return_ACPI_STATUS (AE_NO_MEMORY);
129     }
130
131     Status = AcpiDsInitAmlWalk (WalkState, Op, Node, ObjDesc->Method.AmlStart,
132                 ObjDesc->Method.AmlLength, NULL, 0);
133     if (ACPI_FAILURE (Status))
134     {
135         AcpiDsDeleteWalkState (WalkState);
136         return_ACPI_STATUS (Status);
137     }
138
139     WalkState->DescendingCallback = AcpiDsDetectNamedOpcodes;
140
141     /* Parse the method, scan for creation of named objects */
142
143     Status = AcpiPsParseAml (WalkState);
144     if (ACPI_FAILURE (Status))
145     {
146         return_ACPI_STATUS (Status);
147     }
148
149     AcpiPsDeleteParseTree (Op);
150     return_ACPI_STATUS (Status);
151 }
152
153
154 /*******************************************************************************
155  *
156  * FUNCTION:    AcpiDsDetectNamedOpcodes
157  *
158  * PARAMETERS:  WalkState       - Current state of the parse tree walk
159  *              OutOp           - Unused, required for parser interface
160  *
161  * RETURN:      Status
162  *
163  * DESCRIPTION: Descending callback used during the loading of ACPI tables.
164  *              Currently used to detect methods that must be marked serialized
165  *              in order to avoid problems with the creation of named objects.
166  *
167  ******************************************************************************/
168
169 static ACPI_STATUS
170 AcpiDsDetectNamedOpcodes (
171     ACPI_WALK_STATE         *WalkState,
172     ACPI_PARSE_OBJECT       **OutOp)
173 {
174
175     ACPI_FUNCTION_NAME (AcpiDsDetectNamedOpcodes);
176
177
178     /* We are only interested in opcodes that create a new name */
179
180     if (!(WalkState->OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_FIELD)))
181     {
182         return (AE_OK);
183     }
184
185     /*
186      * At this point, we know we have a Named object opcode.
187      * Mark the method as serialized. Later code will create a mutex for
188      * this method to enforce serialization.
189      */
190     WalkState->MethodDesc->Method.InfoFlags |= ACPI_METHOD_SERIALIZED;
191
192     ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
193         "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
194         WalkState->MethodNode->Name.Ascii, WalkState->MethodNode,
195         WalkState->OpInfo->Name, WalkState->Opcode));
196
197     /* Abort the parse, no need to examine this method any further */
198
199     return (AE_CTRL_TERMINATE);
200 }
201
202
203 /*******************************************************************************
204  *
205  * FUNCTION:    AcpiDsMethodError
206  *
207  * PARAMETERS:  Status          - Execution status
208  *              WalkState       - Current state
209  *
210  * RETURN:      Status
211  *
212  * DESCRIPTION: Called on method error. Invoke the global exception handler if
213  *              present, dump the method data if the disassembler is configured
214  *
215  *              Note: Allows the exception handler to change the status code
216  *
217  ******************************************************************************/
218
219 ACPI_STATUS
220 AcpiDsMethodError (
221     ACPI_STATUS             Status,
222     ACPI_WALK_STATE         *WalkState)
223 {
224     ACPI_FUNCTION_ENTRY ();
225
226
227     /* Ignore AE_OK and control exception codes */
228
229     if (ACPI_SUCCESS (Status) ||
230         (Status & AE_CODE_CONTROL))
231     {
232         return (Status);
233     }
234
235     /* Invoke the global exception handler */
236
237     if (AcpiGbl_ExceptionHandler)
238     {
239         /* Exit the interpreter, allow handler to execute methods */
240
241         AcpiExExitInterpreter ();
242
243         /*
244          * Handler can map the exception code to anything it wants, including
245          * AE_OK, in which case the executing method will not be aborted.
246          */
247         Status = AcpiGbl_ExceptionHandler (Status,
248                     WalkState->MethodNode ?
249                         WalkState->MethodNode->Name.Integer : 0,
250                     WalkState->Opcode, WalkState->AmlOffset, NULL);
251         AcpiExEnterInterpreter ();
252     }
253
254     AcpiDsClearImplicitReturn (WalkState);
255
256 #ifdef ACPI_DISASSEMBLER
257     if (ACPI_FAILURE (Status))
258     {
259         /* Display method locals/args if disassembler is present */
260
261         AcpiDmDumpMethodInfo (Status, WalkState, WalkState->Op);
262     }
263 #endif
264
265     return (Status);
266 }
267
268
269 /*******************************************************************************
270  *
271  * FUNCTION:    AcpiDsCreateMethodMutex
272  *
273  * PARAMETERS:  ObjDesc             - The method object
274  *
275  * RETURN:      Status
276  *
277  * DESCRIPTION: Create a mutex object for a serialized control method
278  *
279  ******************************************************************************/
280
281 static ACPI_STATUS
282 AcpiDsCreateMethodMutex (
283     ACPI_OPERAND_OBJECT     *MethodDesc)
284 {
285     ACPI_OPERAND_OBJECT     *MutexDesc;
286     ACPI_STATUS             Status;
287
288
289     ACPI_FUNCTION_TRACE (DsCreateMethodMutex);
290
291
292     /* Create the new mutex object */
293
294     MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX);
295     if (!MutexDesc)
296     {
297         return_ACPI_STATUS (AE_NO_MEMORY);
298     }
299
300     /* Create the actual OS Mutex */
301
302     Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex);
303     if (ACPI_FAILURE (Status))
304     {
305         AcpiUtDeleteObjectDesc (MutexDesc);
306         return_ACPI_STATUS (Status);
307     }
308
309     MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel;
310     MethodDesc->Method.Mutex = MutexDesc;
311     return_ACPI_STATUS (AE_OK);
312 }
313
314
315 /*******************************************************************************
316  *
317  * FUNCTION:    AcpiDsBeginMethodExecution
318  *
319  * PARAMETERS:  MethodNode          - Node of the method
320  *              ObjDesc             - The method object
321  *              WalkState           - current state, NULL if not yet executing
322  *                                    a method.
323  *
324  * RETURN:      Status
325  *
326  * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
327  *              increments the thread count, and waits at the method semaphore
328  *              for clearance to execute.
329  *
330  ******************************************************************************/
331
332 ACPI_STATUS
333 AcpiDsBeginMethodExecution (
334     ACPI_NAMESPACE_NODE     *MethodNode,
335     ACPI_OPERAND_OBJECT     *ObjDesc,
336     ACPI_WALK_STATE         *WalkState)
337 {
338     ACPI_STATUS             Status = AE_OK;
339
340
341     ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode);
342
343
344     if (!MethodNode)
345     {
346         return_ACPI_STATUS (AE_NULL_ENTRY);
347     }
348
349     /* Prevent wraparound of thread count */
350
351     if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX)
352     {
353         ACPI_ERROR ((AE_INFO,
354             "Method reached maximum reentrancy limit (255)"));
355         return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
356     }
357
358     /*
359      * If this method is serialized, we need to acquire the method mutex.
360      */
361     if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED)
362     {
363         /*
364          * Create a mutex for the method if it is defined to be Serialized
365          * and a mutex has not already been created. We defer the mutex creation
366          * until a method is actually executed, to minimize the object count
367          */
368         if (!ObjDesc->Method.Mutex)
369         {
370             Status = AcpiDsCreateMethodMutex (ObjDesc);
371             if (ACPI_FAILURE (Status))
372             {
373                 return_ACPI_STATUS (Status);
374             }
375         }
376
377         /*
378          * The CurrentSyncLevel (per-thread) must be less than or equal to
379          * the sync level of the method. This mechanism provides some
380          * deadlock prevention
381          *
382          * Top-level method invocation has no walk state at this point
383          */
384         if (WalkState &&
385             (WalkState->Thread->CurrentSyncLevel > ObjDesc->Method.Mutex->Mutex.SyncLevel))
386         {
387             ACPI_ERROR ((AE_INFO,
388                 "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)",
389                 AcpiUtGetNodeName (MethodNode),
390                 WalkState->Thread->CurrentSyncLevel));
391
392             return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
393         }
394
395         /*
396          * Obtain the method mutex if necessary. Do not acquire mutex for a
397          * recursive call.
398          */
399         if (!WalkState ||
400             !ObjDesc->Method.Mutex->Mutex.ThreadId ||
401             (WalkState->Thread->ThreadId != ObjDesc->Method.Mutex->Mutex.ThreadId))
402         {
403             /*
404              * Acquire the method mutex. This releases the interpreter if we
405              * block (and reacquires it before it returns)
406              */
407             Status = AcpiExSystemWaitMutex (ObjDesc->Method.Mutex->Mutex.OsMutex,
408                         ACPI_WAIT_FOREVER);
409             if (ACPI_FAILURE (Status))
410             {
411                 return_ACPI_STATUS (Status);
412             }
413
414             /* Update the mutex and walk info and save the original SyncLevel */
415
416             if (WalkState)
417             {
418                 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
419                     WalkState->Thread->CurrentSyncLevel;
420
421                 ObjDesc->Method.Mutex->Mutex.ThreadId = WalkState->Thread->ThreadId;
422                 WalkState->Thread->CurrentSyncLevel = ObjDesc->Method.SyncLevel;
423             }
424             else
425             {
426                 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
427                     ObjDesc->Method.Mutex->Mutex.SyncLevel;
428             }
429         }
430
431         /* Always increase acquisition depth */
432
433         ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++;
434     }
435
436     /*
437      * Allocate an Owner ID for this method, only if this is the first thread
438      * to begin concurrent execution. We only need one OwnerId, even if the
439      * method is invoked recursively.
440      */
441     if (!ObjDesc->Method.OwnerId)
442     {
443         Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
444         if (ACPI_FAILURE (Status))
445         {
446             goto Cleanup;
447         }
448     }
449
450     /*
451      * Increment the method parse tree thread count since it has been
452      * reentered one more time (even if it is the same thread)
453      */
454     ObjDesc->Method.ThreadCount++;
455     AcpiMethodCount++;
456     return_ACPI_STATUS (Status);
457
458
459 Cleanup:
460     /* On error, must release the method mutex (if present) */
461
462     if (ObjDesc->Method.Mutex)
463     {
464         AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex);
465     }
466     return_ACPI_STATUS (Status);
467 }
468
469
470 /*******************************************************************************
471  *
472  * FUNCTION:    AcpiDsCallControlMethod
473  *
474  * PARAMETERS:  Thread              - Info for this thread
475  *              ThisWalkState       - Current walk state
476  *              Op                  - Current Op to be walked
477  *
478  * RETURN:      Status
479  *
480  * DESCRIPTION: Transfer execution to a called control method
481  *
482  ******************************************************************************/
483
484 ACPI_STATUS
485 AcpiDsCallControlMethod (
486     ACPI_THREAD_STATE       *Thread,
487     ACPI_WALK_STATE         *ThisWalkState,
488     ACPI_PARSE_OBJECT       *Op)
489 {
490     ACPI_STATUS             Status;
491     ACPI_NAMESPACE_NODE     *MethodNode;
492     ACPI_WALK_STATE         *NextWalkState = NULL;
493     ACPI_OPERAND_OBJECT     *ObjDesc;
494     ACPI_EVALUATE_INFO      *Info;
495     UINT32                  i;
496
497
498     ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState);
499
500     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Calling method %p, currentstate=%p\n",
501         ThisWalkState->PrevOp, ThisWalkState));
502
503     /*
504      * Get the namespace entry for the control method we are about to call
505      */
506     MethodNode = ThisWalkState->MethodCallNode;
507     if (!MethodNode)
508     {
509         return_ACPI_STATUS (AE_NULL_ENTRY);
510     }
511
512     ObjDesc = AcpiNsGetAttachedObject (MethodNode);
513     if (!ObjDesc)
514     {
515         return_ACPI_STATUS (AE_NULL_OBJECT);
516     }
517
518     /* Init for new method, possibly wait on method mutex */
519
520     Status = AcpiDsBeginMethodExecution (MethodNode, ObjDesc,
521                 ThisWalkState);
522     if (ACPI_FAILURE (Status))
523     {
524         return_ACPI_STATUS (Status);
525     }
526
527     /* Begin method parse/execution. Create a new walk state */
528
529     NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwnerId,
530                         NULL, ObjDesc, Thread);
531     if (!NextWalkState)
532     {
533         Status = AE_NO_MEMORY;
534         goto Cleanup;
535     }
536
537     /*
538      * The resolved arguments were put on the previous walk state's operand
539      * stack. Operands on the previous walk state stack always
540      * start at index 0. Also, null terminate the list of arguments
541      */
542     ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL;
543
544     /*
545      * Allocate and initialize the evaluation information block
546      * TBD: this is somewhat inefficient, should change interface to
547      * DsInitAmlWalk. For now, keeps this struct off the CPU stack
548      */
549     Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
550     if (!Info)
551     {
552         Status = AE_NO_MEMORY;
553         goto Cleanup;
554     }
555
556     Info->Parameters = &ThisWalkState->Operands[0];
557
558     Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode,
559                 ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength,
560                 Info, ACPI_IMODE_EXECUTE);
561
562     ACPI_FREE (Info);
563     if (ACPI_FAILURE (Status))
564     {
565         goto Cleanup;
566     }
567
568     /*
569      * Delete the operands on the previous walkstate operand stack
570      * (they were copied to new objects)
571      */
572     for (i = 0; i < ObjDesc->Method.ParamCount; i++)
573     {
574         AcpiUtRemoveReference (ThisWalkState->Operands [i]);
575         ThisWalkState->Operands [i] = NULL;
576     }
577
578     /* Clear the operand stack */
579
580     ThisWalkState->NumOperands = 0;
581
582     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
583         "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
584         MethodNode->Name.Ascii, NextWalkState));
585
586     /* Invoke an internal method if necessary */
587
588     if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY)
589     {
590         Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState);
591         if (Status == AE_OK)
592         {
593             Status = AE_CTRL_TERMINATE;
594         }
595     }
596
597     return_ACPI_STATUS (Status);
598
599
600 Cleanup:
601
602     /* On error, we must terminate the method properly */
603
604     AcpiDsTerminateControlMethod (ObjDesc, NextWalkState);
605     if (NextWalkState)
606     {
607         AcpiDsDeleteWalkState (NextWalkState);
608     }
609
610     return_ACPI_STATUS (Status);
611 }
612
613
614 /*******************************************************************************
615  *
616  * FUNCTION:    AcpiDsRestartControlMethod
617  *
618  * PARAMETERS:  WalkState           - State for preempted method (caller)
619  *              ReturnDesc          - Return value from the called method
620  *
621  * RETURN:      Status
622  *
623  * DESCRIPTION: Restart a method that was preempted by another (nested) method
624  *              invocation. Handle the return value (if any) from the callee.
625  *
626  ******************************************************************************/
627
628 ACPI_STATUS
629 AcpiDsRestartControlMethod (
630     ACPI_WALK_STATE         *WalkState,
631     ACPI_OPERAND_OBJECT     *ReturnDesc)
632 {
633     ACPI_STATUS             Status;
634     int                     SameAsImplicitReturn;
635
636
637     ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState);
638
639
640     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
641         "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
642         AcpiUtGetNodeName (WalkState->MethodNode),
643         WalkState->MethodCallOp, ReturnDesc));
644
645     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
646         "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
647         WalkState->ReturnUsed,
648         WalkState->Results, WalkState));
649
650     /* Did the called method return a value? */
651
652     if (ReturnDesc)
653     {
654         /* Is the implicit return object the same as the return desc? */
655
656         SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc);
657
658         /* Are we actually going to use the return value? */
659
660         if (WalkState->ReturnUsed)
661         {
662             /* Save the return value from the previous method */
663
664             Status = AcpiDsResultPush (ReturnDesc, WalkState);
665             if (ACPI_FAILURE (Status))
666             {
667                 AcpiUtRemoveReference (ReturnDesc);
668                 return_ACPI_STATUS (Status);
669             }
670
671             /*
672              * Save as THIS method's return value in case it is returned
673              * immediately to yet another method
674              */
675             WalkState->ReturnDesc = ReturnDesc;
676         }
677
678         /*
679          * The following code is the optional support for the so-called
680          * "implicit return". Some AML code assumes that the last value of the
681          * method is "implicitly" returned to the caller, in the absence of an
682          * explicit return value.
683          *
684          * Just save the last result of the method as the return value.
685          *
686          * NOTE: this is optional because the ASL language does not actually
687          * support this behavior.
688          */
689         else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) ||
690                  SameAsImplicitReturn)
691         {
692             /*
693              * Delete the return value if it will not be used by the
694              * calling method or remove one reference if the explicit return
695              * is the same as the implicit return value.
696              */
697             AcpiUtRemoveReference (ReturnDesc);
698         }
699     }
700
701     return_ACPI_STATUS (AE_OK);
702 }
703
704
705 /*******************************************************************************
706  *
707  * FUNCTION:    AcpiDsTerminateControlMethod
708  *
709  * PARAMETERS:  MethodDesc          - Method object
710  *              WalkState           - State associated with the method
711  *
712  * RETURN:      None
713  *
714  * DESCRIPTION: Terminate a control method. Delete everything that the method
715  *              created, delete all locals and arguments, and delete the parse
716  *              tree if requested.
717  *
718  * MUTEX:       Interpreter is locked
719  *
720  ******************************************************************************/
721
722 void
723 AcpiDsTerminateControlMethod (
724     ACPI_OPERAND_OBJECT     *MethodDesc,
725     ACPI_WALK_STATE         *WalkState)
726 {
727
728     ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState);
729
730
731     /* MethodDesc is required, WalkState is optional */
732
733     if (!MethodDesc)
734     {
735         return_VOID;
736     }
737
738     if (WalkState)
739     {
740         /* Delete all arguments and locals */
741
742         AcpiDsMethodDataDeleteAll (WalkState);
743
744         /*
745          * If method is serialized, release the mutex and restore the
746          * current sync level for this thread
747          */
748         if (MethodDesc->Method.Mutex)
749         {
750             /* Acquisition Depth handles recursive calls */
751
752             MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--;
753             if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth)
754             {
755                 WalkState->Thread->CurrentSyncLevel =
756                     MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel;
757
758                 AcpiOsReleaseMutex (MethodDesc->Method.Mutex->Mutex.OsMutex);
759                 MethodDesc->Method.Mutex->Mutex.ThreadId = 0;
760             }
761         }
762
763         /*
764          * Delete any namespace objects created anywhere within the
765          * namespace by the execution of this method. Unless:
766          * 1) This method is a module-level executable code method, in which
767          *    case we want make the objects permanent.
768          * 2) There are other threads executing the method, in which case we
769          *    will wait until the last thread has completed.
770          */
771         if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) &&
772              (MethodDesc->Method.ThreadCount == 1))
773         {
774             /* Delete any direct children of (created by) this method */
775
776             AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode);
777
778             /*
779              * Delete any objects that were created by this method
780              * elsewhere in the namespace (if any were created).
781              * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
782              * deletion such that we don't have to perform an entire
783              * namespace walk for every control method execution.
784              */
785             if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE)
786             {
787                 AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId);
788                 MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_MODIFIED_NAMESPACE;
789             }
790         }
791     }
792
793     /* Decrement the thread count on the method */
794
795     if (MethodDesc->Method.ThreadCount)
796     {
797         MethodDesc->Method.ThreadCount--;
798     }
799     else
800     {
801         ACPI_ERROR ((AE_INFO,
802             "Invalid zero thread count in method"));
803     }
804
805     /* Are there any other threads currently executing this method? */
806
807     if (MethodDesc->Method.ThreadCount)
808     {
809         /*
810          * Additional threads. Do not release the OwnerId in this case,
811          * we immediately reuse it for the next thread executing this method
812          */
813         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
814             "*** Completed execution of one thread, %u threads remaining\n",
815             MethodDesc->Method.ThreadCount));
816     }
817     else
818     {
819         /* This is the only executing thread for this method */
820
821         /*
822          * Support to dynamically change a method from NotSerialized to
823          * Serialized if it appears that the method is incorrectly written and
824          * does not support multiple thread execution. The best example of this
825          * is if such a method creates namespace objects and blocks. A second
826          * thread will fail with an AE_ALREADY_EXISTS exception.
827          *
828          * This code is here because we must wait until the last thread exits
829          * before marking the method as serialized.
830          */
831         if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING)
832         {
833             if (WalkState)
834             {
835                 ACPI_INFO ((AE_INFO,
836                     "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error",
837                     WalkState->MethodNode->Name.Ascii));
838             }
839
840             /*
841              * Method tried to create an object twice and was marked as
842              * "pending serialized". The probable cause is that the method
843              * cannot handle reentrancy.
844              *
845              * The method was created as NotSerialized, but it tried to create
846              * a named object and then blocked, causing the second thread
847              * entrance to begin and then fail. Workaround this problem by
848              * marking the method permanently as Serialized when the last
849              * thread exits here.
850              */
851             MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_SERIALIZED_PENDING;
852             MethodDesc->Method.InfoFlags |= ACPI_METHOD_SERIALIZED;
853             MethodDesc->Method.SyncLevel = 0;
854         }
855
856         /* No more threads, we can free the OwnerId */
857
858         if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL))
859         {
860             AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId);
861         }
862     }
863
864     return_VOID;
865 }