Skip to content
Merged
46 changes: 36 additions & 10 deletions src/audio/pipeline/pipeline-schedule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
/*
Expand Down Expand Up @@ -211,7 +231,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
Expand Down Expand Up @@ -246,15 +265,15 @@ 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
* active immediately.
*/
p->trigger.cmd = cmd;
p->trigger.host = ppl_data->start;
first_pipe = false;
ppl_data->start = NULL;
} else {
p->status = COMP_STATE_ACTIVE;
}
Expand Down Expand Up @@ -321,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);
}
26 changes: 24 additions & 2 deletions src/audio/pipeline/pipeline-stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Comment thread
lgirdwood marked this conversation as resolved.
Outdated

upstream = current;
}
}
pipeline_schedule_triggered(&walk_ctx, cmd);
}

return ret;
}
Expand Down
13 changes: 12 additions & 1 deletion src/include/sof/audio/pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <sof/lib/mailbox.h>
#include <sof/lib/memory.h>
#include <sof/list.h>
#include <sof/schedule/task.h>
#include <sof/sof.h>
#include <sof/spinlock.h>
#include <sof/audio/pipeline-trace.h>
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -108,6 +110,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
*
Expand Down
89 changes: 86 additions & 3 deletions src/include/sof/schedule/schedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -223,16 +251,71 @@ 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);
}

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)
{
Expand Down Expand Up @@ -264,7 +347,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);
}

Expand All @@ -280,7 +363,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);
}

Expand Down
21 changes: 13 additions & 8 deletions src/include/sof/schedule/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,19 @@ 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 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)
{
Expand Down
Loading