[Cbe-oss-dev] [PATCH 3/9]MARS: Partial context save

Yuji Mano yuji.mano at am.sony.com
Sat Oct 18 10:28:48 EST 2008


This adds support for partial context saves of tasks.
The mars_task_create function now accepts a new input parameter which is a
pointer to a list of mars_task_context_save_unit structures that specify
what blocks of the task context to save/restore during a task context switch.

Signed-off-by: Yuji Mano <yuji.mano at am.sony.com>

---
 include/common/mars/task_types.h |   52 +++++++++++++++-----
 include/host/mars/task.h         |   43 +++++++++++-----
 src/host/lib/task.c              |  100 ++++++++++++++++++++++++++++-----------
 src/mpu/kernel/kernel_task.c     |   56 +++++++++++++++++++--
 src/mpu/lib/task.c               |    4 -
 src/mpu/lib/task_barrier.c       |    4 -
 src/mpu/lib/task_event_flag.c    |    2 
 src/mpu/lib/task_queue.c         |   11 +++-
 src/mpu/lib/task_semaphore.c     |    2 
 src/mpu/lib/task_signal.c        |    2 
 10 files changed, 210 insertions(+), 66 deletions(-)

--- a/include/common/mars/task_types.h
+++ b/include/common/mars/task_types.h
@@ -54,19 +54,30 @@
 
 /**
  * \ingroup group_mars_task
+ * \brief Parameter for full context switch
+ */
+#define MARS_TASK_CONTEXT_SAVE_ALL		mars_task_context_save_all
+
+/**
+ * \ingroup group_mars_task
  * \brief Max length of task name
  */
 #define MARS_TASK_NAME_LEN_MAX			21
 
 /* internal task context defines */
