162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: psxface - Parser external interfaces 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "acparser.h" 1362306a36Sopenharmony_ci#include "acdispat.h" 1462306a36Sopenharmony_ci#include "acinterp.h" 1562306a36Sopenharmony_ci#include "actables.h" 1662306a36Sopenharmony_ci#include "acnamesp.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define _COMPONENT ACPI_PARSER 1962306a36Sopenharmony_ciACPI_MODULE_NAME("psxface") 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* Local Prototypes */ 2262306a36Sopenharmony_cistatic void 2362306a36Sopenharmony_ciacpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/******************************************************************************* 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * FUNCTION: acpi_debug_trace 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * PARAMETERS: method_name - Valid ACPI name string 3062306a36Sopenharmony_ci * debug_level - Optional level mask. 0 to use default 3162306a36Sopenharmony_ci * debug_layer - Optional layer mask. 0 to use default 3262306a36Sopenharmony_ci * flags - bit 1: one shot(1) or persistent(0) 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * RETURN: Status 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * DESCRIPTION: External interface to enable debug tracing during control 3762306a36Sopenharmony_ci * method execution 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci ******************************************************************************/ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciacpi_status 4262306a36Sopenharmony_ciacpi_debug_trace(const char *name, u32 debug_level, u32 debug_layer, u32 flags) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci acpi_status status; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 4762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 4862306a36Sopenharmony_ci return (status); 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci acpi_gbl_trace_method_name = name; 5262306a36Sopenharmony_ci acpi_gbl_trace_flags = flags; 5362306a36Sopenharmony_ci acpi_gbl_trace_dbg_level = debug_level; 5462306a36Sopenharmony_ci acpi_gbl_trace_dbg_layer = debug_layer; 5562306a36Sopenharmony_ci status = AE_OK; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 5862306a36Sopenharmony_ci return (status); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/******************************************************************************* 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * FUNCTION: acpi_ps_execute_method 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * PARAMETERS: info - Method info block, contains: 6662306a36Sopenharmony_ci * node - Method Node to execute 6762306a36Sopenharmony_ci * obj_desc - Method object 6862306a36Sopenharmony_ci * parameters - List of parameters to pass to the method, 6962306a36Sopenharmony_ci * terminated by NULL. Params itself may be 7062306a36Sopenharmony_ci * NULL if no parameters are being passed. 7162306a36Sopenharmony_ci * return_object - Where to put method's return value (if 7262306a36Sopenharmony_ci * any). If NULL, no value is returned. 7362306a36Sopenharmony_ci * parameter_type - Type of Parameter list 7462306a36Sopenharmony_ci * return_object - Where to put method's return value (if 7562306a36Sopenharmony_ci * any). If NULL, no value is returned. 7662306a36Sopenharmony_ci * pass_number - Parse or execute pass 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * RETURN: Status 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * DESCRIPTION: Execute a control method 8162306a36Sopenharmony_ci * 8262306a36Sopenharmony_ci ******************************************************************************/ 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciacpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci acpi_status status; 8762306a36Sopenharmony_ci union acpi_parse_object *op; 8862306a36Sopenharmony_ci struct acpi_walk_state *walk_state; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ps_execute_method); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* Quick validation of DSDT header */ 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci acpi_tb_check_dsdt_header(); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* Validate the Info and method Node */ 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (!info || !info->node) { 9962306a36Sopenharmony_ci return_ACPI_STATUS(AE_NULL_ENTRY); 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* Init for new method, wait on concurrency semaphore */ 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci status = 10562306a36Sopenharmony_ci acpi_ds_begin_method_execution(info->node, info->obj_desc, NULL); 10662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 10762306a36Sopenharmony_ci return_ACPI_STATUS(status); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* 11162306a36Sopenharmony_ci * The caller "owns" the parameters, so give each one an extra reference 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci acpi_ps_update_parameter_list(info, REF_INCREMENT); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * Execute the method. Performs parse simultaneously 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_PARSE, 11962306a36Sopenharmony_ci "**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n", 12062306a36Sopenharmony_ci info->node->name.ascii, info->node, info->obj_desc)); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* Create and init a Root Node */ 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci op = acpi_ps_create_scope_op(info->obj_desc->method.aml_start); 12562306a36Sopenharmony_ci if (!op) { 12662306a36Sopenharmony_ci status = AE_NO_MEMORY; 12762306a36Sopenharmony_ci goto cleanup; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Create and initialize a new walk state */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci info->pass_number = ACPI_IMODE_EXECUTE; 13362306a36Sopenharmony_ci walk_state = 13462306a36Sopenharmony_ci acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL, 13562306a36Sopenharmony_ci NULL, NULL); 13662306a36Sopenharmony_ci if (!walk_state) { 13762306a36Sopenharmony_ci status = AE_NO_MEMORY; 13862306a36Sopenharmony_ci goto cleanup; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci status = acpi_ds_init_aml_walk(walk_state, op, info->node, 14262306a36Sopenharmony_ci info->obj_desc->method.aml_start, 14362306a36Sopenharmony_ci info->obj_desc->method.aml_length, info, 14462306a36Sopenharmony_ci info->pass_number); 14562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 14662306a36Sopenharmony_ci acpi_ds_delete_walk_state(walk_state); 14762306a36Sopenharmony_ci goto cleanup; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci walk_state->method_pathname = info->full_pathname; 15162306a36Sopenharmony_ci walk_state->method_is_nested = FALSE; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (info->obj_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) { 15462306a36Sopenharmony_ci walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Invoke an internal method if necessary */ 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (info->obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) { 16062306a36Sopenharmony_ci status = 16162306a36Sopenharmony_ci info->obj_desc->method.dispatch.implementation(walk_state); 16262306a36Sopenharmony_ci info->return_object = walk_state->return_desc; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Cleanup states */ 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci acpi_ds_scope_stack_clear(walk_state); 16762306a36Sopenharmony_ci acpi_ps_cleanup_scope(&walk_state->parser_state); 16862306a36Sopenharmony_ci acpi_ds_terminate_control_method(walk_state->method_desc, 16962306a36Sopenharmony_ci walk_state); 17062306a36Sopenharmony_ci acpi_ds_delete_walk_state(walk_state); 17162306a36Sopenharmony_ci goto cleanup; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* 17562306a36Sopenharmony_ci * Start method evaluation with an implicit return of zero. 17662306a36Sopenharmony_ci * This is done for Windows compatibility. 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci if (acpi_gbl_enable_interpreter_slack) { 17962306a36Sopenharmony_ci walk_state->implicit_return_obj = 18062306a36Sopenharmony_ci acpi_ut_create_integer_object((u64) 0); 18162306a36Sopenharmony_ci if (!walk_state->implicit_return_obj) { 18262306a36Sopenharmony_ci status = AE_NO_MEMORY; 18362306a36Sopenharmony_ci acpi_ds_delete_walk_state(walk_state); 18462306a36Sopenharmony_ci goto cleanup; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* Parse the AML */ 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci status = acpi_ps_parse_aml(walk_state); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* walk_state was deleted by parse_aml */ 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cicleanup: 19562306a36Sopenharmony_ci acpi_ps_delete_parse_tree(op); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* Take away the extra reference that we gave the parameters above */ 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci acpi_ps_update_parameter_list(info, REF_DECREMENT); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* Exit now if error above */ 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 20462306a36Sopenharmony_ci return_ACPI_STATUS(status); 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* 20862306a36Sopenharmony_ci * If the method has returned an object, signal this to the caller with 20962306a36Sopenharmony_ci * a control exception code 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci if (info->return_object) { 21262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Method returned ObjDesc=%p\n", 21362306a36Sopenharmony_ci info->return_object)); 21462306a36Sopenharmony_ci ACPI_DUMP_STACK_ENTRY(info->return_object); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci status = AE_CTRL_RETURN_VALUE; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return_ACPI_STATUS(status); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/******************************************************************************* 22362306a36Sopenharmony_ci * 22462306a36Sopenharmony_ci * FUNCTION: acpi_ps_execute_table 22562306a36Sopenharmony_ci * 22662306a36Sopenharmony_ci * PARAMETERS: info - Method info block, contains: 22762306a36Sopenharmony_ci * node - Node to where the is entered into the 22862306a36Sopenharmony_ci * namespace 22962306a36Sopenharmony_ci * obj_desc - Pseudo method object describing the AML 23062306a36Sopenharmony_ci * code of the entire table 23162306a36Sopenharmony_ci * pass_number - Parse or execute pass 23262306a36Sopenharmony_ci * 23362306a36Sopenharmony_ci * RETURN: Status 23462306a36Sopenharmony_ci * 23562306a36Sopenharmony_ci * DESCRIPTION: Execute a table 23662306a36Sopenharmony_ci * 23762306a36Sopenharmony_ci ******************************************************************************/ 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ciacpi_status acpi_ps_execute_table(struct acpi_evaluate_info *info) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci acpi_status status; 24262306a36Sopenharmony_ci union acpi_parse_object *op = NULL; 24362306a36Sopenharmony_ci struct acpi_walk_state *walk_state = NULL; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ps_execute_table); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* Create and init a Root Node */ 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci op = acpi_ps_create_scope_op(info->obj_desc->method.aml_start); 25062306a36Sopenharmony_ci if (!op) { 25162306a36Sopenharmony_ci status = AE_NO_MEMORY; 25262306a36Sopenharmony_ci goto cleanup; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Create and initialize a new walk state */ 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci walk_state = 25862306a36Sopenharmony_ci acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL, 25962306a36Sopenharmony_ci NULL, NULL); 26062306a36Sopenharmony_ci if (!walk_state) { 26162306a36Sopenharmony_ci status = AE_NO_MEMORY; 26262306a36Sopenharmony_ci goto cleanup; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci status = acpi_ds_init_aml_walk(walk_state, op, info->node, 26662306a36Sopenharmony_ci info->obj_desc->method.aml_start, 26762306a36Sopenharmony_ci info->obj_desc->method.aml_length, info, 26862306a36Sopenharmony_ci info->pass_number); 26962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 27062306a36Sopenharmony_ci goto cleanup; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci walk_state->method_pathname = info->full_pathname; 27462306a36Sopenharmony_ci walk_state->method_is_nested = FALSE; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (info->obj_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) { 27762306a36Sopenharmony_ci walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* Info->Node is the default location to load the table */ 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (info->node && info->node != acpi_gbl_root_node) { 28362306a36Sopenharmony_ci status = 28462306a36Sopenharmony_ci acpi_ds_scope_stack_push(info->node, ACPI_TYPE_METHOD, 28562306a36Sopenharmony_ci walk_state); 28662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 28762306a36Sopenharmony_ci goto cleanup; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* 29262306a36Sopenharmony_ci * Parse the AML, walk_state will be deleted by parse_aml 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci acpi_ex_enter_interpreter(); 29562306a36Sopenharmony_ci status = acpi_ps_parse_aml(walk_state); 29662306a36Sopenharmony_ci acpi_ex_exit_interpreter(); 29762306a36Sopenharmony_ci walk_state = NULL; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cicleanup: 30062306a36Sopenharmony_ci if (walk_state) { 30162306a36Sopenharmony_ci acpi_ds_delete_walk_state(walk_state); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci if (op) { 30462306a36Sopenharmony_ci acpi_ps_delete_parse_tree(op); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci return_ACPI_STATUS(status); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci/******************************************************************************* 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci * FUNCTION: acpi_ps_update_parameter_list 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * PARAMETERS: info - See struct acpi_evaluate_info 31462306a36Sopenharmony_ci * (Used: parameter_type and Parameters) 31562306a36Sopenharmony_ci * action - Add or Remove reference 31662306a36Sopenharmony_ci * 31762306a36Sopenharmony_ci * RETURN: Status 31862306a36Sopenharmony_ci * 31962306a36Sopenharmony_ci * DESCRIPTION: Update reference count on all method parameter objects 32062306a36Sopenharmony_ci * 32162306a36Sopenharmony_ci ******************************************************************************/ 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void 32462306a36Sopenharmony_ciacpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci u32 i; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (info->parameters) { 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Update reference count for each parameter */ 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci for (i = 0; info->parameters[i]; i++) { 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* Ignore errors, just do them all */ 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci (void)acpi_ut_update_object_reference(info-> 33762306a36Sopenharmony_ci parameters[i], 33862306a36Sopenharmony_ci action); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci} 342