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