schedule: zephyr_dma_domain: Change domain thread priority to coop range

Problem: DMA domain thread can be preempted during a pipeline_copy()
operation. This leads to buffer->walking being set to true which, in
turn, leads to TRIGGER STOP in EDF thread (which has a higher
priority than the DMA domain and can preempt it) not being able
to stop all components in a pipeline.
This is evident in the following logs:

INFO ipc: new cmd 0x60050000
INFO starting pipeline trigger operation: 0x92c10aa0
INFO executing trigger 0 on pipe 0x92c10aa0, registrable: 0
INFO Starting first walk
INFO pipeline_comp_trigger(), current->comp.id = 17, dir = 0,
pipeline: 0x92c10aa0, registrable: 0
INFO component type: 1
ERROR BUFFER WALKING SKIP
INFO ended pipeline trigger operation returned: 0
INFO ipc: new cmd 0x60030000
INFO pipeline_comp_reset(), current->comp.id = 17, dir = 0
INFO component type: 1
ERROR BUFFER WALKING SKIP

Note: "BUFFER WALKING SKIP" error message is caused by a comp_err added
to the following section of pipeline_for_each_comp():

	if (buffer->walking) {
		comp_err(current. "BUFFER WALKING SKIP");
		continue;
	}

Most likely this has always been a problem with the DMA domain but
it was less likely to happen with only a single pipeline task at a
time (the only tested case). The problem was discovered when testing
the mixer component.

This commit solves this problem by simply changing the DMA domain's
thread priority to a value in the cooperative range. This way it won't
be preempted by the EDF thread.

Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
This commit is contained in:
Laurentiu Mihalcea 2023-05-12 14:04:02 +03:00 committed by Daniel Baluta
parent b185ffa6b8
commit 0fec81b0e0
1 changed files with 18 additions and 29 deletions

View File

@ -38,34 +38,6 @@ LOG_MODULE_DECLARE(ll_schedule, CONFIG_SOF_LOG_LEVEL);
#define ZEPHYR_PDOMAIN_STACK_SIZE 8192
#if CONFIG_LOG_PROCESS_THREAD_CUSTOM_PRIORITY
#define ZEPHYR_DMA_DOMAIN_THREAD_PRIO (CONFIG_LOG_PROCESS_THREAD_PRIORITY - 1)
#else
#define ZEPHYR_DMA_DOMAIN_THREAD_PRIO (K_LOWEST_APPLICATION_THREAD_PRIO - 1)
#endif /* CONFIG_LOG_PROCESS_THREAD_CUSTOM_PRIORITY */
/* sanity check regarding the DMA domain's priority.
*
* VERY IMPORTANT: the Zephyr DMA domain's thread priority needs to be
* higher than the logging thread's. If this criteria is not met then
* issues such as buzzing noise when PAUSING/RESUMING a stream due to
* the SAI being underrun may appear. We also want to keep Zephyr DMA
* domain's thread priority in the preemptible range so as to not
* disturb the other Zephyr threads used by SOF (preferably the Zephyr
* DMA domain's thread priority should be lower than the lowest priority
* of the threads used by SOF which is 1 (EDF_SCHEDULER)).
*
* The Zephyr DMA domain's thread priority is unimportant as long as it
* meets the above criteria but we'll make it one less than the logging
* thread's for cases where the user might want to change the logging
* thread's priority.
*
* TODO: this message and the BUILD_ASSERT message need to be updated if
* the lowest priority used by the SOF threads is changed.
*/
BUILD_ASSERT(ZEPHYR_DMA_DOMAIN_THREAD_PRIO >= 0,
"Invalid DMA domain thread priority. Please make sure that logging threads priority is >= 1 or, preferably, >= 3");
/* sanity check - make sure CONFIG_DMA_DOMAIN_SEM_LIMIT is not some
* garbage value.
*/
@ -344,6 +316,23 @@ static int zephyr_dma_domain_register(struct ll_schedule_domain *domain,
thread_name[sizeof(thread_name) - 2] = '0' + core;
/* create Zephyr thread */
/* VERY IMPORTANT: DMA domain's priority needs to be
* in the cooperative range to avoid scenarios such
* as the following:
*
* 1) pipeline_copy() is in the middle of a pipeline
* graph traversal marking buffer->walking as true.
* 2) IPC TRIGGER STOP comes and since edf thread
* has a higher priority it will preempt the DMA domain
* thread.
* 3) When TRIGGER STOP handler does a pipeline graph
* traversal it will find some buffers with walking = true
* and not go through all the components in the pipeline.
* 4) TRIGGER RESET comes and the components are not
* stopped so the handler will try to stop them which
* results in DMA IRQs being stopped and the pipeline tasks
* being stuck in the scheduling queue.
*/
thread = k_thread_create(&dt->ll_thread,
zephyr_dma_domain_stack[core],
ZEPHYR_PDOMAIN_STACK_SIZE,
@ -351,7 +340,7 @@ static int zephyr_dma_domain_register(struct ll_schedule_domain *domain,
dt,
NULL,
NULL,
ZEPHYR_DMA_DOMAIN_THREAD_PRIO,
-CONFIG_NUM_COOP_PRIORITIES,
0,
K_FOREVER);