[Sound-open-firmware] [PATCH] cnl: scheduler: Add list of tasks per irq level

Liam Girdwood liam.r.girdwood at linux.intel.com
Thu Mar 22 12:17:10 CET 2018


From: Tomasz Lauda <tomasz.lauda at linux.intel.com>

This patch adds list of tasks per each irq level and fixes the problem,
where scheduler tried to schedule the same task two times.

Signed-off-by: Tomasz Lauda <tomasz.lauda at linux.intel.com>
---
 src/arch/xtensa/include/arch/task.h |   4 +-
 src/arch/xtensa/init.c              |   2 +-
 src/arch/xtensa/task.c              | 147 ++++++++++++++++++++++++++++--------
 src/include/reef/schedule.h         |   3 +
 src/lib/schedule.c                  |  26 +++----
 5 files changed, 136 insertions(+), 46 deletions(-)

diff --git a/src/arch/xtensa/include/arch/task.h b/src/arch/xtensa/include/arch/task.h
index 1547751b..2ec5f25e 100644
--- a/src/arch/xtensa/include/arch/task.h
+++ b/src/arch/xtensa/include/arch/task.h
@@ -36,6 +36,8 @@ struct task;
 
 void arch_run_task(struct task *task);
 
-int arch_init_tasks(void);
+void arch_allocate_tasks(void);
+
+int arch_assign_tasks(void);
 
 #endif
diff --git a/src/arch/xtensa/init.c b/src/arch/xtensa/init.c
index 04338540..24c99369 100644
--- a/src/arch/xtensa/init.c
+++ b/src/arch/xtensa/init.c
@@ -78,7 +78,7 @@ static void register_exceptions(void)
 int arch_init(struct reef *reef)
 {
 	register_exceptions();
-	arch_init_tasks();
+	arch_assign_tasks();
 	return 0;
 }
 
diff --git a/src/arch/xtensa/task.c b/src/arch/xtensa/task.c
index 349f8abb..0ffedeb9 100644
--- a/src/arch/xtensa/task.c
+++ b/src/arch/xtensa/task.c
@@ -34,12 +34,19 @@
 #include <platform/platform.h>
 #include <reef/debug.h>
 #include <arch/task.h>
+#include <reef/alloc.h>
 #include <stdint.h>
 #include <errno.h>
 
