at v2.6.26 496 lines 13 kB view raw
1/******************************************************************************* 2 * 3 * Module Name: nsalloc - Namespace allocation and deletion utilities 4 * 5 ******************************************************************************/ 6 7/* 8 * Copyright (C) 2000 - 2008, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44#include <acpi/acpi.h> 45#include <acpi/acnamesp.h> 46 47#define _COMPONENT ACPI_NAMESPACE 48ACPI_MODULE_NAME("nsalloc") 49 50/******************************************************************************* 51 * 52 * FUNCTION: acpi_ns_create_node 53 * 54 * PARAMETERS: Name - Name of the new node (4 char ACPI name) 55 * 56 * RETURN: New namespace node (Null on failure) 57 * 58 * DESCRIPTION: Create a namespace node 59 * 60 ******************************************************************************/ 61struct acpi_namespace_node *acpi_ns_create_node(u32 name) 62{ 63 struct acpi_namespace_node *node; 64#ifdef ACPI_DBG_TRACK_ALLOCATIONS 65 u32 temp; 66#endif 67 68 ACPI_FUNCTION_TRACE(ns_create_node); 69 70 node = acpi_os_acquire_object(acpi_gbl_namespace_cache); 71 if (!node) { 72 return_PTR(NULL); 73 } 74 75 ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++); 76 77#ifdef ACPI_DBG_TRACK_ALLOCATIONS 78 temp = 79 acpi_gbl_ns_node_list->total_allocated - 80 acpi_gbl_ns_node_list->total_freed; 81 if (temp > acpi_gbl_ns_node_list->max_occupied) { 82 acpi_gbl_ns_node_list->max_occupied = temp; 83 } 84#endif 85 86 node->name.integer = name; 87 ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED); 88 return_PTR(node); 89} 90 91/******************************************************************************* 92 * 93 * FUNCTION: acpi_ns_delete_node 94 * 95 * PARAMETERS: Node - Node to be deleted 96 * 97 * RETURN: None 98 * 99 * DESCRIPTION: Delete a namespace node 100 * 101 ******************************************************************************/ 102 103void acpi_ns_delete_node(struct acpi_namespace_node *node) 104{ 105 struct acpi_namespace_node *parent_node; 106 struct acpi_namespace_node *prev_node; 107 struct acpi_namespace_node *next_node; 108 109 ACPI_FUNCTION_TRACE_PTR(ns_delete_node, node); 110 111 parent_node = acpi_ns_get_parent_node(node); 112 113 prev_node = NULL; 114 next_node = parent_node->child; 115 116 /* Find the node that is the previous peer in the parent's child list */ 117 118 while (next_node != node) { 119 prev_node = next_node; 120 next_node = prev_node->peer; 121 } 122 123 if (prev_node) { 124 125 /* Node is not first child, unlink it */ 126 127 prev_node->peer = next_node->peer; 128 if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { 129 prev_node->flags |= ANOBJ_END_OF_PEER_LIST; 130 } 131 } else { 132 /* Node is first child (has no previous peer) */ 133 134 if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { 135 136 /* No peers at all */ 137 138 parent_node->child = NULL; 139 } else { /* Link peer list to parent */ 140 141 parent_node->child = next_node->peer; 142 } 143 } 144 145 ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++); 146 147 /* 148 * Detach an object if there is one, then delete the node 149 */ 150 acpi_ns_detach_object(node); 151 (void)acpi_os_release_object(acpi_gbl_namespace_cache, node); 152 return_VOID; 153} 154 155/******************************************************************************* 156 * 157 * FUNCTION: acpi_ns_install_node 158 * 159 * PARAMETERS: walk_state - Current state of the walk 160 * parent_node - The parent of the new Node 161 * Node - The new Node to install 162 * Type - ACPI object type of the new Node 163 * 164 * RETURN: None 165 * 166 * DESCRIPTION: Initialize a new namespace node and install it amongst 167 * its peers. 168 * 169 * Note: Current namespace lookup is linear search. This appears 170 * to be sufficient as namespace searches consume only a small 171 * fraction of the execution time of the ACPI subsystem. 172 * 173 ******************************************************************************/ 174 175void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namespace_node *parent_node, /* Parent */ 176 struct acpi_namespace_node *node, /* New Child */ 177 acpi_object_type type) 178{ 179 acpi_owner_id owner_id = 0; 180 struct acpi_namespace_node *child_node; 181 182 ACPI_FUNCTION_TRACE(ns_install_node); 183 184 /* 185 * Get the owner ID from the Walk state 186 * The owner ID is used to track table deletion and 187 * deletion of objects created by methods 188 */ 189 if (walk_state) { 190 owner_id = walk_state->owner_id; 191 } 192 193 /* Link the new entry into the parent and existing children */ 194 195 child_node = parent_node->child; 196 if (!child_node) { 197 parent_node->child = node; 198 node->flags |= ANOBJ_END_OF_PEER_LIST; 199 node->peer = parent_node; 200 } else { 201 while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) { 202 child_node = child_node->peer; 203 } 204 205 child_node->peer = node; 206 207 /* Clear end-of-list flag */ 208 209 child_node->flags &= ~ANOBJ_END_OF_PEER_LIST; 210 node->flags |= ANOBJ_END_OF_PEER_LIST; 211 node->peer = parent_node; 212 } 213 214 /* Init the new entry */ 215 216 node->owner_id = owner_id; 217 node->type = (u8) type; 218 219 ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 220 "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n", 221 acpi_ut_get_node_name(node), 222 acpi_ut_get_type_name(node->type), node, owner_id, 223 acpi_ut_get_node_name(parent_node), 224 acpi_ut_get_type_name(parent_node->type), 225 parent_node)); 226 227 return_VOID; 228} 229 230/******************************************************************************* 231 * 232 * FUNCTION: acpi_ns_delete_children 233 * 234 * PARAMETERS: parent_node - Delete this objects children 235 * 236 * RETURN: None. 237 * 238 * DESCRIPTION: Delete all children of the parent object. In other words, 239 * deletes a "scope". 240 * 241 ******************************************************************************/ 242 243void acpi_ns_delete_children(struct acpi_namespace_node *parent_node) 244{ 245 struct acpi_namespace_node *child_node; 246 struct acpi_namespace_node *next_node; 247 u8 flags; 248 249 ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node); 250 251 if (!parent_node) { 252 return_VOID; 253 } 254 255 /* If no children, all done! */ 256 257 child_node = parent_node->child; 258 if (!child_node) { 259 return_VOID; 260 } 261 262 /* 263 * Deallocate all children at this level 264 */ 265 do { 266 267 /* Get the things we need */ 268 269 next_node = child_node->peer; 270 flags = child_node->flags; 271 272 /* Grandchildren should have all been deleted already */ 273 274 if (child_node->child) { 275 ACPI_ERROR((AE_INFO, "Found a grandchild! P=%p C=%p", 276 parent_node, child_node)); 277 } 278 279 /* Now we can free this child object */ 280 281 ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_freed++); 282 283 ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, 284 "Object %p, Remaining %X\n", child_node, 285 acpi_gbl_current_node_count)); 286 287 /* 288 * Detach an object if there is one, then free the child node 289 */ 290 acpi_ns_detach_object(child_node); 291 292 /* Now we can delete the node */ 293 294 (void)acpi_os_release_object(acpi_gbl_namespace_cache, 295 child_node); 296 297 /* And move on to the next child in the list */ 298 299 child_node = next_node; 300 301 } while (!(flags & ANOBJ_END_OF_PEER_LIST)); 302 303 /* Clear the parent's child pointer */ 304 305 parent_node->child = NULL; 306 307 return_VOID; 308} 309 310/******************************************************************************* 311 * 312 * FUNCTION: acpi_ns_delete_namespace_subtree 313 * 314 * PARAMETERS: parent_node - Root of the subtree to be deleted 315 * 316 * RETURN: None. 317 * 318 * DESCRIPTION: Delete a subtree of the namespace. This includes all objects 319 * stored within the subtree. 320 * 321 ******************************************************************************/ 322 323void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) 324{ 325 struct acpi_namespace_node *child_node = NULL; 326 u32 level = 1; 327 328 ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree); 329 330 if (!parent_node) { 331 return_VOID; 332 } 333 334 /* 335 * Traverse the tree of objects until we bubble back up 336 * to where we started. 337 */ 338 while (level > 0) { 339 340 /* Get the next node in this scope (NULL if none) */ 341 342 child_node = 343 acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, 344 child_node); 345 if (child_node) { 346 347 /* Found a child node - detach any attached object */ 348 349 acpi_ns_detach_object(child_node); 350 351 /* Check if this node has any children */ 352 353 if (acpi_ns_get_next_node 354 (ACPI_TYPE_ANY, child_node, NULL)) { 355 /* 356 * There is at least one child of this node, 357 * visit the node 358 */ 359 level++; 360 parent_node = child_node; 361 child_node = NULL; 362 } 363 } else { 364 /* 365 * No more children of this parent node. 366 * Move up to the grandparent. 367 */ 368 level--; 369 370 /* 371 * Now delete all of the children of this parent 372 * all at the same time. 373 */ 374 acpi_ns_delete_children(parent_node); 375 376 /* New "last child" is this parent node */ 377 378 child_node = parent_node; 379 380 /* Move up the tree to the grandparent */ 381 382 parent_node = acpi_ns_get_parent_node(parent_node); 383 } 384 } 385 386 return_VOID; 387} 388 389/******************************************************************************* 390 * 391 * FUNCTION: acpi_ns_delete_namespace_by_owner 392 * 393 * PARAMETERS: owner_id - All nodes with this owner will be deleted 394 * 395 * RETURN: Status 396 * 397 * DESCRIPTION: Delete entries within the namespace that are owned by a 398 * specific ID. Used to delete entire ACPI tables. All 399 * reference counts are updated. 400 * 401 * MUTEX: Locks namespace during deletion walk. 402 * 403 ******************************************************************************/ 404 405void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) 406{ 407 struct acpi_namespace_node *child_node; 408 struct acpi_namespace_node *deletion_node; 409 struct acpi_namespace_node *parent_node; 410 u32 level; 411 acpi_status status; 412 413 ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id); 414 415 if (owner_id == 0) { 416 return_VOID; 417 } 418 419 /* Lock namespace for possible update */ 420 421 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 422 if (ACPI_FAILURE(status)) { 423 return_VOID; 424 } 425 426 deletion_node = NULL; 427 parent_node = acpi_gbl_root_node; 428 child_node = NULL; 429 level = 1; 430 431 /* 432 * Traverse the tree of nodes until we bubble back up 433 * to where we started. 434 */ 435 while (level > 0) { 436 /* 437 * Get the next child of this parent node. When child_node is NULL, 438 * the first child of the parent is returned 439 */ 440 child_node = 441 acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, 442 child_node); 443 444 if (deletion_node) { 445 acpi_ns_delete_children(deletion_node); 446 acpi_ns_delete_node(deletion_node); 447 deletion_node = NULL; 448 } 449 450 if (child_node) { 451 if (child_node->owner_id == owner_id) { 452 453 /* Found a matching child node - detach any attached object */ 454 455 acpi_ns_detach_object(child_node); 456 } 457 458 /* Check if this node has any children */ 459 460 if (acpi_ns_get_next_node 461 (ACPI_TYPE_ANY, child_node, NULL)) { 462 /* 463 * There is at least one child of this node, 464 * visit the node 465 */ 466 level++; 467 parent_node = child_node; 468 child_node = NULL; 469 } else if (child_node->owner_id == owner_id) { 470 deletion_node = child_node; 471 } 472 } else { 473 /* 474 * No more children of this parent node. 475 * Move up to the grandparent. 476 */ 477 level--; 478 if (level != 0) { 479 if (parent_node->owner_id == owner_id) { 480 deletion_node = parent_node; 481 } 482 } 483 484 /* New "last child" is this parent node */ 485 486 child_node = parent_node; 487 488 /* Move up the tree to the grandparent */ 489 490 parent_node = acpi_ns_get_parent_node(parent_node); 491 } 492 } 493 494 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 495 return_VOID; 496}