From 3b7d5c9ef91877c4d25aeef49c3ff870d549bab5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 18 Nov 2021 08:46:28 +0100 Subject: [PATCH 01/10] pipeline: start all pipelines on the same timer tick Currently when a multi-pipeline stream starts, the first scheduler run will process the START trigger in the context of the first pipeline, then the next pipeline task within the same scheduler run will already attempt to copy data. This cannot work because the first pipeline hasn't copied its data yet. Make sure to skip the first scheduler run completely on all pipelines. Signed-off-by: Guennadi Liakhovetski --- src/audio/pipeline/pipeline-schedule.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/audio/pipeline/pipeline-schedule.c b/src/audio/pipeline/pipeline-schedule.c index baba00083b89..2655d2510ca9 100644 --- a/src/audio/pipeline/pipeline-schedule.c +++ b/src/audio/pipeline/pipeline-schedule.c @@ -211,7 +211,6 @@ void pipeline_schedule_triggered(struct pipeline_walk_context *ctx, struct list_item *tlist; struct pipeline *p; uint32_t flags; - bool first_pipe = true; /* * Interrupts have to be disabled while adding tasks to or removing them @@ -246,7 +245,7 @@ void pipeline_schedule_triggered(struct pipeline_walk_context *ctx, list_for_item(tlist, &ctx->pipelines) { p = container_of(tlist, struct pipeline, list); p->xrun_bytes = 0; - if (pipeline_is_timer_driven(p) && first_pipe) { + if (pipeline_is_timer_driven(p)) { /* * Use the first of connected pipelines to * trigger, mark all other connected pipelines @@ -254,7 +253,7 @@ void pipeline_schedule_triggered(struct pipeline_walk_context *ctx, */ p->trigger.cmd = cmd; p->trigger.host = ppl_data->start; - first_pipe = false; + ppl_data->start = NULL; } else { p->status = COMP_STATE_ACTIVE; } From 9e26d42fd0ddffe486416b156f06111d789fc14d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 18 Nov 2021 12:17:57 +0100 Subject: [PATCH 02/10] pipeline: don't skip a copying scheduling tick When processing a PAUSE or a STOP trigger in the pipeline task, if the pipeline aborts processing of the trigger, it has to proceed executing the copy() flow instead of skipping the tick. Signed-off-by: Guennadi Liakhovetski --- src/audio/pipeline/pipeline-schedule.c | 32 +++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/audio/pipeline/pipeline-schedule.c b/src/audio/pipeline/pipeline-schedule.c index 2655d2510ca9..9fb855e28bd0 100644 --- a/src/audio/pipeline/pipeline-schedule.c +++ b/src/audio/pipeline/pipeline-schedule.c @@ -45,8 +45,15 @@ static enum task_state pipeline_task_cmd(struct pipeline *p, if (!p->trigger.host) { p->trigger.cmd = COMP_TRIGGER_NO_ACTION; - return p->status == COMP_STATE_PAUSED ? SOF_TASK_STATE_COMPLETED : - SOF_TASK_STATE_RESCHEDULE; + + switch (cmd) { + case COMP_TRIGGER_STOP: + case COMP_TRIGGER_PAUSE: + return p->trigger.aborted ? SOF_TASK_STATE_RUNNING : + SOF_TASK_STATE_COMPLETED; + } + + return SOF_TASK_STATE_RESCHEDULE; } err = pipeline_trigger_run(p, p->trigger.host, cmd); @@ -77,8 +84,18 @@ static enum task_state pipeline_task_cmd(struct pipeline *p, if (p->trigger.delay) return SOF_TASK_STATE_RESCHEDULE; /* No delay: the final stage has already run too */ - } else if (p->status == COMP_STATE_PAUSED && !p->trigger.aborted) { - err = SOF_TASK_STATE_COMPLETED; + err = SOF_TASK_STATE_RESCHEDULE; + } else if (p->status == COMP_STATE_PAUSED) { + if (p->trigger.aborted) { + p->status = COMP_STATE_ACTIVE; + /* + * the pipeline aborted a STOP or a PAUSE + * command, proceed with copying + */ + err = SOF_TASK_STATE_RUNNING; + } else { + err = SOF_TASK_STATE_COMPLETED; + } } else { p->status = COMP_STATE_ACTIVE; err = SOF_TASK_STATE_RESCHEDULE; @@ -136,9 +153,12 @@ static enum task_state pipeline_task(void *arg) return SOF_TASK_STATE_RESCHEDULE; } - if (p->trigger.cmd != COMP_TRIGGER_NO_ACTION) + if (p->trigger.cmd != COMP_TRIGGER_NO_ACTION) { /* Process an offloaded command */ - return pipeline_task_cmd(p, &reply); + err = pipeline_task_cmd(p, &reply); + if (err != SOF_TASK_STATE_RUNNING) + return err; + } if (p->status == COMP_STATE_PAUSED) /* From 5274aa4dd9710c2c589d869c9ccfccfade7c4d56 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 24 Nov 2021 13:03:49 +0100 Subject: [PATCH 03/10] schedule: verify compulsory operations schedule_task_cancel, schedule_task_free and schedule_task are compulsory scheduler operations. Verify them once during scheduler registration and don't check them afterwards when calling. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/schedule/schedule.h | 9 ++++++--- src/schedule/schedule.c | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/include/sof/schedule/schedule.h b/src/include/sof/schedule/schedule.h index af677d3fabad..ae0e354afb16 100644 --- a/src/include/sof/schedule/schedule.h +++ b/src/include/sof/schedule/schedule.h @@ -223,9 +223,12 @@ static inline int schedule_task(struct task *task, uint64_t start, struct schedule_data *sch; struct list_item *slist; + if (!task) + return -EINVAL; + list_for_item(slist, &schedulers->list) { sch = container_of(slist, struct schedule_data, list); - if (task->type == sch->type && sch->ops->schedule_task) + if (task->type == sch->type) return sch->ops->schedule_task(sch->data, task, start, period); } @@ -264,7 +267,7 @@ static inline int schedule_task_cancel(struct task *task) list_for_item(slist, &schedulers->list) { sch = container_of(slist, struct schedule_data, list); - if (task->type == sch->type && sch->ops->schedule_task_cancel) + if (task->type == sch->type) return sch->ops->schedule_task_cancel(sch->data, task); } @@ -280,7 +283,7 @@ static inline int schedule_task_free(struct task *task) list_for_item(slist, &schedulers->list) { sch = container_of(slist, struct schedule_data, list); - if (task->type == sch->type && sch->ops->schedule_task_free) + if (task->type == sch->type) return sch->ops->schedule_task_free(sch->data, task); } diff --git a/src/schedule/schedule.c b/src/schedule/schedule.c index 64a4d74d00fe..543f91e21914 100644 --- a/src/schedule/schedule.c +++ b/src/schedule/schedule.c @@ -61,6 +61,10 @@ void scheduler_init(int type, const struct scheduler_ops *ops, void *data) { struct schedule_data *sch; + if (!ops || !ops->schedule_task || !ops->schedule_task_cancel || + !ops->schedule_task_free) + return; + sch = rzalloc(SOF_MEM_ZONE_SYS, 0, SOF_MEM_CAPS_RAM, sizeof(*sch)); list_init(&sch->list); sch->type = type; From 456a91883ecc730afe2fa1af0daf082acfa6ca9d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 24 Nov 2021 13:06:13 +0100 Subject: [PATCH 04/10] schedule: add schedule_task_before() and schedule_task_after() Sometimes multiple tasks have to be scheduled together - one after another and in a specific order. Add two order-enforcing functions for that. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/schedule/schedule.h | 80 +++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/include/sof/schedule/schedule.h b/src/include/sof/schedule/schedule.h index ae0e354afb16..5d069443ab07 100644 --- a/src/include/sof/schedule/schedule.h +++ b/src/include/sof/schedule/schedule.h @@ -60,6 +60,34 @@ struct scheduler_ops { int (*schedule_task)(void *data, struct task *task, uint64_t start, uint64_t period); + /** + * Schedules task with given scheduling parameters. + * @param data Private data of selected scheduler. + * @param task Task to be scheduled. + * @param start Start time of given task (in microseconds). + * @param period Scheduling period of given task (in microseconds). + * @param before Task to be scheduled before + * @return 0 if succeeded, error code otherwise. + * + * This operation is optional. + */ + int (*schedule_task_before)(void *data, struct task *task, uint64_t start, + uint64_t period, struct task *before); + + /** + * Schedules task with given scheduling parameters. + * @param data Private data of selected scheduler. + * @param task Task to be scheduled. + * @param start Start time of given task (in microseconds). + * @param period Scheduling period of given task (in microseconds). + * @param after Task to be scheduled after + * @return 0 if succeeded, error code otherwise. + * + * This operation is optional. + */ + int (*schedule_task_after)(void *data, struct task *task, uint64_t start, + uint64_t period, struct task *after); + /** * Sets task into running state along with executing additional * scheduler specific operations. @@ -236,6 +264,58 @@ static inline int schedule_task(struct task *task, uint64_t start, return -ENODEV; } +/** See scheduler_ops::schedule_task_before */ +static inline int schedule_task_before(struct task *task, uint64_t start, + uint64_t period, struct task *before) +{ + struct schedulers *schedulers = *arch_schedulers_get(); + struct schedule_data *sch; + struct list_item *slist; + + if (!task || !before) + return -EINVAL; + + list_for_item(slist, &schedulers->list) { + sch = container_of(slist, struct schedule_data, list); + if (task->type == sch->type) { + if (sch->ops->schedule_task_before) + return sch->ops->schedule_task_before(sch->data, task, start, + period, before); + + return sch->ops->schedule_task(sch->data, task, start, + period); + } + } + + return -ENODEV; +} + +/** See scheduler_ops::schedule_task_after */ +static inline int schedule_task_after(struct task *task, uint64_t start, + uint64_t period, struct task *after) +{ + struct schedulers *schedulers = *arch_schedulers_get(); + struct schedule_data *sch; + struct list_item *slist; + + if (!task || !after) + return -EINVAL; + + list_for_item(slist, &schedulers->list) { + sch = container_of(slist, struct schedule_data, list); + if (task->type == sch->type) { + if (sch->ops->schedule_task_after) + return sch->ops->schedule_task_after(sch->data, task, start, + period, after); + + return sch->ops->schedule_task(sch->data, task, start, + period); + } + } + + return -ENODEV; +} + /** See scheduler_ops::reschedule_task */ static inline int reschedule_task(struct task *task, uint64_t start) { From 45b8cb813e79351d40051f9991165f3d8bb074e7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 24 Nov 2021 13:09:40 +0100 Subject: [PATCH 05/10] ll_schedule: implement schedule_task_before and schedule_task_after Add support for order-enforcing scheduling to the ll-scheduler. Signed-off-by: Guennadi Liakhovetski --- src/schedule/ll_schedule.c | 49 ++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/schedule/ll_schedule.c b/src/schedule/ll_schedule.c index 7e0c164919c2..ed97d97bd7e2 100644 --- a/src/schedule/ll_schedule.c +++ b/src/schedule/ll_schedule.c @@ -407,10 +407,20 @@ static void schedule_ll_task_insert(struct task *task, struct list_item *tasks) list_item_append(&task->list, tasks); } -static int schedule_ll_task(void *data, struct task *task, uint64_t start, - uint64_t period) +static void schedule_ll_task_insert_before(struct task *task, struct task *before) +{ + list_item_append(&task->list, &before->list); +} + +static void schedule_ll_task_insert_after(struct task *task, struct task *after) +{ + list_item_prepend(&task->list, &after->list); +} + +static int schedule_ll_task_common(struct ll_schedule_data *sch, struct task *task, + uint64_t start, uint64_t period, + struct task *reference, bool before) { - struct ll_schedule_data *sch = data; struct ll_task_pdata *pdata; struct ll_task_pdata *reg_pdata; struct list_item *tlist; @@ -486,7 +496,12 @@ static int schedule_ll_task(void *data, struct task *task, uint64_t start, } /* insert task into the list */ - schedule_ll_task_insert(task, &sch->tasks); + if (!reference) + schedule_ll_task_insert(task, &sch->tasks); + else if (before) + schedule_ll_task_insert_before(task, reference); + else + schedule_ll_task_insert_after(task, reference); task->state = SOF_TASK_STATE_QUEUED; /* set schedule domain */ @@ -503,6 +518,30 @@ static int schedule_ll_task(void *data, struct task *task, uint64_t start, return ret; } +static int schedule_ll_task(void *data, struct task *task, uint64_t start, + uint64_t period) +{ + struct ll_schedule_data *sch = data; + + return schedule_ll_task_common(sch, task, start, period, NULL, false); +} + +static int schedule_ll_task_before(void *data, struct task *task, uint64_t start, + uint64_t period, struct task *before) +{ + struct ll_schedule_data *sch = data; + + return schedule_ll_task_common(sch, task, start, period, before, true); +} + +static int schedule_ll_task_after(void *data, struct task *task, uint64_t start, + uint64_t period, struct task *after) +{ + struct ll_schedule_data *sch = data; + + return schedule_ll_task_common(sch, task, start, period, after, false); +} + int schedule_task_init_ll(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, uint16_t priority, enum task_state (*run)(void *data), @@ -693,6 +732,8 @@ int scheduler_init_ll(struct ll_schedule_domain *domain) static const struct scheduler_ops schedule_ll_ops = { .schedule_task = schedule_ll_task, + .schedule_task_before = schedule_ll_task_before, + .schedule_task_after = schedule_ll_task_after, .schedule_task_free = schedule_ll_task_free, .schedule_task_cancel = schedule_ll_task_cancel, .reschedule_task = reschedule_ll_task, From cb0d41c71d30bdf8c4627bd049b26d5d085aaa98 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 24 Nov 2021 14:09:23 +0100 Subject: [PATCH 06/10] pipeline: move parts of the pipeline API to pipeline.h struct pipeline_task and pipeline_task_get() belong to the pipeline API, not to the scheduler API. Move them to pipeline.h Signed-off-by: Guennadi Liakhovetski --- src/include/sof/audio/pipeline.h | 11 ++++++++++- src/include/sof/schedule/task.h | 8 -------- src/schedule/ll_schedule.c | 1 + 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index 3bb9cdf86f1f..8c14b5eecc1c 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -25,7 +26,6 @@ struct comp_buffer; struct comp_dev; struct ipc; struct ipc_msg; -struct task; /* Pipeline status to stop execution of current path */ #define PPL_STATUS_PATH_STOP 1 @@ -108,6 +108,15 @@ struct pipeline_data { uint32_t delay_ms; /* between PRE_{START,RELEASE} and {START,RELEASE} */ }; +/** \brief Task type registered by pipelines. */ +struct pipeline_task { + struct task task; /**< parent structure */ + bool registrable; /**< should task be registered on irq */ + struct comp_dev *sched_comp; /**< pipeline scheduling component */ +}; + +#define pipeline_task_get(t) container_of(t, struct pipeline_task, task) + /* * Pipeline Graph APIs * diff --git a/src/include/sof/schedule/task.h b/src/include/sof/schedule/task.h index e38cf0b9ac77..e59acf275945 100644 --- a/src/include/sof/schedule/task.h +++ b/src/include/sof/schedule/task.h @@ -75,14 +75,6 @@ struct task { #endif }; -/** \brief Task type registered by pipelines. */ -struct pipeline_task { - struct task task; /**< parent structure */ - bool registrable; /**< should task be registered on irq */ - struct comp_dev *sched_comp; /**< pipeline scheduling component */ -}; - -#define pipeline_task_get(t) container_of(t, struct pipeline_task, task) static inline enum task_state task_run(struct task *task) { diff --git a/src/schedule/ll_schedule.c b/src/schedule/ll_schedule.c index ed97d97bd7e2..bb1ef1d9c928 100644 --- a/src/schedule/ll_schedule.c +++ b/src/schedule/ll_schedule.c @@ -7,6 +7,7 @@ // Tomasz Lauda #include +#include #include #include #include From 0d859ecba6f1a641fdc1f84b6b0edb609bdd2fc5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 24 Nov 2021 14:14:18 +0100 Subject: [PATCH 07/10] task: add a function to check if a task is active Tasks currently have 9 states defined for them, but they all can be divided into two groups: active and passive. We define all tasks on a scheduler queue as active. All other tasks are passive. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/schedule/task.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/include/sof/schedule/task.h b/src/include/sof/schedule/task.h index e59acf275945..a33bf0d5d599 100644 --- a/src/include/sof/schedule/task.h +++ b/src/include/sof/schedule/task.h @@ -75,6 +75,19 @@ struct task { #endif }; +static inline bool task_is_active(struct task *task) +{ + switch (task->state) { + case SOF_TASK_STATE_QUEUED: + case SOF_TASK_STATE_PENDING: + case SOF_TASK_STATE_RUNNING: + case SOF_TASK_STATE_PREEMPTED: + case SOF_TASK_STATE_RESCHEDULE: + return true; + default: + return false; + } +} static inline enum task_state task_run(struct task *task) { From 5e32f0b4491cc6b64ed5dda31e8b5343098a417b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 24 Nov 2021 14:19:22 +0100 Subject: [PATCH 08/10] pipeline: enforce scheduling order of connected pipelines Connected pipelines have to be scheduled in a specific order, depending on the direction of the data flow. Use the new schedule_task_before() / schedule_task_after() API for that. Signed-off-by: Guennadi Liakhovetski --- src/audio/pipeline/pipeline-schedule.c | 9 ++++++++- src/audio/pipeline/pipeline-stream.c | 26 ++++++++++++++++++++++++-- src/include/sof/audio/pipeline.h | 2 ++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/audio/pipeline/pipeline-schedule.c b/src/audio/pipeline/pipeline-schedule.c index 9fb855e28bd0..d3819191d278 100644 --- a/src/audio/pipeline/pipeline-schedule.c +++ b/src/audio/pipeline/pipeline-schedule.c @@ -340,5 +340,12 @@ void pipeline_schedule_copy(struct pipeline *p, uint64_t start) if (!pipeline_is_timer_driven(p)) sa_set_panic_on_delay(false); - schedule_task(p->pipe_task, start, p->period); + if (p->sched_next && task_is_active(p->sched_next->pipe_task)) + schedule_task_before(p->pipe_task, start, p->period, + p->sched_next->pipe_task); + else if (p->sched_prev && task_is_active(p->sched_prev->pipe_task)) + schedule_task_after(p->pipe_task, start, p->period, + p->sched_prev->pipe_task); + else + schedule_task(p->pipe_task, start, p->period); } diff --git a/src/audio/pipeline/pipeline-stream.c b/src/audio/pipeline/pipeline-stream.c index ddd199c22d1e..850fef1c6a85 100644 --- a/src/audio/pipeline/pipeline-stream.c +++ b/src/audio/pipeline/pipeline-stream.c @@ -175,11 +175,33 @@ static int pipeline_trigger_list(struct pipeline *p, struct comp_dev *host, int list_init(&walk_ctx.pipelines); ret = walk_ctx.comp_func(host, NULL, &walk_ctx, host->direction); - if (ret < 0) + if (ret < 0) { pipe_err(p, "pipeline_trigger_list(): ret = %d, host->comp.id = %u, cmd = %d", ret, dev_comp_id(host), cmd); - else + } else { + if (cmd == COMP_TRIGGER_PRE_START) { + struct list_item *list; + struct pipeline *current, *upstream = NULL; + + /* Make sure the first pipeline has the highest priority */ + list_for_item(list, &walk_ctx.pipelines) { + current = list_item(list, struct pipeline, list); + + if (current->sched_comp->direction == SOF_IPC_STREAM_PLAYBACK) { + current->sched_prev = upstream; + if (upstream) + upstream->sched_next = current; + } else { + current->sched_next = upstream; + if (upstream) + upstream->sched_prev = current; + } + + upstream = current; + } + } pipeline_schedule_triggered(&walk_ctx, cmd); + } return ret; } diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index 8c14b5eecc1c..d27d8728b98c 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -60,6 +60,8 @@ struct pipeline { /* scheduling */ struct task *pipe_task; /* pipeline processing task */ + struct pipeline *sched_next; /* pipeline scheduled after this */ + struct pipeline *sched_prev; /* pipeline scheduled before this */ /* component that drives scheduling in this pipe */ struct comp_dev *sched_comp; From 409cdbfc4d406fe0423b6c50f51c805595bea917 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 19 Nov 2021 11:36:53 +0100 Subject: [PATCH 09/10] ll_schedule: don't adjust periodic tasks to earlier than in a period Current logic in schedule_ll_domain_set() checks a newly submitted periodic task if it has to be scheduled before an existing one. However, when doing this the algorithm might schedule the new task a whole period earlier than would normally be acceptable. Fix this by adding the missing period delay. Signed-off-by: Guennadi Liakhovetski --- src/schedule/ll_schedule.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/schedule/ll_schedule.c b/src/schedule/ll_schedule.c index bb1ef1d9c928..f412ea86bcda 100644 --- a/src/schedule/ll_schedule.c +++ b/src/schedule/ll_schedule.c @@ -330,11 +330,13 @@ static int schedule_ll_domain_set(struct ll_schedule_data *sch, task->start = task_start; if (task->start < domain->next_tick) domain_set(domain, task_start); - } else if (task_start < domain->next_tick) { - /* earlier periodic task, try to make it cadence-aligned with the existed task */ - offset = (domain->next_tick - task_start) % - (domain->ticks_per_ms * period / 1000); - task_start = task_start - task_start_ticks + offset; + } else if (task_start + task_start_ticks < domain->next_tick) { + /* + * Earlier periodic task, try to make it cadence-aligned with the existed task. + * In this case task_start_ticks is the number of ticks per period. + */ + offset = (domain->next_tick - task_start) % task_start_ticks; + task_start += offset; domain_set(domain, task_start); task->start = domain->next_tick; } else { From 8db31ed7e745d338d4e3d5591769cbc7ca6e1b22 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 19 Nov 2021 11:03:44 +0100 Subject: [PATCH 10/10] ll_schedule: schedule with the reference task Sometimes multiple tasks must be scheduled on the same domain tick. Use the reference task pointer for such cases. Signed-off-by: Guennadi Liakhovetski --- src/schedule/ll_schedule.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/schedule/ll_schedule.c b/src/schedule/ll_schedule.c index f412ea86bcda..cd1ecb36fa3d 100644 --- a/src/schedule/ll_schedule.c +++ b/src/schedule/ll_schedule.c @@ -294,7 +294,7 @@ static void schedule_ll_tasks_run(void *data) static int schedule_ll_domain_set(struct ll_schedule_data *sch, struct task *task, uint64_t start, - uint64_t period) + uint64_t period, struct task *reference) { struct ll_schedule_domain *domain = sch->domain; int core = cpu_get_id(); @@ -321,7 +321,9 @@ static int schedule_ll_domain_set(struct ll_schedule_data *sch, task_start_ticks = domain->ticks_per_ms * task_start_us / 1000; task_start = task_start_ticks + platform_timer_get_atomic(timer_get()); - if (domain->next_tick == UINT64_MAX) { + if (reference) { + task->start = reference->start; + } else if (domain->next_tick == UINT64_MAX) { /* first task, set domain */ domain_set(domain, task_start); task->start = domain->next_tick; @@ -508,7 +510,7 @@ static int schedule_ll_task_common(struct ll_schedule_data *sch, struct task *ta task->state = SOF_TASK_STATE_QUEUED; /* set schedule domain */ - ret = schedule_ll_domain_set(sch, task, start, period); + ret = schedule_ll_domain_set(sch, task, start, period, reference); if (ret < 0) { list_item_del(&task->list); goto out;