From 79ca991e8d2e9e9dff1588ce6e777c1a2e48ab3e Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Thu, 31 Oct 2024 16:00:14 +0100 Subject: [PATCH] ipc: add cache flushing and invalidation for IPC data This patch addresses an issue with incorrect IPC responses due to the lack of cache flushing and invalidation on secondary cores. The following changes have been made: 1. Added cache writeback for IPC message data in `ipc_msg_send` when the current core is not the primary core. 2. Added cache invalidation for IPC message data in `ipc_prepare_to_send` before writing to the mailbox. These changes ensure that the IPC data is correctly synchronized between cores. Signed-off-by: Tomasz Leman --- src/include/sof/ipc/msg.h | 1 + src/ipc/ipc-common.c | 9 +++++++++ src/ipc/ipc4/handler.c | 19 ++++++++++++++++--- src/library_manager/lib_notification.c | 1 + 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/include/sof/ipc/msg.h b/src/include/sof/ipc/msg.h index a24fa3711ad0..20dfaf6eb519 100644 --- a/src/include/sof/ipc/msg.h +++ b/src/include/sof/ipc/msg.h @@ -35,6 +35,7 @@ struct ipc_msg { uint32_t extension; /* extension specific to platform */ uint32_t tx_size; /* payload size in bytes */ void *tx_data; /* pointer to payload data */ + bool is_shared; /* the message is shared cross-core */ struct list_item list; }; diff --git a/src/ipc/ipc-common.c b/src/ipc/ipc-common.c index bf94e0481ec0..7714a4650150 100644 --- a/src/ipc/ipc-common.c +++ b/src/ipc/ipc-common.c @@ -214,6 +214,15 @@ void ipc_msg_send(struct ipc_msg *msg, void *data, bool high_priority) msg->tx_data != data) { ret = memcpy_s(msg->tx_data, msg->tx_size, data, msg->tx_size); assert(!ret); + if (!cpu_is_primary(cpu_get_id())) { + /* Write back data to memory to maintain coherence between cores. + * The response was prepared on a secondary core but will be sent + * to the host from the primary core. + */ + dcache_writeback_region((__sparse_force void __sparse_cache *)msg->tx_data, + msg->tx_size); + msg->is_shared = true; + } } /* diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c index 3d7e82645a4f..6645d6fd08e5 100644 --- a/src/ipc/ipc4/handler.c +++ b/src/ipc/ipc4/handler.c @@ -72,9 +72,9 @@ struct ipc4_msg_data { static struct ipc4_msg_data msg_data; /* fw sends a fw ipc message to send the status of the last host ipc message */ -static struct ipc_msg msg_reply = {0, 0, 0, 0, LIST_INIT(msg_reply.list)}; +static struct ipc_msg msg_reply = {0, 0, 0, 0, false, LIST_INIT(msg_reply.list)}; -static struct ipc_msg msg_notify = {0, 0, 0, 0, LIST_INIT(msg_notify.list)}; +static struct ipc_msg msg_notify = {0, 0, 0, 0, false, LIST_INIT(msg_notify.list)}; #if CONFIG_LIBRARY static inline struct ipc4_message_request *ipc4_get_message_request(void) @@ -1494,14 +1494,25 @@ struct ipc_cmd_hdr *ipc_prepare_to_send(const struct ipc_msg *msg) msg_data.msg_out.pri = msg->header; msg_data.msg_out.ext = msg->extension; - if (msg->tx_size) + if (msg->tx_size) { + /* Invalidate cache to ensure we read the latest data from memory. + * The response was prepared on a secondary core but will be sent + * to the host from the primary core. + */ + if (msg->is_shared) { + dcache_invalidate_region((__sparse_force void __sparse_cache *)msg->tx_data, + msg->tx_size); + } + mailbox_dspbox_write(0, (uint32_t *)msg->tx_data, msg->tx_size); + } /* free memory for get config function */ if (msg == &msg_reply && msg_reply.tx_size > 0) { rfree(msg_reply.tx_data); msg_reply.tx_data = NULL; msg_reply.tx_size = 0; + msg_reply.is_shared = false; } return &msg_data.msg_out; @@ -1535,6 +1546,7 @@ void ipc_send_panic_notification(void) { msg_notify.header = SOF_IPC4_NOTIF_HEADER(SOF_IPC4_EXCEPTION_CAUGHT); msg_notify.extension = cpu_get_id(); + msg_notify.is_shared = !cpu_is_primary(cpu_get_id()); msg_notify.tx_size = 0; msg_notify.tx_data = NULL; list_init(&msg_notify.list); @@ -1567,6 +1579,7 @@ void ipc_send_buffer_status_notify(void) msg_notify.header = SOF_IPC4_NOTIF_HEADER(SOF_IPC4_NOTIFY_LOG_BUFFER_STATUS); msg_notify.extension = 0; msg_notify.tx_size = 0; + msg_notify.is_shared = false; tr_dbg(&ipc_tr, "tx-notify\t: %#x|%#x", msg_notify.header, msg_notify.extension); diff --git a/src/library_manager/lib_notification.c b/src/library_manager/lib_notification.c index 29ca2de2a951..f76fc05942b1 100644 --- a/src/library_manager/lib_notification.c +++ b/src/library_manager/lib_notification.c @@ -73,6 +73,7 @@ struct ipc_msg *lib_notif_msg_init(uint32_t header, uint32_t size) /* Update header and size, since message handle can be reused */ msg->header = header; msg->tx_size = size; + msg->is_shared = !cpu_is_primary(cpu_get_id()); return msg; }