1*40d553cfSPaul BeesleyPSCI Power Domain Tree design 2*40d553cfSPaul Beesley============================= 3*40d553cfSPaul Beesley 4*40d553cfSPaul Beesley 5*40d553cfSPaul Beesley 6*40d553cfSPaul Beesley 7*40d553cfSPaul Beesley.. contents:: 8*40d553cfSPaul Beesley 9*40d553cfSPaul Beesley-------------- 10*40d553cfSPaul Beesley 11*40d553cfSPaul BeesleyRequirements 12*40d553cfSPaul Beesley------------ 13*40d553cfSPaul Beesley 14*40d553cfSPaul Beesley#. A platform must export the ``plat_get_aff_count()`` and 15*40d553cfSPaul Beesley ``plat_get_aff_state()`` APIs to enable the generic PSCI code to 16*40d553cfSPaul Beesley populate a tree that describes the hierarchy of power domains in the 17*40d553cfSPaul Beesley system. This approach is inflexible because a change to the topology 18*40d553cfSPaul Beesley requires a change in the code. 19*40d553cfSPaul Beesley 20*40d553cfSPaul Beesley It would be much simpler for the platform to describe its power domain tree 21*40d553cfSPaul Beesley in a data structure. 22*40d553cfSPaul Beesley 23*40d553cfSPaul Beesley#. The generic PSCI code generates MPIDRs in order to populate the power domain 24*40d553cfSPaul Beesley tree. It also uses an MPIDR to find a node in the tree. The assumption that 25*40d553cfSPaul Beesley a platform will use exactly the same MPIDRs as generated by the generic PSCI 26*40d553cfSPaul Beesley code is not scalable. The use of an MPIDR also restricts the number of 27*40d553cfSPaul Beesley levels in the power domain tree to four. 28*40d553cfSPaul Beesley 29*40d553cfSPaul Beesley Therefore, there is a need to decouple allocation of MPIDRs from the 30*40d553cfSPaul Beesley mechanism used to populate the power domain topology tree. 31*40d553cfSPaul Beesley 32*40d553cfSPaul Beesley#. The current arrangement of the power domain tree requires a binary search 33*40d553cfSPaul Beesley over the sibling nodes at a particular level to find a specified power 34*40d553cfSPaul Beesley domain node. During a power management operation, the tree is traversed from 35*40d553cfSPaul Beesley a 'start' to an 'end' power level. The binary search is required to find the 36*40d553cfSPaul Beesley node at each level. The natural way to perform this traversal is to 37*40d553cfSPaul Beesley start from a leaf node and follow the parent node pointer to reach the end 38*40d553cfSPaul Beesley level. 39*40d553cfSPaul Beesley 40*40d553cfSPaul Beesley Therefore, there is a need to define data structures that implement the tree in 41*40d553cfSPaul Beesley a way which facilitates such a traversal. 42*40d553cfSPaul Beesley 43*40d553cfSPaul Beesley#. The attributes of a core power domain differ from the attributes of power 44*40d553cfSPaul Beesley domains at higher levels. For example, only a core power domain can be identified 45*40d553cfSPaul Beesley using an MPIDR. There is no requirement to perform state coordination while 46*40d553cfSPaul Beesley performing a power management operation on the core power domain. 47*40d553cfSPaul Beesley 48*40d553cfSPaul Beesley Therefore, there is a need to implement the tree in a way which facilitates this 49*40d553cfSPaul Beesley distinction between a leaf and non-leaf node and any associated 50*40d553cfSPaul Beesley optimizations. 51*40d553cfSPaul Beesley 52*40d553cfSPaul Beesley-------------- 53*40d553cfSPaul Beesley 54*40d553cfSPaul BeesleyDesign 55*40d553cfSPaul Beesley------ 56*40d553cfSPaul Beesley 57*40d553cfSPaul BeesleyDescribing a power domain tree 58*40d553cfSPaul Beesley~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 59*40d553cfSPaul Beesley 60*40d553cfSPaul BeesleyTo fulfill requirement 1., the existing platform APIs 61*40d553cfSPaul Beesley``plat_get_aff_count()`` and ``plat_get_aff_state()`` have been 62*40d553cfSPaul Beesleyremoved. A platform must define an array of unsigned chars such that: 63*40d553cfSPaul Beesley 64*40d553cfSPaul Beesley#. The first entry in the array specifies the number of power domains at the 65*40d553cfSPaul Beesley highest power level implemented in the platform. This caters for platforms 66*40d553cfSPaul Beesley where the power domain tree does not have a single root node, for example, 67*40d553cfSPaul Beesley the FVP has two cluster power domains at the highest level (1). 68*40d553cfSPaul Beesley 69*40d553cfSPaul Beesley#. Each subsequent entry corresponds to a power domain and contains the number 70*40d553cfSPaul Beesley of power domains that are its direct children. 71*40d553cfSPaul Beesley 72*40d553cfSPaul Beesley#. The size of the array minus the first entry will be equal to the number of 73*40d553cfSPaul Beesley non-leaf power domains. 74*40d553cfSPaul Beesley 75*40d553cfSPaul Beesley#. The value in each entry in the array is used to find the number of entries 76*40d553cfSPaul Beesley to consider at the next level. The sum of the values (number of children) of 77*40d553cfSPaul Beesley all the entries at a level specifies the number of entries in the array for 78*40d553cfSPaul Beesley the next level. 79*40d553cfSPaul Beesley 80*40d553cfSPaul BeesleyThe following example power domain topology tree will be used to describe the 81*40d553cfSPaul Beesleyabove text further. The leaf and non-leaf nodes in this tree have been numbered 82*40d553cfSPaul Beesleyseparately. 83*40d553cfSPaul Beesley 84*40d553cfSPaul Beesley:: 85*40d553cfSPaul Beesley 86*40d553cfSPaul Beesley +-+ 87*40d553cfSPaul Beesley |0| 88*40d553cfSPaul Beesley +-+ 89*40d553cfSPaul Beesley / \ 90*40d553cfSPaul Beesley / \ 91*40d553cfSPaul Beesley / \ 92*40d553cfSPaul Beesley / \ 93*40d553cfSPaul Beesley / \ 94*40d553cfSPaul Beesley / \ 95*40d553cfSPaul Beesley / \ 96*40d553cfSPaul Beesley / \ 97*40d553cfSPaul Beesley / \ 98*40d553cfSPaul Beesley / \ 99*40d553cfSPaul Beesley +-+ +-+ 100*40d553cfSPaul Beesley |1| |2| 101*40d553cfSPaul Beesley +-+ +-+ 102*40d553cfSPaul Beesley / \ / \ 103*40d553cfSPaul Beesley / \ / \ 104*40d553cfSPaul Beesley / \ / \ 105*40d553cfSPaul Beesley / \ / \ 106*40d553cfSPaul Beesley +-+ +-+ +-+ +-+ 107*40d553cfSPaul Beesley |3| |4| |5| |6| 108*40d553cfSPaul Beesley +-+ +-+ +-+ +-+ 109*40d553cfSPaul Beesley +---+-----+ +----+----| +----+----+ +----+-----+-----+ 110*40d553cfSPaul Beesley | | | | | | | | | | | | | 111*40d553cfSPaul Beesley | | | | | | | | | | | | | 112*40d553cfSPaul Beesley v v v v v v v v v v v v v 113*40d553cfSPaul Beesley +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +--+ +--+ +--+ 114*40d553cfSPaul Beesley |0| |1| |2| |3| |4| |5| |6| |7| |8| |9| |10| |11| |12| 115*40d553cfSPaul Beesley +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +--+ +--+ +--+ 116*40d553cfSPaul Beesley 117*40d553cfSPaul BeesleyThis tree is defined by the platform as the array described above as follows: 118*40d553cfSPaul Beesley 119*40d553cfSPaul Beesley:: 120*40d553cfSPaul Beesley 121*40d553cfSPaul Beesley #define PLAT_NUM_POWER_DOMAINS 20 122*40d553cfSPaul Beesley #define PLATFORM_CORE_COUNT 13 123*40d553cfSPaul Beesley #define PSCI_NUM_NON_CPU_PWR_DOMAINS \ 124*40d553cfSPaul Beesley (PLAT_NUM_POWER_DOMAINS - PLATFORM_CORE_COUNT) 125*40d553cfSPaul Beesley 126*40d553cfSPaul Beesley unsigned char plat_power_domain_tree_desc[] = { 1, 2, 2, 2, 3, 3, 3, 4}; 127*40d553cfSPaul Beesley 128*40d553cfSPaul BeesleyRemoving assumptions about MPIDRs used in a platform 129*40d553cfSPaul Beesley~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 130*40d553cfSPaul Beesley 131*40d553cfSPaul BeesleyTo fulfill requirement 2., it is assumed that the platform assigns a 132*40d553cfSPaul Beesleyunique number (core index) between ``0`` and ``PLAT_CORE_COUNT - 1`` to each core 133*40d553cfSPaul Beesleypower domain. MPIDRs could be allocated in any manner and will not be used to 134*40d553cfSPaul Beesleypopulate the tree. 135*40d553cfSPaul Beesley 136*40d553cfSPaul Beesley``plat_core_pos_by_mpidr(mpidr)`` will return the core index for the core 137*40d553cfSPaul Beesleycorresponding to the MPIDR. It will return an error (-1) if an MPIDR is passed 138*40d553cfSPaul Beesleywhich is not allocated or corresponds to an absent core. The semantics of this 139*40d553cfSPaul Beesleyplatform API have changed since it is required to validate the passed MPIDR. It 140*40d553cfSPaul Beesleyhas been made a mandatory API as a result. 141*40d553cfSPaul Beesley 142*40d553cfSPaul BeesleyAnother mandatory API, ``plat_my_core_pos()`` has been added to return the core 143*40d553cfSPaul Beesleyindex for the calling core. This API provides a more lightweight mechanism to get 144*40d553cfSPaul Beesleythe index since there is no need to validate the MPIDR of the calling core. 145*40d553cfSPaul Beesley 146*40d553cfSPaul BeesleyThe platform should assign the core indices (as illustrated in the diagram above) 147*40d553cfSPaul Beesleysuch that, if the core nodes are numbered from left to right, then the index 148*40d553cfSPaul Beesleyfor a core domain will be the same as the index returned by 149*40d553cfSPaul Beesley``plat_core_pos_by_mpidr()`` or ``plat_my_core_pos()`` for that core. This 150*40d553cfSPaul Beesleyrelationship allows the core nodes to be allocated in a separate array 151*40d553cfSPaul Beesley(requirement 4.) during ``psci_setup()`` in such an order that the index of the 152*40d553cfSPaul Beesleycore in the array is the same as the return value from these APIs. 153*40d553cfSPaul Beesley 154*40d553cfSPaul BeesleyDealing with holes in MPIDR allocation 155*40d553cfSPaul Beesley^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 156*40d553cfSPaul Beesley 157*40d553cfSPaul BeesleyFor platforms where the number of allocated MPIDRs is equal to the number of 158*40d553cfSPaul Beesleycore power domains, for example, Juno and FVPs, the logic to convert an MPIDR to 159*40d553cfSPaul Beesleya core index should remain unchanged. Both Juno and FVP use a simple collision 160*40d553cfSPaul Beesleyproof hash function to do this. 161*40d553cfSPaul Beesley 162*40d553cfSPaul BeesleyIt is possible that on some platforms, the allocation of MPIDRs is not 163*40d553cfSPaul Beesleycontiguous or certain cores have been disabled. This essentially means that the 164*40d553cfSPaul BeesleyMPIDRs have been sparsely allocated, that is, the size of the range of MPIDRs 165*40d553cfSPaul Beesleyused by the platform is not equal to the number of core power domains. 166*40d553cfSPaul Beesley 167*40d553cfSPaul BeesleyThe platform could adopt one of the following approaches to deal with this 168*40d553cfSPaul Beesleyscenario: 169*40d553cfSPaul Beesley 170*40d553cfSPaul Beesley#. Implement more complex logic to convert a valid MPIDR to a core index while 171*40d553cfSPaul Beesley maintaining the relationship described earlier. This means that the power 172*40d553cfSPaul Beesley domain tree descriptor will not describe any core power domains which are 173*40d553cfSPaul Beesley disabled or absent. Entries will not be allocated in the tree for these 174*40d553cfSPaul Beesley domains. 175*40d553cfSPaul Beesley 176*40d553cfSPaul Beesley#. Treat unallocated MPIDRs and disabled cores as absent but still describe them 177*40d553cfSPaul Beesley in the power domain descriptor, that is, the number of core nodes described 178*40d553cfSPaul Beesley is equal to the size of the range of MPIDRs allocated. This approach will 179*40d553cfSPaul Beesley lead to memory wastage since entries will be allocated in the tree but will 180*40d553cfSPaul Beesley allow use of a simpler logic to convert an MPIDR to a core index. 181*40d553cfSPaul Beesley 182*40d553cfSPaul BeesleyTraversing through and distinguishing between core and non-core power domains 183*40d553cfSPaul Beesley~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 184*40d553cfSPaul Beesley 185*40d553cfSPaul BeesleyTo fulfill requirement 3 and 4, separate data structures have been defined 186*40d553cfSPaul Beesleyto represent leaf and non-leaf power domain nodes in the tree. 187*40d553cfSPaul Beesley 188*40d553cfSPaul Beesley.. code:: c 189*40d553cfSPaul Beesley 190*40d553cfSPaul Beesley /******************************************************************************* 191*40d553cfSPaul Beesley * The following two data structures implement the power domain tree. The tree 192*40d553cfSPaul Beesley * is used to track the state of all the nodes i.e. power domain instances 193*40d553cfSPaul Beesley * described by the platform. The tree consists of nodes that describe CPU power 194*40d553cfSPaul Beesley * domains i.e. leaf nodes and all other power domains which are parents of a 195*40d553cfSPaul Beesley * CPU power domain i.e. non-leaf nodes. 196*40d553cfSPaul Beesley ******************************************************************************/ 197*40d553cfSPaul Beesley typedef struct non_cpu_pwr_domain_node { 198*40d553cfSPaul Beesley /* 199*40d553cfSPaul Beesley * Index of the first CPU power domain node level 0 which has this node 200*40d553cfSPaul Beesley * as its parent. 201*40d553cfSPaul Beesley */ 202*40d553cfSPaul Beesley unsigned int cpu_start_idx; 203*40d553cfSPaul Beesley 204*40d553cfSPaul Beesley /* 205*40d553cfSPaul Beesley * Number of CPU power domains which are siblings of the domain indexed 206*40d553cfSPaul Beesley * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx 207*40d553cfSPaul Beesley * -> cpu_start_idx + ncpus' have this node as their parent. 208*40d553cfSPaul Beesley */ 209*40d553cfSPaul Beesley unsigned int ncpus; 210*40d553cfSPaul Beesley 211*40d553cfSPaul Beesley /* Index of the parent power domain node */ 212*40d553cfSPaul Beesley unsigned int parent_node; 213*40d553cfSPaul Beesley 214*40d553cfSPaul Beesley ----- 215*40d553cfSPaul Beesley } non_cpu_pd_node_t; 216*40d553cfSPaul Beesley 217*40d553cfSPaul Beesley typedef struct cpu_pwr_domain_node { 218*40d553cfSPaul Beesley u_register_t mpidr; 219*40d553cfSPaul Beesley 220*40d553cfSPaul Beesley /* Index of the parent power domain node */ 221*40d553cfSPaul Beesley unsigned int parent_node; 222*40d553cfSPaul Beesley 223*40d553cfSPaul Beesley ----- 224*40d553cfSPaul Beesley } cpu_pd_node_t; 225*40d553cfSPaul Beesley 226*40d553cfSPaul BeesleyThe power domain tree is implemented as a combination of the following data 227*40d553cfSPaul Beesleystructures. 228*40d553cfSPaul Beesley 229*40d553cfSPaul Beesley:: 230*40d553cfSPaul Beesley 231*40d553cfSPaul Beesley non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS]; 232*40d553cfSPaul Beesley cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT]; 233*40d553cfSPaul Beesley 234*40d553cfSPaul BeesleyPopulating the power domain tree 235*40d553cfSPaul Beesley~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 236*40d553cfSPaul Beesley 237*40d553cfSPaul BeesleyThe ``populate_power_domain_tree()`` function in ``psci_setup.c`` implements the 238*40d553cfSPaul Beesleyalgorithm to parse the power domain descriptor exported by the platform to 239*40d553cfSPaul Beesleypopulate the two arrays. It is essentially a breadth-first-search. The nodes for 240*40d553cfSPaul Beesleyeach level starting from the root are laid out one after another in the 241*40d553cfSPaul Beesley``psci_non_cpu_pd_nodes`` and ``psci_cpu_pd_nodes`` arrays as follows: 242*40d553cfSPaul Beesley 243*40d553cfSPaul Beesley:: 244*40d553cfSPaul Beesley 245*40d553cfSPaul Beesley psci_non_cpu_pd_nodes -> [[Level 3 nodes][Level 2 nodes][Level 1 nodes]] 246*40d553cfSPaul Beesley psci_cpu_pd_nodes -> [Level 0 nodes] 247*40d553cfSPaul Beesley 248*40d553cfSPaul BeesleyFor the example power domain tree illustrated above, the ``psci_cpu_pd_nodes`` 249*40d553cfSPaul Beesleywill be populated as follows. The value in each entry is the index of the parent 250*40d553cfSPaul Beesleynode. Other fields have been ignored for simplicity. 251*40d553cfSPaul Beesley 252*40d553cfSPaul Beesley:: 253*40d553cfSPaul Beesley 254*40d553cfSPaul Beesley +-------------+ ^ 255*40d553cfSPaul Beesley CPU0 | 3 | | 256*40d553cfSPaul Beesley +-------------+ | 257*40d553cfSPaul Beesley CPU1 | 3 | | 258*40d553cfSPaul Beesley +-------------+ | 259*40d553cfSPaul Beesley CPU2 | 3 | | 260*40d553cfSPaul Beesley +-------------+ | 261*40d553cfSPaul Beesley CPU3 | 4 | | 262*40d553cfSPaul Beesley +-------------+ | 263*40d553cfSPaul Beesley CPU4 | 4 | | 264*40d553cfSPaul Beesley +-------------+ | 265*40d553cfSPaul Beesley CPU5 | 4 | | PLATFORM_CORE_COUNT 266*40d553cfSPaul Beesley +-------------+ | 267*40d553cfSPaul Beesley CPU6 | 5 | | 268*40d553cfSPaul Beesley +-------------+ | 269*40d553cfSPaul Beesley CPU7 | 5 | | 270*40d553cfSPaul Beesley +-------------+ | 271*40d553cfSPaul Beesley CPU8 | 5 | | 272*40d553cfSPaul Beesley +-------------+ | 273*40d553cfSPaul Beesley CPU9 | 6 | | 274*40d553cfSPaul Beesley +-------------+ | 275*40d553cfSPaul Beesley CPU10 | 6 | | 276*40d553cfSPaul Beesley +-------------+ | 277*40d553cfSPaul Beesley CPU11 | 6 | | 278*40d553cfSPaul Beesley +-------------+ | 279*40d553cfSPaul Beesley CPU12 | 6 | v 280*40d553cfSPaul Beesley +-------------+ 281*40d553cfSPaul Beesley 282*40d553cfSPaul BeesleyThe ``psci_non_cpu_pd_nodes`` array will be populated as follows. The value in 283*40d553cfSPaul Beesleyeach entry is the index of the parent node. 284*40d553cfSPaul Beesley 285*40d553cfSPaul Beesley:: 286*40d553cfSPaul Beesley 287*40d553cfSPaul Beesley +-------------+ ^ 288*40d553cfSPaul Beesley PD0 | -1 | | 289*40d553cfSPaul Beesley +-------------+ | 290*40d553cfSPaul Beesley PD1 | 0 | | 291*40d553cfSPaul Beesley +-------------+ | 292*40d553cfSPaul Beesley PD2 | 0 | | 293*40d553cfSPaul Beesley +-------------+ | 294*40d553cfSPaul Beesley PD3 | 1 | | PLAT_NUM_POWER_DOMAINS - 295*40d553cfSPaul Beesley +-------------+ | PLATFORM_CORE_COUNT 296*40d553cfSPaul Beesley PD4 | 1 | | 297*40d553cfSPaul Beesley +-------------+ | 298*40d553cfSPaul Beesley PD5 | 2 | | 299*40d553cfSPaul Beesley +-------------+ | 300*40d553cfSPaul Beesley PD6 | 2 | | 301*40d553cfSPaul Beesley +-------------+ v 302*40d553cfSPaul Beesley 303*40d553cfSPaul BeesleyEach core can find its node in the ``psci_cpu_pd_nodes`` array using the 304*40d553cfSPaul Beesley``plat_my_core_pos()`` function. When a core is turned on, the normal world 305*40d553cfSPaul Beesleyprovides an MPIDR. The ``plat_core_pos_by_mpidr()`` function is used to validate 306*40d553cfSPaul Beesleythe MPIDR before using it to find the corresponding core node. The non-core power 307*40d553cfSPaul Beesleydomain nodes do not need to be identified. 308*40d553cfSPaul Beesley 309*40d553cfSPaul Beesley-------------- 310*40d553cfSPaul Beesley 311*40d553cfSPaul Beesley*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.* 312