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_mod_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_mod_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 domains, 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 dev_ctx->max = perf_plugins_ctx.full_perf_table.level[i];
239
240 write_back_adj_values(dev_ctx, i);
241 }
242 }
243 }
244
plugins_policy_update(struct fc_perf_update * fc_update)245 static void plugins_policy_update(struct fc_perf_update *fc_update)
246 {
247 struct perf_plugins_dev_ctx *dev_ctx;
248
249 dev_ctx = perf_ph_get_ctx(fc_update->domain_id);
250
251 fc_update->level = dev_ctx->max;
252 fc_update->adj_min_limit = dev_ctx->lmin;
253 fc_update->adj_max_limit = are_limits_valid(dev_ctx->lmin, dev_ctx->lmax) ?
254 dev_ctx->lmax :
255 dev_ctx->lmin;
256 }
257
plugins_policy_update_no_plugins(struct fc_perf_update * fc_update)258 static void plugins_policy_update_no_plugins(struct fc_perf_update *fc_update)
259 {
260 struct perf_plugins_dev_ctx *dev_ctx;
261 unsigned int phy_dom;
262
263 dev_ctx = perf_ph_get_ctx(fc_update->domain_id);
264
265 if (dev_ctx->log_dom_count == 1) {
266 /* No plugins, no logical domains */
267 fc_update->adj_max_limit = fc_update->max_limit;
268 fc_update->adj_min_limit = fc_update->min_limit;
269 } else {
270 /* No plugins, with logical domains */
271 phy_dom = dev_ctx->log_dom_count;
272
273 fc_update->level = dev_ctx->perf_table.level[phy_dom];
274 fc_update->adj_max_limit = dev_ctx->perf_table.adj_max_limit[phy_dom];
275 fc_update->adj_min_limit = dev_ctx->perf_table.adj_min_limit[phy_dom];
276 }
277 }
278
get_perf_table(struct perf_plugins_perf_update * dom,struct perf_plugins_dev_ctx * ctx,unsigned int dom_ix)279 static inline void get_perf_table(
280 struct perf_plugins_perf_update *dom,
281 struct perf_plugins_dev_ctx *ctx,
282 unsigned int dom_ix)
283 {
284 dom->level = &ctx->perf_table.level[dom_ix];
285 dom->max_limit = &ctx->perf_table.max_limit[dom_ix];
286 dom->adj_max_limit = &ctx->perf_table.adj_max_limit[dom_ix];
287 dom->min_limit = &ctx->perf_table.min_limit[dom_ix];
288 dom->adj_min_limit = &ctx->perf_table.adj_min_limit[dom_ix];
289 }
290
assign_data_for_plugins(fwk_id_t id,struct perf_plugins_perf_update * snapshot,enum plugin_domain_type dom_type)291 static void assign_data_for_plugins(
292 fwk_id_t id,
293 struct perf_plugins_perf_update *snapshot,
294 enum plugin_domain_type dom_type)
295 {
296 struct perf_plugins_dev_ctx *dev_ctx;
297 unsigned int dom_idx;
298
299 dev_ctx = perf_ph_get_ctx(id);
300
301 /* Determine the first entry on the table */
302 if (dom_type == PERF_PLUGIN_DOM_TYPE_FULL) {
303 snapshot->level = &perf_plugins_ctx.full_perf_table.level[0];
304
305 snapshot->max_limit = &perf_plugins_ctx.full_perf_table.max_limit[0];
306 snapshot->min_limit = &perf_plugins_ctx.full_perf_table.min_limit[0];
307
308 snapshot->adj_max_limit =
309 &perf_plugins_ctx.full_perf_table.adj_max_limit[0];
310 snapshot->adj_min_limit =
311 &perf_plugins_ctx.full_perf_table.adj_min_limit[0];
312
313 return;
314 } else if (dom_type == PERF_PLUGIN_DOM_TYPE_LOGICAL) {
315 /* Provide the beginning of the table */
316 dom_idx = 0;
317 } else {
318 /* Provide the last column of the table */
319 dom_idx = dev_ctx->log_dom_count;
320 }
321
322 /* Alter the module identifier only */
323 snapshot->domain_id = FWK_ID_SUB_ELEMENT(
324 FWK_MODULE_IDX_SCMI_PERF,
325 fwk_id_get_element_idx(id),
326 fwk_id_get_sub_element_idx(id));
327
328 get_perf_table(snapshot, dev_ctx, dom_idx);
329 }
330
domain_aggregate(struct perf_plugins_perf_update * this_dom,struct perf_plugins_perf_update * phy_dom)331 static inline void domain_aggregate(
332 struct perf_plugins_perf_update *this_dom,
333 struct perf_plugins_perf_update *phy_dom)
334 {
335 /*
336 * Choose the best values of performance for the physical domain which would
337 * satisfy all the logical domains.
338 *
339 * - pick the max for the level
340 * - pick the max for the min limit
341 * - pick the min for the max limit
342 */
343 if (this_dom->level[0] > phy_dom->level[0]) {
344 phy_dom->level[0] = this_dom->level[0];
345 }
346
347 if (this_dom->max_limit[0] < phy_dom->max_limit[0]) {
348 phy_dom->max_limit[0] = this_dom->max_limit[0];
349 }
350
351 if (this_dom->min_limit[0] > phy_dom->min_limit[0]) {
352 phy_dom->min_limit[0] = this_dom->min_limit[0];
353 }
354 }
355
store_and_aggregate(struct fc_perf_update * fc_update)356 static void store_and_aggregate(struct fc_perf_update *fc_update)
357 {
358 unsigned int this_dom_idx, phy_dom_idx;
359 struct perf_plugins_dev_ctx *dev_ctx;
360 struct perf_plugins_perf_update this_dom;
361 struct perf_plugins_perf_update phy_dom;
362 unsigned int phy_ix;
363
364 dev_ctx = perf_ph_get_ctx(fc_update->domain_id);
365
366 this_dom_idx = fwk_id_get_sub_element_idx(fc_update->domain_id);
367 phy_dom_idx = dev_ctx->log_dom_count;
368
369 get_perf_table(&this_dom, dev_ctx, this_dom_idx);
370 get_perf_table(&phy_dom, dev_ctx, phy_dom_idx);
371
372 this_dom.level[0] = fc_update->level;
373 this_dom.max_limit[0] = fc_update->max_limit;
374 this_dom.min_limit[0] = fc_update->min_limit;
375 this_dom.adj_max_limit[0] = fc_update->max_limit;
376 this_dom.adj_min_limit[0] = fc_update->min_limit;
377
378 if (this_dom_idx == 0) {
379 /* Init max/min for physical domain at the 1st iteration */
380 phy_dom.level[0] = 0;
381 phy_dom.max_limit[0] = UINT32_MAX;
382 phy_dom.min_limit[0] = 0;
383
384 /* as well as ctx */
385 dev_ctx->lmin = 0;
386 dev_ctx->lmax = UINT32_MAX;
387 }
388
389 domain_aggregate(&this_dom, &phy_dom);
390
391 phy_dom.adj_max_limit[0] = phy_dom.max_limit[0];
392 phy_dom.adj_min_limit[0] = phy_dom.min_limit[0];
393
394 if (this_dom_idx == (phy_dom_idx - 1)) {
395 /* Copy values, all-performance table */
396 phy_ix = fwk_id_get_element_idx(fc_update->domain_id);
397
398 perf_plugins_ctx.full_perf_table.level[phy_ix] = phy_dom.level[0];
399
400 perf_plugins_ctx.full_perf_table.max_limit[phy_ix] =
401 phy_dom.max_limit[0];
402 perf_plugins_ctx.full_perf_table.min_limit[phy_ix] =
403 phy_dom.min_limit[0];
404
405 perf_plugins_ctx.full_perf_table.adj_max_limit[phy_ix] =
406 phy_dom.adj_max_limit[0];
407 perf_plugins_ctx.full_perf_table.adj_min_limit[phy_ix] =
408 phy_dom.adj_min_limit[0];
409 }
410 }
411
perf_plugins_handler_update(unsigned int perf_dom_idx,struct fc_perf_update * fc_update)412 void perf_plugins_handler_update(
413 unsigned int perf_dom_idx,
414 struct fc_perf_update *fc_update)
415 {
416 struct perf_plugins_api *plugin_api;
417 struct perf_plugins_perf_update perf_snapshot;
418 unsigned int this_dom_idx, last_logical_dom_idx;
419 struct perf_plugins_dev_ctx *dev_ctx;
420 enum plugin_domain_type dom_type;
421 const struct mod_scmi_perf_config *config;
422 int status;
423
424 store_and_aggregate(fc_update);
425
426 dev_ctx = perf_ph_get_ctx(fc_update->domain_id);
427
428 this_dom_idx = fwk_id_get_sub_element_idx(fc_update->domain_id);
429 last_logical_dom_idx = dev_ctx->log_dom_count - 1;
430
431 config = perf_plugins_ctx.config;
432
433 /*
434 * EITHER last logical domain OR it's only physical domain,
435 * call the plugin - if any - with the data snapshot for this domain.
436 */
437 if (this_dom_idx == last_logical_dom_idx) {
438 if (config->plugins_count == 0) {
439 /* coordination-only */
440 plugins_policy_sync_level_limits(
441 dev_ctx, PERF_PLUGIN_DOM_TYPE_LOGICAL);
442 return;
443 }
444
445 for (size_t i = 0; i < config->plugins_count; i++) {
446 dom_type = config->plugins[i].dom_type;
447
448 if ((perf_dom_idx != (config->perf_doms_count - 1)) &&
449 (dom_type == PERF_PLUGIN_DOM_TYPE_FULL)) {
450 /*
451 * For plugins that need the full snapshot, wait until the
452 * last performance domain.
453 */
454 continue;
455 }
456
457 assign_data_for_plugins(
458 fc_update->domain_id, &perf_snapshot, dom_type);
459
460 plugin_api = perf_plugins_ctx.plugins_api_table[i];
461 status = plugin_api->update(&perf_snapshot);
462 if (status != FWK_SUCCESS) {
463 FWK_LOG_DEBUG(
464 "[P-Handler] Update: Plugin%u returned error %i",
465 (unsigned int)i,
466 status);
467 }
468
469 plugins_policy_sync_level_limits(dev_ctx, dom_type);
470 }
471 }
472 }
473
perf_plugins_handler_get(unsigned int perf_dom_idx,struct fc_perf_update * fc_update)474 void perf_plugins_handler_get(
475 unsigned int perf_dom_idx,
476 struct fc_perf_update *fc_update)
477 {
478 unsigned int this_dom_idx, last_logical_dom_idx;
479 const struct mod_scmi_perf_config *config;
480 struct perf_plugins_dev_ctx *dev_ctx;
481
482 dev_ctx = perf_ph_get_ctx(fc_update->domain_id);
483
484 this_dom_idx = fwk_id_get_sub_element_idx(fc_update->domain_id);
485 last_logical_dom_idx = dev_ctx->log_dom_count - 1;
486
487 if (this_dom_idx != last_logical_dom_idx) {
488 /*
489 * Any other logical domain, no need to forward the request to DVFS,
490 * thus use previous values.
491 */
492 fc_update->level = dev_ctx->max;
493 fc_update->adj_max_limit = dev_ctx->lmax;
494 fc_update->adj_min_limit = dev_ctx->lmin;
495 } else {
496 config = perf_plugins_ctx.config;
497
498 if (config->plugins_count == 0) {
499 /* domains coordination only */
500 plugins_policy_update_no_plugins(fc_update);
501 } else {
502 plugins_policy_update(fc_update);
503 }
504 }
505 }
506
perf_plugins_handler_report(struct perf_plugins_perf_report * data)507 void perf_plugins_handler_report(struct perf_plugins_perf_report *data)
508 {
509 const struct mod_scmi_perf_config *config;
510 struct perf_plugins_api *plugin_api;
511 int status;
512
513 config = perf_plugins_ctx.config;
514
515 if (config->plugins_count == 0) {
516 return;
517 }
518
519 for (size_t i = 0; i < config->plugins_count; i++) {
520 plugin_api = perf_plugins_ctx.plugins_api_table[i];
521
522 if (plugin_api->report != NULL) {
523 status = plugin_api->report(data);
524 if (status != FWK_SUCCESS) {
525 FWK_LOG_DEBUG(
526 "[P-Handler] Report: Plugin%u returned error %i",
527 (unsigned int)i,
528 status);
529 }
530 }
531 }
532 }
533
perf_plugins_alloc_tables(struct perf_plugins_perf_update * table,size_t count)534 static void perf_plugins_alloc_tables(
535 struct perf_plugins_perf_update *table,
536 size_t count)
537 {
538 table->level = fwk_mm_calloc(count, sizeof(uint32_t));
539 table->max_limit = fwk_mm_calloc(count, sizeof(uint32_t));
540 table->adj_max_limit = fwk_mm_calloc(count, sizeof(uint32_t));
541 table->min_limit = fwk_mm_calloc(count, sizeof(uint32_t));
542 table->adj_min_limit = fwk_mm_calloc(count, sizeof(uint32_t));
543 }
544
perf_plugins_handler_init(const struct mod_scmi_perf_config * config)545 int perf_plugins_handler_init(const struct mod_scmi_perf_config *config)
546 {
547 const struct mod_scmi_perf_domain_config *domain;
548 int dvfs_doms_count;
549 struct perf_plugins_dev_ctx *dev_ctx;
550 unsigned int pgroup, ldom = 0;
551 size_t all_doms_count;
552 unsigned int phy_group;
553 bool has_phy_group;
554
555 dvfs_doms_count =
556 fwk_module_get_element_count(FWK_ID_MODULE(FWK_MODULE_IDX_DVFS));
557 if (dvfs_doms_count <= 0) {
558 return FWK_E_SUPPORT;
559 }
560
561 perf_plugins_ctx.dvfs_doms_count = (size_t)dvfs_doms_count;
562
563 perf_plugins_ctx.dev_ctx = fwk_mm_calloc(
564 (size_t)dvfs_doms_count, sizeof(struct perf_plugins_dev_ctx));
565
566 /*
567 * Iterate all over the SCMI performance domain table to build the number of
568 * logical domains that belong to the same physical domain.
569 */
570 for (size_t i = 0; i < config->perf_doms_count; i++) {
571 domain = &(*config->domains)[i];
572
573 has_phy_group = fwk_optional_id_is_defined(domain->phy_group_id);
574 if (has_phy_group) {
575 phy_group = fwk_id_get_element_idx(domain->phy_group_id);
576 } else {
577 phy_group = i;
578 }
579
580 dev_ctx = &perf_plugins_ctx.dev_ctx[phy_group];
581 dev_ctx->log_dom_count++;
582 }
583
584 /*
585 * Allocate a table for each of the physical domain to contain the
586 * requested levels/limits by each of its logical domains.
587 * The size will be: number of logical domains + 1 (for physical domain).
588 *
589 * At the same time, initialise min and max.
590 */
591 for (size_t i = 0; i < perf_plugins_ctx.dvfs_doms_count; i++) {
592 dev_ctx = &perf_plugins_ctx.dev_ctx[i];
593
594 all_doms_count = (size_t)(dev_ctx->log_dom_count + 1);
595
596 perf_plugins_alloc_tables(&dev_ctx->perf_table, all_doms_count);
597
598 dev_ctx->lmin = 0;
599 dev_ctx->lmax = UINT32_MAX;
600 dev_ctx->perf_table.domain_id = FWK_ID_ELEMENT(FWK_MODULE_IDX_DVFS, i);
601 }
602
603 /*
604 * Allocate a table to store the physical/aggregated values for each of the
605 * physical domain for plugins that require the full picture of performance.
606 */
607 perf_plugins_alloc_tables(
608 &perf_plugins_ctx.full_perf_table, perf_plugins_ctx.dvfs_doms_count);
609
610 /*
611 * The data provided for a full snapshot will always have a module
612 * identifier.
613 */
614 perf_plugins_ctx.full_perf_table.domain_id =
615 FWK_ID_MODULE(FWK_MODULE_IDX_SCMI_PERF);
616
617 /* Allocate a table of dependency domains identifiers */
618 perf_plugins_ctx.dep_id_table =
619 fwk_mm_calloc(config->perf_doms_count, sizeof(fwk_id_t));
620
621 domain = &(*config->domains)[0];
622
623 /*
624 * Build the dependency domains.
625 *
626 * If we find the optional identifier for physical domain description,
627 * we assume that SCMI performance domains are grouped and ordered together
628 * for the same physical domain.
629 */
630 for (size_t j = 0; j < config->perf_doms_count; j++) {
631 has_phy_group = fwk_optional_id_is_defined(domain->phy_group_id);
632 if (has_phy_group) {
633 /* Custom mapping */
634 pgroup = fwk_id_get_element_idx(domain->phy_group_id);
635 domain = &(*config->domains)[j];
636
637 if (fwk_id_get_element_idx(domain->phy_group_id) != pgroup) {
638 /* Restart count of logical domains */
639 ldom = 0;
640 }
641
642 perf_plugins_ctx.dep_id_table[j] = FWK_ID_SUB_ELEMENT(
643 FWK_MODULE_IDX_DVFS,
644 fwk_id_get_element_idx(domain->phy_group_id),
645 ldom);
646
647 ldom++;
648 } else {
649 /* Direct implicit mapping to dvfs */
650 perf_plugins_ctx.dep_id_table[j] =
651 FWK_ID_SUB_ELEMENT(FWK_MODULE_IDX_DVFS, j, 0);
652 }
653 }
654
655 perf_plugins_ctx.config = config;
656
657 return FWK_SUCCESS;
658 }
659
perf_plugins_handler_bind(void)660 int perf_plugins_handler_bind(void)
661 {
662 fwk_id_t plugin_id;
663 const struct mod_scmi_perf_config *config = perf_plugins_ctx.config;
664 int status;
665
666 if (config->plugins_count == 0) {
667 return FWK_SUCCESS;
668 }
669
670 perf_plugins_ctx.plugins_api_table =
671 fwk_mm_calloc(config->plugins_count, sizeof(struct perf_plugins_api *));
672
673 /* Bind to all the performance plugins */
674 for (size_t i = 0; i < config->plugins_count; i++) {
675 plugin_id = config->plugins[i].id;
676
677 status = fwk_module_bind(
678 plugin_id,
679 FWK_ID_API(
680 fwk_id_get_module_idx(plugin_id), MOD_SCMI_PERF_PLUGIN_API),
681 &perf_plugins_ctx.plugins_api_table[i]);
682 if (status != FWK_SUCCESS) {
683 return FWK_E_PARAM;
684 }
685 }
686
687 return FWK_SUCCESS;
688 }
689
perf_plugins_handler_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** ph_process_bind_request_api)690 int perf_plugins_handler_process_bind_request(
691 fwk_id_t source_id,
692 fwk_id_t target_id,
693 fwk_id_t api_id,
694 const void **ph_process_bind_request_api)
695 {
696 *ph_process_bind_request_api = &handler_api;
697
698 return FWK_SUCCESS;
699 }
700 #endif /* BUILD_HAS_SCMI_PERF_PLUGIN_HANDLER */
701