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