Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions src/include/sof/ll_schedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@

struct work_queue;

/* range of priorities (0 - SOF_TASK_PRI_COUNT) */
#define LL_PRIORITIES SOF_TASK_PRI_COUNT

#define ll_sch_set_pdata(task, data) \
task->private = data

Expand Down
138 changes: 71 additions & 67 deletions src/lib/ll_schedule.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
*/

struct ll_schedule_data {
struct list_item work[LL_PRIORITIES]; /* list of ll per priority */
struct list_item tasks; /* list of ll tasks */
Comment thread
lgirdwood marked this conversation as resolved.
Outdated
uint64_t timeout; /* timeout for next queue run */
uint32_t window_size; /* window size for pending ll */
spinlock_t lock;
Expand Down Expand Up @@ -141,40 +141,36 @@ static int is_ll_pending(struct ll_schedule_data *queue)
uint64_t win_end;
uint64_t win_start;
int pending_count = 0;
int i;

/* get the current valid window of work */
win_end = ll_get_timer(queue);
win_start = win_end - queue->window_size;

/* check every priority level */
for (i = (LL_PRIORITIES - 1); i >= 0; i--) {
/* mark each valid work item in this time period as pending */
list_for_item(wlist, &queue->work[i]) {
ll_task = container_of(wlist, struct task, list);

/* correct the pending flag window for overflow */
if (win_end > win_start) {
/* mark pending work */
if (ll_task->start >= win_start &&
ll_task->start <= win_end) {
ll_task->state =
SOF_TASK_STATE_PENDING;
pending_count++;
} else {
ll_task->state = 0;
}
/* mark each valid work item in this time period as pending */
list_for_item(wlist, &queue->tasks) {
ll_task = container_of(wlist, struct task, list);

/* correct the pending flag window for overflow */
if (win_end > win_start) {
/* mark pending work */
if (ll_task->start >= win_start &&
ll_task->start <= win_end) {
ll_task->state =
SOF_TASK_STATE_PENDING;
pending_count++;
} else {
/* mark pending work */
if ((ll_task->start <= win_end ||
(ll_task->start >= win_start &&
ll_task->start < ULONG_LONG_MAX))) {
ll_task->state =
SOF_TASK_STATE_PENDING;
pending_count++;
} else {
ll_task->state = 0;
}
ll_task->state = 0;
}
} else {
/* mark pending work */
if ((ll_task->start <= win_end ||
(ll_task->start >= win_start &&
ll_task->start < ULONG_LONG_MAX))) {
ll_task->state =
SOF_TASK_STATE_PENDING;
pending_count++;
} else {
ll_task->state = 0;
}
}
}
Expand Down Expand Up @@ -203,8 +199,7 @@ static inline void ll_next_timeout(struct ll_schedule_data *queue,
}

/* run all pending work */
static void run_ll(struct ll_schedule_data *queue, uint32_t *flags,
uint32_t priority)
static void run_ll(struct ll_schedule_data *queue, uint32_t *flags)
{
struct list_item *wlist;
struct list_item *tlist;
Expand All @@ -213,7 +208,7 @@ static void run_ll(struct ll_schedule_data *queue, uint32_t *flags,
int cpu = cpu_get_id();

/* check each work item in queue for pending */
list_for_item_safe(wlist, tlist, &queue->work[priority]) {
list_for_item_safe(wlist, tlist, &queue->tasks) {
ll_task = container_of(wlist, struct task, list);

/* run work if its pending and remove from the queue */
Expand Down Expand Up @@ -263,28 +258,24 @@ static void queue_recalc_timers(struct ll_schedule_data *queue,
uint64_t delta_ticks;
uint64_t delta_msecs;
uint64_t current;
int i;

/* get current time */
current = ll_get_timer(queue);

/* recalculate for each priority level */
for (i = (LL_PRIORITIES - 1); i >= 0; i--) {
/* recalculate timers for each work item */
list_for_item(wlist, &queue->work[i]) {
ll_task = container_of(wlist, struct task, list);
delta_ticks = calc_delta_ticks(current, ll_task->start);
delta_msecs = delta_ticks /
clk_data->old_ticks_per_msec;

/* is work within next msec, then schedule it now */
if (delta_msecs > 0)
ll_task->start = current +
queue->ticks_per_msec * delta_msecs;
else
ll_task->start = current +
(queue->ticks_per_msec >> 3);
}
/* recalculate timers for each work item */
list_for_item(wlist, &queue->tasks) {
ll_task = container_of(wlist, struct task, list);
delta_ticks = calc_delta_ticks(current, ll_task->start);
delta_msecs = delta_ticks /
clk_data->old_ticks_per_msec;

/* is work within next msec, then schedule it now */
if (delta_msecs > 0)
ll_task->start = current +
queue->ticks_per_msec * delta_msecs;
else
ll_task->start = current +
(queue->ticks_per_msec >> 3);
}
}

Expand Down Expand Up @@ -330,17 +321,14 @@ static void queue_run(void *data)
{
struct ll_schedule_data *queue = (struct ll_schedule_data *)data;
uint32_t flags;
int i;

timer_disable(&queue->ts->timer);

spin_lock_irq(&queue->lock, flags);

/* run work if there is any pending */
if (is_ll_pending(queue)) {
/* run for each priority level */
for (i = (LL_PRIORITIES - 1); i >= 0; i--)
run_ll(queue, &flags, i);
run_ll(queue, &flags);
}

/* re-calc timer and re-arm */
Expand Down Expand Up @@ -374,6 +362,28 @@ static void ll_notify(int message, void *data, void *event_data)
spin_unlock_irq(&queue->lock, flags);
}

static inline void insert_task_to_queue(struct task *w,
struct list_item *q_list)
{
struct task *ll_task;
struct list_item *wlist;

/* works are adding to queue in order */
list_for_item(wlist, q_list) {
ll_task = container_of(wlist, struct task, list);
if (w->priority >= ll_task->priority) {
list_item_append(&w->list, &ll_task->list);
return;
}
}

/* if task has not been added, means that it has the lowest
* priority in queue and it should be added at the end of the list
*/
list_item_append(&w->list, q_list);
return;
}

static void ll_schedule(struct ll_schedule_data *queue, struct task *w,
uint64_t start)
{
Expand All @@ -385,7 +395,7 @@ static void ll_schedule(struct ll_schedule_data *queue, struct task *w,
spin_lock_irq(&queue->lock, flags);

/* check to see if we are already scheduled ? */
list_for_item(wlist, &queue->work[w->priority]) {
list_for_item(wlist, &queue->tasks) {
ll_task = container_of(wlist, struct task, list);

/* keep original start */
Expand All @@ -403,7 +413,7 @@ static void ll_schedule(struct ll_schedule_data *queue, struct task *w,
w->start += ll_shared_ctx->last_tick;

/* insert work into list */
list_item_prepend(&w->list, &queue->work[w->priority]);
insert_task_to_queue(w, &queue->tasks);

ll_set_timer(queue);

Expand All @@ -429,16 +439,15 @@ static void reschedule(struct ll_schedule_data *queue, struct task *w,
spin_lock_irq(&queue->lock, flags);

/* check to see if we are already scheduled */
list_for_item(wlist, &queue->work[w->priority]) {
list_for_item(wlist, &queue->tasks) {
ll_task = container_of(wlist, struct task, list);

/* found it */
if (ll_task == w)
goto found;
}

/* not found insert work into list */
list_item_prepend(&w->list, &queue->work[w->priority]);
insert_task_to_queue(w, &queue->tasks);

ll_set_timer(queue);

Expand Down Expand Up @@ -481,7 +490,7 @@ static int schedule_ll_task_cancel(struct task *w)
spin_lock_irq(&queue->lock, flags);

/* check to see if we are scheduled */
list_for_item(wlist, &queue->work[w->priority]) {
list_for_item(wlist, &queue->tasks) {
ll_task = container_of(wlist, struct task, list);

/* found it */
Expand Down Expand Up @@ -521,13 +530,10 @@ static void schedule_ll_task_free(struct task *w)
static struct ll_schedule_data *work_new_queue(struct timesource_data *ts)
{
struct ll_schedule_data *queue;
int i;

/* init work queue */
queue = rmalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, sizeof(*queue));

for (i = 0; i < LL_PRIORITIES; ++i)
list_init(&queue->work[i]);
list_init(&queue->tasks);

spinlock_init(&queue->lock);
atomic_init(&queue->num_ll, 0);
Expand Down Expand Up @@ -602,16 +608,14 @@ static void ll_scheduler_free(void)
struct ll_schedule_data *queue =
(*arch_schedule_get_data())->ll_sch_data;
uint32_t flags;
int i;

spin_lock_irq(&queue->lock, flags);

timer_unregister(&queue->ts->timer);

notifier_unregister(&queue->notifier);

for (i = 0; i < LL_PRIORITIES; ++i)
list_item_del(&queue->work[i]);
list_item_del(&queue->tasks);

spin_unlock_irq(&queue->lock, flags);
}
Expand Down