Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ipc: add cache flushing and invalidation for IPC data #9630

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/include/sof/ipc/msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
9 changes: 9 additions & 0 deletions src/ipc/ipc-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good catch. I wonder if a better fix would be to just allocate tx_data as uncached.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible, but it probably comes with a performance cost. It's hard for me to determine what is better. However, invalidating each message also seems problematic to me, and I considered adding some flag in the structure that would indicate that the payload should be invalidated before copying.

msg->is_shared = true;
}
}

/*
Expand Down
19 changes: 16 additions & 3 deletions src/ipc/ipc4/handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are those static structures ever cleaned? If not, once is_shared is set to true it'll never be set to back false

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that was a good catch. It seems to me that I managed to cover all cases now.


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)
Expand Down Expand Up @@ -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) {
tmleman marked this conversation as resolved.
Show resolved Hide resolved
/* 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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions src/library_manager/lib_notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Loading