Skip to content

Commit f7586a5

Browse files
committed
idc: zephyr: Fix race between IDC p4wq worker and new msg submission
A race exists between submitting a new IDC message and completion of a IDC previous message. The completion is handled on another core in the core's p4wq worker thread. Add a check to idc_send_msg() to check whether previous message to target core has been completed, and if it's not done, add a blocking wait even for nonblocking messages. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
1 parent 72e31f3 commit f7586a5

1 file changed

Lines changed: 23 additions & 4 deletions

File tree

src/idc/zephyr_idc.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,16 @@ void idc_init_thread(void)
5959
K_P4WQ_ARRAY_DEFINE(q_zephyr_idc, CONFIG_CORE_COUNT, SOF_STACK_SIZE,
6060
K_P4WQ_USER_CPU_MASK);
6161

62+
enum {
63+
WORK_INIT = 0,
64+
WORK_SUBMITTED,
65+
WORK_DONE
66+
};
67+
6268
struct zephyr_idc_msg {
6369
struct k_p4wq_work work;
6470
struct idc_msg msg;
71+
int work_status;
6572
};
6673

6774
static void idc_handler(struct k_p4wq_work *work)
@@ -101,6 +108,8 @@ static void idc_handler(struct k_p4wq_work *work)
101108
ipc_complete_cmd(ipc);
102109
k_spin_unlock(&ipc->lock, key);
103110
}
111+
112+
zmsg->work_status = WORK_DONE;
104113
}
105114

106115
/*
@@ -120,6 +129,18 @@ int idc_send_msg(struct idc_msg *msg, uint32_t mode)
120129
int ret;
121130
int idc_send_memcpy_err __unused;
122131

132+
if (!cpu_is_core_enabled(target_cpu)) {
133+
tr_err(&zephyr_idc_tr, "Core %u is down, cannot sent IDC message", target_cpu);
134+
return -EACCES;
135+
}
136+
137+
if (zmsg->work_status == WORK_SUBMITTED) {
138+
work->sync = 1;
139+
ret = k_p4wq_wait(work, K_USEC(IDC_TIMEOUT));
140+
if (ret < 0 && zmsg->work_status == WORK_SUBMITTED)
141+
return ret;
142+
}
143+
123144
idc_send_memcpy_err = memcpy_s(msg_cp, sizeof(*msg_cp), msg, sizeof(*msg));
124145
assert(!idc_send_memcpy_err);
125146
/* Same priority as the IPC thread which is an EDF task and under Zephyr */
@@ -128,10 +149,8 @@ int idc_send_msg(struct idc_msg *msg, uint32_t mode)
128149
work->handler = idc_handler;
129150
work->sync = mode == IDC_BLOCKING;
130151

131-
if (!cpu_is_core_enabled(target_cpu)) {
132-
tr_err(&zephyr_idc_tr, "Core %u is down, cannot sent IDC message", target_cpu);
133-
return -EACCES;
134-
}
152+
zmsg->work_status = WORK_SUBMITTED;
153+
135154
if (msg->payload) {
136155
idc_send_memcpy_err = memcpy_s(payload->data, sizeof(payload->data),
137156
msg->payload, msg->size);

0 commit comments

Comments
 (0)