1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2022-2024, Linaro Limited and Contributors. All rights
4  * reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * Description:
9  *     msg buffer device driver.
10  */
11 
12 #include <stdbool.h>
13 #include <string.h>
14 #include <fwk_assert.h>
15 #include <fwk_interrupt.h>
16 #include <fwk_log.h>
17 #include <fwk_mm.h>
18 #include <fwk_macros.h>
19 #include <fwk_module.h>
20 #include <fwk_module_idx.h>
21 #include <fwk_status.h>
22 #include <mod_scmi.h>
23 #include <mod_msg_smt.h>
24 
25 struct __attribute((packed)) mod_msg_smt_memory {
26     uint32_t message_header;
27     uint32_t payload[];
28 };
29 
30 struct smt_channel_ctx {
31     /* Channel identifier */
32     fwk_id_t id;
33 
34     /* Channel configuration data */
35     struct mod_msg_smt_channel_config *config;
36 
37     /* Channel read and write cache memory areas */
38     struct mod_msg_smt_memory *in;
39     struct mod_msg_smt_memory *out;
40     size_t in_len;
41     size_t out_len;
42 
43     /* Message processing in progrees flag */
44     volatile bool locked;
45 
46     /* Maximum payload size of the channel */
47     size_t max_payload_size;
48 
49     /* Driver entity identifier */
50     fwk_id_t driver_id;
51 
52     /* SCMI module service bound to the channel */
53     fwk_id_t scmi_service_id;
54 
55     /* Driver API */
56     struct mod_msg_smt_driver_ouput_api *driver_api;
57 
58     /* SCMI service API */
59     struct mod_scmi_from_transport_api *scmi_api;
60 
61     /* Flag indicating the mailbox is ready */
62     bool msg_smt_mailbox_ready;
63 };
64 
65 struct smt_ctx {
66     /* Table of channel contexts */
67     struct smt_channel_ctx *channel_ctx_table;
68 
69     /* Number of channels */
70     unsigned int channel_count;
71 };
72 
73 static struct smt_ctx smt_ctx;
74 
75 /*
76  * SCMI Transport API
77  */
smt_get_secure(fwk_id_t channel_id,bool * secure)78 static int smt_get_secure(fwk_id_t channel_id, bool *secure)
79 {
80     if (secure == NULL) {
81         fwk_assert(false);
82         return FWK_E_PARAM;
83     }
84 
85     /* No msg mailbox is considered secure */
86     *secure = 0;
87 
88     return FWK_SUCCESS;
89 }
90 
smt_get_max_payload_size(fwk_id_t channel_id,size_t * size)91 static int smt_get_max_payload_size(fwk_id_t channel_id, size_t *size)
92 {
93     struct smt_channel_ctx *channel_ctx;
94 
95     if (size == NULL) {
96         fwk_assert(false);
97         return FWK_E_PARAM;
98     }
99 
100     channel_ctx =
101         &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
102 
103     *size = channel_ctx->max_payload_size;
104 
105     return FWK_SUCCESS;
106 }
107 
smt_get_message_header(fwk_id_t channel_id,uint32_t * header)108 static int smt_get_message_header(fwk_id_t channel_id, uint32_t *header)
109 {
110     struct smt_channel_ctx *channel_ctx;
111 
112     if (header == NULL) {
113         fwk_assert(false);
114         return FWK_E_PARAM;
115     }
116 
117     channel_ctx =
118         &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
119 
120     if (!channel_ctx->locked) {
121         return FWK_E_ACCESS;
122     }
123 
124     *header = channel_ctx->in->message_header;
125 
126     return FWK_SUCCESS;
127 }
128 
smt_get_payload(fwk_id_t channel_id,const void ** payload,size_t * size)129 static int smt_get_payload(fwk_id_t channel_id,
130                            const void **payload,
131                            size_t *size)
132 {
133     struct smt_channel_ctx *channel_ctx;
134 
135     if (payload == NULL) {
136         fwk_assert(false);
137         return FWK_E_PARAM;
138     }
139 
140     channel_ctx =
141         &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
142 
143     if (!channel_ctx->locked)
144         return FWK_E_ACCESS;
145 
146     *payload = channel_ctx->in->payload;
147 
148     if (size != NULL) {
149         *size = channel_ctx->in_len -
150             sizeof(channel_ctx->in->message_header);
151     }
152 
153     return FWK_SUCCESS;
154 }
155 
smt_write_payload(fwk_id_t channel_id,size_t offset,const void * payload,size_t size)156 static int smt_write_payload(fwk_id_t channel_id,
157                              size_t offset,
158                              const void *payload,
159                              size_t size)
160 {
161     struct smt_channel_ctx *channel_ctx;
162 
163     channel_ctx =
164         &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
165 
166     if ((payload == NULL)                         ||
167         (offset  > channel_ctx->max_payload_size) ||
168         (size > channel_ctx->max_payload_size)    ||
169         ((offset + size) > channel_ctx->max_payload_size)) {
170 
171         fwk_assert(false);
172         return FWK_E_PARAM;
173     }
174 
175     if (!channel_ctx->locked)
176         return FWK_E_ACCESS;
177 
178     memcpy(((uint8_t*)channel_ctx->out->payload) + offset, payload, size);
179 
180     return FWK_SUCCESS;
181 }
182 
smt_respond(fwk_id_t channel_id,const void * payload,size_t size)183 static int smt_respond(fwk_id_t channel_id, const void *payload, size_t size)
184 {
185     struct smt_channel_ctx *channel_ctx;
186     struct mod_msg_smt_memory *memory;
187 
188     channel_ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
189     memory = ((struct mod_msg_smt_memory *) channel_ctx->out);
190 
191     /* Copy the payload from either the write buffer or the payload parameter */
192     if (payload) {
193         memcpy(memory->payload, payload, size);
194     }
195 
196     channel_ctx->locked = false;
197 
198     channel_ctx->out_len = sizeof(memory->message_header) + size;
199 
200     channel_ctx->driver_api->raise_notification(channel_ctx->driver_id, channel_ctx->out_len);
201 
202     return FWK_SUCCESS;
203 }
204 
smt_transmit(fwk_id_t channel_id,uint32_t message_header,const void * payload,size_t size,bool request_ack_by_interrupt)205 static int smt_transmit(fwk_id_t channel_id, uint32_t message_header,
206     const void *payload, size_t size, bool request_ack_by_interrupt)
207 {
208     struct smt_channel_ctx *channel_ctx;
209     struct mod_msg_smt_memory *memory;
210 
211     if (payload == NULL) {
212         return FWK_E_DATA;
213     }
214 
215     channel_ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
216     memory = ((struct mod_msg_smt_memory *) channel_ctx->out);
217 
218     if (!channel_ctx->locked) {
219         return FWK_SUCCESS;
220     }
221 
222     memory->message_header = message_header;
223 
224     /* Copy the payload */
225     memcpy(memory->payload, payload, size);
226 
227     channel_ctx->out_len = sizeof(memory->message_header) + size;
228 
229     /* Release the channel */
230     channel_ctx->locked = false;
231 
232     /* Notify the agent */
233     channel_ctx->driver_api->raise_notification(channel_ctx->driver_id, channel_ctx->out_len);
234 
235     return FWK_SUCCESS;
236 }
237 
238 static const struct mod_scmi_to_transport_api smt_mod_scmi_to_transport_api = {
239     .get_secure = smt_get_secure,
240     .get_max_payload_size = smt_get_max_payload_size,
241     .get_message_header = smt_get_message_header,
242     .get_payload = smt_get_payload,
243     .write_payload = smt_write_payload,
244     .respond = smt_respond,
245     .transmit = smt_transmit,
246 };
247 
248 /*
249  * Driver handler API
250  */
smt_requester_handler(struct smt_channel_ctx * channel_ctx)251 static int smt_requester_handler(struct smt_channel_ctx *channel_ctx)
252 {
253     int status;
254 
255     /* Commit to sending a response */
256     channel_ctx->locked = true;
257 
258     /* Prepare answer and copy message header (Payload not copied) */
259     channel_ctx->out->message_header = channel_ctx->in->message_header;
260 
261     /* Let SCMI handle the message */
262     status =
263         channel_ctx->scmi_api->signal_message(channel_ctx->scmi_service_id);
264     if (status != FWK_SUCCESS) {
265         return FWK_E_HANDLER;
266     }
267 
268     return FWK_SUCCESS;
269 }
270 
smt_completer_handler(struct smt_channel_ctx * channel_ctx)271 static int smt_completer_handler(struct smt_channel_ctx *channel_ctx)
272 {
273     /* Commit to sending a response */
274     channel_ctx->locked = true;
275 
276     return FWK_SUCCESS;
277 }
278 
msg_signal_message(fwk_id_t channel_id,void * msg_in,size_t in_len,void * msg_out,size_t out_len)279 static int msg_signal_message(fwk_id_t channel_id, void *msg_in, size_t in_len, void *msg_out, size_t out_len)
280 {
281     struct smt_channel_ctx *channel_ctx;
282 
283     channel_ctx =
284         &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
285 
286     if (!channel_ctx->msg_smt_mailbox_ready) {
287         /* Discard any message in the mailbox when not ready */
288         FWK_LOG_ERR("[MSG_SMT] Message not valid");
289 
290         return FWK_SUCCESS;
291     }
292 
293     /* Check if we are already processing */
294     if (channel_ctx->locked) {
295         return FWK_E_STATE;
296     }
297 
298     /* Save input/output buffers */
299     channel_ctx->in = (struct mod_msg_smt_memory *)msg_in ;
300     channel_ctx->in_len = in_len;
301     channel_ctx->out = (struct mod_msg_smt_memory *)msg_out;
302     channel_ctx->out_len = out_len;
303 
304     switch (channel_ctx->config->type) {
305     case MOD_MSG_SMT_CHANNEL_TYPE_REQUESTER:
306         return smt_requester_handler(channel_ctx);
307     case MOD_MSG_SMT_CHANNEL_TYPE_COMPLETER:
308         return smt_completer_handler(channel_ctx);
309     default:
310         /* Invalid config */
311         fwk_assert(false);
312         break;
313     }
314 
315     return FWK_SUCCESS;
316 }
317 
318 static const struct mod_msg_smt_driver_input_api driver_input_api = {
319     .signal_message = msg_signal_message,
320 };
321 
322 /*
323  * Framework API
324  */
msg_init(fwk_id_t module_id,unsigned int element_count,const void * data)325 static int msg_init(fwk_id_t module_id, unsigned int element_count,
326                        const void *data)
327 {
328 
329     if (element_count == 0) {
330         return FWK_E_PARAM;
331     }
332 
333     smt_ctx.channel_ctx_table = fwk_mm_calloc(element_count,
334                                               sizeof(*smt_ctx.channel_ctx_table));
335     if (smt_ctx.channel_ctx_table == NULL) {
336         return FWK_E_NOMEM;
337     }
338 
339     smt_ctx.channel_count = element_count;
340 
341     return FWK_SUCCESS;
342 }
343 
msg_channel_init(fwk_id_t channel_id,unsigned int slot_count,const void * data)344 static int msg_channel_init(fwk_id_t channel_id, unsigned int slot_count,
345                             const void *data)
346 {
347     size_t elt_idx = fwk_id_get_element_idx(channel_id);
348     struct smt_channel_ctx *channel_ctx = &smt_ctx.channel_ctx_table[elt_idx];
349 
350     channel_ctx->config = (struct mod_msg_smt_channel_config*)data;
351 
352     /* Validate channel config */
353     if (channel_ctx->config->type >= MOD_MSG_SMT_CHANNEL_TYPE_COUNT) {
354         fwk_assert(false);
355         return FWK_E_DATA;
356     }
357 
358     channel_ctx->in = NULL;
359     channel_ctx->in_len = 0;
360     channel_ctx->out = NULL;
361     channel_ctx->out_len = 0;
362 
363     channel_ctx->max_payload_size = channel_ctx->config->mailbox_size -
364         sizeof(struct mod_msg_smt_memory);
365 
366     channel_ctx->msg_smt_mailbox_ready = true;
367 
368     return FWK_SUCCESS;
369 }
370 
msg_bind(fwk_id_t id,unsigned int round)371 static int msg_bind(fwk_id_t id, unsigned int round)
372 {
373     int status;
374     struct smt_channel_ctx *channel_ctx;
375 
376     if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
377         return FWK_SUCCESS;
378     }
379 
380     channel_ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(id)];
381 
382     if (round == 0) {
383 
384         status = fwk_module_bind(channel_ctx->config->driver_id,
385                                  channel_ctx->config->driver_api_id,
386                                  &channel_ctx->driver_api);
387         if (status != FWK_SUCCESS) {
388             return status;
389         }
390 
391         channel_ctx->driver_id = channel_ctx->config->driver_id;
392 
393     } else if (round == 1) {
394 
395         status = fwk_module_bind(channel_ctx->scmi_service_id,
396                                  FWK_ID_API(FWK_MODULE_IDX_SCMI, MOD_SCMI_API_IDX_TRANSPORT),
397                                  &channel_ctx->scmi_api);
398         if (status != FWK_SUCCESS) {
399             return status;
400         }
401     }
402 
403     return FWK_SUCCESS;
404 }
405 
msg_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)406 static int msg_process_bind_request(fwk_id_t source_id,
407                                        fwk_id_t target_id,
408                                        fwk_id_t api_id,
409                                        const void **api)
410 {
411     struct smt_channel_ctx *channel_ctx = NULL;
412     size_t elt_idx;
413 
414     /* Only bind to a channel (not the whole module) */
415     if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT)) {
416         return FWK_E_ACCESS;
417     }
418 
419     elt_idx = fwk_id_get_element_idx(target_id);
420     if (elt_idx >= smt_ctx.channel_count) {
421         return FWK_E_ACCESS;
422     }
423 
424     channel_ctx = &smt_ctx.channel_ctx_table[elt_idx];
425 
426     switch (fwk_id_get_api_idx(api_id)) {
427     case MOD_MSG_SMT_API_IDX_DRIVER_INPUT:
428         /* Driver input API */
429 
430        /*
431          * Make sure that the element that is trying to bind to us is the
432          * same element that we previously bound to.
433          *
434          * NOTE: We bound to an element but a sub-element should be binding
435          * back to us. This means we cannot use fwk_id_is_equal() because
436          * the ids have different types. For now we compare the indicies
437          * manually.
438          */
439         if (fwk_id_get_module_idx(channel_ctx->driver_id) ==
440             fwk_id_get_module_idx(source_id) &&
441             fwk_id_get_element_idx(channel_ctx->driver_id) ==
442             fwk_id_get_element_idx(source_id)) {
443             *api = &driver_input_api;
444        } else {
445             /* A module that we did not bind to is trying to bind to us */
446             fwk_assert(false);
447             return FWK_E_ACCESS;
448         }
449         break;
450 
451     case MOD_MSG_SMT_API_IDX_SCMI_TRANSPORT:
452         /* SCMI transport API */
453         *api = &smt_mod_scmi_to_transport_api;
454         channel_ctx->scmi_service_id = source_id;
455         break;
456 
457     default:
458         /* Invalid API */
459         fwk_assert(false);
460         return FWK_E_PARAM;
461     }
462 
463     return FWK_SUCCESS;
464 }
465 
msg_start(fwk_id_t id)466 static int msg_start(fwk_id_t id)
467 {
468     return FWK_SUCCESS;
469 }
470 
471 const struct fwk_module module_msg_smt = {
472     .type = FWK_MODULE_TYPE_SERVICE,
473     .api_count = MOD_MSG_SMT_API_IDX_COUNT,
474     .init = msg_init,
475     .element_init = msg_channel_init,
476     .bind = msg_bind,
477     .start = msg_start,
478     .process_bind_request = msg_process_bind_request,
479 };
480