1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Description:
8 * SCMI Performance Plugins Handler
9 *
10 * This module is an extension of the SCMI-Performance module to support
11 * the addition of optional performance-related modules (plugins). Such
12 * modules can affect the final performance of one or more domains.
13 * It can also be used when the domains exposed by SCMI are different from
14 * the real frequency domains available in hardware as this layer can
15 * perform the domain aggregation.
16 */
17
18 #include "perf_plugins_handler.h"
19 #include "scmi_perf.h"
20
21 #include <mod_dvfs.h>
22
23 #include <fwk_assert.h>
24 #include <fwk_id.h>
25 #include <fwk_log.h>
26 #include <fwk_mm.h>
27 #include <fwk_module.h>
28 #include <fwk_module_idx.h>
29 #include <fwk_status.h>
30
31 #ifdef BUILD_HAS_SCMI_PERF_PLUGIN_HANDLER
32 struct perf_plugins_dev_ctx {
33 /*
34 * Each logical domain within the same dependency - note that physical
35 * domain index is equal to this count.
36 */
37 unsigned int log_dom_count;
38
39 /*
40 * Cause of the logical/physical domains handling, the size of each of the
41 * tables will be (sub_element + 1) which is equivalent to
42 * (number of logical domains + one physical domain).
43 * This is done to optimise the internal handling of the data for both types
44 * of domains.
45 *
46 * The last entry of each table is reserved for the physical domain.
47 */
48 struct perf_plugins_perf_update perf_table;
49
50 /* For this domain, store max/min */
51 uint32_t max;
52 uint32_t lmax;
53 uint32_t lmin;
54 };
55
56 struct perf_plugins_ctx {
57 struct perf_plugins_api **plugins_api_table;
58
59 const struct mod_scmi_perf_config *config;
60
61 struct perf_plugins_dev_ctx *dev_ctx;
62
63 /*
64 * Table of dependency domain.
65 *
66 * It is an artefact to contain both the information of physical and
67 * logical within the same identifier in the following way:
68 * FWK_ID_SUB_ELEMENT(FWK_MODULE_IDX_DVFS, physical_domain, logical_domain)
69 *
70 * This helps the internal logic for handling the domain aggregation back
71 * and forth with scmi-perf.
72 * It assumes that DVFS ignores the identifier to be a sub-element.
73 */
74 fwk_id_t *dep_id_table;
75
76 struct perf_plugins_perf_update full_perf_table;
77
78 size_t dvfs_doms_count;
79 };
80
81 static struct perf_plugins_ctx perf_plugins_ctx;
82
perf_ph_get_ctx(fwk_id_t domain_id)83 static inline struct perf_plugins_dev_ctx *perf_ph_get_ctx(fwk_id_t domain_id)
84 {
85 return &perf_plugins_ctx.dev_ctx[fwk_id_get_element_idx(domain_id)];
86 }
87
get_phy_domain_id(fwk_id_t domain_id)88 static inline fwk_id_t get_phy_domain_id(fwk_id_t domain_id)
89 {
90 return FWK_ID_ELEMENT(
91 FWK_MODULE_IDX_DVFS, fwk_id_get_element_idx(domain_id));
92 }
93
perf_plugins_get_dependency_id(unsigned int dom_idx)94 fwk_id_t perf_plugins_get_dependency_id(unsigned int dom_idx)
95 {
96 return perf_plugins_ctx.dep_id_table[dom_idx];
97 }
98
are_limits_valid(uint32_t min,uint32_t max)99 static inline bool are_limits_valid(uint32_t min, uint32_t max)
100 {
101 return (max > min);
102 }
103
plugin_set_limits(struct plugin_limits_req * data)104 static int plugin_set_limits(struct plugin_limits_req *data)
105 {
106 struct perf_plugins_dev_ctx *dev_ctx;
107 fwk_id_t domain_id;
108 int status;
109
110 if (data == NULL) {
111 return FWK_E_PARAM;
112 }
113
114 struct mod_scmi_perf_level_limits req_limits = {
115 .minimum = data->min_limit,
116 .maximum = data->max_limit,
117 };
118
119 domain_id = get_phy_domain_id(data->domain_id);
120 dev_ctx = perf_ph_get_ctx(domain_id);
121
122 /* Compare with the aggregated value stored for this physical domain */
123 if (req_limits.maximum > dev_ctx->lmax) {
124 req_limits.maximum = dev_ctx->lmax;
125 }
126
127 if (req_limits.minimum < dev_ctx->lmin) {
128 req_limits.minimum = dev_ctx->lmin;
129 }
130
131 if (!are_limits_valid(req_limits.minimum, req_limits.maximum)) {
132 return FWK_E_PARAM;
133 }
134
135 status = perf_set_limits(domain_id, 0, &req_limits);
136 if (status != FWK_SUCCESS) {
137 return FWK_E_DEVICE;
138 }
139
140 return FWK_SUCCESS;
141 }
142
143 static struct perf_plugins_handler_api handler_api = {
144 .plugin_set_limits = plugin_set_limits,
145 };
146
147 /*
148 * Write back the adjusted values for use by the next plugins.
149 * Note that for logical oomains, the aggregated values are written.
150 */
write_back_adj_values(struct perf_plugins_dev_ctx * dev_ctx,size_t phy_dom_idx)151 static void write_back_adj_values(
152 struct perf_plugins_dev_ctx *dev_ctx,
153 size_t phy_dom_idx)
154 {
155 for (unsigned int i = 0; i < (dev_ctx->log_dom_count + 1); i++) {
156 dev_ctx->perf_table.adj_min_limit[i] = dev_ctx->lmin;
157 dev_ctx->perf_table.adj_max_limit[i] = dev_ctx->lmax;
158 }
159
160 perf_plugins_ctx.full_perf_table.adj_min_limit[phy_dom_idx] = dev_ctx->lmin;
161 perf_plugins_ctx.full_perf_table.adj_max_limit[phy_dom_idx] = dev_ctx->lmax;
162 }
163
plugins_policy_sync_level_limits(struct perf_plugins_dev_ctx * dev_ctx,enum plugin_domain_type dom_type)164 static void plugins_policy_sync_level_limits(
165 struct perf_plugins_dev_ctx *dev_ctx,
166 enum plugin_domain_type dom_type)
167 {
168 uint32_t *adj_max_limit_table, *adj_min_limit_table;
169 uint32_t *adj_min_lim_full_table, *adj_max_lim_full_table;
170 uint32_t needle_lim_max, needle_lim_min;
171 unsigned int phy_dom, phy_dom_idx;
172 uint32_t *level_table, *min_limit_table, *max_limit_table;
173
174 adj_min_lim_full_table = perf_plugins_ctx.full_perf_table.adj_min_limit;
175 adj_max_lim_full_table = perf_plugins_ctx.full_perf_table.adj_max_limit;
176
177 adj_max_limit_table = dev_ctx->perf_table.adj_max_limit;
178 adj_min_limit_table = dev_ctx->perf_table.adj_min_limit;
179
180 if (dom_type != PERF_PLUGIN_DOM_TYPE_FULL) {
181 phy_dom = dev_ctx->log_dom_count;
182 level_table = dev_ctx->perf_table.level;
183 min_limit_table = dev_ctx->perf_table.min_limit;
184 max_limit_table = dev_ctx->perf_table.max_limit;
185
186 /*
187 * Conservative approach for adjusted values:
188 * - pick the max for the min limit
189 * - pick the min for the max limit
190 */
191 needle_lim_min = min_limit_table[phy_dom];
192 needle_lim_max = max_limit_table[phy_dom];
193
194 /* Find min/max on adjusted values, physical included */
195 for (unsigned int i = 0; i < (phy_dom + 1); i++) {
196 if (adj_min_limit_table[i] >= needle_lim_min) {
197 needle_lim_min = adj_min_limit_table[i];
198 }
199
200 if (adj_max_limit_table[i] <= needle_lim_max) {
201 needle_lim_max = adj_max_limit_table[i];
202 }
203 }
204
205 /*
206 * Now we apply the same policy against the temporary results for the
207 * plugins updates so far.
208 */
209 if (needle_lim_min > dev_ctx->lmin) {
210 dev_ctx->lmin = needle_lim_min;
211 }
212 if (needle_lim_max < dev_ctx->lmax) {
213 dev_ctx->lmax = needle_lim_max;
214 }
215
216 dev_ctx->max = level_table[phy_dom];
217
218 phy_dom_idx = fwk_id_get_element_idx(dev_ctx->perf_table.domain_id);
219 write_back_adj_values(dev_ctx, (size_t)phy_dom_idx);
220
221 } else {
222 /*
223 * This needs to iterate over all the domains, since we are at the last
224 * domain and this plugin may have changed the limits for all the
225 * domains.
226 */
227 for (size_t i = 0; i < perf_plugins_ctx.dvfs_doms_count; i++) {
228 dev_ctx = perf_ph_get_ctx(FWK_ID_ELEMENT(FWK_MODULE_IDX_DVFS, i));
229
230 /* Update with adjusted min-max */
231 if (adj_min_lim_full_table[i] > dev_ctx->lmin) {
232 dev_ctx->lmin = adj_min_lim_full_table[i];
233 }
234 if (adj_max_lim_full_table[i] < dev_ctx->lmax) {
235 dev_ctx->lmax = adj_max_lim_full_table[i];
236 }
237
238 write_back_adj_values(dev_ctx, i);
239 }
240 }
241 }
242
plugins_policy_update(struct fc_perf_update * fc_update)243 static void plugins_policy_update(struct fc_perf_update *fc_update)
244 {
245 struct perf_plugins_dev_ctx *dev_ctx;
246
247 dev_ctx = perf_ph_get_ctx(fc_update->domain_id);
248
249 fc_update->level = dev_ctx->max;
250 fc_update->adj_min_limit = dev_ctx->lmin;
251 fc_update->adj_max_limit = are_limits_valid(dev_ctx->lmin, dev_ctx->lmax) ?
252 dev_ctx->lmax :
253 dev_ctx->lmin;
254 }
255
plugins_policy_update_no_plugins(struct fc_perf_update * fc_update)256 static void plugins_policy_update_no_plugins(struct fc_perf_update *fc_update)
257 {
258 struct perf_plugins_dev_ctx *dev_ctx;
259 unsigned int phy_dom;
260
261 dev_ctx = perf_ph_get_ctx(fc_update->domain_id);
262
263 if (dev_ctx->log_dom_count == 1) {
264 /* No plugins, no logical domains */
265 fc_update->adj_max_limit = fc_update->max_limit;
266 fc_update->adj_min_limit = fc_update->min_limit;
267 } else {
268 /* No plugins, with logical domains */
269 phy_dom = dev_ctx->log_dom_count;
270
271 fc_update->level = dev_ctx->perf_table.level[phy_dom];
272 fc_update->adj_max_limit = dev_ctx->perf_table.adj_max_limit[phy_dom];
273 fc_update->adj_min_limit = dev_ctx->perf_table.adj_min_limit[phy_dom];
274 }
275 }
276
get_perf_table(struct perf_plugins_perf_update * dom,struct perf_plugins_dev_ctx * ctx,unsigned int dom_ix)277 static inline void get_perf_table(
278 struct perf_plugins_perf_update *dom,
279 struct perf_plugins_dev_ctx *ctx,
280 unsigned int dom_ix)
281 {
282 dom->level = &ctx->perf_table.level[dom_ix];
283 dom->max_limit = &ctx->perf_table.max_limit[dom_ix];
284 dom->adj_max_limit = &ctx->perf_table.adj_max_limit[dom_ix];
285 dom->min_limit = &ctx->perf_table.min_limit[dom_ix];
286 dom->adj_min_limit = &ctx->perf_table.adj_min_limit[dom_ix];
287 }
288
assign_data_for_plugins(fwk_id_t id,struct perf_plugins_perf_update * snapshot,enum plugin_domain_type dom_type)289 static void assign_data_for_plugins(
290 fwk_id_t id,
291 struct perf_plugins_perf_update *snapshot,
292 enum plugin_domain_type dom_type)
293 {
294 struct perf_plugins_dev_ctx *dev_ctx;
295 unsigned int dom_idx;
296
297 dev_ctx = perf_ph_get_ctx(id);
298
299 /* Determine the first entry on the table */
300 if (dom_type == PERF_PLUGIN_DOM_TYPE_FULL) {
301 snapshot->level = &perf_plugins_ctx.full_perf_table.level[0];
302
303 snapshot->max_limit = &perf_plugins_ctx.full_perf_table.max_limit[0];
304 snapshot->min_limit = &perf_plugins_ctx.full_perf_table.min_limit[0];
305
306 snapshot->adj_max_limit =
307 &perf_plugins_ctx.full_perf_table.adj_max_limit[0];
308 snapshot->adj_min_limit =
309 &perf_plugins_ctx.full_perf_table.adj_min_limit[0];
310
311 return;
312 } else if (dom_type == PERF_PLUGIN_DOM_TYPE_LOGICAL) {
313 /* Provide the beginning of the table */
314 dom_idx = 0;
315 } else {
316 /* Provide the last column of the table */
317 dom_idx = dev_ctx->log_dom_count;
318 }
319
320 /* Alter the module identifier only */
321 snapshot->domain_id = FWK_ID_SUB_ELEMENT(
322 FWK_MODULE_IDX_SCMI_PERF,
323 fwk_id_get_element_idx(id),
324 fwk_id_get_sub_element_idx(id));
325
326 get_perf_table(snapshot, dev_ctx, dom_idx);
327 }
328
domain_aggregate(struct perf_plugins_perf_update * this_dom,struct perf_plugins_perf_update * phy_dom)329 static inline void domain_aggregate(
330 struct perf_plugins_perf_update *this_dom,
331 struct perf_plugins_perf_update *phy_dom)
332 {
333 /*
334 * Choose the best values of performance for the physical domain which would
335 * satisfy all the logical domains.
336 *
337 * - pick the max for the level
338 * - pick the max for the min limit
339 * - pick the min for the max limit
340 */
341 if (this_dom->level[0] > phy_dom->level[0]) {
342 phy_dom->level[0] = this_dom->level[0];
343 }
344
345 if (this_dom->max_limit[0] < phy_dom->max_limit[0]) {
346 phy_dom->max_limit[0] = this_dom->max_limit[0];
347 }
348
349 if (this_dom->min_limit[0] > phy_dom->min_limit[0]) {
350 phy_dom->min_limit[0] = this_dom->min_limit[0];
351 }
352 }
353
store_and_aggregate(struct fc_perf_update * fc_update)354 static void store_and_aggregate(struct fc_perf_update *fc_update)
355 {
356 unsigned int this_dom_idx, phy_dom_idx;
357 struct perf_plugins_dev_ctx *dev_ctx;
358 struct perf_plugins_perf_update this_dom;
359 struct perf_plugins_perf_update phy_dom;
360 unsigned int phy_ix;
361
362 dev_ctx = perf_ph_get_ctx(fc_update->domain_id);
363
364 this_dom_idx = fwk_id_get_sub_element_idx(fc_update->domain_id);
365 phy_dom_idx = dev_ctx->log_dom_count;
366
367 get_perf_table(&this_dom, dev_ctx, this_dom_idx);
368 get_perf_table(&phy_dom, dev_ctx, phy_dom_idx);
369
370 this_dom.level[0] = fc_update->level;
371 this_dom.max_limit[0] = fc_update->max_limit;
372 this_dom.min_limit[0] = fc_update->min_limit;
373 this_dom.adj_max_limit[0] = fc_update->max_limit;
374 this_dom.adj_min_limit[0] = fc_update->min_limit;
375
376 if (this_dom_idx == 0) {
377 /* Init max/min for physical domain at the 1st iteration */
378 phy_dom.level[0] = 0;
379 phy_dom.max_limit[0] = UINT32_MAX;
380 phy_dom.min_limit[0] = 0;
381
382 /* as well as ctx */
383 dev_ctx->lmin = 0;
384 dev_ctx->lmax = UINT32_MAX;
385 }
386
387 domain_aggregate(&this_dom, &phy_dom);
388
389 phy_dom.adj_max_limit[0] = phy_dom.max_limit[0];
390 phy_dom.adj_min_limit[0] = phy_dom.min_limit[0];
391
392 if (this_dom_idx == (phy_dom_idx - 1)) {
393 /* Copy values, all-performance table */
394 phy_ix = fwk_id_get_element_idx(fc_update->domain_id);
395
396 perf_plugins_ctx.full_perf_table.level[phy_ix] = phy_dom.level[0];
397
398 perf_plugins_ctx.full_perf_table.max_limit[phy_ix] =
399 phy_dom.max_limit[0];
400 perf_plugins_ctx.full_perf_table.min_limit[phy_ix] =
401 phy_dom.min_limit[0];
402
403 perf_plugins_ctx.full_perf_table.adj_max_limit[phy_ix] =
404 phy_dom.adj_max_limit[0];
405 perf_plugins_ctx.full_perf_table.adj_min_limit[phy_ix] =
406 phy_dom.adj_min_limit[0];
407 }
408 }
409
perf_plugins_handler_update(unsigned int perf_dom_idx,struct fc_perf_update * fc_update)410 void perf_plugins_handler_update(
411 unsigned int perf_dom_idx,
412 struct fc_perf_update *fc_update)
413 {
414 struct perf_plugins_api *api;
415 struct perf_plugins_perf_update perf_snapshot;
416 unsigned int this_dom_idx, last_logical_dom_idx;
417 struct perf_plugins_dev_ctx *dev_ctx;
418 enum plugin_domain_type dom_type;
419 const struct mod_scmi_perf_config *config;
420 int status;
421
422 store_and_aggregate(fc_update);
423
424 dev_ctx = perf_ph_get_ctx(fc_update->domain_id);
425
426 this_dom_idx = fwk_id_get_sub_element_idx(fc_update->domain_id);
427 last_logical_dom_idx = dev_ctx->log_dom_count - 1;
428
429 config = perf_plugins_ctx.config;
430
431 /*
432 * EITHER last logical domain OR it's only physical domain,
433 * call the plugin - if any - with the data snapshot for this domain.
434 */
435 if ((this_dom_idx == last_logical_dom_idx) &&
436 (config->plugins_count != 0)) {
437 for (size_t i = 0; i < config->plugins_count; i++) {
438 dom_type = config->plugins[i].dom_type;
439
440 if ((perf_dom_idx != (config->perf_doms_count - 1)) &&
441 (dom_type == PERF_PLUGIN_DOM_TYPE_FULL)) {
442 /*
443 * For plugins that need the full snapshot, wait until the
444 * last performance domain.
445 */
446 continue;
447 }
448
449 assign_data_for_plugins(
450 fc_update->domain_id, &perf_snapshot, dom_type);
451
452 api = perf_plugins_ctx.plugins_api_table[i];
453 status = api->update(&perf_snapshot);
454 if (status != FWK_SUCCESS) {
455 FWK_LOG_DEBUG(
456 "[P-Handler] Update: Plugin%u returned error %i",
457 (unsigned int)i,
458 status);
459 }
460
461 plugins_policy_sync_level_limits(dev_ctx, dom_type);
462 }
463 }
464 }
465
perf_plugins_handler_get(unsigned int perf_dom_idx,struct fc_perf_update * fc_update)466 void perf_plugins_handler_get(
467 unsigned int perf_dom_idx,
468 struct fc_perf_update *fc_update)
469 {
470 unsigned int this_dom_idx, last_logical_dom_idx;
471 const struct mod_scmi_perf_config *config;
472 struct perf_plugins_dev_ctx *dev_ctx;
473
474 dev_ctx = perf_ph_get_ctx(fc_update->domain_id);
475
476 this_dom_idx = fwk_id_get_sub_element_idx(fc_update->domain_id);
477 last_logical_dom_idx = dev_ctx->log_dom_count - 1;
478
479 config = perf_plugins_ctx.config;
480
481 if (this_dom_idx != last_logical_dom_idx) {
482 /*
483 * Any other logical domain, no need to forward the request to DVFS,
484 * thus use previous values.
485 */
486 fc_update->level = dev_ctx->max;
487 fc_update->adj_max_limit = dev_ctx->lmax;
488 fc_update->adj_min_limit = dev_ctx->lmin;
489 } else {
490 if (config->plugins_count == 0) {
491 /* domains coordination only */
492 plugins_policy_update_no_plugins(fc_update);
493 } else {
494 plugins_policy_update(fc_update);
495 }
496 }
497 }
498
perf_plugins_handler_report(struct perf_plugins_perf_report * data)499 void perf_plugins_handler_report(struct perf_plugins_perf_report *data)
500 {
501 struct perf_plugins_api *api;
502 int status;
503
504 if (perf_plugins_ctx.config->plugins_count == 0) {
505 return;
506 }
507
508 for (size_t i = 0; i < perf_plugins_ctx.config->plugins_count; i++) {
509 api = perf_plugins_ctx.plugins_api_table[i];
510
511 if (api->report != NULL) {
512 status = api->report(data);
513 if (status != FWK_SUCCESS) {
514 FWK_LOG_DEBUG(
515 "[P-Handler] Report: Plugin%u returned error %i",
516 (unsigned int)i,
517 status);
518 }
519 }
520 }
521 }
522
perf_plugins_alloc_tables(struct perf_plugins_perf_update * table,size_t count)523 static void perf_plugins_alloc_tables(
524 struct perf_plugins_perf_update *table,
525 size_t count)
526 {
527 table->level = fwk_mm_calloc(count, sizeof(uint32_t));
528 table->max_limit = fwk_mm_calloc(count, sizeof(uint32_t));
529 table->adj_max_limit = fwk_mm_calloc(count, sizeof(uint32_t));
530 table->min_limit = fwk_mm_calloc(count, sizeof(uint32_t));
531 table->adj_min_limit = fwk_mm_calloc(count, sizeof(uint32_t));
532 }
533
perf_plugins_handler_init(const struct mod_scmi_perf_config * config)534 int perf_plugins_handler_init(const struct mod_scmi_perf_config *config)
535 {
536 const struct mod_scmi_perf_domain_config *domain;
537 int dvfs_doms_count;
538 struct perf_plugins_dev_ctx *dev_ctx;
539 unsigned int pgroup, ldom = 0;
540 size_t all_doms_count;
541 unsigned int phy_group;
542 bool has_phy_group;
543
544 dvfs_doms_count =
545 fwk_module_get_element_count(FWK_ID_MODULE(FWK_MODULE_IDX_DVFS));
546 if (dvfs_doms_count <= 0) {
547 return FWK_E_SUPPORT;
548 }
549
550 perf_plugins_ctx.dvfs_doms_count = (size_t)dvfs_doms_count;
551
552 perf_plugins_ctx.dev_ctx = fwk_mm_calloc(
553 (size_t)dvfs_doms_count, sizeof(struct perf_plugins_dev_ctx));
554
555 /*
556 * Iterate all over the SCMI performance domain table to build the number of
557 * logical domains that belong to the same physical domain.
558 */
559 for (size_t i = 0; i < config->perf_doms_count; i++) {
560 domain = &(*config->domains)[i];
561
562 has_phy_group = fwk_optional_id_is_defined(domain->phy_group_id);
563 if (has_phy_group) {
564 phy_group = fwk_id_get_element_idx(domain->phy_group_id);
565 } else {
566 phy_group = i;
567 }
568
569 dev_ctx = &perf_plugins_ctx.dev_ctx[phy_group];
570 dev_ctx->log_dom_count++;
571 }
572
573 /*
574 * Allocate a table for each of the physical domain to contain the
575 * requested levels/limits by each of its logical domains.
576 * The size will be: number of logical domains + 1 (for physical domain).
577 *
578 * At the same time, initialise min and max.
579 */
580 for (size_t i = 0; i < perf_plugins_ctx.dvfs_doms_count; i++) {
581 dev_ctx = &perf_plugins_ctx.dev_ctx[i];
582
583 all_doms_count = (size_t)(dev_ctx->log_dom_count + 1);
584
585 perf_plugins_alloc_tables(&dev_ctx->perf_table, all_doms_count);
586
587 dev_ctx->lmin = 0;
588 dev_ctx->lmax = UINT32_MAX;
589 dev_ctx->perf_table.domain_id = FWK_ID_ELEMENT(FWK_MODULE_IDX_DVFS, i);
590 }
591
592 /*
593 * Allocate a table to store the physical/aggregated values for each of the
594 * physical domain for plugins that require the full picture of performance.
595 */
596 perf_plugins_alloc_tables(
597 &perf_plugins_ctx.full_perf_table, perf_plugins_ctx.dvfs_doms_count);
598
599 /*
600 * The data provided for a full snapshot will always have a module
601 * identifier.
602 */
603 perf_plugins_ctx.full_perf_table.domain_id =
604 FWK_ID_MODULE(FWK_MODULE_IDX_SCMI_PERF);
605
606 /* Allocate a table of dependency domains identifiers */
607 perf_plugins_ctx.dep_id_table =
608 fwk_mm_calloc(config->perf_doms_count, sizeof(fwk_id_t));
609
610 domain = &(*config->domains)[0];
611
612 /*
613 * Build the dependency domains.
614 *
615 * If we find the optional identifier for physical domain description,
616 * we assume that SCMI performance domains are grouped and ordered together
617 * for the same physical domain.
618 */
619 for (size_t j = 0; j < config->perf_doms_count; j++) {
620 has_phy_group = fwk_optional_id_is_defined(domain->phy_group_id);
621 if (has_phy_group) {
622 /* Custom mapping */
623 pgroup = fwk_id_get_element_idx(domain->phy_group_id);
624 domain = &(*config->domains)[j];
625
626 if (fwk_id_get_element_idx(domain->phy_group_id) != pgroup) {
627 /* Restart count of logical domains */
628 ldom = 0;
629 }
630
631 perf_plugins_ctx.dep_id_table[j] = FWK_ID_SUB_ELEMENT(
632 FWK_MODULE_IDX_DVFS,
633 fwk_id_get_element_idx(domain->phy_group_id),
634 ldom);
635
636 ldom++;
637 } else {
638 /* Direct implicit mapping to dvfs */
639 perf_plugins_ctx.dep_id_table[j] =
640 FWK_ID_SUB_ELEMENT(FWK_MODULE_IDX_DVFS, j, 0);
641 }
642 }
643
644 perf_plugins_ctx.config = config;
645
646 return FWK_SUCCESS;
647 }
648
perf_plugins_handler_bind(void)649 int perf_plugins_handler_bind(void)
650 {
651 fwk_id_t plugin_id;
652 const struct mod_scmi_perf_config *config = perf_plugins_ctx.config;
653 int status;
654
655 if (config->plugins_count == 0) {
656 return FWK_SUCCESS;
657 }
658
659 perf_plugins_ctx.plugins_api_table =
660 fwk_mm_calloc(config->plugins_count, sizeof(struct perf_plugins_api *));
661
662 /* Bind to all the performance plugins */
663 for (size_t i = 0; i < config->plugins_count; i++) {
664 plugin_id = config->plugins[i].id;
665
666 status = fwk_module_bind(
667 plugin_id,
668 FWK_ID_API(
669 fwk_id_get_module_idx(plugin_id), MOD_SCMI_PERF_PLUGIN_API),
670 &perf_plugins_ctx.plugins_api_table[i]);
671 if (status != FWK_SUCCESS) {
672 return FWK_E_PARAM;
673 }
674 }
675
676 return FWK_SUCCESS;
677 }
678
perf_plugins_handler_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)679 int perf_plugins_handler_process_bind_request(
680 fwk_id_t source_id,
681 fwk_id_t target_id,
682 fwk_id_t api_id,
683 const void **api)
684 {
685 *api = &handler_api;
686
687 return FWK_SUCCESS;
688 }
689 #endif /* BUILD_HAS_SCMI_PERF_PLUGIN_HANDLER */
690