diff --git a/module/scmi/include/mod_scmi.h b/module/scmi/include/mod_scmi.h index 955a8f9377a43b7ea23ca7225f7661c495db0203..700a22d2e256f39a822be7aab8bdf75d54a5637e 100644 --- a/module/scmi/include/mod_scmi.h +++ b/module/scmi/include/mod_scmi.h @@ -248,6 +248,23 @@ struct mod_scmi_to_transport_api { * \brief Transport entity API to SCMI module API. */ struct mod_scmi_from_transport_api { + /*! + * \brief Signal to a SCMI service that a incoming message for it has + * incorrect length and payload size and so the incoming message has been + * dropped. + * + * \note Subscribed SCMI service should call the respond API to free the + * channel. + * + * \param service_id service identifier. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The service_id parameter is invalid. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*signal_error)(fwk_id_t service_id); + /*! * \brief Signal to a service that a message is incoming. * diff --git a/module/scmi/src/mod_scmi.c b/module/scmi/src/mod_scmi.c index cd9d2f719a7c5f3a5c4e71d037d6e987c2942311..4c81e5be2c7d0b7bfd2f7703e775859dc070d526 100644 --- a/module/scmi/src/mod_scmi.c +++ b/module/scmi/src/mod_scmi.c @@ -153,6 +153,17 @@ static uint16_t read_token(uint32_t message_header) /* * Transport entity -> SCMI module */ +static int signal_error(fwk_id_t service_id) +{ + fwk_id_t transport_id; + struct scmi_service_ctx *ctx; + + ctx = &scmi_ctx.service_ctx_table[fwk_id_get_element_idx(service_id)]; + transport_id = ctx->transport_id; + + return ctx->respond(transport_id, &(int32_t){SCMI_PROTOCOL_ERROR}, + sizeof(int32_t)); +} static int signal_message(fwk_id_t service_id) { @@ -166,7 +177,8 @@ static int signal_message(fwk_id_t service_id) } static const struct mod_scmi_from_transport_api mod_scmi_from_transport_api = { - .signal_message = signal_message + .signal_error = signal_error, + .signal_message = signal_message, }; /* diff --git a/module/smt/include/mod_smt.h b/module/smt/include/mod_smt.h index 4ecc02379677cc103a59d7906bd01522bc671c52..893f96e1cbbeeb5a9970ce85b9f5c75dd2b668c6 100644 --- a/module/smt/include/mod_smt.h +++ b/module/smt/include/mod_smt.h @@ -76,6 +76,12 @@ struct mod_smt_channel_config { /*! Identifier of the power domain that this channel depends on */ fwk_id_t pd_source_id; + + /*! Identifier of the API to bind to signal message/error for Non SCMI + * channels. This field is irrelevant for SMT channels that are used for + * SCMI messages + */ + fwk_id_t signal_api_id; }; /*! @@ -113,12 +119,149 @@ struct mod_smt_driver_input_api { int (*signal_message)(fwk_id_t channel_id); }; +/*! + * \brief SMT transport API. + * SMT transport API for Non SCMI Shared Memory Transport messages + */ +struct mod_smt_to_transport_api { + /*! + * \brief Check whether a channel is secure or non-secure. + * + * \param channel_id Channel identifier. + * \param[out] secure Channel security state. True if the channel + * is secure, or false if it is non-secure. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The channel_id parameter is invalid. + * \retval FWK_E_PARAM The secure parameter is NULL. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*get_secure)(fwk_id_t channel_id, bool *secure); + + /*! + * \brief Get the maximum permitted payload size of a channel. + * + * \param channel_id Channel identifier. + * \param[out] size Maximum payload size in bytes. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The channel_id parameter is invalid. + * \retval FWK_E_PARAM The size parameter is NULL. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*get_max_payload_size)(fwk_id_t channel_id, size_t *size); + + /*! + * \brief Get the message header from a channel. + * + * \param channel_id Channel identifier. + * \param[out] message_header Pointer to the message header. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The channel_id parameter is invalid. + * \retval FWK_E_PARAM The message_header parameter is NULL. + * \retval FWK_E_ACCESS No message is available to read. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*get_message_header)(fwk_id_t channel_id, uint32_t *message_header); + + /*! + * \brief Get the message payload from a channel. + * + * \param channel_id Channel identifier. + * \param[out] payload Pointer to the payload. + * \param[out] size Payload size. May be NULL, in which case the + * parameter should be ignored. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The channel_id parameter is invalid. + * \retval FWK_E_PARAM The payload parameter is NULL. + * \retval FWK_E_ACCESS No message is available to read. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*get_payload)(fwk_id_t channel_id, const void **payload, + size_t *size); + + /*! + * \brief Write part of a payload to a channel. + * + * \param channel_id Channel identifier. + * \param offset Offset to begin writing at. + * \param payload Payload data to write. + * \param size Size of the payload data. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The payload parameter is NULL. + * \retval FWK_E_PARAM The offset and size provided are not within the + * bounds of the payload area. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*write_payload)(fwk_id_t channel_id, size_t offset, + const void *payload, size_t size); + + /*! + * \brief Respond to a message on a channel. + * + * \param channel_id Channel identifier. + * \param payload Payload data to write, or NULL if a payload has already + * been written. + * \param size Size of the payload source. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The channel_id parameter is invalid. + * \retval FWK_E_PARAM The size parameter is less than the size of one + * payload entry. + * \retval FWK_E_ACCESS No message is available to respond to. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*respond)(fwk_id_t channel_id, const void *payload, size_t size); +}; + +/*! + * SMT API to signal incoming messages/error to subscribers of Non SCMI + * shared memory services. + */ +struct mod_smt_from_transport_api { + /*! + * \brief Signal to a service that a incoming message for it has incorrect + * length and payload size and so the incoming message has been dropped. + * + * \param service_id service identifier. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The service_id parameter is invalid. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*signal_error)(fwk_id_t service_id); + + /*! + * \brief Signal to a service that a message is incoming. + * + * \param service_id Service identifier. + * + * \retval FWK_SUCCESS The operation succeeded. + * \retval FWK_E_PARAM The channel_id parameter is invalid. + * \retval FWK_E_PARAM The secure parameter is NULL. + * \return One of the standard error codes for implementation-defined + * errors. + */ + int (*signal_message)(fwk_id_t service_id); +}; + /*! * \brief Type of the interfaces exposed by the power domain module. */ enum mod_smt_api_idx { MOD_SMT_API_IDX_DRIVER_INPUT, MOD_SMT_API_IDX_SCMI_TRANSPORT, + MOD_SMT_API_IDX_TO_TRANSPORT, MOD_SMT_API_IDX_COUNT, }; diff --git a/module/smt/src/mod_smt.c b/module/smt/src/mod_smt.c index 77bc357293f835520fb5cb7f82aed9ee3133e895..c6fbfee507d5867b4f17179ade648238ff8e5326 100644 --- a/module/smt/src/mod_smt.c +++ b/module/smt/src/mod_smt.c @@ -45,14 +45,20 @@ struct smt_channel_ctx { /* Driver entity identifier */ fwk_id_t driver_id; - /* SCMI module service bound to the channel */ - fwk_id_t scmi_service_id; + /* service bound to the channel */ + fwk_id_t service_id; /* Driver API */ struct mod_smt_driver_api *driver_api; - /* SCMI service API */ - struct mod_scmi_from_transport_api *scmi_api; + /* service APIs to signal incoming messages or errors */ + union signal_apis { + struct mod_scmi_from_transport_api *scmi_api; + struct mod_smt_from_transport_api *signal_api; + } smt_signal; + + /* Flag indicating the service bound to the channel is of type SCMI */ + bool is_scmi_channel; /* Flag indicating the mailbox is ready */ bool smt_mailbox_ready; @@ -227,6 +233,18 @@ static const struct mod_scmi_to_transport_api smt_mod_scmi_to_transport_api = { .respond = smt_respond, }; +/* + * The following API is intended to be used for NON SCMI messages. + */ +static const struct mod_smt_to_transport_api smt_mod_smt_to_transport_api = { + .get_secure = smt_get_secure, + .get_max_payload_size = smt_get_max_payload_size, + .get_message_header = smt_get_message_header, + .get_payload = smt_get_payload, + .write_payload = smt_write_payload, + .respond = smt_respond, +}; + /* * Driver handler API */ @@ -276,17 +294,29 @@ static int smt_slave_handler(struct smt_channel_ctx *channel_ctx) > channel_ctx->max_payload_size)) { out->status |= MOD_SMT_MAILBOX_STATUS_ERROR_MASK; - return smt_respond(channel_ctx->id, &(int32_t){SCMI_PROTOCOL_ERROR}, - sizeof(int32_t)); + + if (channel_ctx->is_scmi_channel) + status = channel_ctx->smt_signal.scmi_api->signal_error( + channel_ctx->service_id); + else + status = channel_ctx->smt_signal.signal_api->signal_error( + channel_ctx->service_id); + + return status; } /* Copy payload from shared memory to read buffer */ payload_size = in->length - sizeof(in->message_header); memcpy(in->payload, memory->payload, payload_size); - /* Let SCMI handle the message */ - status = - channel_ctx->scmi_api->signal_message(channel_ctx->scmi_service_id); + /* Let subscribed service handle the message */ + if (channel_ctx->is_scmi_channel) + status = channel_ctx->smt_signal.scmi_api->signal_message( + channel_ctx->service_id); + else + status = channel_ctx->smt_signal.signal_api->signal_message( + channel_ctx->service_id); + if (status != FWK_SUCCESS) return FWK_E_HANDLER; @@ -388,9 +418,20 @@ static int smt_bind(fwk_id_t id, unsigned int round) if ((round == 1) && fwk_id_is_type(id, FWK_ID_TYPE_ELEMENT)) { channel_ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(id)]; - status = fwk_module_bind(channel_ctx->scmi_service_id, - FWK_ID_API(FWK_MODULE_IDX_SCMI, MOD_SCMI_API_IDX_TRANSPORT), - &channel_ctx->scmi_api); + + if (fwk_id_is_equal(fwk_id_build_module_id(channel_ctx->service_id), + fwk_module_id_scmi)) { + status = fwk_module_bind(channel_ctx->service_id, + FWK_ID_API(FWK_MODULE_IDX_SCMI, + MOD_SCMI_API_IDX_TRANSPORT), + &channel_ctx->smt_signal.scmi_api); + channel_ctx->is_scmi_channel = true; + } else { + status = fwk_module_bind(channel_ctx->service_id, + channel_ctx->config->signal_api_id, + &channel_ctx->smt_signal.signal_api); + channel_ctx->is_scmi_channel = false; + } if (status != FWK_SUCCESS) return status; } @@ -445,7 +486,13 @@ static int smt_process_bind_request(fwk_id_t source_id, case MOD_SMT_API_IDX_SCMI_TRANSPORT: /* SCMI transport API */ *api = &smt_mod_scmi_to_transport_api; - channel_ctx->scmi_service_id = source_id; + channel_ctx->service_id = source_id; + break; + + case MOD_SMT_API_IDX_TO_TRANSPORT: + /* SMT transport API */ + *api = &smt_mod_smt_to_transport_api; + channel_ctx->service_id = source_id; break; default: