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