1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *      SCMI performance domain management protocol support.
9  */
10 
11 #ifndef MOD_SCMI_PERF_H
12 #define MOD_SCMI_PERF_H
13 
14 #include <fwk_id.h>
15 #include <fwk_macros.h>
16 
17 #include <stddef.h>
18 #include <stdint.h>
19 
20 /*!
21  * \addtogroup GroupModules Modules
22  * \{
23  */
24 
25 /*!
26  * \defgroup GroupSCMI_PERF SCMI Performance Domain Management Protocol
27  * \{
28  */
29 
30 /*!
31  * \brief Agent permissions.
32  */
33 enum mod_scmi_perf_permissions {
34     /*! No permissions */
35     MOD_SCMI_PERF_PERMS_NONE = 0,
36 
37     /*! Permission to set performance level */
38     MOD_SCMI_PERF_PERMS_SET_LEVEL = (1U << 0),
39 
40     /*! Permission to set performance limits */
41     MOD_SCMI_PERF_PERMS_SET_LIMITS = (1U << 1),
42 };
43 
44 /*!
45  * \brief Fast channels address index
46  */
47 enum mod_scmi_perf_fast_channels_addr_index {
48     MOD_SCMI_PERF_FAST_CHANNEL_LEVEL_SET = 0,
49     MOD_SCMI_PERF_FAST_CHANNEL_LIMIT_SET = 1,
50     MOD_SCMI_PERF_FAST_CHANNEL_LEVEL_GET = 2,
51     MOD_SCMI_PERF_FAST_CHANNEL_LIMIT_GET = 3,
52     MOD_SCMI_PERF_FAST_CHANNEL_ADDR_INDEX_COUNT = 4
53 };
54 /*!
55  *\brief Per-Domain Fast Channel Limit in shared memory.
56  */
57 struct mod_scmi_perf_fast_channel_limit {
58     /*! Performance limit max. */
59     uint32_t range_max;
60     /*! Performance limit min. */
61     uint32_t range_min;
62 };
63 
64 /*!
65  *\brief Fast channels memory offset
66  */
67 enum mod_scmi_perf_fast_channel_memory_offset {
68     MOD_SCMI_PERF_FAST_CHANNEL_OFFSET_LEVEL_SET = 0,
69     MOD_SCMI_PERF_FAST_CHANNEL_OFFSET_LIMIT_SET = sizeof(uint32_t),
70     MOD_SCMI_PERF_FAST_CHANNEL_OFFSET_LEVEL_GET =
71         sizeof(uint32_t) + sizeof(struct mod_scmi_perf_fast_channel_limit),
72     MOD_SCMI_PERF_FAST_CHANNEL_OFFSET_LIMIT_GET =
73         sizeof(uint32_t) * 2 + sizeof(struct mod_scmi_perf_fast_channel_limit),
74     MOD_SCMI_PERF_FAST_CHANNEL_OFFSET_TOTAL = sizeof(uint32_t) * 2 +
75         sizeof(struct mod_scmi_perf_fast_channel_limit) * 2
76 };
77 
78 /*!
79  * \brief Performance limits.
80  */
81 struct mod_scmi_perf_level_limits {
82     uint32_t minimum; /*!< Minimum permitted level */
83     uint32_t maximum; /*!< Maximum permitted level */
84 };
85 
86 /*!
87  * \brief Performance domain configuration data.
88  */
89 struct mod_scmi_perf_domain_config {
90     /*!
91      * \brief Domain fast channels.
92      *
93      * \details Platform Domain fast channel address
94      *
95      * \note May be set to NULL, in which case support for fast
96      *       channels is disabled for the platform.
97      */
98     uint64_t *fast_channels_addr_scp;
99 
100     /*!
101      * \brief Agent Domain fast channel address
102      *
103      * \details Address of shared memory for the agent
104      */
105     uint64_t *fast_channels_addr_ap;
106 
107     /*!
108      * \brief Rate limit in microsecs
109      */
110     uint32_t fast_channels_rate_limit;
111 
112     /*! Flag indicating that statistics are collected for this domain */
113     bool stats_collected;
114 
115     /*!
116      * \brief Performance group.
117      *
118      * \details When there's a mapping of n logical domains from SCMI to one
119      *      physical DVFS domain, it is required to indicate the physical domain
120      *      associated with each logical domain. See architecture documentation
121      *      for further details.
122      *
123      * \note When not provided, the logical and physical domains are the same.
124      *      It is also expected that either none of the domains or all of them
125      *      are present.
126      */
127     fwk_optional_id_t phy_group_id;
128 };
129 
130 /*!
131  * \brief Performance Plugins domain type
132  *
133  * \details The plugin's view on performance domains. See architecture
134  *      documentation for further details.
135  */
136 enum plugin_domain_type {
137     /*!
138      * \brief Plugin domain type physical
139      *
140      * \details A plugin which requires to have a physical domain' data should
141      *      choose this option. Note that the plugin will receive `n` updates,
142      *      where n is the number of physical domains.
143      */
144     PERF_PLUGIN_DOM_TYPE_PHYSICAL,
145 
146     /*!
147      * \brief Plugin domain type logical
148      *
149      * \details A plugin which requires to have all the logical domains' data
150      *      that belong to a physical domain should choose this option. Note
151      *      that the plugin will receive `n` updates where `n` is the number of
152      *      physical domains.
153      */
154     PERF_PLUGIN_DOM_TYPE_LOGICAL,
155 
156     /*!
157      * \brief Plugin domain type full
158      *
159      * \details A plugin which requires to have all the physical domains' data
160      *      in one go should choose this option. Note that the plugin will
161      *      receive 1 updates at every iteration. See documentation for further
162      *      details.
163      */
164     PERF_PLUGIN_DOM_TYPE_FULL,
165 
166     /*! The number of domain types available for plugins */
167     PERF_PLUGIN_DOM_TYPE_COUNT,
168 };
169 
170 /*!
171  * \brief SCMI Performance Domain Management Protocol configuration data.
172  */
173 struct mod_scmi_perf_config {
174     /*! Per-domain configuration data */
175     const struct mod_scmi_perf_domain_config (*domains)[];
176 
177     /*!
178      * \brief Performance domain count
179      *
180      * \details This is the number of performance domains exposed via SCMI.
181      */
182     size_t perf_doms_count;
183 
184     /*!
185      * \brief Fast Channels Alarm ID
186      *
187      * \details The Fast Channel alarm triggers the callback which
188      *    polls the fast channels and initiates the set_level and
189      *    set_limits operations.
190      */
191     fwk_id_t fast_channels_alarm_id;
192 
193     /*! Fast Channel polling rate */
194     uint32_t fast_channels_rate_limit;
195 
196     /*! Flag indicating statistics in use */
197     bool stats_enabled;
198 
199     /*!
200      * \brief Whether approximate levels are allowed to be requested.
201      *
202      * \details When set to true, and no exact match with requested level is
203      * found, the next upper level will be used as performance level, as long as
204      * it is within current limits.
205      */
206     bool approximate_level;
207 
208     /*! Table of Performance Plugins */
209     const struct mod_scmi_plugin_config *plugins;
210 
211     /*! Number of Performance Plugins */
212     size_t plugins_count;
213 };
214 
215 /*!
216  * \brief SCMI Performance APIs.
217  *
218  * \details APIs exported by SCMI Performance Protocol.
219  */
220 enum scmi_perf_api_idx {
221     /*! Index for the SCMI protocol API */
222     MOD_SCMI_PERF_PROTOCOL_API = 0,
223 
224     /*! Index of the updates notification API */
225     MOD_SCMI_PERF_DVFS_UPDATE_API = 1,
226 
227     /*! Index of the Performance Plugin Handler API */
228     MOD_SCMI_PERF_PLUGINS_API = 2,
229 
230     /*! Number of APIs */
231     MOD_SCMI_PERF_API_COUNT = 3
232 };
233 
234 /*!
235  * \brief Performance Plugins configuration data.
236  */
237 struct mod_scmi_plugin_config {
238     /*! Performance Plugin identifier */
239     fwk_id_t id;
240 
241     /*! Performance Plugin domain type mode */
242     enum plugin_domain_type dom_type;
243 };
244 
245 /*!
246  * \brief SCMI Perf updates notification API.
247  *
248  * \details API used by DVFS to notify the Perf layer when either the
249  *      limits or level has been changed.
250  */
251 struct mod_scmi_perf_updated_api {
252     /*!
253      * \brief Inform SCMI Perf that the domain limits have been updated.
254      *
255      * \param domain_id Domain identifier.
256      * \param cookie Context-specific value.
257      * \param range_min Min allowed performance level.
258      * \param range_max Max allowed performance level.
259      */
260     void (*notify_limits_updated)(
261         fwk_id_t domain_id,
262         uintptr_t cookie,
263         uint32_t range_min,
264         uint32_t range_max);
265 
266     /*!
267      * \brief Inform SCMI Perf that the domain level has been updated.
268      *
269      * \param domain_id Domain identifier.
270      * \param cookie Context-specific value.
271      * \param level The new performance level of the domain.
272      */
273     void (*notify_level_updated)(
274         fwk_id_t domain_id,
275         uintptr_t cookie,
276         uint32_t level);
277 };
278 
279 /*!
280  * \defgroup GroupScmiPerformancePolicyHandlers Policy Handlers
281  *
282  * \brief SCMI Performance Policy Handlers.
283  *
284  * \details The SCMI policy handlers are weak definitions to allow a platform
285  *      to implement a policy appropriate to that platform. The SCMI
286  *      performance policy functions may be overridden in the
287  *      `product/<platform>/src` directory.
288  *
289  * \note The `level`/`range` values may be changed by the policy handlers.
290  * \note See `product/juno/src/juno_scmi_clock.c` for an example policy
291  *      handler.
292  *
293  * \{
294  */
295 
296 /*!
297  * \brief Policy handler policies.
298  *
299  * \details These values are returned to the message handler by the policy
300  *      handlers to determine whether the message handler should continue
301  *      processing the message, or whether the request has been rejected.
302  */
303 enum mod_scmi_perf_policy_status {
304     /*! Do not execute the message handler */
305     MOD_SCMI_PERF_SKIP_MESSAGE_HANDLER = 0,
306 
307     /*! Execute the message handler */
308     MOD_SCMI_PERF_EXECUTE_MESSAGE_HANDLER = 1,
309 };
310 
311 /*!
312  *
313  * \brief SCMI Performance Set Level command policy.
314  *
315  * \details This function determines whether the SCMI message handler should
316  *      allow or reject a given SCMI Performance Set Level command.
317  *
318  *      The SCMI policy handler is executed before the message handler is
319  *      called. The SCMI protocol message handler will only continue if the
320  *      policy handler both returns ::FWK_SUCCESS and sets the policy status to
321  *      ::MOD_SCMI_PERF_EXECUTE_MESSAGE_HANDLER.
322  *
323  * \param[out] policy_status Whether the command should be accepted or not.
324  * \param[in, out] level Level requested to be set.
325  * \param[in] agent_id Identifier of the agent requesting the service.
326  * \param[in] domain_id Identifier of the performance domain.
327  *
328  * \retval ::FWK_SUCCESS The operation succeeded.
329  *
330  * \return Status code representing the result of the operation.
331  */
332 int scmi_perf_level_set_policy(
333     enum mod_scmi_perf_policy_status *policy_status,
334     uint32_t *level,
335     unsigned int agent_id,
336     fwk_id_t domain_id);
337 
338 /*!
339  * \brief SCMI Performance Set Limits command policy.
340  *
341  * \details This function determines whether the SCMI message handler should
342  *      allow or reject a given SCMI Performance Set Limits command.
343  *
344  *      The SCMI policy handler is executed before the message handler is
345  *      called. The SCMI protocol message handler will only continue if the
346  *      policy handler both returns ::FWK_SUCCESS and sets the policy status to
347  *      ::MOD_SCMI_PERF_EXECUTE_MESSAGE_HANDLER.
348  *
349  * \param[out] policy_status Whether the command should be accepted or not.
350  * \param[in, out] range_min Minimum level range.
351  * \param[in, out] range_max Maximum level range.
352  * \param[in] agent_id Identifier of the agent requesting the service.
353  * \param[in] domain_id Identifier of the performance domain.
354  *
355  * \retval ::FWK_SUCCESS The operation succeeded.
356  *
357  * \return Status code representing the result of the operation.
358  */
359 int scmi_perf_limits_set_policy(
360     enum mod_scmi_perf_policy_status *policy_status,
361     uint32_t *range_min,
362     uint32_t *range_max,
363     unsigned int agent_id,
364     fwk_id_t domain_id);
365 
366 /*!
367  * \}
368  */
369 
370 /*!
371  * \brief Performance Plugins performance data.
372  *
373  * \details This dataset is shared with the plugins. It contains the data
374  *      collected from fast-channels and provides a way for the plugins to
375  *      request an adjusted limit for the performance driver.
376  *      Depending ond the plugin's domain view (physical or logical), levels and
377  *      limits can be scalars or arrays.
378  */
379 struct perf_plugins_perf_update {
380     /*! Performance domain identifier */
381     fwk_id_t domain_id;
382 
383     /*! Performance level(s) - This is an input for the plugin */
384     uint32_t *level;
385 
386     /*! Performance max limit(s) - This is an input for the plugin */
387     uint32_t *max_limit;
388 
389     /*! Performance min limit(s) - This is an input for the plugin */
390     uint32_t *min_limit;
391 
392     /*!
393      * \brief Adjusted performance max limit(s).
394      *
395      * \details This is an input/output for the plugin.
396      *      This table contains the aggregated adjusted values set out by
397      *      previous plugins. Plugins can use this info for their algorithms.
398      *      A performance plugin should overwrite these values if wishes to
399      *      affect the performance limit for targeted domains.
400      */
401     uint32_t *adj_max_limit;
402 
403     /*!
404      * \brief Adjusted performance min limit(s).
405      *
406      * \details This is an input/output for the plugin.
407      *      This table contains the aggregated adjusted values set out by
408      *      previous plugins. Plugins can use this info for their algorithms.
409      *      A performance plugin should overwrite these values if wishes to
410      *      affect the performance limit for targeted domains.
411      */
412     uint32_t *adj_min_limit;
413 };
414 
415 /*!
416  * \brief Performance Report data.
417  *
418  * \details This dataset is shared with the plugins when the performance driver
419  *      reports the final applied performance level/limit change.
420  */
421 struct perf_plugins_perf_report {
422     /*! Physical (or dependency) domain identifier */
423     const fwk_id_t dep_dom_id;
424 
425     /*! Performance level */
426     const uint32_t level;
427 
428     /*! Performance max limit */
429     const uint32_t max_limit;
430 
431     /*! Performance min limit */
432     const uint32_t min_limit;
433 };
434 
435 /*!
436  * \brief Performance Plugin APIs.
437  *
438  * \details APIs exported by the Performance Plugins.
439  */
440 enum scmi_perf_plugin_api_idx {
441     /*! Index for SCMI Performance Plugin API */
442     MOD_SCMI_PERF_PLUGIN_API = 0,
443 
444     /*! Number of SCMI Performance Plugins APIs */
445 
446     /*!
447      * \brief Number of SCMI Performance Plugins APIs
448      *
449      * \details Other APIs implemented by a performance plugin will start from
450      *      this index afterwards.
451      */
452     MOD_SCMI_PERF_PLUGIN_API_COUNT = 1,
453 };
454 
455 /*!
456  * \brief Performance Plugins interface.
457  *
458  * \details The interface that performance plugins should implement to receive
459  *      updates on performance.
460  */
461 struct perf_plugins_api {
462     /*!
463      * \brief Update performance data.
464      *
465      * \details This function is called periodically to inform the plugin with
466      *      the latest performance requests coming from SCMI.
467      *
468      * \details This callback serves the following purposes:
469      *      - periodic tick: the plugins is called at determined time intervals
470      *      that can be specified in the configuration and corresponds to the
471      *      periodicity of the FastChannels sampling.
472      *      - last performance level: the plugin has visibility of the last
473      *      updated performance level that is taken from the FastChannels.
474      *      - last performance limits: the plugin has visibility of the last
475      *      updated performance limits that are taken from the FastChannels.
476      *      - adjusted performance limits: the plugin has the opportunity to
477      *      affect the final performance limits by writing a performance limit
478      *      back to the SCMI Performance.
479      *      All the above are put together along with an identifier of the
480      *      performance domain being controlled.
481      *
482      *      A typical scenario for a plugin would be that upon every callback,
483      *      the plugin runs its own algorithm which can take advantage of the
484      *      periodicity. In this algorithm the plugin can - if required - read
485      *      the current performance level and limits for the given domain and,
486      *      when necessary, can apply (write) new limits in the `adjusted`
487      *      fields. This is expected to be done for each of the relevant
488      *      performance domains that the plugin is concerned, unless its view
489      *      is _FULL. In the latter case, the callback will execute once only in
490      *      the tick period and the plugin will be provided with the entire blob
491      *      of performance level/limits for all the domains.
492      *      This is made available for plugins whose algorithm needs to take
493      *      into account all the performance domains collectively in order to
494      *      make a sane decision of the limits to be applied.
495      *
496      * \param data Performance data
497      * \retval ::FWK_SUCCESS or one of FWK_E_* error codes.
498      *
499      * \return Status code representing the result of the operation.
500      */
501     int (*update)(struct perf_plugins_perf_update *data);
502 
503     /*!
504      * \brief Report performance data.
505      *
506      * \details This function is called once a final performance level limit has
507      *      been applied.
508      *
509      * \param data Performance data
510      * \retval ::FWK_SUCCESS or one of FWK_E_* error codes.
511      *
512      * \note This function is optional. Plugins that are not interested to
513      *      receive a report of the last performance transition can omit this
514      *      function.
515      *
516      * \return Status code representing the result of the operation.
517      */
518     int (*report)(struct perf_plugins_perf_report *data);
519 };
520 
521 /*!
522  * \brief Performance Request Limits data.
523  *
524  * \details Data container for the plugin hanlder, contains the requested
525  *      limits.
526  */
527 struct plugin_limits_req {
528     /*! Performance domain identifier */
529     const fwk_id_t domain_id;
530 
531     /*! Performance max limit requested */
532     const uint32_t max_limit;
533 
534     /*! Performance min limit requested */
535     const uint32_t min_limit;
536 };
537 
538 /*!
539  * \brief Plugin handler API - reserved for plugins only
540  *
541  * \details This interface can be used by any of the performance plugins to
542  *      interact with the plugin handler to asyncronously request a performance
543  *      level/limit.
544  *
545  * \warning This API should be used only in circumstances where waiting for the
546  *      next update call would cause a significant loss of performance.
547  *      Plugins should always try to use the update callback (see above)
548  *      whenever possible.
549  */
550 struct perf_plugins_handler_api {
551     /*!
552      * \brief Set limits
553      *
554      * \param data Limits request data.
555      *
556      * \retval ::FWK_E_PARAM Invalid parameter.
557      * \retval ::FWK_E_DEVICE The request to the performance driver failed.
558      * \retval ::FWK_SUCCESS The operation succeeded. Note that the operation
559      *      may complete asyncronously depending on the performance driver.
560      *
561      * \return Status code representing the result of the operation.
562      */
563     int (*plugin_set_limits)(struct plugin_limits_req *data);
564 };
565 
566 /*!
567  * \}
568  */
569 
570 /*!
571  * \}
572  */
573 
574 #endif /* MOD_SCMI_PERF_H */
575