Skip to content

Commit 7411f40

Browse files
committed
audio: component: wait for remote component reset to complete
comp_reset_remote() sent the cross-core IDC_MSG_RESET with IDC_BLOCKING, which only waits CONFIG_IDC_TIMEOUT_US (15 ms) before returning -EAGAIN. A data-processing (DP) module reset runs schedule_task_cancel() -> k_thread_join() on the target core and cannot return until the DP thread finishes its in-flight process() call. That call is bounded but can be long during a codec cold-start (a deferred avcodec_open2 table build, up to ~1.4 s for aac, or the first decode after it), far exceeding the IDC timeout. When it timed out the component was left un-reset (not COMP_STATE_READY), so pipeline_reset() failed and the host-side free was then refused with an invalid-state error and the remote core could not be disabled - every teardown wedged until reboot. The caller (pipeline_reset -> host) depends on the reset actually being finished before it frees the component and powers down the remote core, so the reset must stay synchronous. Add IDC_BLOCKING_NO_TIMEOUT, which is IDC_BLOCKING but waits K_FOREVER for the handler to complete, and use it for comp_reset_remote(). A normal end-of-stream teardown joins an idle DP thread and returns immediately, so this only waits when it must. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
1 parent 5875cbb commit 7411f40

4 files changed

Lines changed: 36 additions & 2 deletions

File tree

‎posix/include/rtos/idc.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
/** \brief IDC send non-blocking flag. */
2929
#define IDC_NON_BLOCKING 1
3030

31+
/** \brief IDC send blocking flag, wait for completion without timing out. */
32+
#define IDC_BLOCKING_NO_TIMEOUT 4
33+
3134
/** \brief IDC send core power up flag. */
3235
#define IDC_POWER_UP 2
3336

‎src/idc/zephyr_idc.c‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ int idc_send_msg(struct idc_msg *msg, uint32_t mode)
157157
work->priority = CONFIG_EDF_THREAD_PRIORITY;
158158
work->deadline = 0;
159159
work->handler = idc_handler;
160-
work->sync = mode == IDC_BLOCKING;
160+
work->sync = mode == IDC_BLOCKING || mode == IDC_BLOCKING_NO_TIMEOUT;
161161

162162
if (msg->payload) {
163163
idc_send_memcpy_err = memcpy_s(payload->data, sizeof(payload->data),
@@ -189,6 +189,13 @@ int idc_send_msg(struct idc_msg *msg, uint32_t mode)
189189
/* message was sent and executed successfully, get status code */
190190
ret = idc_msg_status_get(msg->core);
191191
break;
192+
case IDC_BLOCKING_NO_TIMEOUT:
193+
/* wait for completion; the handler is bounded but may exceed
194+
* CONFIG_IDC_TIMEOUT_US (see IDC_BLOCKING_NO_TIMEOUT) */
195+
ret = k_p4wq_wait(work, K_FOREVER);
196+
if (!ret)
197+
ret = idc_msg_status_get(msg->core);
198+
break;
192199
case IDC_POWER_UP:
193200
case IDC_NON_BLOCKING:
194201
default:

‎src/include/sof/audio/component_ext.h‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,22 @@ static inline int comp_reset_remote(struct comp_dev *dev)
405405
struct idc_msg msg = { IDC_MSG_RESET,
406406
IDC_MSG_RESET_EXT(dev->ipc_config.id), dev->ipc_config.core, };
407407

408-
return idc_send_msg(&msg, IDC_BLOCKING);
408+
/*
409+
* Blocking, and waiting for actual completion (no timeout): the caller
410+
* (pipeline_reset -> host) depends on the reset being finished before it
411+
* frees the component and powers down the remote core. A DP decoder's
412+
* reset runs schedule_task_cancel() -> k_thread_join() on that core, which
413+
* only returns once the DP thread finishes its in-flight process() call.
414+
* That call is bounded but can be long during codec cold-start (a deferred
415+
* avcodec_open2 table build, ~1.4 s for aac, or the first decode after it),
416+
* exceeding CONFIG_IDC_TIMEOUT_US. A plain IDC_BLOCKING would give up at
417+
* that timeout (-EAGAIN) while the reset is still running remotely, leaving
418+
* the component un-reset; pipeline_reset() then fails and the subsequent
419+
* free is refused (invalid state) / the core cannot be disabled, wedging
420+
* every teardown until reboot. A normal end-of-stream teardown joins an
421+
* idle DP thread and returns immediately, so this only waits when it must.
422+
*/
423+
return idc_send_msg(&msg, IDC_BLOCKING_NO_TIMEOUT);
409424
}
410425

411426
/**

‎zephyr/include/rtos/idc.h‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@
2828
/** \brief IDC send non-blocking flag. */
2929
#define IDC_NON_BLOCKING 1
3030

31+
/** \brief IDC send blocking flag, wait for completion without timing out.
32+
* Like IDC_BLOCKING but waits (K_FOREVER) for the handler to finish rather
33+
* than only CONFIG_IDC_TIMEOUT_US. For remote ops whose completion the
34+
* caller depends on and which are bounded but can exceed the IDC timeout
35+
* (e.g. a DP component reset that joins a decoder thread mid codec
36+
* cold-start).
37+
*/
38+
#define IDC_BLOCKING_NO_TIMEOUT 4
39+
3140
/** \brief IDC send core power up flag. */
3241
#define IDC_POWER_UP 2
3342

0 commit comments

Comments
 (0)