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