Skip to content

Commit

Permalink
kpb: Fix draining task and LL conflict
Browse files Browse the repository at this point in the history
KPB draining task is executed by low priority preemptible EDF thread.
The task accesses KPB sink buffer and calls comp_copy() for component
connected to sink. If LL thread preempts draining task that could result
in broken state of sink buffer or component connected to sink. This fix
prevents LL from preempting draining task in bad moment.

Signed-off-by: Serhiy Katsyuba <serhiy.katsyuba@intel.com>
  • Loading branch information
serhiy-katsyuba-intel committed Mar 13, 2024
1 parent 7507b32 commit 2b74d2c
Showing 1 changed file with 28 additions and 1 deletion.
29 changes: 28 additions & 1 deletion src/audio/kpb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1742,13 +1742,24 @@ static enum task_state kpb_draining_task(void *arg)
uint64_t current_time;
size_t period_bytes = 0;
size_t period_bytes_limit = draining_data->pb_limit;
size_t period_copy_start = sof_cycle_get_64();
size_t period_copy_start;
size_t time_taken;
size_t *rt_stream_update = &draining_data->buffered_while_draining;
struct comp_data *kpb = comp_get_drvdata(draining_data->dev);
bool sync_mode_on = draining_data->sync_mode_on;
bool pm_is_active;

/*
* WORKAROUND: The code below accesses KPB sink buffer and calls comp_copy() on
* component connected to sink. EDF task thread has preemptible low priority and
* so can be preempted by LL thread. This could result in broken state of sink buffer
* or component connected to sink.
* Hence k_sched_lock() is used temporary to block LL from preempting EDF task thread.
*/
#ifdef __ZEPHYR__
k_sched_lock();
#endif

comp_cl_info(&comp_kpb, "kpb_draining_task(), start.");

pm_is_active = pm_runtime_is_active(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID);
Expand All @@ -1760,8 +1771,19 @@ static enum task_state kpb_draining_task(void *arg)
kpb_change_state(kpb, KPB_STATE_DRAINING);

draining_time_start = sof_cycle_get_64();
period_copy_start = draining_time_start;

while (drain_req > 0) {
/*
* Draining task usually runs for quite a lot of time (could be few seconds).
* LL should not be blocked for such a long time.
*/
#ifdef __ZEPHYR__
k_sched_unlock();
k_yield();
k_sched_lock();
#endif

/* Have we received reset request? */
if (kpb->state == KPB_STATE_RESETTING) {
kpb_change_state(kpb, KPB_STATE_RESET_FINISHING);
Expand Down Expand Up @@ -1868,6 +1890,11 @@ static enum task_state kpb_draining_task(void *arg)
comp_cl_info(&comp_kpb, "KPB: kpb_draining_task(), done. %u drained in > %u ms",
drained, UINT_MAX);

/* Restore original EDF thread priority */
#ifdef __ZEPHYR__
k_sched_unlock();
#endif

return SOF_TASK_STATE_COMPLETED;
}

Expand Down

0 comments on commit 2b74d2c

Please sign in to comment.