1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Description:
8 * System Control and Management Interface (SCMI) support.
9 */
10
11 #include <internal/mod_scmi.h>
12 #ifdef BUILD_HAS_BASE_PROTOCOL
13 # include <internal/mod_scmi_base.h>
14 #endif
15 #include <internal/scmi.h>
16
17 #include <mod_scmi.h>
18 #include <mod_scmi_header.h>
19
20 #include <fwk_assert.h>
21 #include <fwk_core.h>
22 #include <fwk_event.h>
23 #include <fwk_id.h>
24 #include <fwk_log.h>
25 #include <fwk_macros.h>
26 #include <fwk_mm.h>
27 #include <fwk_module.h>
28 #include <fwk_module_idx.h>
29 #include <fwk_notification.h>
30 #include <fwk_status.h>
31 #include <fwk_string.h>
32
33 #ifdef BUILD_HAS_MOD_RESOURCE_PERMS
34 # include <mod_resource_perms.h>
35 #endif
36
37 #include <inttypes.h>
38
39 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
40
41 /* Following macros are used for scmi notification related operations */
42 # define MOD_SCMI_PROTOCOL_MAX_OPERATION_ID 0x20
43 # define MOD_SCMI_PROTOCOL_OPERATION_IDX_INVALID 0xFF
44
45 struct scmi_notification_subscribers {
46 unsigned int agent_count;
47 unsigned int element_count;
48 unsigned int operation_count;
49 unsigned int operation_idx;
50 uint8_t operation_id_to_idx[MOD_SCMI_PROTOCOL_MAX_OPERATION_ID];
51
52 /*
53 * Table of protocol operations for which SCMI notification is requested
54 * An agent which is requesting a SCMI notification is identified using its
55 * service_id and associated context as below.
56 *
57 * Usually, a notification is requested for
58 * 1. A specific operation on the protocol.
59 * 2. An element (e.g. domain_id)
60 * 3. And a specific agent (e.g PSCI/OSPM)
61 *
62 * e.g. in Performance domain case,
63 * 1. operation_id maps to
64 * either PERFORMANCE_LIMITS_CHANGED/PERFORMANCE_LEVEL_CHANGED
65 * 2. element maps to a performance domain.
66 * 3. And an agent maps to either a PSCI agent or an OSPM agent
67 *
68 * Thus, a service_id of a requesting agent can be indexed using above
69 * information using a simple 3-dimentional array as below
70 *
71 * agent_service_ids[operation_idx][element_idx][agent_idx]
72 */
73 fwk_id_t *agent_service_ids;
74 };
75
76 #endif
77
78 /*
79 * Entry zero (0) of the protocol table 'protocol_table' is not used, as index
80 * 0 is the index of the unused entries of the 'scmi_protocol_id_to_idx[]'
81 * table. Entry one (1) is reserved for the base protocol implemented in this
82 * file.
83 */
84 #define PROTOCOL_TABLE_BASE_PROTOCOL_IDX 1
85 #define PROTOCOL_TABLE_RESERVED_ENTRIES_COUNT 2
86
87 static struct mod_scmi_ctx scmi_ctx;
88
89 /*
90 * Utility functions
91 */
92
93 /*
94 * Return a packed 32-bit message header comprised of an 8-bit message
95 * identifier, a 2-bit message type, an 8-bit protocol identifier,
96 * and a 10-bit token.
97 */
scmi_message_header(uint8_t message_id,uint8_t message_type,uint8_t protocol_id,uint8_t token)98 static uint32_t scmi_message_header(uint8_t message_id,
99 uint8_t message_type, uint8_t protocol_id, uint8_t token)
100 {
101 return (
102 (((message_id) << SCMI_MESSAGE_HEADER_MESSAGE_ID_POS) &
103 SCMI_MESSAGE_HEADER_MESSAGE_ID_MASK) |
104 (((message_type) << SCMI_MESSAGE_HEADER_MESSAGE_TYPE_POS) &
105 SCMI_MESSAGE_HEADER_MESSAGE_TYPE_MASK) |
106 (((protocol_id) << SCMI_MESSAGE_HEADER_PROTOCOL_ID_POS) &
107 SCMI_MESSAGE_HEADER_PROTOCOL_ID_MASK) |
108 (((token) << SCMI_MESSAGE_HEADER_TOKEN_POS) &
109 SCMI_MESSAGE_HEADER_TOKEN_MASK));
110 }
111
read_message_id(uint32_t message_header)112 static uint16_t read_message_id(uint32_t message_header)
113 {
114 return (uint16_t)(
115 ((message_header & SCMI_MESSAGE_HEADER_MESSAGE_ID_MASK) >>
116 SCMI_MESSAGE_HEADER_MESSAGE_ID_POS));
117 }
118
read_message_type(uint32_t message_header)119 static uint8_t read_message_type(uint32_t message_header)
120 {
121 return (uint8_t)(
122 ((message_header & SCMI_MESSAGE_HEADER_MESSAGE_TYPE_MASK) >>
123 SCMI_MESSAGE_HEADER_MESSAGE_TYPE_POS));
124 }
125
read_protocol_id(uint32_t message_header)126 static uint8_t read_protocol_id(uint32_t message_header)
127 {
128 return (uint8_t)(
129 ((message_header & SCMI_MESSAGE_HEADER_PROTOCOL_ID_MASK) >>
130 SCMI_MESSAGE_HEADER_PROTOCOL_ID_POS));
131 }
132
read_token(uint32_t message_header)133 static uint16_t read_token(uint32_t message_header)
134 {
135 return (uint16_t)(
136 ((message_header & SCMI_MESSAGE_HEADER_TOKEN_MASK) >>
137 SCMI_MESSAGE_HEADER_TOKEN_POS));
138 }
139
get_message_type_str(const struct scmi_service_ctx * ctx)140 static const char *get_message_type_str(const struct scmi_service_ctx *ctx)
141 {
142 enum mod_scmi_message_type message_type = ctx->scmi_message_type;
143 switch (message_type) {
144 case MOD_SCMI_MESSAGE_TYPE_COMMAND:
145 if (ctx->config->scmi_entity_role == MOD_SCMI_ROLE_PLATFORM) {
146 return "Cmd";
147 } else if (ctx->config->scmi_entity_role == MOD_SCMI_ROLE_AGENT) {
148 return "Cmd-Resp";
149 } else {
150 return "";
151 }
152
153 case MOD_SCMI_MESSAGE_TYPE_DELAYED_RESPONSE:
154 return "Del-Resp";
155
156 case MOD_SCMI_MESSAGE_TYPE_NOTIFICATION:
157 return "Notif";
158
159 default:
160 return "Invalid message";
161 }
162 }
163
164 /*
165 * Transport entity -> SCMI module
166 */
signal_error(fwk_id_t service_id)167 static int signal_error(fwk_id_t service_id)
168 {
169 fwk_id_t transport_id;
170 struct scmi_service_ctx *ctx;
171
172 ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(service_id)];
173 transport_id = ctx->transport_id;
174
175 return ctx->respond(transport_id, &(int32_t){SCMI_PROTOCOL_ERROR},
176 sizeof(int32_t));
177 }
178
signal_message(fwk_id_t service_id)179 static int signal_message(fwk_id_t service_id)
180 {
181 struct fwk_event_light event = (struct fwk_event_light){
182 .id = FWK_ID_EVENT(FWK_MODULE_IDX_SCMI, 0),
183 .source_id = FWK_ID_MODULE(FWK_MODULE_IDX_SCMI),
184 .target_id = service_id,
185 };
186
187 return fwk_put_event(&event);
188 }
189
190 static const struct mod_scmi_from_transport_api scmi_from_transport_api = {
191 .signal_error = signal_error,
192 .signal_message = signal_message,
193 };
194
195 /*
196 * SCMI protocol module -> SCMI module interface
197 */
198
get_agent_count(unsigned int * agent_count)199 static int get_agent_count(unsigned int *agent_count)
200 {
201 if (agent_count == NULL) {
202 return FWK_E_PARAM;
203 }
204
205 /* Include the platform in the count */
206 *agent_count = scmi_ctx.config->agent_count + 1u;
207
208 return FWK_SUCCESS;
209 }
210
211
get_agent_id(fwk_id_t service_id,unsigned int * agent_id)212 static int get_agent_id(fwk_id_t service_id, unsigned int *agent_id)
213 {
214 struct scmi_service_ctx *ctx;
215
216 if (agent_id == NULL) {
217 return FWK_E_PARAM;
218 }
219
220 ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(service_id)];
221
222 *agent_id = ctx->config->scmi_agent_id;
223
224 return FWK_SUCCESS;
225 }
226
get_agent_type(uint32_t scmi_agent_id,enum scmi_agent_type * agent_type)227 static int get_agent_type(uint32_t scmi_agent_id,
228 enum scmi_agent_type *agent_type)
229 {
230 if ((agent_type == NULL) ||
231 (scmi_agent_id > scmi_ctx.config->agent_count) ||
232 (scmi_agent_id == MOD_SCMI_PLATFORM_ID)) {
233 return FWK_E_PARAM;
234 }
235
236 *agent_type = scmi_ctx.config->agent_table[scmi_agent_id].type;
237
238 return FWK_SUCCESS;
239 }
240
get_max_payload_size(fwk_id_t service_id,size_t * size)241 static int get_max_payload_size(fwk_id_t service_id, size_t *size)
242 {
243 struct scmi_service_ctx *ctx;
244
245 if (size == NULL) {
246 return FWK_E_PARAM;
247 }
248
249 ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(service_id)];
250
251 return ctx->transport_api->get_max_payload_size(ctx->transport_id, size);
252 }
253
write_payload(fwk_id_t service_id,size_t offset,const void * payload,size_t size)254 static int write_payload(fwk_id_t service_id, size_t offset,
255 const void *payload, size_t size)
256 {
257 const struct scmi_service_ctx *ctx;
258
259 ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(service_id)];
260
261 return ctx->transport_api->write_payload(ctx->transport_id,
262 offset, payload, size);
263 }
264
respond(fwk_id_t service_id,const void * payload,size_t size)265 static int respond(fwk_id_t service_id, const void *payload, size_t size)
266 {
267 int status;
268 const struct scmi_service_ctx *ctx;
269 const char *service_name;
270 const char *message_type_name;
271
272 ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(service_id)];
273
274 service_name = fwk_module_get_element_name(service_id);
275 message_type_name = get_message_type_str(ctx);
276
277 /*
278 * Print to the error log if the message was not successfully processed.
279 * We assume here that the first payload entry of the command response
280 * holds an SCMI status code. This is the case for all the SCMI commands
281 * specified so far, but it is not explicitly stated (yet) in the
282 * specification it should be like that for all commands.
283 */
284 if ((payload != NULL) && (*((int32_t *)payload) < SCMI_SUCCESS)) {
285 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
286 FWK_LOG_ERR(
287 "[SCMI] %s: %s [%" PRIu16 " (0x%x:0x%x)] returned error (%d)",
288 service_name,
289 message_type_name,
290 ctx->scmi_token,
291 ctx->scmi_protocol_id,
292 ctx->scmi_message_id,
293 *((int *)payload));
294 #else
295 (void)service_name;
296 (void)message_type_name;
297 #endif
298 } else {
299 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_DEBUG
300 FWK_LOG_DEBUG(
301 "[SCMI] %s: %s [%" PRIu16 " (0x%x:0x%x)] returned successfully",
302 service_name,
303 message_type_name,
304 ctx->scmi_token,
305 ctx->scmi_protocol_id,
306 ctx->scmi_message_id);
307 #endif
308 }
309
310 status = ctx->respond(ctx->transport_id, payload, size);
311 if (status != FWK_SUCCESS) {
312 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
313 FWK_LOG_ERR(
314 "[SCMI] %s: %s [%" PRIu16
315 " (0x%x:0x%x)] failed to respond (%s)",
316 service_name,
317 message_type_name,
318 ctx->scmi_token,
319 ctx->scmi_protocol_id,
320 ctx->scmi_message_id,
321 fwk_status_str(status));
322 #endif
323 }
324 return status;
325 }
326
scmi_notify(fwk_id_t id,int protocol_id,int message_id,const void * payload,size_t size)327 static void scmi_notify(fwk_id_t id, int protocol_id, int message_id,
328 const void *payload, size_t size)
329 {
330 const struct scmi_service_ctx *ctx, *p2a_ctx;
331 uint32_t message_header;
332 int status;
333 bool request_ack_by_interrupt;
334
335 /*
336 * The ID is the identifier of the service channel which
337 * the agent used to request notificatiosn on. This ID is
338 * linked to a P2A channel by the scmi_p2a_id.
339 */
340 if (fwk_id_is_equal(id, FWK_ID_NONE)) {
341 return;
342 }
343
344 ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(id)];
345 if (ctx == NULL) {
346 return;
347 }
348 /* ctx is the original A2P service channel */
349 if (fwk_id_is_equal(ctx->config->scmi_p2a_id, FWK_ID_NONE)) {
350 return;
351 }
352 /* Get the P2A service channel for A2P ctx */
353 p2a_ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(
354 ctx->config->scmi_p2a_id)];
355 if ((p2a_ctx == NULL) || (p2a_ctx->transmit == NULL)) {
356 return; /* No notification service configured */
357 }
358
359 message_header = scmi_message_header(
360 (uint8_t)message_id,
361 (uint8_t)MOD_SCMI_MESSAGE_TYPE_NOTIFICATION,
362 (uint8_t)protocol_id,
363 0);
364
365 request_ack_by_interrupt = false;
366 status = p2a_ctx->transmit(
367 p2a_ctx->transport_id,
368 message_header,
369 payload,
370 size,
371 request_ack_by_interrupt);
372 if (status != FWK_SUCCESS) {
373 FWK_LOG_DEBUG("[SCMI] %s @%d", __func__, __LINE__);
374 }
375 }
376
scmi_send_message(uint8_t message_id,uint8_t protocol_id,uint8_t token,fwk_id_t service_id,const void * payload,size_t payload_size,bool request_ack_by_interrupt)377 int scmi_send_message(
378 uint8_t message_id,
379 uint8_t protocol_id,
380 uint8_t token,
381 fwk_id_t service_id,
382 const void *payload,
383 size_t payload_size,
384 bool request_ack_by_interrupt)
385 {
386 int status;
387
388 /* All commands, synchronous or asynchronous, have a message type of 0 */
389 uint8_t message_type = 0;
390
391 /* Create the SCMI message header from the arguments */
392 uint32_t message_header =
393 scmi_message_header(message_id, message_type, protocol_id, token);
394
395 if (fwk_id_is_equal(service_id, FWK_ID_NONE)) {
396 return FWK_E_DATA;
397 }
398
399 /* Fetch scmi module context data using the service_id */
400 const struct mod_scmi_to_transport_api *transport_api;
401 const struct scmi_service_ctx *ctx;
402 ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(service_id)];
403
404 if (ctx == NULL) {
405 return FWK_E_DATA;
406 }
407
408 /* Initalize the transport api pointer to TRANSPORT module api */
409 transport_api = ctx->transport_api;
410
411 /* Send the SCMI message using the transport_transmit() API */
412 status = transport_api->transmit(
413 ctx->transport_id,
414 message_header,
415 payload,
416 payload_size,
417 request_ack_by_interrupt);
418
419 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
420 if (status == FWK_SUCCESS) {
421 FWK_LOG_DEBUG(
422 "[SCMI] %s: Cmd [%" PRIu16 " (0x%x:0x%x)] was sent",
423 fwk_module_get_element_name(service_id),
424 token,
425 protocol_id,
426 message_id);
427 } else {
428 FWK_LOG_ERR(
429 "[SCMI] %s: Cmd [%" PRIu16 " (0x%x:0x%x)] failed to respond (%s)",
430 fwk_module_get_element_name(service_id),
431 token,
432 protocol_id,
433 message_id,
434 fwk_status_str(status));
435 }
436 #endif
437
438 return status;
439 };
440
response_message_handler(fwk_id_t service_id)441 int response_message_handler(fwk_id_t service_id)
442 {
443 int status;
444 const struct scmi_service_ctx *ctx;
445
446 ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(service_id)];
447
448 /* release the tranport channel lock */
449 status =
450 ctx->transport_api->release_transport_channel_lock(ctx->transport_id);
451
452 return status;
453 }
454
455 static const struct mod_scmi_from_protocol_api scmi_from_protocol_api = {
456 .get_agent_count = get_agent_count,
457 .get_agent_id = get_agent_id,
458 .get_agent_type = get_agent_type,
459 .get_max_payload_size = get_max_payload_size,
460 .write_payload = write_payload,
461 .respond = respond,
462 .notify = scmi_notify,
463 };
464
465 static const struct mod_scmi_from_protocol_req_api
466 scmi_from_protocol_req_api = {
467 .scmi_send_message = scmi_send_message,
468 .response_message_handler = response_message_handler,
469 };
470
471 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
notification_subscribers(unsigned int protocol_id)472 static struct scmi_notification_subscribers *notification_subscribers(
473 unsigned int protocol_id)
474 {
475 unsigned int protocol_idx;
476 protocol_idx = scmi_ctx.scmi_protocol_id_to_idx[protocol_id];
477 /*
478 * Couple of entries are reserved in scmi_protocol_id_to_idx,
479 * out of these, one is reserved for the Base protocol. Since we may need
480 * to enable notification for the Base protocol adjust the protocol_idx
481 * accordingly.
482 */
483 protocol_idx -= (PROTOCOL_TABLE_RESERVED_ENTRIES_COUNT - 1);
484 return &scmi_ctx.scmi_notif_subscribers[protocol_idx];
485 }
486
scmi_notification_init(unsigned int protocol_id,unsigned int agent_count,unsigned int element_count,unsigned int operation_count)487 static int scmi_notification_init(
488 unsigned int protocol_id,
489 unsigned int agent_count,
490 unsigned int element_count,
491 unsigned int operation_count)
492 {
493 int i;
494 int total_count;
495 struct scmi_notification_subscribers *subscribers =
496 notification_subscribers(protocol_id);
497
498 subscribers->agent_count = agent_count;
499 subscribers->element_count = element_count;
500 subscribers->operation_count = operation_count;
501
502 total_count = (int)(operation_count * element_count * agent_count);
503
504 subscribers->agent_service_ids =
505 fwk_mm_calloc((size_t)total_count, sizeof(fwk_id_t));
506
507 /*
508 * Mark all operations_idx as invalid. This will be updated
509 * whenever an agent subscribes to a notification for an operation.
510 */
511 fwk_str_memset(
512 subscribers->operation_id_to_idx,
513 MOD_SCMI_PROTOCOL_OPERATION_IDX_INVALID,
514 MOD_SCMI_PROTOCOL_MAX_OPERATION_ID);
515
516 for (i = 0; i < total_count; i++) {
517 subscribers->agent_service_ids[i] = FWK_ID_NONE;
518 }
519
520 return FWK_SUCCESS;
521 }
522
scmi_notification_service_idx(unsigned int agent_idx,unsigned int element_idx,unsigned int operation_idx,unsigned int agent_count,unsigned int element_count)523 static int scmi_notification_service_idx(
524 unsigned int agent_idx,
525 unsigned int element_idx,
526 unsigned int operation_idx,
527 unsigned int agent_count,
528 unsigned int element_count)
529 {
530 /*
531 * The index is from a 3-dimentional array
532 * [operation_idx][element_idx][agent_idx]
533 * The calculation of service_id offset in above array is as below
534 * 1. Get the offset of the service_id in the 3rd array .
535 * +
536 * 2. Get the offset of the 3rd array within the 2nd array.
537 * +
538 * 3. Get the offset of the 2nd array within the first array.
539 */
540 return (
541 int)(agent_idx + element_idx * agent_count + operation_idx * element_count * agent_count);
542 }
543
scmi_notification_add_subscriber(unsigned int protocol_id,unsigned int element_idx,unsigned int operation_id,fwk_id_t service_id)544 static int scmi_notification_add_subscriber(
545 unsigned int protocol_id,
546 unsigned int element_idx,
547 unsigned int operation_id,
548 fwk_id_t service_id)
549 {
550 int status;
551 unsigned int service_id_idx;
552 unsigned int agent_idx;
553
554 struct scmi_notification_subscribers *subscribers =
555 notification_subscribers(protocol_id);
556
557 status = get_agent_id(service_id, &agent_idx);
558 if (status != FWK_SUCCESS) {
559 return status;
560 }
561
562 fwk_assert(operation_id < MOD_SCMI_PROTOCOL_MAX_OPERATION_ID);
563 /*
564 * Initialize only if the entry is
565 * invalid (MOD_SCMI_PROTOCOL_OPERATION_IDX_INVALID)
566 */
567 if (subscribers->operation_id_to_idx[operation_id] ==
568 MOD_SCMI_PROTOCOL_OPERATION_IDX_INVALID) {
569 fwk_assert(subscribers->operation_idx < subscribers->operation_count);
570 subscribers->operation_id_to_idx[operation_id] =
571 (uint8_t)subscribers->operation_idx++;
572 }
573
574 service_id_idx = (unsigned int)scmi_notification_service_idx(
575 agent_idx,
576 element_idx,
577 subscribers->operation_id_to_idx[operation_id],
578 subscribers->agent_count,
579 subscribers->element_count);
580
581 subscribers->agent_service_ids[service_id_idx] = service_id;
582
583 return FWK_SUCCESS;
584 }
585
scmi_notification_remove_subscriber(unsigned int protocol_id,unsigned int agent_idx,unsigned int element_idx,unsigned int operation_id)586 static int scmi_notification_remove_subscriber(
587 unsigned int protocol_id,
588 unsigned int agent_idx,
589 unsigned int element_idx,
590 unsigned int operation_id)
591 {
592 unsigned int operation_idx = 0;
593 unsigned int service_id_idx;
594
595 struct scmi_notification_subscribers *subscribers =
596 notification_subscribers(protocol_id);
597
598 fwk_assert(operation_id < MOD_SCMI_PROTOCOL_MAX_OPERATION_ID);
599
600 operation_idx = subscribers->operation_id_to_idx[operation_id];
601
602 service_id_idx = (unsigned int)scmi_notification_service_idx(
603 agent_idx,
604 element_idx,
605 operation_idx,
606 subscribers->agent_count,
607 subscribers->element_count);
608
609 subscribers->agent_service_ids[service_id_idx] = FWK_ID_NONE;
610
611 return FWK_SUCCESS;
612 }
613
scmi_notification_notify(unsigned int protocol_id,unsigned int operation_id,unsigned int scmi_response_id,void * payload_p2a,size_t payload_size)614 static int scmi_notification_notify(
615 unsigned int protocol_id,
616 unsigned int operation_id,
617 unsigned int scmi_response_id,
618 void *payload_p2a,
619 size_t payload_size)
620 {
621 unsigned int i, j;
622 unsigned int operation_idx;
623 fwk_id_t service_id;
624 unsigned int service_id_idx;
625
626 struct scmi_notification_subscribers *subscribers =
627 notification_subscribers(protocol_id);
628
629 fwk_assert(operation_id < MOD_SCMI_PROTOCOL_MAX_OPERATION_ID);
630 operation_idx = subscribers->operation_id_to_idx[operation_id];
631
632 /*
633 * Silently return FWK_SUCCESS if no valid operation_idx is found
634 * for a given operation_id. This is required in where(e.g. DVFS/perf)
635 * scmi_notification_notify gets called before a call to
636 * scmi_notification_add_subscriber.
637 */
638 if (operation_idx == MOD_SCMI_PROTOCOL_OPERATION_IDX_INVALID) {
639 return FWK_SUCCESS;
640 }
641
642 for (i = 0; i < subscribers->element_count; i++) {
643 /* Skip agent 0, platform agent */
644 for (j = 1; j < subscribers->agent_count; j++) {
645 service_id_idx = (unsigned int)scmi_notification_service_idx(
646 j,
647 i,
648 operation_idx,
649 subscribers->agent_count,
650 subscribers->element_count);
651
652 service_id = subscribers->agent_service_ids[service_id_idx];
653
654 if (!fwk_id_is_equal(service_id, FWK_ID_NONE)) {
655 scmi_notify(
656 service_id,
657 (int)protocol_id,
658 (int)scmi_response_id,
659 payload_p2a,
660 payload_size);
661 }
662 }
663 }
664
665 return FWK_SUCCESS;
666 }
667
668 static struct mod_scmi_notification_api mod_scmi_notif_api = {
669 .scmi_notification_init = scmi_notification_init,
670 .scmi_notification_add_subscriber = scmi_notification_add_subscriber,
671 .scmi_notification_remove_subscriber = scmi_notification_remove_subscriber,
672 .scmi_notification_notify = scmi_notification_notify,
673 };
674 #endif
675
676 /*
677 * Framework handlers
678 */
679
scmi_init(fwk_id_t module_id,unsigned int service_count,const void * data)680 static int scmi_init(fwk_id_t module_id, unsigned int service_count,
681 const void *data)
682 {
683 struct mod_scmi_config *config = (struct mod_scmi_config *)data;
684 unsigned int agent_idx;
685 const struct mod_scmi_agent *agent;
686
687 if (config == NULL) {
688 return FWK_E_PARAM;
689 }
690
691 if (config->agent_count > MOD_SCMI_AGENT_ID_MAX) {
692 return FWK_E_PARAM;
693 }
694
695 /*
696 * Loop over the agent descriptors. The MOD_SCMI_PLATFORM_ID(0) entry of
697 * the table - that would refer to the platform - is ignored.
698 */
699 for (agent_idx = MOD_SCMI_PLATFORM_ID + 1;
700 agent_idx <= config->agent_count;
701 agent_idx++) {
702 agent = &config->agent_table[agent_idx];
703 if (agent->type >= SCMI_AGENT_TYPE_COUNT) {
704 return FWK_E_PARAM;
705 }
706 }
707
708 scmi_ctx.protocol_table = fwk_mm_calloc(
709 config->protocol_count_max + PROTOCOL_TABLE_RESERVED_ENTRIES_COUNT,
710 sizeof(scmi_ctx.protocol_table[0]));
711
712 if (config->protocol_requester_count_max != 0) {
713 scmi_ctx.protocol_requester_table = fwk_mm_calloc(
714 config->protocol_requester_count_max,
715 sizeof(scmi_ctx.protocol_requester_table[0]));
716 } else {
717 scmi_ctx.protocol_requester_table = NULL;
718 }
719
720 scmi_ctx.service_ctx_table = fwk_mm_calloc(
721 service_count, sizeof(scmi_ctx.service_ctx_table[0]));
722
723 #ifdef BUILD_HAS_BASE_PROTOCOL
724 scmi_ctx.protocol_table[PROTOCOL_TABLE_BASE_PROTOCOL_IDX].message_handler =
725 scmi_base_message_handler;
726 scmi_ctx.scmi_protocol_id_to_idx[MOD_SCMI_PROTOCOL_ID_BASE] =
727 PROTOCOL_TABLE_BASE_PROTOCOL_IDX;
728 scmi_base_set_api(&scmi_from_protocol_api);
729 scmi_base_set_shared_ctx(&scmi_ctx);
730 #endif
731 scmi_ctx.config = config;
732
733 return FWK_SUCCESS;
734 }
735
scmi_service_init(fwk_id_t service_id,unsigned int unused,const void * data)736 static int scmi_service_init(fwk_id_t service_id, unsigned int unused,
737 const void *data)
738 {
739 const struct mod_scmi_service_config *config =
740 (struct mod_scmi_service_config *)data;
741 struct scmi_service_ctx *ctx;
742
743 if (((config->scmi_agent_id == MOD_SCMI_PLATFORM_ID) ||
744 (config->scmi_agent_id > scmi_ctx.config->agent_count)) &&
745 (config->scmi_entity_role == MOD_SCMI_ROLE_PLATFORM)) {
746 return FWK_E_PARAM;
747 }
748
749 ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(service_id)];
750 ctx->config = config;
751
752 return FWK_SUCCESS;
753 }
754
scmi_bind(fwk_id_t id,unsigned int round)755 static int scmi_bind(fwk_id_t id, unsigned int round)
756 {
757 int status;
758 struct scmi_service_ctx *ctx;
759 const struct mod_scmi_to_transport_api *transport_api = NULL;
760 unsigned int protocol_idx;
761 struct scmi_protocol *protocol, *protocol_req;
762 struct mod_scmi_to_protocol_api *protocol_api = NULL;
763 uint8_t scmi_protocol_id;
764
765 if (round == 0) {
766 if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
767 return FWK_SUCCESS;
768 }
769
770 ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(id)];
771 status = fwk_module_bind(ctx->config->transport_id,
772 ctx->config->transport_api_id, &transport_api);
773 if (status != FWK_SUCCESS) {
774 return status;
775 }
776
777 if ((transport_api->get_secure == NULL) ||
778 (transport_api->get_max_payload_size == NULL) ||
779 (transport_api->get_message_header == NULL) ||
780 (transport_api->get_payload == NULL) ||
781 (transport_api->write_payload == NULL)) {
782 return FWK_E_DATA;
783 }
784
785 ctx->transport_api = transport_api;
786 ctx->transport_id = ctx->config->transport_id;
787 ctx->respond = transport_api->respond;
788 ctx->transmit = transport_api->transmit;
789
790 return FWK_SUCCESS;
791 }
792
793 if (fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT)) {
794 return FWK_SUCCESS;
795 }
796
797 for (protocol_idx = 0;
798 protocol_idx < scmi_ctx.protocol_count; protocol_idx++) {
799 protocol = &scmi_ctx.protocol_table[
800 PROTOCOL_TABLE_RESERVED_ENTRIES_COUNT + protocol_idx];
801
802 status = fwk_module_bind(protocol->id,
803 FWK_ID_API(fwk_id_get_module_idx(protocol->id), 0), &protocol_api);
804 if (status != FWK_SUCCESS) {
805 return status;
806 }
807
808 if ((protocol_api->get_scmi_protocol_id == NULL) ||
809 (protocol_api->message_handler == NULL)) {
810 return FWK_E_DATA;
811 }
812 status = protocol_api->get_scmi_protocol_id(protocol->id,
813 &scmi_protocol_id);
814 if (status != FWK_SUCCESS) {
815 return status;
816 }
817
818 if (scmi_ctx.scmi_protocol_id_to_idx[scmi_protocol_id] != 0) {
819 return FWK_E_STATE;
820 }
821
822 scmi_ctx.scmi_protocol_id_to_idx[scmi_protocol_id] =
823 (uint8_t)(protocol_idx + PROTOCOL_TABLE_RESERVED_ENTRIES_COUNT);
824 protocol->message_handler = protocol_api->message_handler;
825 }
826
827 for (protocol_idx = 0; protocol_idx < scmi_ctx.protocol_requester_count;
828 protocol_idx++) {
829 protocol_req = &scmi_ctx.protocol_requester_table[protocol_idx];
830
831 status = fwk_module_bind(
832 protocol_req->id,
833 FWK_ID_API(fwk_id_get_module_idx(protocol_req->id), 0),
834 &protocol_api);
835 if (status != FWK_SUCCESS) {
836 return status;
837 }
838
839 if ((protocol_api->get_scmi_protocol_id == NULL) ||
840 (protocol_api->message_handler == NULL)) {
841 return FWK_E_DATA;
842 }
843 status = protocol_api->get_scmi_protocol_id(
844 protocol_req->id, &scmi_protocol_id);
845 if (status != FWK_SUCCESS) {
846 return status;
847 }
848
849 scmi_ctx.scmi_protocol_requester_id_to_idx[scmi_protocol_id] =
850 (uint8_t)(protocol_idx);
851 protocol_req->message_handler = protocol_api->message_handler;
852 }
853
854 #ifdef BUILD_HAS_MOD_RESOURCE_PERMS
855 status = fwk_module_bind(
856 FWK_ID_MODULE(FWK_MODULE_IDX_RESOURCE_PERMS),
857 FWK_ID_API(FWK_MODULE_IDX_RESOURCE_PERMS, MOD_RES_PERM_RESOURCE_PERMS),
858 &scmi_ctx.res_perms_api);
859 if (status != FWK_SUCCESS) {
860 return status;
861 }
862 #endif
863
864 return FWK_SUCCESS;
865 }
866
scmi_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)867 static int scmi_process_bind_request(fwk_id_t source_id, fwk_id_t target_id,
868 fwk_id_t api_id, const void **api)
869 {
870 unsigned int api_idx;
871 struct scmi_service_ctx *ctx;
872 enum mod_scmi_api_idx api_id_type;
873
874 api_idx = fwk_id_get_api_idx(api_id);
875
876 api_id_type = (enum mod_scmi_api_idx)api_idx;
877
878 switch (api_id_type) {
879 case MOD_SCMI_API_IDX_PROTOCOL:
880 if (!fwk_id_is_type(target_id, FWK_ID_TYPE_MODULE)) {
881 return FWK_E_SUPPORT;
882 }
883
884 if (scmi_ctx.protocol_count >= scmi_ctx.config->protocol_count_max) {
885 return FWK_E_NOMEM;
886 }
887
888 scmi_ctx.protocol_table[PROTOCOL_TABLE_RESERVED_ENTRIES_COUNT +
889 scmi_ctx.protocol_count++].id = source_id;
890 *api = &scmi_from_protocol_api;
891 break;
892
893 case MOD_SCMI_API_IDX_PROTOCOL_REQ:
894 if (!fwk_id_is_type(target_id, FWK_ID_TYPE_MODULE)) {
895 return FWK_E_SUPPORT;
896 }
897 if (scmi_ctx.protocol_requester_count >=
898 scmi_ctx.config->protocol_requester_count_max) {
899 return FWK_E_PARAM;
900 }
901
902 scmi_ctx.protocol_requester_table[scmi_ctx.protocol_requester_count++]
903 .id = source_id;
904 *api = &scmi_from_protocol_req_api;
905 break;
906
907 case MOD_SCMI_API_IDX_TRANSPORT:
908 if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT)) {
909 return FWK_E_SUPPORT;
910 }
911
912 ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(target_id)];
913 if (!fwk_id_is_equal(source_id, ctx->transport_id)) {
914 return FWK_E_ACCESS;
915 }
916
917 *api = &scmi_from_transport_api;
918 break;
919
920 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
921 case MOD_SCMI_API_IDX_NOTIFICATION:
922 if (!fwk_id_is_type(target_id, FWK_ID_TYPE_MODULE)) {
923 return FWK_E_SUPPORT;
924 }
925
926 *api = &mod_scmi_notif_api;
927 break;
928 #endif
929
930 default:
931 return FWK_E_SUPPORT;
932 };
933
934 return FWK_SUCCESS;
935 }
936
scmi_process_event(const struct fwk_event * event,struct fwk_event * resp)937 static int scmi_process_event(const struct fwk_event *event,
938 struct fwk_event *resp)
939 {
940 int status;
941 struct scmi_service_ctx *ctx;
942 const struct mod_scmi_to_transport_api *transport_api;
943 fwk_id_t transport_id;
944 uint32_t message_header;
945 const void *payload;
946 size_t payload_size;
947 unsigned int protocol_idx;
948 #ifndef BUILD_HAS_MOD_RESOURCE_PERMS
949 enum scmi_agent_type agent_type;
950 unsigned int agent_id;
951 unsigned int dis_protocol_list_psci_index;
952 #endif
953 struct scmi_protocol *protocol;
954 const char *service_name;
955 const char *message_type_name;
956
957 ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(event->target_id)];
958 transport_api = ctx->transport_api;
959 transport_id = ctx->transport_id;
960
961 service_name = fwk_module_get_element_name(event->target_id);
962
963 status = transport_api->get_message_header(transport_id, &message_header);
964 if (status != FWK_SUCCESS) {
965 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
966 FWK_LOG_ERR("[SCMI] %s: Unable to read message header", service_name);
967 #else
968 (void)service_name;
969 #endif
970 return status;
971 }
972
973 status = transport_api->get_payload(transport_id, &payload, &payload_size);
974 if (status != FWK_SUCCESS) {
975 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
976 FWK_LOG_ERR("[SCMI] %s: Unable to read message payload", service_name);
977 #else
978 (void)service_name;
979 #endif
980 return status;
981 }
982
983 ctx->scmi_protocol_id = read_protocol_id(message_header);
984 ctx->scmi_message_id = read_message_id(message_header);
985 ctx->scmi_message_type =
986 (enum mod_scmi_message_type)read_message_type(message_header);
987 ctx->scmi_token = read_token(message_header);
988 message_type_name = get_message_type_str(ctx);
989
990 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_DEBUG
991 FWK_LOG_DEBUG(
992 "[SCMI] %s: %s [%" PRIu16 " (0x%x:0x%x)] was received",
993 service_name,
994 message_type_name,
995 ctx->scmi_token,
996 ctx->scmi_protocol_id,
997 ctx->scmi_message_id);
998 #else
999 (void)service_name;
1000 (void)message_type_name;
1001 #endif
1002 if (ctx->config->scmi_entity_role == MOD_SCMI_ROLE_PLATFORM) {
1003 protocol_idx = scmi_ctx.scmi_protocol_id_to_idx[ctx->scmi_protocol_id];
1004 if (protocol_idx == 0) {
1005 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
1006 FWK_LOG_ERR(
1007 "[SCMI] %s: %s [%" PRIu16
1008 "(0x%x:0x%x)] requested an unsupported protocol",
1009 service_name,
1010 message_type_name,
1011 ctx->scmi_token,
1012 ctx->scmi_protocol_id,
1013 ctx->scmi_message_id);
1014 #endif
1015 status = ctx->respond(
1016 transport_id,
1017 &(int32_t){ SCMI_NOT_SUPPORTED },
1018 sizeof(int32_t));
1019 if (status != FWK_SUCCESS) {
1020 FWK_LOG_DEBUG("[SCMI] %s @%d", __func__, __LINE__);
1021 }
1022 return FWK_SUCCESS;
1023 }
1024
1025 #ifndef BUILD_HAS_MOD_RESOURCE_PERMS
1026 status = get_agent_id(event->target_id, &agent_id);
1027 if (status != FWK_SUCCESS) {
1028 # if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
1029 FWK_LOG_ERR("[SCMI] %s: Unable to get agent id", service_name);
1030 # endif
1031 return status;
1032 }
1033
1034 status = get_agent_type(agent_id, &agent_type);
1035 if (status != FWK_SUCCESS) {
1036 # if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
1037 FWK_LOG_ERR("[SCMI] %s: Unable to get agent type", service_name);
1038 # endif
1039 return status;
1040 }
1041
1042 if (agent_type == SCMI_AGENT_TYPE_PSCI) {
1043 /*
1044 * check if the current protocol is within the disabled protocols
1045 * list for PSCI agent.
1046 */
1047 for (dis_protocol_list_psci_index = 0; dis_protocol_list_psci_index <
1048 scmi_ctx.config->dis_protocol_count_psci;
1049 dis_protocol_list_psci_index++) {
1050 if (ctx->scmi_protocol_id ==
1051 scmi_ctx.config
1052 ->dis_protocol_list_psci[dis_protocol_list_psci_index]) {
1053 # if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
1054 FWK_LOG_ERR(
1055 "[SCMI] %s: %s [%" PRIu16
1056 "(0x%x:0x%x)] requested a denied protocol",
1057 service_name,
1058 message_type_name,
1059 ctx->scmi_token,
1060 ctx->scmi_protocol_id,
1061 ctx->scmi_message_id);
1062 # endif
1063 status = ctx->respond(
1064 transport_id, &(int32_t){ SCMI_DENIED }, sizeof(int32_t));
1065 if (status != FWK_SUCCESS) {
1066 FWK_LOG_DEBUG("[SCMI] %s @%d", __func__, __LINE__);
1067 }
1068 return FWK_SUCCESS;
1069 }
1070 }
1071 }
1072 #endif
1073 protocol = &scmi_ctx.protocol_table[protocol_idx];
1074 } else if (ctx->config->scmi_entity_role == MOD_SCMI_ROLE_AGENT) {
1075 protocol_idx =
1076 scmi_ctx.scmi_protocol_requester_id_to_idx[ctx->scmi_protocol_id];
1077 protocol = &scmi_ctx.protocol_requester_table[protocol_idx];
1078 } else {
1079 return FWK_E_INIT;
1080 }
1081
1082 status = protocol->message_handler(
1083 protocol->id,
1084 event->target_id,
1085 payload,
1086 payload_size,
1087 ctx->scmi_message_id);
1088
1089 if (status != FWK_SUCCESS) {
1090 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
1091 FWK_LOG_ERR(
1092 "[SCMI] %s: %s [%" PRIu16 " (0x%x:0x%x)] handler error (%s)",
1093 service_name,
1094 message_type_name,
1095 ctx->scmi_token,
1096 ctx->scmi_protocol_id,
1097 ctx->scmi_message_id,
1098 fwk_status_str(status));
1099 #endif
1100 return FWK_SUCCESS;
1101 }
1102
1103 /*
1104 * If we are receiving a command response, we need to set the transport
1105 * layer that we already received the response and are free
1106 */
1107 if (ctx->config->scmi_entity_role == MOD_SCMI_ROLE_AGENT) {
1108 status =
1109 ctx->transport_api->release_transport_channel_lock(transport_id);
1110 if (status != FWK_SUCCESS) {
1111 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
1112 FWK_LOG_ERR(
1113 "[SCMI] %s: %s [%" PRIu16
1114 " (0x%x:0x%x)] confirm reception error (%s)",
1115 service_name,
1116 message_type_name,
1117 ctx->scmi_token,
1118 ctx->scmi_protocol_id,
1119 ctx->scmi_message_id,
1120 fwk_status_str(status));
1121 #endif
1122 return FWK_SUCCESS;
1123 }
1124 }
1125
1126 return FWK_SUCCESS;
1127 }
1128
scmi_start(fwk_id_t id)1129 static int scmi_start(fwk_id_t id)
1130 {
1131 #ifdef BUILD_HAS_NOTIFICATION
1132 const struct mod_scmi_service_config *config;
1133 unsigned int notifications_sent;
1134
1135 if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
1136 # ifdef BUILD_HAS_SCMI_NOTIFICATIONS
1137 /* scmi_ctx.protocol_count + 1 to include Base protocol */
1138 scmi_ctx.scmi_notif_subscribers = fwk_mm_calloc(
1139 scmi_ctx.protocol_count + 1,
1140 sizeof(struct scmi_notification_subscribers));
1141 # endif
1142
1143 return FWK_SUCCESS;
1144 }
1145
1146 config = fwk_module_get_data(id);
1147
1148 if (fwk_id_is_equal(config->transport_notification_init_id, FWK_ID_NONE)) {
1149 /* Notify that the service is immediately ready */
1150 struct fwk_event scmi_services_initialized_notification = {
1151 .id = mod_scmi_notification_id_initialized,
1152 .source_id = id,
1153 };
1154
1155 return fwk_notification_notify(&scmi_services_initialized_notification,
1156 ¬ifications_sent);
1157 }
1158
1159 return fwk_notification_subscribe(config->transport_notification_init_id,
1160 config->transport_id,
1161 id);
1162 #else
1163 return FWK_SUCCESS;
1164 #endif
1165 }
1166
1167 #ifdef BUILD_HAS_NOTIFICATION
scmi_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)1168 static int scmi_process_notification(const struct fwk_event *event,
1169 struct fwk_event *resp_event)
1170 {
1171 const struct mod_scmi_service_config *config;
1172 unsigned int notifications_sent;
1173
1174 fwk_assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_ELEMENT));
1175
1176 config = fwk_module_get_data(event->target_id);
1177 if (config == NULL) {
1178 return FWK_E_PARAM;
1179 }
1180
1181 fwk_assert(fwk_id_is_equal(event->id,
1182 config->transport_notification_init_id));
1183
1184 /* Notify that this service is ready */
1185 struct fwk_event scmi_services_initialized_notification = {
1186 .id = mod_scmi_notification_id_initialized,
1187 .source_id = FWK_ID_NONE
1188 };
1189
1190 return fwk_notification_notify(&scmi_services_initialized_notification,
1191 ¬ifications_sent);
1192 }
1193 #endif
1194
1195 /* SCMI module definition */
1196 const struct fwk_module module_scmi = {
1197 .api_count = (unsigned int)MOD_SCMI_API_IDX_COUNT,
1198 .event_count = 1,
1199 #ifdef BUILD_HAS_NOTIFICATION
1200 .notification_count = (unsigned int)MOD_SCMI_NOTIFICATION_IDX_COUNT,
1201 #endif
1202 .type = FWK_MODULE_TYPE_SERVICE,
1203 .init = scmi_init,
1204 .element_init = scmi_service_init,
1205 .bind = scmi_bind,
1206 .start = scmi_start,
1207 .process_bind_request = scmi_process_bind_request,
1208 .process_event = scmi_process_event,
1209 #ifdef BUILD_HAS_NOTIFICATION
1210 .process_notification = scmi_process_notification,
1211 #endif
1212 };
1213