LCOV - code coverage report
Current view: top level - drivers/acpi/acpica - nswalk.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 57 73 78.1 %
Date: 2022-04-01 14:35:51 Functions: 2 3 66.7 %
Branches: 32 49 65.3 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
       2                 :            : /******************************************************************************
       3                 :            :  *
       4                 :            :  * Module Name: nswalk - Functions for walking the ACPI namespace
       5                 :            :  *
       6                 :            :  * Copyright (C) 2000 - 2020, Intel Corp.
       7                 :            :  *
       8                 :            :  *****************************************************************************/
       9                 :            : 
      10                 :            : #include <acpi/acpi.h>
      11                 :            : #include "accommon.h"
      12                 :            : #include "acnamesp.h"
      13                 :            : 
      14                 :            : #define _COMPONENT          ACPI_NAMESPACE
      15                 :            : ACPI_MODULE_NAME("nswalk")
      16                 :            : 
      17                 :            : /*******************************************************************************
      18                 :            :  *
      19                 :            :  * FUNCTION:    acpi_ns_get_next_node
      20                 :            :  *
      21                 :            :  * PARAMETERS:  parent_node         - Parent node whose children we are
      22                 :            :  *                                    getting
      23                 :            :  *              child_node          - Previous child that was found.
      24                 :            :  *                                    The NEXT child will be returned
      25                 :            :  *
      26                 :            :  * RETURN:      struct acpi_namespace_node - Pointer to the NEXT child or NULL if
      27                 :            :  *                                    none is found.
      28                 :            :  *
      29                 :            :  * DESCRIPTION: Return the next peer node within the namespace. If Handle
      30                 :            :  *              is valid, Scope is ignored. Otherwise, the first node
      31                 :            :  *              within Scope is returned.
      32                 :            :  *
      33                 :            :  ******************************************************************************/
      34                 :     111552 : struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
      35                 :            :                                                   *parent_node,
      36                 :            :                                                   struct acpi_namespace_node
      37                 :            :                                                   *child_node)
      38                 :            : {
      39                 :     111552 :         ACPI_FUNCTION_ENTRY();
      40                 :            : 
      41         [ +  + ]:       2499 :         if (!child_node) {
      42                 :            : 
      43                 :            :                 /* It's really the parent's _scope_ that we want */
      44                 :            : 
      45                 :       2100 :                 return (parent_node->child);
      46                 :            :         }
      47                 :            : 
      48                 :            :         /* Otherwise just return the next peer */
      49                 :            : 
      50                 :        399 :         return (child_node->peer);
      51                 :            : }
      52                 :            : 
      53                 :            : /*******************************************************************************
      54                 :            :  *
      55                 :            :  * FUNCTION:    acpi_ns_get_next_node_typed
      56                 :            :  *
      57                 :            :  * PARAMETERS:  type                - Type of node to be searched for
      58                 :            :  *              parent_node         - Parent node whose children we are
      59                 :            :  *                                    getting
      60                 :            :  *              child_node          - Previous child that was found.
      61                 :            :  *                                    The NEXT child will be returned
      62                 :            :  *
      63                 :            :  * RETURN:      struct acpi_namespace_node - Pointer to the NEXT child or NULL if
      64                 :            :  *                                    none is found.
      65                 :            :  *
      66                 :            :  * DESCRIPTION: Return the next peer node within the namespace. If Handle
      67                 :            :  *              is valid, Scope is ignored. Otherwise, the first node
      68                 :            :  *              within Scope is returned.
      69                 :            :  *
      70                 :            :  ******************************************************************************/
      71                 :            : 
      72                 :          0 : struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
      73                 :            :                                                         struct
      74                 :            :                                                         acpi_namespace_node
      75                 :            :                                                         *parent_node,
      76                 :            :                                                         struct
      77                 :            :                                                         acpi_namespace_node
      78                 :            :                                                         *child_node)
      79                 :            : {
      80                 :          0 :         struct acpi_namespace_node *next_node = NULL;
      81                 :            : 
      82                 :          0 :         ACPI_FUNCTION_ENTRY();
      83                 :            : 
      84         [ #  # ]:          0 :         next_node = acpi_ns_get_next_node(parent_node, child_node);
      85                 :            : 
      86                 :            : 
      87                 :            :         /* If any type is OK, we are done */
      88                 :            : 
      89         [ #  # ]:          0 :         if (type == ACPI_TYPE_ANY) {
      90                 :            : 
      91                 :            :                 /* next_node is NULL if we are at the end-of-list */
      92                 :            : 
      93                 :            :                 return (next_node);
      94                 :            :         }
      95                 :            : 
      96                 :            :         /* Must search for the node -- but within this scope only */
      97                 :            : 
      98         [ #  # ]:          0 :         while (next_node) {
      99                 :            : 
     100                 :            :                 /* If type matches, we are done */
     101                 :            : 
     102         [ #  # ]:          0 :                 if (next_node->type == type) {
     103                 :          0 :                         return (next_node);
     104                 :            :                 }
     105                 :            : 
     106                 :            :                 /* Otherwise, move on to the next peer node */
     107                 :            : 
     108                 :          0 :                 next_node = next_node->peer;
     109                 :            :         }
     110                 :            : 
     111                 :            :         /* Not found */
     112                 :            : 
     113                 :            :         return (NULL);
     114                 :            : }
     115                 :            : 
     116                 :            : /*******************************************************************************
     117                 :            :  *
     118                 :            :  * FUNCTION:    acpi_ns_walk_namespace
     119                 :            :  *
     120                 :            :  * PARAMETERS:  type                - acpi_object_type to search for
     121                 :            :  *              start_node          - Handle in namespace where search begins
     122                 :            :  *              max_depth           - Depth to which search is to reach
     123                 :            :  *              flags               - Whether to unlock the NS before invoking
     124                 :            :  *                                    the callback routine
     125                 :            :  *              descending_callback - Called during tree descent
     126                 :            :  *                                    when an object of "Type" is found
     127                 :            :  *              ascending_callback  - Called during tree ascent
     128                 :            :  *                                    when an object of "Type" is found
     129                 :            :  *              context             - Passed to user function(s) above
     130                 :            :  *              return_value        - from the user_function if terminated
     131                 :            :  *                                    early. Otherwise, returns NULL.
     132                 :            :  * RETURNS:     Status
     133                 :            :  *
     134                 :            :  * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
     135                 :            :  *              starting (and ending) at the node specified by start_handle.
     136                 :            :  *              The callback function is called whenever a node that matches
     137                 :            :  *              the type parameter is found. If the callback function returns
     138                 :            :  *              a non-zero value, the search is terminated immediately and
     139                 :            :  *              this value is returned to the caller.
     140                 :            :  *
     141                 :            :  *              The point of this procedure is to provide a generic namespace
     142                 :            :  *              walk routine that can be called from multiple places to
     143                 :            :  *              provide multiple services; the callback function(s) can be
     144                 :            :  *              tailored to each task, whether it is a print function,
     145                 :            :  *              a compare function, etc.
     146                 :            :  *
     147                 :            :  ******************************************************************************/
     148                 :            : 
     149                 :            : acpi_status
     150                 :        504 : acpi_ns_walk_namespace(acpi_object_type type,
     151                 :            :                        acpi_handle start_node,
     152                 :            :                        u32 max_depth,
     153                 :            :                        u32 flags,
     154                 :            :                        acpi_walk_callback descending_callback,
     155                 :            :                        acpi_walk_callback ascending_callback,
     156                 :            :                        void *context, void **return_value)
     157                 :            : {
     158                 :        504 :         acpi_status status;
     159                 :        504 :         acpi_status mutex_status;
     160                 :        504 :         struct acpi_namespace_node *child_node;
     161                 :        504 :         struct acpi_namespace_node *parent_node;
     162                 :        504 :         acpi_object_type child_type;
     163                 :        504 :         u32 level;
     164                 :        504 :         u8 node_previously_visited = FALSE;
     165                 :            : 
     166                 :        504 :         ACPI_FUNCTION_TRACE(ns_walk_namespace);
     167                 :            : 
     168                 :            :         /* Special case for the namespace Root Node */
     169                 :            : 
     170         [ +  + ]:        504 :         if (start_node == ACPI_ROOT_OBJECT) {
     171                 :        231 :                 start_node = acpi_gbl_root_node;
     172                 :            :         }
     173                 :            : 
     174                 :            :         /* Null child means "get first node" */
     175                 :            : 
     176                 :        504 :         parent_node = start_node;
     177                 :        504 :         child_node = acpi_ns_get_next_node(parent_node, NULL);
     178                 :        504 :         child_type = ACPI_TYPE_ANY;
     179                 :        504 :         level = 1;
     180                 :            : 
     181                 :            :         /*
     182                 :            :          * Traverse the tree of nodes until we bubble back up to where we
     183                 :            :          * started. When Level is zero, the loop is done because we have
     184                 :            :          * bubbled up to (and passed) the original parent handle (start_entry)
     185                 :            :          */
     186         [ +  + ]:     183582 :         while (level > 0 && child_node) {
     187                 :     183078 :                 status = AE_OK;
     188                 :            : 
     189                 :            :                 /* Found next child, get the type if we are not searching for ANY */
     190                 :            : 
     191         [ +  + ]:     183078 :                 if (type != ACPI_TYPE_ANY) {
     192                 :      97734 :                         child_type = child_node->type;
     193                 :            :                 }
     194                 :            : 
     195                 :            :                 /*
     196                 :            :                  * Ignore all temporary namespace nodes (created during control
     197                 :            :                  * method execution) unless told otherwise. These temporary nodes
     198                 :            :                  * can cause a race condition because they can be deleted during
     199                 :            :                  * the execution of the user function (if the namespace is
     200                 :            :                  * unlocked before invocation of the user function.) Only the
     201                 :            :                  * debugger namespace dump will examine the temporary nodes.
     202                 :            :                  */
     203         [ -  + ]:     183078 :                 if ((child_node->flags & ANOBJ_TEMPORARY) &&
     204         [ #  # ]:          0 :                     !(flags & ACPI_NS_WALK_TEMP_NODES)) {
     205                 :            :                         status = AE_CTRL_DEPTH;
     206                 :            :                 }
     207                 :            : 
     208                 :            :                 /* Type must match requested type */
     209                 :            : 
     210         [ +  + ]:     183078 :                 else if (child_type == type) {
     211                 :            :                         /*
     212                 :            :                          * Found a matching node, invoke the user callback function.
     213                 :            :                          * Unlock the namespace if flag is set.
     214                 :            :                          */
     215         [ +  + ]:     100506 :                         if (flags & ACPI_NS_WALK_UNLOCK) {
     216                 :      71484 :                                 mutex_status =
     217                 :      71484 :                                     acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
     218         [ -  + ]:      71484 :                                 if (ACPI_FAILURE(mutex_status)) {
     219                 :          0 :                                         return_ACPI_STATUS(mutex_status);
     220                 :            :                                 }
     221                 :            :                         }
     222                 :            : 
     223                 :            :                         /*
     224                 :            :                          * Invoke the user function, either descending, ascending,
     225                 :            :                          * or both.
     226                 :            :                          */
     227         [ +  + ]:     100506 :                         if (!node_previously_visited) {
     228         [ +  - ]:      50253 :                                 if (descending_callback) {
     229                 :      50253 :                                         status =
     230                 :      50253 :                                             descending_callback(child_node,
     231                 :            :                                                                 level, context,
     232                 :            :                                                                 return_value);
     233                 :            :                                 }
     234                 :            :                         } else {
     235         [ -  + ]:      50253 :                                 if (ascending_callback) {
     236                 :          0 :                                         status =
     237                 :          0 :                                             ascending_callback(child_node,
     238                 :            :                                                                level, context,
     239                 :            :                                                                return_value);
     240                 :            :                                 }
     241                 :            :                         }
     242                 :            : 
     243         [ +  + ]:     100506 :                         if (flags & ACPI_NS_WALK_UNLOCK) {
     244                 :      71484 :                                 mutex_status =
     245                 :      71484 :                                     acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
     246         [ -  + ]:      71484 :                                 if (ACPI_FAILURE(mutex_status)) {
     247                 :          0 :                                         return_ACPI_STATUS(mutex_status);
     248                 :            :                                 }
     249                 :            :                         }
     250                 :            : 
     251      [ -  +  - ]:     100506 :                         switch (status) {
     252                 :            :                         case AE_OK:
     253                 :            :                         case AE_CTRL_DEPTH:
     254                 :            : 
     255                 :            :                                 /* Just keep going */
     256                 :            :                                 break;
     257                 :            : 
     258                 :            :                         case AE_CTRL_TERMINATE:
     259                 :            : 
     260                 :            :                                 /* Exit now, with OK status */
     261                 :            : 
     262                 :            :                                 return_ACPI_STATUS(AE_OK);
     263                 :            : 
     264                 :          0 :                         default:
     265                 :            : 
     266                 :            :                                 /* All others are valid exceptions */
     267                 :            : 
     268                 :          0 :                                 return_ACPI_STATUS(status);
     269                 :            :                         }
     270                 :      82572 :                 }
     271                 :            : 
     272                 :            :                 /*
     273                 :            :                  * Depth first search: Attempt to go down another level in the
     274                 :            :                  * namespace if we are allowed to. Don't go any further if we have
     275                 :            :                  * reached the caller specified maximum depth or if the user
     276                 :            :                  * function has specified that the maximum depth has been reached.
     277                 :            :                  */
     278                 :     183078 :                 if (!node_previously_visited &&
     279   [ +  +  +  + ]:     183078 :                     (level < max_depth) && (status != AE_CTRL_DEPTH)) {
     280         [ +  + ]:      89460 :                         if (child_node->child) {
     281                 :            : 
     282                 :            :                                 /* There is at least one child of this node, visit it */
     283                 :            : 
     284                 :      17010 :                                 level++;
     285                 :      17010 :                                 parent_node = child_node;
     286                 :      17010 :                                 child_node =
     287                 :            :                                     acpi_ns_get_next_node(parent_node, NULL);
     288                 :      17010 :                                 continue;
     289                 :            :                         }
     290                 :            :                 }
     291                 :            : 
     292                 :            :                 /* No more children, re-visit this node */
     293                 :            : 
     294         [ +  + ]:     166068 :                 if (!node_previously_visited) {
     295                 :      74529 :                         node_previously_visited = TRUE;
     296                 :      74529 :                         continue;
     297                 :            :                 }
     298                 :            : 
     299                 :            :                 /* No more children, visit peers */
     300                 :            : 
     301                 :      91539 :                 child_node = acpi_ns_get_next_node(parent_node, child_node);
     302         [ +  + ]:      91539 :                 if (child_node) {
     303                 :            :                         node_previously_visited = FALSE;
     304                 :            :                 }
     305                 :            : 
     306                 :            :                 /* No peers, re-visit parent */
     307                 :            : 
     308                 :            :                 else {
     309                 :            :                         /*
     310                 :            :                          * No more children of this node (acpi_ns_get_next_node failed), go
     311                 :            :                          * back upwards in the namespace tree to the node's parent.
     312                 :            :                          */
     313                 :      17514 :                         level--;
     314                 :      17514 :                         child_node = parent_node;
     315                 :      17514 :                         parent_node = parent_node->parent;
     316                 :            : 
     317                 :      17514 :                         node_previously_visited = TRUE;
     318                 :            :                 }
     319                 :            :         }
     320                 :            : 
     321                 :            :         /* Complete walk, not terminated by user function */
     322                 :            : 
     323                 :            :         return_ACPI_STATUS(AE_OK);
     324                 :            : }

Generated by: LCOV version 1.14