[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