-static struct task *_irq_low_task = NULL;
-static struct task *_irq_med_task = NULL;
-static struct task *_irq_high_task = NULL;
+struct irq_task {
+	spinlock_t lock;
+	struct list_item list;	/* list of tasks per irq */
+	uint32_t irq;
+};
+
+static struct irq_task *irq_low_task;
+static struct irq_task *irq_med_task;
+static struct irq_task *irq_high_task;
 
 static inline uint32_t task_get_irq(struct task *task)
 {
@@ -65,55 +72,106 @@ static inline void task_set_data(struct task *task)
 {
 	switch (task->priority) {
 	case TASK_PRI_MED + 1 ... TASK_PRI_LOW:
-		_irq_low_task = task;
+		list_item_append(&task->irq_low_list, &irq_low_task->list);
 		break;
 	case TASK_PRI_HIGH ... TASK_PRI_MED - 1:
-		_irq_high_task = task;
+		list_item_append(&task->irq_high_list, &irq_high_task->list);
 		break;
 	case TASK_PRI_MED:
 	default:
-		_irq_med_task = task;
+		list_item_append(&task->irq_med_list, &irq_med_task->list);
 		break;
 	}
 }
 
 static void _irq_low(void *arg)
 {
-	struct task *task = *(struct task **)arg;
-	uint32_t irq;
+	struct irq_task *irq_task = *(struct irq_task **)arg;
+	struct list_item *tlist;
+	struct list_item *clist;
+	struct task *task;
+	uint32_t flags;
 
-	if (task->func)
-		task->func(task->data);
+	/* intentionally don't lock list to have task added from schedule irq */
+	list_for_item(tlist, &irq_task->list) {
+		task = container_of(tlist, struct task, irq_low_list);
 
-	schedule_task_complete(task);
-	irq = task_get_irq(task);
-	interrupt_clear(irq);
+		if (task->func)
+			task->func(task->data);
+
+		schedule_task_complete(task);
+	}
+
+	spin_lock_irq(&irq_task->lock, flags);
+
+	list_for_item_safe(clist, tlist, &irq_task->list) {
+		task = container_of(clist, struct task, irq_low_list);
+		list_item_del(&task->irq_low_list);
+	}
+
+	interrupt_clear(irq_task->irq);
+
+	spin_unlock_irq(&irq_task->lock, flags);
 }
 
 static void _irq_med(void *arg)
 {
-	struct task *task = *(struct task **)arg;
-	uint32_t irq;
+	struct irq_task *irq_task = *(struct irq_task **)arg;
+	struct list_item *tlist;
+	struct list_item *clist;
+	struct task *task;
+	uint32_t flags;
 
-	if (task->func)
-		task->func(task->data);
+	/* intentionally don't lock list to have task added from schedule irq */
+	list_for_item(tlist, &irq_task->list) {
+		task = container_of(tlist, struct task, irq_med_list);
 
-	schedule_task_complete(task);
-	irq = task_get_irq(task);
-	interrupt_clear(irq);
+		if (task->func)
+			task->func(task->data);
+
+		schedule_task_complete(task);
+	}
+
+	spin_lock_irq(&irq_task->lock, flags);
+
+	list_for_item_safe(clist, tlist, &irq_task->list) {
+		task = container_of(clist, struct task, irq_med_list);
+		list_item_del(&task->irq_med_list);
+	}
+
+	interrupt_clear(irq_task->irq);
+
+	spin_unlock_irq(&irq_task->lock, flags);
 }
 
 static void _irq_high(void *arg)
 {
-	struct task *task = *(struct task **)arg;
-	uint32_t irq;
+	struct irq_task *irq_task = *(struct irq_task **)arg;
+	struct list_item *tlist;
+	struct list_item *clist;
+	struct task *task;
+	uint32_t flags;
 
-	if (task->func)
-		task->func(task->data);
+	/* intentionally don't lock list to have task added from schedule irq */
+	list_for_item(tlist, &irq_task->list) {
+		task = container_of(tlist, struct task, irq_high_list);
 
-	schedule_task_complete(task);
-	irq = task_get_irq(task);
-	interrupt_clear(irq);
+		if (task->func)
+			task->func(task->data);
+
+		schedule_task_complete(task);
+	}
+
+	spin_lock_irq(&irq_task->lock, flags);
+
+	list_for_item_safe(clist, tlist, &irq_task->list) {
+		task = container_of(clist, struct task, irq_high_list);
+		list_item_del(&task->irq_high_list);
+	}
+
+	interrupt_clear(irq_task->irq);
+
+	spin_unlock_irq(&irq_task->lock, flags);
 }
 
 /* architecture specific method of running task */
@@ -126,15 +184,42 @@ void arch_run_task(struct task *task)
 	interrupt_set(irq);
 }
 
