1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #ifndef MOD_STATISTICS_H
9 #define MOD_STATISTICS_H
10 
11 #include <fwk_attributes.h>
12 #include <fwk_id.h>
13 #include <fwk_macros.h>
14 #include <fwk_module_idx.h>
15 
16 #include <stdint.h>
17 
18 /*!
19  * \ingroup GroupModules
20  * \defgroup GroupStatistics Statistics for Performance and Power domains
21  *      of operating level changes
22  * \{
23  */
24 
25 /*!
26  * \defgroup GroupStatisticsTypes Types
27  * \{
28  */
29 
30 /*!
31  * \brief Statistics memory region information.
32  */
33 struct FWK_PACKED mod_stats_config_info {
34     /*! AP physical address where statistics are located */
35     uint64_t ap_stats_addr;
36 
37     /*! SCP physical address where statistics are located */
38     uintptr_t scp_stats_addr;
39 
40     /*! Size in bytes of the shared memory region for statistics */
41     uint32_t stats_region_size;
42 
43     /*! Alarm used for period updates */
44     fwk_id_t alarm_id;
45 };
46 
47 /*!
48  * \brief Domain statistics mapping structure.
49  */
50 struct mod_stats_map {
51     /*! Array which contains values with levels that each domain has.
52      * We do not rely on domain_section->level_count in SCP address or
53      * offset calculation, since it can be modified by OSPM */
54     int *se_level_count;
55 
56     /*! Array which contains values with current level for each domain.
57      * We do not rely on domain_section->curr_level in SCP address or
58      * offset calculation, since it can be modified by OSPM */
59     uint32_t *se_curr_level;
60 
61     /*! An array of pointers to the domain statistics table. Every domain
62      * has its own table when statistics collection is set for it. */
63     struct mod_stats_domain_stats_data *se_stats[];
64 };
65 
66 /*!
67  * \brief Domain statistics management structure.
68  */
69 struct mod_stats_context {
70     /*! Number of all stats entities of this type in the system (e.g. power
71      * domains, performance domains, etc) */
72     int se_total_num;
73 
74     /*! Number of stats entities of this type for which the statistics are
75      * collected */
76     int se_used_num;
77 
78     /*! Index used for mapping incremented after adding a new domain. */
79     int last_stats_id;
80 
81     /*! Array to map system entity id to index used in statistics memory
82      * allocator. It's needed because statistics are not enabled for all
83      * entities */
84     int *se_index_map;
85 
86     /*! Pointer to performance or power domain statistics mapping. Every
87      * domain has its own table when statistics collection is set for it. */
88     struct mod_stats_map *se_stats_map;
89 };
90 
91 /*!
92  * \brief Statistics status and mode enum.
93  */
94 enum mod_stats_mode {
95     STATS_NOT_INITIALIZED, /*!< Module not initialized */
96     STATS_SETUP, /*!< Module in setup phase, not ready to use */
97     STATS_INITIALIZED, /*!< Module ready to use */
98     STATS_NOT_SUPPORTED, /*!< Statistics are not supported */
99     STATS_INTERNAL_ERROR, /*!< Module reached an error */
100     STATS_STOPPED, /*!< Statistics tracking stopped */
101 };
102 
103 /*!
104  * \brief Statistics context.
105  */
106 struct mod_stats_info {
107     /*! type_signature - private copy which should be the same as in shared
108      * memory description header describing type of statistics region. */
109     uint32_t type_signature;
110 
111     /*! Pointer to the shared memory header location */
112     struct mod_stats_desc_header *desc_header;
113 
114     /*! Size of the shared memory header */
115     unsigned int desc_header_size;
116 
117     /*! Size of unused shared memory region provided by the platform, which
118      * might be evaluated and adjusted to actual need */
119     unsigned int used_mem_size;
120 
121     /*! Offset inside the shared memory region to the header */
122     uintptr_t desc_header_offset;
123 
124     /*! Pointer to the structure maintaining internal data, allocations
125      * and sections of the entity (power domain, performance domain)
126      * statistics */
127     struct mod_stats_context *context;
128 
129     /*! Mode of operation for the statistics module */
130     enum mod_stats_mode mode;
131 };
132 
133 /*!
134  * \brief Performance or power statistics memory region as defined in SCMIv2
135  *      specification
136  */
137 struct mod_stats_desc_header {
138     /*! Signature - 0x50455246 (‘PERF’) or 0x504F5752 ('POWR'). */
139     uint32_t signature;
140 
141     /*! The revision value aligned with the SCMI specification. */
142     uint16_t revision;
143 
144     /*! The attributes aligned with the SCMI specification. */
145     uint16_t attributes;
146 
147     /*! Total number of all performance or power domains in the system, which
148      * also corresponds to the size of 'domain_offset' array size. */
149     uint16_t domain_count;
150 
151     /*! Empty space just for memory alignment as per SCMI specification. */
152     uint16_t reserved[3];
153 
154     /*! For each domain this array provides 4B offset from start addr of the
155      * statistics memory region to the particular performance or power domain
156      * statistics data section. If the value is 0 then statistics are not
157      * collected for this domain. */
158     uint32_t domain_offset[];
159 };
160 
161 /*!
162  * \brief Performance or power level statistics data
163  *
164  * \note In case of power domain. Here the reference to level means power state
165  */
166 struct FWK_PACKED mod_stats_level_stats {
167     /*! The performance or power level ID. */
168     uint32_t level_id;
169 
170     /*! Reserved field as per SCMI specification. */
171     uint32_t reserved;
172 
173     /*! Maintains the number of how many time this level has been used. */
174     uint64_t usage_count;
175 
176     /*! Cumulative time of how long this level has been used. Value is in
177      * microseconds. */
178     uint64_t total_residency_us;
179 };
180 
181 /*!
182  * \brief Performance or power domain statistics data
183  */
184 struct FWK_PACKED mod_stats_domain_stats_data {
185     /*! Holds value of total number of performance or power levels available
186      * in the domain. */
187     uint16_t level_count;
188 
189     /*! Holds current Operating Performance Point or power level ID. */
190     uint16_t curr_level_id;
191 
192     /*! An offset to the extended statistics area if they are present. */
193     uint32_t extended_stats_offset;
194 
195     /*! Holds time stamp when the last performance or power level has been
196      * changed. Value is in microseconds.*/
197     uint64_t ts_last_change_us;
198 
199     /*! Beginning of the statistics region with information for each
200      * performance or power level. */
201     struct mod_stats_level_stats level[];
202 };
203 
204 /*!
205  * \}
206  */
207 
208 
209 /*!
210  * \defgroup GroupStatsApis APIs
211  * \{
212  */
213 
214 /*!
215  * \brief Stats API.
216  */
217 struct mod_stats_api {
218     /*!
219      * \brief Initialize statistics for a given module.
220      *
221      * \param module_id Element identifier of the module.
222      * \param domain_count Total number of domains in this module.
223      * \param used_domains Total number of domains that have statistics.
224      */
225     int (*init_stats)(
226         fwk_id_t module_id,
227         int domain_count,
228         int used_domains);
229 
230     /*!
231      * \brief Start the statistics for the given module.
232      *
233      * \param module_id Element identifier of the module.
234      */
235     int (*start_stats)(fwk_id_t module_id);
236 
237     /*!
238      * \brief Add new domain to the statistics of the parent module.
239      *
240      * \param module_id Element identifier of the module.
241      * \param domain_id Element identifier of the domain.
242      * \param level_count Total number of levels in this domain.
243      */
244     int (*add_domain)(
245         fwk_id_t module_id,
246         fwk_id_t domain_id,
247         int level_count);
248 
249     /*!
250      * \brief Update the domain statistics with new level ID set.
251      *
252      * \param module_id Element identifier of the module.
253      * \param domain_id Element identifier of the domain.
254      * \param level_id Current operating level ID.
255      */
256     int (*update_domain)(
257         fwk_id_t module_id,
258         fwk_id_t domain_id,
259         uint32_t level_id);
260 
261     /*!
262      * \brief Get low and high addresses of statistics in AP address space
263      *          with length of the memory region
264      *
265      * \param module_id Element identifier of the module.
266      * \param [out] addr_low lower 32 bits of the statistics address
267      * \param [out] addr_high higher 32 bits of the statistics address
268      * \param [out] length of the statistics memory region
269      */
270     int (*get_statistics_desc)(
271         fwk_id_t module_id,
272         uint32_t *addr_low,
273         uint32_t *addr_high,
274         uint32_t *len);
275 };
276 /*!
277  * \}
278  */
279 /*!
280  * \defgroup GroupStatisticsIds Identifiers
281  * \{
282  */
283 
284 /*!
285  * \brief API indices.
286  */
287 enum mod_stats_api_idx {
288     MOD_STATS_API_IDX_STATS, /*!< API index for mod_stats_api_id_stats() */
289     MOD_STATS_API_IDX_COUNT /*!< Number of defined APIs */
290 };
291 
292 /*! Module API identifier */
293 static const fwk_id_t mod_stats_api_id_stats =
294     FWK_ID_API_INIT(FWK_MODULE_IDX_STATISTICS, MOD_STATS_API_IDX_STATS);
295 
296 /*!
297  * \}
298  */
299 
300 /*!
301  * \}
302  */
303 
304 #endif
305