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