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