1*95857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 295b482a8SLen Brown /****************************************************************************** 395b482a8SLen Brown * 495b482a8SLen Brown * Module Name: nswalk - Functions for walking the ACPI namespace 595b482a8SLen Brown * 6da6f8320SBob Moore * Copyright (C) 2000 - 2018, Intel Corp. 795b482a8SLen Brown * 8*95857638SErik Schmauss *****************************************************************************/ 995b482a8SLen Brown 1095b482a8SLen Brown #include <acpi/acpi.h> 11e2f7a777SLen Brown #include "accommon.h" 12e2f7a777SLen Brown #include "acnamesp.h" 1395b482a8SLen Brown 1495b482a8SLen Brown #define _COMPONENT ACPI_NAMESPACE 1595b482a8SLen Brown ACPI_MODULE_NAME("nswalk") 1695b482a8SLen Brown 1795b482a8SLen Brown /******************************************************************************* 1895b482a8SLen Brown * 1995b482a8SLen Brown * FUNCTION: acpi_ns_get_next_node 2095b482a8SLen Brown * 218c725bf9SBob Moore * PARAMETERS: parent_node - Parent node whose children we are 228c725bf9SBob Moore * getting 238c725bf9SBob Moore * child_node - Previous child that was found. 248c725bf9SBob Moore * The NEXT child will be returned 258c725bf9SBob Moore * 268c725bf9SBob Moore * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if 278c725bf9SBob Moore * none is found. 288c725bf9SBob Moore * 298c725bf9SBob Moore * DESCRIPTION: Return the next peer node within the namespace. If Handle 308c725bf9SBob Moore * is valid, Scope is ignored. Otherwise, the first node 318c725bf9SBob Moore * within Scope is returned. 328c725bf9SBob Moore * 338c725bf9SBob Moore ******************************************************************************/ 348c725bf9SBob Moore struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node 358c725bf9SBob Moore *parent_node, 368c725bf9SBob Moore struct acpi_namespace_node 378c725bf9SBob Moore *child_node) 388c725bf9SBob Moore { 398c725bf9SBob Moore ACPI_FUNCTION_ENTRY(); 408c725bf9SBob Moore 418c725bf9SBob Moore if (!child_node) { 428c725bf9SBob Moore 438c725bf9SBob Moore /* It's really the parent's _scope_ that we want */ 448c725bf9SBob Moore 459c0d7939SLv Zheng return (parent_node->child); 468c725bf9SBob Moore } 478c725bf9SBob Moore 488c725bf9SBob Moore /* Otherwise just return the next peer */ 498c725bf9SBob Moore 509c0d7939SLv Zheng return (child_node->peer); 518c725bf9SBob Moore } 528c725bf9SBob Moore 538c725bf9SBob Moore /******************************************************************************* 548c725bf9SBob Moore * 558c725bf9SBob Moore * FUNCTION: acpi_ns_get_next_node_typed 568c725bf9SBob Moore * 57ba494beeSBob Moore * PARAMETERS: type - Type of node to be searched for 5895b482a8SLen Brown * parent_node - Parent node whose children we are 5995b482a8SLen Brown * getting 6095b482a8SLen Brown * child_node - Previous child that was found. 6195b482a8SLen Brown * The NEXT child will be returned 6295b482a8SLen Brown * 6395b482a8SLen Brown * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if 6495b482a8SLen Brown * none is found. 6595b482a8SLen Brown * 6695b482a8SLen Brown * DESCRIPTION: Return the next peer node within the namespace. If Handle 6795b482a8SLen Brown * is valid, Scope is ignored. Otherwise, the first node 6895b482a8SLen Brown * within Scope is returned. 6995b482a8SLen Brown * 7095b482a8SLen Brown ******************************************************************************/ 718c725bf9SBob Moore 728c725bf9SBob Moore struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, 738c725bf9SBob Moore struct 748c725bf9SBob Moore acpi_namespace_node 758c725bf9SBob Moore *parent_node, 768c725bf9SBob Moore struct 778c725bf9SBob Moore acpi_namespace_node 7895b482a8SLen Brown *child_node) 7995b482a8SLen Brown { 8095b482a8SLen Brown struct acpi_namespace_node *next_node = NULL; 8195b482a8SLen Brown 8295b482a8SLen Brown ACPI_FUNCTION_ENTRY(); 8395b482a8SLen Brown 848c725bf9SBob Moore next_node = acpi_ns_get_next_node(parent_node, child_node); 8595b482a8SLen Brown 8695b482a8SLen Brown 8795b482a8SLen Brown /* If any type is OK, we are done */ 8895b482a8SLen Brown 8995b482a8SLen Brown if (type == ACPI_TYPE_ANY) { 9095b482a8SLen Brown 9195b482a8SLen Brown /* next_node is NULL if we are at the end-of-list */ 9295b482a8SLen Brown 9395b482a8SLen Brown return (next_node); 9495b482a8SLen Brown } 9595b482a8SLen Brown 9695b482a8SLen Brown /* Must search for the node -- but within this scope only */ 9795b482a8SLen Brown 9895b482a8SLen Brown while (next_node) { 9995b482a8SLen Brown 10095b482a8SLen Brown /* If type matches, we are done */ 10195b482a8SLen Brown 10295b482a8SLen Brown if (next_node->type == type) { 10395b482a8SLen Brown return (next_node); 10495b482a8SLen Brown } 10595b482a8SLen Brown 106c45b5c09SAlexey Starikovskiy /* Otherwise, move on to the next peer node */ 10795b482a8SLen Brown 108c45b5c09SAlexey Starikovskiy next_node = next_node->peer; 10995b482a8SLen Brown } 11095b482a8SLen Brown 11195b482a8SLen Brown /* Not found */ 11295b482a8SLen Brown 11395b482a8SLen Brown return (NULL); 11495b482a8SLen Brown } 11595b482a8SLen Brown 11695b482a8SLen Brown /******************************************************************************* 11795b482a8SLen Brown * 11895b482a8SLen Brown * FUNCTION: acpi_ns_walk_namespace 11995b482a8SLen Brown * 120ba494beeSBob Moore * PARAMETERS: type - acpi_object_type to search for 12195b482a8SLen Brown * start_node - Handle in namespace where search begins 12295b482a8SLen Brown * max_depth - Depth to which search is to reach 123ba494beeSBob Moore * flags - Whether to unlock the NS before invoking 12495b482a8SLen Brown * the callback routine 1254ef17507SBob Moore * descending_callback - Called during tree descent 1262263576cSLin Ming * when an object of "Type" is found 1274ef17507SBob Moore * ascending_callback - Called during tree ascent 1282263576cSLin Ming * when an object of "Type" is found 129ba494beeSBob Moore * context - Passed to user function(s) above 1302263576cSLin Ming * return_value - from the user_function if terminated 1312263576cSLin Ming * early. Otherwise, returns NULL. 13295b482a8SLen Brown * RETURNS: Status 13395b482a8SLen Brown * 13495b482a8SLen Brown * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, 13595b482a8SLen Brown * starting (and ending) at the node specified by start_handle. 1362263576cSLin Ming * The callback function is called whenever a node that matches 1372263576cSLin Ming * the type parameter is found. If the callback function returns 138d4913dc6SBob Moore * a non-zero value, the search is terminated immediately and 139d4913dc6SBob Moore * this value is returned to the caller. 14095b482a8SLen Brown * 14195b482a8SLen Brown * The point of this procedure is to provide a generic namespace 14295b482a8SLen Brown * walk routine that can be called from multiple places to 1432263576cSLin Ming * provide multiple services; the callback function(s) can be 1442263576cSLin Ming * tailored to each task, whether it is a print function, 1452263576cSLin Ming * a compare function, etc. 14695b482a8SLen Brown * 14795b482a8SLen Brown ******************************************************************************/ 14895b482a8SLen Brown 14995b482a8SLen Brown acpi_status 15095b482a8SLen Brown acpi_ns_walk_namespace(acpi_object_type type, 15195b482a8SLen Brown acpi_handle start_node, 15295b482a8SLen Brown u32 max_depth, 15395b482a8SLen Brown u32 flags, 1544ef17507SBob Moore acpi_walk_callback descending_callback, 1554ef17507SBob Moore acpi_walk_callback ascending_callback, 15695b482a8SLen Brown void *context, void **return_value) 15795b482a8SLen Brown { 15895b482a8SLen Brown acpi_status status; 15995b482a8SLen Brown acpi_status mutex_status; 16095b482a8SLen Brown struct acpi_namespace_node *child_node; 16195b482a8SLen Brown struct acpi_namespace_node *parent_node; 16295b482a8SLen Brown acpi_object_type child_type; 16395b482a8SLen Brown u32 level; 1642263576cSLin Ming u8 node_previously_visited = FALSE; 16595b482a8SLen Brown 16695b482a8SLen Brown ACPI_FUNCTION_TRACE(ns_walk_namespace); 16795b482a8SLen Brown 16895b482a8SLen Brown /* Special case for the namespace Root Node */ 16995b482a8SLen Brown 17095b482a8SLen Brown if (start_node == ACPI_ROOT_OBJECT) { 17195b482a8SLen Brown start_node = acpi_gbl_root_node; 17295b482a8SLen Brown } 17395b482a8SLen Brown 17495b482a8SLen Brown /* Null child means "get first node" */ 17595b482a8SLen Brown 17695b482a8SLen Brown parent_node = start_node; 1772263576cSLin Ming child_node = acpi_ns_get_next_node(parent_node, NULL); 17895b482a8SLen Brown child_type = ACPI_TYPE_ANY; 17995b482a8SLen Brown level = 1; 18095b482a8SLen Brown 18195b482a8SLen Brown /* 18295b482a8SLen Brown * Traverse the tree of nodes until we bubble back up to where we 18395b482a8SLen Brown * started. When Level is zero, the loop is done because we have 18495b482a8SLen Brown * bubbled up to (and passed) the original parent handle (start_entry) 18595b482a8SLen Brown */ 1862263576cSLin Ming while (level > 0 && child_node) { 18795b482a8SLen Brown status = AE_OK; 18895b482a8SLen Brown 18995b482a8SLen Brown /* Found next child, get the type if we are not searching for ANY */ 19095b482a8SLen Brown 19195b482a8SLen Brown if (type != ACPI_TYPE_ANY) { 19295b482a8SLen Brown child_type = child_node->type; 19395b482a8SLen Brown } 19495b482a8SLen Brown 19595b482a8SLen Brown /* 19695b482a8SLen Brown * Ignore all temporary namespace nodes (created during control 19795b482a8SLen Brown * method execution) unless told otherwise. These temporary nodes 198d4913dc6SBob Moore * can cause a race condition because they can be deleted during 199d4913dc6SBob Moore * the execution of the user function (if the namespace is 200d4913dc6SBob Moore * unlocked before invocation of the user function.) Only the 201d4913dc6SBob Moore * debugger namespace dump will examine the temporary nodes. 20295b482a8SLen Brown */ 20395b482a8SLen Brown if ((child_node->flags & ANOBJ_TEMPORARY) && 20495b482a8SLen Brown !(flags & ACPI_NS_WALK_TEMP_NODES)) { 20595b482a8SLen Brown status = AE_CTRL_DEPTH; 20695b482a8SLen Brown } 20795b482a8SLen Brown 20895b482a8SLen Brown /* Type must match requested type */ 20995b482a8SLen Brown 21095b482a8SLen Brown else if (child_type == type) { 21195b482a8SLen Brown /* 21295b482a8SLen Brown * Found a matching node, invoke the user callback function. 21395b482a8SLen Brown * Unlock the namespace if flag is set. 21495b482a8SLen Brown */ 21595b482a8SLen Brown if (flags & ACPI_NS_WALK_UNLOCK) { 21695b482a8SLen Brown mutex_status = 2172263576cSLin Ming acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 21895b482a8SLen Brown if (ACPI_FAILURE(mutex_status)) { 2192263576cSLin Ming return_ACPI_STATUS(mutex_status); 22095b482a8SLen Brown } 22195b482a8SLen Brown } 22295b482a8SLen Brown 2232263576cSLin Ming /* 2244ef17507SBob Moore * Invoke the user function, either descending, ascending, 2252263576cSLin Ming * or both. 2262263576cSLin Ming */ 2272263576cSLin Ming if (!node_previously_visited) { 2284ef17507SBob Moore if (descending_callback) { 22995b482a8SLen Brown status = 2304ef17507SBob Moore descending_callback(child_node, 2314ef17507SBob Moore level, context, 23295b482a8SLen Brown return_value); 2332263576cSLin Ming } 2342263576cSLin Ming } else { 2354ef17507SBob Moore if (ascending_callback) { 2362263576cSLin Ming status = 2374ef17507SBob Moore ascending_callback(child_node, 2384ef17507SBob Moore level, context, 2392263576cSLin Ming return_value); 2402263576cSLin Ming } 2412263576cSLin Ming } 24295b482a8SLen Brown 24395b482a8SLen Brown if (flags & ACPI_NS_WALK_UNLOCK) { 24495b482a8SLen Brown mutex_status = 2452263576cSLin Ming acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 24695b482a8SLen Brown if (ACPI_FAILURE(mutex_status)) { 2472263576cSLin Ming return_ACPI_STATUS(mutex_status); 24895b482a8SLen Brown } 24995b482a8SLen Brown } 25095b482a8SLen Brown 25195b482a8SLen Brown switch (status) { 25295b482a8SLen Brown case AE_OK: 25395b482a8SLen Brown case AE_CTRL_DEPTH: 25495b482a8SLen Brown 25595b482a8SLen Brown /* Just keep going */ 25695b482a8SLen Brown break; 25795b482a8SLen Brown 25895b482a8SLen Brown case AE_CTRL_TERMINATE: 25995b482a8SLen Brown 26095b482a8SLen Brown /* Exit now, with OK status */ 26195b482a8SLen Brown 26295b482a8SLen Brown return_ACPI_STATUS(AE_OK); 26395b482a8SLen Brown 26495b482a8SLen Brown default: 26595b482a8SLen Brown 26695b482a8SLen Brown /* All others are valid exceptions */ 26795b482a8SLen Brown 26895b482a8SLen Brown return_ACPI_STATUS(status); 26995b482a8SLen Brown } 27095b482a8SLen Brown } 27195b482a8SLen Brown 27295b482a8SLen Brown /* 27395b482a8SLen Brown * Depth first search: Attempt to go down another level in the 27495b482a8SLen Brown * namespace if we are allowed to. Don't go any further if we have 27595b482a8SLen Brown * reached the caller specified maximum depth or if the user 27695b482a8SLen Brown * function has specified that the maximum depth has been reached. 27795b482a8SLen Brown */ 2782263576cSLin Ming if (!node_previously_visited && 2792263576cSLin Ming (level < max_depth) && (status != AE_CTRL_DEPTH)) { 2808c725bf9SBob Moore if (child_node->child) { 28195b482a8SLen Brown 28295b482a8SLen Brown /* There is at least one child of this node, visit it */ 28395b482a8SLen Brown 28495b482a8SLen Brown level++; 28595b482a8SLen Brown parent_node = child_node; 2862263576cSLin Ming child_node = 2872263576cSLin Ming acpi_ns_get_next_node(parent_node, NULL); 2882263576cSLin Ming continue; 28995b482a8SLen Brown } 29095b482a8SLen Brown } 2912263576cSLin Ming 2922263576cSLin Ming /* No more children, re-visit this node */ 2932263576cSLin Ming 2942263576cSLin Ming if (!node_previously_visited) { 2952263576cSLin Ming node_previously_visited = TRUE; 2962263576cSLin Ming continue; 2972263576cSLin Ming } 2982263576cSLin Ming 2992263576cSLin Ming /* No more children, visit peers */ 3002263576cSLin Ming 3012263576cSLin Ming child_node = acpi_ns_get_next_node(parent_node, child_node); 3022263576cSLin Ming if (child_node) { 3032263576cSLin Ming node_previously_visited = FALSE; 3042263576cSLin Ming } 3052263576cSLin Ming 3062263576cSLin Ming /* No peers, re-visit parent */ 3072263576cSLin Ming 3082263576cSLin Ming else { 30995b482a8SLen Brown /* 31095b482a8SLen Brown * No more children of this node (acpi_ns_get_next_node failed), go 31195b482a8SLen Brown * back upwards in the namespace tree to the node's parent. 31295b482a8SLen Brown */ 31395b482a8SLen Brown level--; 31495b482a8SLen Brown child_node = parent_node; 315c45b5c09SAlexey Starikovskiy parent_node = parent_node->parent; 3162263576cSLin Ming 3172263576cSLin Ming node_previously_visited = TRUE; 31895b482a8SLen Brown } 31995b482a8SLen Brown } 32095b482a8SLen Brown 32195b482a8SLen Brown /* Complete walk, not terminated by user function */ 32295b482a8SLen Brown 32395b482a8SLen Brown return_ACPI_STATUS(AE_OK); 32495b482a8SLen Brown } 325