Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 : : /******************************************************************************
3 : : *
4 : : * Module Name: nswalk - Functions for walking the ACPI namespace
5 : : *
6 : : * Copyright (C) 2000 - 2020, Intel Corp.
7 : : *
8 : : *****************************************************************************/
9 : :
10 : : #include <acpi/acpi.h>
11 : : #include "accommon.h"
12 : : #include "acnamesp.h"
13 : :
14 : : #define _COMPONENT ACPI_NAMESPACE
15 : : ACPI_MODULE_NAME("nswalk")
16 : :
17 : : /*******************************************************************************
18 : : *
19 : : * FUNCTION: acpi_ns_get_next_node
20 : : *
21 : : * PARAMETERS: parent_node - Parent node whose children we are
22 : : * getting
23 : : * child_node - Previous child that was found.
24 : : * The NEXT child will be returned
25 : : *
26 : : * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if
27 : : * none is found.
28 : : *
29 : : * DESCRIPTION: Return the next peer node within the namespace. If Handle
30 : : * is valid, Scope is ignored. Otherwise, the first node
31 : : * within Scope is returned.
32 : : *
33 : : ******************************************************************************/
34 : 111552 : struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
35 : : *parent_node,
36 : : struct acpi_namespace_node
37 : : *child_node)
38 : : {
39 : 111552 : ACPI_FUNCTION_ENTRY();
40 : :
41 [ + + ]: 2499 : if (!child_node) {
42 : :
43 : : /* It's really the parent's _scope_ that we want */
44 : :
45 : 2100 : return (parent_node->child);
46 : : }
47 : :
48 : : /* Otherwise just return the next peer */
49 : :
50 : 399 : return (child_node->peer);
51 : : }
52 : :
53 : : /*******************************************************************************
54 : : *
55 : : * FUNCTION: acpi_ns_get_next_node_typed
56 : : *
57 : : * PARAMETERS: type - Type of node to be searched for
58 : : * parent_node - Parent node whose children we are
59 : : * getting
60 : : * child_node - Previous child that was found.
61 : : * The NEXT child will be returned
62 : : *
63 : : * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if
64 : : * none is found.
65 : : *
66 : : * DESCRIPTION: Return the next peer node within the namespace. If Handle
67 : : * is valid, Scope is ignored. Otherwise, the first node
68 : : * within Scope is returned.
69 : : *
70 : : ******************************************************************************/
71 : :
72 : 0 : struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
73 : : struct
74 : : acpi_namespace_node
75 : : *parent_node,
76 : : struct
77 : : acpi_namespace_node
78 : : *child_node)
79 : : {
80 : 0 : struct acpi_namespace_node *next_node = NULL;
81 : :
82 : 0 : ACPI_FUNCTION_ENTRY();
83 : :
84 [ # # ]: 0 : next_node = acpi_ns_get_next_node(parent_node, child_node);
85 : :
86 : :
87 : : /* If any type is OK, we are done */
88 : :
89 [ # # ]: 0 : if (type == ACPI_TYPE_ANY) {
90 : :
91 : : /* next_node is NULL if we are at the end-of-list */
92 : :
93 : : return (next_node);
94 : : }
95 : :
96 : : /* Must search for the node -- but within this scope only */
97 : :
98 [ # # ]: 0 : while (next_node) {
99 : :
100 : : /* If type matches, we are done */
101 : :
102 [ # # ]: 0 : if (next_node->type == type) {
103 : 0 : return (next_node);
104 : : }
105 : :
106 : : /* Otherwise, move on to the next peer node */
107 : :
108 : 0 : next_node = next_node->peer;
109 : : }
110 : :
111 : : /* Not found */
112 : :
113 : : return (NULL);
114 : : }
115 : :
116 : : /*******************************************************************************
117 : : *
118 : : * FUNCTION: acpi_ns_walk_namespace
119 : : *
120 : : * PARAMETERS: type - acpi_object_type to search for
121 : : * start_node - Handle in namespace where search begins
122 : : * max_depth - Depth to which search is to reach
123 : : * flags - Whether to unlock the NS before invoking
124 : : * the callback routine
125 : : * descending_callback - Called during tree descent
126 : : * when an object of "Type" is found
127 : : * ascending_callback - Called during tree ascent
128 : : * when an object of "Type" is found
129 : : * context - Passed to user function(s) above
130 : : * return_value - from the user_function if terminated
131 : : * early. Otherwise, returns NULL.
132 : : * RETURNS: Status
133 : : *
134 : : * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
135 : : * starting (and ending) at the node specified by start_handle.
136 : : * The callback function is called whenever a node that matches
137 : : * the type parameter is found. If the callback function returns
138 : : * a non-zero value, the search is terminated immediately and
139 : : * this value is returned to the caller.
140 : : *
141 : : * The point of this procedure is to provide a generic namespace
142 : : * walk routine that can be called from multiple places to
143 : : * provide multiple services; the callback function(s) can be
144 : : * tailored to each task, whether it is a print function,
145 : : * a compare function, etc.
146 : : *
147 : : ******************************************************************************/
148 : :
149 : : acpi_status
150 : 504 : acpi_ns_walk_namespace(acpi_object_type type,
151 : : acpi_handle start_node,
152 : : u32 max_depth,
153 : : u32 flags,
154 : : acpi_walk_callback descending_callback,
155 : : acpi_walk_callback ascending_callback,
156 : : void *context, void **return_value)
157 : : {
158 : 504 : acpi_status status;
159 : 504 : acpi_status mutex_status;
160 : 504 : struct acpi_namespace_node *child_node;
161 : 504 : struct acpi_namespace_node *parent_node;
162 : 504 : acpi_object_type child_type;
163 : 504 : u32 level;
164 : 504 : u8 node_previously_visited = FALSE;
165 : :
166 : 504 : ACPI_FUNCTION_TRACE(ns_walk_namespace);
167 : :
168 : : /* Special case for the namespace Root Node */
169 : :
170 [ + + ]: 504 : if (start_node == ACPI_ROOT_OBJECT) {
171 : 231 : start_node = acpi_gbl_root_node;
172 : : }
173 : :
174 : : /* Null child means "get first node" */
175 : :
176 : 504 : parent_node = start_node;
177 : 504 : child_node = acpi_ns_get_next_node(parent_node, NULL);
178 : 504 : child_type = ACPI_TYPE_ANY;
179 : 504 : level = 1;
180 : :
181 : : /*
182 : : * Traverse the tree of nodes until we bubble back up to where we
183 : : * started. When Level is zero, the loop is done because we have
184 : : * bubbled up to (and passed) the original parent handle (start_entry)
185 : : */
186 [ + + ]: 183582 : while (level > 0 && child_node) {
187 : 183078 : status = AE_OK;
188 : :
189 : : /* Found next child, get the type if we are not searching for ANY */
190 : :
191 [ + + ]: 183078 : if (type != ACPI_TYPE_ANY) {
192 : 97734 : child_type = child_node->type;
193 : : }
194 : :
195 : : /*
196 : : * Ignore all temporary namespace nodes (created during control
197 : : * method execution) unless told otherwise. These temporary nodes
198 : : * can cause a race condition because they can be deleted during
199 : : * the execution of the user function (if the namespace is
200 : : * unlocked before invocation of the user function.) Only the
201 : : * debugger namespace dump will examine the temporary nodes.
202 : : */
203 [ - + ]: 183078 : if ((child_node->flags & ANOBJ_TEMPORARY) &&
204 [ # # ]: 0 : !(flags & ACPI_NS_WALK_TEMP_NODES)) {
205 : : status = AE_CTRL_DEPTH;
206 : : }
207 : :
208 : : /* Type must match requested type */
209 : :
210 [ + + ]: 183078 : else if (child_type == type) {
211 : : /*
212 : : * Found a matching node, invoke the user callback function.
213 : : * Unlock the namespace if flag is set.
214 : : */
215 [ + + ]: 100506 : if (flags & ACPI_NS_WALK_UNLOCK) {
216 : 71484 : mutex_status =
217 : 71484 : acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
218 [ - + ]: 71484 : if (ACPI_FAILURE(mutex_status)) {
219 : 0 : return_ACPI_STATUS(mutex_status);
220 : : }
221 : : }
222 : :
223 : : /*
224 : : * Invoke the user function, either descending, ascending,
225 : : * or both.
226 : : */
227 [ + + ]: 100506 : if (!node_previously_visited) {
228 [ + - ]: 50253 : if (descending_callback) {
229 : 50253 : status =
230 : 50253 : descending_callback(child_node,
231 : : level, context,
232 : : return_value);
233 : : }
234 : : } else {
235 [ - + ]: 50253 : if (ascending_callback) {
236 : 0 : status =
237 : 0 : ascending_callback(child_node,
238 : : level, context,
239 : : return_value);
240 : : }
241 : : }
242 : :
243 [ + + ]: 100506 : if (flags & ACPI_NS_WALK_UNLOCK) {
244 : 71484 : mutex_status =
245 : 71484 : acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
246 [ - + ]: 71484 : if (ACPI_FAILURE(mutex_status)) {
247 : 0 : return_ACPI_STATUS(mutex_status);
248 : : }
249 : : }
250 : :
251 [ - + - ]: 100506 : switch (status) {
252 : : case AE_OK:
253 : : case AE_CTRL_DEPTH:
254 : :
255 : : /* Just keep going */
256 : : break;
257 : :
258 : : case AE_CTRL_TERMINATE:
259 : :
260 : : /* Exit now, with OK status */
261 : :
262 : : return_ACPI_STATUS(AE_OK);
263 : :
264 : 0 : default:
265 : :
266 : : /* All others are valid exceptions */
267 : :
268 : 0 : return_ACPI_STATUS(status);
269 : : }
270 : 82572 : }
271 : :
272 : : /*
273 : : * Depth first search: Attempt to go down another level in the
274 : : * namespace if we are allowed to. Don't go any further if we have
275 : : * reached the caller specified maximum depth or if the user
276 : : * function has specified that the maximum depth has been reached.
277 : : */
278 : 183078 : if (!node_previously_visited &&
279 [ + + + + ]: 183078 : (level < max_depth) && (status != AE_CTRL_DEPTH)) {
280 [ + + ]: 89460 : if (child_node->child) {
281 : :
282 : : /* There is at least one child of this node, visit it */
283 : :
284 : 17010 : level++;
285 : 17010 : parent_node = child_node;
286 : 17010 : child_node =
287 : : acpi_ns_get_next_node(parent_node, NULL);
288 : 17010 : continue;
289 : : }
290 : : }
291 : :
292 : : /* No more children, re-visit this node */
293 : :
294 [ + + ]: 166068 : if (!node_previously_visited) {
295 : 74529 : node_previously_visited = TRUE;
296 : 74529 : continue;
297 : : }
298 : :
299 : : /* No more children, visit peers */
300 : :
301 : 91539 : child_node = acpi_ns_get_next_node(parent_node, child_node);
302 [ + + ]: 91539 : if (child_node) {
303 : : node_previously_visited = FALSE;
304 : : }
305 : :
306 : : /* No peers, re-visit parent */
307 : :
308 : : else {
309 : : /*
310 : : * No more children of this node (acpi_ns_get_next_node failed), go
311 : : * back upwards in the namespace tree to the node's parent.
312 : : */
313 : 17514 : level--;
314 : 17514 : child_node = parent_node;
315 : 17514 : parent_node = parent_node->parent;
316 : :
317 : 17514 : node_previously_visited = TRUE;
318 : : }
319 : : }
320 : :
321 : : /* Complete walk, not terminated by user function */
322 : :
323 : : return_ACPI_STATUS(AE_OK);
324 : : }
|