1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2019-2023, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     SCMI Reset Domain management protocol support.
9  */
10 
11 #include <internal/scmi_reset_domain.h>
12 
13 #include <mod_reset_domain.h>
14 #include <mod_scmi.h>
15 #include <mod_scmi_reset_domain.h>
16 
17 #include <fwk_assert.h>
18 #include <fwk_attributes.h>
19 #include <fwk_log.h>
20 #include <fwk_macros.h>
21 #include <fwk_mm.h>
22 #include <fwk_module.h>
23 #include <fwk_module_idx.h>
24 #include <fwk_notification.h>
25 #include <fwk_status.h>
26 
27 #include <string.h>
28 
29 #ifdef BUILD_HAS_MOD_RESOURCE_PERMS
30 #    include <mod_resource_perms.h>
31 #endif
32 
33 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
34 #    define MOD_SCMI_RESET_DOMAIN_NOTIFICATION_COUNT 1
35 #endif
36 
37 struct scmi_rd_ctx {
38     /*! SCMI Reset Module Configuration */
39     const struct mod_scmi_reset_domain_config *config;
40 
41     /* Bound module APIs */
42     const struct mod_scmi_from_protocol_api *scmi_api;
43     const struct mod_reset_domain_api *reset_api;
44 
45     /*! Number of reset domains available on platform */
46     uint8_t plat_reset_domain_count;
47 
48 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
49     /*! SCMI notification_id */
50     fwk_id_t notification_id;
51 
52     /* SCMI notification API */
53     const struct mod_scmi_notification_api *scmi_notification_api;
54 #endif
55 
56 #ifdef BUILD_HAS_MOD_RESOURCE_PERMS
57     /* SCMI Resource Permissions API */
58     const struct mod_res_permissions_api *res_perms_api;
59 #endif
60 };
61 
62 static int protocol_version_handler(fwk_id_t service_id,
63                                     const uint32_t *payload);
64 
65 static int protocol_attributes_handler(fwk_id_t service_id,
66                                        const uint32_t *payload);
67 static int protocol_message_attributes_handler(fwk_id_t service_id,
68                                                const uint32_t *payload);
69 static int reset_attributes_handler(fwk_id_t service_id,
70                                     const uint32_t *payload);
71 static int reset_request_handler(fwk_id_t service_id,
72                                  const uint32_t *payload);
73 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
74 static int reset_notify_handler(fwk_id_t service_id,
75                                 const uint32_t *payload);
76 #endif
77 
78 /*
79  * Internal variables
80  */
81 
82 static struct scmi_rd_ctx scmi_rd_ctx;
83 
84 static int (*msg_handler_table[])(fwk_id_t, const uint32_t *) = {
85     [MOD_SCMI_PROTOCOL_VERSION] = protocol_version_handler,
86     [MOD_SCMI_PROTOCOL_ATTRIBUTES] = protocol_attributes_handler,
87     [MOD_SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] =
88          protocol_message_attributes_handler,
89     [MOD_SCMI_RESET_DOMAIN_ATTRIBUTES] = reset_attributes_handler,
90     [MOD_SCMI_RESET_REQUEST] = reset_request_handler,
91 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
92     [MOD_SCMI_RESET_NOTIFY] = reset_notify_handler,
93 #endif
94 };
95 
96 static unsigned int payload_size_table[] = {
97     [MOD_SCMI_PROTOCOL_VERSION] = 0,
98     [MOD_SCMI_PROTOCOL_ATTRIBUTES] = 0,
99     [MOD_SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] =
100         (unsigned int)sizeof(struct scmi_protocol_message_attributes_a2p),
101     [MOD_SCMI_RESET_DOMAIN_ATTRIBUTES] =
102         (unsigned int)sizeof(struct scmi_reset_domain_attributes_a2p),
103     [MOD_SCMI_RESET_REQUEST] =
104         (unsigned int)sizeof(struct scmi_reset_domain_request_a2p),
105 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
106     [MOD_SCMI_RESET_NOTIFY] = sizeof(struct scmi_reset_domain_notify_a2p),
107 #endif
108 };
109 
110 /*
111  * Reset domain management protocol implementation
112  */
113 
protocol_version_handler(fwk_id_t service_id,const uint32_t * payload)114 static int protocol_version_handler(fwk_id_t service_id,
115                                     const uint32_t *payload)
116 {
117     struct scmi_protocol_version_p2a outmsg = {
118         .status = (int32_t)SCMI_SUCCESS,
119         .version = SCMI_PROTOCOL_VERSION_RESET_DOMAIN,
120     };
121 
122     return scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, sizeof(outmsg));
123 }
124 
protocol_attributes_handler(fwk_id_t service_id,const uint32_t * payload)125 static int protocol_attributes_handler(fwk_id_t service_id,
126                                        const uint32_t *payload)
127 {
128     struct scmi_reset_domain_protocol_attributes_p2a outmsg = {
129         .status = (int32_t)SCMI_SUCCESS,
130     };
131     int status = 0;
132     unsigned int agent_id = 0;
133 
134     status = scmi_rd_ctx.scmi_api->get_agent_id(service_id, &agent_id);
135     if (status != FWK_SUCCESS)
136         return status;
137 
138     if (agent_id >= scmi_rd_ctx.config->agent_count)
139         return FWK_E_PARAM;
140 
141     outmsg.attributes = scmi_rd_ctx.config->
142                             agent_table[agent_id].agent_domain_count;
143 
144     return scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, sizeof(outmsg));
145 }
146 
protocol_message_attributes_handler(fwk_id_t service_id,const uint32_t * payload)147 static int protocol_message_attributes_handler(fwk_id_t service_id,
148                                                const uint32_t *payload)
149 {
150     struct scmi_protocol_message_attributes_p2a outmsg = {
151         .status = (int32_t)SCMI_NOT_FOUND,
152     };
153     size_t outmsg_size = sizeof(outmsg.status);
154     struct scmi_protocol_message_attributes_a2p params = { 0 };
155 
156     params = *(const struct scmi_protocol_message_attributes_a2p *)payload;
157 
158     if ((params.message_id < FWK_ARRAY_SIZE(msg_handler_table)) &&
159         (msg_handler_table[params.message_id] != NULL)) {
160         outmsg.status = (int32_t)SCMI_SUCCESS;
161         outmsg_size = sizeof(outmsg);
162     }
163 
164     return scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, outmsg_size);
165 }
166 
167 /*
168  * Given a service identifier, retrieve a agent identifier
169  */
get_agent_id(fwk_id_t service_id,unsigned int * agent_id)170 static int get_agent_id(fwk_id_t service_id, unsigned int* agent_id)
171 {
172     int status;
173 
174     status = scmi_rd_ctx.scmi_api->get_agent_id(service_id, agent_id);
175     if (status != FWK_SUCCESS)
176         return status;
177 
178     if (*agent_id >= scmi_rd_ctx.config->agent_count)
179         return FWK_E_PARAM;
180 
181     return FWK_SUCCESS;
182 }
183 
184 /*
185  * Given a service identifier, retrieve a pointer to its agent's
186  * \c mod_scmi_reset_domain_agent structure within the agent table.
187  */
get_agent_entry(fwk_id_t service_id,const struct mod_scmi_reset_domain_agent ** agent)188 static int get_agent_entry(fwk_id_t service_id,
189                            const struct mod_scmi_reset_domain_agent **agent)
190 {
191     int status = 0;
192     unsigned int agent_id = 0;
193 
194     status = get_agent_id(service_id, &agent_id);
195     if (status != FWK_SUCCESS)
196         return status;
197 
198     *agent = &scmi_rd_ctx.config->agent_table[agent_id];
199 
200     return FWK_SUCCESS;
201 }
202 
get_reset_device(fwk_id_t service_id,unsigned int domain_id,const struct mod_scmi_reset_domain_device ** device)203 static int get_reset_device(fwk_id_t service_id,
204                             unsigned int domain_id,
205                             const struct mod_scmi_reset_domain_device **device)
206 {
207     int status;
208     const struct mod_scmi_reset_domain_agent *agent_entry = NULL;
209 
210     status = get_agent_entry(service_id, &agent_entry);
211     if (status != FWK_SUCCESS)
212         return status;
213 
214     if (domain_id >= agent_entry->agent_domain_count)
215         return FWK_E_RANGE;
216 
217     *device = &agent_entry->device_table[domain_id];
218 
219     fwk_assert(fwk_module_is_valid_element_id((*device)->element_id));
220 
221     if (!fwk_module_is_valid_element_id((*device)->element_id))
222         return FWK_E_PANIC;
223 
224     return FWK_SUCCESS;
225 }
226 
227 /*
228  * Reset Request Policy Handler
229  */
scmi_reset_domain_reset_request_policy(enum mod_scmi_reset_domain_policy_status * policy_status,enum mod_reset_domain_mode * mode,uint32_t * reset_state,uint32_t agent_id,uint32_t domain_id)230 FWK_WEAK int scmi_reset_domain_reset_request_policy(
231     enum mod_scmi_reset_domain_policy_status *policy_status,
232     enum mod_reset_domain_mode *mode,
233     uint32_t *reset_state,
234     uint32_t agent_id,
235     uint32_t domain_id)
236 {
237     *policy_status = MOD_SCMI_RESET_DOMAIN_EXECUTE_MESSAGE_HANDLER;
238 
239     return FWK_SUCCESS;
240 }
241 
242 
reset_attributes_handler(fwk_id_t service_id,const uint32_t * payload)243 static int reset_attributes_handler(fwk_id_t service_id,
244                                     const uint32_t *payload)
245 {
246     const struct mod_scmi_reset_domain_device *reset_device = NULL;
247     struct mod_reset_domain_dev_config *reset_dev_config = NULL;
248     struct scmi_reset_domain_attributes_a2p params = { 0 };
249     struct scmi_reset_domain_attributes_p2a outmsg = {
250         .status = (int32_t)SCMI_GENERIC_ERROR,
251     };
252     size_t outmsg_size = sizeof(outmsg.status);
253     int status = FWK_SUCCESS;
254     int respond_status;
255 
256     params = *(const struct scmi_reset_domain_attributes_a2p *)payload;
257 
258     status = get_reset_device(service_id, params.domain_id, &reset_device);
259     if (status != FWK_SUCCESS) {
260         outmsg.status = (int32_t)SCMI_NOT_FOUND;
261         goto exit;
262     }
263 
264     reset_dev_config = (struct mod_reset_domain_dev_config *)
265                            fwk_module_get_data(reset_device->element_id);
266     /*
267      * Currently: no support for async reset.
268      */
269     outmsg.flags &= (uint32_t)~SCMI_RESET_DOMAIN_ATTR_ASYNC;
270 
271     if (reset_dev_config->capabilities & MOD_RESET_DOMAIN_CAP_NOTIFICATION)
272         outmsg.flags |= (uint32_t)SCMI_RESET_DOMAIN_ATTR_NOTIF;
273 
274     outmsg.latency = reset_dev_config->latency;
275 
276     strncpy(
277         (char *)outmsg.name,
278         fwk_module_get_element_name(reset_device->element_id),
279         sizeof(outmsg.name) - 1);
280 
281     outmsg.status = (int32_t)SCMI_SUCCESS;
282     outmsg_size = sizeof(outmsg);
283 
284 exit:
285     respond_status =
286         scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, outmsg_size);
287 
288     if (respond_status != FWK_SUCCESS) {
289         FWK_LOG_DEBUG("[SCMI-RESET] %s @%d", __func__, __LINE__);
290     }
291 
292     return status;
293 }
294 
reset_request_handler(fwk_id_t service_id,const uint32_t * payload)295 static int reset_request_handler(fwk_id_t service_id,
296                                  const uint32_t *payload)
297 {
298     int status, respond_status;
299     unsigned int agent_id;
300     struct mod_reset_domain_dev_config *reset_dev_config;
301     struct scmi_reset_domain_request_a2p params = { 0 };
302     struct scmi_reset_domain_request_p2a outmsg = {
303         .status = (int32_t)SCMI_NOT_FOUND
304     };
305     enum mod_reset_domain_mode mode = MOD_RESET_DOMAIN_MODE_EXPLICIT_DEASSERT;
306 
307     size_t outmsg_size = sizeof(outmsg.status);
308     const struct mod_reset_domain_api *reset_api = scmi_rd_ctx.reset_api;
309     const struct mod_scmi_reset_domain_device *reset_device = NULL;
310     enum mod_scmi_reset_domain_policy_status policy_status;
311     uint32_t reset_state;
312 
313     params = *(const struct scmi_reset_domain_request_a2p *)payload;
314 
315     if ((params.flags & ~SCMI_RESET_DOMAIN_FLAGS_MASK) != 0) {
316         status = FWK_SUCCESS;
317         outmsg.status = (int32_t)SCMI_INVALID_PARAMETERS;
318         goto exit;
319     }
320 
321     /**
322      * Verify that the reset state ID is 0 when the reset
323      * state type is Architectural.
324      */
325     if (((params.reset_state & SCMI_RESET_DOMAIN_RESET_STATE_TYPE_MASK) == 0) &&
326         ((params.reset_state & SCMI_RESET_DOMAIN_RESET_STATE_ID_MASK) != 0)) {
327         status = FWK_SUCCESS;
328         outmsg.status = (int32_t)SCMI_INVALID_PARAMETERS;
329         goto exit;
330     }
331 
332     status = scmi_rd_ctx.scmi_api->get_agent_id(service_id, &agent_id);
333     if (status != FWK_SUCCESS)
334         goto exit;
335 
336     if (params.domain_id >= scmi_rd_ctx.plat_reset_domain_count) {
337         status = FWK_E_PARAM;
338         goto exit;
339     }
340 
341     status = get_reset_device(service_id, params.domain_id, &reset_device);
342     if (status != FWK_SUCCESS)
343         goto exit;
344 
345     reset_dev_config = (struct mod_reset_domain_dev_config *)
346                        fwk_module_get_data(reset_device->element_id);
347 
348     /* Check if explicit assert is requested.
349      * Note, valid request in flags
350      *       b000 Explicit de-assert request.
351      *       b001 Auto Reset request.
352      *       b010 Explicit reset request.
353      *       b101 Auto Reset Async.
354      */
355     if (!(params.flags & SCMI_RESET_DOMAIN_AUTO)) {
356         /* If auto reset is not requested then check if device supports explicit
357          * assert/de-assert reset.
358          */
359         if (!(reset_dev_config->modes &
360             (MOD_RESET_DOMAIN_MODE_EXPLICIT_ASSERT |
361             MOD_RESET_DOMAIN_MODE_EXPLICIT_DEASSERT))) {
362             outmsg.status = (int32_t)SCMI_NOT_SUPPORTED;
363             goto exit;
364         } else {
365            if (params.flags & SCMI_RESET_DOMAIN_EXPLICIT)
366                mode = MOD_RESET_DOMAIN_MODE_EXPLICIT_ASSERT;
367         }
368     } else {
369         mode = (enum mod_reset_domain_mode)SCMI_RESET_DOMAIN_AUTO;
370     }
371 
372     /* Handle async reset request. */
373     if (params.flags & SCMI_RESET_DOMAIN_ASYNC) {
374         /* Async reset request is valid only in auto reset mode
375          */
376         if (!(params.flags & SCMI_RESET_DOMAIN_AUTO)) {
377             outmsg.status = (int32_t)SCMI_INVALID_PARAMETERS;
378             goto exit;
379         }
380 
381         /* Return not supported as associated device does not support
382          * Async reset.
383          */
384         if (!(reset_dev_config->modes &
385             MOD_RESET_DOMAIN_MODE_AUTO_RESET_ASYNC)) {
386             outmsg.status = (int32_t)SCMI_NOT_SUPPORTED;
387             goto exit;
388         } else {
389             mode |= MOD_RESET_DOMAIN_MODE_AUTO_RESET_ASYNC;
390         }
391     }
392 
393     reset_state = params.reset_state;
394     status = scmi_reset_domain_reset_request_policy(&policy_status,
395         &mode, &reset_state, agent_id, params.domain_id);
396 
397     if (status != FWK_SUCCESS) {
398         outmsg.status = (int32_t)SCMI_GENERIC_ERROR;
399         goto exit;
400     }
401     if (policy_status == MOD_SCMI_RESET_DOMAIN_SKIP_MESSAGE_HANDLER) {
402         outmsg.status = (int32_t)SCMI_SUCCESS;
403         goto exit;
404     }
405 
406     outmsg.status = (int32_t)SCMI_NOT_SUPPORTED;
407     status = reset_api->set_reset_state(reset_device->element_id,
408                                         mode,
409                                         reset_state,
410                                         (uintptr_t)agent_id);
411     if (status != FWK_SUCCESS) {
412         if (status == FWK_E_STATE)
413             outmsg.status = (int32_t)SCMI_HARDWARE_ERROR;
414         goto exit;
415     }
416 
417     outmsg.status = (int32_t)SCMI_SUCCESS;
418     outmsg_size = sizeof(outmsg);
419 
420 exit:
421     respond_status =
422         scmi_rd_ctx.scmi_api->respond(service_id, &outmsg, outmsg_size);
423 
424     if (respond_status != FWK_SUCCESS) {
425         FWK_LOG_DEBUG("[SCMI-RESET] %s @%d", __func__, __LINE__);
426     }
427 
428     return status;
429 }
430 
431 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
reset_notify_handler(fwk_id_t service_id,const uint32_t * payload)432 static int reset_notify_handler(fwk_id_t service_id,
433                                 const uint32_t *payload)
434 {
435     unsigned int agent_id;
436     int status, respond_status;
437     unsigned int domain_id;
438     const struct scmi_reset_domain_notify_a2p *parameters;
439     struct scmi_reset_domain_notify_p2a outmsg = {
440         .status = SCMI_GENERIC_ERROR,
441     };
442 
443     status = get_agent_id(service_id, &agent_id);
444     if (status != FWK_SUCCESS)
445         goto exit;
446 
447     parameters = (const struct scmi_reset_domain_notify_a2p *)payload;
448 
449     domain_id = parameters->domain_id;
450     if (domain_id >= scmi_rd_ctx.config->
451         agent_table[agent_id].agent_domain_count) {
452         status = FWK_SUCCESS;
453         outmsg.status = SCMI_NOT_FOUND;
454         goto exit;
455     }
456 
457     if ((parameters->notify_enable & ~SCMI_RESET_DOMAIN_DO_NOTIFY) != 0) {
458         status = FWK_SUCCESS;
459         outmsg.status = SCMI_INVALID_PARAMETERS;
460         goto exit;
461     }
462 
463     if (parameters->notify_enable)
464         scmi_rd_ctx.scmi_notification_api->scmi_notification_add_subscriber(
465             MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN,
466             domain_id,
467             MOD_SCMI_RESET_NOTIFY,
468             service_id);
469     else
470         scmi_rd_ctx.scmi_notification_api->scmi_notification_remove_subscriber(
471             MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN,
472             agent_id,
473             domain_id,
474             MOD_SCMI_RESET_NOTIFY);
475 
476     outmsg.status = SCMI_SUCCESS;
477 
478 exit:
479     respond_status = scmi_rd_ctx.scmi_api->respond(
480         service_id,
481         &outmsg,
482         (outmsg.status == SCMI_SUCCESS) ? sizeof(outmsg) :
483                                           sizeof(outmsg.status));
484 
485     if (respond_status != FWK_SUCCESS) {
486         FWK_LOG_DEBUG("[SCMI-RESET] %s @%d", __func__, __LINE__);
487     }
488 
489     return status;
490 }
491 
scmi_reset_issued_notify(uint32_t domain_id,uint32_t reset_state,uintptr_t cookie)492 static void scmi_reset_issued_notify(uint32_t domain_id,
493                                      uint32_t reset_state,
494                                      uintptr_t cookie)
495 {
496     struct scmi_reset_domain_issued_p2a reset_issued = {
497          .agent_id = (uint32_t)cookie
498     };
499 
500     reset_issued.domain_id = domain_id;
501     reset_issued.reset_state = reset_state;
502 
503     scmi_rd_ctx.scmi_notification_api->scmi_notification_notify(
504         MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN,
505         MOD_SCMI_RESET_NOTIFY,
506         MOD_SCMI_RESET_ISSUED,
507         &reset_issued,
508         sizeof(reset_issued));
509 }
510 #endif
511 
512 /*
513  * SCMI Resource Permissions handler
514  */
515 #ifdef BUILD_HAS_MOD_RESOURCE_PERMS
get_reset_domain_id(const uint32_t * payload)516 static unsigned int get_reset_domain_id(const uint32_t *payload)
517 {
518     struct scmi_reset_domain_request_a2p *params;
519 
520     params = (struct scmi_reset_domain_request_a2p *)payload;
521     return params->domain_id;
522 }
523 
scmi_reset_domain_permissions_handler(fwk_id_t service_id,const uint32_t * payload,size_t payload_size,unsigned int message_id)524 static int scmi_reset_domain_permissions_handler(
525     fwk_id_t service_id,
526     const uint32_t *payload,
527     size_t payload_size,
528     unsigned int message_id)
529 {
530     enum mod_res_perms_permissions perms;
531     unsigned int agent_id, domain_id;
532     int status;
533 
534     status = scmi_rd_ctx.scmi_api->get_agent_id(service_id, &agent_id);
535     if (status != FWK_SUCCESS)
536         return FWK_E_ACCESS;
537 
538     if (message_id < 3) {
539         perms = scmi_rd_ctx.res_perms_api->agent_has_protocol_permission(
540             agent_id, MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN);
541         if (perms == MOD_RES_PERMS_ACCESS_ALLOWED)
542             return FWK_SUCCESS;
543         return FWK_E_ACCESS;
544     }
545 
546     domain_id = get_reset_domain_id(payload);
547 
548     perms = scmi_rd_ctx.res_perms_api->agent_has_resource_permission(
549         agent_id, MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN, message_id, domain_id);
550 
551     if (perms == MOD_RES_PERMS_ACCESS_ALLOWED)
552         return FWK_SUCCESS;
553     else
554         return FWK_E_ACCESS;
555 }
556 #endif
557 
558 /*
559  * SCMI module -> SCMI reset module interface
560  */
scmi_reset_get_scmi_protocol_id(fwk_id_t protocol_id,uint8_t * scmi_protocol_id)561 static int scmi_reset_get_scmi_protocol_id(fwk_id_t protocol_id,
562                                            uint8_t *scmi_protocol_id)
563 {
564     *scmi_protocol_id = MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN;
565 
566     return FWK_SUCCESS;
567 }
568 
scmi_reset_message_handler(fwk_id_t protocol_id,fwk_id_t service_id,const uint32_t * payload,size_t payload_size,unsigned int message_id)569 static int scmi_reset_message_handler(fwk_id_t protocol_id,
570                                       fwk_id_t service_id,
571                                       const uint32_t *payload,
572                                       size_t payload_size,
573                                       unsigned int message_id)
574 {
575     int32_t return_value;
576 
577     static_assert(FWK_ARRAY_SIZE(msg_handler_table) ==
578                   FWK_ARRAY_SIZE(payload_size_table),
579                   "[SCMI] reset domain protocol table sizes not consistent");
580 
581     fwk_assert(payload != NULL);
582 
583     if (message_id >= FWK_ARRAY_SIZE(msg_handler_table)) {
584         return_value = (int32_t)SCMI_NOT_FOUND;
585         goto error;
586     }
587 
588     if (payload_size != payload_size_table[message_id]) {
589         return_value = (int32_t)SCMI_PROTOCOL_ERROR;
590         goto error;
591     }
592 
593 #ifdef BUILD_HAS_MOD_RESOURCE_PERMS
594     if (scmi_reset_domain_permissions_handler(
595             service_id, payload, payload_size, message_id) != FWK_SUCCESS) {
596         return_value = SCMI_DENIED;
597         goto error;
598     }
599 #endif
600 
601     return msg_handler_table[message_id](service_id, payload);
602 
603 error:
604     return scmi_rd_ctx.scmi_api->respond(
605         service_id, &return_value, sizeof(return_value));
606 }
607 
608 static struct mod_scmi_to_protocol_api scmi_reset_mod_scmi_to_protocol_api = {
609     .get_scmi_protocol_id = scmi_reset_get_scmi_protocol_id,
610     .message_handler = scmi_reset_message_handler
611 };
612 
613 /*
614  * Framework handlers
615  */
616 
scmi_reset_init(fwk_id_t module_id,unsigned int element_count,const void * data)617 static int scmi_reset_init(fwk_id_t module_id,
618                            unsigned int element_count,
619                            const void *data)
620 {
621     const struct mod_scmi_reset_domain_config *config;
622 
623     config = (const struct mod_scmi_reset_domain_config *)data;
624 
625     if ((config == NULL) || (config->agent_table == NULL))
626         return FWK_E_PARAM;
627 
628     scmi_rd_ctx.config = config;
629 
630     return FWK_SUCCESS;
631 }
632 
633 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
scmi_reset_init_notifications(void)634 static int scmi_reset_init_notifications(void)
635 {
636     fwk_assert(scmi_rd_ctx.config->agent_count != 0u);
637 
638     return scmi_rd_ctx.scmi_notification_api->scmi_notification_init(
639         MOD_SCMI_PROTOCOL_ID_RESET_DOMAIN,
640         scmi_rd_ctx.config->agent_count,
641         scmi_rd_ctx.plat_reset_domain_count,
642         MOD_SCMI_RESET_DOMAIN_NOTIFICATION_COUNT);
643 }
644 #endif
645 
scmi_reset_bind(fwk_id_t id,unsigned int round)646 static int scmi_reset_bind(fwk_id_t id, unsigned int round)
647 {
648     int status;
649     int rst_dom_count;
650 
651     if (round == 1)
652         return FWK_SUCCESS;
653 
654     status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_SCMI),
655                              FWK_ID_API(FWK_MODULE_IDX_SCMI,
656                                         MOD_SCMI_API_IDX_PROTOCOL),
657                              &scmi_rd_ctx.scmi_api);
658     if (status != FWK_SUCCESS)
659         return status;
660 
661 #ifdef BUILD_HAS_SCMI_NOTIFICATIONS
662     status = fwk_module_bind(
663         FWK_ID_MODULE(FWK_MODULE_IDX_SCMI),
664         FWK_ID_API(FWK_MODULE_IDX_SCMI, MOD_SCMI_API_IDX_NOTIFICATION),
665         &scmi_rd_ctx.scmi_notification_api);
666     if (status != FWK_SUCCESS)
667         return status;
668 #endif
669 
670     rst_dom_count = fwk_module_get_element_count(
671         FWK_ID_MODULE(FWK_MODULE_IDX_RESET_DOMAIN));
672 
673     if (rst_dom_count <= 0) {
674         return FWK_E_SUPPORT;
675     } else {
676         scmi_rd_ctx.plat_reset_domain_count = (uint8_t)rst_dom_count;
677     }
678 
679 #ifdef BUILD_HAS_MOD_RESOURCE_PERMS
680     status = fwk_module_bind(
681         FWK_ID_MODULE(FWK_MODULE_IDX_RESOURCE_PERMS),
682         FWK_ID_API(FWK_MODULE_IDX_RESOURCE_PERMS, MOD_RES_PERM_RESOURCE_PERMS),
683         &scmi_rd_ctx.res_perms_api);
684     if (status != FWK_SUCCESS)
685         return status;
686 #endif
687 
688     return fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_RESET_DOMAIN),
689                            FWK_ID_API(FWK_MODULE_IDX_RESET_DOMAIN, 0),
690                            &scmi_rd_ctx.reset_api);
691 }
692 
scmi_reset_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)693 static int scmi_reset_process_bind_request(fwk_id_t source_id,
694                                            fwk_id_t target_id,
695                                            fwk_id_t api_id, const void **api)
696 {
697     switch ((enum scmi_reset_domain_api_idx)fwk_id_get_api_idx(api_id)) {
698     case MOD_SCMI_RESET_DOMAIN_PROTOCOL_API:
699         *api = &scmi_reset_mod_scmi_to_protocol_api;
700         break;
701 
702     default:
703         return FWK_E_ACCESS;
704     }
705 
706     return FWK_SUCCESS;
707 }
708 
709 #if defined(BUILD_HAS_SCMI_NOTIFICATIONS) && defined(BUILD_HAS_NOTIFICATION)
scmi_reset_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)710 static int scmi_reset_process_notification(const struct fwk_event *event,
711     struct fwk_event *resp_event)
712 {
713     struct mod_reset_domain_notification_event_params* params =
714         (struct mod_reset_domain_notification_event_params*)event->params;
715 
716     if (!fwk_id_is_equal(scmi_rd_ctx.notification_id,
717                          event->id))
718         return FWK_E_SUPPORT;
719 
720     scmi_reset_issued_notify(params->domain_id, params->reset_state,
721                              params->cookie);
722 
723     return FWK_SUCCESS;
724 }
725 
scmi_reset_start(fwk_id_t id)726 static int scmi_reset_start(fwk_id_t id)
727 {
728     int status;
729     struct mod_reset_domain_config *config;
730     config = (struct mod_reset_domain_config*)fwk_module_get_data(
731         FWK_ID_MODULE(FWK_MODULE_IDX_RESET_DOMAIN)
732         );
733 
734     scmi_rd_ctx.notification_id = config->notification_id;
735 
736     status = scmi_reset_init_notifications();
737     if (status != FWK_SUCCESS)
738         return status;
739 
740     return fwk_notification_subscribe(
741         scmi_rd_ctx.notification_id,
742         FWK_ID_MODULE(FWK_MODULE_IDX_RESET_DOMAIN),
743         id);
744 }
745 #endif
746 
747 /* SCMI Reset Domain Management Protocol Definition */
748 const struct fwk_module module_scmi_reset_domain = {
749     .api_count = (unsigned int)MOD_SCMI_RESET_DOMAIN_API_COUNT,
750     .type = FWK_MODULE_TYPE_PROTOCOL,
751     .init = scmi_reset_init,
752     .bind = scmi_reset_bind,
753     .process_bind_request = scmi_reset_process_bind_request,
754 #if defined(BUILD_HAS_SCMI_NOTIFICATIONS) && defined(BUILD_HAS_NOTIFICATION)
755     .start = scmi_reset_start,
756     .process_notification = scmi_reset_process_notification,
757 #endif
758 };
759