diff --git a/src/idc/zephyr_idc.c b/src/idc/zephyr_idc.c index 887cff0eb375..88a0ef40c449 100644 --- a/src/idc/zephyr_idc.c +++ b/src/idc/zephyr_idc.c @@ -73,8 +73,7 @@ static void idc_handler(struct k_p4wq_work *work) int payload = -1; k_spinlock_key_t key; - /* A message is received from another core, invalidate local cache */ - sys_cache_data_invd_range(msg, sizeof(*msg)); + __ASSERT_NO_MSG(!is_cached(msg)); if (msg->size == sizeof(int)) { const int idc_handler_memcpy_err __unused = @@ -121,6 +120,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 */ @@ -129,10 +154,6 @@ int idc_send_msg(struct idc_msg *msg, uint32_t mode) work->handler = idc_handler; work->sync = mode == IDC_BLOCKING; - if (!cpu_is_core_enabled(target_cpu)) { - tr_err(&zephyr_idc_tr, "Core %u is down, cannot sent IDC message", target_cpu); - return -EACCES; - } if (msg->payload) { idc_send_memcpy_err = memcpy_s(payload->data, sizeof(payload->data), msg->payload, msg->size); @@ -145,13 +166,13 @@ int idc_send_msg(struct idc_msg *msg, uint32_t mode) /* Temporarily store sender core ID */ msg_cp->core = cpu_get_id(); - /* Sending a message to another core, write back local message cache */ - sys_cache_data_flush_range(msg_cp, sizeof(*msg_cp)); + __ASSERT_NO_MSG(!is_cached(msg_cp)); + k_p4wq_submit(q_zephyr_idc + target_cpu, work); switch (mode) { case IDC_BLOCKING: - ret = k_p4wq_wait(work, K_FOREVER); + ret = k_p4wq_wait(work, K_USEC(IDC_TIMEOUT)); if (!ret) /* message was sent and executed successfully, get status code */ ret = idc_msg_status_get(msg->core);