xref: /freebsd/sys/contrib/dev/acpica/components/dispatcher/dsmethod.c (revision 273c26a3c3bea87a241d6879abd4f991db180bf0)
1 /******************************************************************************
2  *
3  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 <contrib/dev/acpica/include/acpi.h>
45 #include <contrib/dev/acpica/include/accommon.h>
46 #include <contrib/dev/acpica/include/acdispat.h>
47 #include <contrib/dev/acpica/include/acinterp.h>
48 #include <contrib/dev/acpica/include/acnamesp.h>
49 #include <contrib/dev/acpica/include/acparser.h>
50 #include <contrib/dev/acpica/include/amlcode.h>
51 #include <contrib/dev/acpica/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                 ObjDesc->Method.Mutex->Mutex.ThreadId =
465                     AcpiOsGetThreadId ();
466             }
467         }
468 
469         /* Always increase acquisition depth */
470 
471         ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++;
472     }
473 
474     /*
475      * Allocate an Owner ID for this method, only if this is the first thread
476      * to begin concurrent execution. We only need one OwnerId, even if the
477      * method is invoked recursively.
478      */
479     if (!ObjDesc->Method.OwnerId)
480     {
481         Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
482         if (ACPI_FAILURE (Status))
483         {
484             goto Cleanup;
485         }
486     }
487 
488     /*
489      * Increment the method parse tree thread count since it has been
490      * reentered one more time (even if it is the same thread)
491      */
492     ObjDesc->Method.ThreadCount++;
493     AcpiMethodCount++;
494     return_ACPI_STATUS (Status);
495 
496 
497 Cleanup:
498     /* On error, must release the method mutex (if present) */
499 
500     if (ObjDesc->Method.Mutex)
501     {
502         AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex);
503     }
504     return_ACPI_STATUS (Status);
505 }
506 
507 
508 /*******************************************************************************
509  *
510  * FUNCTION:    AcpiDsCallControlMethod
511  *
512  * PARAMETERS:  Thread              - Info for this thread
513  *              ThisWalkState       - Current walk state
514  *              Op                  - Current Op to be walked
515  *
516  * RETURN:      Status
517  *
518  * DESCRIPTION: Transfer execution to a called control method
519  *
520  ******************************************************************************/
521 
522 ACPI_STATUS
523 AcpiDsCallControlMethod (
524     ACPI_THREAD_STATE       *Thread,
525     ACPI_WALK_STATE         *ThisWalkState,
526     ACPI_PARSE_OBJECT       *Op)
527 {
528     ACPI_STATUS             Status;
529     ACPI_NAMESPACE_NODE     *MethodNode;
530     ACPI_WALK_STATE         *NextWalkState = NULL;
531     ACPI_OPERAND_OBJECT     *ObjDesc;
532     ACPI_EVALUATE_INFO      *Info;
533     UINT32                  i;
534 
535 
536     ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState);
537 
538     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
539         "Calling method %p, currentstate=%p\n",
540         ThisWalkState->PrevOp, ThisWalkState));
541 
542     /*
543      * Get the namespace entry for the control method we are about to call
544      */
545     MethodNode = ThisWalkState->MethodCallNode;
546     if (!MethodNode)
547     {
548         return_ACPI_STATUS (AE_NULL_ENTRY);
549     }
550 
551     ObjDesc = AcpiNsGetAttachedObject (MethodNode);
552     if (!ObjDesc)
553     {
554         return_ACPI_STATUS (AE_NULL_OBJECT);
555     }
556 
557     /* Init for new method, possibly wait on method mutex */
558 
559     Status = AcpiDsBeginMethodExecution (
560         MethodNode, ObjDesc, ThisWalkState);
561     if (ACPI_FAILURE (Status))
562     {
563         return_ACPI_STATUS (Status);
564     }
565 
566     /* Begin method parse/execution. Create a new walk state */
567 
568     NextWalkState = AcpiDsCreateWalkState (
569         ObjDesc->Method.OwnerId, NULL, ObjDesc, Thread);
570     if (!NextWalkState)
571     {
572         Status = AE_NO_MEMORY;
573         goto Cleanup;
574     }
575 
576     /*
577      * The resolved arguments were put on the previous walk state's operand
578      * stack. Operands on the previous walk state stack always
579      * start at index 0. Also, null terminate the list of arguments
580      */
581     ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL;
582 
583     /*
584      * Allocate and initialize the evaluation information block
585      * TBD: this is somewhat inefficient, should change interface to
586      * DsInitAmlWalk. For now, keeps this struct off the CPU stack
587      */
588     Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
589     if (!Info)
590     {
591         Status = AE_NO_MEMORY;
592         goto Cleanup;
593     }
594 
595     Info->Parameters = &ThisWalkState->Operands[0];
596 
597     Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode,
598         ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength,
599         Info, ACPI_IMODE_EXECUTE);
600 
601     ACPI_FREE (Info);
602     if (ACPI_FAILURE (Status))
603     {
604         goto Cleanup;
605     }
606 
607     /*
608      * Delete the operands on the previous walkstate operand stack
609      * (they were copied to new objects)
610      */
611     for (i = 0; i < ObjDesc->Method.ParamCount; i++)
612     {
613         AcpiUtRemoveReference (ThisWalkState->Operands [i]);
614         ThisWalkState->Operands [i] = NULL;
615     }
616 
617     /* Clear the operand stack */
618 
619     ThisWalkState->NumOperands = 0;
620 
621     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
622         "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
623         MethodNode->Name.Ascii, NextWalkState));
624 
625     /* Invoke an internal method if necessary */
626 
627     if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY)
628     {
629         Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState);
630         if (Status == AE_OK)
631         {
632             Status = AE_CTRL_TERMINATE;
633         }
634     }
635 
636     return_ACPI_STATUS (Status);
637 
638 
639 Cleanup:
640 
641     /* On error, we must terminate the method properly */
642 
643     AcpiDsTerminateControlMethod (ObjDesc, NextWalkState);
644     AcpiDsDeleteWalkState (NextWalkState);
645 
646     return_ACPI_STATUS (Status);
647 }
648 
649 
650 /*******************************************************************************
651  *
652  * FUNCTION:    AcpiDsRestartControlMethod
653  *
654  * PARAMETERS:  WalkState           - State for preempted method (caller)
655  *              ReturnDesc          - Return value from the called method
656  *
657  * RETURN:      Status
658  *
659  * DESCRIPTION: Restart a method that was preempted by another (nested) method
660  *              invocation. Handle the return value (if any) from the callee.
661  *
662  ******************************************************************************/
663 
664 ACPI_STATUS
665 AcpiDsRestartControlMethod (
666     ACPI_WALK_STATE         *WalkState,
667     ACPI_OPERAND_OBJECT     *ReturnDesc)
668 {
669     ACPI_STATUS             Status;
670     int                     SameAsImplicitReturn;
671 
672 
673     ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState);
674 
675 
676     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
677         "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
678         AcpiUtGetNodeName (WalkState->MethodNode),
679         WalkState->MethodCallOp, ReturnDesc));
680 
681     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
682         "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
683         WalkState->ReturnUsed,
684         WalkState->Results, WalkState));
685 
686     /* Did the called method return a value? */
687 
688     if (ReturnDesc)
689     {
690         /* Is the implicit return object the same as the return desc? */
691 
692         SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc);
693 
694         /* Are we actually going to use the return value? */
695 
696         if (WalkState->ReturnUsed)
697         {
698             /* Save the return value from the previous method */
699 
700             Status = AcpiDsResultPush (ReturnDesc, WalkState);
701             if (ACPI_FAILURE (Status))
702             {
703                 AcpiUtRemoveReference (ReturnDesc);
704                 return_ACPI_STATUS (Status);
705             }
706 
707             /*
708              * Save as THIS method's return value in case it is returned
709              * immediately to yet another method
710              */
711             WalkState->ReturnDesc = ReturnDesc;
712         }
713 
714         /*
715          * The following code is the optional support for the so-called
716          * "implicit return". Some AML code assumes that the last value of the
717          * method is "implicitly" returned to the caller, in the absence of an
718          * explicit return value.
719          *
720          * Just save the last result of the method as the return value.
721          *
722          * NOTE: this is optional because the ASL language does not actually
723          * support this behavior.
724          */
725         else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) ||
726                  SameAsImplicitReturn)
727         {
728             /*
729              * Delete the return value if it will not be used by the
730              * calling method or remove one reference if the explicit return
731              * is the same as the implicit return value.
732              */
733             AcpiUtRemoveReference (ReturnDesc);
734         }
735     }
736 
737     return_ACPI_STATUS (AE_OK);
738 }
739 
740 
741 /*******************************************************************************
742  *
743  * FUNCTION:    AcpiDsTerminateControlMethod
744  *
745  * PARAMETERS:  MethodDesc          - Method object
746  *              WalkState           - State associated with the method
747  *
748  * RETURN:      None
749  *
750  * DESCRIPTION: Terminate a control method. Delete everything that the method
751  *              created, delete all locals and arguments, and delete the parse
752  *              tree if requested.
753  *
754  * MUTEX:       Interpreter is locked
755  *
756  ******************************************************************************/
757 
758 void
759 AcpiDsTerminateControlMethod (
760     ACPI_OPERAND_OBJECT     *MethodDesc,
761     ACPI_WALK_STATE         *WalkState)
762 {
763 
764     ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState);
765 
766 
767     /* MethodDesc is required, WalkState is optional */
768 
769     if (!MethodDesc)
770     {
771         return_VOID;
772     }
773 
774     if (WalkState)
775     {
776         /* Delete all arguments and locals */
777 
778         AcpiDsMethodDataDeleteAll (WalkState);
779 
780         /*
781          * If method is serialized, release the mutex and restore the
782          * current sync level for this thread
783          */
784         if (MethodDesc->Method.Mutex)
785         {
786             /* Acquisition Depth handles recursive calls */
787 
788             MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--;
789             if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth)
790             {
791                 WalkState->Thread->CurrentSyncLevel =
792                     MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel;
793 
794                 AcpiOsReleaseMutex (
795                     MethodDesc->Method.Mutex->Mutex.OsMutex);
796                 MethodDesc->Method.Mutex->Mutex.ThreadId = 0;
797             }
798         }
799 
800         /*
801          * Delete any namespace objects created anywhere within the
802          * namespace by the execution of this method. Unless:
803          * 1) This method is a module-level executable code method, in which
804          *    case we want make the objects permanent.
805          * 2) There are other threads executing the method, in which case we
806          *    will wait until the last thread has completed.
807          */
808         if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) &&
809              (MethodDesc->Method.ThreadCount == 1))
810         {
811             /* Delete any direct children of (created by) this method */
812 
813             AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode);
814 
815             /*
816              * Delete any objects that were created by this method
817              * elsewhere in the namespace (if any were created).
818              * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
819              * deletion such that we don't have to perform an entire
820              * namespace walk for every control method execution.
821              */
822             if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE)
823             {
824                 AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId);
825                 MethodDesc->Method.InfoFlags &=
826                     ~ACPI_METHOD_MODIFIED_NAMESPACE;
827             }
828         }
829     }
830 
831     /* Decrement the thread count on the method */
832 
833     if (MethodDesc->Method.ThreadCount)
834     {
835         MethodDesc->Method.ThreadCount--;
836     }
837     else
838     {
839         ACPI_ERROR ((AE_INFO,
840             "Invalid zero thread count in method"));
841     }
842 
843     /* Are there any other threads currently executing this method? */
844 
845     if (MethodDesc->Method.ThreadCount)
846     {
847         /*
848          * Additional threads. Do not release the OwnerId in this case,
849          * we immediately reuse it for the next thread executing this method
850          */
851         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
852             "*** Completed execution of one thread, %u threads remaining\n",
853             MethodDesc->Method.ThreadCount));
854     }
855     else
856     {
857         /* This is the only executing thread for this method */
858 
859         /*
860          * Support to dynamically change a method from NotSerialized to
861          * Serialized if it appears that the method is incorrectly written and
862          * does not support multiple thread execution. The best example of this
863          * is if such a method creates namespace objects and blocks. A second
864          * thread will fail with an AE_ALREADY_EXISTS exception.
865          *
866          * This code is here because we must wait until the last thread exits
867          * before marking the method as serialized.
868          */
869         if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING)
870         {
871             if (WalkState)
872             {
873                 ACPI_INFO ((
874                     "Marking method %4.4s as Serialized "
875                     "because of AE_ALREADY_EXISTS error",
876                     WalkState->MethodNode->Name.Ascii));
877             }
878 
879             /*
880              * Method tried to create an object twice and was marked as
881              * "pending serialized". The probable cause is that the method
882              * cannot handle reentrancy.
883              *
884              * The method was created as NotSerialized, but it tried to create
885              * a named object and then blocked, causing the second thread
886              * entrance to begin and then fail. Workaround this problem by
887              * marking the method permanently as Serialized when the last
888              * thread exits here.
889              */
890             MethodDesc->Method.InfoFlags &=
891                 ~ACPI_METHOD_SERIALIZED_PENDING;
892 
893             MethodDesc->Method.InfoFlags |=
894                 (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
895             MethodDesc->Method.SyncLevel = 0;
896         }
897 
898         /* No more threads, we can free the OwnerId */
899 
900         if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL))
901         {
902             AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId);
903         }
904     }
905 
906     AcpiExStopTraceMethod ((ACPI_NAMESPACE_NODE *) MethodDesc->Method.Node,
907         MethodDesc, WalkState);
908 
909     return_VOID;
910 }
911