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