| From 06c3e612cb0927d783f115077d83ed97841c5668 Mon Sep 17 00:00:00 2001 |
| From: Emekcan Aras <emekcan.aras@arm.com> |
| Date: Tue, 14 Nov 2023 14:43:44 +0000 |
| Subject: [PATCH] plat: corstone1000: fix synchronization issue on openamp notification |
| |
| This fixes a race that is observed rarely in the FVP. It occurs in FVP |
| when Secure Enclave sends the notication ack in openamp, and then reset the access |
| request which resets the mhu registers before received by the SE-proxy-sp in the |
| host processort. This solution introduces polling on the status register of |
| mhu until the notificaiton is read by the host processor. (Inspired by |
| signal_and_wait_for_signal function in mhu_wrapper_v2_x.c in trusted-firmware-m |
| https://git.trustedfirmware.org/TF-M/trusted-firmware-m.git/tree/platform/ext/target/arm/rss/common/native_drivers/mhu_wrapper_v2_x.c#n61) |
| |
| Signed-off-by: Emekcan Aras <emekcan.aras@arm.com> |
| Upstream-Status: Pending [Not submitted to upstream yet] |
| --- |
| components/messaging/openamp/sp/openamp_mhu.c | 9 ++++++++- |
| platform/drivers/arm/mhu_driver/mhu_v2.h | 18 ++++++++++++++++++ |
| platform/drivers/arm/mhu_driver/mhu_v2_x.c | 17 +++++++++++++++++ |
| 3 files changed, 43 insertions(+), 1 deletion(-) |
| |
| diff --git a/components/messaging/openamp/sp/openamp_mhu.c b/components/messaging/openamp/sp/openamp_mhu.c |
| index bafba3e3..0700b8b9 100644 |
| --- a/components/messaging/openamp/sp/openamp_mhu.c |
| +++ b/components/messaging/openamp/sp/openamp_mhu.c |
| @@ -85,7 +85,7 @@ int openamp_mhu_notify_peer(struct openamp_messenger *openamp) |
| struct mhu_v2_x_dev_t *tx_dev; |
| enum mhu_v2_x_error_t ret; |
| struct openamp_mhu *mhu; |
| - uint32_t access_ready; |
| + uint32_t access_ready,val; |
| |
| if (!openamp->transport) { |
| EMSG("openamp: mhu: notify transport not initialized"); |
| @@ -116,6 +116,13 @@ int openamp_mhu_notify_peer(struct openamp_messenger *openamp) |
| return -EPROTO; |
| } |
| |
| + do { |
| + ret = mhu_v2_x_channel_poll(tx_dev, MHU_V_2_NOTIFY_CHANNEL, &val); |
| + if (ret != MHU_V_2_X_ERR_NONE) { |
| + break; |
| + } |
| + } while (val != 0); |
| + |
| ret = mhu_v2_x_reset_access_request(tx_dev); |
| if (ret != MHU_V_2_X_ERR_NONE) { |
| EMSG("openamp: mhu: failed reset access request"); |
| diff --git a/platform/drivers/arm/mhu_driver/mhu_v2.h b/platform/drivers/arm/mhu_driver/mhu_v2.h |
| index 26b3a5d6..2b4d6fcb 100644 |
| --- a/platform/drivers/arm/mhu_driver/mhu_v2.h |
| +++ b/platform/drivers/arm/mhu_driver/mhu_v2.h |
| @@ -384,6 +384,24 @@ enum mhu_v2_x_error_t mhu_v2_x_interrupt_clear( |
| enum mhu_v2_x_error_t mhu_v2_1_get_ch_interrupt_num( |
| const struct mhu_v2_x_dev_t *dev, uint32_t *channel); |
| |
| + |
| +/** |
| + * \brief Polls sender channel status. |
| + * |
| + * \param[in] dev MHU device struct \ref mhu_v2_x_dev_t |
| + * \param[in] channel Channel to poll the status of. |
| + * \param[out] value Pointer to variable that will store the value. |
| + * |
| + * Polls sender channel status. |
| + * |
| + * \return Returns mhu_v2_x_error_t error code |
| + * |
| + * \note This function doesn't check if dev is NULL. |
| + * \note This function doesn't check if channel is implemented. |
| + */ |
| +enum mhu_v2_x_error_t mhu_v2_x_channel_poll(const struct mhu_v2_x_dev_t *dev, |
| + uint32_t channel, uint32_t *value); |
| + |
| #ifdef __cplusplus |
| } |
| #endif |
| diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x.c b/platform/drivers/arm/mhu_driver/mhu_v2_x.c |
| index d7e70efa..022e287a 100644 |
| --- a/platform/drivers/arm/mhu_driver/mhu_v2_x.c |
| +++ b/platform/drivers/arm/mhu_driver/mhu_v2_x.c |
| @@ -600,3 +600,20 @@ enum mhu_v2_x_error_t mhu_v2_1_get_ch_interrupt_num( |
| |
| return MHU_V_2_X_ERR_GENERAL; |
| } |
| + |
| +enum mhu_v2_x_error_t mhu_v2_x_channel_poll(const struct mhu_v2_x_dev_t *dev, |
| + uint32_t channel, uint32_t *value) |
| +{ |
| + union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base; |
| + |
| + if ( !(dev->is_initialized) ) { |
| + return MHU_V_2_X_ERR_NOT_INIT; |
| + } |
| + |
| + if (dev->frame == MHU_V2_X_SENDER_FRAME) { |
| + *value = (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_st; |
| + return MHU_V_2_X_ERR_NONE; |
| + } else { |
| + return MHU_V_2_X_ERR_INVALID_ARG; |
| + } |
| +} |
| -- |
| 2.25.1 |
| |