nsalloc.c revision 229989
1166124Srafan/******************************************************************************* 2166124Srafan * 3166124Srafan * Module Name: nsalloc - Namespace allocation and deletion utilities 4166124Srafan * 5166124Srafan ******************************************************************************/ 6166124Srafan 7166124Srafan/* 8166124Srafan * Copyright (C) 2000 - 2012, Intel Corp. 9166124Srafan * All rights reserved. 10166124Srafan * 11166124Srafan * Redistribution and use in source and binary forms, with or without 12166124Srafan * modification, are permitted provided that the following conditions 13166124Srafan * are met: 14166124Srafan * 1. Redistributions of source code must retain the above copyright 15166124Srafan * notice, this list of conditions, and the following disclaimer, 16166124Srafan * without modification. 17166124Srafan * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18166124Srafan * substantially similar to the "NO WARRANTY" disclaimer below 19166124Srafan * ("Disclaimer") and any redistribution must be conditioned upon 20166124Srafan * including a substantially similar Disclaimer requirement for further 21166124Srafan * binary redistribution. 22166124Srafan * 3. Neither the names of the above-listed copyright holders nor the names 23166124Srafan * of any contributors may be used to endorse or promote products derived 24166124Srafan * from this software without specific prior written permission. 25166124Srafan * 26166124Srafan * Alternatively, this software may be distributed under the terms of the 27166124Srafan * GNU General Public License ("GPL") version 2 as published by the Free 28166124Srafan * Software Foundation. 2950276Speter * 30166124Srafan * NO WARRANTY 3150276Speter * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3250276Speter * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3350276Speter * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3450276Speter * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3550276Speter * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3650276Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3750276Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3850276Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3950276Speter * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4050276Speter * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4150276Speter * POSSIBILITY OF SUCH DAMAGES. 4250276Speter */ 4350276Speter 4450276Speter 4550276Speter#define __NSALLOC_C__ 4650276Speter 4750276Speter#include <contrib/dev/acpica/include/acpi.h> 4850276Speter#include <contrib/dev/acpica/include/accommon.h> 4950276Speter#include <contrib/dev/acpica/include/acnamesp.h> 5050276Speter 5150276Speter 5250276Speter#define _COMPONENT ACPI_NAMESPACE 5350276Speter ACPI_MODULE_NAME ("nsalloc") 5450276Speter 5550276Speter 5650276Speter/******************************************************************************* 5750276Speter * 5850276Speter * FUNCTION: AcpiNsCreateNode 5950276Speter * 6050276Speter * PARAMETERS: Name - Name of the new node (4 char ACPI name) 6150276Speter * 6250276Speter * RETURN: New namespace node (Null on failure) 6350276Speter * 6450276Speter * DESCRIPTION: Create a namespace node 6550276Speter * 6650276Speter ******************************************************************************/ 6750276Speter 6850276SpeterACPI_NAMESPACE_NODE * 6950276SpeterAcpiNsCreateNode ( 7050276Speter UINT32 Name) 7150276Speter{ 7250276Speter ACPI_NAMESPACE_NODE *Node; 7350276Speter#ifdef ACPI_DBG_TRACK_ALLOCATIONS 7450276Speter UINT32 Temp; 7550276Speter#endif 7650276Speter 7750276Speter 7850276Speter ACPI_FUNCTION_TRACE (NsCreateNode); 7950276Speter 8050276Speter 8150276Speter Node = AcpiOsAcquireObject (AcpiGbl_NamespaceCache); 8250276Speter if (!Node) 8350276Speter { 8450276Speter return_PTR (NULL); 8550276Speter } 8650276Speter 8750276Speter ACPI_MEM_TRACKING (AcpiGbl_NsNodeList->TotalAllocated++); 8850276Speter 8950276Speter#ifdef ACPI_DBG_TRACK_ALLOCATIONS 9050276Speter Temp = AcpiGbl_NsNodeList->TotalAllocated - 9150276Speter AcpiGbl_NsNodeList->TotalFreed; 9250276Speter if (Temp > AcpiGbl_NsNodeList->MaxOccupied) 9350276Speter { 9450276Speter AcpiGbl_NsNodeList->MaxOccupied = Temp; 9550276Speter } 9650276Speter#endif 9750276Speter 9850276Speter Node->Name.Integer = Name; 9950276Speter ACPI_SET_DESCRIPTOR_TYPE (Node, ACPI_DESC_TYPE_NAMED); 10050276Speter return_PTR (Node); 10150276Speter} 10250276Speter 10350276Speter 10450276Speter/******************************************************************************* 10550276Speter * 10650276Speter * FUNCTION: AcpiNsDeleteNode 10750276Speter * 10850276Speter * PARAMETERS: Node - Node to be deleted 10950276Speter * 11050276Speter * RETURN: None 11150276Speter * 11250276Speter * DESCRIPTION: Delete a namespace node. All node deletions must come through 11350276Speter * here. Detaches any attached objects, including any attached 11450276Speter * data. If a handler is associated with attached data, it is 11550276Speter * invoked before the node is deleted. 11650276Speter * 11750276Speter ******************************************************************************/ 11850276Speter 11950276Spetervoid 12050276SpeterAcpiNsDeleteNode ( 12150276Speter ACPI_NAMESPACE_NODE *Node) 12250276Speter{ 12350276Speter ACPI_OPERAND_OBJECT *ObjDesc; 12450276Speter 12550276Speter 12650276Speter ACPI_FUNCTION_NAME (NsDeleteNode); 12750276Speter 12850276Speter 12950276Speter /* Detach an object if there is one */ 13050276Speter 13150276Speter AcpiNsDetachObject (Node); 13250276Speter 13350276Speter /* 13450276Speter * Delete an attached data object if present (an object that was created 13550276Speter * and attached via AcpiAttachData). Note: After any normal object is 13650276Speter * detached above, the only possible remaining object is a data object. 13750276Speter */ 13850276Speter ObjDesc = Node->Object; 13950276Speter if (ObjDesc && 14050276Speter (ObjDesc->Common.Type == ACPI_TYPE_LOCAL_DATA)) 14150276Speter { 14250276Speter /* Invoke the attached data deletion handler if present */ 14350276Speter 14450276Speter if (ObjDesc->Data.Handler) 14550276Speter { 14650276Speter ObjDesc->Data.Handler (Node, ObjDesc->Data.Pointer); 14750276Speter } 14850276Speter 14950276Speter AcpiUtRemoveReference (ObjDesc); 15050276Speter } 15150276Speter 15250276Speter /* Now we can delete the node */ 15350276Speter 15450276Speter (void) AcpiOsReleaseObject (AcpiGbl_NamespaceCache, Node); 15550276Speter 15650276Speter ACPI_MEM_TRACKING (AcpiGbl_NsNodeList->TotalFreed++); 15750276Speter ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Node %p, Remaining %X\n", 15850276Speter Node, AcpiGbl_CurrentNodeCount)); 15950276Speter} 16050276Speter 16150276Speter 16250276Speter/******************************************************************************* 16350276Speter * 16450276Speter * FUNCTION: AcpiNsRemoveNode 16550276Speter * 16650276Speter * PARAMETERS: Node - Node to be removed/deleted 16750276Speter * 16850276Speter * RETURN: None 16950276Speter * 17050276Speter * DESCRIPTION: Remove (unlink) and delete a namespace node 17150276Speter * 17250276Speter ******************************************************************************/ 17350276Speter 17450276Spetervoid 17550276SpeterAcpiNsRemoveNode ( 17650276Speter ACPI_NAMESPACE_NODE *Node) 17750276Speter{ 17850276Speter ACPI_NAMESPACE_NODE *ParentNode; 17950276Speter ACPI_NAMESPACE_NODE *PrevNode; 180 ACPI_NAMESPACE_NODE *NextNode; 181 182 183 ACPI_FUNCTION_TRACE_PTR (NsRemoveNode, Node); 184 185 186 ParentNode = Node->Parent; 187 188 PrevNode = NULL; 189 NextNode = ParentNode->Child; 190 191 /* Find the node that is the previous peer in the parent's child list */ 192 193 while (NextNode != Node) 194 { 195 PrevNode = NextNode; 196 NextNode = NextNode->Peer; 197 } 198 199 if (PrevNode) 200 { 201 /* Node is not first child, unlink it */ 202 203 PrevNode->Peer = Node->Peer; 204 } 205 else 206 { 207 /* 208 * Node is first child (has no previous peer). 209 * Link peer list to parent 210 */ 211 ParentNode->Child = Node->Peer; 212 } 213 214 /* Delete the node and any attached objects */ 215 216 AcpiNsDeleteNode (Node); 217 return_VOID; 218} 219 220 221/******************************************************************************* 222 * 223 * FUNCTION: AcpiNsInstallNode 224 * 225 * PARAMETERS: WalkState - Current state of the walk 226 * ParentNode - The parent of the new Node 227 * Node - The new Node to install 228 * Type - ACPI object type of the new Node 229 * 230 * RETURN: None 231 * 232 * DESCRIPTION: Initialize a new namespace node and install it amongst 233 * its peers. 234 * 235 * Note: Current namespace lookup is linear search. This appears 236 * to be sufficient as namespace searches consume only a small 237 * fraction of the execution time of the ACPI subsystem. 238 * 239 ******************************************************************************/ 240 241void 242AcpiNsInstallNode ( 243 ACPI_WALK_STATE *WalkState, 244 ACPI_NAMESPACE_NODE *ParentNode, /* Parent */ 245 ACPI_NAMESPACE_NODE *Node, /* New Child*/ 246 ACPI_OBJECT_TYPE Type) 247{ 248 ACPI_OWNER_ID OwnerId = 0; 249 ACPI_NAMESPACE_NODE *ChildNode; 250 251 252 ACPI_FUNCTION_TRACE (NsInstallNode); 253 254 255 if (WalkState) 256 { 257 /* 258 * Get the owner ID from the Walk state. The owner ID is used to 259 * track table deletion and deletion of objects created by methods. 260 */ 261 OwnerId = WalkState->OwnerId; 262 263 if ((WalkState->MethodDesc) && 264 (ParentNode != WalkState->MethodNode)) 265 { 266 /* 267 * A method is creating a new node that is not a child of the 268 * method (it is non-local). Mark the executing method as having 269 * modified the namespace. This is used for cleanup when the 270 * method exits. 271 */ 272 WalkState->MethodDesc->Method.InfoFlags |= ACPI_METHOD_MODIFIED_NAMESPACE; 273 } 274 } 275 276 /* Link the new entry into the parent and existing children */ 277 278 Node->Peer = NULL; 279 Node->Parent = ParentNode; 280 ChildNode = ParentNode->Child; 281 282 if (!ChildNode) 283 { 284 ParentNode->Child = Node; 285 } 286 else 287 { 288 /* Add node to the end of the peer list */ 289 290 while (ChildNode->Peer) 291 { 292 ChildNode = ChildNode->Peer; 293 } 294 295 ChildNode->Peer = Node; 296 } 297 298 /* Init the new entry */ 299 300 Node->OwnerId = OwnerId; 301 Node->Type = (UINT8) Type; 302 303 ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, 304 "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n", 305 AcpiUtGetNodeName (Node), AcpiUtGetTypeName (Node->Type), Node, OwnerId, 306 AcpiUtGetNodeName (ParentNode), AcpiUtGetTypeName (ParentNode->Type), 307 ParentNode)); 308 309 return_VOID; 310} 311 312 313/******************************************************************************* 314 * 315 * FUNCTION: AcpiNsDeleteChildren 316 * 317 * PARAMETERS: ParentNode - Delete this objects children 318 * 319 * RETURN: None. 320 * 321 * DESCRIPTION: Delete all children of the parent object. In other words, 322 * deletes a "scope". 323 * 324 ******************************************************************************/ 325 326void 327AcpiNsDeleteChildren ( 328 ACPI_NAMESPACE_NODE *ParentNode) 329{ 330 ACPI_NAMESPACE_NODE *NextNode; 331 ACPI_NAMESPACE_NODE *NodeToDelete; 332 333 334 ACPI_FUNCTION_TRACE_PTR (NsDeleteChildren, ParentNode); 335 336 337 if (!ParentNode) 338 { 339 return_VOID; 340 } 341 342 /* Deallocate all children at this level */ 343 344 NextNode = ParentNode->Child; 345 while (NextNode) 346 { 347 /* Grandchildren should have all been deleted already */ 348 349 if (NextNode->Child) 350 { 351 ACPI_ERROR ((AE_INFO, "Found a grandchild! P=%p C=%p", 352 ParentNode, NextNode)); 353 } 354 355 /* 356 * Delete this child node and move on to the next child in the list. 357 * No need to unlink the node since we are deleting the entire branch. 358 */ 359 NodeToDelete = NextNode; 360 NextNode = NextNode->Peer; 361 AcpiNsDeleteNode (NodeToDelete); 362 }; 363 364 /* Clear the parent's child pointer */ 365 366 ParentNode->Child = NULL; 367 return_VOID; 368} 369 370 371/******************************************************************************* 372 * 373 * FUNCTION: AcpiNsDeleteNamespaceSubtree 374 * 375 * PARAMETERS: ParentNode - Root of the subtree to be deleted 376 * 377 * RETURN: None. 378 * 379 * DESCRIPTION: Delete a subtree of the namespace. This includes all objects 380 * stored within the subtree. 381 * 382 ******************************************************************************/ 383 384void 385AcpiNsDeleteNamespaceSubtree ( 386 ACPI_NAMESPACE_NODE *ParentNode) 387{ 388 ACPI_NAMESPACE_NODE *ChildNode = NULL; 389 UINT32 Level = 1; 390 ACPI_STATUS Status; 391 392 393 ACPI_FUNCTION_TRACE (NsDeleteNamespaceSubtree); 394 395 396 if (!ParentNode) 397 { 398 return_VOID; 399 } 400 401 /* Lock namespace for possible update */ 402 403 Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); 404 if (ACPI_FAILURE (Status)) 405 { 406 return_VOID; 407 } 408 409 /* 410 * Traverse the tree of objects until we bubble back up 411 * to where we started. 412 */ 413 while (Level > 0) 414 { 415 /* Get the next node in this scope (NULL if none) */ 416 417 ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode); 418 if (ChildNode) 419 { 420 /* Found a child node - detach any attached object */ 421 422 AcpiNsDetachObject (ChildNode); 423 424 /* Check if this node has any children */ 425 426 if (ChildNode->Child) 427 { 428 /* 429 * There is at least one child of this node, 430 * visit the node 431 */ 432 Level++; 433 ParentNode = ChildNode; 434 ChildNode = NULL; 435 } 436 } 437 else 438 { 439 /* 440 * No more children of this parent node. 441 * Move up to the grandparent. 442 */ 443 Level--; 444 445 /* 446 * Now delete all of the children of this parent 447 * all at the same time. 448 */ 449 AcpiNsDeleteChildren (ParentNode); 450 451 /* New "last child" is this parent node */ 452 453 ChildNode = ParentNode; 454 455 /* Move up the tree to the grandparent */ 456 457 ParentNode = ParentNode->Parent; 458 } 459 } 460 461 (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); 462 return_VOID; 463} 464 465 466/******************************************************************************* 467 * 468 * FUNCTION: AcpiNsDeleteNamespaceByOwner 469 * 470 * PARAMETERS: OwnerId - All nodes with this owner will be deleted 471 * 472 * RETURN: Status 473 * 474 * DESCRIPTION: Delete entries within the namespace that are owned by a 475 * specific ID. Used to delete entire ACPI tables. All 476 * reference counts are updated. 477 * 478 * MUTEX: Locks namespace during deletion walk. 479 * 480 ******************************************************************************/ 481 482void 483AcpiNsDeleteNamespaceByOwner ( 484 ACPI_OWNER_ID OwnerId) 485{ 486 ACPI_NAMESPACE_NODE *ChildNode; 487 ACPI_NAMESPACE_NODE *DeletionNode; 488 ACPI_NAMESPACE_NODE *ParentNode; 489 UINT32 Level; 490 ACPI_STATUS Status; 491 492 493 ACPI_FUNCTION_TRACE_U32 (NsDeleteNamespaceByOwner, OwnerId); 494 495 496 if (OwnerId == 0) 497 { 498 return_VOID; 499 } 500 501 /* Lock namespace for possible update */ 502 503 Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); 504 if (ACPI_FAILURE (Status)) 505 { 506 return_VOID; 507 } 508 509 DeletionNode = NULL; 510 ParentNode = AcpiGbl_RootNode; 511 ChildNode = NULL; 512 Level = 1; 513 514 /* 515 * Traverse the tree of nodes until we bubble back up 516 * to where we started. 517 */ 518 while (Level > 0) 519 { 520 /* 521 * Get the next child of this parent node. When ChildNode is NULL, 522 * the first child of the parent is returned 523 */ 524 ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode); 525 526 if (DeletionNode) 527 { 528 AcpiNsDeleteChildren (DeletionNode); 529 AcpiNsRemoveNode (DeletionNode); 530 DeletionNode = NULL; 531 } 532 533 if (ChildNode) 534 { 535 if (ChildNode->OwnerId == OwnerId) 536 { 537 /* Found a matching child node - detach any attached object */ 538 539 AcpiNsDetachObject (ChildNode); 540 } 541 542 /* Check if this node has any children */ 543 544 if (ChildNode->Child) 545 { 546 /* 547 * There is at least one child of this node, 548 * visit the node 549 */ 550 Level++; 551 ParentNode = ChildNode; 552 ChildNode = NULL; 553 } 554 else if (ChildNode->OwnerId == OwnerId) 555 { 556 DeletionNode = ChildNode; 557 } 558 } 559 else 560 { 561 /* 562 * No more children of this parent node. 563 * Move up to the grandparent. 564 */ 565 Level--; 566 if (Level != 0) 567 { 568 if (ParentNode->OwnerId == OwnerId) 569 { 570 DeletionNode = ParentNode; 571 } 572 } 573 574 /* New "last child" is this parent node */ 575 576 ChildNode = ParentNode; 577 578 /* Move up the tree to the grandparent */ 579 580 ParentNode = ParentNode->Parent; 581 } 582 } 583 584 (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); 585 return_VOID; 586} 587 588 589