blob: ceb9eb552256c5add2965c0065bdc441105df0f8 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
Charlie Barehamaf8934c2024-07-26 14:51:14 +01002 * Copyright (c) 2018-2025, Arm Limited. All rights reserved.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef __PLAT_TOPOLOGY_H__
8#define __PLAT_TOPOLOGY_H__
9
10#include <arch.h>
11#include <platform_def.h>
12#include <stdint.h>
13
14/*
15 * This is the initial value of the power domain index when used
16 * as argument to the tftf topology helpers. They are also used
17 * to indicate the end of iterative topology navigation when returned
18 * by the tftf topology helpers.
19 */
20#define PWR_DOMAIN_INIT ((unsigned int) -1)
21
22/*
23 * Return the total number of clusters in the system.
24 * Currently there is correspondence between power level and affinity
25 * level and hence cluster power level corresponds to affinity level 1.
26 */
27#define tftf_get_total_clusters_count() tftf_get_total_aff_count(1)
28
29/*
30 * Return the total number of CPUs in the system (across all clusters).
31 * Currently there is correspondence between power level and affinity
32 * level and hence CPU power level correspond to affinity level 0.
33 */
34#define tftf_get_total_cpus_count() tftf_get_total_aff_count(0)
35
36/*
37 * Converts a 'core_pos' into an MPIDR. The 'core_pos' is a unique number
38 * corresponding to a CPU as returned by platform_get_core_pos() API
39 */
40#define tftf_core_pos_to_mpidr(core_pos) \
41 tftf_get_mpidr_from_node(core_pos + tftf_pwr_domain_start_idx[0])
42
43/*
44 * The following array stores the start index of each level in the power
45 * domain topology tree.
46 */
47extern unsigned int tftf_pwr_domain_start_idx[PLATFORM_MAX_AFFLVL + 1];
48
49/*
50 * The following data structure represents a TFTF power domain node.
51 */
52typedef struct tftf_pwr_domain_node {
53 /*
54 * Array index of the first CPU in the topology array for which this
55 * power domain is the parent. If this power domain is a CPU, then
56 * `cpu_start_node` will be its own index in the power domain
57 * topology array.
58 */
59 unsigned int cpu_start_node;
60
61 /*
62 * Number of CPU power domains which belong to this power domain.
63 * i.e. all the CPUs in the range 'cpu_start_node
64 * -> cpu_start_node + ncpus - 1 ' will belong to this power domain.
65 * If this power domain is a CPU then 'ncpus' will be 1.
66 */
67 unsigned int ncpus;
68
69 /* Valid only for CPU power domains */
70 unsigned int mpidr;
71
72 /* Index of the parent power domain node */
73 unsigned int parent_node;
74
75 /*
76 * The level of this power domain node in the power domain topology
77 * tree. It could correspond to the affinity level but the platform
78 * could have power levels which do not match affinity levels.
79 */
80 unsigned int level;
81
82 /*
83 * The 'is_present' field is used to cater for power domains
84 * which are absent.
85 */
86 unsigned char is_present;
87} tftf_pwr_domain_node_t;
88
Wing Licb88add2022-10-29 02:32:06 +010089extern tftf_pwr_domain_node_t tftf_pd_nodes[PLATFORM_NUM_AFFS];
90
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020091/*
92 * Detect and store the platform topology so that test cases can query it later.
93 */
94void tftf_init_topology(void);
95
96/*
97 * Return the number of affinity instances implemented at the affinity level
98 * passed as an argument. This function returns 0 for any other affinity
99 * level higher than that supported by the platform.
100 */
101unsigned int tftf_get_total_aff_count(unsigned int aff_lvl);
102
103/*
104 * Returns the index of the next power domain after `pwr_domain_idx`
105 * in the topology tree at the same `aff_lvl`. The `pwr_domain_idx`
106 * has to be initialized to PWR_DOMAIN_INIT to get the first entry.
107 * It returns PWR_DOMAIN_INIT if none is found.
108 */
109unsigned int tftf_get_next_peer_domain(unsigned int pwr_domain_idx,
110 unsigned int pwr_lvl);
111
112/*
113 * Returns the index of the next CPU after the current CPU `cpu_node`
114 * which belongs to the power domain `pwr_domain_idx`. The `cpu_node`
115 * has to be initialized to PWR_DOMAIN_INIT to get the first entry.
116 * It returns PWR_DOMAIN_INIT if none is found.
117 */
118unsigned int tftf_get_next_cpu_in_pwr_domain(unsigned int pwr_domain_idx,
119 unsigned int cpu_node);
120
121/*
122 * Return the node index of the next CPU after 'cpu_node' in the topology tree.
123 * Skip absent CPUs.
124 * cpu_node: Node index of the current CPU.
125 */
126unsigned int tftf_topology_next_cpu(unsigned int cpu_node);
127
128/*
129 * Iterate over every CPU. Skip absent CPUs.
130 * cpu: unsigned integer corresponding to the index of the cpu in
John Tsichritzis941fab42018-10-30 14:49:31 +0000131 * the topology array.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200132 */
John Tsichritzis941fab42018-10-30 14:49:31 +0000133#define for_each_cpu(cpu) \
134 for (cpu = tftf_topology_next_cpu(PWR_DOMAIN_INIT); \
135 cpu != PWR_DOMAIN_INIT; \
136 cpu = tftf_topology_next_cpu(cpu))
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200137
138/*
139 * Iterate over every power domain idx for a given level.
John Tsichritzis941fab42018-10-30 14:49:31 +0000140 * - idx: unsigned integer corresponding to the power domain index.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200141 * - lvl: level
142 */
John Tsichritzis941fab42018-10-30 14:49:31 +0000143#define for_each_power_domain_idx(idx, lvl) \
144 for (idx = tftf_get_next_peer_domain(PWR_DOMAIN_INIT, (lvl)); \
145 idx != PWR_DOMAIN_INIT; \
146 idx = tftf_get_next_peer_domain(idx, (lvl)))
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200147
148/*
149 * Iterate over every CPU in a power domain idx.
John Tsichritzis941fab42018-10-30 14:49:31 +0000150 * - cpu_idx: CPU index.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200151 * - pwr_domain_idx: unsigned integer corresponding to the power domain index.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200152 */
John Tsichritzis941fab42018-10-30 14:49:31 +0000153#define for_each_cpu_in_power_domain(cpu_idx, pwr_domain_idx) \
154 for (cpu_idx = tftf_get_next_cpu_in_pwr_domain( \
155 (pwr_domain_idx), PWR_DOMAIN_INIT); \
156 cpu_idx != PWR_DOMAIN_INIT; \
157 cpu_idx = tftf_get_next_cpu_in_pwr_domain( \
158 (pwr_domain_idx), cpu_idx))
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200159
160/*
161 * Returns the MPIDR of the CPU power domain node indexed by `cpu_node`
162 * or INVALID_MPID if it is absent.
163 */
164unsigned int tftf_get_mpidr_from_node(unsigned int cpu_node);
165
Soby Mathew8d84b4c2018-07-09 13:07:57 +0100166
167/*
168 * Returns the index corresponding to the parent power domain at `pwrlvl` of the
169 * CPU specified by `mpidr`. Returns POWER_DOMAIN_INIT if any of input arguments
170 * are incorrect.
171 */
172unsigned int tftf_get_parent_node_from_mpidr(unsigned int mpidr,
173 unsigned int pwrlvl);
174
175
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200176/*
177 * Query the platform topology to find another CPU than the one specified
178 * as an argument.
179 * Return the MPID of this other CPU, or INVALID_MPID if none could be found.
180 */
181unsigned int tftf_find_any_cpu_other_than(unsigned int exclude_mpid);
182
183/*
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100184 * Query the platform topology to find another CPU that is in a different
185 * cluster to the one specified as an argument.
186 * Return the MPID of this other CPU, or INVALID_MPID if none could be found.
187 */
188unsigned int tftf_find_any_cpu_in_other_cluster(unsigned int exclude_mpid);
189
190/*
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200191 * Query the platform topology to find a random CPU other than the one specified
192 * as an argument.
193 * The difference between this function and tftf_find_any_cpu_other_than is
194 * the randomness in selecting a CPU.
195 * Return the MPID of this other CPU, or INVALID_MPID if none could be found.
196 */
197unsigned int tftf_find_random_cpu_other_than(unsigned int exclude_mpid);
198
199#endif /* __PLAT_TOPOLOGY_H__ */