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