-#define MARS_TASK_ID_SIZE			32
-#define MARS_TASK_ID_ALIGN			16
-#define MARS_TASK_ARGS_SIZE			32
-#define MARS_TASK_ARGS_ALIGN			16
-#define MARS_TASK_CONTEXT_SIZE			128
-#define MARS_TASK_CONTEXT_ALIGN			16
-#define MARS_TASK_CONTEXT_SAVE_ALIGN		128
-#define MARS_TASK_CONTEXT_SAVE_SIZE_MAX		0x30000
+#define MARS_TASK_ID_SIZE				32
+#define MARS_TASK_ID_ALIGN				16
+#define MARS_TASK_ARGS_SIZE				32
+#define MARS_TASK_ARGS_ALIGN				16
+#define MARS_TASK_CONTEXT_SIZE				128
+#define MARS_TASK_CONTEXT_ALIGN				16
+#define MARS_TASK_CONTEXT_SAVE_ALIGN			128
+#define MARS_TASK_CONTEXT_SAVE_SIZE_MAX			0x30000
+#define MARS_TASK_CONTEXT_SAVE_UNIT_MAX			16
+#define MARS_TASK_CONTEXT_SAVE_UNIT_SIZE		8
+#define MARS_TASK_CONTEXT_SAVE_UNIT_ALIGN		128
+#define MARS_TASK_CONTEXT_SAVE_UNIT_ADDR_ALIGN_MASK	0xf
+#define MARS_TASK_CONTEXT_SAVE_UNIT_SIZE_ALIGN_MASK	0xf
 
 /**
  * \ingroup group_mars_task
@@ -108,6 +119,25 @@ struct mars_task_args {
 	} type;
 } __attribute__((aligned(MARS_TASK_ARGS_ALIGN)));
 
+/**
+ * \ingroup group_mars_task
+ * \brief MARS task context save unit structure
+ *
+ * This structure is initialized by the user and passed into
+ * \ref mars_task_create for MARS task creation.
+ *
+ * A list of this structure determines what areas of MPU storage
+ * to save and restore during a task context switch.
+ */
+struct mars_task_context_save_unit {
+	/** address relative to the virtual address of task elf */
+	uint32_t addr;
+	/** size of context save unit */
+	uint32_t size;
+};
+
+extern const struct mars_task_context_save_unit mars_task_context_save_all[];
+
 struct mars_task_context {
 	struct mars_task_id id;		/* task id */
 	struct mars_task_args args;	/* task args */
@@ -117,10 +147,10 @@ struct mars_task_context {
 	uint32_t vaddr;			/* vaddr address of exec */
 	uint32_t entry;			/* entry address of exec */
 	uint32_t stack;			/* stack pointer of exec */
-	uint32_t context_save_size;	/* context save size */
-	uint64_t context_save_ea;	/* context save ea */
 	 int32_t exit_code;		/* exit code */
-	 uint8_t pad[20];		/* padding */
+	uint64_t context_save_area_ea;	/* ea of context save area */
+	uint64_t context_save_unit_ea;	/* ea of context save unit list */
+	 uint8_t pad[16];		/* padding */
 } __attribute__((aligned(MARS_TASK_CONTEXT_ALIGN)));
 
 #endif
--- a/include/host/mars/task.h
+++ b/include/host/mars/task.h
@@ -76,20 +76,37 @@ extern "C" {
  * - \e elf_image: The address of MPU program elf image in host storage that
  *	will be to be run by this task.
  * \n \n
- * - \e context_save_size: The size of context save area allocated and used
- *	during the time a task enters into the wait state. If 0 is specified,
- *	then no context save area will be allocated for the task and therefore
- *	the task must be a run-complete task. A run-complete task will run and
- *	occupy an MPU until it has completed running and exits. A run-complete
- *	task cannot enter the wait state, and therefore cannot call functions
- *	that will enter that task into a wait state. Currently either 0 or
- *	\ref MARS_TASK_CONTEXT_SAVE_SIZE_MAX must be specified.
+ * - \e save_units: A list of structures defining the areas of MPU storage to
+ *	save and restore during a task context switch.
+ *
+ *	If NULL is specified, then no context save area will be allocated for
+ *	the task and therefore the task must be a run-complete task.
+ *	A run-complete task will run and occupy an MPU until it has completed
+ *	running and exits.
+ *	A run-complete task cannot context switch, and therefore cannot call
+ *	functions that will enter that task into a wait state.
+ *
+ *	If MARS_TASK_CONTEXT_SAVE_ALL is specified, the maximum size context
+ *	save area will be allocated and all of the MPU storage not occuppied
+ *	by the MARS kernel will be saved and restored.
+ *	This will guarantee all necessary areas of the task context will be
+ *	saved and restored during a context switch.
+ *	However, this also may not be the most efficient, since areas of MPU
+ *	storage not needed by the task may be saved and restored.
+ *
+ *	For maximum efficiency, the user should initialize a static list of
+ *	\ref struct mars_task_context_save_unit that define each memory areas
+ *	to save and restore during a task context switch.
+ *	The user can specify as many save units as desired, but the
+ *	responsibility of efficiency will be left up to the user.
+ *	The last unit structure's 'size' member should be 0 to specify the end
+ *	of the save unit list.
  *
  * \param[in] mars		- pointer to MARS context
  * \param[out] id		- address of pointer to task id instance
  * \param[in] name		- name of task
  * \param[in] elf_image		- address of MPU program elf image
- * \param[in] context_save_size - size of context save area allocated for task
+ * \param[in] context_save_unit	- pointer to list of context save units
  * \return
  *	MARS_SUCCESS		- successfully created MARS task
  * \n	MARS_ERROR_NULL		- null pointer specified
@@ -98,10 +115,10 @@ extern "C" {
  * \n	MARS_ERROR_LIMIT	- task queue is currently full
  */
 int mars_task_create(struct mars_context *mars,
-			struct mars_task_id *id,
-			const char *name,
-			const void *elf_image,
-			uint32_t context_save_size);
+		struct mars_task_id *id,
+		const char *name,
+		const void *elf_image,
+		const struct mars_task_context_save_unit *context_save_unit);
 
 /**
  * \ingroup group_mars_task
--- a/src/host/lib/task.c
+++ b/src/host/lib/task.c
@@ -45,17 +45,27 @@
 
 #include "workload_queue.h"
 
+const struct mars_task_context_save_unit mars_task_context_save_all[] =
+{
+	{ .addr = 0, .size = MARS_TASK_CONTEXT_SAVE_SIZE_MAX },
+	{ .addr = 0, .size = 0 },
+};
+
 int mars_task_create(struct mars_context *mars,
-			struct mars_task_id *id_ret,
-			const char *name, const void *elf_image,
-			uint32_t context_save_size)
+		struct mars_task_id *id_ret,
+		const char *name, const void *elf_image,
+		const struct mars_task_context_save_unit *context_save_unit)
 {
 	int ret;
+	Elf32_Ehdr *ehdr;
+	Elf32_Phdr *phdr;
 	uint16_t workload_id;
 	struct mars_task_context *task;
 	struct mars_workload_context *workload;
-	Elf32_Ehdr *ehdr;
-	Elf32_Phdr *phdr;
+
+	int context_save_area_size = 0;
+	int context_save_unit_count = 1;
+	const struct mars_task_context_save_unit *p = context_save_unit;
 
 	/* check function params */
 	if (!mars)
@@ -66,8 +76,6 @@ int mars_task_create(struct mars_context
 		return MARS_ERROR_NULL;
 	if (name && strlen(name) > MARS_TASK_NAME_LEN_MAX)
 		return MARS_ERROR_PARAMS;
-	if (context_save_size > MARS_TASK_CONTEXT_SAVE_SIZE_MAX)
-		return MARS_ERROR_PARAMS;
 
 	/* process elf header information */
 	ehdr = (Elf32_Ehdr *)elf_image;
@@ -100,35 +108,71 @@ int mars_task_create(struct mars_context
 	task->vaddr = phdr->p_vaddr;
 	task->entry = ehdr->e_entry;
 
-	/* allocate the task context area if specified */
-	if (context_save_size) {
-		task->context_save_size = context_save_size;
-		task->context_save_ea = mars_ptr_to_ea(memalign(
-			MARS_TASK_CONTEXT_SAVE_ALIGN, task->context_save_size));
-		if (!task->context_save_ea) {
-			mars_workload_queue_add_cancel(mars->workload_queue,
-				workload_id);
-			return MARS_ERROR_MEMORY;
+	/* no context save - run complete */
+	if (!context_save_unit) {
+		task->context_save_unit_ea = 0;
+		task->context_save_area_ea = 0;
+		goto done;
+	}
+
+	/* calculate save unit count and save area size */
+	while (p->size) {
+		if (p->addr & MARS_TASK_CONTEXT_SAVE_UNIT_ADDR_ALIGN_MASK ||
+			p->size & MARS_TASK_CONTEXT_SAVE_UNIT_SIZE_ALIGN_MASK) {
+			ret = MARS_ERROR_PARAMS;
+			goto error_context_save_unit_addr_align;
 		}
-	} else {
-		task->context_save_size = 0;
-		task->context_save_ea = 0;
+
+		context_save_area_size += context_save_unit->size;
+		context_save_unit_count++;
+		p++;
+
+		if (context_save_unit_count == MARS_TASK_CONTEXT_SAVE_UNIT_MAX)
+			break;
+	}
+
+	/* allocate context save unit storage */
+	task->context_save_unit_ea = mars_ptr_to_ea(memalign(
+		MARS_TASK_CONTEXT_SAVE_UNIT_ALIGN,
+		context_save_unit_count * MARS_TASK_CONTEXT_SAVE_UNIT_SIZE));
+	if (!task->context_save_unit_ea) {
+		ret = MARS_ERROR_MEMORY;
+		goto error_malloc_context_save_unit;
 	}
 
+	/* allocate context save area */
+	task->context_save_area_ea = mars_ptr_to_ea(memalign(
+		MARS_TASK_CONTEXT_SAVE_ALIGN, context_save_area_size));
+	if (!task->context_save_area_ea) {
+		ret = MARS_ERROR_MEMORY;
+		goto error_malloc_context_save_area;
+	}
+
+	/* copy the context save struct into allocated storage */
+	memcpy(mars_ea_to_ptr(task->context_save_unit_ea),
+		context_save_unit,
+		context_save_unit_count * MARS_TASK_CONTEXT_SAVE_UNIT_SIZE);
+
+done:
 	/* end process to add the task to the workload queue */
 	ret = mars_workload_queue_add_end(mars->workload_queue, workload_id);
-	if (ret != MARS_SUCCESS) {
-		mars_workload_queue_add_cancel(mars->workload_queue,
-			workload_id);
-		if (context_save_size)
-			free(mars_ea_to_ptr(task->context_save_ea));
-		return ret;
-	}
+	if (ret != MARS_SUCCESS)
+		goto error_workload_queue_add_end;
 
 	/* return id to caller */
 	*id_ret = task->id;
 
 	return MARS_SUCCESS;
+
+error_workload_queue_add_end:
+	free(mars_ea_to_ptr(task->context_save_area_ea));
+error_malloc_context_save_area:
+	free(mars_ea_to_ptr(task->context_save_unit_ea));
+error_malloc_context_save_unit:
+error_context_save_unit_addr_align:
+	mars_workload_queue_add_cancel(mars->workload_queue, workload_id);
+
+	return ret;
 }
 
 int mars_task_destroy(struct mars_task_id *id)
@@ -159,8 +203,8 @@ int mars_task_destroy(struct mars_task_i
 	task = (struct mars_task_context *)workload;
 
 	/* free the allocated task context area if it has one */
-	if (task->context_save_size)
-		free(mars_ea_to_ptr(task->context_save_ea));
+	if (task->context_save_area_ea)
+		free(mars_ea_to_ptr(task->context_save_area_ea));
 
 	/* end process to remove the task from the workload queue */
 	ret = mars_workload_queue_remove_end(mars->workload_queue,
--- a/src/mpu/kernel/kernel_task.c
+++ b/src/mpu/kernel/kernel_task.c
@@ -66,22 +66,66 @@ void task_exit(struct mars_task_context 
 
 void task_yield(struct mars_task_context *task)
 {
+	struct mars_task_context_save_unit
+		list[MARS_TASK_CONTEXT_SAVE_UNIT_MAX];
+	int i, offset = 0;
+
 	/* save workload stack pointer */
 	task->stack = (uint32_t)workload_stack;
 
-	/* dma context into context save area in host storage */
-	mars_dma_large_put_and_wait((void *)task->vaddr,
-		task->context_save_ea, task->context_save_size, MARS_DMA_TAG);
+	/* dma get context save unit list */
+	mars_dma_get_and_wait(list, task->context_save_unit_ea,
+		MARS_TASK_CONTEXT_SAVE_UNIT_SIZE *
+		MARS_TASK_CONTEXT_SAVE_UNIT_MAX, MARS_DMA_TAG);
+
+	/* loop through save unit list */
+	for (i = 0; i < MARS_TASK_CONTEXT_SAVE_UNIT_MAX; i++) {
+		/* list terminator so exit loop */
+		if (!list[i].size)
+			break;
+
+		/* request dma put of the context save unit specified */
+		mars_dma_large_put((void *)(task->vaddr + list[i].addr),
+			task->context_save_area_ea + offset,
+			list[i].size, MARS_DMA_TAG);
+
+		offset += list[i].size;
+	}
+
+	/* wait for all dmas to complete */
+	mars_dma_wait(MARS_DMA_TAG);
 }
 
 void task_resume(struct mars_task_context *task)
 {
+	struct mars_task_context_save_unit
+		list[MARS_TASK_CONTEXT_SAVE_UNIT_MAX];
+	int i, offset = 0;
+
 	/* restore workload stack pointer */
 	workload_stack = (void *)task->stack;
 
-	/* dma context to mpu storage from context save area in host storage */
-	mars_dma_large_get_and_wait((void *)task->vaddr,
-		task->context_save_ea, task->context_save_size, MARS_DMA_TAG);
+	/* dma save get context save unit list */
+	mars_dma_get_and_wait(list, task->context_save_unit_ea,
+		MARS_TASK_CONTEXT_SAVE_UNIT_SIZE *
+		MARS_TASK_CONTEXT_SAVE_UNIT_MAX, MARS_DMA_TAG);
+
+	/* loop through save unit list */
+	for (i = 0; i < MARS_TASK_CONTEXT_SAVE_UNIT_MAX; i++) {
+		/* list terminator so exit loop */
+		if (!list[i].size)
+			break;
+
+		/* request dma get of the context save unit specified */
+		mars_dma_large_get((void *)(task->vaddr + list[i].addr),
+			task->context_save_area_ea + offset,
+			list[i].size, MARS_DMA_TAG);
+
+		offset += list[i].size;
+	}
+
+	/* wait for all dmas to complete */
+	mars_dma_wait(MARS_DMA_TAG);
 }
 
 void task_schedule(struct mars_task_context *task, struct mars_task_args *args)
--- a/src/mpu/lib/task.c
+++ b/src/mpu/lib/task.c
@@ -61,7 +61,7 @@ int mars_task_yield(void)
 	task = (struct mars_task_context *)mars_get_workload();
 
 	/* make sure task context has a context save area */
-	if (!task->context_save_size || !task->context_save_ea)
+	if (!task->context_save_area_ea)
 		return MARS_ERROR_FORMAT;
 
 	mars_yield();
@@ -92,7 +92,7 @@ int mars_task_wait(struct mars_task_id *
 	task = (struct mars_task_context *)mars_get_workload();
 
 	/* make sure task context has a context save area */
-	if (!task->context_save_size || !task->context_save_ea)
+	if (!task->context_save_area_ea)
 		return MARS_ERROR_FORMAT;
 
 	ret = mars_wait(id->workload_id);
--- a/src/mpu/lib/task_barrier.c
+++ b/src/mpu/lib/task_barrier.c
@@ -59,7 +59,7 @@ int mars_task_barrier_notify(uint64_t ba
 	task = (struct mars_task_context *)mars_get_workload();
 
 	/* make sure task context has a context save area */
-	if (!task->context_save_size || !task->context_save_ea)
+	if (!task->context_save_area_ea)
 		return MARS_ERROR_FORMAT;
 
 	mars_mutex_lock_get(barrier_ea, (struct mars_mutex *)&barrier);
@@ -146,7 +146,7 @@ int mars_task_barrier_wait(uint64_t barr
 	task = (struct mars_task_context *)mars_get_workload();
 
 	/* make sure task context has a context save area */
-	if (!task->context_save_size || !task->context_save_ea)
+	if (!task->context_save_area_ea)
 		return MARS_ERROR_FORMAT;
 
 	mars_mutex_lock_get(barrier_ea, (struct mars_mutex *)&barrier);
--- a/src/mpu/lib/task_event_flag.c
+++ b/src/mpu/lib/task_event_flag.c
@@ -147,7 +147,7 @@ int mars_task_event_flag_wait(uint64_t e
 	task = (struct mars_task_context *)mars_get_workload();
 
 	/* make sure task context has a context save area */
-	if (!task->context_save_size || !task->context_save_ea)
+	if (!task->context_save_area_ea)
 		return MARS_ERROR_FORMAT;
 
 	mars_mutex_lock_get(event_flag_ea, (struct mars_mutex *)&event_flag);
--- a/src/mpu/lib/task_queue.c
+++ b/src/mpu/lib/task_queue.c
@@ -123,6 +123,8 @@ static void push_update(void)
 static int push(uint64_t queue_ea, const void *data,
 		int try, int begin, uint32_t tag)
 {
+	struct mars_task_context *task;
+
 	/* check function params */
 	if (!queue_ea)
 		return MARS_ERROR_NULL;
@@ -133,6 +135,13 @@ static int push(uint64_t queue_ea, const
 	if (tag > MARS_DMA_TAG_MAX)
 		return MARS_ERROR_PARAMS;
 
+	/* get task context */
+	task = (struct mars_task_context *)mars_get_workload();
+
+	/* make sure task context has a context save area */
+	if (!task->context_save_area_ea)
+		return MARS_ERROR_FORMAT;
+
 	mars_mutex_lock_get(queue_ea, (struct mars_mutex *)&queue);
 
 	/* check for valid direction */
@@ -275,7 +284,7 @@ static int pop(uint64_t queue_ea, void *
 	task = (struct mars_task_context *)mars_get_workload();
 
 	/* make sure task context has a context save area */
-	if (!task->context_save_size || !task->context_save_ea)
+	if (!task->context_save_area_ea)
 		return MARS_ERROR_FORMAT;
 
 	mars_mutex_lock_get(queue_ea, (struct mars_mutex *)&queue);
--- a/src/mpu/lib/task_semaphore.c
+++ b/src/mpu/lib/task_semaphore.c
@@ -61,7 +61,7 @@ int mars_task_semaphore_acquire(uint64_t
 	task = (struct mars_task_context *)mars_get_workload();
 
 	/* make sure task context has a context save area */
-	if (!task->context_save_size || !task->context_save_ea)
+	if (!task->context_save_area_ea)
 		return MARS_ERROR_FORMAT;
 
 	mars_mutex_lock_get(semaphore_ea, (struct mars_mutex *)&semaphore);
--- a/src/mpu/lib/task_signal.c
+++ b/src/mpu/lib/task_signal.c
@@ -58,7 +58,7 @@ int mars_task_signal_wait(void)
 	task = (struct mars_task_context *)mars_get_workload();
 
 	/* make sure task context has a context save area */
-	if (!task->context_save_size || !task->context_save_ea)
+	if (!task->context_save_area_ea)
 		return MARS_ERROR_FORMAT;
 
 	mars_signal_wait();






More information about the cbe-oss-dev mailing list