aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpica/nswalk.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/acpica/nswalk.c')
-rw-r--r--drivers/acpi/acpica/nswalk.c200
1 files changed, 117 insertions, 83 deletions
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index 35539df5c75d..d7e6b52b4482 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -165,24 +165,27 @@ struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
165 * max_depth - Depth to which search is to reach 165 * max_depth - Depth to which search is to reach
166 * Flags - Whether to unlock the NS before invoking 166 * Flags - Whether to unlock the NS before invoking
167 * the callback routine 167 * the callback routine
168 * user_function - Called when an object of "Type" is found 168 * pre_order_visit - Called during tree pre-order visit
169 * Context - Passed to user function 169 * when an object of "Type" is found
170 * return_value - from the user_function if terminated early. 170 * post_order_visit - Called during tree post-order visit
171 * Otherwise, returns NULL. 171 * when an object of "Type" is found
172 * Context - Passed to user function(s) above
173 * return_value - from the user_function if terminated
174 * early. Otherwise, returns NULL.
172 * RETURNS: Status 175 * RETURNS: Status
173 * 176 *
174 * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, 177 * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
175 * starting (and ending) at the node specified by start_handle. 178 * starting (and ending) at the node specified by start_handle.
176 * The user_function is called whenever a node that matches 179 * The callback function is called whenever a node that matches
177 * the type parameter is found. If the user function returns 180 * the type parameter is found. If the callback function returns
178 * a non-zero value, the search is terminated immediately and 181 * a non-zero value, the search is terminated immediately and
179 * this value is returned to the caller. 182 * this value is returned to the caller.
180 * 183 *
181 * The point of this procedure is to provide a generic namespace 184 * The point of this procedure is to provide a generic namespace
182 * walk routine that can be called from multiple places to 185 * walk routine that can be called from multiple places to
183 * provide multiple services; the User Function can be tailored 186 * provide multiple services; the callback function(s) can be
184 * to each task, whether it is a print function, a compare 187 * tailored to each task, whether it is a print function,
185 * function, etc. 188 * a compare function, etc.
186 * 189 *
187 ******************************************************************************/ 190 ******************************************************************************/
188 191
@@ -191,7 +194,8 @@ acpi_ns_walk_namespace(acpi_object_type type,
191 acpi_handle start_node, 194 acpi_handle start_node,
192 u32 max_depth, 195 u32 max_depth,
193 u32 flags, 196 u32 flags,
194 acpi_walk_callback user_function, 197 acpi_walk_callback pre_order_visit,
198 acpi_walk_callback post_order_visit,
195 void *context, void **return_value) 199 void *context, void **return_value)
196{ 200{
197 acpi_status status; 201 acpi_status status;
@@ -200,6 +204,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
200 struct acpi_namespace_node *parent_node; 204 struct acpi_namespace_node *parent_node;
201 acpi_object_type child_type; 205 acpi_object_type child_type;
202 u32 level; 206 u32 level;
207 u8 node_previously_visited = FALSE;
203 208
204 ACPI_FUNCTION_TRACE(ns_walk_namespace); 209 ACPI_FUNCTION_TRACE(ns_walk_namespace);
205 210
@@ -212,7 +217,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
212 /* Null child means "get first node" */ 217 /* Null child means "get first node" */
213 218
214 parent_node = start_node; 219 parent_node = start_node;
215 child_node = NULL; 220 child_node = acpi_ns_get_next_node(parent_node, NULL);
216 child_type = ACPI_TYPE_ANY; 221 child_type = ACPI_TYPE_ANY;
217 level = 1; 222 level = 1;
218 223
@@ -221,102 +226,129 @@ acpi_ns_walk_namespace(acpi_object_type type,
221 * started. When Level is zero, the loop is done because we have 226 * started. When Level is zero, the loop is done because we have
222 * bubbled up to (and passed) the original parent handle (start_entry) 227 * bubbled up to (and passed) the original parent handle (start_entry)
223 */ 228 */
224 while (level > 0) { 229 while (level > 0 && child_node) {
230 status = AE_OK;
225 231
226 /* Get the next node in this scope. Null if not found */ 232 /* Found next child, get the type if we are not searching for ANY */
227 233
228 status = AE_OK; 234 if (type != ACPI_TYPE_ANY) {
229 child_node = acpi_ns_get_next_node(parent_node, child_node); 235 child_type = child_node->type;
230 if (child_node) { 236 }
231 237
232 /* Found next child, get the type if we are not searching for ANY */ 238 /*
239 * Ignore all temporary namespace nodes (created during control
240 * method execution) unless told otherwise. These temporary nodes
241 * can cause a race condition because they can be deleted during
242 * the execution of the user function (if the namespace is
243 * unlocked before invocation of the user function.) Only the
244 * debugger namespace dump will examine the temporary nodes.
245 */
246 if ((child_node->flags & ANOBJ_TEMPORARY) &&
247 !(flags & ACPI_NS_WALK_TEMP_NODES)) {
248 status = AE_CTRL_DEPTH;
249 }
233 250
234 if (type != ACPI_TYPE_ANY) { 251 /* Type must match requested type */
235 child_type = child_node->type;
236 }
237 252
253 else if (child_type == type) {
238 /* 254 /*
239 * Ignore all temporary namespace nodes (created during control 255 * Found a matching node, invoke the user callback function.
240 * method execution) unless told otherwise. These temporary nodes 256 * Unlock the namespace if flag is set.
241 * can cause a race condition because they can be deleted during
242 * the execution of the user function (if the namespace is
243 * unlocked before invocation of the user function.) Only the
244 * debugger namespace dump will examine the temporary nodes.
245 */ 257 */
246 if ((child_node->flags & ANOBJ_TEMPORARY) && 258 if (flags & ACPI_NS_WALK_UNLOCK) {
247 !(flags & ACPI_NS_WALK_TEMP_NODES)) { 259 mutex_status =
248 status = AE_CTRL_DEPTH; 260 acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
261 if (ACPI_FAILURE(mutex_status)) {
262 return_ACPI_STATUS(mutex_status);
263 }
249 } 264 }
250 265
251 /* Type must match requested type */ 266 /*
252 267 * Invoke the user function, either pre-order or post-order
253 else if (child_type == type) { 268 * or both.
254 /* 269 */
255 * Found a matching node, invoke the user callback function. 270 if (!node_previously_visited) {
256 * Unlock the namespace if flag is set. 271 if (pre_order_visit) {
257 */ 272 status =
258 if (flags & ACPI_NS_WALK_UNLOCK) { 273 pre_order_visit(child_node, level,
259 mutex_status = 274 context,
260 acpi_ut_release_mutex 275 return_value);
261 (ACPI_MTX_NAMESPACE);
262 if (ACPI_FAILURE(mutex_status)) {
263 return_ACPI_STATUS
264 (mutex_status);
265 }
266 } 276 }
277 } else {
278 if (post_order_visit) {
279 status =
280 post_order_visit(child_node, level,
281 context,
282 return_value);
283 }
284 }
267 285
268 status = 286 if (flags & ACPI_NS_WALK_UNLOCK) {
269 user_function(child_node, level, context, 287 mutex_status =
270 return_value); 288 acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
271 289 if (ACPI_FAILURE(mutex_status)) {
272 if (flags & ACPI_NS_WALK_UNLOCK) { 290 return_ACPI_STATUS(mutex_status);
273 mutex_status =
274 acpi_ut_acquire_mutex
275 (ACPI_MTX_NAMESPACE);
276 if (ACPI_FAILURE(mutex_status)) {
277 return_ACPI_STATUS
278 (mutex_status);
279 }
280 } 291 }
292 }
281 293
282 switch (status) { 294 switch (status) {
283 case AE_OK: 295 case AE_OK:
284 case AE_CTRL_DEPTH: 296 case AE_CTRL_DEPTH:
285 297
286 /* Just keep going */ 298 /* Just keep going */
287 break; 299 break;
288 300
289 case AE_CTRL_TERMINATE: 301 case AE_CTRL_TERMINATE:
290 302
291 /* Exit now, with OK status */ 303 /* Exit now, with OK status */
292 304
293 return_ACPI_STATUS(AE_OK); 305 return_ACPI_STATUS(AE_OK);
294 306
295 default: 307 default:
296 308
297 /* All others are valid exceptions */ 309 /* All others are valid exceptions */
298 310
299 return_ACPI_STATUS(status); 311 return_ACPI_STATUS(status);
300 } 312 }
313 }
314
315 /*
316 * Depth first search: Attempt to go down another level in the
317 * namespace if we are allowed to. Don't go any further if we have
318 * reached the caller specified maximum depth or if the user
319 * function has specified that the maximum depth has been reached.
320 */
321 if (!node_previously_visited &&
322 (level < max_depth) && (status != AE_CTRL_DEPTH)) {
323 if (child_node->child) {
324
325 /* There is at least one child of this node, visit it */
326
327 level++;
328 parent_node = child_node;
329 child_node =
330 acpi_ns_get_next_node(parent_node, NULL);
331 continue;
301 } 332 }
333 }
302 334
303 /* 335 /* No more children, re-visit this node */
304 * Depth first search: Attempt to go down another level in the
305 * namespace if we are allowed to. Don't go any further if we have
306 * reached the caller specified maximum depth or if the user
307 * function has specified that the maximum depth has been reached.
308 */
309 if ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
310 if (child_node->child) {
311 336
312 /* There is at least one child of this node, visit it */ 337 if (!node_previously_visited) {
338 node_previously_visited = TRUE;
339 continue;
340 }
313 341
314 level++; 342 /* No more children, visit peers */
315 parent_node = child_node; 343
316 child_node = NULL; 344 child_node = acpi_ns_get_next_node(parent_node, child_node);
317 } 345 if (child_node) {
318 } 346 node_previously_visited = FALSE;
319 } else { 347 }
348
349 /* No peers, re-visit parent */
350
351 else {
320 /* 352 /*
321 * No more children of this node (acpi_ns_get_next_node failed), go 353 * No more children of this node (acpi_ns_get_next_node failed), go
322 * back upwards in the namespace tree to the node's parent. 354 * back upwards in the namespace tree to the node's parent.
@@ -324,6 +356,8 @@ acpi_ns_walk_namespace(acpi_object_type type,
324 level--; 356 level--;
325 child_node = parent_node; 357 child_node = parent_node;
326 parent_node = acpi_ns_get_parent_node(parent_node); 358 parent_node = acpi_ns_get_parent_node(parent_node);
359
360 node_previously_visited = TRUE;
327 } 361 }
328 } 362 }
329 363