-int arch_init_tasks(void)
+void arch_allocate_tasks(void)
+{
+	/* irq low */
+	irq_low_task = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM,
+			sizeof(*irq_low_task));
+	list_init(&irq_low_task->list);
+	spinlock_init(&irq_low_task->lock);
+	irq_low_task->irq = PLATFORM_IRQ_TASK_LOW;
+
+	/* irq medium */
+	irq_med_task = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM,
+			sizeof(*irq_med_task));
+	list_init(&irq_med_task->list);
+	spinlock_init(&irq_med_task->lock);
+	irq_med_task->irq = PLATFORM_IRQ_TASK_MED;
+
+	/* irq high */
+	irq_high_task = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM,
+			sizeof(*irq_high_task));
+	list_init(&irq_high_task->list);
+	spinlock_init(&irq_high_task->lock);
+	irq_high_task->irq = PLATFORM_IRQ_TASK_HIGH;
+}
+
+int arch_assign_tasks(void)
 {
-	interrupt_register(PLATFORM_IRQ_TASK_LOW, _irq_low, &_irq_low_task);
+	/* irq low */
+	interrupt_register(PLATFORM_IRQ_TASK_LOW, _irq_low, &irq_low_task);
 	interrupt_enable(PLATFORM_IRQ_TASK_LOW);
 
-	interrupt_register(PLATFORM_IRQ_TASK_MED, _irq_med, &_irq_med_task);
+	/* irq medium */
+	interrupt_register(PLATFORM_IRQ_TASK_MED, _irq_med, &irq_med_task);
 	interrupt_enable(PLATFORM_IRQ_TASK_MED);
 
-	interrupt_register(PLATFORM_IRQ_TASK_HIGH, _irq_high, &_irq_high_task);
+	/* irq high */
+	interrupt_register(PLATFORM_IRQ_TASK_HIGH, _irq_high, &irq_high_task);
 	interrupt_enable(PLATFORM_IRQ_TASK_HIGH);
 
 	return 0;
diff --git a/src/include/reef/schedule.h b/src/include/reef/schedule.h
index 68aa0adf..26b3a935 100644
--- a/src/include/reef/schedule.h
+++ b/src/include/reef/schedule.h
@@ -64,6 +64,9 @@ struct task {
 	uint64_t deadline;		/* scheduling deadline */
 	uint32_t state;			/* TASK_STATE_ */
 	struct list_item list;		/* list in scheduler */
+	struct list_item irq_low_list;	/* list for low irq level */
+	struct list_item irq_med_list;	/* list for medium irq level */
+	struct list_item irq_high_list;	/* list for high irq level */
 
 	/* task function and private data */
 	void *data;
diff --git a/src/lib/schedule.c b/src/lib/schedule.c
index 77284196..c21d222b 100644
--- a/src/lib/schedule.c
+++ b/src/lib/schedule.c
@@ -172,7 +172,7 @@ static uint64_t sch_work(void *data, uint64_t delay)
 static struct task *schedule_edf(void)
 {
 	struct task *task;
-	struct task *next_plus1_task = NULL;
+	struct task *future_task = NULL;
 	uint64_t current;
 
 	tracev_pipe("edf");
@@ -192,18 +192,16 @@ static struct task *schedule_edf(void)
 	/* can task be started now ? */
 	if (task->start > current) {
 		/* no, then schedule wake up */
-		next_plus1_task = task;
+		future_task = task;
 	} else {
-		/* yes, get next task and run this one now */
-		next_plus1_task = edf_get_next(current, task);
-
-		/* run current task */
+		/* yes, run current task */
 		task->start = current;
+		task->state = TASK_STATE_RUNNING;
 		arch_run_task(task);
 	}
 
-	/* teall caller about next task (after current) */
-	return next_plus1_task;
+	/* tell caller about future task */
+	return future_task;
 }
 
 #if 0 /* FIXME: is this needed ? */
@@ -319,15 +317,14 @@ void schedule_task_complete(struct task *task)
 
 static void scheduler_run(void *unused)
 {
-	struct task *next_task;
+	struct task *future_task;
 
 	tracev_pipe("run");
 
 	/* EDF is only scheduler supported atm */
-	next_task = schedule_edf();
-	if (next_task) {
-		work_reschedule_default_at(&sch->work, next_task->start);
-	}
+	future_task = schedule_edf();
+	if (future_task)
+		work_reschedule_default_at(&sch->work, future_task->start);
 }
 
 /* run the scheduler */
@@ -382,5 +379,8 @@ int scheduler_init(struct reef *reef)
 	interrupt_register(PLATFORM_SCHEDULE_IRQ, scheduler_run, NULL);
 	interrupt_enable(PLATFORM_SCHEDULE_IRQ);
 
+	/* allocate arch tasks */
+	arch_allocate_tasks();
+
 	return 0;
 }
-- 
2.14.1



More information about the Sound-open-firmware mailing list