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