• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1PSCI Library Integration guide for ARMv8-A AArch32 systems
2==========================================================
3
4
5.. section-numbering::
6    :suffix: .
7
8.. contents::
9
10--------------
11
12Requirements
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
55Design
56------
57
58Describing a power domain tree
59~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
60
61To fulfill requirement 1., the existing platform APIs
62``plat_get_aff_count()`` and ``plat_get_aff_state()`` have been
63removed. 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
81The following example power domain topology tree will be used to describe the
82above text further. The leaf and non-leaf nodes in this tree have been numbered
83separately.
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
118This 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
129Removing assumptions about MPIDRs used in a platform
130~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
131
132To fulfill requirement 2., it is assumed that the platform assigns a
133unique number (core index) between ``0`` and ``PLAT_CORE_COUNT - 1`` to each core
134power domain. MPIDRs could be allocated in any manner and will not be used to
135populate the tree.
136
137``plat_core_pos_by_mpidr(mpidr)`` will return the core index for the core
138corresponding to the MPIDR. It will return an error (-1) if an MPIDR is passed
139which is not allocated or corresponds to an absent core. The semantics of this
140platform API have changed since it is required to validate the passed MPIDR. It
141has been made a mandatory API as a result.
142
143Another mandatory API, ``plat_my_core_pos()`` has been added to return the core
144index for the calling core. This API provides a more lightweight mechanism to get
145the index since there is no need to validate the MPIDR of the calling core.
146
147The platform should assign the core indices (as illustrated in the diagram above)
148such that, if the core nodes are numbered from left to right, then the index
149for 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
151relationship 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
153core in the array is the same as the return value from these APIs.
154
155Dealing with holes in MPIDR allocation
156^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
157
158For platforms where the number of allocated MPIDRs is equal to the number of
159core power domains, for example, Juno and FVPs, the logic to convert an MPIDR to
160a core index should remain unchanged. Both Juno and FVP use a simple collision
161proof hash function to do this.
162
163It is possible that on some platforms, the allocation of MPIDRs is not
164contiguous or certain cores have been disabled. This essentially means that the
165MPIDRs have been sparsely allocated, that is, the size of the range of MPIDRs
166used by the platform is not equal to the number of core power domains.
167
168The platform could adopt one of the following approaches to deal with this
169scenario:
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
183Traversing through and distinguishing between core and non-core power domains
184~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
185
186To fulfill requirement 3 and 4, separate data structures have been defined
187to 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
227The power domain tree is implemented as a combination of the following data
228structures.
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
235Populating the power domain tree
236~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
237
238The ``populate_power_domain_tree()`` function in ``psci_setup.c`` implements the
239algorithm to parse the power domain descriptor exported by the platform to
240populate the two arrays. It is essentially a breadth-first-search. The nodes for
241each 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
249For the example power domain tree illustrated above, the ``psci_cpu_pd_nodes``
250will be populated as follows. The value in each entry is the index of the parent
251node. 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
283The ``psci_non_cpu_pd_nodes`` array will be populated as follows. The value in
284each 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
304Each 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
306provides an MPIDR. The ``plat_core_pos_by_mpidr()`` function is used to validate
307the MPIDR before using it to find the corresponding core node. The non-core power
308domain nodes do not need to be identified.
309
310--------------
311
312*Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.*
313