162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: dspkginit - Completion of deferred package 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 "amlcode.h"
1462306a36Sopenharmony_ci#include "acdispat.h"
1562306a36Sopenharmony_ci#include "acinterp.h"
1662306a36Sopenharmony_ci#include "acparser.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define _COMPONENT          ACPI_NAMESPACE
1962306a36Sopenharmony_ciACPI_MODULE_NAME("dspkginit")
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* Local prototypes */
2262306a36Sopenharmony_cistatic void
2362306a36Sopenharmony_ciacpi_ds_resolve_package_element(union acpi_operand_object **element);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/*******************************************************************************
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * FUNCTION:    acpi_ds_build_internal_package_obj
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * PARAMETERS:  walk_state      - Current walk state
3062306a36Sopenharmony_ci *              op              - Parser object to be translated
3162306a36Sopenharmony_ci *              element_count   - Number of elements in the package - this is
3262306a36Sopenharmony_ci *                                the num_elements argument to Package()
3362306a36Sopenharmony_ci *              obj_desc_ptr    - Where the ACPI internal object is returned
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci * RETURN:      Status
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * DESCRIPTION: Translate a parser Op package object to the equivalent
3862306a36Sopenharmony_ci *              namespace object
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * NOTE: The number of elements in the package will be always be the num_elements
4162306a36Sopenharmony_ci * count, regardless of the number of elements in the package list. If
4262306a36Sopenharmony_ci * num_elements is smaller, only that many package list elements are used.
4362306a36Sopenharmony_ci * if num_elements is larger, the Package object is padded out with
4462306a36Sopenharmony_ci * objects of type Uninitialized (as per ACPI spec.)
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci * Even though the ASL compilers do not allow num_elements to be smaller
4762306a36Sopenharmony_ci * than the Package list length (for the fixed length package opcode), some
4862306a36Sopenharmony_ci * BIOS code modifies the AML on the fly to adjust the num_elements, and
4962306a36Sopenharmony_ci * this code compensates for that. This also provides compatibility with
5062306a36Sopenharmony_ci * other AML interpreters.
5162306a36Sopenharmony_ci *
5262306a36Sopenharmony_ci ******************************************************************************/
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ciacpi_status
5562306a36Sopenharmony_ciacpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
5662306a36Sopenharmony_ci				   union acpi_parse_object *op,
5762306a36Sopenharmony_ci				   u32 element_count,
5862306a36Sopenharmony_ci				   union acpi_operand_object **obj_desc_ptr)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	union acpi_parse_object *arg;
6162306a36Sopenharmony_ci	union acpi_parse_object *parent;
6262306a36Sopenharmony_ci	union acpi_operand_object *obj_desc = NULL;
6362306a36Sopenharmony_ci	acpi_status status = AE_OK;
6462306a36Sopenharmony_ci	u8 module_level_code = FALSE;
6562306a36Sopenharmony_ci	u16 reference_count;
6662306a36Sopenharmony_ci	u32 index;
6762306a36Sopenharmony_ci	u32 i;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_build_internal_package_obj);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/* Check if we are executing module level code */
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL) {
7462306a36Sopenharmony_ci		module_level_code = TRUE;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* Find the parent of a possibly nested package */
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	parent = op->common.parent;
8062306a36Sopenharmony_ci	while ((parent->common.aml_opcode == AML_PACKAGE_OP) ||
8162306a36Sopenharmony_ci	       (parent->common.aml_opcode == AML_VARIABLE_PACKAGE_OP)) {
8262306a36Sopenharmony_ci		parent = parent->common.parent;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	/*
8662306a36Sopenharmony_ci	 * If we are evaluating a Named package object of the form:
8762306a36Sopenharmony_ci	 *      Name (xxxx, Package)
8862306a36Sopenharmony_ci	 * the package object already exists, otherwise it must be created.
8962306a36Sopenharmony_ci	 */
9062306a36Sopenharmony_ci	obj_desc = *obj_desc_ptr;
9162306a36Sopenharmony_ci	if (!obj_desc) {
9262306a36Sopenharmony_ci		obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PACKAGE);
9362306a36Sopenharmony_ci		*obj_desc_ptr = obj_desc;
9462306a36Sopenharmony_ci		if (!obj_desc) {
9562306a36Sopenharmony_ci			return_ACPI_STATUS(AE_NO_MEMORY);
9662306a36Sopenharmony_ci		}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci		obj_desc->package.node = parent->common.node;
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (obj_desc->package.flags & AOPOBJ_DATA_VALID) {	/* Just in case */
10262306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/*
10662306a36Sopenharmony_ci	 * Allocate the element array (array of pointers to the individual
10762306a36Sopenharmony_ci	 * objects) if necessary. the count is based on the num_elements
10862306a36Sopenharmony_ci	 * parameter. Add an extra pointer slot so that the list is always
10962306a36Sopenharmony_ci	 * null terminated.
11062306a36Sopenharmony_ci	 */
11162306a36Sopenharmony_ci	if (!obj_desc->package.elements) {
11262306a36Sopenharmony_ci		obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size)
11362306a36Sopenharmony_ci								   element_count
11462306a36Sopenharmony_ci								   +
11562306a36Sopenharmony_ci								   1) *
11662306a36Sopenharmony_ci								  sizeof(void
11762306a36Sopenharmony_ci									 *));
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci		if (!obj_desc->package.elements) {
12062306a36Sopenharmony_ci			acpi_ut_delete_object_desc(obj_desc);
12162306a36Sopenharmony_ci			return_ACPI_STATUS(AE_NO_MEMORY);
12262306a36Sopenharmony_ci		}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		obj_desc->package.count = element_count;
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* First arg is element count. Second arg begins the initializer list */
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	arg = op->common.value.arg;
13062306a36Sopenharmony_ci	arg = arg->common.next;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/*
13362306a36Sopenharmony_ci	 * If we are executing module-level code, we will defer the
13462306a36Sopenharmony_ci	 * full resolution of the package elements in order to support
13562306a36Sopenharmony_ci	 * forward references from the elements. This provides
13662306a36Sopenharmony_ci	 * compatibility with other ACPI implementations.
13762306a36Sopenharmony_ci	 */
13862306a36Sopenharmony_ci	if (module_level_code) {
13962306a36Sopenharmony_ci		obj_desc->package.aml_start = walk_state->aml;
14062306a36Sopenharmony_ci		obj_desc->package.aml_length = 0;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
14362306a36Sopenharmony_ci				      "%s: Deferring resolution of Package elements\n",
14462306a36Sopenharmony_ci				      ACPI_GET_FUNCTION_NAME));
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	/*
14862306a36Sopenharmony_ci	 * Initialize the elements of the package, up to the num_elements count.
14962306a36Sopenharmony_ci	 * Package is automatically padded with uninitialized (NULL) elements
15062306a36Sopenharmony_ci	 * if num_elements is greater than the package list length. Likewise,
15162306a36Sopenharmony_ci	 * Package is truncated if num_elements is less than the list length.
15262306a36Sopenharmony_ci	 */
15362306a36Sopenharmony_ci	for (i = 0; arg && (i < element_count); i++) {
15462306a36Sopenharmony_ci		if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
15562306a36Sopenharmony_ci			if (!arg->common.node) {
15662306a36Sopenharmony_ci				/*
15762306a36Sopenharmony_ci				 * This is the case where an expression has returned a value.
15862306a36Sopenharmony_ci				 * The use of expressions (term_args) within individual
15962306a36Sopenharmony_ci				 * package elements is not supported by the AML interpreter,
16062306a36Sopenharmony_ci				 * even though the ASL grammar supports it. Example:
16162306a36Sopenharmony_ci				 *
16262306a36Sopenharmony_ci				 *      Name (INT1, 0x1234)
16362306a36Sopenharmony_ci				 *
16462306a36Sopenharmony_ci				 *      Name (PKG3, Package () {
16562306a36Sopenharmony_ci				 *          Add (INT1, 0xAAAA0000)
16662306a36Sopenharmony_ci				 *      })
16762306a36Sopenharmony_ci				 *
16862306a36Sopenharmony_ci				 *  1) No known AML interpreter supports this type of construct
16962306a36Sopenharmony_ci				 *  2) This fixes a fault if the construct is encountered
17062306a36Sopenharmony_ci				 */
17162306a36Sopenharmony_ci				ACPI_EXCEPTION((AE_INFO, AE_SUPPORT,
17262306a36Sopenharmony_ci						"Expressions within package elements are not supported"));
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci				/* Cleanup the return object, it is not needed */
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci				acpi_ut_remove_reference(walk_state->results->
17762306a36Sopenharmony_ci							 results.obj_desc[0]);
17862306a36Sopenharmony_ci				return_ACPI_STATUS(AE_SUPPORT);
17962306a36Sopenharmony_ci			}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci			if (arg->common.node->type == ACPI_TYPE_METHOD) {
18262306a36Sopenharmony_ci				/*
18362306a36Sopenharmony_ci				 * A method reference "looks" to the parser to be a method
18462306a36Sopenharmony_ci				 * invocation, so we special case it here
18562306a36Sopenharmony_ci				 */
18662306a36Sopenharmony_ci				arg->common.aml_opcode = AML_INT_NAMEPATH_OP;
18762306a36Sopenharmony_ci				status =
18862306a36Sopenharmony_ci				    acpi_ds_build_internal_object(walk_state,
18962306a36Sopenharmony_ci								  arg,
19062306a36Sopenharmony_ci								  &obj_desc->
19162306a36Sopenharmony_ci								  package.
19262306a36Sopenharmony_ci								  elements[i]);
19362306a36Sopenharmony_ci			} else {
19462306a36Sopenharmony_ci				/* This package element is already built, just get it */
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci				obj_desc->package.elements[i] =
19762306a36Sopenharmony_ci				    ACPI_CAST_PTR(union acpi_operand_object,
19862306a36Sopenharmony_ci						  arg->common.node);
19962306a36Sopenharmony_ci			}
20062306a36Sopenharmony_ci		} else {
20162306a36Sopenharmony_ci			status =
20262306a36Sopenharmony_ci			    acpi_ds_build_internal_object(walk_state, arg,
20362306a36Sopenharmony_ci							  &obj_desc->package.
20462306a36Sopenharmony_ci							  elements[i]);
20562306a36Sopenharmony_ci			if (status == AE_NOT_FOUND) {
20662306a36Sopenharmony_ci				ACPI_ERROR((AE_INFO, "%-48s",
20762306a36Sopenharmony_ci					    "****DS namepath not found"));
20862306a36Sopenharmony_ci			}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci			if (!module_level_code) {
21162306a36Sopenharmony_ci				/*
21262306a36Sopenharmony_ci				 * Initialize this package element. This function handles the
21362306a36Sopenharmony_ci				 * resolution of named references within the package.
21462306a36Sopenharmony_ci				 * Forward references from module-level code are deferred
21562306a36Sopenharmony_ci				 * until all ACPI tables are loaded.
21662306a36Sopenharmony_ci				 */
21762306a36Sopenharmony_ci				acpi_ds_init_package_element(0,
21862306a36Sopenharmony_ci							     obj_desc->package.
21962306a36Sopenharmony_ci							     elements[i], NULL,
22062306a36Sopenharmony_ci							     &obj_desc->package.
22162306a36Sopenharmony_ci							     elements[i]);
22262306a36Sopenharmony_ci			}
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		if (*obj_desc_ptr) {
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci			/* Existing package, get existing reference count */
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci			reference_count =
23062306a36Sopenharmony_ci			    (*obj_desc_ptr)->common.reference_count;
23162306a36Sopenharmony_ci			if (reference_count > 1) {
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci				/* Make new element ref count match original ref count */
23462306a36Sopenharmony_ci				/* TBD: Probably need an acpi_ut_add_references function */
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci				for (index = 0;
23762306a36Sopenharmony_ci				     index < ((u32)reference_count - 1);
23862306a36Sopenharmony_ci				     index++) {
23962306a36Sopenharmony_ci					acpi_ut_add_reference((obj_desc->
24062306a36Sopenharmony_ci							       package.
24162306a36Sopenharmony_ci							       elements[i]));
24262306a36Sopenharmony_ci				}
24362306a36Sopenharmony_ci			}
24462306a36Sopenharmony_ci		}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci		arg = arg->common.next;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/* Check for match between num_elements and actual length of package_list */
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (arg) {
25262306a36Sopenharmony_ci		/*
25362306a36Sopenharmony_ci		 * num_elements was exhausted, but there are remaining elements in
25462306a36Sopenharmony_ci		 * the package_list. Truncate the package to num_elements.
25562306a36Sopenharmony_ci		 *
25662306a36Sopenharmony_ci		 * Note: technically, this is an error, from ACPI spec: "It is an
25762306a36Sopenharmony_ci		 * error for NumElements to be less than the number of elements in
25862306a36Sopenharmony_ci		 * the PackageList". However, we just print a message and no
25962306a36Sopenharmony_ci		 * exception is returned. This provides compatibility with other
26062306a36Sopenharmony_ci		 * ACPI implementations. Some firmware implementations will alter
26162306a36Sopenharmony_ci		 * the num_elements on the fly, possibly creating this type of
26262306a36Sopenharmony_ci		 * ill-formed package object.
26362306a36Sopenharmony_ci		 */
26462306a36Sopenharmony_ci		while (arg) {
26562306a36Sopenharmony_ci			/*
26662306a36Sopenharmony_ci			 * We must delete any package elements that were created earlier
26762306a36Sopenharmony_ci			 * and are not going to be used because of the package truncation.
26862306a36Sopenharmony_ci			 */
26962306a36Sopenharmony_ci			if (arg->common.node) {
27062306a36Sopenharmony_ci				acpi_ut_remove_reference(ACPI_CAST_PTR
27162306a36Sopenharmony_ci							 (union
27262306a36Sopenharmony_ci							  acpi_operand_object,
27362306a36Sopenharmony_ci							  arg->common.node));
27462306a36Sopenharmony_ci				arg->common.node = NULL;
27562306a36Sopenharmony_ci			}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci			/* Find out how many elements there really are */
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci			i++;
28062306a36Sopenharmony_ci			arg = arg->common.next;
28162306a36Sopenharmony_ci		}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		ACPI_INFO(("Actual Package length (%u) is larger than "
28462306a36Sopenharmony_ci			   "NumElements field (%u), truncated",
28562306a36Sopenharmony_ci			   i, element_count));
28662306a36Sopenharmony_ci	} else if (i < element_count) {
28762306a36Sopenharmony_ci		/*
28862306a36Sopenharmony_ci		 * Arg list (elements) was exhausted, but we did not reach
28962306a36Sopenharmony_ci		 * num_elements count.
29062306a36Sopenharmony_ci		 *
29162306a36Sopenharmony_ci		 * Note: this is not an error, the package is padded out
29262306a36Sopenharmony_ci		 * with NULLs as per the ACPI specification.
29362306a36Sopenharmony_ci		 */
29462306a36Sopenharmony_ci		ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,
29562306a36Sopenharmony_ci				      "%s: Package List length (%u) smaller than NumElements "
29662306a36Sopenharmony_ci				      "count (%u), padded with null elements\n",
29762306a36Sopenharmony_ci				      ACPI_GET_FUNCTION_NAME, i,
29862306a36Sopenharmony_ci				      element_count));
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	/* Module-level packages will be resolved later */
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (!module_level_code) {
30462306a36Sopenharmony_ci		obj_desc->package.flags |= AOPOBJ_DATA_VALID;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
30862306a36Sopenharmony_ci	return_ACPI_STATUS(status);
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/*******************************************************************************
31262306a36Sopenharmony_ci *
31362306a36Sopenharmony_ci * FUNCTION:    acpi_ds_init_package_element
31462306a36Sopenharmony_ci *
31562306a36Sopenharmony_ci * PARAMETERS:  acpi_pkg_callback
31662306a36Sopenharmony_ci *
31762306a36Sopenharmony_ci * RETURN:      Status
31862306a36Sopenharmony_ci *
31962306a36Sopenharmony_ci * DESCRIPTION: Resolve a named reference element within a package object
32062306a36Sopenharmony_ci *
32162306a36Sopenharmony_ci ******************************************************************************/
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ciacpi_status
32462306a36Sopenharmony_ciacpi_ds_init_package_element(u8 object_type,
32562306a36Sopenharmony_ci			     union acpi_operand_object *source_object,
32662306a36Sopenharmony_ci			     union acpi_generic_state *state, void *context)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	union acpi_operand_object **element_ptr;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_init_package_element);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (!source_object) {
33362306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	/*
33762306a36Sopenharmony_ci	 * The following code is a bit of a hack to workaround a (current)
33862306a36Sopenharmony_ci	 * limitation of the acpi_pkg_callback interface. We need a pointer
33962306a36Sopenharmony_ci	 * to the location within the element array because a new object
34062306a36Sopenharmony_ci	 * may be created and stored there.
34162306a36Sopenharmony_ci	 */
34262306a36Sopenharmony_ci	if (context) {
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci		/* A direct call was made to this function */
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		element_ptr = (union acpi_operand_object **)context;
34762306a36Sopenharmony_ci	} else {
34862306a36Sopenharmony_ci		/* Call came from acpi_ut_walk_package_tree */
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci		element_ptr = state->pkg.this_target_obj;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* We are only interested in reference objects/elements */
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (source_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) {
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		/* Attempt to resolve the (named) reference to a namespace node */
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		acpi_ds_resolve_package_element(element_ptr);
36062306a36Sopenharmony_ci	} else if (source_object->common.type == ACPI_TYPE_PACKAGE) {
36162306a36Sopenharmony_ci		source_object->package.flags |= AOPOBJ_DATA_VALID;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/*******************************************************************************
36862306a36Sopenharmony_ci *
36962306a36Sopenharmony_ci * FUNCTION:    acpi_ds_resolve_package_element
37062306a36Sopenharmony_ci *
37162306a36Sopenharmony_ci * PARAMETERS:  element_ptr         - Pointer to a reference object
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * RETURN:      Possible new element is stored to the indirect element_ptr
37462306a36Sopenharmony_ci *
37562306a36Sopenharmony_ci * DESCRIPTION: Resolve a package element that is a reference to a named
37662306a36Sopenharmony_ci *              object.
37762306a36Sopenharmony_ci *
37862306a36Sopenharmony_ci ******************************************************************************/
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void
38162306a36Sopenharmony_ciacpi_ds_resolve_package_element(union acpi_operand_object **element_ptr)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	acpi_status status;
38462306a36Sopenharmony_ci	acpi_status status2;
38562306a36Sopenharmony_ci	union acpi_generic_state scope_info;
38662306a36Sopenharmony_ci	union acpi_operand_object *element = *element_ptr;
38762306a36Sopenharmony_ci	struct acpi_namespace_node *resolved_node;
38862306a36Sopenharmony_ci	struct acpi_namespace_node *original_node;
38962306a36Sopenharmony_ci	char *external_path = "";
39062306a36Sopenharmony_ci	acpi_object_type type;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_resolve_package_element);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/* Check if reference element is already resolved */
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (element->reference.resolved) {
39762306a36Sopenharmony_ci		ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
39862306a36Sopenharmony_ci				      "%s: Package element is already resolved\n",
39962306a36Sopenharmony_ci				      ACPI_GET_FUNCTION_NAME));
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci		return_VOID;
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	/* Element must be a reference object of correct type */
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	scope_info.scope.node = element->reference.node;	/* Prefix node */
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	status = acpi_ns_lookup(&scope_info, (char *)element->reference.aml,
40962306a36Sopenharmony_ci				ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
41062306a36Sopenharmony_ci				ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
41162306a36Sopenharmony_ci				NULL, &resolved_node);
41262306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
41362306a36Sopenharmony_ci		if ((status == AE_NOT_FOUND)
41462306a36Sopenharmony_ci		    && acpi_gbl_ignore_package_resolution_errors) {
41562306a36Sopenharmony_ci			/*
41662306a36Sopenharmony_ci			 * Optionally be silent about the NOT_FOUND case for the referenced
41762306a36Sopenharmony_ci			 * name. Although this is potentially a serious problem,
41862306a36Sopenharmony_ci			 * it can generate a lot of noise/errors on platforms whose
41962306a36Sopenharmony_ci			 * firmware carries around a bunch of unused Package objects.
42062306a36Sopenharmony_ci			 * To disable these errors, set this global to TRUE:
42162306a36Sopenharmony_ci			 *     acpi_gbl_ignore_package_resolution_errors
42262306a36Sopenharmony_ci			 *
42362306a36Sopenharmony_ci			 * If the AML actually tries to use such a package, the unresolved
42462306a36Sopenharmony_ci			 * element(s) will be replaced with NULL elements.
42562306a36Sopenharmony_ci			 */
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci			/* Referenced name not found, set the element to NULL */
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci			acpi_ut_remove_reference(*element_ptr);
43062306a36Sopenharmony_ci			*element_ptr = NULL;
43162306a36Sopenharmony_ci			return_VOID;
43262306a36Sopenharmony_ci		}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		status2 = acpi_ns_externalize_name(ACPI_UINT32_MAX,
43562306a36Sopenharmony_ci						   (char *)element->reference.
43662306a36Sopenharmony_ci						   aml, NULL, &external_path);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status,
43962306a36Sopenharmony_ci				"While resolving a named reference package element - %s",
44062306a36Sopenharmony_ci				external_path));
44162306a36Sopenharmony_ci		if (ACPI_SUCCESS(status2)) {
44262306a36Sopenharmony_ci			ACPI_FREE(external_path);
44362306a36Sopenharmony_ci		}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		/* Could not resolve name, set the element to NULL */
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci		acpi_ut_remove_reference(*element_ptr);
44862306a36Sopenharmony_ci		*element_ptr = NULL;
44962306a36Sopenharmony_ci		return_VOID;
45062306a36Sopenharmony_ci	} else if (resolved_node->type == ACPI_TYPE_ANY) {
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci		/* Named reference not resolved, return a NULL package element */
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
45562306a36Sopenharmony_ci			    "Could not resolve named package element [%4.4s] in [%4.4s]",
45662306a36Sopenharmony_ci			    resolved_node->name.ascii,
45762306a36Sopenharmony_ci			    scope_info.scope.node->name.ascii));
45862306a36Sopenharmony_ci		*element_ptr = NULL;
45962306a36Sopenharmony_ci		return_VOID;
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	/*
46362306a36Sopenharmony_ci	 * Special handling for Alias objects. We need resolved_node to point
46462306a36Sopenharmony_ci	 * to the Alias target. This effectively "resolves" the alias.
46562306a36Sopenharmony_ci	 */
46662306a36Sopenharmony_ci	if (resolved_node->type == ACPI_TYPE_LOCAL_ALIAS) {
46762306a36Sopenharmony_ci		resolved_node = ACPI_CAST_PTR(struct acpi_namespace_node,
46862306a36Sopenharmony_ci					      resolved_node->object);
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* Update the reference object */
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	element->reference.resolved = TRUE;
47462306a36Sopenharmony_ci	element->reference.node = resolved_node;
47562306a36Sopenharmony_ci	type = element->reference.node->type;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/*
47862306a36Sopenharmony_ci	 * Attempt to resolve the node to a value before we insert it into
47962306a36Sopenharmony_ci	 * the package. If this is a reference to a common data type,
48062306a36Sopenharmony_ci	 * resolve it immediately. According to the ACPI spec, package
48162306a36Sopenharmony_ci	 * elements can only be "data objects" or method references.
48262306a36Sopenharmony_ci	 * Attempt to resolve to an Integer, Buffer, String or Package.
48362306a36Sopenharmony_ci	 * If cannot, return the named reference (for things like Devices,
48462306a36Sopenharmony_ci	 * Methods, etc.) Buffer Fields and Fields will resolve to simple
48562306a36Sopenharmony_ci	 * objects (int/buf/str/pkg).
48662306a36Sopenharmony_ci	 *
48762306a36Sopenharmony_ci	 * NOTE: References to things like Devices, Methods, Mutexes, etc.
48862306a36Sopenharmony_ci	 * will remain as named references. This behavior is not described
48962306a36Sopenharmony_ci	 * in the ACPI spec, but it appears to be an oversight.
49062306a36Sopenharmony_ci	 */
49162306a36Sopenharmony_ci	original_node = resolved_node;
49262306a36Sopenharmony_ci	status = acpi_ex_resolve_node_to_value(&resolved_node, NULL);
49362306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
49462306a36Sopenharmony_ci		return_VOID;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	switch (type) {
49862306a36Sopenharmony_ci		/*
49962306a36Sopenharmony_ci		 * These object types are a result of named references, so we will
50062306a36Sopenharmony_ci		 * leave them as reference objects. In other words, these types
50162306a36Sopenharmony_ci		 * have no intrinsic "value".
50262306a36Sopenharmony_ci		 */
50362306a36Sopenharmony_ci	case ACPI_TYPE_DEVICE:
50462306a36Sopenharmony_ci	case ACPI_TYPE_THERMAL:
50562306a36Sopenharmony_ci	case ACPI_TYPE_METHOD:
50662306a36Sopenharmony_ci		break;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	case ACPI_TYPE_MUTEX:
50962306a36Sopenharmony_ci	case ACPI_TYPE_POWER:
51062306a36Sopenharmony_ci	case ACPI_TYPE_PROCESSOR:
51162306a36Sopenharmony_ci	case ACPI_TYPE_EVENT:
51262306a36Sopenharmony_ci	case ACPI_TYPE_REGION:
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		/* acpi_ex_resolve_node_to_value gave these an extra reference */
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci		acpi_ut_remove_reference(original_node->object);
51762306a36Sopenharmony_ci		break;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	default:
52062306a36Sopenharmony_ci		/*
52162306a36Sopenharmony_ci		 * For all other types - the node was resolved to an actual
52262306a36Sopenharmony_ci		 * operand object with a value, return the object. Remove
52362306a36Sopenharmony_ci		 * a reference on the existing object.
52462306a36Sopenharmony_ci		 */
52562306a36Sopenharmony_ci		acpi_ut_remove_reference(element);
52662306a36Sopenharmony_ci		*element_ptr = (union acpi_operand_object *)resolved_node;
52762306a36Sopenharmony_ci		break;
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return_VOID;
53162306a36Sopenharmony_ci}
532