1*8aa05055SPaul BeesleyPSCI Power Domain Tree Structure 2*8aa05055SPaul Beesley================================ 340d553cfSPaul Beesley 440d553cfSPaul Beesley.. contents:: 540d553cfSPaul Beesley 640d553cfSPaul Beesley-------------- 740d553cfSPaul Beesley 840d553cfSPaul BeesleyRequirements 940d553cfSPaul Beesley------------ 1040d553cfSPaul Beesley 1140d553cfSPaul Beesley#. A platform must export the ``plat_get_aff_count()`` and 1240d553cfSPaul Beesley ``plat_get_aff_state()`` APIs to enable the generic PSCI code to 1340d553cfSPaul Beesley populate a tree that describes the hierarchy of power domains in the 1440d553cfSPaul Beesley system. This approach is inflexible because a change to the topology 1540d553cfSPaul Beesley requires a change in the code. 1640d553cfSPaul Beesley 1740d553cfSPaul Beesley It would be much simpler for the platform to describe its power domain tree 1840d553cfSPaul Beesley in a data structure. 1940d553cfSPaul Beesley 2040d553cfSPaul Beesley#. The generic PSCI code generates MPIDRs in order to populate the power domain 2140d553cfSPaul Beesley tree. It also uses an MPIDR to find a node in the tree. The assumption that 2240d553cfSPaul Beesley a platform will use exactly the same MPIDRs as generated by the generic PSCI 2340d553cfSPaul Beesley code is not scalable. The use of an MPIDR also restricts the number of 2440d553cfSPaul Beesley levels in the power domain tree to four. 2540d553cfSPaul Beesley 2640d553cfSPaul Beesley Therefore, there is a need to decouple allocation of MPIDRs from the 2740d553cfSPaul Beesley mechanism used to populate the power domain topology tree. 2840d553cfSPaul Beesley 2940d553cfSPaul Beesley#. The current arrangement of the power domain tree requires a binary search 3040d553cfSPaul Beesley over the sibling nodes at a particular level to find a specified power 3140d553cfSPaul Beesley domain node. During a power management operation, the tree is traversed from 3240d553cfSPaul Beesley a 'start' to an 'end' power level. The binary search is required to find the 3340d553cfSPaul Beesley node at each level. The natural way to perform this traversal is to 3440d553cfSPaul Beesley start from a leaf node and follow the parent node pointer to reach the end 3540d553cfSPaul Beesley level. 3640d553cfSPaul Beesley 3740d553cfSPaul Beesley Therefore, there is a need to define data structures that implement the tree in 3840d553cfSPaul Beesley a way which facilitates such a traversal. 3940d553cfSPaul Beesley 4040d553cfSPaul Beesley#. The attributes of a core power domain differ from the attributes of power 4140d553cfSPaul Beesley domains at higher levels. For example, only a core power domain can be identified 4240d553cfSPaul Beesley using an MPIDR. There is no requirement to perform state coordination while 4340d553cfSPaul Beesley performing a power management operation on the core power domain. 4440d553cfSPaul Beesley 4540d553cfSPaul Beesley Therefore, there is a need to implement the tree in a way which facilitates this 4640d553cfSPaul Beesley distinction between a leaf and non-leaf node and any associated 4740d553cfSPaul Beesley optimizations. 4840d553cfSPaul Beesley 4940d553cfSPaul Beesley-------------- 5040d553cfSPaul Beesley 5140d553cfSPaul BeesleyDesign 5240d553cfSPaul Beesley------ 5340d553cfSPaul Beesley 5440d553cfSPaul BeesleyDescribing a power domain tree 5540d553cfSPaul Beesley~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5640d553cfSPaul Beesley 5740d553cfSPaul BeesleyTo fulfill requirement 1., the existing platform APIs 5840d553cfSPaul Beesley``plat_get_aff_count()`` and ``plat_get_aff_state()`` have been 5940d553cfSPaul Beesleyremoved. A platform must define an array of unsigned chars such that: 6040d553cfSPaul Beesley 6140d553cfSPaul Beesley#. The first entry in the array specifies the number of power domains at the 6240d553cfSPaul Beesley highest power level implemented in the platform. This caters for platforms 6340d553cfSPaul Beesley where the power domain tree does not have a single root node, for example, 6440d553cfSPaul Beesley the FVP has two cluster power domains at the highest level (1). 6540d553cfSPaul Beesley 6640d553cfSPaul Beesley#. Each subsequent entry corresponds to a power domain and contains the number 6740d553cfSPaul Beesley of power domains that are its direct children. 6840d553cfSPaul Beesley 6940d553cfSPaul Beesley#. The size of the array minus the first entry will be equal to the number of 7040d553cfSPaul Beesley non-leaf power domains. 7140d553cfSPaul Beesley 7240d553cfSPaul Beesley#. The value in each entry in the array is used to find the number of entries 7340d553cfSPaul Beesley to consider at the next level. The sum of the values (number of children) of 7440d553cfSPaul Beesley all the entries at a level specifies the number of entries in the array for 7540d553cfSPaul Beesley the next level. 7640d553cfSPaul Beesley 7740d553cfSPaul BeesleyThe following example power domain topology tree will be used to describe the 7840d553cfSPaul Beesleyabove text further. The leaf and non-leaf nodes in this tree have been numbered 7940d553cfSPaul Beesleyseparately. 8040d553cfSPaul Beesley 8140d553cfSPaul Beesley:: 8240d553cfSPaul Beesley 8340d553cfSPaul Beesley +-+ 8440d553cfSPaul Beesley |0| 8540d553cfSPaul Beesley +-+ 8640d553cfSPaul Beesley / \ 8740d553cfSPaul Beesley / \ 8840d553cfSPaul Beesley / \ 8940d553cfSPaul Beesley / \ 9040d553cfSPaul Beesley / \ 9140d553cfSPaul Beesley / \ 9240d553cfSPaul Beesley / \ 9340d553cfSPaul Beesley / \ 9440d553cfSPaul Beesley / \ 9540d553cfSPaul Beesley / \ 9640d553cfSPaul Beesley +-+ +-+ 9740d553cfSPaul Beesley |1| |2| 9840d553cfSPaul Beesley +-+ +-+ 9940d553cfSPaul Beesley / \ / \ 10040d553cfSPaul Beesley / \ / \ 10140d553cfSPaul Beesley / \ / \ 10240d553cfSPaul Beesley / \ / \ 10340d553cfSPaul Beesley +-+ +-+ +-+ +-+ 10440d553cfSPaul Beesley |3| |4| |5| |6| 10540d553cfSPaul Beesley +-+ +-+ +-+ +-+ 10640d553cfSPaul Beesley +---+-----+ +----+----| +----+----+ +----+-----+-----+ 10740d553cfSPaul Beesley | | | | | | | | | | | | | 10840d553cfSPaul Beesley | | | | | | | | | | | | | 10940d553cfSPaul Beesley v v v v v v v v v v v v v 11040d553cfSPaul Beesley +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +--+ +--+ +--+ 11140d553cfSPaul Beesley |0| |1| |2| |3| |4| |5| |6| |7| |8| |9| |10| |11| |12| 11240d553cfSPaul Beesley +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +--+ +--+ +--+ 11340d553cfSPaul Beesley 11440d553cfSPaul BeesleyThis tree is defined by the platform as the array described above as follows: 11540d553cfSPaul Beesley 11640d553cfSPaul Beesley:: 11740d553cfSPaul Beesley 11840d553cfSPaul Beesley #define PLAT_NUM_POWER_DOMAINS 20 11940d553cfSPaul Beesley #define PLATFORM_CORE_COUNT 13 12040d553cfSPaul Beesley #define PSCI_NUM_NON_CPU_PWR_DOMAINS \ 12140d553cfSPaul Beesley (PLAT_NUM_POWER_DOMAINS - PLATFORM_CORE_COUNT) 12240d553cfSPaul Beesley 12340d553cfSPaul Beesley unsigned char plat_power_domain_tree_desc[] = { 1, 2, 2, 2, 3, 3, 3, 4}; 12440d553cfSPaul Beesley 12540d553cfSPaul BeesleyRemoving assumptions about MPIDRs used in a platform 12640d553cfSPaul Beesley~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 12740d553cfSPaul Beesley 12840d553cfSPaul BeesleyTo fulfill requirement 2., it is assumed that the platform assigns a 12940d553cfSPaul Beesleyunique number (core index) between ``0`` and ``PLAT_CORE_COUNT - 1`` to each core 13040d553cfSPaul Beesleypower domain. MPIDRs could be allocated in any manner and will not be used to 13140d553cfSPaul Beesleypopulate the tree. 13240d553cfSPaul Beesley 13340d553cfSPaul Beesley``plat_core_pos_by_mpidr(mpidr)`` will return the core index for the core 13440d553cfSPaul Beesleycorresponding to the MPIDR. It will return an error (-1) if an MPIDR is passed 13540d553cfSPaul Beesleywhich is not allocated or corresponds to an absent core. The semantics of this 13640d553cfSPaul Beesleyplatform API have changed since it is required to validate the passed MPIDR. It 13740d553cfSPaul Beesleyhas been made a mandatory API as a result. 13840d553cfSPaul Beesley 13940d553cfSPaul BeesleyAnother mandatory API, ``plat_my_core_pos()`` has been added to return the core 14040d553cfSPaul Beesleyindex for the calling core. This API provides a more lightweight mechanism to get 14140d553cfSPaul Beesleythe index since there is no need to validate the MPIDR of the calling core. 14240d553cfSPaul Beesley 14340d553cfSPaul BeesleyThe platform should assign the core indices (as illustrated in the diagram above) 14440d553cfSPaul Beesleysuch that, if the core nodes are numbered from left to right, then the index 14540d553cfSPaul Beesleyfor a core domain will be the same as the index returned by 14640d553cfSPaul Beesley``plat_core_pos_by_mpidr()`` or ``plat_my_core_pos()`` for that core. This 14740d553cfSPaul Beesleyrelationship allows the core nodes to be allocated in a separate array 14840d553cfSPaul Beesley(requirement 4.) during ``psci_setup()`` in such an order that the index of the 14940d553cfSPaul Beesleycore in the array is the same as the return value from these APIs. 15040d553cfSPaul Beesley 15140d553cfSPaul BeesleyDealing with holes in MPIDR allocation 15240d553cfSPaul Beesley^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 15340d553cfSPaul Beesley 15440d553cfSPaul BeesleyFor platforms where the number of allocated MPIDRs is equal to the number of 15540d553cfSPaul Beesleycore power domains, for example, Juno and FVPs, the logic to convert an MPIDR to 15640d553cfSPaul Beesleya core index should remain unchanged. Both Juno and FVP use a simple collision 15740d553cfSPaul Beesleyproof hash function to do this. 15840d553cfSPaul Beesley 15940d553cfSPaul BeesleyIt is possible that on some platforms, the allocation of MPIDRs is not 16040d553cfSPaul Beesleycontiguous or certain cores have been disabled. This essentially means that the 16140d553cfSPaul BeesleyMPIDRs have been sparsely allocated, that is, the size of the range of MPIDRs 16240d553cfSPaul Beesleyused by the platform is not equal to the number of core power domains. 16340d553cfSPaul Beesley 16440d553cfSPaul BeesleyThe platform could adopt one of the following approaches to deal with this 16540d553cfSPaul Beesleyscenario: 16640d553cfSPaul Beesley 16740d553cfSPaul Beesley#. Implement more complex logic to convert a valid MPIDR to a core index while 16840d553cfSPaul Beesley maintaining the relationship described earlier. This means that the power 16940d553cfSPaul Beesley domain tree descriptor will not describe any core power domains which are 17040d553cfSPaul Beesley disabled or absent. Entries will not be allocated in the tree for these 17140d553cfSPaul Beesley domains. 17240d553cfSPaul Beesley 17340d553cfSPaul Beesley#. Treat unallocated MPIDRs and disabled cores as absent but still describe them 17440d553cfSPaul Beesley in the power domain descriptor, that is, the number of core nodes described 17540d553cfSPaul Beesley is equal to the size of the range of MPIDRs allocated. This approach will 17640d553cfSPaul Beesley lead to memory wastage since entries will be allocated in the tree but will 17740d553cfSPaul Beesley allow use of a simpler logic to convert an MPIDR to a core index. 17840d553cfSPaul Beesley 17940d553cfSPaul BeesleyTraversing through and distinguishing between core and non-core power domains 18040d553cfSPaul Beesley~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18140d553cfSPaul Beesley 18240d553cfSPaul BeesleyTo fulfill requirement 3 and 4, separate data structures have been defined 18340d553cfSPaul Beesleyto represent leaf and non-leaf power domain nodes in the tree. 18440d553cfSPaul Beesley 18540d553cfSPaul Beesley.. code:: c 18640d553cfSPaul Beesley 18740d553cfSPaul Beesley /******************************************************************************* 18840d553cfSPaul Beesley * The following two data structures implement the power domain tree. The tree 18940d553cfSPaul Beesley * is used to track the state of all the nodes i.e. power domain instances 19040d553cfSPaul Beesley * described by the platform. The tree consists of nodes that describe CPU power 19140d553cfSPaul Beesley * domains i.e. leaf nodes and all other power domains which are parents of a 19240d553cfSPaul Beesley * CPU power domain i.e. non-leaf nodes. 19340d553cfSPaul Beesley ******************************************************************************/ 19440d553cfSPaul Beesley typedef struct non_cpu_pwr_domain_node { 19540d553cfSPaul Beesley /* 19640d553cfSPaul Beesley * Index of the first CPU power domain node level 0 which has this node 19740d553cfSPaul Beesley * as its parent. 19840d553cfSPaul Beesley */ 19940d553cfSPaul Beesley unsigned int cpu_start_idx; 20040d553cfSPaul Beesley 20140d553cfSPaul Beesley /* 20240d553cfSPaul Beesley * Number of CPU power domains which are siblings of the domain indexed 20340d553cfSPaul Beesley * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx 20440d553cfSPaul Beesley * -> cpu_start_idx + ncpus' have this node as their parent. 20540d553cfSPaul Beesley */ 20640d553cfSPaul Beesley unsigned int ncpus; 20740d553cfSPaul Beesley 20840d553cfSPaul Beesley /* Index of the parent power domain node */ 20940d553cfSPaul Beesley unsigned int parent_node; 21040d553cfSPaul Beesley 21140d553cfSPaul Beesley ----- 21240d553cfSPaul Beesley } non_cpu_pd_node_t; 21340d553cfSPaul Beesley 21440d553cfSPaul Beesley typedef struct cpu_pwr_domain_node { 21540d553cfSPaul Beesley u_register_t mpidr; 21640d553cfSPaul Beesley 21740d553cfSPaul Beesley /* Index of the parent power domain node */ 21840d553cfSPaul Beesley unsigned int parent_node; 21940d553cfSPaul Beesley 22040d553cfSPaul Beesley ----- 22140d553cfSPaul Beesley } cpu_pd_node_t; 22240d553cfSPaul Beesley 22340d553cfSPaul BeesleyThe power domain tree is implemented as a combination of the following data 22440d553cfSPaul Beesleystructures. 22540d553cfSPaul Beesley 22640d553cfSPaul Beesley:: 22740d553cfSPaul Beesley 22840d553cfSPaul Beesley non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS]; 22940d553cfSPaul Beesley cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT]; 23040d553cfSPaul Beesley 23140d553cfSPaul BeesleyPopulating the power domain tree 23240d553cfSPaul Beesley~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23340d553cfSPaul Beesley 23440d553cfSPaul BeesleyThe ``populate_power_domain_tree()`` function in ``psci_setup.c`` implements the 23540d553cfSPaul Beesleyalgorithm to parse the power domain descriptor exported by the platform to 23640d553cfSPaul Beesleypopulate the two arrays. It is essentially a breadth-first-search. The nodes for 23740d553cfSPaul Beesleyeach level starting from the root are laid out one after another in the 23840d553cfSPaul Beesley``psci_non_cpu_pd_nodes`` and ``psci_cpu_pd_nodes`` arrays as follows: 23940d553cfSPaul Beesley 24040d553cfSPaul Beesley:: 24140d553cfSPaul Beesley 24240d553cfSPaul Beesley psci_non_cpu_pd_nodes -> [[Level 3 nodes][Level 2 nodes][Level 1 nodes]] 24340d553cfSPaul Beesley psci_cpu_pd_nodes -> [Level 0 nodes] 24440d553cfSPaul Beesley 24540d553cfSPaul BeesleyFor the example power domain tree illustrated above, the ``psci_cpu_pd_nodes`` 24640d553cfSPaul Beesleywill be populated as follows. The value in each entry is the index of the parent 24740d553cfSPaul Beesleynode. Other fields have been ignored for simplicity. 24840d553cfSPaul Beesley 24940d553cfSPaul Beesley:: 25040d553cfSPaul Beesley 25140d553cfSPaul Beesley +-------------+ ^ 25240d553cfSPaul Beesley CPU0 | 3 | | 25340d553cfSPaul Beesley +-------------+ | 25440d553cfSPaul Beesley CPU1 | 3 | | 25540d553cfSPaul Beesley +-------------+ | 25640d553cfSPaul Beesley CPU2 | 3 | | 25740d553cfSPaul Beesley +-------------+ | 25840d553cfSPaul Beesley CPU3 | 4 | | 25940d553cfSPaul Beesley +-------------+ | 26040d553cfSPaul Beesley CPU4 | 4 | | 26140d553cfSPaul Beesley +-------------+ | 26240d553cfSPaul Beesley CPU5 | 4 | | PLATFORM_CORE_COUNT 26340d553cfSPaul Beesley +-------------+ | 26440d553cfSPaul Beesley CPU6 | 5 | | 26540d553cfSPaul Beesley +-------------+ | 26640d553cfSPaul Beesley CPU7 | 5 | | 26740d553cfSPaul Beesley +-------------+ | 26840d553cfSPaul Beesley CPU8 | 5 | | 26940d553cfSPaul Beesley +-------------+ | 27040d553cfSPaul Beesley CPU9 | 6 | | 27140d553cfSPaul Beesley +-------------+ | 27240d553cfSPaul Beesley CPU10 | 6 | | 27340d553cfSPaul Beesley +-------------+ | 27440d553cfSPaul Beesley CPU11 | 6 | | 27540d553cfSPaul Beesley +-------------+ | 27640d553cfSPaul Beesley CPU12 | 6 | v 27740d553cfSPaul Beesley +-------------+ 27840d553cfSPaul Beesley 27940d553cfSPaul BeesleyThe ``psci_non_cpu_pd_nodes`` array will be populated as follows. The value in 28040d553cfSPaul Beesleyeach entry is the index of the parent node. 28140d553cfSPaul Beesley 28240d553cfSPaul Beesley:: 28340d553cfSPaul Beesley 28440d553cfSPaul Beesley +-------------+ ^ 28540d553cfSPaul Beesley PD0 | -1 | | 28640d553cfSPaul Beesley +-------------+ | 28740d553cfSPaul Beesley PD1 | 0 | | 28840d553cfSPaul Beesley +-------------+ | 28940d553cfSPaul Beesley PD2 | 0 | | 29040d553cfSPaul Beesley +-------------+ | 29140d553cfSPaul Beesley PD3 | 1 | | PLAT_NUM_POWER_DOMAINS - 29240d553cfSPaul Beesley +-------------+ | PLATFORM_CORE_COUNT 29340d553cfSPaul Beesley PD4 | 1 | | 29440d553cfSPaul Beesley +-------------+ | 29540d553cfSPaul Beesley PD5 | 2 | | 29640d553cfSPaul Beesley +-------------+ | 29740d553cfSPaul Beesley PD6 | 2 | | 29840d553cfSPaul Beesley +-------------+ v 29940d553cfSPaul Beesley 30040d553cfSPaul BeesleyEach core can find its node in the ``psci_cpu_pd_nodes`` array using the 30140d553cfSPaul Beesley``plat_my_core_pos()`` function. When a core is turned on, the normal world 30240d553cfSPaul Beesleyprovides an MPIDR. The ``plat_core_pos_by_mpidr()`` function is used to validate 30340d553cfSPaul Beesleythe MPIDR before using it to find the corresponding core node. The non-core power 30440d553cfSPaul Beesleydomain nodes do not need to be identified. 30540d553cfSPaul Beesley 30640d553cfSPaul Beesley-------------- 30740d553cfSPaul Beesley 30840d553cfSPaul Beesley*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.* 309