xref: /titanic_51/usr/src/uts/intel/io/acpica/namespace/nswalk.c (revision 385cc6b4ad1792caef3f84eb61eed3f27085801f)
1ae115bc7Smrj /******************************************************************************
2ae115bc7Smrj  *
3ae115bc7Smrj  * Module Name: nswalk - Functions for walking the ACPI namespace
4ae115bc7Smrj  *
5ae115bc7Smrj  *****************************************************************************/
6ae115bc7Smrj 
726f3cdf0SGordon Ross /*
8*385cc6b4SJerry Jelinek  * Copyright (C) 2000 - 2016, Intel Corp.
9ae115bc7Smrj  * All rights reserved.
10ae115bc7Smrj  *
1126f3cdf0SGordon Ross  * Redistribution and use in source and binary forms, with or without
1226f3cdf0SGordon Ross  * modification, are permitted provided that the following conditions
1326f3cdf0SGordon Ross  * are met:
1426f3cdf0SGordon Ross  * 1. Redistributions of source code must retain the above copyright
1526f3cdf0SGordon Ross  *    notice, this list of conditions, and the following disclaimer,
1626f3cdf0SGordon Ross  *    without modification.
1726f3cdf0SGordon Ross  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1826f3cdf0SGordon Ross  *    substantially similar to the "NO WARRANTY" disclaimer below
1926f3cdf0SGordon Ross  *    ("Disclaimer") and any redistribution must be conditioned upon
2026f3cdf0SGordon Ross  *    including a substantially similar Disclaimer requirement for further
2126f3cdf0SGordon Ross  *    binary redistribution.
2226f3cdf0SGordon Ross  * 3. Neither the names of the above-listed copyright holders nor the names
2326f3cdf0SGordon Ross  *    of any contributors may be used to endorse or promote products derived
2426f3cdf0SGordon Ross  *    from this software without specific prior written permission.
25ae115bc7Smrj  *
2626f3cdf0SGordon Ross  * Alternatively, this software may be distributed under the terms of the
2726f3cdf0SGordon Ross  * GNU General Public License ("GPL") version 2 as published by the Free
2826f3cdf0SGordon Ross  * Software Foundation.
29ae115bc7Smrj  *
3026f3cdf0SGordon Ross  * NO WARRANTY
3126f3cdf0SGordon Ross  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3226f3cdf0SGordon Ross  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3326f3cdf0SGordon Ross  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3426f3cdf0SGordon Ross  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3526f3cdf0SGordon Ross  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3626f3cdf0SGordon Ross  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3726f3cdf0SGordon Ross  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3826f3cdf0SGordon Ross  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3926f3cdf0SGordon Ross  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4026f3cdf0SGordon Ross  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4126f3cdf0SGordon Ross  * POSSIBILITY OF SUCH DAMAGES.
4226f3cdf0SGordon Ross  */
43ae115bc7Smrj 
44ae115bc7Smrj #include "acpi.h"
45aa2aa9a6SDana Myers #include "accommon.h"
46ae115bc7Smrj #include "acnamesp.h"
47ae115bc7Smrj 
48ae115bc7Smrj 
49ae115bc7Smrj #define _COMPONENT          ACPI_NAMESPACE
50ae115bc7Smrj         ACPI_MODULE_NAME    ("nswalk")
51ae115bc7Smrj 
52ae115bc7Smrj 
53ae115bc7Smrj /*******************************************************************************
54ae115bc7Smrj  *
55ae115bc7Smrj  * FUNCTION:    AcpiNsGetNextNode
56ae115bc7Smrj  *
57aa2aa9a6SDana Myers  * PARAMETERS:  ParentNode          - Parent node whose children we are
58aa2aa9a6SDana Myers  *                                    getting
59aa2aa9a6SDana Myers  *              ChildNode           - Previous child that was found.
60aa2aa9a6SDana Myers  *                                    The NEXT child will be returned
61aa2aa9a6SDana Myers  *
62aa2aa9a6SDana Myers  * RETURN:      ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if
63aa2aa9a6SDana Myers  *                                    none is found.
64aa2aa9a6SDana Myers  *
65aa2aa9a6SDana Myers  * DESCRIPTION: Return the next peer node within the namespace. If Handle
66aa2aa9a6SDana Myers  *              is valid, Scope is ignored. Otherwise, the first node
67aa2aa9a6SDana Myers  *              within Scope is returned.
68aa2aa9a6SDana Myers  *
69aa2aa9a6SDana Myers  ******************************************************************************/
70aa2aa9a6SDana Myers 
71aa2aa9a6SDana Myers ACPI_NAMESPACE_NODE *
72aa2aa9a6SDana Myers AcpiNsGetNextNode (
73aa2aa9a6SDana Myers     ACPI_NAMESPACE_NODE     *ParentNode,
74aa2aa9a6SDana Myers     ACPI_NAMESPACE_NODE     *ChildNode)
75aa2aa9a6SDana Myers {
76aa2aa9a6SDana Myers     ACPI_FUNCTION_ENTRY ();
77aa2aa9a6SDana Myers 
78aa2aa9a6SDana Myers 
79aa2aa9a6SDana Myers     if (!ChildNode)
80aa2aa9a6SDana Myers     {
81aa2aa9a6SDana Myers         /* It's really the parent's _scope_ that we want */
82aa2aa9a6SDana Myers 
83aa2aa9a6SDana Myers         return (ParentNode->Child);
84aa2aa9a6SDana Myers     }
85aa2aa9a6SDana Myers 
86aa2aa9a6SDana Myers     /* Otherwise just return the next peer */
87aa2aa9a6SDana Myers 
88aa2aa9a6SDana Myers     return (ChildNode->Peer);
89aa2aa9a6SDana Myers }
90aa2aa9a6SDana Myers 
91aa2aa9a6SDana Myers 
92aa2aa9a6SDana Myers /*******************************************************************************
93aa2aa9a6SDana Myers  *
94aa2aa9a6SDana Myers  * FUNCTION:    AcpiNsGetNextNodeTyped
95aa2aa9a6SDana Myers  *
96ae115bc7Smrj  * PARAMETERS:  Type                - Type of node to be searched for
97ae115bc7Smrj  *              ParentNode          - Parent node whose children we are
98ae115bc7Smrj  *                                    getting
99ae115bc7Smrj  *              ChildNode           - Previous child that was found.
100ae115bc7Smrj  *                                    The NEXT child will be returned
101ae115bc7Smrj  *
102ae115bc7Smrj  * RETURN:      ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if
103ae115bc7Smrj  *                                    none is found.
104ae115bc7Smrj  *
105ae115bc7Smrj  * DESCRIPTION: Return the next peer node within the namespace. If Handle
106ae115bc7Smrj  *              is valid, Scope is ignored. Otherwise, the first node
107ae115bc7Smrj  *              within Scope is returned.
108ae115bc7Smrj  *
109ae115bc7Smrj  ******************************************************************************/
110ae115bc7Smrj 
111ae115bc7Smrj ACPI_NAMESPACE_NODE *
112aa2aa9a6SDana Myers AcpiNsGetNextNodeTyped (
113ae115bc7Smrj     ACPI_OBJECT_TYPE        Type,
114ae115bc7Smrj     ACPI_NAMESPACE_NODE     *ParentNode,
115ae115bc7Smrj     ACPI_NAMESPACE_NODE     *ChildNode)
116ae115bc7Smrj {
117ae115bc7Smrj     ACPI_NAMESPACE_NODE     *NextNode = NULL;
118ae115bc7Smrj 
119ae115bc7Smrj 
120ae115bc7Smrj     ACPI_FUNCTION_ENTRY ();
121ae115bc7Smrj 
122ae115bc7Smrj 
123aa2aa9a6SDana Myers     NextNode = AcpiNsGetNextNode (ParentNode, ChildNode);
124ae115bc7Smrj 
125ae115bc7Smrj     /* If any type is OK, we are done */
126ae115bc7Smrj 
127ae115bc7Smrj     if (Type == ACPI_TYPE_ANY)
128ae115bc7Smrj     {
129ae115bc7Smrj         /* NextNode is NULL if we are at the end-of-list */
130ae115bc7Smrj 
131ae115bc7Smrj         return (NextNode);
132ae115bc7Smrj     }
133ae115bc7Smrj 
134ae115bc7Smrj     /* Must search for the node -- but within this scope only */
135ae115bc7Smrj 
136ae115bc7Smrj     while (NextNode)
137ae115bc7Smrj     {
138ae115bc7Smrj         /* If type matches, we are done */
139ae115bc7Smrj 
140ae115bc7Smrj         if (NextNode->Type == Type)
141ae115bc7Smrj         {
142ae115bc7Smrj             return (NextNode);
143ae115bc7Smrj         }
144ae115bc7Smrj 
14526f3cdf0SGordon Ross         /* Otherwise, move on to the next peer node */
146ae115bc7Smrj 
14726f3cdf0SGordon Ross         NextNode = NextNode->Peer;
148ae115bc7Smrj     }
149ae115bc7Smrj 
150ae115bc7Smrj     /* Not found */
151ae115bc7Smrj 
152ae115bc7Smrj     return (NULL);
153ae115bc7Smrj }
154ae115bc7Smrj 
155ae115bc7Smrj 
156ae115bc7Smrj /*******************************************************************************
157ae115bc7Smrj  *
158ae115bc7Smrj  * FUNCTION:    AcpiNsWalkNamespace
159ae115bc7Smrj  *
160ae115bc7Smrj  * PARAMETERS:  Type                - ACPI_OBJECT_TYPE to search for
161ae115bc7Smrj  *              StartNode           - Handle in namespace where search begins
162ae115bc7Smrj  *              MaxDepth            - Depth to which search is to reach
163db2bae30SDana Myers  *              Flags               - Whether to unlock the NS before invoking
164ae115bc7Smrj  *                                    the callback routine
165*385cc6b4SJerry Jelinek  *              DescendingCallback  - Called during tree descent
16657190917SDana Myers  *                                    when an object of "Type" is found
167*385cc6b4SJerry Jelinek  *              AscendingCallback   - Called during tree ascent
16857190917SDana Myers  *                                    when an object of "Type" is found
16957190917SDana Myers  *              Context             - Passed to user function(s) above
17057190917SDana Myers  *              ReturnValue         - from the UserFunction if terminated
17157190917SDana Myers  *                                    early. Otherwise, returns NULL.
172ae115bc7Smrj  * RETURNS:     Status
173ae115bc7Smrj  *
174ae115bc7Smrj  * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
175ae115bc7Smrj  *              starting (and ending) at the node specified by StartHandle.
17657190917SDana Myers  *              The callback function is called whenever a node that matches
17757190917SDana Myers  *              the type parameter is found. If the callback function returns
178aa2aa9a6SDana Myers  *              a non-zero value, the search is terminated immediately and
179aa2aa9a6SDana Myers  *              this value is returned to the caller.
180ae115bc7Smrj  *
181ae115bc7Smrj  *              The point of this procedure is to provide a generic namespace
182ae115bc7Smrj  *              walk routine that can be called from multiple places to
18357190917SDana Myers  *              provide multiple services; the callback function(s) can be
18457190917SDana Myers  *              tailored to each task, whether it is a print function,
18557190917SDana Myers  *              a compare function, etc.
186ae115bc7Smrj  *
187ae115bc7Smrj  ******************************************************************************/
188ae115bc7Smrj 
189ae115bc7Smrj ACPI_STATUS
190ae115bc7Smrj AcpiNsWalkNamespace (
191ae115bc7Smrj     ACPI_OBJECT_TYPE        Type,
192ae115bc7Smrj     ACPI_HANDLE             StartNode,
193ae115bc7Smrj     UINT32                  MaxDepth,
194db2bae30SDana Myers     UINT32                  Flags,
195*385cc6b4SJerry Jelinek     ACPI_WALK_CALLBACK      DescendingCallback,
196*385cc6b4SJerry Jelinek     ACPI_WALK_CALLBACK      AscendingCallback,
197ae115bc7Smrj     void                    *Context,
198ae115bc7Smrj     void                    **ReturnValue)
199ae115bc7Smrj {
200ae115bc7Smrj     ACPI_STATUS             Status;
201ae115bc7Smrj     ACPI_STATUS             MutexStatus;
202ae115bc7Smrj     ACPI_NAMESPACE_NODE     *ChildNode;
203ae115bc7Smrj     ACPI_NAMESPACE_NODE     *ParentNode;
204ae115bc7Smrj     ACPI_OBJECT_TYPE        ChildType;
205ae115bc7Smrj     UINT32                  Level;
20657190917SDana Myers     BOOLEAN                 NodePreviouslyVisited = FALSE;
207ae115bc7Smrj 
208ae115bc7Smrj 
209ae115bc7Smrj     ACPI_FUNCTION_TRACE (NsWalkNamespace);
210ae115bc7Smrj 
211ae115bc7Smrj 
212ae115bc7Smrj     /* Special case for the namespace Root Node */
213ae115bc7Smrj 
214ae115bc7Smrj     if (StartNode == ACPI_ROOT_OBJECT)
215ae115bc7Smrj     {
216ae115bc7Smrj         StartNode = AcpiGbl_RootNode;
217ae115bc7Smrj     }
218ae115bc7Smrj 
219ae115bc7Smrj     /* Null child means "get first node" */
220ae115bc7Smrj 
221ae115bc7Smrj     ParentNode = StartNode;
22257190917SDana Myers     ChildNode = AcpiNsGetNextNode (ParentNode, NULL);
223ae115bc7Smrj     ChildType = ACPI_TYPE_ANY;
224ae115bc7Smrj     Level = 1;
225ae115bc7Smrj 
226ae115bc7Smrj     /*
227ae115bc7Smrj      * Traverse the tree of nodes until we bubble back up to where we
228ae115bc7Smrj      * started. When Level is zero, the loop is done because we have
229ae115bc7Smrj      * bubbled up to (and passed) the original parent handle (StartEntry)
230ae115bc7Smrj      */
23157190917SDana Myers     while (Level > 0 && ChildNode)
232ae115bc7Smrj     {
233ae115bc7Smrj         Status = AE_OK;
23457190917SDana Myers 
235db2bae30SDana Myers         /* Found next child, get the type if we are not searching for ANY */
236db2bae30SDana Myers 
237ae115bc7Smrj         if (Type != ACPI_TYPE_ANY)
238ae115bc7Smrj         {
239ae115bc7Smrj             ChildType = ChildNode->Type;
240ae115bc7Smrj         }
241ae115bc7Smrj 
242db2bae30SDana Myers         /*
243db2bae30SDana Myers          * Ignore all temporary namespace nodes (created during control
244db2bae30SDana Myers          * method execution) unless told otherwise. These temporary nodes
245aa2aa9a6SDana Myers          * can cause a race condition because they can be deleted during
246aa2aa9a6SDana Myers          * the execution of the user function (if the namespace is
247aa2aa9a6SDana Myers          * unlocked before invocation of the user function.) Only the
248aa2aa9a6SDana Myers          * debugger namespace dump will examine the temporary nodes.
249db2bae30SDana Myers          */
250db2bae30SDana Myers         if ((ChildNode->Flags & ANOBJ_TEMPORARY) &&
251db2bae30SDana Myers             !(Flags & ACPI_NS_WALK_TEMP_NODES))
252db2bae30SDana Myers         {
253db2bae30SDana Myers             Status = AE_CTRL_DEPTH;
254db2bae30SDana Myers         }
255db2bae30SDana Myers 
256db2bae30SDana Myers         /* Type must match requested type */
257db2bae30SDana Myers 
258db2bae30SDana Myers         else if (ChildType == Type)
259ae115bc7Smrj         {
260ae115bc7Smrj             /*
261db2bae30SDana Myers              * Found a matching node, invoke the user callback function.
262db2bae30SDana Myers              * Unlock the namespace if flag is set.
263ae115bc7Smrj              */
264db2bae30SDana Myers             if (Flags & ACPI_NS_WALK_UNLOCK)
265ae115bc7Smrj             {
266ae115bc7Smrj                 MutexStatus = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
267ae115bc7Smrj                 if (ACPI_FAILURE (MutexStatus))
268ae115bc7Smrj                 {
269ae115bc7Smrj                     return_ACPI_STATUS (MutexStatus);
270ae115bc7Smrj                 }
271ae115bc7Smrj             }
272ae115bc7Smrj 
27357190917SDana Myers             /*
274*385cc6b4SJerry Jelinek              * Invoke the user function, either descending, ascending,
27557190917SDana Myers              * or both.
27657190917SDana Myers              */
27757190917SDana Myers             if (!NodePreviouslyVisited)
27857190917SDana Myers             {
279*385cc6b4SJerry Jelinek                 if (DescendingCallback)
28057190917SDana Myers                 {
281*385cc6b4SJerry Jelinek                     Status = DescendingCallback (ChildNode, Level,
28257190917SDana Myers                         Context, ReturnValue);
28357190917SDana Myers                 }
28457190917SDana Myers             }
28557190917SDana Myers             else
28657190917SDana Myers             {
287*385cc6b4SJerry Jelinek                 if (AscendingCallback)
28857190917SDana Myers                 {
289*385cc6b4SJerry Jelinek                     Status = AscendingCallback (ChildNode, Level,
29057190917SDana Myers                         Context, ReturnValue);
29157190917SDana Myers                 }
29257190917SDana Myers             }
293ae115bc7Smrj 
294db2bae30SDana Myers             if (Flags & ACPI_NS_WALK_UNLOCK)
295ae115bc7Smrj             {
296ae115bc7Smrj                 MutexStatus = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
297ae115bc7Smrj                 if (ACPI_FAILURE (MutexStatus))
298ae115bc7Smrj                 {
299ae115bc7Smrj                     return_ACPI_STATUS (MutexStatus);
300ae115bc7Smrj                 }
301ae115bc7Smrj             }
302ae115bc7Smrj 
303ae115bc7Smrj             switch (Status)
304ae115bc7Smrj             {
305ae115bc7Smrj             case AE_OK:
306ae115bc7Smrj             case AE_CTRL_DEPTH:
307ae115bc7Smrj 
308ae115bc7Smrj                 /* Just keep going */
309ae115bc7Smrj                 break;
310ae115bc7Smrj 
311ae115bc7Smrj             case AE_CTRL_TERMINATE:
312ae115bc7Smrj 
313ae115bc7Smrj                 /* Exit now, with OK status */
314ae115bc7Smrj 
315ae115bc7Smrj                 return_ACPI_STATUS (AE_OK);
316ae115bc7Smrj 
317ae115bc7Smrj             default:
318ae115bc7Smrj 
319ae115bc7Smrj                 /* All others are valid exceptions */
320ae115bc7Smrj 
321ae115bc7Smrj                 return_ACPI_STATUS (Status);
322ae115bc7Smrj             }
323ae115bc7Smrj         }
324ae115bc7Smrj 
325ae115bc7Smrj         /*
326db2bae30SDana Myers          * Depth first search: Attempt to go down another level in the
327db2bae30SDana Myers          * namespace if we are allowed to. Don't go any further if we have
328db2bae30SDana Myers          * reached the caller specified maximum depth or if the user
329db2bae30SDana Myers          * function has specified that the maximum depth has been reached.
330ae115bc7Smrj          */
33157190917SDana Myers         if (!NodePreviouslyVisited &&
33257190917SDana Myers             (Level < MaxDepth) &&
33357190917SDana Myers             (Status != AE_CTRL_DEPTH))
334ae115bc7Smrj         {
335aa2aa9a6SDana Myers             if (ChildNode->Child)
336ae115bc7Smrj             {
337db2bae30SDana Myers                 /* There is at least one child of this node, visit it */
338db2bae30SDana Myers 
339ae115bc7Smrj                 Level++;
340ae115bc7Smrj                 ParentNode = ChildNode;
34157190917SDana Myers                 ChildNode = AcpiNsGetNextNode (ParentNode, NULL);
34257190917SDana Myers                 continue;
343ae115bc7Smrj             }
344ae115bc7Smrj         }
34557190917SDana Myers 
34657190917SDana Myers         /* No more children, re-visit this node */
34757190917SDana Myers 
34857190917SDana Myers         if (!NodePreviouslyVisited)
34957190917SDana Myers         {
35057190917SDana Myers             NodePreviouslyVisited = TRUE;
35157190917SDana Myers             continue;
352ae115bc7Smrj         }
35357190917SDana Myers 
35457190917SDana Myers         /* No more children, visit peers */
35557190917SDana Myers 
35657190917SDana Myers         ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode);
35757190917SDana Myers         if (ChildNode)
35857190917SDana Myers         {
35957190917SDana Myers             NodePreviouslyVisited = FALSE;
36057190917SDana Myers         }
36157190917SDana Myers 
36257190917SDana Myers         /* No peers, re-visit parent */
36357190917SDana Myers 
364ae115bc7Smrj         else
365ae115bc7Smrj         {
366ae115bc7Smrj             /*
367db2bae30SDana Myers              * No more children of this node (AcpiNsGetNextNode failed), go
368db2bae30SDana Myers              * back upwards in the namespace tree to the node's parent.
369ae115bc7Smrj              */
370ae115bc7Smrj             Level--;
371ae115bc7Smrj             ChildNode = ParentNode;
37226f3cdf0SGordon Ross             ParentNode = ParentNode->Parent;
37357190917SDana Myers 
37457190917SDana Myers             NodePreviouslyVisited = TRUE;
375ae115bc7Smrj         }
376ae115bc7Smrj     }
377ae115bc7Smrj 
378ae115bc7Smrj     /* Complete walk, not terminated by user function */
379ae115bc7Smrj 
380ae115bc7Smrj     return_ACPI_STATUS (AE_OK);
381ae115bc7Smrj }
382