162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: nsinit - namespace initialization 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 "acnamesp.h" 1362306a36Sopenharmony_ci#include "acdispat.h" 1462306a36Sopenharmony_ci#include "acinterp.h" 1562306a36Sopenharmony_ci#include "acevents.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define _COMPONENT ACPI_NAMESPACE 1862306a36Sopenharmony_ciACPI_MODULE_NAME("nsinit") 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* Local prototypes */ 2162306a36Sopenharmony_cistatic acpi_status 2262306a36Sopenharmony_ciacpi_ns_init_one_object(acpi_handle obj_handle, 2362306a36Sopenharmony_ci u32 level, void *context, void **return_value); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic acpi_status 2662306a36Sopenharmony_ciacpi_ns_init_one_device(acpi_handle obj_handle, 2762306a36Sopenharmony_ci u32 nesting_level, void *context, void **return_value); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic acpi_status 3062306a36Sopenharmony_ciacpi_ns_find_ini_methods(acpi_handle obj_handle, 3162306a36Sopenharmony_ci u32 nesting_level, void *context, void **return_value); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/******************************************************************************* 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * FUNCTION: acpi_ns_initialize_objects 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * PARAMETERS: None 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * RETURN: Status 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * DESCRIPTION: Walk the entire namespace and perform any necessary 4262306a36Sopenharmony_ci * initialization on the objects found therein 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci ******************************************************************************/ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ciacpi_status acpi_ns_initialize_objects(void) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci acpi_status status; 4962306a36Sopenharmony_ci struct acpi_init_walk_info info; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_initialize_objects); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 5462306a36Sopenharmony_ci "[Init] Completing Initialization of ACPI Objects\n")); 5562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, 5662306a36Sopenharmony_ci "**** Starting initialization of namespace objects ****\n")); 5762306a36Sopenharmony_ci ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, 5862306a36Sopenharmony_ci "Final data object initialization: ")); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* Clear the info block */ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci memset(&info, 0, sizeof(struct acpi_init_walk_info)); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* Walk entire namespace from the supplied root */ 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* 6762306a36Sopenharmony_ci * TBD: will become ACPI_TYPE_PACKAGE as this type object 6862306a36Sopenharmony_ci * is now the only one that supports deferred initialization 6962306a36Sopenharmony_ci * (forward references). 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_ci status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 7262306a36Sopenharmony_ci ACPI_UINT32_MAX, acpi_ns_init_one_object, 7362306a36Sopenharmony_ci NULL, &info, NULL); 7462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 7562306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, 7962306a36Sopenharmony_ci "Namespace contains %u (0x%X) objects\n", 8062306a36Sopenharmony_ci info.object_count, info.object_count)); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, 8362306a36Sopenharmony_ci "%u Control Methods found\n%u Op Regions found\n", 8462306a36Sopenharmony_ci info.method_count, info.op_region_count)); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/******************************************************************************* 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * FUNCTION: acpi_ns_initialize_devices 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * PARAMETERS: None 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * RETURN: acpi_status 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * DESCRIPTION: Walk the entire namespace and initialize all ACPI devices. 9862306a36Sopenharmony_ci * This means running _INI on all present devices. 9962306a36Sopenharmony_ci * 10062306a36Sopenharmony_ci * Note: We install PCI config space handler on region access, 10162306a36Sopenharmony_ci * not here. 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci ******************************************************************************/ 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ciacpi_status acpi_ns_initialize_devices(u32 flags) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci acpi_status status = AE_OK; 10862306a36Sopenharmony_ci struct acpi_device_walk_info info; 10962306a36Sopenharmony_ci acpi_handle handle; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_initialize_devices); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (!(flags & ACPI_NO_DEVICE_INIT)) { 11462306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 11562306a36Sopenharmony_ci "[Init] Initializing ACPI Devices\n")); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* Init counters */ 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci info.device_count = 0; 12062306a36Sopenharmony_ci info.num_STA = 0; 12162306a36Sopenharmony_ci info.num_INI = 0; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, 12462306a36Sopenharmony_ci "Initializing Device/Processor/Thermal objects " 12562306a36Sopenharmony_ci "and executing _INI/_STA methods:\n")); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* Tree analysis: find all subtrees that contain _INI methods */ 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 13062306a36Sopenharmony_ci ACPI_UINT32_MAX, FALSE, 13162306a36Sopenharmony_ci acpi_ns_find_ini_methods, NULL, 13262306a36Sopenharmony_ci &info, NULL); 13362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 13462306a36Sopenharmony_ci goto error_exit; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Allocate the evaluation information block */ 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci info.evaluate_info = 14062306a36Sopenharmony_ci ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); 14162306a36Sopenharmony_ci if (!info.evaluate_info) { 14262306a36Sopenharmony_ci status = AE_NO_MEMORY; 14362306a36Sopenharmony_ci goto error_exit; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * Execute the "global" _INI method that may appear at the root. 14862306a36Sopenharmony_ci * This support is provided for Windows compatibility (Vista+) and 14962306a36Sopenharmony_ci * is not part of the ACPI specification. 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_ci info.evaluate_info->prefix_node = acpi_gbl_root_node; 15262306a36Sopenharmony_ci info.evaluate_info->relative_pathname = METHOD_NAME__INI; 15362306a36Sopenharmony_ci info.evaluate_info->parameters = NULL; 15462306a36Sopenharmony_ci info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci status = acpi_ns_evaluate(info.evaluate_info); 15762306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 15862306a36Sopenharmony_ci info.num_INI++; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* 16262306a36Sopenharmony_ci * Execute \_SB._INI. 16362306a36Sopenharmony_ci * There appears to be a strict order requirement for \_SB._INI, 16462306a36Sopenharmony_ci * which should be evaluated before any _REG evaluations. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci status = acpi_get_handle(NULL, "\\_SB", &handle); 16762306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 16862306a36Sopenharmony_ci memset(info.evaluate_info, 0, 16962306a36Sopenharmony_ci sizeof(struct acpi_evaluate_info)); 17062306a36Sopenharmony_ci info.evaluate_info->prefix_node = handle; 17162306a36Sopenharmony_ci info.evaluate_info->relative_pathname = 17262306a36Sopenharmony_ci METHOD_NAME__INI; 17362306a36Sopenharmony_ci info.evaluate_info->parameters = NULL; 17462306a36Sopenharmony_ci info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci status = acpi_ns_evaluate(info.evaluate_info); 17762306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 17862306a36Sopenharmony_ci info.num_INI++; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* 18462306a36Sopenharmony_ci * Run all _REG methods 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * Note: Any objects accessed by the _REG methods will be automatically 18762306a36Sopenharmony_ci * initialized, even if they contain executable AML (see the call to 18862306a36Sopenharmony_ci * acpi_ns_initialize_objects below). 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * Note: According to the ACPI specification, we actually needn't execute 19162306a36Sopenharmony_ci * _REG for system_memory/system_io operation regions, but for PCI_Config 19262306a36Sopenharmony_ci * operation regions, it is required to evaluate _REG for those on a PCI 19362306a36Sopenharmony_ci * root bus that doesn't contain _BBN object. So this code is kept here 19462306a36Sopenharmony_ci * in order not to break things. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_ci if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) { 19762306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 19862306a36Sopenharmony_ci "[Init] Executing _REG OpRegion methods\n")); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci status = acpi_ev_initialize_op_regions(); 20162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 20262306a36Sopenharmony_ci goto error_exit; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (!(flags & ACPI_NO_DEVICE_INIT)) { 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Walk namespace to execute all _INIs on present devices */ 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 21162306a36Sopenharmony_ci ACPI_UINT32_MAX, FALSE, 21262306a36Sopenharmony_ci acpi_ns_init_one_device, NULL, 21362306a36Sopenharmony_ci &info, NULL); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* 21662306a36Sopenharmony_ci * Any _OSI requests should be completed by now. If the BIOS has 21762306a36Sopenharmony_ci * requested any Windows OSI strings, we will always truncate 21862306a36Sopenharmony_ci * I/O addresses to 16 bits -- for Windows compatibility. 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_ci if (acpi_gbl_osi_data >= ACPI_OSI_WIN_2000) { 22162306a36Sopenharmony_ci acpi_gbl_truncate_io_addresses = TRUE; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci ACPI_FREE(info.evaluate_info); 22562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 22662306a36Sopenharmony_ci goto error_exit; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, 23062306a36Sopenharmony_ci " Executed %u _INI methods requiring %u _STA executions " 23162306a36Sopenharmony_ci "(examined %u objects)\n", 23262306a36Sopenharmony_ci info.num_INI, info.num_STA, 23362306a36Sopenharmony_ci info.device_count)); 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return_ACPI_STATUS(status); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cierror_exit: 23962306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, "During device initialization")); 24062306a36Sopenharmony_ci return_ACPI_STATUS(status); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/******************************************************************************* 24462306a36Sopenharmony_ci * 24562306a36Sopenharmony_ci * FUNCTION: acpi_ns_init_one_package 24662306a36Sopenharmony_ci * 24762306a36Sopenharmony_ci * PARAMETERS: obj_handle - Node 24862306a36Sopenharmony_ci * level - Current nesting level 24962306a36Sopenharmony_ci * context - Not used 25062306a36Sopenharmony_ci * return_value - Not used 25162306a36Sopenharmony_ci * 25262306a36Sopenharmony_ci * RETURN: Status 25362306a36Sopenharmony_ci * 25462306a36Sopenharmony_ci * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every package 25562306a36Sopenharmony_ci * within the namespace. Used during dynamic load of an SSDT. 25662306a36Sopenharmony_ci * 25762306a36Sopenharmony_ci ******************************************************************************/ 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ciacpi_status 26062306a36Sopenharmony_ciacpi_ns_init_one_package(acpi_handle obj_handle, 26162306a36Sopenharmony_ci u32 level, void *context, void **return_value) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci acpi_status status; 26462306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 26562306a36Sopenharmony_ci struct acpi_namespace_node *node = 26662306a36Sopenharmony_ci (struct acpi_namespace_node *)obj_handle; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci obj_desc = acpi_ns_get_attached_object(node); 26962306a36Sopenharmony_ci if (!obj_desc) { 27062306a36Sopenharmony_ci return (AE_OK); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* Exit if package is already initialized */ 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (obj_desc->package.flags & AOPOBJ_DATA_VALID) { 27662306a36Sopenharmony_ci return (AE_OK); 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci status = acpi_ds_get_package_arguments(obj_desc); 28062306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 28162306a36Sopenharmony_ci return (AE_OK); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci status = 28562306a36Sopenharmony_ci acpi_ut_walk_package_tree(obj_desc, NULL, 28662306a36Sopenharmony_ci acpi_ds_init_package_element, NULL); 28762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 28862306a36Sopenharmony_ci return (AE_OK); 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci obj_desc->package.flags |= AOPOBJ_DATA_VALID; 29262306a36Sopenharmony_ci return (AE_OK); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/******************************************************************************* 29662306a36Sopenharmony_ci * 29762306a36Sopenharmony_ci * FUNCTION: acpi_ns_init_one_object 29862306a36Sopenharmony_ci * 29962306a36Sopenharmony_ci * PARAMETERS: obj_handle - Node 30062306a36Sopenharmony_ci * level - Current nesting level 30162306a36Sopenharmony_ci * context - Points to a init info struct 30262306a36Sopenharmony_ci * return_value - Not used 30362306a36Sopenharmony_ci * 30462306a36Sopenharmony_ci * RETURN: Status 30562306a36Sopenharmony_ci * 30662306a36Sopenharmony_ci * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object 30762306a36Sopenharmony_ci * within the namespace. 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * Currently, the only objects that require initialization are: 31062306a36Sopenharmony_ci * 1) Methods 31162306a36Sopenharmony_ci * 2) Op Regions 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci ******************************************************************************/ 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic acpi_status 31662306a36Sopenharmony_ciacpi_ns_init_one_object(acpi_handle obj_handle, 31762306a36Sopenharmony_ci u32 level, void *context, void **return_value) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci acpi_object_type type; 32062306a36Sopenharmony_ci acpi_status status = AE_OK; 32162306a36Sopenharmony_ci struct acpi_init_walk_info *info = 32262306a36Sopenharmony_ci (struct acpi_init_walk_info *)context; 32362306a36Sopenharmony_ci struct acpi_namespace_node *node = 32462306a36Sopenharmony_ci (struct acpi_namespace_node *)obj_handle; 32562306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci ACPI_FUNCTION_NAME(ns_init_one_object); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci info->object_count++; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* And even then, we are only interested in a few object types */ 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci type = acpi_ns_get_type(obj_handle); 33462306a36Sopenharmony_ci obj_desc = acpi_ns_get_attached_object(node); 33562306a36Sopenharmony_ci if (!obj_desc) { 33662306a36Sopenharmony_ci return (AE_OK); 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* Increment counters for object types we are looking for */ 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci switch (type) { 34262306a36Sopenharmony_ci case ACPI_TYPE_REGION: 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci info->op_region_count++; 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci case ACPI_TYPE_BUFFER_FIELD: 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci info->field_count++; 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci case ACPI_TYPE_LOCAL_BANK_FIELD: 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci info->field_count++; 35562306a36Sopenharmony_ci break; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci case ACPI_TYPE_BUFFER: 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci info->buffer_count++; 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci case ACPI_TYPE_PACKAGE: 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci info->package_count++; 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci default: 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* No init required, just exit now */ 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return (AE_OK); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* If the object is already initialized, nothing else to do */ 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { 37762306a36Sopenharmony_ci return (AE_OK); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* Must lock the interpreter before executing AML code */ 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci acpi_ex_enter_interpreter(); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* 38562306a36Sopenharmony_ci * Only initialization of Package objects can be deferred, in order 38662306a36Sopenharmony_ci * to support forward references. 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_ci switch (type) { 38962306a36Sopenharmony_ci case ACPI_TYPE_LOCAL_BANK_FIELD: 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* TBD: bank_fields do not require deferred init, remove this code */ 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci info->field_init++; 39462306a36Sopenharmony_ci status = acpi_ds_get_bank_field_arguments(obj_desc); 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci case ACPI_TYPE_PACKAGE: 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* Complete the initialization/resolution of the package object */ 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci info->package_init++; 40262306a36Sopenharmony_ci status = 40362306a36Sopenharmony_ci acpi_ns_init_one_package(obj_handle, level, NULL, NULL); 40462306a36Sopenharmony_ci break; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci default: 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* No other types should get here */ 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci status = AE_TYPE; 41162306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 41262306a36Sopenharmony_ci "Opcode is not deferred [%4.4s] (%s)", 41362306a36Sopenharmony_ci acpi_ut_get_node_name(node), 41462306a36Sopenharmony_ci acpi_ut_get_type_name(type))); 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 41962306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 42062306a36Sopenharmony_ci "Could not execute arguments for [%4.4s] (%s)", 42162306a36Sopenharmony_ci acpi_ut_get_node_name(node), 42262306a36Sopenharmony_ci acpi_ut_get_type_name(type))); 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* 42662306a36Sopenharmony_ci * We ignore errors from above, and always return OK, since we don't want 42762306a36Sopenharmony_ci * to abort the walk on any single error. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_ci acpi_ex_exit_interpreter(); 43062306a36Sopenharmony_ci return (AE_OK); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci/******************************************************************************* 43462306a36Sopenharmony_ci * 43562306a36Sopenharmony_ci * FUNCTION: acpi_ns_find_ini_methods 43662306a36Sopenharmony_ci * 43762306a36Sopenharmony_ci * PARAMETERS: acpi_walk_callback 43862306a36Sopenharmony_ci * 43962306a36Sopenharmony_ci * RETURN: acpi_status 44062306a36Sopenharmony_ci * 44162306a36Sopenharmony_ci * DESCRIPTION: Called during namespace walk. Finds objects named _INI under 44262306a36Sopenharmony_ci * device/processor/thermal objects, and marks the entire subtree 44362306a36Sopenharmony_ci * with a SUBTREE_HAS_INI flag. This flag is used during the 44462306a36Sopenharmony_ci * subsequent device initialization walk to avoid entire subtrees 44562306a36Sopenharmony_ci * that do not contain an _INI. 44662306a36Sopenharmony_ci * 44762306a36Sopenharmony_ci ******************************************************************************/ 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic acpi_status 45062306a36Sopenharmony_ciacpi_ns_find_ini_methods(acpi_handle obj_handle, 45162306a36Sopenharmony_ci u32 nesting_level, void *context, void **return_value) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct acpi_device_walk_info *info = 45462306a36Sopenharmony_ci ACPI_CAST_PTR(struct acpi_device_walk_info, context); 45562306a36Sopenharmony_ci struct acpi_namespace_node *node; 45662306a36Sopenharmony_ci struct acpi_namespace_node *parent_node; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* Keep count of device/processor/thermal objects */ 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); 46162306a36Sopenharmony_ci if ((node->type == ACPI_TYPE_DEVICE) || 46262306a36Sopenharmony_ci (node->type == ACPI_TYPE_PROCESSOR) || 46362306a36Sopenharmony_ci (node->type == ACPI_TYPE_THERMAL)) { 46462306a36Sopenharmony_ci info->device_count++; 46562306a36Sopenharmony_ci return (AE_OK); 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* We are only looking for methods named _INI */ 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (!ACPI_COMPARE_NAMESEG(node->name.ascii, METHOD_NAME__INI)) { 47162306a36Sopenharmony_ci return (AE_OK); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* 47562306a36Sopenharmony_ci * The only _INI methods that we care about are those that are 47662306a36Sopenharmony_ci * present under Device, Processor, and Thermal objects. 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_ci parent_node = node->parent; 47962306a36Sopenharmony_ci switch (parent_node->type) { 48062306a36Sopenharmony_ci case ACPI_TYPE_DEVICE: 48162306a36Sopenharmony_ci case ACPI_TYPE_PROCESSOR: 48262306a36Sopenharmony_ci case ACPI_TYPE_THERMAL: 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* Mark parent and bubble up the INI present flag to the root */ 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci while (parent_node) { 48762306a36Sopenharmony_ci parent_node->flags |= ANOBJ_SUBTREE_HAS_INI; 48862306a36Sopenharmony_ci parent_node = parent_node->parent; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci default: 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return (AE_OK); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci/******************************************************************************* 50162306a36Sopenharmony_ci * 50262306a36Sopenharmony_ci * FUNCTION: acpi_ns_init_one_device 50362306a36Sopenharmony_ci * 50462306a36Sopenharmony_ci * PARAMETERS: acpi_walk_callback 50562306a36Sopenharmony_ci * 50662306a36Sopenharmony_ci * RETURN: acpi_status 50762306a36Sopenharmony_ci * 50862306a36Sopenharmony_ci * DESCRIPTION: This is called once per device soon after ACPI is enabled 50962306a36Sopenharmony_ci * to initialize each device. It determines if the device is 51062306a36Sopenharmony_ci * present, and if so, calls _INI. 51162306a36Sopenharmony_ci * 51262306a36Sopenharmony_ci ******************************************************************************/ 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic acpi_status 51562306a36Sopenharmony_ciacpi_ns_init_one_device(acpi_handle obj_handle, 51662306a36Sopenharmony_ci u32 nesting_level, void *context, void **return_value) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci struct acpi_device_walk_info *walk_info = 51962306a36Sopenharmony_ci ACPI_CAST_PTR(struct acpi_device_walk_info, context); 52062306a36Sopenharmony_ci struct acpi_evaluate_info *info = walk_info->evaluate_info; 52162306a36Sopenharmony_ci u32 flags; 52262306a36Sopenharmony_ci acpi_status status; 52362306a36Sopenharmony_ci struct acpi_namespace_node *device_node; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_init_one_device); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* We are interested in Devices, Processors and thermal_zones only */ 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci device_node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); 53062306a36Sopenharmony_ci if ((device_node->type != ACPI_TYPE_DEVICE) && 53162306a36Sopenharmony_ci (device_node->type != ACPI_TYPE_PROCESSOR) && 53262306a36Sopenharmony_ci (device_node->type != ACPI_TYPE_THERMAL)) { 53362306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* 53762306a36Sopenharmony_ci * Because of an earlier namespace analysis, all subtrees that contain an 53862306a36Sopenharmony_ci * _INI method are tagged. 53962306a36Sopenharmony_ci * 54062306a36Sopenharmony_ci * If this device subtree does not contain any _INI methods, we 54162306a36Sopenharmony_ci * can exit now and stop traversing this entire subtree. 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_ci if (!(device_node->flags & ANOBJ_SUBTREE_HAS_INI)) { 54462306a36Sopenharmony_ci return_ACPI_STATUS(AE_CTRL_DEPTH); 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* 54862306a36Sopenharmony_ci * Run _STA to determine if this device is present and functioning. We 54962306a36Sopenharmony_ci * must know this information for two important reasons (from ACPI spec): 55062306a36Sopenharmony_ci * 55162306a36Sopenharmony_ci * 1) We can only run _INI if the device is present. 55262306a36Sopenharmony_ci * 2) We must abort the device tree walk on this subtree if the device is 55362306a36Sopenharmony_ci * not present and is not functional (we will not examine the children) 55462306a36Sopenharmony_ci * 55562306a36Sopenharmony_ci * The _STA method is not required to be present under the device, we 55662306a36Sopenharmony_ci * assume the device is present if _STA does not exist. 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_ci ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname 55962306a36Sopenharmony_ci (ACPI_TYPE_METHOD, device_node, METHOD_NAME__STA)); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci status = acpi_ut_execute_STA(device_node, &flags); 56262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* Ignore error and move on to next device */ 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* 57062306a36Sopenharmony_ci * Flags == -1 means that _STA was not found. In this case, we assume that 57162306a36Sopenharmony_ci * the device is both present and functional. 57262306a36Sopenharmony_ci * 57362306a36Sopenharmony_ci * From the ACPI spec, description of _STA: 57462306a36Sopenharmony_ci * 57562306a36Sopenharmony_ci * "If a device object (including the processor object) does not have an 57662306a36Sopenharmony_ci * _STA object, then OSPM assumes that all of the above bits are set (in 57762306a36Sopenharmony_ci * other words, the device is present, ..., and functioning)" 57862306a36Sopenharmony_ci */ 57962306a36Sopenharmony_ci if (flags != ACPI_UINT32_MAX) { 58062306a36Sopenharmony_ci walk_info->num_STA++; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* 58462306a36Sopenharmony_ci * Examine the PRESENT and FUNCTIONING status bits 58562306a36Sopenharmony_ci * 58662306a36Sopenharmony_ci * Note: ACPI spec does not seem to specify behavior for the present but 58762306a36Sopenharmony_ci * not functioning case, so we assume functioning if present. 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_ci if (!(flags & ACPI_STA_DEVICE_PRESENT)) { 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* Device is not present, we must examine the Functioning bit */ 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (flags & ACPI_STA_DEVICE_FUNCTIONING) { 59462306a36Sopenharmony_ci /* 59562306a36Sopenharmony_ci * Device is not present but is "functioning". In this case, 59662306a36Sopenharmony_ci * we will not run _INI, but we continue to examine the children 59762306a36Sopenharmony_ci * of this device. 59862306a36Sopenharmony_ci * 59962306a36Sopenharmony_ci * From the ACPI spec, description of _STA: (note - no mention 60062306a36Sopenharmony_ci * of whether to run _INI or not on the device in question) 60162306a36Sopenharmony_ci * 60262306a36Sopenharmony_ci * "_STA may return bit 0 clear (not present) with bit 3 set 60362306a36Sopenharmony_ci * (device is functional). This case is used to indicate a valid 60462306a36Sopenharmony_ci * device for which no device driver should be loaded (for example, 60562306a36Sopenharmony_ci * a bridge device.) Children of this device may be present and 60662306a36Sopenharmony_ci * valid. OSPM should continue enumeration below a device whose 60762306a36Sopenharmony_ci * _STA returns this bit combination" 60862306a36Sopenharmony_ci */ 60962306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 61062306a36Sopenharmony_ci } else { 61162306a36Sopenharmony_ci /* 61262306a36Sopenharmony_ci * Device is not present and is not functioning. We must abort the 61362306a36Sopenharmony_ci * walk of this subtree immediately -- don't look at the children 61462306a36Sopenharmony_ci * of such a device. 61562306a36Sopenharmony_ci * 61662306a36Sopenharmony_ci * From the ACPI spec, description of _INI: 61762306a36Sopenharmony_ci * 61862306a36Sopenharmony_ci * "If the _STA method indicates that the device is not present, 61962306a36Sopenharmony_ci * OSPM will not run the _INI and will not examine the children 62062306a36Sopenharmony_ci * of the device for _INI methods" 62162306a36Sopenharmony_ci */ 62262306a36Sopenharmony_ci return_ACPI_STATUS(AE_CTRL_DEPTH); 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* 62762306a36Sopenharmony_ci * The device is present or is assumed present if no _STA exists. 62862306a36Sopenharmony_ci * Run the _INI if it exists (not required to exist) 62962306a36Sopenharmony_ci * 63062306a36Sopenharmony_ci * Note: We know there is an _INI within this subtree, but it may not be 63162306a36Sopenharmony_ci * under this particular device, it may be lower in the branch. 63262306a36Sopenharmony_ci */ 63362306a36Sopenharmony_ci if (!ACPI_COMPARE_NAMESEG(device_node->name.ascii, "_SB_") || 63462306a36Sopenharmony_ci device_node->parent != acpi_gbl_root_node) { 63562306a36Sopenharmony_ci ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname 63662306a36Sopenharmony_ci (ACPI_TYPE_METHOD, device_node, 63762306a36Sopenharmony_ci METHOD_NAME__INI)); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci memset(info, 0, sizeof(struct acpi_evaluate_info)); 64062306a36Sopenharmony_ci info->prefix_node = device_node; 64162306a36Sopenharmony_ci info->relative_pathname = METHOD_NAME__INI; 64262306a36Sopenharmony_ci info->parameters = NULL; 64362306a36Sopenharmony_ci info->flags = ACPI_IGNORE_RETURN_VALUE; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci status = acpi_ns_evaluate(info); 64662306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 64762306a36Sopenharmony_ci walk_info->num_INI++; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci#ifdef ACPI_DEBUG_OUTPUT 65062306a36Sopenharmony_ci else if (status != AE_NOT_FOUND) { 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci /* Ignore error and move on to next device */ 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci char *scope_name = 65562306a36Sopenharmony_ci acpi_ns_get_normalized_pathname(device_node, TRUE); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 65862306a36Sopenharmony_ci "during %s._INI execution", 65962306a36Sopenharmony_ci scope_name)); 66062306a36Sopenharmony_ci ACPI_FREE(scope_name); 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci#endif 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* Ignore errors from above */ 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci status = AE_OK; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* 67062306a36Sopenharmony_ci * The _INI method has been run if present; call the Global Initialization 67162306a36Sopenharmony_ci * Handler for this device. 67262306a36Sopenharmony_ci */ 67362306a36Sopenharmony_ci if (acpi_gbl_init_handler) { 67462306a36Sopenharmony_ci status = 67562306a36Sopenharmony_ci acpi_gbl_init_handler(device_node, ACPI_INIT_DEVICE_INI); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci return_ACPI_STATUS(status); 67962306a36Sopenharmony_ci} 680