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 12, 2024
1 parent 7507b32 commit 63998ff
Showing 1 changed file with 22 additions and 1 deletion.
23 changes: 22 additions & 1 deletion src/audio/kpb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1742,13 +1742,22 @@ 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 preemptable 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 temporarly to block LL from preempting EDF task thread.
*/
k_sched_lock();

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 +1769,17 @@ 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.
*/
k_sched_unlock();
k_yield();
k_sched_lock();

/* 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 +1886,9 @@ 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 */
k_sched_unlock();

return SOF_TASK_STATE_COMPLETED;
}

Expand Down

0 comments on commit 63998ff

Please sign in to comment.