kpb: Fix draining task and LL conflict

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>
This commit is contained in:
Serhiy Katsyuba 2024-03-12 18:08:03 +01:00 committed by Kai Vehmanen
parent 6f7aee832c
commit 6f33aee270
1 changed files with 28 additions and 1 deletions

View File

@ -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);
@ -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);
@ -1868,6 +1890,11 @@ out:
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;
}