162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: nsload - namespace loading/expanding/contracting procedures
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 "actables.h"
1562306a36Sopenharmony_ci#include "acinterp.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define _COMPONENT          ACPI_NAMESPACE
1862306a36Sopenharmony_ciACPI_MODULE_NAME("nsload")
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* Local prototypes */
2162306a36Sopenharmony_ci#ifdef ACPI_FUTURE_IMPLEMENTATION
2262306a36Sopenharmony_ciacpi_status acpi_ns_unload_namespace(acpi_handle handle);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
2562306a36Sopenharmony_ci#endif
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*******************************************************************************
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * FUNCTION:    acpi_ns_load_table
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * PARAMETERS:  table_index     - Index for table to be loaded
3262306a36Sopenharmony_ci *              node            - Owning NS node
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * RETURN:      Status
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * DESCRIPTION: Load one ACPI table into the namespace
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci ******************************************************************************/
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ciacpi_status
4162306a36Sopenharmony_ciacpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	acpi_status status;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ns_load_table);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	/* If table already loaded into namespace, just return */
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	if (acpi_tb_is_table_loaded(table_index)) {
5062306a36Sopenharmony_ci		status = AE_ALREADY_EXISTS;
5162306a36Sopenharmony_ci		goto unlock;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
5562306a36Sopenharmony_ci			  "**** Loading table into namespace ****\n"));
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	status = acpi_tb_allocate_owner_id(table_index);
5862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
5962306a36Sopenharmony_ci		goto unlock;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/*
6362306a36Sopenharmony_ci	 * Parse the table and load the namespace with all named
6462306a36Sopenharmony_ci	 * objects found within. Control methods are NOT parsed
6562306a36Sopenharmony_ci	 * at this time. In fact, the control methods cannot be
6662306a36Sopenharmony_ci	 * parsed until the entire namespace is loaded, because
6762306a36Sopenharmony_ci	 * if a control method makes a forward reference (call)
6862306a36Sopenharmony_ci	 * to another control method, we can't continue parsing
6962306a36Sopenharmony_ci	 * because we don't know how many arguments to parse next!
7062306a36Sopenharmony_ci	 */
7162306a36Sopenharmony_ci	status = acpi_ns_parse_table(table_index, node);
7262306a36Sopenharmony_ci	if (ACPI_SUCCESS(status)) {
7362306a36Sopenharmony_ci		acpi_tb_set_table_loaded_flag(table_index, TRUE);
7462306a36Sopenharmony_ci	} else {
7562306a36Sopenharmony_ci		/*
7662306a36Sopenharmony_ci		 * On error, delete any namespace objects created by this table.
7762306a36Sopenharmony_ci		 * We cannot initialize these objects, so delete them. There are
7862306a36Sopenharmony_ci		 * a couple of especially bad cases:
7962306a36Sopenharmony_ci		 * AE_ALREADY_EXISTS - namespace collision.
8062306a36Sopenharmony_ci		 * AE_NOT_FOUND - the target of a Scope operator does not
8162306a36Sopenharmony_ci		 * exist. This target of Scope must already exist in the
8262306a36Sopenharmony_ci		 * namespace, as per the ACPI specification.
8362306a36Sopenharmony_ci		 */
8462306a36Sopenharmony_ci		acpi_ns_delete_namespace_by_owner(acpi_gbl_root_table_list.
8562306a36Sopenharmony_ci						  tables[table_index].owner_id);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci		acpi_tb_release_owner_id(table_index);
8862306a36Sopenharmony_ci		return_ACPI_STATUS(status);
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ciunlock:
9262306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
9362306a36Sopenharmony_ci		return_ACPI_STATUS(status);
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/*
9762306a36Sopenharmony_ci	 * Now we can parse the control methods. We always parse
9862306a36Sopenharmony_ci	 * them here for a sanity check, and if configured for
9962306a36Sopenharmony_ci	 * just-in-time parsing, we delete the control method
10062306a36Sopenharmony_ci	 * parse trees.
10162306a36Sopenharmony_ci	 */
10262306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
10362306a36Sopenharmony_ci			  "**** Begin Table Object Initialization\n"));
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	acpi_ex_enter_interpreter();
10662306a36Sopenharmony_ci	status = acpi_ds_initialize_objects(table_index, node);
10762306a36Sopenharmony_ci	acpi_ex_exit_interpreter();
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
11062306a36Sopenharmony_ci			  "**** Completed Table Object Initialization\n"));
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return_ACPI_STATUS(status);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci#ifdef ACPI_OBSOLETE_FUNCTIONS
11662306a36Sopenharmony_ci/*******************************************************************************
11762306a36Sopenharmony_ci *
11862306a36Sopenharmony_ci * FUNCTION:    acpi_load_namespace
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci * PARAMETERS:  None
12162306a36Sopenharmony_ci *
12262306a36Sopenharmony_ci * RETURN:      Status
12362306a36Sopenharmony_ci *
12462306a36Sopenharmony_ci * DESCRIPTION: Load the name space from what ever is pointed to by DSDT.
12562306a36Sopenharmony_ci *              (DSDT points to either the BIOS or a buffer.)
12662306a36Sopenharmony_ci *
12762306a36Sopenharmony_ci ******************************************************************************/
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ciacpi_status acpi_ns_load_namespace(void)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	acpi_status status;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_load_name_space);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* There must be at least a DSDT installed */
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	if (acpi_gbl_DSDT == NULL) {
13862306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "DSDT is not in memory"));
13962306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_ACPI_TABLES);
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/*
14362306a36Sopenharmony_ci	 * Load the namespace. The DSDT is required,
14462306a36Sopenharmony_ci	 * but the SSDT and PSDT tables are optional.
14562306a36Sopenharmony_ci	 */
14662306a36Sopenharmony_ci	status = acpi_ns_load_table_by_type(ACPI_TABLE_ID_DSDT);
14762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
14862306a36Sopenharmony_ci		return_ACPI_STATUS(status);
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* Ignore exceptions from these */
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	(void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_SSDT);
15462306a36Sopenharmony_ci	(void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_PSDT);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
15762306a36Sopenharmony_ci			      "ACPI Namespace successfully loaded at root %p\n",
15862306a36Sopenharmony_ci			      acpi_gbl_root_node));
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	return_ACPI_STATUS(status);
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci#endif
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#ifdef ACPI_FUTURE_IMPLEMENTATION
16562306a36Sopenharmony_ci/*******************************************************************************
16662306a36Sopenharmony_ci *
16762306a36Sopenharmony_ci * FUNCTION:    acpi_ns_delete_subtree
16862306a36Sopenharmony_ci *
16962306a36Sopenharmony_ci * PARAMETERS:  start_handle        - Handle in namespace where search begins
17062306a36Sopenharmony_ci *
17162306a36Sopenharmony_ci * RETURNS      Status
17262306a36Sopenharmony_ci *
17362306a36Sopenharmony_ci * DESCRIPTION: Walks the namespace starting at the given handle and deletes
17462306a36Sopenharmony_ci *              all objects, entries, and scopes in the entire subtree.
17562306a36Sopenharmony_ci *
17662306a36Sopenharmony_ci *              Namespace/Interpreter should be locked or the subsystem should
17762306a36Sopenharmony_ci *              be in shutdown before this routine is called.
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci ******************************************************************************/
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic acpi_status acpi_ns_delete_subtree(acpi_handle start_handle)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	acpi_status status;
18462306a36Sopenharmony_ci	acpi_handle child_handle;
18562306a36Sopenharmony_ci	acpi_handle parent_handle;
18662306a36Sopenharmony_ci	acpi_handle next_child_handle;
18762306a36Sopenharmony_ci	acpi_handle dummy;
18862306a36Sopenharmony_ci	u32 level;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ns_delete_subtree);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	parent_handle = start_handle;
19362306a36Sopenharmony_ci	child_handle = NULL;
19462306a36Sopenharmony_ci	level = 1;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/*
19762306a36Sopenharmony_ci	 * Traverse the tree of objects until we bubble back up
19862306a36Sopenharmony_ci	 * to where we started.
19962306a36Sopenharmony_ci	 */
20062306a36Sopenharmony_ci	while (level > 0) {
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci		/* Attempt to get the next object in this scope */
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle,
20562306a36Sopenharmony_ci					      child_handle, &next_child_handle);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		child_handle = next_child_handle;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		/* Did we get a new object? */
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci			/* Check if this object has any children */
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci			if (ACPI_SUCCESS
21662306a36Sopenharmony_ci			    (acpi_get_next_object
21762306a36Sopenharmony_ci			     (ACPI_TYPE_ANY, child_handle, NULL, &dummy))) {
21862306a36Sopenharmony_ci				/*
21962306a36Sopenharmony_ci				 * There is at least one child of this object,
22062306a36Sopenharmony_ci				 * visit the object
22162306a36Sopenharmony_ci				 */
22262306a36Sopenharmony_ci				level++;
22362306a36Sopenharmony_ci				parent_handle = child_handle;
22462306a36Sopenharmony_ci				child_handle = NULL;
22562306a36Sopenharmony_ci			}
22662306a36Sopenharmony_ci		} else {
22762306a36Sopenharmony_ci			/*
22862306a36Sopenharmony_ci			 * No more children in this object, go back up to
22962306a36Sopenharmony_ci			 * the object's parent
23062306a36Sopenharmony_ci			 */
23162306a36Sopenharmony_ci			level--;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci			/* Delete all children now */
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci			acpi_ns_delete_children(child_handle);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci			child_handle = parent_handle;
23862306a36Sopenharmony_ci			status = acpi_get_parent(parent_handle, &parent_handle);
23962306a36Sopenharmony_ci			if (ACPI_FAILURE(status)) {
24062306a36Sopenharmony_ci				return_ACPI_STATUS(status);
24162306a36Sopenharmony_ci			}
24262306a36Sopenharmony_ci		}
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* Now delete the starting object, and we are done */
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	acpi_ns_remove_node(child_handle);
24862306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci/*******************************************************************************
25262306a36Sopenharmony_ci *
25362306a36Sopenharmony_ci *  FUNCTION:       acpi_ns_unload_name_space
25462306a36Sopenharmony_ci *
25562306a36Sopenharmony_ci *  PARAMETERS:     handle          - Root of namespace subtree to be deleted
25662306a36Sopenharmony_ci *
25762306a36Sopenharmony_ci *  RETURN:         Status
25862306a36Sopenharmony_ci *
25962306a36Sopenharmony_ci *  DESCRIPTION:    Shrinks the namespace, typically in response to an undocking
26062306a36Sopenharmony_ci *                  event. Deletes an entire subtree starting from (and
26162306a36Sopenharmony_ci *                  including) the given handle.
26262306a36Sopenharmony_ci *
26362306a36Sopenharmony_ci ******************************************************************************/
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ciacpi_status acpi_ns_unload_namespace(acpi_handle handle)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	acpi_status status;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ns_unload_name_space);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* Parameter validation */
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (!acpi_gbl_root_node) {
27462306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_NAMESPACE);
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	if (!handle) {
27862306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	/* This function does the real work */
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	status = acpi_ns_delete_subtree(handle);
28462306a36Sopenharmony_ci	return_ACPI_STATUS(status);
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci#endif
287