Skip to content

Commit

Permalink
idc: zephyr: fix race between IDC p4wq worker and new msg submission
Browse files Browse the repository at this point in the history
A race exists between submitting a new IDC message and completion
of a previous message. The p4wq interface mandates k_p4wq_wait() must
be called to claim back ownership of the work object.  The SOF IDC
code does not do this, but relies on the caller not to send multiple
IDC messages to the same destination core.

Add appropriate calls to k_p4wq_wait() to handle this issue. If caller
wants to send an IDC in blocking mode, also call k_p4wq_wait() in
blocking mode. If non-blocking, return -EBUSY immediately.

The check for CPU status is moved earlier in the function. No pointing
in waiting for p4wq semaphore if the target core is already powered
down, so do the power state check as the first step.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
  • Loading branch information
kv2019i authored and abonislawski committed Jan 18, 2024
1 parent 2d2f605 commit 461043b
Showing 1 changed file with 26 additions and 0 deletions.
26 changes: 26 additions & 0 deletions src/idc/zephyr_idc.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,32 @@ int idc_send_msg(struct idc_msg *msg, uint32_t mode)
int ret;
int idc_send_memcpy_err __unused;

if (!cpu_is_core_enabled(target_cpu)) {
tr_err(&zephyr_idc_tr, "Core %u is down, cannot sent IDC message", target_cpu);
return -EACCES;
}

/*
* Handler is NULL when work object has never been submitted.
* In all other cases, we must use k_p4wq_wait() before reuse
* of the object.
*/
if (work->handler) {
/*
* If new request is in blocking mode, we must call
* k_p4wq in blocking mode. This is workaround for
* k_p4wq_wait() interface.
*/
work->sync = (mode == IDC_BLOCKING);

ret = k_p4wq_wait(work, K_USEC(IDC_TIMEOUT));
if (ret < 0) {
tr_err(&zephyr_idc_tr, "idc_send_msg error %d, target core %u",
ret, target_cpu);
return ret;
}
}

idc_send_memcpy_err = memcpy_s(msg_cp, sizeof(*msg_cp), msg, sizeof(*msg));
assert(!idc_send_memcpy_err);
/* Same priority as the IPC thread which is an EDF task and under Zephyr */
Expand Down

0 comments on commit 461043b

Please sign in to comment.