psci-pd-tree.rst 13 KB

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