1*a159c266SJung-uk Kim /****************************************************************************** 2*a159c266SJung-uk Kim * 3*a159c266SJung-uk Kim * Module Name: dsmethod - Parser/Interpreter interface - control method parsing 4*a159c266SJung-uk Kim * 5*a159c266SJung-uk Kim *****************************************************************************/ 6*a159c266SJung-uk Kim 7*a159c266SJung-uk Kim /* 8*a159c266SJung-uk Kim * Copyright (C) 2000 - 2012, Intel Corp. 9*a159c266SJung-uk Kim * All rights reserved. 10*a159c266SJung-uk Kim * 11*a159c266SJung-uk Kim * Redistribution and use in source and binary forms, with or without 12*a159c266SJung-uk Kim * modification, are permitted provided that the following conditions 13*a159c266SJung-uk Kim * are met: 14*a159c266SJung-uk Kim * 1. Redistributions of source code must retain the above copyright 15*a159c266SJung-uk Kim * notice, this list of conditions, and the following disclaimer, 16*a159c266SJung-uk Kim * without modification. 17*a159c266SJung-uk Kim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18*a159c266SJung-uk Kim * substantially similar to the "NO WARRANTY" disclaimer below 19*a159c266SJung-uk Kim * ("Disclaimer") and any redistribution must be conditioned upon 20*a159c266SJung-uk Kim * including a substantially similar Disclaimer requirement for further 21*a159c266SJung-uk Kim * binary redistribution. 22*a159c266SJung-uk Kim * 3. Neither the names of the above-listed copyright holders nor the names 23*a159c266SJung-uk Kim * of any contributors may be used to endorse or promote products derived 24*a159c266SJung-uk Kim * from this software without specific prior written permission. 25*a159c266SJung-uk Kim * 26*a159c266SJung-uk Kim * Alternatively, this software may be distributed under the terms of the 27*a159c266SJung-uk Kim * GNU General Public License ("GPL") version 2 as published by the Free 28*a159c266SJung-uk Kim * Software Foundation. 29*a159c266SJung-uk Kim * 30*a159c266SJung-uk Kim * NO WARRANTY 31*a159c266SJung-uk Kim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32*a159c266SJung-uk Kim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33*a159c266SJung-uk Kim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34*a159c266SJung-uk Kim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35*a159c266SJung-uk Kim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36*a159c266SJung-uk Kim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37*a159c266SJung-uk Kim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38*a159c266SJung-uk Kim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39*a159c266SJung-uk Kim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40*a159c266SJung-uk Kim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41*a159c266SJung-uk Kim * POSSIBILITY OF SUCH DAMAGES. 42*a159c266SJung-uk Kim */ 43*a159c266SJung-uk Kim 44*a159c266SJung-uk Kim #define __DSMETHOD_C__ 45*a159c266SJung-uk Kim 46*a159c266SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h> 47*a159c266SJung-uk Kim #include <contrib/dev/acpica/include/accommon.h> 48*a159c266SJung-uk Kim #include <contrib/dev/acpica/include/acdispat.h> 49*a159c266SJung-uk Kim #include <contrib/dev/acpica/include/acinterp.h> 50*a159c266SJung-uk Kim #include <contrib/dev/acpica/include/acnamesp.h> 51*a159c266SJung-uk Kim #include <contrib/dev/acpica/include/acdisasm.h> 52*a159c266SJung-uk Kim 53*a159c266SJung-uk Kim 54*a159c266SJung-uk Kim #define _COMPONENT ACPI_DISPATCHER 55*a159c266SJung-uk Kim ACPI_MODULE_NAME ("dsmethod") 56*a159c266SJung-uk Kim 57*a159c266SJung-uk Kim /* Local prototypes */ 58*a159c266SJung-uk Kim 59*a159c266SJung-uk Kim static ACPI_STATUS 60*a159c266SJung-uk Kim AcpiDsCreateMethodMutex ( 61*a159c266SJung-uk Kim ACPI_OPERAND_OBJECT *MethodDesc); 62*a159c266SJung-uk Kim 63*a159c266SJung-uk Kim 64*a159c266SJung-uk Kim /******************************************************************************* 65*a159c266SJung-uk Kim * 66*a159c266SJung-uk Kim * FUNCTION: AcpiDsMethodError 67*a159c266SJung-uk Kim * 68*a159c266SJung-uk Kim * PARAMETERS: Status - Execution status 69*a159c266SJung-uk Kim * WalkState - Current state 70*a159c266SJung-uk Kim * 71*a159c266SJung-uk Kim * RETURN: Status 72*a159c266SJung-uk Kim * 73*a159c266SJung-uk Kim * DESCRIPTION: Called on method error. Invoke the global exception handler if 74*a159c266SJung-uk Kim * present, dump the method data if the disassembler is configured 75*a159c266SJung-uk Kim * 76*a159c266SJung-uk Kim * Note: Allows the exception handler to change the status code 77*a159c266SJung-uk Kim * 78*a159c266SJung-uk Kim ******************************************************************************/ 79*a159c266SJung-uk Kim 80*a159c266SJung-uk Kim ACPI_STATUS 81*a159c266SJung-uk Kim AcpiDsMethodError ( 82*a159c266SJung-uk Kim ACPI_STATUS Status, 83*a159c266SJung-uk Kim ACPI_WALK_STATE *WalkState) 84*a159c266SJung-uk Kim { 85*a159c266SJung-uk Kim ACPI_FUNCTION_ENTRY (); 86*a159c266SJung-uk Kim 87*a159c266SJung-uk Kim 88*a159c266SJung-uk Kim /* Ignore AE_OK and control exception codes */ 89*a159c266SJung-uk Kim 90*a159c266SJung-uk Kim if (ACPI_SUCCESS (Status) || 91*a159c266SJung-uk Kim (Status & AE_CODE_CONTROL)) 92*a159c266SJung-uk Kim { 93*a159c266SJung-uk Kim return (Status); 94*a159c266SJung-uk Kim } 95*a159c266SJung-uk Kim 96*a159c266SJung-uk Kim /* Invoke the global exception handler */ 97*a159c266SJung-uk Kim 98*a159c266SJung-uk Kim if (AcpiGbl_ExceptionHandler) 99*a159c266SJung-uk Kim { 100*a159c266SJung-uk Kim /* Exit the interpreter, allow handler to execute methods */ 101*a159c266SJung-uk Kim 102*a159c266SJung-uk Kim AcpiExExitInterpreter (); 103*a159c266SJung-uk Kim 104*a159c266SJung-uk Kim /* 105*a159c266SJung-uk Kim * Handler can map the exception code to anything it wants, including 106*a159c266SJung-uk Kim * AE_OK, in which case the executing method will not be aborted. 107*a159c266SJung-uk Kim */ 108*a159c266SJung-uk Kim Status = AcpiGbl_ExceptionHandler (Status, 109*a159c266SJung-uk Kim WalkState->MethodNode ? 110*a159c266SJung-uk Kim WalkState->MethodNode->Name.Integer : 0, 111*a159c266SJung-uk Kim WalkState->Opcode, WalkState->AmlOffset, NULL); 112*a159c266SJung-uk Kim AcpiExEnterInterpreter (); 113*a159c266SJung-uk Kim } 114*a159c266SJung-uk Kim 115*a159c266SJung-uk Kim AcpiDsClearImplicitReturn (WalkState); 116*a159c266SJung-uk Kim 117*a159c266SJung-uk Kim #ifdef ACPI_DISASSEMBLER 118*a159c266SJung-uk Kim if (ACPI_FAILURE (Status)) 119*a159c266SJung-uk Kim { 120*a159c266SJung-uk Kim /* Display method locals/args if disassembler is present */ 121*a159c266SJung-uk Kim 122*a159c266SJung-uk Kim AcpiDmDumpMethodInfo (Status, WalkState, WalkState->Op); 123*a159c266SJung-uk Kim } 124*a159c266SJung-uk Kim #endif 125*a159c266SJung-uk Kim 126*a159c266SJung-uk Kim return (Status); 127*a159c266SJung-uk Kim } 128*a159c266SJung-uk Kim 129*a159c266SJung-uk Kim 130*a159c266SJung-uk Kim /******************************************************************************* 131*a159c266SJung-uk Kim * 132*a159c266SJung-uk Kim * FUNCTION: AcpiDsCreateMethodMutex 133*a159c266SJung-uk Kim * 134*a159c266SJung-uk Kim * PARAMETERS: ObjDesc - The method object 135*a159c266SJung-uk Kim * 136*a159c266SJung-uk Kim * RETURN: Status 137*a159c266SJung-uk Kim * 138*a159c266SJung-uk Kim * DESCRIPTION: Create a mutex object for a serialized control method 139*a159c266SJung-uk Kim * 140*a159c266SJung-uk Kim ******************************************************************************/ 141*a159c266SJung-uk Kim 142*a159c266SJung-uk Kim static ACPI_STATUS 143*a159c266SJung-uk Kim AcpiDsCreateMethodMutex ( 144*a159c266SJung-uk Kim ACPI_OPERAND_OBJECT *MethodDesc) 145*a159c266SJung-uk Kim { 146*a159c266SJung-uk Kim ACPI_OPERAND_OBJECT *MutexDesc; 147*a159c266SJung-uk Kim ACPI_STATUS Status; 148*a159c266SJung-uk Kim 149*a159c266SJung-uk Kim 150*a159c266SJung-uk Kim ACPI_FUNCTION_TRACE (DsCreateMethodMutex); 151*a159c266SJung-uk Kim 152*a159c266SJung-uk Kim 153*a159c266SJung-uk Kim /* Create the new mutex object */ 154*a159c266SJung-uk Kim 155*a159c266SJung-uk Kim MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX); 156*a159c266SJung-uk Kim if (!MutexDesc) 157*a159c266SJung-uk Kim { 158*a159c266SJung-uk Kim return_ACPI_STATUS (AE_NO_MEMORY); 159*a159c266SJung-uk Kim } 160*a159c266SJung-uk Kim 161*a159c266SJung-uk Kim /* Create the actual OS Mutex */ 162*a159c266SJung-uk Kim 163*a159c266SJung-uk Kim Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex); 164*a159c266SJung-uk Kim if (ACPI_FAILURE (Status)) 165*a159c266SJung-uk Kim { 166*a159c266SJung-uk Kim return_ACPI_STATUS (Status); 167*a159c266SJung-uk Kim } 168*a159c266SJung-uk Kim 169*a159c266SJung-uk Kim MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel; 170*a159c266SJung-uk Kim MethodDesc->Method.Mutex = MutexDesc; 171*a159c266SJung-uk Kim return_ACPI_STATUS (AE_OK); 172*a159c266SJung-uk Kim } 173*a159c266SJung-uk Kim 174*a159c266SJung-uk Kim 175*a159c266SJung-uk Kim /******************************************************************************* 176*a159c266SJung-uk Kim * 177*a159c266SJung-uk Kim * FUNCTION: AcpiDsBeginMethodExecution 178*a159c266SJung-uk Kim * 179*a159c266SJung-uk Kim * PARAMETERS: MethodNode - Node of the method 180*a159c266SJung-uk Kim * ObjDesc - The method object 181*a159c266SJung-uk Kim * WalkState - current state, NULL if not yet executing 182*a159c266SJung-uk Kim * a method. 183*a159c266SJung-uk Kim * 184*a159c266SJung-uk Kim * RETURN: Status 185*a159c266SJung-uk Kim * 186*a159c266SJung-uk Kim * DESCRIPTION: Prepare a method for execution. Parses the method if necessary, 187*a159c266SJung-uk Kim * increments the thread count, and waits at the method semaphore 188*a159c266SJung-uk Kim * for clearance to execute. 189*a159c266SJung-uk Kim * 190*a159c266SJung-uk Kim ******************************************************************************/ 191*a159c266SJung-uk Kim 192*a159c266SJung-uk Kim ACPI_STATUS 193*a159c266SJung-uk Kim AcpiDsBeginMethodExecution ( 194*a159c266SJung-uk Kim ACPI_NAMESPACE_NODE *MethodNode, 195*a159c266SJung-uk Kim ACPI_OPERAND_OBJECT *ObjDesc, 196*a159c266SJung-uk Kim ACPI_WALK_STATE *WalkState) 197*a159c266SJung-uk Kim { 198*a159c266SJung-uk Kim ACPI_STATUS Status = AE_OK; 199*a159c266SJung-uk Kim 200*a159c266SJung-uk Kim 201*a159c266SJung-uk Kim ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode); 202*a159c266SJung-uk Kim 203*a159c266SJung-uk Kim 204*a159c266SJung-uk Kim if (!MethodNode) 205*a159c266SJung-uk Kim { 206*a159c266SJung-uk Kim return_ACPI_STATUS (AE_NULL_ENTRY); 207*a159c266SJung-uk Kim } 208*a159c266SJung-uk Kim 209*a159c266SJung-uk Kim /* Prevent wraparound of thread count */ 210*a159c266SJung-uk Kim 211*a159c266SJung-uk Kim if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX) 212*a159c266SJung-uk Kim { 213*a159c266SJung-uk Kim ACPI_ERROR ((AE_INFO, 214*a159c266SJung-uk Kim "Method reached maximum reentrancy limit (255)")); 215*a159c266SJung-uk Kim return_ACPI_STATUS (AE_AML_METHOD_LIMIT); 216*a159c266SJung-uk Kim } 217*a159c266SJung-uk Kim 218*a159c266SJung-uk Kim /* 219*a159c266SJung-uk Kim * If this method is serialized, we need to acquire the method mutex. 220*a159c266SJung-uk Kim */ 221*a159c266SJung-uk Kim if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED) 222*a159c266SJung-uk Kim { 223*a159c266SJung-uk Kim /* 224*a159c266SJung-uk Kim * Create a mutex for the method if it is defined to be Serialized 225*a159c266SJung-uk Kim * and a mutex has not already been created. We defer the mutex creation 226*a159c266SJung-uk Kim * until a method is actually executed, to minimize the object count 227*a159c266SJung-uk Kim */ 228*a159c266SJung-uk Kim if (!ObjDesc->Method.Mutex) 229*a159c266SJung-uk Kim { 230*a159c266SJung-uk Kim Status = AcpiDsCreateMethodMutex (ObjDesc); 231*a159c266SJung-uk Kim if (ACPI_FAILURE (Status)) 232*a159c266SJung-uk Kim { 233*a159c266SJung-uk Kim return_ACPI_STATUS (Status); 234*a159c266SJung-uk Kim } 235*a159c266SJung-uk Kim } 236*a159c266SJung-uk Kim 237*a159c266SJung-uk Kim /* 238*a159c266SJung-uk Kim * The CurrentSyncLevel (per-thread) must be less than or equal to 239*a159c266SJung-uk Kim * the sync level of the method. This mechanism provides some 240*a159c266SJung-uk Kim * deadlock prevention 241*a159c266SJung-uk Kim * 242*a159c266SJung-uk Kim * Top-level method invocation has no walk state at this point 243*a159c266SJung-uk Kim */ 244*a159c266SJung-uk Kim if (WalkState && 245*a159c266SJung-uk Kim (WalkState->Thread->CurrentSyncLevel > ObjDesc->Method.Mutex->Mutex.SyncLevel)) 246*a159c266SJung-uk Kim { 247*a159c266SJung-uk Kim ACPI_ERROR ((AE_INFO, 248*a159c266SJung-uk Kim "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)", 249*a159c266SJung-uk Kim AcpiUtGetNodeName (MethodNode), 250*a159c266SJung-uk Kim WalkState->Thread->CurrentSyncLevel)); 251*a159c266SJung-uk Kim 252*a159c266SJung-uk Kim return_ACPI_STATUS (AE_AML_MUTEX_ORDER); 253*a159c266SJung-uk Kim } 254*a159c266SJung-uk Kim 255*a159c266SJung-uk Kim /* 256*a159c266SJung-uk Kim * Obtain the method mutex if necessary. Do not acquire mutex for a 257*a159c266SJung-uk Kim * recursive call. 258*a159c266SJung-uk Kim */ 259*a159c266SJung-uk Kim if (!WalkState || 260*a159c266SJung-uk Kim !ObjDesc->Method.Mutex->Mutex.ThreadId || 261*a159c266SJung-uk Kim (WalkState->Thread->ThreadId != ObjDesc->Method.Mutex->Mutex.ThreadId)) 262*a159c266SJung-uk Kim { 263*a159c266SJung-uk Kim /* 264*a159c266SJung-uk Kim * Acquire the method mutex. This releases the interpreter if we 265*a159c266SJung-uk Kim * block (and reacquires it before it returns) 266*a159c266SJung-uk Kim */ 267*a159c266SJung-uk Kim Status = AcpiExSystemWaitMutex (ObjDesc->Method.Mutex->Mutex.OsMutex, 268*a159c266SJung-uk Kim ACPI_WAIT_FOREVER); 269*a159c266SJung-uk Kim if (ACPI_FAILURE (Status)) 270*a159c266SJung-uk Kim { 271*a159c266SJung-uk Kim return_ACPI_STATUS (Status); 272*a159c266SJung-uk Kim } 273*a159c266SJung-uk Kim 274*a159c266SJung-uk Kim /* Update the mutex and walk info and save the original SyncLevel */ 275*a159c266SJung-uk Kim 276*a159c266SJung-uk Kim if (WalkState) 277*a159c266SJung-uk Kim { 278*a159c266SJung-uk Kim ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = 279*a159c266SJung-uk Kim WalkState->Thread->CurrentSyncLevel; 280*a159c266SJung-uk Kim 281*a159c266SJung-uk Kim ObjDesc->Method.Mutex->Mutex.ThreadId = WalkState->Thread->ThreadId; 282*a159c266SJung-uk Kim WalkState->Thread->CurrentSyncLevel = ObjDesc->Method.SyncLevel; 283*a159c266SJung-uk Kim } 284*a159c266SJung-uk Kim else 285*a159c266SJung-uk Kim { 286*a159c266SJung-uk Kim ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = 287*a159c266SJung-uk Kim ObjDesc->Method.Mutex->Mutex.SyncLevel; 288*a159c266SJung-uk Kim } 289*a159c266SJung-uk Kim } 290*a159c266SJung-uk Kim 291*a159c266SJung-uk Kim /* Always increase acquisition depth */ 292*a159c266SJung-uk Kim 293*a159c266SJung-uk Kim ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++; 294*a159c266SJung-uk Kim } 295*a159c266SJung-uk Kim 296*a159c266SJung-uk Kim /* 297*a159c266SJung-uk Kim * Allocate an Owner ID for this method, only if this is the first thread 298*a159c266SJung-uk Kim * to begin concurrent execution. We only need one OwnerId, even if the 299*a159c266SJung-uk Kim * method is invoked recursively. 300*a159c266SJung-uk Kim */ 301*a159c266SJung-uk Kim if (!ObjDesc->Method.OwnerId) 302*a159c266SJung-uk Kim { 303*a159c266SJung-uk Kim Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId); 304*a159c266SJung-uk Kim if (ACPI_FAILURE (Status)) 305*a159c266SJung-uk Kim { 306*a159c266SJung-uk Kim goto Cleanup; 307*a159c266SJung-uk Kim } 308*a159c266SJung-uk Kim } 309*a159c266SJung-uk Kim 310*a159c266SJung-uk Kim /* 311*a159c266SJung-uk Kim * Increment the method parse tree thread count since it has been 312*a159c266SJung-uk Kim * reentered one more time (even if it is the same thread) 313*a159c266SJung-uk Kim */ 314*a159c266SJung-uk Kim ObjDesc->Method.ThreadCount++; 315*a159c266SJung-uk Kim AcpiMethodCount++; 316*a159c266SJung-uk Kim return_ACPI_STATUS (Status); 317*a159c266SJung-uk Kim 318*a159c266SJung-uk Kim 319*a159c266SJung-uk Kim Cleanup: 320*a159c266SJung-uk Kim /* On error, must release the method mutex (if present) */ 321*a159c266SJung-uk Kim 322*a159c266SJung-uk Kim if (ObjDesc->Method.Mutex) 323*a159c266SJung-uk Kim { 324*a159c266SJung-uk Kim AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex); 325*a159c266SJung-uk Kim } 326*a159c266SJung-uk Kim return_ACPI_STATUS (Status); 327*a159c266SJung-uk Kim } 328*a159c266SJung-uk Kim 329*a159c266SJung-uk Kim 330*a159c266SJung-uk Kim /******************************************************************************* 331*a159c266SJung-uk Kim * 332*a159c266SJung-uk Kim * FUNCTION: AcpiDsCallControlMethod 333*a159c266SJung-uk Kim * 334*a159c266SJung-uk Kim * PARAMETERS: Thread - Info for this thread 335*a159c266SJung-uk Kim * ThisWalkState - Current walk state 336*a159c266SJung-uk Kim * Op - Current Op to be walked 337*a159c266SJung-uk Kim * 338*a159c266SJung-uk Kim * RETURN: Status 339*a159c266SJung-uk Kim * 340*a159c266SJung-uk Kim * DESCRIPTION: Transfer execution to a called control method 341*a159c266SJung-uk Kim * 342*a159c266SJung-uk Kim ******************************************************************************/ 343*a159c266SJung-uk Kim 344*a159c266SJung-uk Kim ACPI_STATUS 345*a159c266SJung-uk Kim AcpiDsCallControlMethod ( 346*a159c266SJung-uk Kim ACPI_THREAD_STATE *Thread, 347*a159c266SJung-uk Kim ACPI_WALK_STATE *ThisWalkState, 348*a159c266SJung-uk Kim ACPI_PARSE_OBJECT *Op) 349*a159c266SJung-uk Kim { 350*a159c266SJung-uk Kim ACPI_STATUS Status; 351*a159c266SJung-uk Kim ACPI_NAMESPACE_NODE *MethodNode; 352*a159c266SJung-uk Kim ACPI_WALK_STATE *NextWalkState = NULL; 353*a159c266SJung-uk Kim ACPI_OPERAND_OBJECT *ObjDesc; 354*a159c266SJung-uk Kim ACPI_EVALUATE_INFO *Info; 355*a159c266SJung-uk Kim UINT32 i; 356*a159c266SJung-uk Kim 357*a159c266SJung-uk Kim 358*a159c266SJung-uk Kim ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState); 359*a159c266SJung-uk Kim 360*a159c266SJung-uk Kim ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Calling method %p, currentstate=%p\n", 361*a159c266SJung-uk Kim ThisWalkState->PrevOp, ThisWalkState)); 362*a159c266SJung-uk Kim 363*a159c266SJung-uk Kim /* 364*a159c266SJung-uk Kim * Get the namespace entry for the control method we are about to call 365*a159c266SJung-uk Kim */ 366*a159c266SJung-uk Kim MethodNode = ThisWalkState->MethodCallNode; 367*a159c266SJung-uk Kim if (!MethodNode) 368*a159c266SJung-uk Kim { 369*a159c266SJung-uk Kim return_ACPI_STATUS (AE_NULL_ENTRY); 370*a159c266SJung-uk Kim } 371*a159c266SJung-uk Kim 372*a159c266SJung-uk Kim ObjDesc = AcpiNsGetAttachedObject (MethodNode); 373*a159c266SJung-uk Kim if (!ObjDesc) 374*a159c266SJung-uk Kim { 375*a159c266SJung-uk Kim return_ACPI_STATUS (AE_NULL_OBJECT); 376*a159c266SJung-uk Kim } 377*a159c266SJung-uk Kim 378*a159c266SJung-uk Kim /* Init for new method, possibly wait on method mutex */ 379*a159c266SJung-uk Kim 380*a159c266SJung-uk Kim Status = AcpiDsBeginMethodExecution (MethodNode, ObjDesc, 381*a159c266SJung-uk Kim ThisWalkState); 382*a159c266SJung-uk Kim if (ACPI_FAILURE (Status)) 383*a159c266SJung-uk Kim { 384*a159c266SJung-uk Kim return_ACPI_STATUS (Status); 385*a159c266SJung-uk Kim } 386*a159c266SJung-uk Kim 387*a159c266SJung-uk Kim /* Begin method parse/execution. Create a new walk state */ 388*a159c266SJung-uk Kim 389*a159c266SJung-uk Kim NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwnerId, 390*a159c266SJung-uk Kim NULL, ObjDesc, Thread); 391*a159c266SJung-uk Kim if (!NextWalkState) 392*a159c266SJung-uk Kim { 393*a159c266SJung-uk Kim Status = AE_NO_MEMORY; 394*a159c266SJung-uk Kim goto Cleanup; 395*a159c266SJung-uk Kim } 396*a159c266SJung-uk Kim 397*a159c266SJung-uk Kim /* 398*a159c266SJung-uk Kim * The resolved arguments were put on the previous walk state's operand 399*a159c266SJung-uk Kim * stack. Operands on the previous walk state stack always 400*a159c266SJung-uk Kim * start at index 0. Also, null terminate the list of arguments 401*a159c266SJung-uk Kim */ 402*a159c266SJung-uk Kim ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL; 403*a159c266SJung-uk Kim 404*a159c266SJung-uk Kim /* 405*a159c266SJung-uk Kim * Allocate and initialize the evaluation information block 406*a159c266SJung-uk Kim * TBD: this is somewhat inefficient, should change interface to 407*a159c266SJung-uk Kim * DsInitAmlWalk. For now, keeps this struct off the CPU stack 408*a159c266SJung-uk Kim */ 409*a159c266SJung-uk Kim Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); 410*a159c266SJung-uk Kim if (!Info) 411*a159c266SJung-uk Kim { 412*a159c266SJung-uk Kim return_ACPI_STATUS (AE_NO_MEMORY); 413*a159c266SJung-uk Kim } 414*a159c266SJung-uk Kim 415*a159c266SJung-uk Kim Info->Parameters = &ThisWalkState->Operands[0]; 416*a159c266SJung-uk Kim 417*a159c266SJung-uk Kim Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode, 418*a159c266SJung-uk Kim ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, 419*a159c266SJung-uk Kim Info, ACPI_IMODE_EXECUTE); 420*a159c266SJung-uk Kim 421*a159c266SJung-uk Kim ACPI_FREE (Info); 422*a159c266SJung-uk Kim if (ACPI_FAILURE (Status)) 423*a159c266SJung-uk Kim { 424*a159c266SJung-uk Kim goto Cleanup; 425*a159c266SJung-uk Kim } 426*a159c266SJung-uk Kim 427*a159c266SJung-uk Kim /* 428*a159c266SJung-uk Kim * Delete the operands on the previous walkstate operand stack 429*a159c266SJung-uk Kim * (they were copied to new objects) 430*a159c266SJung-uk Kim */ 431*a159c266SJung-uk Kim for (i = 0; i < ObjDesc->Method.ParamCount; i++) 432*a159c266SJung-uk Kim { 433*a159c266SJung-uk Kim AcpiUtRemoveReference (ThisWalkState->Operands [i]); 434*a159c266SJung-uk Kim ThisWalkState->Operands [i] = NULL; 435*a159c266SJung-uk Kim } 436*a159c266SJung-uk Kim 437*a159c266SJung-uk Kim /* Clear the operand stack */ 438*a159c266SJung-uk Kim 439*a159c266SJung-uk Kim ThisWalkState->NumOperands = 0; 440*a159c266SJung-uk Kim 441*a159c266SJung-uk Kim ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 442*a159c266SJung-uk Kim "**** Begin nested execution of [%4.4s] **** WalkState=%p\n", 443*a159c266SJung-uk Kim MethodNode->Name.Ascii, NextWalkState)); 444*a159c266SJung-uk Kim 445*a159c266SJung-uk Kim /* Invoke an internal method if necessary */ 446*a159c266SJung-uk Kim 447*a159c266SJung-uk Kim if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY) 448*a159c266SJung-uk Kim { 449*a159c266SJung-uk Kim Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState); 450*a159c266SJung-uk Kim if (Status == AE_OK) 451*a159c266SJung-uk Kim { 452*a159c266SJung-uk Kim Status = AE_CTRL_TERMINATE; 453*a159c266SJung-uk Kim } 454*a159c266SJung-uk Kim } 455*a159c266SJung-uk Kim 456*a159c266SJung-uk Kim return_ACPI_STATUS (Status); 457*a159c266SJung-uk Kim 458*a159c266SJung-uk Kim 459*a159c266SJung-uk Kim Cleanup: 460*a159c266SJung-uk Kim 461*a159c266SJung-uk Kim /* On error, we must terminate the method properly */ 462*a159c266SJung-uk Kim 463*a159c266SJung-uk Kim AcpiDsTerminateControlMethod (ObjDesc, NextWalkState); 464*a159c266SJung-uk Kim if (NextWalkState) 465*a159c266SJung-uk Kim { 466*a159c266SJung-uk Kim AcpiDsDeleteWalkState (NextWalkState); 467*a159c266SJung-uk Kim } 468*a159c266SJung-uk Kim 469*a159c266SJung-uk Kim return_ACPI_STATUS (Status); 470*a159c266SJung-uk Kim } 471*a159c266SJung-uk Kim 472*a159c266SJung-uk Kim 473*a159c266SJung-uk Kim /******************************************************************************* 474*a159c266SJung-uk Kim * 475*a159c266SJung-uk Kim * FUNCTION: AcpiDsRestartControlMethod 476*a159c266SJung-uk Kim * 477*a159c266SJung-uk Kim * PARAMETERS: WalkState - State for preempted method (caller) 478*a159c266SJung-uk Kim * ReturnDesc - Return value from the called method 479*a159c266SJung-uk Kim * 480*a159c266SJung-uk Kim * RETURN: Status 481*a159c266SJung-uk Kim * 482*a159c266SJung-uk Kim * DESCRIPTION: Restart a method that was preempted by another (nested) method 483*a159c266SJung-uk Kim * invocation. Handle the return value (if any) from the callee. 484*a159c266SJung-uk Kim * 485*a159c266SJung-uk Kim ******************************************************************************/ 486*a159c266SJung-uk Kim 487*a159c266SJung-uk Kim ACPI_STATUS 488*a159c266SJung-uk Kim AcpiDsRestartControlMethod ( 489*a159c266SJung-uk Kim ACPI_WALK_STATE *WalkState, 490*a159c266SJung-uk Kim ACPI_OPERAND_OBJECT *ReturnDesc) 491*a159c266SJung-uk Kim { 492*a159c266SJung-uk Kim ACPI_STATUS Status; 493*a159c266SJung-uk Kim int SameAsImplicitReturn; 494*a159c266SJung-uk Kim 495*a159c266SJung-uk Kim 496*a159c266SJung-uk Kim ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState); 497*a159c266SJung-uk Kim 498*a159c266SJung-uk Kim 499*a159c266SJung-uk Kim ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 500*a159c266SJung-uk Kim "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", 501*a159c266SJung-uk Kim AcpiUtGetNodeName (WalkState->MethodNode), 502*a159c266SJung-uk Kim WalkState->MethodCallOp, ReturnDesc)); 503*a159c266SJung-uk Kim 504*a159c266SJung-uk Kim ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 505*a159c266SJung-uk Kim " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", 506*a159c266SJung-uk Kim WalkState->ReturnUsed, 507*a159c266SJung-uk Kim WalkState->Results, WalkState)); 508*a159c266SJung-uk Kim 509*a159c266SJung-uk Kim /* Did the called method return a value? */ 510*a159c266SJung-uk Kim 511*a159c266SJung-uk Kim if (ReturnDesc) 512*a159c266SJung-uk Kim { 513*a159c266SJung-uk Kim /* Is the implicit return object the same as the return desc? */ 514*a159c266SJung-uk Kim 515*a159c266SJung-uk Kim SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc); 516*a159c266SJung-uk Kim 517*a159c266SJung-uk Kim /* Are we actually going to use the return value? */ 518*a159c266SJung-uk Kim 519*a159c266SJung-uk Kim if (WalkState->ReturnUsed) 520*a159c266SJung-uk Kim { 521*a159c266SJung-uk Kim /* Save the return value from the previous method */ 522*a159c266SJung-uk Kim 523*a159c266SJung-uk Kim Status = AcpiDsResultPush (ReturnDesc, WalkState); 524*a159c266SJung-uk Kim if (ACPI_FAILURE (Status)) 525*a159c266SJung-uk Kim { 526*a159c266SJung-uk Kim AcpiUtRemoveReference (ReturnDesc); 527*a159c266SJung-uk Kim return_ACPI_STATUS (Status); 528*a159c266SJung-uk Kim } 529*a159c266SJung-uk Kim 530*a159c266SJung-uk Kim /* 531*a159c266SJung-uk Kim * Save as THIS method's return value in case it is returned 532*a159c266SJung-uk Kim * immediately to yet another method 533*a159c266SJung-uk Kim */ 534*a159c266SJung-uk Kim WalkState->ReturnDesc = ReturnDesc; 535*a159c266SJung-uk Kim } 536*a159c266SJung-uk Kim 537*a159c266SJung-uk Kim /* 538*a159c266SJung-uk Kim * The following code is the optional support for the so-called 539*a159c266SJung-uk Kim * "implicit return". Some AML code assumes that the last value of the 540*a159c266SJung-uk Kim * method is "implicitly" returned to the caller, in the absence of an 541*a159c266SJung-uk Kim * explicit return value. 542*a159c266SJung-uk Kim * 543*a159c266SJung-uk Kim * Just save the last result of the method as the return value. 544*a159c266SJung-uk Kim * 545*a159c266SJung-uk Kim * NOTE: this is optional because the ASL language does not actually 546*a159c266SJung-uk Kim * support this behavior. 547*a159c266SJung-uk Kim */ 548*a159c266SJung-uk Kim else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) || 549*a159c266SJung-uk Kim SameAsImplicitReturn) 550*a159c266SJung-uk Kim { 551*a159c266SJung-uk Kim /* 552*a159c266SJung-uk Kim * Delete the return value if it will not be used by the 553*a159c266SJung-uk Kim * calling method or remove one reference if the explicit return 554*a159c266SJung-uk Kim * is the same as the implicit return value. 555*a159c266SJung-uk Kim */ 556*a159c266SJung-uk Kim AcpiUtRemoveReference (ReturnDesc); 557*a159c266SJung-uk Kim } 558*a159c266SJung-uk Kim } 559*a159c266SJung-uk Kim 560*a159c266SJung-uk Kim return_ACPI_STATUS (AE_OK); 561*a159c266SJung-uk Kim } 562*a159c266SJung-uk Kim 563*a159c266SJung-uk Kim 564*a159c266SJung-uk Kim /******************************************************************************* 565*a159c266SJung-uk Kim * 566*a159c266SJung-uk Kim * FUNCTION: AcpiDsTerminateControlMethod 567*a159c266SJung-uk Kim * 568*a159c266SJung-uk Kim * PARAMETERS: MethodDesc - Method object 569*a159c266SJung-uk Kim * WalkState - State associated with the method 570*a159c266SJung-uk Kim * 571*a159c266SJung-uk Kim * RETURN: None 572*a159c266SJung-uk Kim * 573*a159c266SJung-uk Kim * DESCRIPTION: Terminate a control method. Delete everything that the method 574*a159c266SJung-uk Kim * created, delete all locals and arguments, and delete the parse 575*a159c266SJung-uk Kim * tree if requested. 576*a159c266SJung-uk Kim * 577*a159c266SJung-uk Kim * MUTEX: Interpreter is locked 578*a159c266SJung-uk Kim * 579*a159c266SJung-uk Kim ******************************************************************************/ 580*a159c266SJung-uk Kim 581*a159c266SJung-uk Kim void 582*a159c266SJung-uk Kim AcpiDsTerminateControlMethod ( 583*a159c266SJung-uk Kim ACPI_OPERAND_OBJECT *MethodDesc, 584*a159c266SJung-uk Kim ACPI_WALK_STATE *WalkState) 585*a159c266SJung-uk Kim { 586*a159c266SJung-uk Kim 587*a159c266SJung-uk Kim ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState); 588*a159c266SJung-uk Kim 589*a159c266SJung-uk Kim 590*a159c266SJung-uk Kim /* MethodDesc is required, WalkState is optional */ 591*a159c266SJung-uk Kim 592*a159c266SJung-uk Kim if (!MethodDesc) 593*a159c266SJung-uk Kim { 594*a159c266SJung-uk Kim return_VOID; 595*a159c266SJung-uk Kim } 596*a159c266SJung-uk Kim 597*a159c266SJung-uk Kim if (WalkState) 598*a159c266SJung-uk Kim { 599*a159c266SJung-uk Kim /* Delete all arguments and locals */ 600*a159c266SJung-uk Kim 601*a159c266SJung-uk Kim AcpiDsMethodDataDeleteAll (WalkState); 602*a159c266SJung-uk Kim 603*a159c266SJung-uk Kim /* 604*a159c266SJung-uk Kim * If method is serialized, release the mutex and restore the 605*a159c266SJung-uk Kim * current sync level for this thread 606*a159c266SJung-uk Kim */ 607*a159c266SJung-uk Kim if (MethodDesc->Method.Mutex) 608*a159c266SJung-uk Kim { 609*a159c266SJung-uk Kim /* Acquisition Depth handles recursive calls */ 610*a159c266SJung-uk Kim 611*a159c266SJung-uk Kim MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--; 612*a159c266SJung-uk Kim if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth) 613*a159c266SJung-uk Kim { 614*a159c266SJung-uk Kim WalkState->Thread->CurrentSyncLevel = 615*a159c266SJung-uk Kim MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel; 616*a159c266SJung-uk Kim 617*a159c266SJung-uk Kim AcpiOsReleaseMutex (MethodDesc->Method.Mutex->Mutex.OsMutex); 618*a159c266SJung-uk Kim MethodDesc->Method.Mutex->Mutex.ThreadId = 0; 619*a159c266SJung-uk Kim } 620*a159c266SJung-uk Kim } 621*a159c266SJung-uk Kim 622*a159c266SJung-uk Kim /* 623*a159c266SJung-uk Kim * Delete any namespace objects created anywhere within the 624*a159c266SJung-uk Kim * namespace by the execution of this method. Unless: 625*a159c266SJung-uk Kim * 1) This method is a module-level executable code method, in which 626*a159c266SJung-uk Kim * case we want make the objects permanent. 627*a159c266SJung-uk Kim * 2) There are other threads executing the method, in which case we 628*a159c266SJung-uk Kim * will wait until the last thread has completed. 629*a159c266SJung-uk Kim */ 630*a159c266SJung-uk Kim if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) && 631*a159c266SJung-uk Kim (MethodDesc->Method.ThreadCount == 1)) 632*a159c266SJung-uk Kim { 633*a159c266SJung-uk Kim /* Delete any direct children of (created by) this method */ 634*a159c266SJung-uk Kim 635*a159c266SJung-uk Kim AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode); 636*a159c266SJung-uk Kim 637*a159c266SJung-uk Kim /* 638*a159c266SJung-uk Kim * Delete any objects that were created by this method 639*a159c266SJung-uk Kim * elsewhere in the namespace (if any were created). 640*a159c266SJung-uk Kim * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the 641*a159c266SJung-uk Kim * deletion such that we don't have to perform an entire 642*a159c266SJung-uk Kim * namespace walk for every control method execution. 643*a159c266SJung-uk Kim */ 644*a159c266SJung-uk Kim if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE) 645*a159c266SJung-uk Kim { 646*a159c266SJung-uk Kim AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId); 647*a159c266SJung-uk Kim MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_MODIFIED_NAMESPACE; 648*a159c266SJung-uk Kim } 649*a159c266SJung-uk Kim } 650*a159c266SJung-uk Kim } 651*a159c266SJung-uk Kim 652*a159c266SJung-uk Kim /* Decrement the thread count on the method */ 653*a159c266SJung-uk Kim 654*a159c266SJung-uk Kim if (MethodDesc->Method.ThreadCount) 655*a159c266SJung-uk Kim { 656*a159c266SJung-uk Kim MethodDesc->Method.ThreadCount--; 657*a159c266SJung-uk Kim } 658*a159c266SJung-uk Kim else 659*a159c266SJung-uk Kim { 660*a159c266SJung-uk Kim ACPI_ERROR ((AE_INFO, 661*a159c266SJung-uk Kim "Invalid zero thread count in method")); 662*a159c266SJung-uk Kim } 663*a159c266SJung-uk Kim 664*a159c266SJung-uk Kim /* Are there any other threads currently executing this method? */ 665*a159c266SJung-uk Kim 666*a159c266SJung-uk Kim if (MethodDesc->Method.ThreadCount) 667*a159c266SJung-uk Kim { 668*a159c266SJung-uk Kim /* 669*a159c266SJung-uk Kim * Additional threads. Do not release the OwnerId in this case, 670*a159c266SJung-uk Kim * we immediately reuse it for the next thread executing this method 671*a159c266SJung-uk Kim */ 672*a159c266SJung-uk Kim ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 673*a159c266SJung-uk Kim "*** Completed execution of one thread, %u threads remaining\n", 674*a159c266SJung-uk Kim MethodDesc->Method.ThreadCount)); 675*a159c266SJung-uk Kim } 676*a159c266SJung-uk Kim else 677*a159c266SJung-uk Kim { 678*a159c266SJung-uk Kim /* This is the only executing thread for this method */ 679*a159c266SJung-uk Kim 680*a159c266SJung-uk Kim /* 681*a159c266SJung-uk Kim * Support to dynamically change a method from NotSerialized to 682*a159c266SJung-uk Kim * Serialized if it appears that the method is incorrectly written and 683*a159c266SJung-uk Kim * does not support multiple thread execution. The best example of this 684*a159c266SJung-uk Kim * is if such a method creates namespace objects and blocks. A second 685*a159c266SJung-uk Kim * thread will fail with an AE_ALREADY_EXISTS exception. 686*a159c266SJung-uk Kim * 687*a159c266SJung-uk Kim * This code is here because we must wait until the last thread exits 688*a159c266SJung-uk Kim * before marking the method as serialized. 689*a159c266SJung-uk Kim */ 690*a159c266SJung-uk Kim if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING) 691*a159c266SJung-uk Kim { 692*a159c266SJung-uk Kim if (WalkState) 693*a159c266SJung-uk Kim { 694*a159c266SJung-uk Kim ACPI_INFO ((AE_INFO, 695*a159c266SJung-uk Kim "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", 696*a159c266SJung-uk Kim WalkState->MethodNode->Name.Ascii)); 697*a159c266SJung-uk Kim } 698*a159c266SJung-uk Kim 699*a159c266SJung-uk Kim /* 700*a159c266SJung-uk Kim * Method tried to create an object twice and was marked as 701*a159c266SJung-uk Kim * "pending serialized". The probable cause is that the method 702*a159c266SJung-uk Kim * cannot handle reentrancy. 703*a159c266SJung-uk Kim * 704*a159c266SJung-uk Kim * The method was created as NotSerialized, but it tried to create 705*a159c266SJung-uk Kim * a named object and then blocked, causing the second thread 706*a159c266SJung-uk Kim * entrance to begin and then fail. Workaround this problem by 707*a159c266SJung-uk Kim * marking the method permanently as Serialized when the last 708*a159c266SJung-uk Kim * thread exits here. 709*a159c266SJung-uk Kim */ 710*a159c266SJung-uk Kim MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_SERIALIZED_PENDING; 711*a159c266SJung-uk Kim MethodDesc->Method.InfoFlags |= ACPI_METHOD_SERIALIZED; 712*a159c266SJung-uk Kim MethodDesc->Method.SyncLevel = 0; 713*a159c266SJung-uk Kim } 714*a159c266SJung-uk Kim 715*a159c266SJung-uk Kim /* No more threads, we can free the OwnerId */ 716*a159c266SJung-uk Kim 717*a159c266SJung-uk Kim if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL)) 718*a159c266SJung-uk Kim { 719*a159c266SJung-uk Kim AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId); 720*a159c266SJung-uk Kim } 721*a159c266SJung-uk Kim } 722*a159c266SJung-uk Kim 723*a159c266SJung-uk Kim return_VOID; 724*a159c266SJung-uk Kim } 725*a159c266SJung-uk Kim 726*a159c266SJung-uk Kim 727