xref: /OK3568_Linux_fs/kernel/drivers/acpi/acpica/nsload.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /******************************************************************************
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Module Name: nsload - namespace loading/expanding/contracting procedures
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2000 - 2020, Intel Corp.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *****************************************************************************/
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <acpi/acpi.h>
11*4882a593Smuzhiyun #include "accommon.h"
12*4882a593Smuzhiyun #include "acnamesp.h"
13*4882a593Smuzhiyun #include "acdispat.h"
14*4882a593Smuzhiyun #include "actables.h"
15*4882a593Smuzhiyun #include "acinterp.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define _COMPONENT          ACPI_NAMESPACE
18*4882a593Smuzhiyun ACPI_MODULE_NAME("nsload")
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /* Local prototypes */
21*4882a593Smuzhiyun #ifdef ACPI_FUTURE_IMPLEMENTATION
22*4882a593Smuzhiyun acpi_status acpi_ns_unload_namespace(acpi_handle handle);
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
25*4882a593Smuzhiyun #endif
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*******************************************************************************
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * FUNCTION:    acpi_ns_load_table
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  * PARAMETERS:  table_index     - Index for table to be loaded
32*4882a593Smuzhiyun  *              node            - Owning NS node
33*4882a593Smuzhiyun  *
34*4882a593Smuzhiyun  * RETURN:      Status
35*4882a593Smuzhiyun  *
36*4882a593Smuzhiyun  * DESCRIPTION: Load one ACPI table into the namespace
37*4882a593Smuzhiyun  *
38*4882a593Smuzhiyun  ******************************************************************************/
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun acpi_status
acpi_ns_load_table(u32 table_index,struct acpi_namespace_node * node)41*4882a593Smuzhiyun acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	acpi_status status;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE(ns_load_table);
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	/* If table already loaded into namespace, just return */
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	if (acpi_tb_is_table_loaded(table_index)) {
50*4882a593Smuzhiyun 		status = AE_ALREADY_EXISTS;
51*4882a593Smuzhiyun 		goto unlock;
52*4882a593Smuzhiyun 	}
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
55*4882a593Smuzhiyun 			  "**** Loading table into namespace ****\n"));
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	status = acpi_tb_allocate_owner_id(table_index);
58*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
59*4882a593Smuzhiyun 		goto unlock;
60*4882a593Smuzhiyun 	}
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	/*
63*4882a593Smuzhiyun 	 * Parse the table and load the namespace with all named
64*4882a593Smuzhiyun 	 * objects found within. Control methods are NOT parsed
65*4882a593Smuzhiyun 	 * at this time. In fact, the control methods cannot be
66*4882a593Smuzhiyun 	 * parsed until the entire namespace is loaded, because
67*4882a593Smuzhiyun 	 * if a control method makes a forward reference (call)
68*4882a593Smuzhiyun 	 * to another control method, we can't continue parsing
69*4882a593Smuzhiyun 	 * because we don't know how many arguments to parse next!
70*4882a593Smuzhiyun 	 */
71*4882a593Smuzhiyun 	status = acpi_ns_parse_table(table_index, node);
72*4882a593Smuzhiyun 	if (ACPI_SUCCESS(status)) {
73*4882a593Smuzhiyun 		acpi_tb_set_table_loaded_flag(table_index, TRUE);
74*4882a593Smuzhiyun 	} else {
75*4882a593Smuzhiyun 		/*
76*4882a593Smuzhiyun 		 * On error, delete any namespace objects created by this table.
77*4882a593Smuzhiyun 		 * We cannot initialize these objects, so delete them. There are
78*4882a593Smuzhiyun 		 * a couple of especially bad cases:
79*4882a593Smuzhiyun 		 * AE_ALREADY_EXISTS - namespace collision.
80*4882a593Smuzhiyun 		 * AE_NOT_FOUND - the target of a Scope operator does not
81*4882a593Smuzhiyun 		 * exist. This target of Scope must already exist in the
82*4882a593Smuzhiyun 		 * namespace, as per the ACPI specification.
83*4882a593Smuzhiyun 		 */
84*4882a593Smuzhiyun 		acpi_ns_delete_namespace_by_owner(acpi_gbl_root_table_list.
85*4882a593Smuzhiyun 						  tables[table_index].owner_id);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 		acpi_tb_release_owner_id(table_index);
88*4882a593Smuzhiyun 		return_ACPI_STATUS(status);
89*4882a593Smuzhiyun 	}
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun unlock:
92*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
93*4882a593Smuzhiyun 		return_ACPI_STATUS(status);
94*4882a593Smuzhiyun 	}
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	/*
97*4882a593Smuzhiyun 	 * Now we can parse the control methods. We always parse
98*4882a593Smuzhiyun 	 * them here for a sanity check, and if configured for
99*4882a593Smuzhiyun 	 * just-in-time parsing, we delete the control method
100*4882a593Smuzhiyun 	 * parse trees.
101*4882a593Smuzhiyun 	 */
102*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
103*4882a593Smuzhiyun 			  "**** Begin Table Object Initialization\n"));
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	acpi_ex_enter_interpreter();
106*4882a593Smuzhiyun 	status = acpi_ds_initialize_objects(table_index, node);
107*4882a593Smuzhiyun 	acpi_ex_exit_interpreter();
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
110*4882a593Smuzhiyun 			  "**** Completed Table Object Initialization\n"));
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	return_ACPI_STATUS(status);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun #ifdef ACPI_OBSOLETE_FUNCTIONS
116*4882a593Smuzhiyun /*******************************************************************************
117*4882a593Smuzhiyun  *
118*4882a593Smuzhiyun  * FUNCTION:    acpi_load_namespace
119*4882a593Smuzhiyun  *
120*4882a593Smuzhiyun  * PARAMETERS:  None
121*4882a593Smuzhiyun  *
122*4882a593Smuzhiyun  * RETURN:      Status
123*4882a593Smuzhiyun  *
124*4882a593Smuzhiyun  * DESCRIPTION: Load the name space from what ever is pointed to by DSDT.
125*4882a593Smuzhiyun  *              (DSDT points to either the BIOS or a buffer.)
126*4882a593Smuzhiyun  *
127*4882a593Smuzhiyun  ******************************************************************************/
128*4882a593Smuzhiyun 
acpi_ns_load_namespace(void)129*4882a593Smuzhiyun acpi_status acpi_ns_load_namespace(void)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	acpi_status status;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE(acpi_load_name_space);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	/* There must be at least a DSDT installed */
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	if (acpi_gbl_DSDT == NULL) {
138*4882a593Smuzhiyun 		ACPI_ERROR((AE_INFO, "DSDT is not in memory"));
139*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_NO_ACPI_TABLES);
140*4882a593Smuzhiyun 	}
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	/*
143*4882a593Smuzhiyun 	 * Load the namespace. The DSDT is required,
144*4882a593Smuzhiyun 	 * but the SSDT and PSDT tables are optional.
145*4882a593Smuzhiyun 	 */
146*4882a593Smuzhiyun 	status = acpi_ns_load_table_by_type(ACPI_TABLE_ID_DSDT);
147*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
148*4882a593Smuzhiyun 		return_ACPI_STATUS(status);
149*4882a593Smuzhiyun 	}
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	/* Ignore exceptions from these */
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	(void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_SSDT);
154*4882a593Smuzhiyun 	(void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_PSDT);
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
157*4882a593Smuzhiyun 			      "ACPI Namespace successfully loaded at root %p\n",
158*4882a593Smuzhiyun 			      acpi_gbl_root_node));
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	return_ACPI_STATUS(status);
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun #endif
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun #ifdef ACPI_FUTURE_IMPLEMENTATION
165*4882a593Smuzhiyun /*******************************************************************************
166*4882a593Smuzhiyun  *
167*4882a593Smuzhiyun  * FUNCTION:    acpi_ns_delete_subtree
168*4882a593Smuzhiyun  *
169*4882a593Smuzhiyun  * PARAMETERS:  start_handle        - Handle in namespace where search begins
170*4882a593Smuzhiyun  *
171*4882a593Smuzhiyun  * RETURNS      Status
172*4882a593Smuzhiyun  *
173*4882a593Smuzhiyun  * DESCRIPTION: Walks the namespace starting at the given handle and deletes
174*4882a593Smuzhiyun  *              all objects, entries, and scopes in the entire subtree.
175*4882a593Smuzhiyun  *
176*4882a593Smuzhiyun  *              Namespace/Interpreter should be locked or the subsystem should
177*4882a593Smuzhiyun  *              be in shutdown before this routine is called.
178*4882a593Smuzhiyun  *
179*4882a593Smuzhiyun  ******************************************************************************/
180*4882a593Smuzhiyun 
acpi_ns_delete_subtree(acpi_handle start_handle)181*4882a593Smuzhiyun static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	acpi_status status;
184*4882a593Smuzhiyun 	acpi_handle child_handle;
185*4882a593Smuzhiyun 	acpi_handle parent_handle;
186*4882a593Smuzhiyun 	acpi_handle next_child_handle;
187*4882a593Smuzhiyun 	acpi_handle dummy;
188*4882a593Smuzhiyun 	u32 level;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE(ns_delete_subtree);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	parent_handle = start_handle;
193*4882a593Smuzhiyun 	child_handle = NULL;
194*4882a593Smuzhiyun 	level = 1;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	/*
197*4882a593Smuzhiyun 	 * Traverse the tree of objects until we bubble back up
198*4882a593Smuzhiyun 	 * to where we started.
199*4882a593Smuzhiyun 	 */
200*4882a593Smuzhiyun 	while (level > 0) {
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 		/* Attempt to get the next object in this scope */
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 		status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle,
205*4882a593Smuzhiyun 					      child_handle, &next_child_handle);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 		child_handle = next_child_handle;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 		/* Did we get a new object? */
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 		if (ACPI_SUCCESS(status)) {
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 			/* Check if this object has any children */
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 			if (ACPI_SUCCESS
216*4882a593Smuzhiyun 			    (acpi_get_next_object
217*4882a593Smuzhiyun 			     (ACPI_TYPE_ANY, child_handle, NULL, &dummy))) {
218*4882a593Smuzhiyun 				/*
219*4882a593Smuzhiyun 				 * There is at least one child of this object,
220*4882a593Smuzhiyun 				 * visit the object
221*4882a593Smuzhiyun 				 */
222*4882a593Smuzhiyun 				level++;
223*4882a593Smuzhiyun 				parent_handle = child_handle;
224*4882a593Smuzhiyun 				child_handle = NULL;
225*4882a593Smuzhiyun 			}
226*4882a593Smuzhiyun 		} else {
227*4882a593Smuzhiyun 			/*
228*4882a593Smuzhiyun 			 * No more children in this object, go back up to
229*4882a593Smuzhiyun 			 * the object's parent
230*4882a593Smuzhiyun 			 */
231*4882a593Smuzhiyun 			level--;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 			/* Delete all children now */
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 			acpi_ns_delete_children(child_handle);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 			child_handle = parent_handle;
238*4882a593Smuzhiyun 			status = acpi_get_parent(parent_handle, &parent_handle);
239*4882a593Smuzhiyun 			if (ACPI_FAILURE(status)) {
240*4882a593Smuzhiyun 				return_ACPI_STATUS(status);
241*4882a593Smuzhiyun 			}
242*4882a593Smuzhiyun 		}
243*4882a593Smuzhiyun 	}
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	/* Now delete the starting object, and we are done */
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	acpi_ns_remove_node(child_handle);
248*4882a593Smuzhiyun 	return_ACPI_STATUS(AE_OK);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun /*******************************************************************************
252*4882a593Smuzhiyun  *
253*4882a593Smuzhiyun  *  FUNCTION:       acpi_ns_unload_name_space
254*4882a593Smuzhiyun  *
255*4882a593Smuzhiyun  *  PARAMETERS:     handle          - Root of namespace subtree to be deleted
256*4882a593Smuzhiyun  *
257*4882a593Smuzhiyun  *  RETURN:         Status
258*4882a593Smuzhiyun  *
259*4882a593Smuzhiyun  *  DESCRIPTION:    Shrinks the namespace, typically in response to an undocking
260*4882a593Smuzhiyun  *                  event. Deletes an entire subtree starting from (and
261*4882a593Smuzhiyun  *                  including) the given handle.
262*4882a593Smuzhiyun  *
263*4882a593Smuzhiyun  ******************************************************************************/
264*4882a593Smuzhiyun 
acpi_ns_unload_namespace(acpi_handle handle)265*4882a593Smuzhiyun acpi_status acpi_ns_unload_namespace(acpi_handle handle)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	acpi_status status;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE(ns_unload_name_space);
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	/* Parameter validation */
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	if (!acpi_gbl_root_node) {
274*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_NO_NAMESPACE);
275*4882a593Smuzhiyun 	}
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	if (!handle) {
278*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_BAD_PARAMETER);
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	/* This function does the real work */
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	status = acpi_ns_delete_subtree(handle);
284*4882a593Smuzhiyun 	return_ACPI_STATUS(status);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun #endif
287