xref: /minix3/minix/drivers/power/acpi/dispatcher/dsmethod.c (revision 29492bb71c7148a089a5afafa0c99409161218df)
1433d6423SLionel Sambuc /******************************************************************************
2433d6423SLionel Sambuc  *
3433d6423SLionel Sambuc  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
4433d6423SLionel Sambuc  *
5433d6423SLionel Sambuc  *****************************************************************************/
6433d6423SLionel Sambuc 
7*29492bb7SDavid van Moolenbroek /*
8*29492bb7SDavid van Moolenbroek  * Copyright (C) 2000 - 2014, Intel Corp.
9433d6423SLionel Sambuc  * All rights reserved.
10433d6423SLionel Sambuc  *
11*29492bb7SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
12*29492bb7SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
13*29492bb7SDavid van Moolenbroek  * are met:
14*29492bb7SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
15*29492bb7SDavid van Moolenbroek  *    notice, this list of conditions, and the following disclaimer,
16*29492bb7SDavid van Moolenbroek  *    without modification.
17*29492bb7SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18*29492bb7SDavid van Moolenbroek  *    substantially similar to the "NO WARRANTY" disclaimer below
19*29492bb7SDavid van Moolenbroek  *    ("Disclaimer") and any redistribution must be conditioned upon
20*29492bb7SDavid van Moolenbroek  *    including a substantially similar Disclaimer requirement for further
21*29492bb7SDavid van Moolenbroek  *    binary redistribution.
22*29492bb7SDavid van Moolenbroek  * 3. Neither the names of the above-listed copyright holders nor the names
23*29492bb7SDavid van Moolenbroek  *    of any contributors may be used to endorse or promote products derived
24*29492bb7SDavid van Moolenbroek  *    from this software without specific prior written permission.
25433d6423SLionel Sambuc  *
26*29492bb7SDavid van Moolenbroek  * Alternatively, this software may be distributed under the terms of the
27*29492bb7SDavid van Moolenbroek  * GNU General Public License ("GPL") version 2 as published by the Free
28*29492bb7SDavid van Moolenbroek  * Software Foundation.
29433d6423SLionel Sambuc  *
30*29492bb7SDavid van Moolenbroek  * NO WARRANTY
31*29492bb7SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32*29492bb7SDavid van Moolenbroek  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33*29492bb7SDavid van Moolenbroek  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34*29492bb7SDavid van Moolenbroek  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35*29492bb7SDavid van Moolenbroek  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36*29492bb7SDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37*29492bb7SDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38*29492bb7SDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39*29492bb7SDavid van Moolenbroek  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40*29492bb7SDavid van Moolenbroek  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41*29492bb7SDavid van Moolenbroek  * POSSIBILITY OF SUCH DAMAGES.
42*29492bb7SDavid van Moolenbroek  */
43433d6423SLionel Sambuc 
44433d6423SLionel Sambuc #include "acpi.h"
45433d6423SLionel Sambuc #include "accommon.h"
46433d6423SLionel Sambuc #include "acdispat.h"
47433d6423SLionel Sambuc #include "acinterp.h"
48433d6423SLionel Sambuc #include "acnamesp.h"
49433d6423SLionel Sambuc #include "acdisasm.h"
50*29492bb7SDavid van Moolenbroek #include "acparser.h"
51*29492bb7SDavid van Moolenbroek #include "amlcode.h"
52433d6423SLionel Sambuc 
53433d6423SLionel Sambuc 
54433d6423SLionel Sambuc #define _COMPONENT          ACPI_DISPATCHER
55433d6423SLionel Sambuc         ACPI_MODULE_NAME    ("dsmethod")
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc /* Local prototypes */
58433d6423SLionel Sambuc 
59433d6423SLionel Sambuc static ACPI_STATUS
60*29492bb7SDavid van Moolenbroek AcpiDsDetectNamedOpcodes (
61*29492bb7SDavid van Moolenbroek     ACPI_WALK_STATE         *WalkState,
62*29492bb7SDavid van Moolenbroek     ACPI_PARSE_OBJECT       **OutOp);
63*29492bb7SDavid van Moolenbroek 
64*29492bb7SDavid van Moolenbroek static ACPI_STATUS
65433d6423SLionel Sambuc AcpiDsCreateMethodMutex (
66433d6423SLionel Sambuc     ACPI_OPERAND_OBJECT     *MethodDesc);
67433d6423SLionel Sambuc 
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc /*******************************************************************************
70433d6423SLionel Sambuc  *
71*29492bb7SDavid van Moolenbroek  * FUNCTION:    AcpiDsAutoSerializeMethod
72*29492bb7SDavid van Moolenbroek  *
73*29492bb7SDavid van Moolenbroek  * PARAMETERS:  Node                        - Namespace Node of the method
74*29492bb7SDavid van Moolenbroek  *              ObjDesc                     - Method object attached to node
75*29492bb7SDavid van Moolenbroek  *
76*29492bb7SDavid van Moolenbroek  * RETURN:      Status
77*29492bb7SDavid van Moolenbroek  *
78*29492bb7SDavid van Moolenbroek  * DESCRIPTION: Parse a control method AML to scan for control methods that
79*29492bb7SDavid van Moolenbroek  *              need serialization due to the creation of named objects.
80*29492bb7SDavid van Moolenbroek  *
81*29492bb7SDavid van Moolenbroek  * NOTE: It is a bit of overkill to mark all such methods serialized, since
82*29492bb7SDavid van Moolenbroek  * there is only a problem if the method actually blocks during execution.
83*29492bb7SDavid van Moolenbroek  * A blocking operation is, for example, a Sleep() operation, or any access
84*29492bb7SDavid van Moolenbroek  * to an operation region. However, it is probably not possible to easily
85*29492bb7SDavid van Moolenbroek  * detect whether a method will block or not, so we simply mark all suspicious
86*29492bb7SDavid van Moolenbroek  * methods as serialized.
87*29492bb7SDavid van Moolenbroek  *
88*29492bb7SDavid van Moolenbroek  * NOTE2: This code is essentially a generic routine for parsing a single
89*29492bb7SDavid van Moolenbroek  * control method.
90*29492bb7SDavid van Moolenbroek  *
91*29492bb7SDavid van Moolenbroek  ******************************************************************************/
92*29492bb7SDavid van Moolenbroek 
93*29492bb7SDavid van Moolenbroek ACPI_STATUS
AcpiDsAutoSerializeMethod(ACPI_NAMESPACE_NODE * Node,ACPI_OPERAND_OBJECT * ObjDesc)94*29492bb7SDavid van Moolenbroek AcpiDsAutoSerializeMethod (
95*29492bb7SDavid van Moolenbroek     ACPI_NAMESPACE_NODE     *Node,
96*29492bb7SDavid van Moolenbroek     ACPI_OPERAND_OBJECT     *ObjDesc)
97*29492bb7SDavid van Moolenbroek {
98*29492bb7SDavid van Moolenbroek     ACPI_STATUS             Status;
99*29492bb7SDavid van Moolenbroek     ACPI_PARSE_OBJECT       *Op = NULL;
100*29492bb7SDavid van Moolenbroek     ACPI_WALK_STATE         *WalkState;
101*29492bb7SDavid van Moolenbroek 
102*29492bb7SDavid van Moolenbroek 
103*29492bb7SDavid van Moolenbroek     ACPI_FUNCTION_TRACE_PTR (DsAutoSerializeMethod, Node);
104*29492bb7SDavid van Moolenbroek 
105*29492bb7SDavid van Moolenbroek 
106*29492bb7SDavid van Moolenbroek     ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
107*29492bb7SDavid van Moolenbroek         "Method auto-serialization parse [%4.4s] %p\n",
108*29492bb7SDavid van Moolenbroek         AcpiUtGetNodeName (Node), Node));
109*29492bb7SDavid van Moolenbroek 
110*29492bb7SDavid van Moolenbroek     /* Create/Init a root op for the method parse tree */
111*29492bb7SDavid van Moolenbroek 
112*29492bb7SDavid van Moolenbroek     Op = AcpiPsAllocOp (AML_METHOD_OP);
113*29492bb7SDavid van Moolenbroek     if (!Op)
114*29492bb7SDavid van Moolenbroek     {
115*29492bb7SDavid van Moolenbroek         return_ACPI_STATUS (AE_NO_MEMORY);
116*29492bb7SDavid van Moolenbroek     }
117*29492bb7SDavid van Moolenbroek 
118*29492bb7SDavid van Moolenbroek     AcpiPsSetName (Op, Node->Name.Integer);
119*29492bb7SDavid van Moolenbroek     Op->Common.Node = Node;
120*29492bb7SDavid van Moolenbroek 
121*29492bb7SDavid van Moolenbroek     /* Create and initialize a new walk state */
122*29492bb7SDavid van Moolenbroek 
123*29492bb7SDavid van Moolenbroek     WalkState = AcpiDsCreateWalkState (Node->OwnerId, NULL, NULL, NULL);
124*29492bb7SDavid van Moolenbroek     if (!WalkState)
125*29492bb7SDavid van Moolenbroek     {
126*29492bb7SDavid van Moolenbroek         return_ACPI_STATUS (AE_NO_MEMORY);
127*29492bb7SDavid van Moolenbroek     }
128*29492bb7SDavid van Moolenbroek 
129*29492bb7SDavid van Moolenbroek     Status = AcpiDsInitAmlWalk (WalkState, Op, Node, ObjDesc->Method.AmlStart,
130*29492bb7SDavid van Moolenbroek                 ObjDesc->Method.AmlLength, NULL, 0);
131*29492bb7SDavid van Moolenbroek     if (ACPI_FAILURE (Status))
132*29492bb7SDavid van Moolenbroek     {
133*29492bb7SDavid van Moolenbroek         AcpiDsDeleteWalkState (WalkState);
134*29492bb7SDavid van Moolenbroek         return_ACPI_STATUS (Status);
135*29492bb7SDavid van Moolenbroek     }
136*29492bb7SDavid van Moolenbroek 
137*29492bb7SDavid van Moolenbroek     WalkState->DescendingCallback = AcpiDsDetectNamedOpcodes;
138*29492bb7SDavid van Moolenbroek 
139*29492bb7SDavid van Moolenbroek     /* Parse the method, scan for creation of named objects */
140*29492bb7SDavid van Moolenbroek 
141*29492bb7SDavid van Moolenbroek     Status = AcpiPsParseAml (WalkState);
142*29492bb7SDavid van Moolenbroek     if (ACPI_FAILURE (Status))
143*29492bb7SDavid van Moolenbroek     {
144*29492bb7SDavid van Moolenbroek         return_ACPI_STATUS (Status);
145*29492bb7SDavid van Moolenbroek     }
146*29492bb7SDavid van Moolenbroek 
147*29492bb7SDavid van Moolenbroek     AcpiPsDeleteParseTree (Op);
148*29492bb7SDavid van Moolenbroek     return_ACPI_STATUS (Status);
149*29492bb7SDavid van Moolenbroek }
150*29492bb7SDavid van Moolenbroek 
151*29492bb7SDavid van Moolenbroek 
152*29492bb7SDavid van Moolenbroek /*******************************************************************************
153*29492bb7SDavid van Moolenbroek  *
154*29492bb7SDavid van Moolenbroek  * FUNCTION:    AcpiDsDetectNamedOpcodes
155*29492bb7SDavid van Moolenbroek  *
156*29492bb7SDavid van Moolenbroek  * PARAMETERS:  WalkState       - Current state of the parse tree walk
157*29492bb7SDavid van Moolenbroek  *              OutOp           - Unused, required for parser interface
158*29492bb7SDavid van Moolenbroek  *
159*29492bb7SDavid van Moolenbroek  * RETURN:      Status
160*29492bb7SDavid van Moolenbroek  *
161*29492bb7SDavid van Moolenbroek  * DESCRIPTION: Descending callback used during the loading of ACPI tables.
162*29492bb7SDavid van Moolenbroek  *              Currently used to detect methods that must be marked serialized
163*29492bb7SDavid van Moolenbroek  *              in order to avoid problems with the creation of named objects.
164*29492bb7SDavid van Moolenbroek  *
165*29492bb7SDavid van Moolenbroek  ******************************************************************************/
166*29492bb7SDavid van Moolenbroek 
167*29492bb7SDavid van Moolenbroek static ACPI_STATUS
AcpiDsDetectNamedOpcodes(ACPI_WALK_STATE * WalkState,ACPI_PARSE_OBJECT ** OutOp)168*29492bb7SDavid van Moolenbroek AcpiDsDetectNamedOpcodes (
169*29492bb7SDavid van Moolenbroek     ACPI_WALK_STATE         *WalkState,
170*29492bb7SDavid van Moolenbroek     ACPI_PARSE_OBJECT       **OutOp)
171*29492bb7SDavid van Moolenbroek {
172*29492bb7SDavid van Moolenbroek 
173*29492bb7SDavid van Moolenbroek     ACPI_FUNCTION_NAME (AcpiDsDetectNamedOpcodes);
174*29492bb7SDavid van Moolenbroek 
175*29492bb7SDavid van Moolenbroek 
176*29492bb7SDavid van Moolenbroek     /* We are only interested in opcodes that create a new name */
177*29492bb7SDavid van Moolenbroek 
178*29492bb7SDavid van Moolenbroek     if (!(WalkState->OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_FIELD)))
179*29492bb7SDavid van Moolenbroek     {
180*29492bb7SDavid van Moolenbroek         return (AE_OK);
181*29492bb7SDavid van Moolenbroek     }
182*29492bb7SDavid van Moolenbroek 
183*29492bb7SDavid van Moolenbroek     /*
184*29492bb7SDavid van Moolenbroek      * At this point, we know we have a Named object opcode.
185*29492bb7SDavid van Moolenbroek      * Mark the method as serialized. Later code will create a mutex for
186*29492bb7SDavid van Moolenbroek      * this method to enforce serialization.
187*29492bb7SDavid van Moolenbroek      *
188*29492bb7SDavid van Moolenbroek      * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the
189*29492bb7SDavid van Moolenbroek      * Sync Level mechanism for this method, even though it is now serialized.
190*29492bb7SDavid van Moolenbroek      * Otherwise, there can be conflicts with existing ASL code that actually
191*29492bb7SDavid van Moolenbroek      * uses sync levels.
192*29492bb7SDavid van Moolenbroek      */
193*29492bb7SDavid van Moolenbroek     WalkState->MethodDesc->Method.SyncLevel = 0;
194*29492bb7SDavid van Moolenbroek     WalkState->MethodDesc->Method.InfoFlags |=
195*29492bb7SDavid van Moolenbroek         (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
196*29492bb7SDavid van Moolenbroek 
197*29492bb7SDavid van Moolenbroek     ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
198*29492bb7SDavid van Moolenbroek         "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
199*29492bb7SDavid van Moolenbroek         WalkState->MethodNode->Name.Ascii, WalkState->MethodNode,
200*29492bb7SDavid van Moolenbroek         WalkState->OpInfo->Name, WalkState->Opcode));
201*29492bb7SDavid van Moolenbroek 
202*29492bb7SDavid van Moolenbroek     /* Abort the parse, no need to examine this method any further */
203*29492bb7SDavid van Moolenbroek 
204*29492bb7SDavid van Moolenbroek     return (AE_CTRL_TERMINATE);
205*29492bb7SDavid van Moolenbroek }
206*29492bb7SDavid van Moolenbroek 
207*29492bb7SDavid van Moolenbroek 
208*29492bb7SDavid van Moolenbroek /*******************************************************************************
209*29492bb7SDavid van Moolenbroek  *
210433d6423SLionel Sambuc  * FUNCTION:    AcpiDsMethodError
211433d6423SLionel Sambuc  *
212433d6423SLionel Sambuc  * PARAMETERS:  Status          - Execution status
213433d6423SLionel Sambuc  *              WalkState       - Current state
214433d6423SLionel Sambuc  *
215433d6423SLionel Sambuc  * RETURN:      Status
216433d6423SLionel Sambuc  *
217433d6423SLionel Sambuc  * DESCRIPTION: Called on method error. Invoke the global exception handler if
218433d6423SLionel Sambuc  *              present, dump the method data if the disassembler is configured
219433d6423SLionel Sambuc  *
220433d6423SLionel Sambuc  *              Note: Allows the exception handler to change the status code
221433d6423SLionel Sambuc  *
222433d6423SLionel Sambuc  ******************************************************************************/
223433d6423SLionel Sambuc 
224433d6423SLionel Sambuc ACPI_STATUS
AcpiDsMethodError(ACPI_STATUS Status,ACPI_WALK_STATE * WalkState)225433d6423SLionel Sambuc AcpiDsMethodError (
226433d6423SLionel Sambuc     ACPI_STATUS             Status,
227433d6423SLionel Sambuc     ACPI_WALK_STATE         *WalkState)
228433d6423SLionel Sambuc {
229433d6423SLionel Sambuc     ACPI_FUNCTION_ENTRY ();
230433d6423SLionel Sambuc 
231433d6423SLionel Sambuc 
232433d6423SLionel Sambuc     /* Ignore AE_OK and control exception codes */
233433d6423SLionel Sambuc 
234433d6423SLionel Sambuc     if (ACPI_SUCCESS (Status) ||
235433d6423SLionel Sambuc         (Status & AE_CODE_CONTROL))
236433d6423SLionel Sambuc     {
237433d6423SLionel Sambuc         return (Status);
238433d6423SLionel Sambuc     }
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc     /* Invoke the global exception handler */
241433d6423SLionel Sambuc 
242433d6423SLionel Sambuc     if (AcpiGbl_ExceptionHandler)
243433d6423SLionel Sambuc     {
244433d6423SLionel Sambuc         /* Exit the interpreter, allow handler to execute methods */
245433d6423SLionel Sambuc 
246433d6423SLionel Sambuc         AcpiExExitInterpreter ();
247433d6423SLionel Sambuc 
248433d6423SLionel Sambuc         /*
249433d6423SLionel Sambuc          * Handler can map the exception code to anything it wants, including
250433d6423SLionel Sambuc          * AE_OK, in which case the executing method will not be aborted.
251433d6423SLionel Sambuc          */
252433d6423SLionel Sambuc         Status = AcpiGbl_ExceptionHandler (Status,
253433d6423SLionel Sambuc                     WalkState->MethodNode ?
254433d6423SLionel Sambuc                         WalkState->MethodNode->Name.Integer : 0,
255433d6423SLionel Sambuc                     WalkState->Opcode, WalkState->AmlOffset, NULL);
256433d6423SLionel Sambuc         AcpiExEnterInterpreter ();
257433d6423SLionel Sambuc     }
258433d6423SLionel Sambuc 
259433d6423SLionel Sambuc     AcpiDsClearImplicitReturn (WalkState);
260433d6423SLionel Sambuc 
261433d6423SLionel Sambuc #ifdef ACPI_DISASSEMBLER
262433d6423SLionel Sambuc     if (ACPI_FAILURE (Status))
263433d6423SLionel Sambuc     {
264433d6423SLionel Sambuc         /* Display method locals/args if disassembler is present */
265433d6423SLionel Sambuc 
266433d6423SLionel Sambuc         AcpiDmDumpMethodInfo (Status, WalkState, WalkState->Op);
267433d6423SLionel Sambuc     }
268433d6423SLionel Sambuc #endif
269433d6423SLionel Sambuc 
270433d6423SLionel Sambuc     return (Status);
271433d6423SLionel Sambuc }
272433d6423SLionel Sambuc 
273433d6423SLionel Sambuc 
274433d6423SLionel Sambuc /*******************************************************************************
275433d6423SLionel Sambuc  *
276433d6423SLionel Sambuc  * FUNCTION:    AcpiDsCreateMethodMutex
277433d6423SLionel Sambuc  *
278433d6423SLionel Sambuc  * PARAMETERS:  ObjDesc             - The method object
279433d6423SLionel Sambuc  *
280433d6423SLionel Sambuc  * RETURN:      Status
281433d6423SLionel Sambuc  *
282433d6423SLionel Sambuc  * DESCRIPTION: Create a mutex object for a serialized control method
283433d6423SLionel Sambuc  *
284433d6423SLionel Sambuc  ******************************************************************************/
285433d6423SLionel Sambuc 
286433d6423SLionel Sambuc static ACPI_STATUS
AcpiDsCreateMethodMutex(ACPI_OPERAND_OBJECT * MethodDesc)287433d6423SLionel Sambuc AcpiDsCreateMethodMutex (
288433d6423SLionel Sambuc     ACPI_OPERAND_OBJECT     *MethodDesc)
289433d6423SLionel Sambuc {
290433d6423SLionel Sambuc     ACPI_OPERAND_OBJECT     *MutexDesc;
291433d6423SLionel Sambuc     ACPI_STATUS             Status;
292433d6423SLionel Sambuc 
293433d6423SLionel Sambuc 
294433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE (DsCreateMethodMutex);
295433d6423SLionel Sambuc 
296433d6423SLionel Sambuc 
297433d6423SLionel Sambuc     /* Create the new mutex object */
298433d6423SLionel Sambuc 
299433d6423SLionel Sambuc     MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX);
300433d6423SLionel Sambuc     if (!MutexDesc)
301433d6423SLionel Sambuc     {
302433d6423SLionel Sambuc         return_ACPI_STATUS (AE_NO_MEMORY);
303433d6423SLionel Sambuc     }
304433d6423SLionel Sambuc 
305433d6423SLionel Sambuc     /* Create the actual OS Mutex */
306433d6423SLionel Sambuc 
307433d6423SLionel Sambuc     Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex);
308433d6423SLionel Sambuc     if (ACPI_FAILURE (Status))
309433d6423SLionel Sambuc     {
310*29492bb7SDavid van Moolenbroek         AcpiUtDeleteObjectDesc (MutexDesc);
311433d6423SLionel Sambuc         return_ACPI_STATUS (Status);
312433d6423SLionel Sambuc     }
313433d6423SLionel Sambuc 
314433d6423SLionel Sambuc     MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel;
315433d6423SLionel Sambuc     MethodDesc->Method.Mutex = MutexDesc;
316433d6423SLionel Sambuc     return_ACPI_STATUS (AE_OK);
317433d6423SLionel Sambuc }
318433d6423SLionel Sambuc 
319433d6423SLionel Sambuc 
320433d6423SLionel Sambuc /*******************************************************************************
321433d6423SLionel Sambuc  *
322433d6423SLionel Sambuc  * FUNCTION:    AcpiDsBeginMethodExecution
323433d6423SLionel Sambuc  *
324433d6423SLionel Sambuc  * PARAMETERS:  MethodNode          - Node of the method
325433d6423SLionel Sambuc  *              ObjDesc             - The method object
326433d6423SLionel Sambuc  *              WalkState           - current state, NULL if not yet executing
327433d6423SLionel Sambuc  *                                    a method.
328433d6423SLionel Sambuc  *
329433d6423SLionel Sambuc  * RETURN:      Status
330433d6423SLionel Sambuc  *
331433d6423SLionel Sambuc  * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
332433d6423SLionel Sambuc  *              increments the thread count, and waits at the method semaphore
333433d6423SLionel Sambuc  *              for clearance to execute.
334433d6423SLionel Sambuc  *
335433d6423SLionel Sambuc  ******************************************************************************/
336433d6423SLionel Sambuc 
337433d6423SLionel Sambuc ACPI_STATUS
AcpiDsBeginMethodExecution(ACPI_NAMESPACE_NODE * MethodNode,ACPI_OPERAND_OBJECT * ObjDesc,ACPI_WALK_STATE * WalkState)338433d6423SLionel Sambuc AcpiDsBeginMethodExecution (
339433d6423SLionel Sambuc     ACPI_NAMESPACE_NODE     *MethodNode,
340433d6423SLionel Sambuc     ACPI_OPERAND_OBJECT     *ObjDesc,
341433d6423SLionel Sambuc     ACPI_WALK_STATE         *WalkState)
342433d6423SLionel Sambuc {
343433d6423SLionel Sambuc     ACPI_STATUS             Status = AE_OK;
344433d6423SLionel Sambuc 
345433d6423SLionel Sambuc 
346433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode);
347433d6423SLionel Sambuc 
348433d6423SLionel Sambuc 
349433d6423SLionel Sambuc     if (!MethodNode)
350433d6423SLionel Sambuc     {
351433d6423SLionel Sambuc         return_ACPI_STATUS (AE_NULL_ENTRY);
352433d6423SLionel Sambuc     }
353433d6423SLionel Sambuc 
354433d6423SLionel Sambuc     /* Prevent wraparound of thread count */
355433d6423SLionel Sambuc 
356433d6423SLionel Sambuc     if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX)
357433d6423SLionel Sambuc     {
358433d6423SLionel Sambuc         ACPI_ERROR ((AE_INFO,
359433d6423SLionel Sambuc             "Method reached maximum reentrancy limit (255)"));
360433d6423SLionel Sambuc         return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
361433d6423SLionel Sambuc     }
362433d6423SLionel Sambuc 
363433d6423SLionel Sambuc     /*
364433d6423SLionel Sambuc      * If this method is serialized, we need to acquire the method mutex.
365433d6423SLionel Sambuc      */
366*29492bb7SDavid van Moolenbroek     if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED)
367433d6423SLionel Sambuc     {
368433d6423SLionel Sambuc         /*
369433d6423SLionel Sambuc          * Create a mutex for the method if it is defined to be Serialized
370433d6423SLionel Sambuc          * and a mutex has not already been created. We defer the mutex creation
371433d6423SLionel Sambuc          * until a method is actually executed, to minimize the object count
372433d6423SLionel Sambuc          */
373433d6423SLionel Sambuc         if (!ObjDesc->Method.Mutex)
374433d6423SLionel Sambuc         {
375433d6423SLionel Sambuc             Status = AcpiDsCreateMethodMutex (ObjDesc);
376433d6423SLionel Sambuc             if (ACPI_FAILURE (Status))
377433d6423SLionel Sambuc             {
378433d6423SLionel Sambuc                 return_ACPI_STATUS (Status);
379433d6423SLionel Sambuc             }
380433d6423SLionel Sambuc         }
381433d6423SLionel Sambuc 
382433d6423SLionel Sambuc         /*
383433d6423SLionel Sambuc          * The CurrentSyncLevel (per-thread) must be less than or equal to
384433d6423SLionel Sambuc          * the sync level of the method. This mechanism provides some
385*29492bb7SDavid van Moolenbroek          * deadlock prevention.
386*29492bb7SDavid van Moolenbroek          *
387*29492bb7SDavid van Moolenbroek          * If the method was auto-serialized, we just ignore the sync level
388*29492bb7SDavid van Moolenbroek          * mechanism, because auto-serialization of methods can interfere
389*29492bb7SDavid van Moolenbroek          * with ASL code that actually uses sync levels.
390433d6423SLionel Sambuc          *
391433d6423SLionel Sambuc          * Top-level method invocation has no walk state at this point
392433d6423SLionel Sambuc          */
393433d6423SLionel Sambuc         if (WalkState &&
394*29492bb7SDavid van Moolenbroek             (!(ObjDesc->Method.InfoFlags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) &&
395433d6423SLionel Sambuc             (WalkState->Thread->CurrentSyncLevel > ObjDesc->Method.Mutex->Mutex.SyncLevel))
396433d6423SLionel Sambuc         {
397433d6423SLionel Sambuc             ACPI_ERROR ((AE_INFO,
398433d6423SLionel Sambuc                 "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)",
399433d6423SLionel Sambuc                 AcpiUtGetNodeName (MethodNode),
400433d6423SLionel Sambuc                 WalkState->Thread->CurrentSyncLevel));
401433d6423SLionel Sambuc 
402433d6423SLionel Sambuc             return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
403433d6423SLionel Sambuc         }
404433d6423SLionel Sambuc 
405433d6423SLionel Sambuc         /*
406433d6423SLionel Sambuc          * Obtain the method mutex if necessary. Do not acquire mutex for a
407433d6423SLionel Sambuc          * recursive call.
408433d6423SLionel Sambuc          */
409433d6423SLionel Sambuc         if (!WalkState ||
410433d6423SLionel Sambuc             !ObjDesc->Method.Mutex->Mutex.ThreadId ||
411433d6423SLionel Sambuc             (WalkState->Thread->ThreadId != ObjDesc->Method.Mutex->Mutex.ThreadId))
412433d6423SLionel Sambuc         {
413433d6423SLionel Sambuc             /*
414433d6423SLionel Sambuc              * Acquire the method mutex. This releases the interpreter if we
415433d6423SLionel Sambuc              * block (and reacquires it before it returns)
416433d6423SLionel Sambuc              */
417433d6423SLionel Sambuc             Status = AcpiExSystemWaitMutex (ObjDesc->Method.Mutex->Mutex.OsMutex,
418433d6423SLionel Sambuc                         ACPI_WAIT_FOREVER);
419433d6423SLionel Sambuc             if (ACPI_FAILURE (Status))
420433d6423SLionel Sambuc             {
421433d6423SLionel Sambuc                 return_ACPI_STATUS (Status);
422433d6423SLionel Sambuc             }
423433d6423SLionel Sambuc 
424433d6423SLionel Sambuc             /* Update the mutex and walk info and save the original SyncLevel */
425433d6423SLionel Sambuc 
426433d6423SLionel Sambuc             if (WalkState)
427433d6423SLionel Sambuc             {
428433d6423SLionel Sambuc                 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
429433d6423SLionel Sambuc                     WalkState->Thread->CurrentSyncLevel;
430433d6423SLionel Sambuc 
431433d6423SLionel Sambuc                 ObjDesc->Method.Mutex->Mutex.ThreadId = WalkState->Thread->ThreadId;
432433d6423SLionel Sambuc                 WalkState->Thread->CurrentSyncLevel = ObjDesc->Method.SyncLevel;
433433d6423SLionel Sambuc             }
434433d6423SLionel Sambuc             else
435433d6423SLionel Sambuc             {
436433d6423SLionel Sambuc                 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
437433d6423SLionel Sambuc                     ObjDesc->Method.Mutex->Mutex.SyncLevel;
438433d6423SLionel Sambuc             }
439433d6423SLionel Sambuc         }
440433d6423SLionel Sambuc 
441433d6423SLionel Sambuc         /* Always increase acquisition depth */
442433d6423SLionel Sambuc 
443433d6423SLionel Sambuc         ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++;
444433d6423SLionel Sambuc     }
445433d6423SLionel Sambuc 
446433d6423SLionel Sambuc     /*
447433d6423SLionel Sambuc      * Allocate an Owner ID for this method, only if this is the first thread
448433d6423SLionel Sambuc      * to begin concurrent execution. We only need one OwnerId, even if the
449433d6423SLionel Sambuc      * method is invoked recursively.
450433d6423SLionel Sambuc      */
451433d6423SLionel Sambuc     if (!ObjDesc->Method.OwnerId)
452433d6423SLionel Sambuc     {
453433d6423SLionel Sambuc         Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
454433d6423SLionel Sambuc         if (ACPI_FAILURE (Status))
455433d6423SLionel Sambuc         {
456433d6423SLionel Sambuc             goto Cleanup;
457433d6423SLionel Sambuc         }
458433d6423SLionel Sambuc     }
459433d6423SLionel Sambuc 
460433d6423SLionel Sambuc     /*
461433d6423SLionel Sambuc      * Increment the method parse tree thread count since it has been
462433d6423SLionel Sambuc      * reentered one more time (even if it is the same thread)
463433d6423SLionel Sambuc      */
464433d6423SLionel Sambuc     ObjDesc->Method.ThreadCount++;
465433d6423SLionel Sambuc     AcpiMethodCount++;
466433d6423SLionel Sambuc     return_ACPI_STATUS (Status);
467433d6423SLionel Sambuc 
468433d6423SLionel Sambuc 
469433d6423SLionel Sambuc Cleanup:
470433d6423SLionel Sambuc     /* On error, must release the method mutex (if present) */
471433d6423SLionel Sambuc 
472433d6423SLionel Sambuc     if (ObjDesc->Method.Mutex)
473433d6423SLionel Sambuc     {
474433d6423SLionel Sambuc         AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex);
475433d6423SLionel Sambuc     }
476433d6423SLionel Sambuc     return_ACPI_STATUS (Status);
477433d6423SLionel Sambuc }
478433d6423SLionel Sambuc 
479433d6423SLionel Sambuc 
480433d6423SLionel Sambuc /*******************************************************************************
481433d6423SLionel Sambuc  *
482433d6423SLionel Sambuc  * FUNCTION:    AcpiDsCallControlMethod
483433d6423SLionel Sambuc  *
484433d6423SLionel Sambuc  * PARAMETERS:  Thread              - Info for this thread
485433d6423SLionel Sambuc  *              ThisWalkState       - Current walk state
486433d6423SLionel Sambuc  *              Op                  - Current Op to be walked
487433d6423SLionel Sambuc  *
488433d6423SLionel Sambuc  * RETURN:      Status
489433d6423SLionel Sambuc  *
490433d6423SLionel Sambuc  * DESCRIPTION: Transfer execution to a called control method
491433d6423SLionel Sambuc  *
492433d6423SLionel Sambuc  ******************************************************************************/
493433d6423SLionel Sambuc 
494433d6423SLionel Sambuc ACPI_STATUS
AcpiDsCallControlMethod(ACPI_THREAD_STATE * Thread,ACPI_WALK_STATE * ThisWalkState,ACPI_PARSE_OBJECT * Op)495433d6423SLionel Sambuc AcpiDsCallControlMethod (
496433d6423SLionel Sambuc     ACPI_THREAD_STATE       *Thread,
497433d6423SLionel Sambuc     ACPI_WALK_STATE         *ThisWalkState,
498433d6423SLionel Sambuc     ACPI_PARSE_OBJECT       *Op)
499433d6423SLionel Sambuc {
500433d6423SLionel Sambuc     ACPI_STATUS             Status;
501433d6423SLionel Sambuc     ACPI_NAMESPACE_NODE     *MethodNode;
502433d6423SLionel Sambuc     ACPI_WALK_STATE         *NextWalkState = NULL;
503433d6423SLionel Sambuc     ACPI_OPERAND_OBJECT     *ObjDesc;
504433d6423SLionel Sambuc     ACPI_EVALUATE_INFO      *Info;
505433d6423SLionel Sambuc     UINT32                  i;
506433d6423SLionel Sambuc 
507433d6423SLionel Sambuc 
508433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState);
509433d6423SLionel Sambuc 
510433d6423SLionel Sambuc     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Calling method %p, currentstate=%p\n",
511433d6423SLionel Sambuc         ThisWalkState->PrevOp, ThisWalkState));
512433d6423SLionel Sambuc 
513433d6423SLionel Sambuc     /*
514433d6423SLionel Sambuc      * Get the namespace entry for the control method we are about to call
515433d6423SLionel Sambuc      */
516433d6423SLionel Sambuc     MethodNode = ThisWalkState->MethodCallNode;
517433d6423SLionel Sambuc     if (!MethodNode)
518433d6423SLionel Sambuc     {
519433d6423SLionel Sambuc         return_ACPI_STATUS (AE_NULL_ENTRY);
520433d6423SLionel Sambuc     }
521433d6423SLionel Sambuc 
522433d6423SLionel Sambuc     ObjDesc = AcpiNsGetAttachedObject (MethodNode);
523433d6423SLionel Sambuc     if (!ObjDesc)
524433d6423SLionel Sambuc     {
525433d6423SLionel Sambuc         return_ACPI_STATUS (AE_NULL_OBJECT);
526433d6423SLionel Sambuc     }
527433d6423SLionel Sambuc 
528433d6423SLionel Sambuc     /* Init for new method, possibly wait on method mutex */
529433d6423SLionel Sambuc 
530433d6423SLionel Sambuc     Status = AcpiDsBeginMethodExecution (MethodNode, ObjDesc,
531433d6423SLionel Sambuc                 ThisWalkState);
532433d6423SLionel Sambuc     if (ACPI_FAILURE (Status))
533433d6423SLionel Sambuc     {
534433d6423SLionel Sambuc         return_ACPI_STATUS (Status);
535433d6423SLionel Sambuc     }
536433d6423SLionel Sambuc 
537433d6423SLionel Sambuc     /* Begin method parse/execution. Create a new walk state */
538433d6423SLionel Sambuc 
539433d6423SLionel Sambuc     NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwnerId,
540433d6423SLionel Sambuc                         NULL, ObjDesc, Thread);
541433d6423SLionel Sambuc     if (!NextWalkState)
542433d6423SLionel Sambuc     {
543433d6423SLionel Sambuc         Status = AE_NO_MEMORY;
544433d6423SLionel Sambuc         goto Cleanup;
545433d6423SLionel Sambuc     }
546433d6423SLionel Sambuc 
547433d6423SLionel Sambuc     /*
548433d6423SLionel Sambuc      * The resolved arguments were put on the previous walk state's operand
549433d6423SLionel Sambuc      * stack. Operands on the previous walk state stack always
550433d6423SLionel Sambuc      * start at index 0. Also, null terminate the list of arguments
551433d6423SLionel Sambuc      */
552433d6423SLionel Sambuc     ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL;
553433d6423SLionel Sambuc 
554433d6423SLionel Sambuc     /*
555433d6423SLionel Sambuc      * Allocate and initialize the evaluation information block
556433d6423SLionel Sambuc      * TBD: this is somewhat inefficient, should change interface to
557433d6423SLionel Sambuc      * DsInitAmlWalk. For now, keeps this struct off the CPU stack
558433d6423SLionel Sambuc      */
559433d6423SLionel Sambuc     Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
560433d6423SLionel Sambuc     if (!Info)
561433d6423SLionel Sambuc     {
562*29492bb7SDavid van Moolenbroek         Status = AE_NO_MEMORY;
563*29492bb7SDavid van Moolenbroek         goto Cleanup;
564433d6423SLionel Sambuc     }
565433d6423SLionel Sambuc 
566433d6423SLionel Sambuc     Info->Parameters = &ThisWalkState->Operands[0];
567433d6423SLionel Sambuc 
568433d6423SLionel Sambuc     Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode,
569433d6423SLionel Sambuc                 ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength,
570433d6423SLionel Sambuc                 Info, ACPI_IMODE_EXECUTE);
571433d6423SLionel Sambuc 
572433d6423SLionel Sambuc     ACPI_FREE (Info);
573433d6423SLionel Sambuc     if (ACPI_FAILURE (Status))
574433d6423SLionel Sambuc     {
575433d6423SLionel Sambuc         goto Cleanup;
576433d6423SLionel Sambuc     }
577433d6423SLionel Sambuc 
578433d6423SLionel Sambuc     /*
579433d6423SLionel Sambuc      * Delete the operands on the previous walkstate operand stack
580433d6423SLionel Sambuc      * (they were copied to new objects)
581433d6423SLionel Sambuc      */
582433d6423SLionel Sambuc     for (i = 0; i < ObjDesc->Method.ParamCount; i++)
583433d6423SLionel Sambuc     {
584433d6423SLionel Sambuc         AcpiUtRemoveReference (ThisWalkState->Operands [i]);
585433d6423SLionel Sambuc         ThisWalkState->Operands [i] = NULL;
586433d6423SLionel Sambuc     }
587433d6423SLionel Sambuc 
588433d6423SLionel Sambuc     /* Clear the operand stack */
589433d6423SLionel Sambuc 
590433d6423SLionel Sambuc     ThisWalkState->NumOperands = 0;
591433d6423SLionel Sambuc 
592433d6423SLionel Sambuc     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
593433d6423SLionel Sambuc         "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
594433d6423SLionel Sambuc         MethodNode->Name.Ascii, NextWalkState));
595433d6423SLionel Sambuc 
596433d6423SLionel Sambuc     /* Invoke an internal method if necessary */
597433d6423SLionel Sambuc 
598*29492bb7SDavid van Moolenbroek     if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY)
599433d6423SLionel Sambuc     {
600*29492bb7SDavid van Moolenbroek         Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState);
601433d6423SLionel Sambuc         if (Status == AE_OK)
602433d6423SLionel Sambuc         {
603433d6423SLionel Sambuc             Status = AE_CTRL_TERMINATE;
604433d6423SLionel Sambuc         }
605433d6423SLionel Sambuc     }
606433d6423SLionel Sambuc 
607433d6423SLionel Sambuc     return_ACPI_STATUS (Status);
608433d6423SLionel Sambuc 
609433d6423SLionel Sambuc 
610433d6423SLionel Sambuc Cleanup:
611433d6423SLionel Sambuc 
612433d6423SLionel Sambuc     /* On error, we must terminate the method properly */
613433d6423SLionel Sambuc 
614433d6423SLionel Sambuc     AcpiDsTerminateControlMethod (ObjDesc, NextWalkState);
615433d6423SLionel Sambuc     if (NextWalkState)
616433d6423SLionel Sambuc     {
617433d6423SLionel Sambuc         AcpiDsDeleteWalkState (NextWalkState);
618433d6423SLionel Sambuc     }
619433d6423SLionel Sambuc 
620433d6423SLionel Sambuc     return_ACPI_STATUS (Status);
621433d6423SLionel Sambuc }
622433d6423SLionel Sambuc 
623433d6423SLionel Sambuc 
624433d6423SLionel Sambuc /*******************************************************************************
625433d6423SLionel Sambuc  *
626433d6423SLionel Sambuc  * FUNCTION:    AcpiDsRestartControlMethod
627433d6423SLionel Sambuc  *
628433d6423SLionel Sambuc  * PARAMETERS:  WalkState           - State for preempted method (caller)
629433d6423SLionel Sambuc  *              ReturnDesc          - Return value from the called method
630433d6423SLionel Sambuc  *
631433d6423SLionel Sambuc  * RETURN:      Status
632433d6423SLionel Sambuc  *
633433d6423SLionel Sambuc  * DESCRIPTION: Restart a method that was preempted by another (nested) method
634433d6423SLionel Sambuc  *              invocation. Handle the return value (if any) from the callee.
635433d6423SLionel Sambuc  *
636433d6423SLionel Sambuc  ******************************************************************************/
637433d6423SLionel Sambuc 
638433d6423SLionel Sambuc ACPI_STATUS
AcpiDsRestartControlMethod(ACPI_WALK_STATE * WalkState,ACPI_OPERAND_OBJECT * ReturnDesc)639433d6423SLionel Sambuc AcpiDsRestartControlMethod (
640433d6423SLionel Sambuc     ACPI_WALK_STATE         *WalkState,
641433d6423SLionel Sambuc     ACPI_OPERAND_OBJECT     *ReturnDesc)
642433d6423SLionel Sambuc {
643433d6423SLionel Sambuc     ACPI_STATUS             Status;
644433d6423SLionel Sambuc     int                     SameAsImplicitReturn;
645433d6423SLionel Sambuc 
646433d6423SLionel Sambuc 
647433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState);
648433d6423SLionel Sambuc 
649433d6423SLionel Sambuc 
650433d6423SLionel Sambuc     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
651433d6423SLionel Sambuc         "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
652433d6423SLionel Sambuc         AcpiUtGetNodeName (WalkState->MethodNode),
653433d6423SLionel Sambuc         WalkState->MethodCallOp, ReturnDesc));
654433d6423SLionel Sambuc 
655433d6423SLionel Sambuc     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
656433d6423SLionel Sambuc         "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
657433d6423SLionel Sambuc         WalkState->ReturnUsed,
658433d6423SLionel Sambuc         WalkState->Results, WalkState));
659433d6423SLionel Sambuc 
660433d6423SLionel Sambuc     /* Did the called method return a value? */
661433d6423SLionel Sambuc 
662433d6423SLionel Sambuc     if (ReturnDesc)
663433d6423SLionel Sambuc     {
664433d6423SLionel Sambuc         /* Is the implicit return object the same as the return desc? */
665433d6423SLionel Sambuc 
666433d6423SLionel Sambuc         SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc);
667433d6423SLionel Sambuc 
668433d6423SLionel Sambuc         /* Are we actually going to use the return value? */
669433d6423SLionel Sambuc 
670433d6423SLionel Sambuc         if (WalkState->ReturnUsed)
671433d6423SLionel Sambuc         {
672433d6423SLionel Sambuc             /* Save the return value from the previous method */
673433d6423SLionel Sambuc 
674433d6423SLionel Sambuc             Status = AcpiDsResultPush (ReturnDesc, WalkState);
675433d6423SLionel Sambuc             if (ACPI_FAILURE (Status))
676433d6423SLionel Sambuc             {
677433d6423SLionel Sambuc                 AcpiUtRemoveReference (ReturnDesc);
678433d6423SLionel Sambuc                 return_ACPI_STATUS (Status);
679433d6423SLionel Sambuc             }
680433d6423SLionel Sambuc 
681433d6423SLionel Sambuc             /*
682433d6423SLionel Sambuc              * Save as THIS method's return value in case it is returned
683433d6423SLionel Sambuc              * immediately to yet another method
684433d6423SLionel Sambuc              */
685433d6423SLionel Sambuc             WalkState->ReturnDesc = ReturnDesc;
686433d6423SLionel Sambuc         }
687433d6423SLionel Sambuc 
688433d6423SLionel Sambuc         /*
689433d6423SLionel Sambuc          * The following code is the optional support for the so-called
690433d6423SLionel Sambuc          * "implicit return". Some AML code assumes that the last value of the
691433d6423SLionel Sambuc          * method is "implicitly" returned to the caller, in the absence of an
692433d6423SLionel Sambuc          * explicit return value.
693433d6423SLionel Sambuc          *
694433d6423SLionel Sambuc          * Just save the last result of the method as the return value.
695433d6423SLionel Sambuc          *
696433d6423SLionel Sambuc          * NOTE: this is optional because the ASL language does not actually
697433d6423SLionel Sambuc          * support this behavior.
698433d6423SLionel Sambuc          */
699433d6423SLionel Sambuc         else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) ||
700433d6423SLionel Sambuc                  SameAsImplicitReturn)
701433d6423SLionel Sambuc         {
702433d6423SLionel Sambuc             /*
703433d6423SLionel Sambuc              * Delete the return value if it will not be used by the
704433d6423SLionel Sambuc              * calling method or remove one reference if the explicit return
705433d6423SLionel Sambuc              * is the same as the implicit return value.
706433d6423SLionel Sambuc              */
707433d6423SLionel Sambuc             AcpiUtRemoveReference (ReturnDesc);
708433d6423SLionel Sambuc         }
709433d6423SLionel Sambuc     }
710433d6423SLionel Sambuc 
711433d6423SLionel Sambuc     return_ACPI_STATUS (AE_OK);
712433d6423SLionel Sambuc }
713433d6423SLionel Sambuc 
714433d6423SLionel Sambuc 
715433d6423SLionel Sambuc /*******************************************************************************
716433d6423SLionel Sambuc  *
717433d6423SLionel Sambuc  * FUNCTION:    AcpiDsTerminateControlMethod
718433d6423SLionel Sambuc  *
719433d6423SLionel Sambuc  * PARAMETERS:  MethodDesc          - Method object
720433d6423SLionel Sambuc  *              WalkState           - State associated with the method
721433d6423SLionel Sambuc  *
722433d6423SLionel Sambuc  * RETURN:      None
723433d6423SLionel Sambuc  *
724433d6423SLionel Sambuc  * DESCRIPTION: Terminate a control method. Delete everything that the method
725433d6423SLionel Sambuc  *              created, delete all locals and arguments, and delete the parse
726433d6423SLionel Sambuc  *              tree if requested.
727433d6423SLionel Sambuc  *
728433d6423SLionel Sambuc  * MUTEX:       Interpreter is locked
729433d6423SLionel Sambuc  *
730433d6423SLionel Sambuc  ******************************************************************************/
731433d6423SLionel Sambuc 
732433d6423SLionel Sambuc void
AcpiDsTerminateControlMethod(ACPI_OPERAND_OBJECT * MethodDesc,ACPI_WALK_STATE * WalkState)733433d6423SLionel Sambuc AcpiDsTerminateControlMethod (
734433d6423SLionel Sambuc     ACPI_OPERAND_OBJECT     *MethodDesc,
735433d6423SLionel Sambuc     ACPI_WALK_STATE         *WalkState)
736433d6423SLionel Sambuc {
737433d6423SLionel Sambuc 
738433d6423SLionel Sambuc     ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState);
739433d6423SLionel Sambuc 
740433d6423SLionel Sambuc 
741433d6423SLionel Sambuc     /* MethodDesc is required, WalkState is optional */
742433d6423SLionel Sambuc 
743433d6423SLionel Sambuc     if (!MethodDesc)
744433d6423SLionel Sambuc     {
745433d6423SLionel Sambuc         return_VOID;
746433d6423SLionel Sambuc     }
747433d6423SLionel Sambuc 
748433d6423SLionel Sambuc     if (WalkState)
749433d6423SLionel Sambuc     {
750433d6423SLionel Sambuc         /* Delete all arguments and locals */
751433d6423SLionel Sambuc 
752433d6423SLionel Sambuc         AcpiDsMethodDataDeleteAll (WalkState);
753433d6423SLionel Sambuc 
754433d6423SLionel Sambuc         /*
755433d6423SLionel Sambuc          * If method is serialized, release the mutex and restore the
756433d6423SLionel Sambuc          * current sync level for this thread
757433d6423SLionel Sambuc          */
758433d6423SLionel Sambuc         if (MethodDesc->Method.Mutex)
759433d6423SLionel Sambuc         {
760433d6423SLionel Sambuc             /* Acquisition Depth handles recursive calls */
761433d6423SLionel Sambuc 
762433d6423SLionel Sambuc             MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--;
763433d6423SLionel Sambuc             if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth)
764433d6423SLionel Sambuc             {
765433d6423SLionel Sambuc                 WalkState->Thread->CurrentSyncLevel =
766433d6423SLionel Sambuc                     MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel;
767433d6423SLionel Sambuc 
768433d6423SLionel Sambuc                 AcpiOsReleaseMutex (MethodDesc->Method.Mutex->Mutex.OsMutex);
769433d6423SLionel Sambuc                 MethodDesc->Method.Mutex->Mutex.ThreadId = 0;
770433d6423SLionel Sambuc             }
771433d6423SLionel Sambuc         }
772433d6423SLionel Sambuc 
773433d6423SLionel Sambuc         /*
774433d6423SLionel Sambuc          * Delete any namespace objects created anywhere within the
775*29492bb7SDavid van Moolenbroek          * namespace by the execution of this method. Unless:
776*29492bb7SDavid van Moolenbroek          * 1) This method is a module-level executable code method, in which
777*29492bb7SDavid van Moolenbroek          *    case we want make the objects permanent.
778*29492bb7SDavid van Moolenbroek          * 2) There are other threads executing the method, in which case we
779*29492bb7SDavid van Moolenbroek          *    will wait until the last thread has completed.
780433d6423SLionel Sambuc          */
781*29492bb7SDavid van Moolenbroek         if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) &&
782*29492bb7SDavid van Moolenbroek              (MethodDesc->Method.ThreadCount == 1))
783433d6423SLionel Sambuc         {
784433d6423SLionel Sambuc             /* Delete any direct children of (created by) this method */
785433d6423SLionel Sambuc 
786433d6423SLionel Sambuc             AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode);
787433d6423SLionel Sambuc 
788433d6423SLionel Sambuc             /*
789433d6423SLionel Sambuc              * Delete any objects that were created by this method
790433d6423SLionel Sambuc              * elsewhere in the namespace (if any were created).
791*29492bb7SDavid van Moolenbroek              * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
792*29492bb7SDavid van Moolenbroek              * deletion such that we don't have to perform an entire
793*29492bb7SDavid van Moolenbroek              * namespace walk for every control method execution.
794433d6423SLionel Sambuc              */
795*29492bb7SDavid van Moolenbroek             if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE)
796433d6423SLionel Sambuc             {
797433d6423SLionel Sambuc                 AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId);
798*29492bb7SDavid van Moolenbroek                 MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_MODIFIED_NAMESPACE;
799433d6423SLionel Sambuc             }
800433d6423SLionel Sambuc         }
801433d6423SLionel Sambuc     }
802433d6423SLionel Sambuc 
803433d6423SLionel Sambuc     /* Decrement the thread count on the method */
804433d6423SLionel Sambuc 
805433d6423SLionel Sambuc     if (MethodDesc->Method.ThreadCount)
806433d6423SLionel Sambuc     {
807433d6423SLionel Sambuc         MethodDesc->Method.ThreadCount--;
808433d6423SLionel Sambuc     }
809433d6423SLionel Sambuc     else
810433d6423SLionel Sambuc     {
811433d6423SLionel Sambuc         ACPI_ERROR ((AE_INFO,
812433d6423SLionel Sambuc             "Invalid zero thread count in method"));
813433d6423SLionel Sambuc     }
814433d6423SLionel Sambuc 
815433d6423SLionel Sambuc     /* Are there any other threads currently executing this method? */
816433d6423SLionel Sambuc 
817433d6423SLionel Sambuc     if (MethodDesc->Method.ThreadCount)
818433d6423SLionel Sambuc     {
819433d6423SLionel Sambuc         /*
820433d6423SLionel Sambuc          * Additional threads. Do not release the OwnerId in this case,
821433d6423SLionel Sambuc          * we immediately reuse it for the next thread executing this method
822433d6423SLionel Sambuc          */
823433d6423SLionel Sambuc         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
824433d6423SLionel Sambuc             "*** Completed execution of one thread, %u threads remaining\n",
825433d6423SLionel Sambuc             MethodDesc->Method.ThreadCount));
826433d6423SLionel Sambuc     }
827433d6423SLionel Sambuc     else
828433d6423SLionel Sambuc     {
829433d6423SLionel Sambuc         /* This is the only executing thread for this method */
830433d6423SLionel Sambuc 
831433d6423SLionel Sambuc         /*
832433d6423SLionel Sambuc          * Support to dynamically change a method from NotSerialized to
833433d6423SLionel Sambuc          * Serialized if it appears that the method is incorrectly written and
834433d6423SLionel Sambuc          * does not support multiple thread execution. The best example of this
835433d6423SLionel Sambuc          * is if such a method creates namespace objects and blocks. A second
836*29492bb7SDavid van Moolenbroek          * thread will fail with an AE_ALREADY_EXISTS exception.
837433d6423SLionel Sambuc          *
838433d6423SLionel Sambuc          * This code is here because we must wait until the last thread exits
839*29492bb7SDavid van Moolenbroek          * before marking the method as serialized.
840433d6423SLionel Sambuc          */
841*29492bb7SDavid van Moolenbroek         if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING)
842433d6423SLionel Sambuc         {
843*29492bb7SDavid van Moolenbroek             if (WalkState)
844*29492bb7SDavid van Moolenbroek             {
845*29492bb7SDavid van Moolenbroek                 ACPI_INFO ((AE_INFO,
846*29492bb7SDavid van Moolenbroek                     "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error",
847*29492bb7SDavid van Moolenbroek                     WalkState->MethodNode->Name.Ascii));
848*29492bb7SDavid van Moolenbroek             }
849*29492bb7SDavid van Moolenbroek 
850*29492bb7SDavid van Moolenbroek             /*
851*29492bb7SDavid van Moolenbroek              * Method tried to create an object twice and was marked as
852*29492bb7SDavid van Moolenbroek              * "pending serialized". The probable cause is that the method
853*29492bb7SDavid van Moolenbroek              * cannot handle reentrancy.
854*29492bb7SDavid van Moolenbroek              *
855*29492bb7SDavid van Moolenbroek              * The method was created as NotSerialized, but it tried to create
856*29492bb7SDavid van Moolenbroek              * a named object and then blocked, causing the second thread
857*29492bb7SDavid van Moolenbroek              * entrance to begin and then fail. Workaround this problem by
858*29492bb7SDavid van Moolenbroek              * marking the method permanently as Serialized when the last
859*29492bb7SDavid van Moolenbroek              * thread exits here.
860*29492bb7SDavid van Moolenbroek              */
861*29492bb7SDavid van Moolenbroek             MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_SERIALIZED_PENDING;
862*29492bb7SDavid van Moolenbroek             MethodDesc->Method.InfoFlags |=
863*29492bb7SDavid van Moolenbroek                 (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
864*29492bb7SDavid van Moolenbroek             MethodDesc->Method.SyncLevel = 0;
865433d6423SLionel Sambuc         }
866433d6423SLionel Sambuc 
867433d6423SLionel Sambuc         /* No more threads, we can free the OwnerId */
868433d6423SLionel Sambuc 
869*29492bb7SDavid van Moolenbroek         if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL))
870433d6423SLionel Sambuc         {
871433d6423SLionel Sambuc             AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId);
872433d6423SLionel Sambuc         }
873433d6423SLionel Sambuc     }
874433d6423SLionel Sambuc 
875433d6423SLionel Sambuc     return_VOID;
876433d6423SLionel Sambuc }
877