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