Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/acpica/dsmethod.c need to be fixed.

0001 /******************************************************************************
0002  *
0003  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
0004  *
0005  *****************************************************************************/
0006 
0007 /******************************************************************************
0008  *
0009  * 1. Copyright Notice
0010  *
0011  * Some or all of this work - Copyright (c) 1999 - 2009, Intel Corp.
0012  * All rights reserved.
0013  *
0014  * 2. License
0015  *
0016  * 2.1. This is your license from Intel Corp. under its intellectual property
0017  * rights.  You may have additional license terms from the party that provided
0018  * you this software, covering your right to use that party's intellectual
0019  * property rights.
0020  *
0021  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
0022  * copy of the source code appearing in this file ("Covered Code") an
0023  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
0024  * base code distributed originally by Intel ("Original Intel Code") to copy,
0025  * make derivatives, distribute, use and display any portion of the Covered
0026  * Code in any form, with the right to sublicense such rights; and
0027  *
0028  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
0029  * license (with the right to sublicense), under only those claims of Intel
0030  * patents that are infringed by the Original Intel Code, to make, use, sell,
0031  * offer to sell, and import the Covered Code and derivative works thereof
0032  * solely to the minimum extent necessary to exercise the above copyright
0033  * license, and in no event shall the patent license extend to any additions
0034  * to or modifications of the Original Intel Code.  No other license or right
0035  * is granted directly or by implication, estoppel or otherwise;
0036  *
0037  * The above copyright and patent license is granted only if the following
0038  * conditions are met:
0039  *
0040  * 3. Conditions
0041  *
0042  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
0043  * Redistribution of source code of any substantial portion of the Covered
0044  * Code or modification with rights to further distribute source must include
0045  * the above Copyright Notice, the above License, this list of Conditions,
0046  * and the following Disclaimer and Export Compliance provision.  In addition,
0047  * Licensee must cause all Covered Code to which Licensee contributes to
0048  * contain a file documenting the changes Licensee made to create that Covered
0049  * Code and the date of any change.  Licensee must include in that file the
0050  * documentation of any changes made by any predecessor Licensee.  Licensee
0051  * must include a prominent statement that the modification is derived,
0052  * directly or indirectly, from Original Intel Code.
0053  *
0054  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
0055  * Redistribution of source code of any substantial portion of the Covered
0056  * Code or modification without rights to further distribute source must
0057  * include the following Disclaimer and Export Compliance provision in the
0058  * documentation and/or other materials provided with distribution.  In
0059  * addition, Licensee may not authorize further sublicense of source of any
0060  * portion of the Covered Code, and must include terms to the effect that the
0061  * license from Licensee to its licensee is limited to the intellectual
0062  * property embodied in the software Licensee provides to its licensee, and
0063  * not to intellectual property embodied in modifications its licensee may
0064  * make.
0065  *
0066  * 3.3. Redistribution of Executable. Redistribution in executable form of any
0067  * substantial portion of the Covered Code or modification must reproduce the
0068  * above Copyright Notice, and the following Disclaimer and Export Compliance
0069  * provision in the documentation and/or other materials provided with the
0070  * distribution.
0071  *
0072  * 3.4. Intel retains all right, title, and interest in and to the Original
0073  * Intel Code.
0074  *
0075  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
0076  * Intel shall be used in advertising or otherwise to promote the sale, use or
0077  * other dealings in products derived from or relating to the Covered Code
0078  * without prior written authorization from Intel.
0079  *
0080  * 4. Disclaimer and Export Compliance
0081  *
0082  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
0083  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
0084  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
0085  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
0086  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
0087  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
0088  * PARTICULAR PURPOSE.
0089  *
0090  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
0091  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
0092  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
0093  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
0094  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
0095  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
0096  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
0097  * LIMITED REMEDY.
0098  *
0099  * 4.3. Licensee shall not export, either directly or indirectly, any of this
0100  * software or system incorporating such software without first obtaining any
0101  * required license or other approval from the U. S. Department of Commerce or
0102  * any other agency or department of the United States Government.  In the
0103  * event Licensee exports any such software from the United States or
0104  * re-exports any such software from a foreign destination, Licensee shall
0105  * ensure that the distribution and export/re-export of the software is in
0106  * compliance with all laws, regulations, orders, or other restrictions of the
0107  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
0108  * any of its subsidiaries will export/re-export any technical data, process,
0109  * software, or service, directly or indirectly, to any country for which the
0110  * United States government or any agency thereof requires an export license,
0111  * other governmental approval, or letter of assurance, without first obtaining
0112  * such license, approval or letter.
0113  *
0114  *****************************************************************************/
0115 
0116 #define __DSMETHOD_C__
0117 
0118 #include "acpi.h"
0119 #include "accommon.h"
0120 #include "amlcode.h"
0121 #include "acdispat.h"
0122 #include "acinterp.h"
0123 #include "acnamesp.h"
0124 #include "acdisasm.h"
0125 
0126 
0127 #define _COMPONENT          ACPI_DISPATCHER
0128         ACPI_MODULE_NAME    ("dsmethod")
0129 
0130 /* Local prototypes */
0131 
0132 static ACPI_STATUS
0133 AcpiDsCreateMethodMutex (
0134     ACPI_OPERAND_OBJECT     *MethodDesc);
0135 
0136 
0137 /*******************************************************************************
0138  *
0139  * FUNCTION:    AcpiDsMethodError
0140  *
0141  * PARAMETERS:  Status          - Execution status
0142  *              WalkState       - Current state
0143  *
0144  * RETURN:      Status
0145  *
0146  * DESCRIPTION: Called on method error. Invoke the global exception handler if
0147  *              present, dump the method data if the disassembler is configured
0148  *
0149  *              Note: Allows the exception handler to change the status code
0150  *
0151  ******************************************************************************/
0152 
0153 ACPI_STATUS
0154 AcpiDsMethodError (
0155     ACPI_STATUS             Status,
0156     ACPI_WALK_STATE         *WalkState)
0157 {
0158     ACPI_FUNCTION_ENTRY ();
0159 
0160 
0161     /* Ignore AE_OK and control exception codes */
0162 
0163     if (ACPI_SUCCESS (Status) ||
0164         (Status & AE_CODE_CONTROL))
0165     {
0166         return (Status);
0167     }
0168 
0169     /* Invoke the global exception handler */
0170 
0171     if (AcpiGbl_ExceptionHandler)
0172     {
0173         /* Exit the interpreter, allow handler to execute methods */
0174 
0175         AcpiExExitInterpreter ();
0176 
0177         /*
0178          * Handler can map the exception code to anything it wants, including
0179          * AE_OK, in which case the executing method will not be aborted.
0180          */
0181         Status = AcpiGbl_ExceptionHandler (Status,
0182                     WalkState->MethodNode ?
0183                         WalkState->MethodNode->Name.Integer : 0,
0184                     WalkState->Opcode, WalkState->AmlOffset, NULL);
0185         AcpiExEnterInterpreter ();
0186     }
0187 
0188     AcpiDsClearImplicitReturn (WalkState);
0189 
0190 #ifdef ACPI_DISASSEMBLER
0191     if (ACPI_FAILURE (Status))
0192     {
0193         /* Display method locals/args if disassembler is present */
0194 
0195         AcpiDmDumpMethodInfo (Status, WalkState, WalkState->Op);
0196     }
0197 #endif
0198 
0199     return (Status);
0200 }
0201 
0202 
0203 /*******************************************************************************
0204  *
0205  * FUNCTION:    AcpiDsCreateMethodMutex
0206  *
0207  * PARAMETERS:  ObjDesc             - The method object
0208  *
0209  * RETURN:      Status
0210  *
0211  * DESCRIPTION: Create a mutex object for a serialized control method
0212  *
0213  ******************************************************************************/
0214 
0215 static ACPI_STATUS
0216 AcpiDsCreateMethodMutex (
0217     ACPI_OPERAND_OBJECT     *MethodDesc)
0218 {
0219     ACPI_OPERAND_OBJECT     *MutexDesc;
0220     ACPI_STATUS             Status;
0221 
0222 
0223     ACPI_FUNCTION_TRACE (DsCreateMethodMutex);
0224 
0225 
0226     /* Create the new mutex object */
0227 
0228     MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX);
0229     if (!MutexDesc)
0230     {
0231         return_ACPI_STATUS (AE_NO_MEMORY);
0232     }
0233 
0234     /* Create the actual OS Mutex */
0235 
0236     Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex);
0237     if (ACPI_FAILURE (Status))
0238     {
0239         return_ACPI_STATUS (Status);
0240     }
0241 
0242     MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel;
0243     MethodDesc->Method.Mutex = MutexDesc;
0244     return_ACPI_STATUS (AE_OK);
0245 }
0246 
0247 
0248 /*******************************************************************************
0249  *
0250  * FUNCTION:    AcpiDsBeginMethodExecution
0251  *
0252  * PARAMETERS:  MethodNode          - Node of the method
0253  *              ObjDesc             - The method object
0254  *              WalkState           - current state, NULL if not yet executing
0255  *                                    a method.
0256  *
0257  * RETURN:      Status
0258  *
0259  * DESCRIPTION: Prepare a method for execution.  Parses the method if necessary,
0260  *              increments the thread count, and waits at the method semaphore
0261  *              for clearance to execute.
0262  *
0263  ******************************************************************************/
0264 
0265 ACPI_STATUS
0266 AcpiDsBeginMethodExecution (
0267     ACPI_NAMESPACE_NODE     *MethodNode,
0268     ACPI_OPERAND_OBJECT     *ObjDesc,
0269     ACPI_WALK_STATE         *WalkState)
0270 {
0271     ACPI_STATUS             Status = AE_OK;
0272 
0273 
0274     ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode);
0275 
0276 
0277     if (!MethodNode)
0278     {
0279         return_ACPI_STATUS (AE_NULL_ENTRY);
0280     }
0281 
0282     /* Prevent wraparound of thread count */
0283 
0284     if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX)
0285     {
0286         ACPI_ERROR ((AE_INFO,
0287             "Method reached maximum reentrancy limit (255)"));
0288         return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
0289     }
0290 
0291     /*
0292      * If this method is serialized, we need to acquire the method mutex.
0293      */
0294     if (ObjDesc->Method.MethodFlags & AML_METHOD_SERIALIZED)
0295     {
0296         /*
0297          * Create a mutex for the method if it is defined to be Serialized
0298          * and a mutex has not already been created. We defer the mutex creation
0299          * until a method is actually executed, to minimize the object count
0300          */
0301         if (!ObjDesc->Method.Mutex)
0302         {
0303             Status = AcpiDsCreateMethodMutex (ObjDesc);
0304             if (ACPI_FAILURE (Status))
0305             {
0306                 return_ACPI_STATUS (Status);
0307             }
0308         }
0309 
0310         /*
0311          * The CurrentSyncLevel (per-thread) must be less than or equal to
0312          * the sync level of the method. This mechanism provides some
0313          * deadlock prevention
0314          *
0315          * Top-level method invocation has no walk state at this point
0316          */
0317         if (WalkState &&
0318             (WalkState->Thread->CurrentSyncLevel > ObjDesc->Method.Mutex->Mutex.SyncLevel))
0319         {
0320             ACPI_ERROR ((AE_INFO,
0321                 "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%d)",
0322                 AcpiUtGetNodeName (MethodNode),
0323                 WalkState->Thread->CurrentSyncLevel));
0324 
0325             return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
0326         }
0327 
0328         /*
0329          * Obtain the method mutex if necessary. Do not acquire mutex for a
0330          * recursive call.
0331          */
0332         if (!WalkState ||
0333             !ObjDesc->Method.Mutex->Mutex.ThreadId ||
0334             (WalkState->Thread->ThreadId != ObjDesc->Method.Mutex->Mutex.ThreadId))
0335         {
0336             /*
0337              * Acquire the method mutex. This releases the interpreter if we
0338              * block (and reacquires it before it returns)
0339              */
0340             Status = AcpiExSystemWaitMutex (ObjDesc->Method.Mutex->Mutex.OsMutex,
0341                         ACPI_WAIT_FOREVER);
0342             if (ACPI_FAILURE (Status))
0343             {
0344                 return_ACPI_STATUS (Status);
0345             }
0346 
0347             /* Update the mutex and walk info and save the original SyncLevel */
0348 
0349             if (WalkState)
0350             {
0351                 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
0352                     WalkState->Thread->CurrentSyncLevel;
0353 
0354                 ObjDesc->Method.Mutex->Mutex.ThreadId = WalkState->Thread->ThreadId;
0355                 WalkState->Thread->CurrentSyncLevel = ObjDesc->Method.SyncLevel;
0356             }
0357             else
0358             {
0359                 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel =
0360                     ObjDesc->Method.Mutex->Mutex.SyncLevel;
0361             }
0362         }
0363 
0364         /* Always increase acquisition depth */
0365 
0366         ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++;
0367     }
0368 
0369     /*
0370      * Allocate an Owner ID for this method, only if this is the first thread
0371      * to begin concurrent execution. We only need one OwnerId, even if the
0372      * method is invoked recursively.
0373      */
0374     if (!ObjDesc->Method.OwnerId)
0375     {
0376         Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
0377         if (ACPI_FAILURE (Status))
0378         {
0379             goto Cleanup;
0380         }
0381     }
0382 
0383     /*
0384      * Increment the method parse tree thread count since it has been
0385      * reentered one more time (even if it is the same thread)
0386      */
0387     ObjDesc->Method.ThreadCount++;
0388     AcpiMethodCount++;
0389     return_ACPI_STATUS (Status);
0390 
0391 
0392 Cleanup:
0393     /* On error, must release the method mutex (if present) */
0394 
0395     if (ObjDesc->Method.Mutex)
0396     {
0397         AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex);
0398     }
0399     return_ACPI_STATUS (Status);
0400 }
0401 
0402 
0403 /*******************************************************************************
0404  *
0405  * FUNCTION:    AcpiDsCallControlMethod
0406  *
0407  * PARAMETERS:  Thread              - Info for this thread
0408  *              ThisWalkState       - Current walk state
0409  *              Op                  - Current Op to be walked
0410  *
0411  * RETURN:      Status
0412  *
0413  * DESCRIPTION: Transfer execution to a called control method
0414  *
0415  ******************************************************************************/
0416 
0417 ACPI_STATUS
0418 AcpiDsCallControlMethod (
0419     ACPI_THREAD_STATE       *Thread,
0420     ACPI_WALK_STATE         *ThisWalkState,
0421     ACPI_PARSE_OBJECT       *Op)
0422 {
0423     ACPI_STATUS             Status;
0424     ACPI_NAMESPACE_NODE     *MethodNode;
0425     ACPI_WALK_STATE         *NextWalkState = NULL;
0426     ACPI_OPERAND_OBJECT     *ObjDesc;
0427     ACPI_EVALUATE_INFO      *Info;
0428     UINT32                  i;
0429 
0430 
0431     ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState);
0432 
0433     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Calling method %p, currentstate=%p\n",
0434         ThisWalkState->PrevOp, ThisWalkState));
0435 
0436     /*
0437      * Get the namespace entry for the control method we are about to call
0438      */
0439     MethodNode = ThisWalkState->MethodCallNode;
0440     if (!MethodNode)
0441     {
0442         return_ACPI_STATUS (AE_NULL_ENTRY);
0443     }
0444 
0445     ObjDesc = AcpiNsGetAttachedObject (MethodNode);
0446     if (!ObjDesc)
0447     {
0448         return_ACPI_STATUS (AE_NULL_OBJECT);
0449     }
0450 
0451     /* Init for new method, possibly wait on method mutex */
0452 
0453     Status = AcpiDsBeginMethodExecution (MethodNode, ObjDesc,
0454                 ThisWalkState);
0455     if (ACPI_FAILURE (Status))
0456     {
0457         return_ACPI_STATUS (Status);
0458     }
0459 
0460     /* Begin method parse/execution. Create a new walk state */
0461 
0462     NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwnerId,
0463                         NULL, ObjDesc, Thread);
0464     if (!NextWalkState)
0465     {
0466         Status = AE_NO_MEMORY;
0467         goto Cleanup;
0468     }
0469 
0470     /*
0471      * The resolved arguments were put on the previous walk state's operand
0472      * stack. Operands on the previous walk state stack always
0473      * start at index 0. Also, null terminate the list of arguments
0474      */
0475     ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL;
0476 
0477     /*
0478      * Allocate and initialize the evaluation information block
0479      * TBD: this is somewhat inefficient, should change interface to
0480      * DsInitAmlWalk. For now, keeps this struct off the CPU stack
0481      */
0482     Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
0483     if (!Info)
0484     {
0485         return_ACPI_STATUS (AE_NO_MEMORY);
0486     }
0487 
0488     Info->Parameters = &ThisWalkState->Operands[0];
0489 
0490     Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode,
0491                 ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength,
0492                 Info, ACPI_IMODE_EXECUTE);
0493 
0494     ACPI_FREE (Info);
0495     if (ACPI_FAILURE (Status))
0496     {
0497         goto Cleanup;
0498     }
0499 
0500     /*
0501      * Delete the operands on the previous walkstate operand stack
0502      * (they were copied to new objects)
0503      */
0504     for (i = 0; i < ObjDesc->Method.ParamCount; i++)
0505     {
0506         AcpiUtRemoveReference (ThisWalkState->Operands [i]);
0507         ThisWalkState->Operands [i] = NULL;
0508     }
0509 
0510     /* Clear the operand stack */
0511 
0512     ThisWalkState->NumOperands = 0;
0513 
0514     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
0515         "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
0516         MethodNode->Name.Ascii, NextWalkState));
0517 
0518     /* Invoke an internal method if necessary */
0519 
0520     if (ObjDesc->Method.MethodFlags & AML_METHOD_INTERNAL_ONLY)
0521     {
0522         Status = ObjDesc->Method.Implementation (NextWalkState);
0523         if (Status == AE_OK)
0524         {
0525             Status = AE_CTRL_TERMINATE;
0526         }
0527     }
0528 
0529     return_ACPI_STATUS (Status);
0530 
0531 
0532 Cleanup:
0533 
0534     /* On error, we must terminate the method properly */
0535 
0536     AcpiDsTerminateControlMethod (ObjDesc, NextWalkState);
0537     if (NextWalkState)
0538     {
0539         AcpiDsDeleteWalkState (NextWalkState);
0540     }
0541 
0542     return_ACPI_STATUS (Status);
0543 }
0544 
0545 
0546 /*******************************************************************************
0547  *
0548  * FUNCTION:    AcpiDsRestartControlMethod
0549  *
0550  * PARAMETERS:  WalkState           - State for preempted method (caller)
0551  *              ReturnDesc          - Return value from the called method
0552  *
0553  * RETURN:      Status
0554  *
0555  * DESCRIPTION: Restart a method that was preempted by another (nested) method
0556  *              invocation.  Handle the return value (if any) from the callee.
0557  *
0558  ******************************************************************************/
0559 
0560 ACPI_STATUS
0561 AcpiDsRestartControlMethod (
0562     ACPI_WALK_STATE         *WalkState,
0563     ACPI_OPERAND_OBJECT     *ReturnDesc)
0564 {
0565     ACPI_STATUS             Status;
0566     int                     SameAsImplicitReturn;
0567 
0568 
0569     ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState);
0570 
0571 
0572     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
0573         "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
0574         AcpiUtGetNodeName (WalkState->MethodNode),
0575         WalkState->MethodCallOp, ReturnDesc));
0576 
0577     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
0578         "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
0579         WalkState->ReturnUsed,
0580         WalkState->Results, WalkState));
0581 
0582     /* Did the called method return a value? */
0583 
0584     if (ReturnDesc)
0585     {
0586         /* Is the implicit return object the same as the return desc? */
0587 
0588         SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc);
0589 
0590         /* Are we actually going to use the return value? */
0591 
0592         if (WalkState->ReturnUsed)
0593         {
0594             /* Save the return value from the previous method */
0595 
0596             Status = AcpiDsResultPush (ReturnDesc, WalkState);
0597             if (ACPI_FAILURE (Status))
0598             {
0599                 AcpiUtRemoveReference (ReturnDesc);
0600                 return_ACPI_STATUS (Status);
0601             }
0602 
0603             /*
0604              * Save as THIS method's return value in case it is returned
0605              * immediately to yet another method
0606              */
0607             WalkState->ReturnDesc = ReturnDesc;
0608         }
0609 
0610         /*
0611          * The following code is the optional support for the so-called
0612          * "implicit return". Some AML code assumes that the last value of the
0613          * method is "implicitly" returned to the caller, in the absence of an
0614          * explicit return value.
0615          *
0616          * Just save the last result of the method as the return value.
0617          *
0618          * NOTE: this is optional because the ASL language does not actually
0619          * support this behavior.
0620          */
0621         else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) ||
0622                  SameAsImplicitReturn)
0623         {
0624             /*
0625              * Delete the return value if it will not be used by the
0626              * calling method or remove one reference if the explicit return
0627              * is the same as the implicit return value.
0628              */
0629             AcpiUtRemoveReference (ReturnDesc);
0630         }
0631     }
0632 
0633     return_ACPI_STATUS (AE_OK);
0634 }
0635 
0636 
0637 /*******************************************************************************
0638  *
0639  * FUNCTION:    AcpiDsTerminateControlMethod
0640  *
0641  * PARAMETERS:  MethodDesc          - Method object
0642  *              WalkState           - State associated with the method
0643  *
0644  * RETURN:      None
0645  *
0646  * DESCRIPTION: Terminate a control method.  Delete everything that the method
0647  *              created, delete all locals and arguments, and delete the parse
0648  *              tree if requested.
0649  *
0650  * MUTEX:       Interpreter is locked
0651  *
0652  ******************************************************************************/
0653 
0654 void
0655 AcpiDsTerminateControlMethod (
0656     ACPI_OPERAND_OBJECT     *MethodDesc,
0657     ACPI_WALK_STATE         *WalkState)
0658 {
0659 
0660     ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState);
0661 
0662 
0663     /* MethodDesc is required, WalkState is optional */
0664 
0665     if (!MethodDesc)
0666     {
0667         return_VOID;
0668     }
0669 
0670     if (WalkState)
0671     {
0672         /* Delete all arguments and locals */
0673 
0674         AcpiDsMethodDataDeleteAll (WalkState);
0675 
0676         /*
0677          * If method is serialized, release the mutex and restore the
0678          * current sync level for this thread
0679          */
0680         if (MethodDesc->Method.Mutex)
0681         {
0682             /* Acquisition Depth handles recursive calls */
0683 
0684             MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--;
0685             if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth)
0686             {
0687                 WalkState->Thread->CurrentSyncLevel =
0688                     MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel;
0689 
0690                 AcpiOsReleaseMutex (MethodDesc->Method.Mutex->Mutex.OsMutex);
0691                 MethodDesc->Method.Mutex->Mutex.ThreadId = 0;
0692             }
0693         }
0694 
0695         /*
0696          * Delete any namespace objects created anywhere within
0697          * the namespace by the execution of this method
0698          */
0699         AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId);
0700     }
0701 
0702     /* Decrement the thread count on the method */
0703 
0704     if (MethodDesc->Method.ThreadCount)
0705     {
0706         MethodDesc->Method.ThreadCount--;
0707     }
0708     else
0709     {
0710         ACPI_ERROR ((AE_INFO,
0711             "Invalid zero thread count in method"));
0712     }
0713 
0714     /* Are there any other threads currently executing this method? */
0715 
0716     if (MethodDesc->Method.ThreadCount)
0717     {
0718         /*
0719          * Additional threads. Do not release the OwnerId in this case,
0720          * we immediately reuse it for the next thread executing this method
0721          */
0722         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
0723             "*** Completed execution of one thread, %d threads remaining\n",
0724             MethodDesc->Method.ThreadCount));
0725     }
0726     else
0727     {
0728         /* This is the only executing thread for this method */
0729 
0730         /*
0731          * Support to dynamically change a method from NotSerialized to
0732          * Serialized if it appears that the method is incorrectly written and
0733          * does not support multiple thread execution. The best example of this
0734          * is if such a method creates namespace objects and blocks. A second
0735          * thread will fail with an AE_ALREADY_EXISTS exception
0736          *
0737          * This code is here because we must wait until the last thread exits
0738          * before creating the synchronization semaphore.
0739          */
0740         if ((MethodDesc->Method.MethodFlags & AML_METHOD_SERIALIZED) &&
0741             (!MethodDesc->Method.Mutex))
0742         {
0743             (void) AcpiDsCreateMethodMutex (MethodDesc);
0744         }
0745 
0746         /* No more threads, we can free the OwnerId */
0747 
0748         AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId);
0749     }
0750 
0751     return_VOID;
0752 }
0753 
0754