Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acdispat.h"
0013 #include "acinterp.h"
0014 #include "acnamesp.h"
0015 #include "acparser.h"
0016 #include "amlcode.h"
0017 #include "acdebug.h"
0018 
0019 #define _COMPONENT          ACPI_DISPATCHER
0020 ACPI_MODULE_NAME("dsmethod")
0021 
0022 /* Local prototypes */
0023 static acpi_status
0024 acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state,
0025                  union acpi_parse_object **out_op);
0026 
0027 static acpi_status
0028 acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);
0029 
0030 /*******************************************************************************
0031  *
0032  * FUNCTION:    acpi_ds_auto_serialize_method
0033  *
0034  * PARAMETERS:  node                        - Namespace Node of the method
0035  *              obj_desc                    - Method object attached to node
0036  *
0037  * RETURN:      Status
0038  *
0039  * DESCRIPTION: Parse a control method AML to scan for control methods that
0040  *              need serialization due to the creation of named objects.
0041  *
0042  * NOTE: It is a bit of overkill to mark all such methods serialized, since
0043  * there is only a problem if the method actually blocks during execution.
0044  * A blocking operation is, for example, a Sleep() operation, or any access
0045  * to an operation region. However, it is probably not possible to easily
0046  * detect whether a method will block or not, so we simply mark all suspicious
0047  * methods as serialized.
0048  *
0049  * NOTE2: This code is essentially a generic routine for parsing a single
0050  * control method.
0051  *
0052  ******************************************************************************/
0053 
0054 acpi_status
0055 acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
0056                   union acpi_operand_object *obj_desc)
0057 {
0058     acpi_status status;
0059     union acpi_parse_object *op = NULL;
0060     struct acpi_walk_state *walk_state;
0061 
0062     ACPI_FUNCTION_TRACE_PTR(ds_auto_serialize_method, node);
0063 
0064     ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
0065               "Method auto-serialization parse [%4.4s] %p\n",
0066               acpi_ut_get_node_name(node), node));
0067 
0068     /* Create/Init a root op for the method parse tree */
0069 
0070     op = acpi_ps_alloc_op(AML_METHOD_OP, obj_desc->method.aml_start);
0071     if (!op) {
0072         return_ACPI_STATUS(AE_NO_MEMORY);
0073     }
0074 
0075     acpi_ps_set_name(op, node->name.integer);
0076     op->common.node = node;
0077 
0078     /* Create and initialize a new walk state */
0079 
0080     walk_state =
0081         acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL);
0082     if (!walk_state) {
0083         acpi_ps_free_op(op);
0084         return_ACPI_STATUS(AE_NO_MEMORY);
0085     }
0086 
0087     status = acpi_ds_init_aml_walk(walk_state, op, node,
0088                        obj_desc->method.aml_start,
0089                        obj_desc->method.aml_length, NULL, 0);
0090     if (ACPI_FAILURE(status)) {
0091         acpi_ds_delete_walk_state(walk_state);
0092         acpi_ps_free_op(op);
0093         return_ACPI_STATUS(status);
0094     }
0095 
0096     walk_state->descending_callback = acpi_ds_detect_named_opcodes;
0097 
0098     /* Parse the method, scan for creation of named objects */
0099 
0100     status = acpi_ps_parse_aml(walk_state);
0101 
0102     acpi_ps_delete_parse_tree(op);
0103     return_ACPI_STATUS(status);
0104 }
0105 
0106 /*******************************************************************************
0107  *
0108  * FUNCTION:    acpi_ds_detect_named_opcodes
0109  *
0110  * PARAMETERS:  walk_state      - Current state of the parse tree walk
0111  *              out_op          - Unused, required for parser interface
0112  *
0113  * RETURN:      Status
0114  *
0115  * DESCRIPTION: Descending callback used during the loading of ACPI tables.
0116  *              Currently used to detect methods that must be marked serialized
0117  *              in order to avoid problems with the creation of named objects.
0118  *
0119  ******************************************************************************/
0120 
0121 static acpi_status
0122 acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state,
0123                  union acpi_parse_object **out_op)
0124 {
0125 
0126     ACPI_FUNCTION_NAME(acpi_ds_detect_named_opcodes);
0127 
0128     /* We are only interested in opcodes that create a new name */
0129 
0130     if (!
0131         (walk_state->op_info->
0132          flags & (AML_NAMED | AML_CREATE | AML_FIELD))) {
0133         return (AE_OK);
0134     }
0135 
0136     /*
0137      * At this point, we know we have a Named object opcode.
0138      * Mark the method as serialized. Later code will create a mutex for
0139      * this method to enforce serialization.
0140      *
0141      * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the
0142      * Sync Level mechanism for this method, even though it is now serialized.
0143      * Otherwise, there can be conflicts with existing ASL code that actually
0144      * uses sync levels.
0145      */
0146     walk_state->method_desc->method.sync_level = 0;
0147     walk_state->method_desc->method.info_flags |=
0148         (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
0149 
0150     ACPI_DEBUG_PRINT((ACPI_DB_INFO,
0151               "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
0152               walk_state->method_node->name.ascii,
0153               walk_state->method_node, walk_state->op_info->name,
0154               walk_state->opcode));
0155 
0156     /* Abort the parse, no need to examine this method any further */
0157 
0158     return (AE_CTRL_TERMINATE);
0159 }
0160 
0161 /*******************************************************************************
0162  *
0163  * FUNCTION:    acpi_ds_method_error
0164  *
0165  * PARAMETERS:  status          - Execution status
0166  *              walk_state      - Current state
0167  *
0168  * RETURN:      Status
0169  *
0170  * DESCRIPTION: Called on method error. Invoke the global exception handler if
0171  *              present, dump the method data if the debugger is configured
0172  *
0173  *              Note: Allows the exception handler to change the status code
0174  *
0175  ******************************************************************************/
0176 
0177 acpi_status
0178 acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
0179 {
0180     u32 aml_offset;
0181     acpi_name name = 0;
0182 
0183     ACPI_FUNCTION_ENTRY();
0184 
0185     /* Ignore AE_OK and control exception codes */
0186 
0187     if (ACPI_SUCCESS(status) || (status & AE_CODE_CONTROL)) {
0188         return (status);
0189     }
0190 
0191     /* Invoke the global exception handler */
0192 
0193     if (acpi_gbl_exception_handler) {
0194 
0195         /* Exit the interpreter, allow handler to execute methods */
0196 
0197         acpi_ex_exit_interpreter();
0198 
0199         /*
0200          * Handler can map the exception code to anything it wants, including
0201          * AE_OK, in which case the executing method will not be aborted.
0202          */
0203         aml_offset = (u32)ACPI_PTR_DIFF(walk_state->aml,
0204                         walk_state->parser_state.
0205                         aml_start);
0206 
0207         if (walk_state->method_node) {
0208             name = walk_state->method_node->name.integer;
0209         } else if (walk_state->deferred_node) {
0210             name = walk_state->deferred_node->name.integer;
0211         }
0212 
0213         status = acpi_gbl_exception_handler(status, name,
0214                             walk_state->opcode,
0215                             aml_offset, NULL);
0216         acpi_ex_enter_interpreter();
0217     }
0218 
0219     acpi_ds_clear_implicit_return(walk_state);
0220 
0221     if (ACPI_FAILURE(status)) {
0222         acpi_ds_dump_method_stack(status, walk_state, walk_state->op);
0223 
0224         /* Display method locals/args if debugger is present */
0225 
0226 #ifdef ACPI_DEBUGGER
0227         acpi_db_dump_method_info(status, walk_state);
0228 #endif
0229     }
0230 
0231     return (status);
0232 }
0233 
0234 /*******************************************************************************
0235  *
0236  * FUNCTION:    acpi_ds_create_method_mutex
0237  *
0238  * PARAMETERS:  obj_desc            - The method object
0239  *
0240  * RETURN:      Status
0241  *
0242  * DESCRIPTION: Create a mutex object for a serialized control method
0243  *
0244  ******************************************************************************/
0245 
0246 static acpi_status
0247 acpi_ds_create_method_mutex(union acpi_operand_object *method_desc)
0248 {
0249     union acpi_operand_object *mutex_desc;
0250     acpi_status status;
0251 
0252     ACPI_FUNCTION_TRACE(ds_create_method_mutex);
0253 
0254     /* Create the new mutex object */
0255 
0256     mutex_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX);
0257     if (!mutex_desc) {
0258         return_ACPI_STATUS(AE_NO_MEMORY);
0259     }
0260 
0261     /* Create the actual OS Mutex */
0262 
0263     status = acpi_os_create_mutex(&mutex_desc->mutex.os_mutex);
0264     if (ACPI_FAILURE(status)) {
0265         acpi_ut_delete_object_desc(mutex_desc);
0266         return_ACPI_STATUS(status);
0267     }
0268 
0269     mutex_desc->mutex.sync_level = method_desc->method.sync_level;
0270     method_desc->method.mutex = mutex_desc;
0271     return_ACPI_STATUS(AE_OK);
0272 }
0273 
0274 /*******************************************************************************
0275  *
0276  * FUNCTION:    acpi_ds_begin_method_execution
0277  *
0278  * PARAMETERS:  method_node         - Node of the method
0279  *              obj_desc            - The method object
0280  *              walk_state          - current state, NULL if not yet executing
0281  *                                    a method.
0282  *
0283  * RETURN:      Status
0284  *
0285  * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
0286  *              increments the thread count, and waits at the method semaphore
0287  *              for clearance to execute.
0288  *
0289  ******************************************************************************/
0290 
0291 acpi_status
0292 acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
0293                    union acpi_operand_object *obj_desc,
0294                    struct acpi_walk_state *walk_state)
0295 {
0296     acpi_status status = AE_OK;
0297 
0298     ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node);
0299 
0300     if (!method_node) {
0301         return_ACPI_STATUS(AE_NULL_ENTRY);
0302     }
0303 
0304     acpi_ex_start_trace_method(method_node, obj_desc, walk_state);
0305 
0306     /* Prevent wraparound of thread count */
0307 
0308     if (obj_desc->method.thread_count == ACPI_UINT8_MAX) {
0309         ACPI_ERROR((AE_INFO,
0310                 "Method reached maximum reentrancy limit (255)"));
0311         return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
0312     }
0313 
0314     /*
0315      * If this method is serialized, we need to acquire the method mutex.
0316      */
0317     if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) {
0318         /*
0319          * Create a mutex for the method if it is defined to be Serialized
0320          * and a mutex has not already been created. We defer the mutex creation
0321          * until a method is actually executed, to minimize the object count
0322          */
0323         if (!obj_desc->method.mutex) {
0324             status = acpi_ds_create_method_mutex(obj_desc);
0325             if (ACPI_FAILURE(status)) {
0326                 return_ACPI_STATUS(status);
0327             }
0328         }
0329 
0330         /*
0331          * The current_sync_level (per-thread) must be less than or equal to
0332          * the sync level of the method. This mechanism provides some
0333          * deadlock prevention.
0334          *
0335          * If the method was auto-serialized, we just ignore the sync level
0336          * mechanism, because auto-serialization of methods can interfere
0337          * with ASL code that actually uses sync levels.
0338          *
0339          * Top-level method invocation has no walk state at this point
0340          */
0341         if (walk_state &&
0342             (!(obj_desc->method.
0343                info_flags & ACPI_METHOD_IGNORE_SYNC_LEVEL))
0344             && (walk_state->thread->current_sync_level >
0345             obj_desc->method.mutex->mutex.sync_level)) {
0346             ACPI_ERROR((AE_INFO,
0347                     "Cannot acquire Mutex for method [%4.4s]"
0348                     ", current SyncLevel is too large (%u)",
0349                     acpi_ut_get_node_name(method_node),
0350                     walk_state->thread->current_sync_level));
0351 
0352             return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
0353         }
0354 
0355         /*
0356          * Obtain the method mutex if necessary. Do not acquire mutex for a
0357          * recursive call.
0358          */
0359         if (!walk_state ||
0360             !obj_desc->method.mutex->mutex.thread_id ||
0361             (walk_state->thread->thread_id !=
0362              obj_desc->method.mutex->mutex.thread_id)) {
0363             /*
0364              * Acquire the method mutex. This releases the interpreter if we
0365              * block (and reacquires it before it returns)
0366              */
0367             status =
0368                 acpi_ex_system_wait_mutex(obj_desc->method.mutex->
0369                               mutex.os_mutex,
0370                               ACPI_WAIT_FOREVER);
0371             if (ACPI_FAILURE(status)) {
0372                 return_ACPI_STATUS(status);
0373             }
0374 
0375             /* Update the mutex and walk info and save the original sync_level */
0376 
0377             if (walk_state) {
0378                 obj_desc->method.mutex->mutex.
0379                     original_sync_level =
0380                     walk_state->thread->current_sync_level;
0381 
0382                 obj_desc->method.mutex->mutex.thread_id =
0383                     walk_state->thread->thread_id;
0384 
0385                 /*
0386                  * Update the current sync_level only if this is not an auto-
0387                  * serialized method. In the auto case, we have to ignore
0388                  * the sync level for the method mutex (created for the
0389                  * auto-serialization) because we have no idea of what the
0390                  * sync level should be. Therefore, just ignore it.
0391                  */
0392                 if (!(obj_desc->method.info_flags &
0393                       ACPI_METHOD_IGNORE_SYNC_LEVEL)) {
0394                     walk_state->thread->current_sync_level =
0395                         obj_desc->method.sync_level;
0396                 }
0397             } else {
0398                 obj_desc->method.mutex->mutex.
0399                     original_sync_level =
0400                     obj_desc->method.mutex->mutex.sync_level;
0401 
0402                 obj_desc->method.mutex->mutex.thread_id =
0403                     acpi_os_get_thread_id();
0404             }
0405         }
0406 
0407         /* Always increase acquisition depth */
0408 
0409         obj_desc->method.mutex->mutex.acquisition_depth++;
0410     }
0411 
0412     /*
0413      * Allocate an Owner ID for this method, only if this is the first thread
0414      * to begin concurrent execution. We only need one owner_id, even if the
0415      * method is invoked recursively.
0416      */
0417     if (!obj_desc->method.owner_id) {
0418         status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
0419         if (ACPI_FAILURE(status)) {
0420             goto cleanup;
0421         }
0422     }
0423 
0424     /*
0425      * Increment the method parse tree thread count since it has been
0426      * reentered one more time (even if it is the same thread)
0427      */
0428     obj_desc->method.thread_count++;
0429     acpi_method_count++;
0430     return_ACPI_STATUS(status);
0431 
0432 cleanup:
0433     /* On error, must release the method mutex (if present) */
0434 
0435     if (obj_desc->method.mutex) {
0436         acpi_os_release_mutex(obj_desc->method.mutex->mutex.os_mutex);
0437     }
0438     return_ACPI_STATUS(status);
0439 }
0440 
0441 /*******************************************************************************
0442  *
0443  * FUNCTION:    acpi_ds_call_control_method
0444  *
0445  * PARAMETERS:  thread              - Info for this thread
0446  *              this_walk_state     - Current walk state
0447  *              op                  - Current Op to be walked
0448  *
0449  * RETURN:      Status
0450  *
0451  * DESCRIPTION: Transfer execution to a called control method
0452  *
0453  ******************************************************************************/
0454 
0455 acpi_status
0456 acpi_ds_call_control_method(struct acpi_thread_state *thread,
0457                 struct acpi_walk_state *this_walk_state,
0458                 union acpi_parse_object *op)
0459 {
0460     acpi_status status;
0461     struct acpi_namespace_node *method_node;
0462     struct acpi_walk_state *next_walk_state = NULL;
0463     union acpi_operand_object *obj_desc;
0464     struct acpi_evaluate_info *info;
0465     u32 i;
0466 
0467     ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
0468 
0469     ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
0470               "Calling method %p, currentstate=%p\n",
0471               this_walk_state->prev_op, this_walk_state));
0472 
0473     /*
0474      * Get the namespace entry for the control method we are about to call
0475      */
0476     method_node = this_walk_state->method_call_node;
0477     if (!method_node) {
0478         return_ACPI_STATUS(AE_NULL_ENTRY);
0479     }
0480 
0481     obj_desc = acpi_ns_get_attached_object(method_node);
0482     if (!obj_desc) {
0483         return_ACPI_STATUS(AE_NULL_OBJECT);
0484     }
0485 
0486     /* Init for new method, possibly wait on method mutex */
0487 
0488     status =
0489         acpi_ds_begin_method_execution(method_node, obj_desc,
0490                        this_walk_state);
0491     if (ACPI_FAILURE(status)) {
0492         return_ACPI_STATUS(status);
0493     }
0494 
0495     /* Begin method parse/execution. Create a new walk state */
0496 
0497     next_walk_state =
0498         acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, obj_desc,
0499                       thread);
0500     if (!next_walk_state) {
0501         status = AE_NO_MEMORY;
0502         goto cleanup;
0503     }
0504 
0505     /*
0506      * The resolved arguments were put on the previous walk state's operand
0507      * stack. Operands on the previous walk state stack always
0508      * start at index 0. Also, null terminate the list of arguments
0509      */
0510     this_walk_state->operands[this_walk_state->num_operands] = NULL;
0511 
0512     /*
0513      * Allocate and initialize the evaluation information block
0514      * TBD: this is somewhat inefficient, should change interface to
0515      * ds_init_aml_walk. For now, keeps this struct off the CPU stack
0516      */
0517     info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
0518     if (!info) {
0519         status = AE_NO_MEMORY;
0520         goto cleanup;
0521     }
0522 
0523     info->parameters = &this_walk_state->operands[0];
0524 
0525     status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
0526                        obj_desc->method.aml_start,
0527                        obj_desc->method.aml_length, info,
0528                        ACPI_IMODE_EXECUTE);
0529 
0530     ACPI_FREE(info);
0531     if (ACPI_FAILURE(status)) {
0532         goto cleanup;
0533     }
0534 
0535     next_walk_state->method_nesting_depth =
0536         this_walk_state->method_nesting_depth + 1;
0537 
0538     /*
0539      * Delete the operands on the previous walkstate operand stack
0540      * (they were copied to new objects)
0541      */
0542     for (i = 0; i < obj_desc->method.param_count; i++) {
0543         acpi_ut_remove_reference(this_walk_state->operands[i]);
0544         this_walk_state->operands[i] = NULL;
0545     }
0546 
0547     /* Clear the operand stack */
0548 
0549     this_walk_state->num_operands = 0;
0550 
0551     ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
0552               "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
0553               method_node->name.ascii, next_walk_state));
0554 
0555     this_walk_state->method_pathname =
0556         acpi_ns_get_normalized_pathname(method_node, TRUE);
0557     this_walk_state->method_is_nested = TRUE;
0558 
0559     /* Optional object evaluation log */
0560 
0561     ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
0562                   "%-26s:  %*s%s\n", "   Nested method call",
0563                   next_walk_state->method_nesting_depth * 3, " ",
0564                   &this_walk_state->method_pathname[1]));
0565 
0566     /* Invoke an internal method if necessary */
0567 
0568     if (obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) {
0569         status =
0570             obj_desc->method.dispatch.implementation(next_walk_state);
0571         if (status == AE_OK) {
0572             status = AE_CTRL_TERMINATE;
0573         }
0574     }
0575 
0576     return_ACPI_STATUS(status);
0577 
0578 cleanup:
0579 
0580     /* On error, we must terminate the method properly */
0581 
0582     acpi_ds_terminate_control_method(obj_desc, next_walk_state);
0583     acpi_ds_delete_walk_state(next_walk_state);
0584 
0585     return_ACPI_STATUS(status);
0586 }
0587 
0588 /*******************************************************************************
0589  *
0590  * FUNCTION:    acpi_ds_restart_control_method
0591  *
0592  * PARAMETERS:  walk_state          - State for preempted method (caller)
0593  *              return_desc         - Return value from the called method
0594  *
0595  * RETURN:      Status
0596  *
0597  * DESCRIPTION: Restart a method that was preempted by another (nested) method
0598  *              invocation. Handle the return value (if any) from the callee.
0599  *
0600  ******************************************************************************/
0601 
0602 acpi_status
0603 acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
0604                    union acpi_operand_object *return_desc)
0605 {
0606     acpi_status status;
0607     int same_as_implicit_return;
0608 
0609     ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state);
0610 
0611     ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
0612               "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
0613               acpi_ut_get_node_name(walk_state->method_node),
0614               walk_state->method_call_op, return_desc));
0615 
0616     ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
0617               "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
0618               walk_state->return_used,
0619               walk_state->results, walk_state));
0620 
0621     /* Did the called method return a value? */
0622 
0623     if (return_desc) {
0624 
0625         /* Is the implicit return object the same as the return desc? */
0626 
0627         same_as_implicit_return =
0628             (walk_state->implicit_return_obj == return_desc);
0629 
0630         /* Are we actually going to use the return value? */
0631 
0632         if (walk_state->return_used) {
0633 
0634             /* Save the return value from the previous method */
0635 
0636             status = acpi_ds_result_push(return_desc, walk_state);
0637             if (ACPI_FAILURE(status)) {
0638                 acpi_ut_remove_reference(return_desc);
0639                 return_ACPI_STATUS(status);
0640             }
0641 
0642             /*
0643              * Save as THIS method's return value in case it is returned
0644              * immediately to yet another method
0645              */
0646             walk_state->return_desc = return_desc;
0647         }
0648 
0649         /*
0650          * The following code is the optional support for the so-called
0651          * "implicit return". Some AML code assumes that the last value of the
0652          * method is "implicitly" returned to the caller, in the absence of an
0653          * explicit return value.
0654          *
0655          * Just save the last result of the method as the return value.
0656          *
0657          * NOTE: this is optional because the ASL language does not actually
0658          * support this behavior.
0659          */
0660         else if (!acpi_ds_do_implicit_return
0661              (return_desc, walk_state, FALSE)
0662              || same_as_implicit_return) {
0663             /*
0664              * Delete the return value if it will not be used by the
0665              * calling method or remove one reference if the explicit return
0666              * is the same as the implicit return value.
0667              */
0668             acpi_ut_remove_reference(return_desc);
0669         }
0670     }
0671 
0672     return_ACPI_STATUS(AE_OK);
0673 }
0674 
0675 /*******************************************************************************
0676  *
0677  * FUNCTION:    acpi_ds_terminate_control_method
0678  *
0679  * PARAMETERS:  method_desc         - Method object
0680  *              walk_state          - State associated with the method
0681  *
0682  * RETURN:      None
0683  *
0684  * DESCRIPTION: Terminate a control method. Delete everything that the method
0685  *              created, delete all locals and arguments, and delete the parse
0686  *              tree if requested.
0687  *
0688  * MUTEX:       Interpreter is locked
0689  *
0690  ******************************************************************************/
0691 
0692 void
0693 acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
0694                  struct acpi_walk_state *walk_state)
0695 {
0696 
0697     ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state);
0698 
0699     /* method_desc is required, walk_state is optional */
0700 
0701     if (!method_desc) {
0702         return_VOID;
0703     }
0704 
0705     if (walk_state) {
0706 
0707         /* Delete all arguments and locals */
0708 
0709         acpi_ds_method_data_delete_all(walk_state);
0710 
0711         /*
0712          * Delete any namespace objects created anywhere within the
0713          * namespace by the execution of this method. Unless:
0714          * 1) This method is a module-level executable code method, in which
0715          *    case we want make the objects permanent.
0716          * 2) There are other threads executing the method, in which case we
0717          *    will wait until the last thread has completed.
0718          */
0719         if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL)
0720             && (method_desc->method.thread_count == 1)) {
0721 
0722             /* Delete any direct children of (created by) this method */
0723 
0724             (void)acpi_ex_exit_interpreter();
0725             acpi_ns_delete_namespace_subtree(walk_state->
0726                              method_node);
0727             (void)acpi_ex_enter_interpreter();
0728 
0729             /*
0730              * Delete any objects that were created by this method
0731              * elsewhere in the namespace (if any were created).
0732              * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
0733              * deletion such that we don't have to perform an entire
0734              * namespace walk for every control method execution.
0735              */
0736             if (method_desc->method.
0737                 info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) {
0738                 (void)acpi_ex_exit_interpreter();
0739                 acpi_ns_delete_namespace_by_owner(method_desc->
0740                                   method.
0741                                   owner_id);
0742                 (void)acpi_ex_enter_interpreter();
0743                 method_desc->method.info_flags &=
0744                     ~ACPI_METHOD_MODIFIED_NAMESPACE;
0745             }
0746         }
0747 
0748         /*
0749          * If method is serialized, release the mutex and restore the
0750          * current sync level for this thread
0751          */
0752         if (method_desc->method.mutex) {
0753 
0754             /* Acquisition Depth handles recursive calls */
0755 
0756             method_desc->method.mutex->mutex.acquisition_depth--;
0757             if (!method_desc->method.mutex->mutex.acquisition_depth) {
0758                 walk_state->thread->current_sync_level =
0759                     method_desc->method.mutex->mutex.
0760                     original_sync_level;
0761 
0762                 acpi_os_release_mutex(method_desc->method.
0763                               mutex->mutex.os_mutex);
0764                 method_desc->method.mutex->mutex.thread_id = 0;
0765             }
0766         }
0767     }
0768 
0769     /* Decrement the thread count on the method */
0770 
0771     if (method_desc->method.thread_count) {
0772         method_desc->method.thread_count--;
0773     } else {
0774         ACPI_ERROR((AE_INFO, "Invalid zero thread count in method"));
0775     }
0776 
0777     /* Are there any other threads currently executing this method? */
0778 
0779     if (method_desc->method.thread_count) {
0780         /*
0781          * Additional threads. Do not release the owner_id in this case,
0782          * we immediately reuse it for the next thread executing this method
0783          */
0784         ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
0785                   "*** Completed execution of one thread, %u threads remaining\n",
0786                   method_desc->method.thread_count));
0787     } else {
0788         /* This is the only executing thread for this method */
0789 
0790         /*
0791          * Support to dynamically change a method from not_serialized to
0792          * Serialized if it appears that the method is incorrectly written and
0793          * does not support multiple thread execution. The best example of this
0794          * is if such a method creates namespace objects and blocks. A second
0795          * thread will fail with an AE_ALREADY_EXISTS exception.
0796          *
0797          * This code is here because we must wait until the last thread exits
0798          * before marking the method as serialized.
0799          */
0800         if (method_desc->method.
0801             info_flags & ACPI_METHOD_SERIALIZED_PENDING) {
0802             if (walk_state) {
0803                 ACPI_INFO(("Marking method %4.4s as Serialized "
0804                        "because of AE_ALREADY_EXISTS error",
0805                        walk_state->method_node->name.
0806                        ascii));
0807             }
0808 
0809             /*
0810              * Method tried to create an object twice and was marked as
0811              * "pending serialized". The probable cause is that the method
0812              * cannot handle reentrancy.
0813              *
0814              * The method was created as not_serialized, but it tried to create
0815              * a named object and then blocked, causing the second thread
0816              * entrance to begin and then fail. Workaround this problem by
0817              * marking the method permanently as Serialized when the last
0818              * thread exits here.
0819              */
0820             method_desc->method.info_flags &=
0821                 ~ACPI_METHOD_SERIALIZED_PENDING;
0822 
0823             method_desc->method.info_flags |=
0824                 (ACPI_METHOD_SERIALIZED |
0825                  ACPI_METHOD_IGNORE_SYNC_LEVEL);
0826             method_desc->method.sync_level = 0;
0827         }
0828 
0829         /* No more threads, we can free the owner_id */
0830 
0831         if (!
0832             (method_desc->method.
0833              info_flags & ACPI_METHOD_MODULE_LEVEL)) {
0834             acpi_ut_release_owner_id(&method_desc->method.owner_id);
0835         }
0836     }
0837 
0838     acpi_ex_stop_trace_method((struct acpi_namespace_node *)method_desc->
0839                   method.node, method_desc, walk_state);
0840 
0841     return_VOID;
0842 }