schedule: cancel a task before freeing it

When a chain DMA stream is the only one running, stopping it
currently takes 100ms. The reason is that the chain DMA driver is
trying to stop the task directly from the IPC context instead of
letting the task exit on its next scheduling event. The IPC thread is
indeed trying to wait on a semaphore for the task to exit, but that
doesn't work either, because zephyr_domain_unregister() terminates
the thread before it signals the semaphore. To fix this we swap the
order and signal the semaphore before terminating the thread.

Link: https://github.com/thesofproject/sof/issues/8445
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
This commit is contained in:
Guennadi Liakhovetski 2023-11-06 16:49:45 +01:00 committed by Kai Vehmanen
parent 3bd9991121
commit b7d7fb0ed2
1 changed files with 10 additions and 9 deletions

View File

@ -57,6 +57,8 @@ static void zephyr_ll_assert_core(const struct zephyr_ll *sch)
static void zephyr_ll_task_done(struct zephyr_ll *sch,
struct task *task)
{
struct zephyr_ll_pdata *pdata = task->priv_data;
list_item_del(&task->list);
if (!sch->n_tasks) {
@ -66,6 +68,13 @@ static void zephyr_ll_task_done(struct zephyr_ll *sch,
task->state = SOF_TASK_STATE_FREE;
if (pdata->freeing)
/*
* zephyr_ll_task_free() is trying to free this task. Complete
* it and signal the semaphore to let the function proceed
*/
k_sem_give(&pdata->sem);
tr_info(&ll_tr, "task complete %p %pU", task, task->uid);
tr_info(&ll_tr, "num_tasks %d total_num_tasks %ld",
sch->n_tasks, atomic_read(&sch->ll_domain->total_num_tasks));
@ -212,15 +221,7 @@ static void zephyr_ll_run(void *data)
zephyr_ll_lock(sch, &flags);
if (pdata->freeing) {
/*
* zephyr_ll_task_free() is trying to free this task.
* complete it and signal the semaphore to let the
* function proceed
*/
zephyr_ll_task_done(sch, task);
k_sem_give(&pdata->sem);
} else if (state == SOF_TASK_STATE_COMPLETED) {
if (pdata->freeing || state == SOF_TASK_STATE_COMPLETED) {
zephyr_ll_task_done(sch, task);
} else {
/*