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