680 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: nsinit - namespace initialization5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12#include "acnamesp.h"13#include "acdispat.h"14#include "acinterp.h"15#include "acevents.h"16 17#define _COMPONENT ACPI_NAMESPACE18ACPI_MODULE_NAME("nsinit")19 20/* Local prototypes */21static acpi_status22acpi_ns_init_one_object(acpi_handle obj_handle,23 u32 level, void *context, void **return_value);24 25static acpi_status26acpi_ns_init_one_device(acpi_handle obj_handle,27 u32 nesting_level, void *context, void **return_value);28 29static acpi_status30acpi_ns_find_ini_methods(acpi_handle obj_handle,31 u32 nesting_level, void *context, void **return_value);32 33/*******************************************************************************34 *35 * FUNCTION: acpi_ns_initialize_objects36 *37 * PARAMETERS: None38 *39 * RETURN: Status40 *41 * DESCRIPTION: Walk the entire namespace and perform any necessary42 * initialization on the objects found therein43 *44 ******************************************************************************/45 46acpi_status acpi_ns_initialize_objects(void)47{48 acpi_status status;49 struct acpi_init_walk_info info;50 51 ACPI_FUNCTION_TRACE(ns_initialize_objects);52 53 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,54 "[Init] Completing Initialization of ACPI Objects\n"));55 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,56 "**** Starting initialization of namespace objects ****\n"));57 ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,58 "Final data object initialization: "));59 60 /* Clear the info block */61 62 memset(&info, 0, sizeof(struct acpi_init_walk_info));63 64 /* Walk entire namespace from the supplied root */65 66 /*67 * TBD: will become ACPI_TYPE_PACKAGE as this type object68 * is now the only one that supports deferred initialization69 * (forward references).70 */71 status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,72 ACPI_UINT32_MAX, acpi_ns_init_one_object,73 NULL, &info, NULL);74 if (ACPI_FAILURE(status)) {75 ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));76 }77 78 ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,79 "Namespace contains %u (0x%X) objects\n",80 info.object_count, info.object_count));81 82 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,83 "%u Control Methods found\n%u Op Regions found\n",84 info.method_count, info.op_region_count));85 86 return_ACPI_STATUS(AE_OK);87}88 89/*******************************************************************************90 *91 * FUNCTION: acpi_ns_initialize_devices92 *93 * PARAMETERS: None94 *95 * RETURN: acpi_status96 *97 * DESCRIPTION: Walk the entire namespace and initialize all ACPI devices.98 * This means running _INI on all present devices.99 *100 * Note: We install PCI config space handler on region access,101 * not here.102 *103 ******************************************************************************/104 105acpi_status acpi_ns_initialize_devices(u32 flags)106{107 acpi_status status = AE_OK;108 struct acpi_device_walk_info info;109 acpi_handle handle;110 111 ACPI_FUNCTION_TRACE(ns_initialize_devices);112 113 if (!(flags & ACPI_NO_DEVICE_INIT)) {114 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,115 "[Init] Initializing ACPI Devices\n"));116 117 /* Init counters */118 119 info.device_count = 0;120 info.num_STA = 0;121 info.num_INI = 0;122 123 ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,124 "Initializing Device/Processor/Thermal objects "125 "and executing _INI/_STA methods:\n"));126 127 /* Tree analysis: find all subtrees that contain _INI methods */128 129 status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,130 ACPI_UINT32_MAX, FALSE,131 acpi_ns_find_ini_methods, NULL,132 &info, NULL);133 if (ACPI_FAILURE(status)) {134 goto error_exit;135 }136 137 /* Allocate the evaluation information block */138 139 info.evaluate_info =140 ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));141 if (!info.evaluate_info) {142 status = AE_NO_MEMORY;143 goto error_exit;144 }145 146 /*147 * Execute the "global" _INI method that may appear at the root.148 * This support is provided for Windows compatibility (Vista+) and149 * is not part of the ACPI specification.150 */151 info.evaluate_info->prefix_node = acpi_gbl_root_node;152 info.evaluate_info->relative_pathname = METHOD_NAME__INI;153 info.evaluate_info->parameters = NULL;154 info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE;155 156 status = acpi_ns_evaluate(info.evaluate_info);157 if (ACPI_SUCCESS(status)) {158 info.num_INI++;159 }160 161 /*162 * Execute \_SB._INI.163 * There appears to be a strict order requirement for \_SB._INI,164 * which should be evaluated before any _REG evaluations.165 */166 status = acpi_get_handle(NULL, "\\_SB", &handle);167 if (ACPI_SUCCESS(status)) {168 memset(info.evaluate_info, 0,169 sizeof(struct acpi_evaluate_info));170 info.evaluate_info->prefix_node = handle;171 info.evaluate_info->relative_pathname =172 METHOD_NAME__INI;173 info.evaluate_info->parameters = NULL;174 info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE;175 176 status = acpi_ns_evaluate(info.evaluate_info);177 if (ACPI_SUCCESS(status)) {178 info.num_INI++;179 }180 }181 }182 183 /*184 * Run all _REG methods185 *186 * Note: Any objects accessed by the _REG methods will be automatically187 * initialized, even if they contain executable AML (see the call to188 * acpi_ns_initialize_objects below).189 *190 * Note: According to the ACPI specification, we actually needn't execute191 * _REG for system_memory/system_io operation regions, but for PCI_Config192 * operation regions, it is required to evaluate _REG for those on a PCI193 * root bus that doesn't contain _BBN object. So this code is kept here194 * in order not to break things.195 */196 if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) {197 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,198 "[Init] Executing _REG OpRegion methods\n"));199 200 status = acpi_ev_initialize_op_regions();201 if (ACPI_FAILURE(status)) {202 goto error_exit;203 }204 }205 206 if (!(flags & ACPI_NO_DEVICE_INIT)) {207 208 /* Walk namespace to execute all _INIs on present devices */209 210 status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,211 ACPI_UINT32_MAX, FALSE,212 acpi_ns_init_one_device, NULL,213 &info, NULL);214 215 /*216 * Any _OSI requests should be completed by now. If the BIOS has217 * requested any Windows OSI strings, we will always truncate218 * I/O addresses to 16 bits -- for Windows compatibility.219 */220 if (acpi_gbl_osi_data >= ACPI_OSI_WIN_2000) {221 acpi_gbl_truncate_io_addresses = TRUE;222 }223 224 ACPI_FREE(info.evaluate_info);225 if (ACPI_FAILURE(status)) {226 goto error_exit;227 }228 229 ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,230 " Executed %u _INI methods requiring %u _STA executions "231 "(examined %u objects)\n",232 info.num_INI, info.num_STA,233 info.device_count));234 }235 236 return_ACPI_STATUS(status);237 238error_exit:239 ACPI_EXCEPTION((AE_INFO, status, "During device initialization"));240 return_ACPI_STATUS(status);241}242 243/*******************************************************************************244 *245 * FUNCTION: acpi_ns_init_one_package246 *247 * PARAMETERS: obj_handle - Node248 * level - Current nesting level249 * context - Not used250 * return_value - Not used251 *252 * RETURN: Status253 *254 * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every package255 * within the namespace. Used during dynamic load of an SSDT.256 *257 ******************************************************************************/258 259acpi_status260acpi_ns_init_one_package(acpi_handle obj_handle,261 u32 level, void *context, void **return_value)262{263 acpi_status status;264 union acpi_operand_object *obj_desc;265 struct acpi_namespace_node *node =266 (struct acpi_namespace_node *)obj_handle;267 268 obj_desc = acpi_ns_get_attached_object(node);269 if (!obj_desc) {270 return (AE_OK);271 }272 273 /* Exit if package is already initialized */274 275 if (obj_desc->package.flags & AOPOBJ_DATA_VALID) {276 return (AE_OK);277 }278 279 status = acpi_ds_get_package_arguments(obj_desc);280 if (ACPI_FAILURE(status)) {281 return (AE_OK);282 }283 284 status =285 acpi_ut_walk_package_tree(obj_desc, NULL,286 acpi_ds_init_package_element, NULL);287 if (ACPI_FAILURE(status)) {288 return (AE_OK);289 }290 291 obj_desc->package.flags |= AOPOBJ_DATA_VALID;292 return (AE_OK);293}294 295/*******************************************************************************296 *297 * FUNCTION: acpi_ns_init_one_object298 *299 * PARAMETERS: obj_handle - Node300 * level - Current nesting level301 * context - Points to a init info struct302 * return_value - Not used303 *304 * RETURN: Status305 *306 * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object307 * within the namespace.308 *309 * Currently, the only objects that require initialization are:310 * 1) Methods311 * 2) Op Regions312 *313 ******************************************************************************/314 315static acpi_status316acpi_ns_init_one_object(acpi_handle obj_handle,317 u32 level, void *context, void **return_value)318{319 acpi_object_type type;320 acpi_status status = AE_OK;321 struct acpi_init_walk_info *info =322 (struct acpi_init_walk_info *)context;323 struct acpi_namespace_node *node =324 (struct acpi_namespace_node *)obj_handle;325 union acpi_operand_object *obj_desc;326 327 ACPI_FUNCTION_NAME(ns_init_one_object);328 329 info->object_count++;330 331 /* And even then, we are only interested in a few object types */332 333 type = acpi_ns_get_type(obj_handle);334 obj_desc = acpi_ns_get_attached_object(node);335 if (!obj_desc) {336 return (AE_OK);337 }338 339 /* Increment counters for object types we are looking for */340 341 switch (type) {342 case ACPI_TYPE_REGION:343 344 info->op_region_count++;345 break;346 347 case ACPI_TYPE_BUFFER_FIELD:348 349 info->field_count++;350 break;351 352 case ACPI_TYPE_LOCAL_BANK_FIELD:353 354 info->field_count++;355 break;356 357 case ACPI_TYPE_BUFFER:358 359 info->buffer_count++;360 break;361 362 case ACPI_TYPE_PACKAGE:363 364 info->package_count++;365 break;366 367 default:368 369 /* No init required, just exit now */370 371 return (AE_OK);372 }373 374 /* If the object is already initialized, nothing else to do */375 376 if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {377 return (AE_OK);378 }379 380 /* Must lock the interpreter before executing AML code */381 382 acpi_ex_enter_interpreter();383 384 /*385 * Only initialization of Package objects can be deferred, in order386 * to support forward references.387 */388 switch (type) {389 case ACPI_TYPE_LOCAL_BANK_FIELD:390 391 /* TBD: bank_fields do not require deferred init, remove this code */392 393 info->field_init++;394 status = acpi_ds_get_bank_field_arguments(obj_desc);395 break;396 397 case ACPI_TYPE_PACKAGE:398 399 /* Complete the initialization/resolution of the package object */400 401 info->package_init++;402 status =403 acpi_ns_init_one_package(obj_handle, level, NULL, NULL);404 break;405 406 default:407 408 /* No other types should get here */409 410 status = AE_TYPE;411 ACPI_EXCEPTION((AE_INFO, status,412 "Opcode is not deferred [%4.4s] (%s)",413 acpi_ut_get_node_name(node),414 acpi_ut_get_type_name(type)));415 break;416 }417 418 if (ACPI_FAILURE(status)) {419 ACPI_EXCEPTION((AE_INFO, status,420 "Could not execute arguments for [%4.4s] (%s)",421 acpi_ut_get_node_name(node),422 acpi_ut_get_type_name(type)));423 }424 425 /*426 * We ignore errors from above, and always return OK, since we don't want427 * to abort the walk on any single error.428 */429 acpi_ex_exit_interpreter();430 return (AE_OK);431}432 433/*******************************************************************************434 *435 * FUNCTION: acpi_ns_find_ini_methods436 *437 * PARAMETERS: acpi_walk_callback438 *439 * RETURN: acpi_status440 *441 * DESCRIPTION: Called during namespace walk. Finds objects named _INI under442 * device/processor/thermal objects, and marks the entire subtree443 * with a SUBTREE_HAS_INI flag. This flag is used during the444 * subsequent device initialization walk to avoid entire subtrees445 * that do not contain an _INI.446 *447 ******************************************************************************/448 449static acpi_status450acpi_ns_find_ini_methods(acpi_handle obj_handle,451 u32 nesting_level, void *context, void **return_value)452{453 struct acpi_device_walk_info *info =454 ACPI_CAST_PTR(struct acpi_device_walk_info, context);455 struct acpi_namespace_node *node;456 struct acpi_namespace_node *parent_node;457 458 /* Keep count of device/processor/thermal objects */459 460 node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);461 if ((node->type == ACPI_TYPE_DEVICE) ||462 (node->type == ACPI_TYPE_PROCESSOR) ||463 (node->type == ACPI_TYPE_THERMAL)) {464 info->device_count++;465 return (AE_OK);466 }467 468 /* We are only looking for methods named _INI */469 470 if (!ACPI_COMPARE_NAMESEG(node->name.ascii, METHOD_NAME__INI)) {471 return (AE_OK);472 }473 474 /*475 * The only _INI methods that we care about are those that are476 * present under Device, Processor, and Thermal objects.477 */478 parent_node = node->parent;479 switch (parent_node->type) {480 case ACPI_TYPE_DEVICE:481 case ACPI_TYPE_PROCESSOR:482 case ACPI_TYPE_THERMAL:483 484 /* Mark parent and bubble up the INI present flag to the root */485 486 while (parent_node) {487 parent_node->flags |= ANOBJ_SUBTREE_HAS_INI;488 parent_node = parent_node->parent;489 }490 break;491 492 default:493 494 break;495 }496 497 return (AE_OK);498}499 500/*******************************************************************************501 *502 * FUNCTION: acpi_ns_init_one_device503 *504 * PARAMETERS: acpi_walk_callback505 *506 * RETURN: acpi_status507 *508 * DESCRIPTION: This is called once per device soon after ACPI is enabled509 * to initialize each device. It determines if the device is510 * present, and if so, calls _INI.511 *512 ******************************************************************************/513 514static acpi_status515acpi_ns_init_one_device(acpi_handle obj_handle,516 u32 nesting_level, void *context, void **return_value)517{518 struct acpi_device_walk_info *walk_info =519 ACPI_CAST_PTR(struct acpi_device_walk_info, context);520 struct acpi_evaluate_info *info = walk_info->evaluate_info;521 u32 flags;522 acpi_status status;523 struct acpi_namespace_node *device_node;524 525 ACPI_FUNCTION_TRACE(ns_init_one_device);526 527 /* We are interested in Devices, Processors and thermal_zones only */528 529 device_node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);530 if ((device_node->type != ACPI_TYPE_DEVICE) &&531 (device_node->type != ACPI_TYPE_PROCESSOR) &&532 (device_node->type != ACPI_TYPE_THERMAL)) {533 return_ACPI_STATUS(AE_OK);534 }535 536 /*537 * Because of an earlier namespace analysis, all subtrees that contain an538 * _INI method are tagged.539 *540 * If this device subtree does not contain any _INI methods, we541 * can exit now and stop traversing this entire subtree.542 */543 if (!(device_node->flags & ANOBJ_SUBTREE_HAS_INI)) {544 return_ACPI_STATUS(AE_CTRL_DEPTH);545 }546 547 /*548 * Run _STA to determine if this device is present and functioning. We549 * must know this information for two important reasons (from ACPI spec):550 *551 * 1) We can only run _INI if the device is present.552 * 2) We must abort the device tree walk on this subtree if the device is553 * not present and is not functional (we will not examine the children)554 *555 * The _STA method is not required to be present under the device, we556 * assume the device is present if _STA does not exist.557 */558 ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname559 (ACPI_TYPE_METHOD, device_node, METHOD_NAME__STA));560 561 status = acpi_ut_execute_STA(device_node, &flags);562 if (ACPI_FAILURE(status)) {563 564 /* Ignore error and move on to next device */565 566 return_ACPI_STATUS(AE_OK);567 }568 569 /*570 * Flags == -1 means that _STA was not found. In this case, we assume that571 * the device is both present and functional.572 *573 * From the ACPI spec, description of _STA:574 *575 * "If a device object (including the processor object) does not have an576 * _STA object, then OSPM assumes that all of the above bits are set (in577 * other words, the device is present, ..., and functioning)"578 */579 if (flags != ACPI_UINT32_MAX) {580 walk_info->num_STA++;581 }582 583 /*584 * Examine the PRESENT and FUNCTIONING status bits585 *586 * Note: ACPI spec does not seem to specify behavior for the present but587 * not functioning case, so we assume functioning if present.588 */589 if (!(flags & ACPI_STA_DEVICE_PRESENT)) {590 591 /* Device is not present, we must examine the Functioning bit */592 593 if (flags & ACPI_STA_DEVICE_FUNCTIONING) {594 /*595 * Device is not present but is "functioning". In this case,596 * we will not run _INI, but we continue to examine the children597 * of this device.598 *599 * From the ACPI spec, description of _STA: (note - no mention600 * of whether to run _INI or not on the device in question)601 *602 * "_STA may return bit 0 clear (not present) with bit 3 set603 * (device is functional). This case is used to indicate a valid604 * device for which no device driver should be loaded (for example,605 * a bridge device.) Children of this device may be present and606 * valid. OSPM should continue enumeration below a device whose607 * _STA returns this bit combination"608 */609 return_ACPI_STATUS(AE_OK);610 } else {611 /*612 * Device is not present and is not functioning. We must abort the613 * walk of this subtree immediately -- don't look at the children614 * of such a device.615 *616 * From the ACPI spec, description of _INI:617 *618 * "If the _STA method indicates that the device is not present,619 * OSPM will not run the _INI and will not examine the children620 * of the device for _INI methods"621 */622 return_ACPI_STATUS(AE_CTRL_DEPTH);623 }624 }625 626 /*627 * The device is present or is assumed present if no _STA exists.628 * Run the _INI if it exists (not required to exist)629 *630 * Note: We know there is an _INI within this subtree, but it may not be631 * under this particular device, it may be lower in the branch.632 */633 if (!ACPI_COMPARE_NAMESEG(device_node->name.ascii, "_SB_") ||634 device_node->parent != acpi_gbl_root_node) {635 ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname636 (ACPI_TYPE_METHOD, device_node,637 METHOD_NAME__INI));638 639 memset(info, 0, sizeof(struct acpi_evaluate_info));640 info->prefix_node = device_node;641 info->relative_pathname = METHOD_NAME__INI;642 info->parameters = NULL;643 info->flags = ACPI_IGNORE_RETURN_VALUE;644 645 status = acpi_ns_evaluate(info);646 if (ACPI_SUCCESS(status)) {647 walk_info->num_INI++;648 }649#ifdef ACPI_DEBUG_OUTPUT650 else if (status != AE_NOT_FOUND) {651 652 /* Ignore error and move on to next device */653 654 char *scope_name =655 acpi_ns_get_normalized_pathname(device_node, TRUE);656 657 ACPI_EXCEPTION((AE_INFO, status,658 "during %s._INI execution",659 scope_name));660 ACPI_FREE(scope_name);661 }662#endif663 }664 665 /* Ignore errors from above */666 667 status = AE_OK;668 669 /*670 * The _INI method has been run if present; call the Global Initialization671 * Handler for this device.672 */673 if (acpi_gbl_init_handler) {674 status =675 acpi_gbl_init_handler(device_node, ACPI_INIT_DEVICE_INI);676 }677 678 return_ACPI_STATUS(status);679}680