162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/******************************************************************************* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: nsalloc - Namespace allocation and deletion utilities 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci ******************************************************************************/ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <acpi/acpi.h> 962306a36Sopenharmony_ci#include "accommon.h" 1062306a36Sopenharmony_ci#include "acnamesp.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define _COMPONENT ACPI_NAMESPACE 1362306a36Sopenharmony_ciACPI_MODULE_NAME("nsalloc") 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/******************************************************************************* 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * FUNCTION: acpi_ns_create_node 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * PARAMETERS: name - Name of the new node (4 char ACPI name) 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * RETURN: New namespace node (Null on failure) 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * DESCRIPTION: Create a namespace node 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci ******************************************************************************/ 2662306a36Sopenharmony_cistruct acpi_namespace_node *acpi_ns_create_node(u32 name) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct acpi_namespace_node *node; 2962306a36Sopenharmony_ci#ifdef ACPI_DBG_TRACK_ALLOCATIONS 3062306a36Sopenharmony_ci u32 temp; 3162306a36Sopenharmony_ci#endif 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_create_node); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci node = acpi_os_acquire_object(acpi_gbl_namespace_cache); 3662306a36Sopenharmony_ci if (!node) { 3762306a36Sopenharmony_ci return_PTR(NULL); 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#ifdef ACPI_DBG_TRACK_ALLOCATIONS 4362306a36Sopenharmony_ci temp = acpi_gbl_ns_node_list->total_allocated - 4462306a36Sopenharmony_ci acpi_gbl_ns_node_list->total_freed; 4562306a36Sopenharmony_ci if (temp > acpi_gbl_ns_node_list->max_occupied) { 4662306a36Sopenharmony_ci acpi_gbl_ns_node_list->max_occupied = temp; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci#endif 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci node->name.integer = name; 5162306a36Sopenharmony_ci ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED); 5262306a36Sopenharmony_ci return_PTR(node); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/******************************************************************************* 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * FUNCTION: acpi_ns_delete_node 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * PARAMETERS: node - Node to be deleted 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * RETURN: None 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * DESCRIPTION: Delete a namespace node. All node deletions must come through 6462306a36Sopenharmony_ci * here. Detaches any attached objects, including any attached 6562306a36Sopenharmony_ci * data. If a handler is associated with attached data, it is 6662306a36Sopenharmony_ci * invoked before the node is deleted. 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci ******************************************************************************/ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_civoid acpi_ns_delete_node(struct acpi_namespace_node *node) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 7362306a36Sopenharmony_ci union acpi_operand_object *next_desc; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci ACPI_FUNCTION_NAME(ns_delete_node); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (!node) { 7862306a36Sopenharmony_ci return_VOID; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* Detach an object if there is one */ 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci acpi_ns_detach_object(node); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* 8662306a36Sopenharmony_ci * Delete an attached data object list if present (objects that were 8762306a36Sopenharmony_ci * attached via acpi_attach_data). Note: After any normal object is 8862306a36Sopenharmony_ci * detached above, the only possible remaining object(s) are data 8962306a36Sopenharmony_ci * objects, in a linked list. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ci obj_desc = node->object; 9262306a36Sopenharmony_ci while (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) { 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* Invoke the attached data deletion handler if present */ 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (obj_desc->data.handler) { 9762306a36Sopenharmony_ci obj_desc->data.handler(node, obj_desc->data.pointer); 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci next_desc = obj_desc->common.next_object; 10162306a36Sopenharmony_ci acpi_ut_remove_reference(obj_desc); 10262306a36Sopenharmony_ci obj_desc = next_desc; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* Special case for the statically allocated root node */ 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (node == acpi_gbl_root_node) { 10862306a36Sopenharmony_ci return; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* Now we can delete the node */ 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci (void)acpi_os_release_object(acpi_gbl_namespace_cache, node); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++); 11662306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Node %p, Remaining %X\n", 11762306a36Sopenharmony_ci node, acpi_gbl_current_node_count)); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/******************************************************************************* 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci * FUNCTION: acpi_ns_remove_node 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * PARAMETERS: node - Node to be removed/deleted 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * RETURN: None 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci * DESCRIPTION: Remove (unlink) and delete a namespace node 12962306a36Sopenharmony_ci * 13062306a36Sopenharmony_ci ******************************************************************************/ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_civoid acpi_ns_remove_node(struct acpi_namespace_node *node) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct acpi_namespace_node *parent_node; 13562306a36Sopenharmony_ci struct acpi_namespace_node *prev_node; 13662306a36Sopenharmony_ci struct acpi_namespace_node *next_node; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci parent_node = node->parent; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci prev_node = NULL; 14362306a36Sopenharmony_ci next_node = parent_node->child; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* Find the node that is the previous peer in the parent's child list */ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci while (next_node != node) { 14862306a36Sopenharmony_ci prev_node = next_node; 14962306a36Sopenharmony_ci next_node = next_node->peer; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (prev_node) { 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* Node is not first child, unlink it */ 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci prev_node->peer = node->peer; 15762306a36Sopenharmony_ci } else { 15862306a36Sopenharmony_ci /* 15962306a36Sopenharmony_ci * Node is first child (has no previous peer). 16062306a36Sopenharmony_ci * Link peer list to parent 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_ci parent_node->child = node->peer; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Delete the node and any attached objects */ 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci acpi_ns_delete_node(node); 16862306a36Sopenharmony_ci return_VOID; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/******************************************************************************* 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * FUNCTION: acpi_ns_install_node 17462306a36Sopenharmony_ci * 17562306a36Sopenharmony_ci * PARAMETERS: walk_state - Current state of the walk 17662306a36Sopenharmony_ci * parent_node - The parent of the new Node 17762306a36Sopenharmony_ci * node - The new Node to install 17862306a36Sopenharmony_ci * type - ACPI object type of the new Node 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * RETURN: None 18162306a36Sopenharmony_ci * 18262306a36Sopenharmony_ci * DESCRIPTION: Initialize a new namespace node and install it amongst 18362306a36Sopenharmony_ci * its peers. 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * Note: Current namespace lookup is linear search. This appears 18662306a36Sopenharmony_ci * to be sufficient as namespace searches consume only a small 18762306a36Sopenharmony_ci * fraction of the execution time of the ACPI subsystem. 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci ******************************************************************************/ 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_civoid acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namespace_node *parent_node, /* Parent */ 19262306a36Sopenharmony_ci struct acpi_namespace_node *node, /* New Child */ 19362306a36Sopenharmony_ci acpi_object_type type) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci acpi_owner_id owner_id = 0; 19662306a36Sopenharmony_ci struct acpi_namespace_node *child_node; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_install_node); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (walk_state) { 20162306a36Sopenharmony_ci /* 20262306a36Sopenharmony_ci * Get the owner ID from the Walk state. The owner ID is used to 20362306a36Sopenharmony_ci * track table deletion and deletion of objects created by methods. 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_ci owner_id = walk_state->owner_id; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if ((walk_state->method_desc) && 20862306a36Sopenharmony_ci (parent_node != walk_state->method_node)) { 20962306a36Sopenharmony_ci /* 21062306a36Sopenharmony_ci * A method is creating a new node that is not a child of the 21162306a36Sopenharmony_ci * method (it is non-local). Mark the executing method as having 21262306a36Sopenharmony_ci * modified the namespace. This is used for cleanup when the 21362306a36Sopenharmony_ci * method exits. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_ci walk_state->method_desc->method.info_flags |= 21662306a36Sopenharmony_ci ACPI_METHOD_MODIFIED_NAMESPACE; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* Link the new entry into the parent and existing children */ 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci node->peer = NULL; 22362306a36Sopenharmony_ci node->parent = parent_node; 22462306a36Sopenharmony_ci child_node = parent_node->child; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (!child_node) { 22762306a36Sopenharmony_ci parent_node->child = node; 22862306a36Sopenharmony_ci } else { 22962306a36Sopenharmony_ci /* Add node to the end of the peer list */ 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci while (child_node->peer) { 23262306a36Sopenharmony_ci child_node = child_node->peer; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci child_node->peer = node; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Init the new entry */ 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci node->owner_id = owner_id; 24162306a36Sopenharmony_ci node->type = (u8) type; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 24462306a36Sopenharmony_ci "%4.4s (%s) [Node %p Owner %3.3X] added to %4.4s (%s) [Node %p]\n", 24562306a36Sopenharmony_ci acpi_ut_get_node_name(node), 24662306a36Sopenharmony_ci acpi_ut_get_type_name(node->type), node, owner_id, 24762306a36Sopenharmony_ci acpi_ut_get_node_name(parent_node), 24862306a36Sopenharmony_ci acpi_ut_get_type_name(parent_node->type), 24962306a36Sopenharmony_ci parent_node)); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return_VOID; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/******************************************************************************* 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * FUNCTION: acpi_ns_delete_children 25762306a36Sopenharmony_ci * 25862306a36Sopenharmony_ci * PARAMETERS: parent_node - Delete this objects children 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * RETURN: None. 26162306a36Sopenharmony_ci * 26262306a36Sopenharmony_ci * DESCRIPTION: Delete all children of the parent object. In other words, 26362306a36Sopenharmony_ci * deletes a "scope". 26462306a36Sopenharmony_ci * 26562306a36Sopenharmony_ci ******************************************************************************/ 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_civoid acpi_ns_delete_children(struct acpi_namespace_node *parent_node) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct acpi_namespace_node *next_node; 27062306a36Sopenharmony_ci struct acpi_namespace_node *node_to_delete; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (!parent_node) { 27562306a36Sopenharmony_ci return_VOID; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* Deallocate all children at this level */ 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci next_node = parent_node->child; 28162306a36Sopenharmony_ci while (next_node) { 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* Grandchildren should have all been deleted already */ 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (next_node->child) { 28662306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Found a grandchild! P=%p C=%p", 28762306a36Sopenharmony_ci parent_node, next_node)); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* 29162306a36Sopenharmony_ci * Delete this child node and move on to the next child in the list. 29262306a36Sopenharmony_ci * No need to unlink the node since we are deleting the entire branch. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci node_to_delete = next_node; 29562306a36Sopenharmony_ci next_node = next_node->peer; 29662306a36Sopenharmony_ci acpi_ns_delete_node(node_to_delete); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* Clear the parent's child pointer */ 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci parent_node->child = NULL; 30262306a36Sopenharmony_ci return_VOID; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/******************************************************************************* 30662306a36Sopenharmony_ci * 30762306a36Sopenharmony_ci * FUNCTION: acpi_ns_delete_namespace_subtree 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * PARAMETERS: parent_node - Root of the subtree to be deleted 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci * RETURN: None. 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * DESCRIPTION: Delete a subtree of the namespace. This includes all objects 31462306a36Sopenharmony_ci * stored within the subtree. 31562306a36Sopenharmony_ci * 31662306a36Sopenharmony_ci ******************************************************************************/ 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_civoid acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct acpi_namespace_node *child_node = NULL; 32162306a36Sopenharmony_ci u32 level = 1; 32262306a36Sopenharmony_ci acpi_status status; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (!parent_node) { 32762306a36Sopenharmony_ci return_VOID; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Lock namespace for possible update */ 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 33362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 33462306a36Sopenharmony_ci return_VOID; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* 33862306a36Sopenharmony_ci * Traverse the tree of objects until we bubble back up 33962306a36Sopenharmony_ci * to where we started. 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci while (level > 0) { 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* Get the next node in this scope (NULL if none) */ 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci child_node = acpi_ns_get_next_node(parent_node, child_node); 34662306a36Sopenharmony_ci if (child_node) { 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* Found a child node - detach any attached object */ 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci acpi_ns_detach_object(child_node); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* Check if this node has any children */ 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (child_node->child) { 35562306a36Sopenharmony_ci /* 35662306a36Sopenharmony_ci * There is at least one child of this node, 35762306a36Sopenharmony_ci * visit the node 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci level++; 36062306a36Sopenharmony_ci parent_node = child_node; 36162306a36Sopenharmony_ci child_node = NULL; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci } else { 36462306a36Sopenharmony_ci /* 36562306a36Sopenharmony_ci * No more children of this parent node. 36662306a36Sopenharmony_ci * Move up to the grandparent. 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci level--; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* 37162306a36Sopenharmony_ci * Now delete all of the children of this parent 37262306a36Sopenharmony_ci * all at the same time. 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_ci acpi_ns_delete_children(parent_node); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* New "last child" is this parent node */ 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci child_node = parent_node; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* Move up the tree to the grandparent */ 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci parent_node = parent_node->parent; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 38762306a36Sopenharmony_ci return_VOID; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci/******************************************************************************* 39162306a36Sopenharmony_ci * 39262306a36Sopenharmony_ci * FUNCTION: acpi_ns_delete_namespace_by_owner 39362306a36Sopenharmony_ci * 39462306a36Sopenharmony_ci * PARAMETERS: owner_id - All nodes with this owner will be deleted 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * RETURN: Status 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * DESCRIPTION: Delete entries within the namespace that are owned by a 39962306a36Sopenharmony_ci * specific ID. Used to delete entire ACPI tables. All 40062306a36Sopenharmony_ci * reference counts are updated. 40162306a36Sopenharmony_ci * 40262306a36Sopenharmony_ci * MUTEX: Locks namespace during deletion walk. 40362306a36Sopenharmony_ci * 40462306a36Sopenharmony_ci ******************************************************************************/ 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_civoid acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct acpi_namespace_node *child_node; 40962306a36Sopenharmony_ci struct acpi_namespace_node *deletion_node; 41062306a36Sopenharmony_ci struct acpi_namespace_node *parent_node; 41162306a36Sopenharmony_ci u32 level; 41262306a36Sopenharmony_ci acpi_status status; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (owner_id == 0) { 41762306a36Sopenharmony_ci return_VOID; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* Lock namespace for possible update */ 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 42362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 42462306a36Sopenharmony_ci return_VOID; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci deletion_node = NULL; 42862306a36Sopenharmony_ci parent_node = acpi_gbl_root_node; 42962306a36Sopenharmony_ci child_node = NULL; 43062306a36Sopenharmony_ci level = 1; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* 43362306a36Sopenharmony_ci * Traverse the tree of nodes until we bubble back up 43462306a36Sopenharmony_ci * to where we started. 43562306a36Sopenharmony_ci */ 43662306a36Sopenharmony_ci while (level > 0) { 43762306a36Sopenharmony_ci /* 43862306a36Sopenharmony_ci * Get the next child of this parent node. When child_node is NULL, 43962306a36Sopenharmony_ci * the first child of the parent is returned 44062306a36Sopenharmony_ci */ 44162306a36Sopenharmony_ci child_node = acpi_ns_get_next_node(parent_node, child_node); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (deletion_node) { 44462306a36Sopenharmony_ci acpi_ns_delete_children(deletion_node); 44562306a36Sopenharmony_ci acpi_ns_remove_node(deletion_node); 44662306a36Sopenharmony_ci deletion_node = NULL; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (child_node) { 45062306a36Sopenharmony_ci if (child_node->owner_id == owner_id) { 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* Found a matching child node - detach any attached object */ 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci acpi_ns_detach_object(child_node); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* Check if this node has any children */ 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (child_node->child) { 46062306a36Sopenharmony_ci /* 46162306a36Sopenharmony_ci * There is at least one child of this node, 46262306a36Sopenharmony_ci * visit the node 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci level++; 46562306a36Sopenharmony_ci parent_node = child_node; 46662306a36Sopenharmony_ci child_node = NULL; 46762306a36Sopenharmony_ci } else if (child_node->owner_id == owner_id) { 46862306a36Sopenharmony_ci deletion_node = child_node; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci } else { 47162306a36Sopenharmony_ci /* 47262306a36Sopenharmony_ci * No more children of this parent node. 47362306a36Sopenharmony_ci * Move up to the grandparent. 47462306a36Sopenharmony_ci */ 47562306a36Sopenharmony_ci level--; 47662306a36Sopenharmony_ci if (level != 0) { 47762306a36Sopenharmony_ci if (parent_node->owner_id == owner_id) { 47862306a36Sopenharmony_ci deletion_node = parent_node; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* New "last child" is this parent node */ 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci child_node = parent_node; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* Move up the tree to the grandparent */ 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci parent_node = parent_node->parent; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 49362306a36Sopenharmony_ci return_VOID; 49462306a36Sopenharmony_ci} 495