xref: /openbmc/linux/drivers/acpi/acpica/nsload.c (revision 612c2932)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: nsload - namespace loading/expanding/contracting procedures
595b482a8SLen Brown  *
6*612c2932SBob Moore  * Copyright (C) 2000 - 2023, Intel Corp.
795b482a8SLen Brown  *
895857638SErik Schmauss  *****************************************************************************/
995b482a8SLen Brown 
1095b482a8SLen Brown #include <acpi/acpi.h>
11e2f7a777SLen Brown #include "accommon.h"
12e2f7a777SLen Brown #include "acnamesp.h"
13e2f7a777SLen Brown #include "acdispat.h"
14e2f7a777SLen Brown #include "actables.h"
1574f51b80SLv Zheng #include "acinterp.h"
1695b482a8SLen Brown 
1795b482a8SLen Brown #define _COMPONENT          ACPI_NAMESPACE
1895b482a8SLen Brown ACPI_MODULE_NAME("nsload")
1995b482a8SLen Brown 
2095b482a8SLen Brown /* Local prototypes */
2195b482a8SLen Brown #ifdef ACPI_FUTURE_IMPLEMENTATION
2295b482a8SLen Brown acpi_status acpi_ns_unload_namespace(acpi_handle handle);
2395b482a8SLen Brown 
2495b482a8SLen Brown static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
2595b482a8SLen Brown #endif
2695b482a8SLen Brown 
2795b482a8SLen Brown /*******************************************************************************
2895b482a8SLen Brown  *
2995b482a8SLen Brown  * FUNCTION:    acpi_ns_load_table
3095b482a8SLen Brown  *
3195b482a8SLen Brown  * PARAMETERS:  table_index     - Index for table to be loaded
32ba494beeSBob Moore  *              node            - Owning NS node
3395b482a8SLen Brown  *
3495b482a8SLen Brown  * RETURN:      Status
3595b482a8SLen Brown  *
3695b482a8SLen Brown  * DESCRIPTION: Load one ACPI table into the namespace
3795b482a8SLen Brown  *
3895b482a8SLen Brown  ******************************************************************************/
3995b482a8SLen Brown 
4095b482a8SLen Brown acpi_status
acpi_ns_load_table(u32 table_index,struct acpi_namespace_node * node)4195b482a8SLen Brown acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node)
4295b482a8SLen Brown {
4395b482a8SLen Brown 	acpi_status status;
4495b482a8SLen Brown 
4595b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ns_load_table);
4695b482a8SLen Brown 
4795b482a8SLen Brown 	/* If table already loaded into namespace, just return */
4895b482a8SLen Brown 
4995b482a8SLen Brown 	if (acpi_tb_is_table_loaded(table_index)) {
5095b482a8SLen Brown 		status = AE_ALREADY_EXISTS;
5195b482a8SLen Brown 		goto unlock;
5295b482a8SLen Brown 	}
5395b482a8SLen Brown 
5495b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
5595b482a8SLen Brown 			  "**** Loading table into namespace ****\n"));
5695b482a8SLen Brown 
5795b482a8SLen Brown 	status = acpi_tb_allocate_owner_id(table_index);
5895b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
5995b482a8SLen Brown 		goto unlock;
6095b482a8SLen Brown 	}
6195b482a8SLen Brown 
6274f51b80SLv Zheng 	/*
6374f51b80SLv Zheng 	 * Parse the table and load the namespace with all named
6474f51b80SLv Zheng 	 * objects found within. Control methods are NOT parsed
6574f51b80SLv Zheng 	 * at this time. In fact, the control methods cannot be
6674f51b80SLv Zheng 	 * parsed until the entire namespace is loaded, because
6774f51b80SLv Zheng 	 * if a control method makes a forward reference (call)
6874f51b80SLv Zheng 	 * to another control method, we can't continue parsing
6974f51b80SLv Zheng 	 * because we don't know how many arguments to parse next!
7074f51b80SLv Zheng 	 */
7195b482a8SLen Brown 	status = acpi_ns_parse_table(table_index, node);
7295b482a8SLen Brown 	if (ACPI_SUCCESS(status)) {
7395b482a8SLen Brown 		acpi_tb_set_table_loaded_flag(table_index, TRUE);
7495b482a8SLen Brown 	} else {
754712f71bSBob Moore 		/*
764712f71bSBob Moore 		 * On error, delete any namespace objects created by this table.
774712f71bSBob Moore 		 * We cannot initialize these objects, so delete them. There are
78c163f90cSErik Schmauss 		 * a couple of especially bad cases:
794712f71bSBob Moore 		 * AE_ALREADY_EXISTS - namespace collision.
804712f71bSBob Moore 		 * AE_NOT_FOUND - the target of a Scope operator does not
814712f71bSBob Moore 		 * exist. This target of Scope must already exist in the
824712f71bSBob Moore 		 * namespace, as per the ACPI specification.
834712f71bSBob Moore 		 */
844712f71bSBob Moore 		acpi_ns_delete_namespace_by_owner(acpi_gbl_root_table_list.
854712f71bSBob Moore 						  tables[table_index].owner_id);
864712f71bSBob Moore 
8780b28810SLv Zheng 		acpi_tb_release_owner_id(table_index);
884712f71bSBob Moore 		return_ACPI_STATUS(status);
8995b482a8SLen Brown 	}
9095b482a8SLen Brown 
9195b482a8SLen Brown unlock:
9295b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
9395b482a8SLen Brown 		return_ACPI_STATUS(status);
9495b482a8SLen Brown 	}
9595b482a8SLen Brown 
9695b482a8SLen Brown 	/*
9795b482a8SLen Brown 	 * Now we can parse the control methods. We always parse
9895b482a8SLen Brown 	 * them here for a sanity check, and if configured for
9995b482a8SLen Brown 	 * just-in-time parsing, we delete the control method
10095b482a8SLen Brown 	 * parse trees.
10195b482a8SLen Brown 	 */
10295b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
10322b5afceSBob Moore 			  "**** Begin Table Object Initialization\n"));
10495b482a8SLen Brown 
1058633db6bSLv Zheng 	acpi_ex_enter_interpreter();
10695b482a8SLen Brown 	status = acpi_ds_initialize_objects(table_index, node);
1078633db6bSLv Zheng 	acpi_ex_exit_interpreter();
10895b482a8SLen Brown 
10995b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
11022b5afceSBob Moore 			  "**** Completed Table Object Initialization\n"));
11195b482a8SLen Brown 
11295b482a8SLen Brown 	return_ACPI_STATUS(status);
11395b482a8SLen Brown }
11495b482a8SLen Brown 
11595b482a8SLen Brown #ifdef ACPI_OBSOLETE_FUNCTIONS
11695b482a8SLen Brown /*******************************************************************************
11795b482a8SLen Brown  *
11895b482a8SLen Brown  * FUNCTION:    acpi_load_namespace
11995b482a8SLen Brown  *
12095b482a8SLen Brown  * PARAMETERS:  None
12195b482a8SLen Brown  *
12295b482a8SLen Brown  * RETURN:      Status
12395b482a8SLen Brown  *
12495b482a8SLen Brown  * DESCRIPTION: Load the name space from what ever is pointed to by DSDT.
12595b482a8SLen Brown  *              (DSDT points to either the BIOS or a buffer.)
12695b482a8SLen Brown  *
12795b482a8SLen Brown  ******************************************************************************/
12895b482a8SLen Brown 
acpi_ns_load_namespace(void)12995b482a8SLen Brown acpi_status acpi_ns_load_namespace(void)
13095b482a8SLen Brown {
13195b482a8SLen Brown 	acpi_status status;
13295b482a8SLen Brown 
13395b482a8SLen Brown 	ACPI_FUNCTION_TRACE(acpi_load_name_space);
13495b482a8SLen Brown 
13595b482a8SLen Brown 	/* There must be at least a DSDT installed */
13695b482a8SLen Brown 
13795b482a8SLen Brown 	if (acpi_gbl_DSDT == NULL) {
13895b482a8SLen Brown 		ACPI_ERROR((AE_INFO, "DSDT is not in memory"));
13995b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_ACPI_TABLES);
14095b482a8SLen Brown 	}
14195b482a8SLen Brown 
14295b482a8SLen Brown 	/*
14395b482a8SLen Brown 	 * Load the namespace. The DSDT is required,
14495b482a8SLen Brown 	 * but the SSDT and PSDT tables are optional.
14595b482a8SLen Brown 	 */
14695b482a8SLen Brown 	status = acpi_ns_load_table_by_type(ACPI_TABLE_ID_DSDT);
14795b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
14895b482a8SLen Brown 		return_ACPI_STATUS(status);
14995b482a8SLen Brown 	}
15095b482a8SLen Brown 
15195b482a8SLen Brown 	/* Ignore exceptions from these */
15295b482a8SLen Brown 
15395b482a8SLen Brown 	(void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_SSDT);
15495b482a8SLen Brown 	(void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_PSDT);
15595b482a8SLen Brown 
15695b482a8SLen Brown 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
15795b482a8SLen Brown 			      "ACPI Namespace successfully loaded at root %p\n",
15895b482a8SLen Brown 			      acpi_gbl_root_node));
15995b482a8SLen Brown 
16095b482a8SLen Brown 	return_ACPI_STATUS(status);
16195b482a8SLen Brown }
16295b482a8SLen Brown #endif
16395b482a8SLen Brown 
16495b482a8SLen Brown #ifdef ACPI_FUTURE_IMPLEMENTATION
16595b482a8SLen Brown /*******************************************************************************
16695b482a8SLen Brown  *
16795b482a8SLen Brown  * FUNCTION:    acpi_ns_delete_subtree
16895b482a8SLen Brown  *
16995b482a8SLen Brown  * PARAMETERS:  start_handle        - Handle in namespace where search begins
17095b482a8SLen Brown  *
17195b482a8SLen Brown  * RETURNS      Status
17295b482a8SLen Brown  *
17395b482a8SLen Brown  * DESCRIPTION: Walks the namespace starting at the given handle and deletes
17495b482a8SLen Brown  *              all objects, entries, and scopes in the entire subtree.
17595b482a8SLen Brown  *
17695b482a8SLen Brown  *              Namespace/Interpreter should be locked or the subsystem should
17795b482a8SLen Brown  *              be in shutdown before this routine is called.
17895b482a8SLen Brown  *
17995b482a8SLen Brown  ******************************************************************************/
18095b482a8SLen Brown 
acpi_ns_delete_subtree(acpi_handle start_handle)18195b482a8SLen Brown static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle)
18295b482a8SLen Brown {
18395b482a8SLen Brown 	acpi_status status;
18495b482a8SLen Brown 	acpi_handle child_handle;
18595b482a8SLen Brown 	acpi_handle parent_handle;
18695b482a8SLen Brown 	acpi_handle next_child_handle;
18795b482a8SLen Brown 	acpi_handle dummy;
18895b482a8SLen Brown 	u32 level;
18995b482a8SLen Brown 
19095b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ns_delete_subtree);
19195b482a8SLen Brown 
19295b482a8SLen Brown 	parent_handle = start_handle;
19395b482a8SLen Brown 	child_handle = NULL;
19495b482a8SLen Brown 	level = 1;
19595b482a8SLen Brown 
19695b482a8SLen Brown 	/*
19795b482a8SLen Brown 	 * Traverse the tree of objects until we bubble back up
19895b482a8SLen Brown 	 * to where we started.
19995b482a8SLen Brown 	 */
20095b482a8SLen Brown 	while (level > 0) {
20195b482a8SLen Brown 
20295b482a8SLen Brown 		/* Attempt to get the next object in this scope */
20395b482a8SLen Brown 
20495b482a8SLen Brown 		status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle,
20595b482a8SLen Brown 					      child_handle, &next_child_handle);
20695b482a8SLen Brown 
20795b482a8SLen Brown 		child_handle = next_child_handle;
20895b482a8SLen Brown 
20995b482a8SLen Brown 		/* Did we get a new object? */
21095b482a8SLen Brown 
21195b482a8SLen Brown 		if (ACPI_SUCCESS(status)) {
21295b482a8SLen Brown 
21395b482a8SLen Brown 			/* Check if this object has any children */
21495b482a8SLen Brown 
21595b482a8SLen Brown 			if (ACPI_SUCCESS
21695b482a8SLen Brown 			    (acpi_get_next_object
21795b482a8SLen Brown 			     (ACPI_TYPE_ANY, child_handle, NULL, &dummy))) {
21895b482a8SLen Brown 				/*
21995b482a8SLen Brown 				 * There is at least one child of this object,
22095b482a8SLen Brown 				 * visit the object
22195b482a8SLen Brown 				 */
22295b482a8SLen Brown 				level++;
22395b482a8SLen Brown 				parent_handle = child_handle;
22495b482a8SLen Brown 				child_handle = NULL;
22595b482a8SLen Brown 			}
22695b482a8SLen Brown 		} else {
22795b482a8SLen Brown 			/*
22895b482a8SLen Brown 			 * No more children in this object, go back up to
22995b482a8SLen Brown 			 * the object's parent
23095b482a8SLen Brown 			 */
23195b482a8SLen Brown 			level--;
23295b482a8SLen Brown 
23395b482a8SLen Brown 			/* Delete all children now */
23495b482a8SLen Brown 
23595b482a8SLen Brown 			acpi_ns_delete_children(child_handle);
23695b482a8SLen Brown 
23795b482a8SLen Brown 			child_handle = parent_handle;
23895b482a8SLen Brown 			status = acpi_get_parent(parent_handle, &parent_handle);
23995b482a8SLen Brown 			if (ACPI_FAILURE(status)) {
24095b482a8SLen Brown 				return_ACPI_STATUS(status);
24195b482a8SLen Brown 			}
24295b482a8SLen Brown 		}
24395b482a8SLen Brown 	}
24495b482a8SLen Brown 
24595b482a8SLen Brown 	/* Now delete the starting object, and we are done */
24695b482a8SLen Brown 
2478e4319c4SBob Moore 	acpi_ns_remove_node(child_handle);
24895b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
24995b482a8SLen Brown }
25095b482a8SLen Brown 
25195b482a8SLen Brown /*******************************************************************************
25295b482a8SLen Brown  *
25395b482a8SLen Brown  *  FUNCTION:       acpi_ns_unload_name_space
25495b482a8SLen Brown  *
255ba494beeSBob Moore  *  PARAMETERS:     handle          - Root of namespace subtree to be deleted
25695b482a8SLen Brown  *
25795b482a8SLen Brown  *  RETURN:         Status
25895b482a8SLen Brown  *
25995b482a8SLen Brown  *  DESCRIPTION:    Shrinks the namespace, typically in response to an undocking
26095b482a8SLen Brown  *                  event. Deletes an entire subtree starting from (and
26195b482a8SLen Brown  *                  including) the given handle.
26295b482a8SLen Brown  *
26395b482a8SLen Brown  ******************************************************************************/
26495b482a8SLen Brown 
acpi_ns_unload_namespace(acpi_handle handle)26595b482a8SLen Brown acpi_status acpi_ns_unload_namespace(acpi_handle handle)
26695b482a8SLen Brown {
26795b482a8SLen Brown 	acpi_status status;
26895b482a8SLen Brown 
26995b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ns_unload_name_space);
27095b482a8SLen Brown 
27195b482a8SLen Brown 	/* Parameter validation */
27295b482a8SLen Brown 
27395b482a8SLen Brown 	if (!acpi_gbl_root_node) {
27495b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_NAMESPACE);
27595b482a8SLen Brown 	}
27695b482a8SLen Brown 
27795b482a8SLen Brown 	if (!handle) {
27895b482a8SLen Brown 		return_ACPI_STATUS(AE_BAD_PARAMETER);
27995b482a8SLen Brown 	}
28095b482a8SLen Brown 
28195b482a8SLen Brown 	/* This function does the real work */
28295b482a8SLen Brown 
28395b482a8SLen Brown 	status = acpi_ns_delete_subtree(handle);
28495b482a8SLen Brown 	return_ACPI_STATUS(status);
28595b482a8SLen Brown }
28695b482a8SLen Brown #endif
287