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