[Cbe-oss-dev] [PATCH 05/22]MARS/base: add callback system

Yuji Mano yuji.mano at am.sony.com
Fri Mar 20 07:53:59 EST 2009


This patch introduces new API that will allow workloads to call host callback
functions. The callback system is hooked into the scheduler and will schedule
out workloads from the MPUs while callbacks are being processed on the host.

Signed-off-by: Yuji Mano <yuji.mano at am.sony.com>
---
 base/include/common/mars/callback_types.h |   89 ++++++++
 base/include/mpu/mars/module.h            |   25 ++
 base/src/common/callback_internal_types.h |   59 +++++
 base/src/common/kernel_internal_types.h   |   19 +
 base/src/common/workload_internal_types.h |   12 +
 base/src/host/lib/Makefile.am             |    2 
 base/src/host/lib/callback_cell.c         |  310 ++++++++++++++++++++++++++++++
 base/src/host/lib/context.c               |   20 +
 base/src/host/lib/context_internal.h      |   21 +-
 base/src/mpu/kernel/kernel.c              |   91 ++++++++
 base/src/mpu/kernel/mutex.c               |    7 
 base/src/mpu/lib/Makefile.am              |    1 
 base/src/mpu/lib/module.c                 |   11 +
 13 files changed, 646 insertions(+), 21 deletions(-)

--- /dev/null
+++ b/base/include/common/mars/callback_types.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2008 Sony Corporation of America
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this Library and associated documentation files (the
+ * "Library"), to deal in the Library without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Library, and to
+ * permit persons to whom the Library is furnished to do so, subject to
+ * the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be
+ *  included in all copies or substantial portions of the Library.
+ *
+ *  If you modify the Library, you may copy and distribute your modified
+ *  version of the Library in object code or as an executable provided
+ *  that you also do one of the following:
+ *
+ *   Accompany the modified version of the Library with the complete
+ *   corresponding machine-readable source code for the modified version
+ *   of the Library; or,
+ *
+ *   Accompany the modified version of the Library with a written offer
+ *   for a complete machine-readable copy of the corresponding source
+ *   code of the modified version of the Library.
+ *
+ *
+ * THE LIBRARY IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * LIBRARY OR THE USE OR OTHER DEALINGS IN THE LIBRARY.
+ */
+
+#ifndef MARS_CALLBACK_TYPES_H
+#define MARS_CALLBACK_TYPES_H
+
+/**
+ * \file
+ * \ingroup group_mars_callback
+ * \brief <b>[host/MPU]</b> MARS Callback Types
+ */
+
+#include <stdint.h>
+
+/**
+ * \ingroup group_mars_callback
+ * \brief Size of callback args structure
+ */
+#define MARS_CALLBACK_ARGS_SIZE			48
+
+/**
+ * \ingroup group_mars_callback
+ * \brief Alignment of callback args structure
+ */
+#define MARS_CALLBACK_ARGS_ALIGN		16
+
+/**
+ * \ingroup group_mars_callback
+ * \brief MARS callback argument structure
+ *
+ * This structure is an arbitrary callback argument structure.
+ */
+struct mars_callback_args {
+	union {
+		/** array of 48 8-bit unsigned ints */
+		uint8_t  u8[48];
+		/** array of 24 16-bit unsigned ints */
+		uint16_t u16[24];
+		/** array of 12 32-bit unsigned ints */
+		uint32_t u32[12];
+		/** array of 6 64-bit unsigned ints */
+		uint64_t u64[6];
+	} type;
+} __attribute__((aligned(MARS_CALLBACK_ARGS_ALIGN)));
+
+/**
+ * \ingroup group_mars_callback
+ * \brief MARS callback function
+ *
+ * This is the type definition of the callback function.
+ */
+typedef int (*mars_callback)(
+	const struct mars_callback_args *in, struct mars_callback_args *out);
+
+#endif
--- a/base/include/mpu/mars/module.h
+++ b/base/include/mpu/mars/module.h
@@ -46,6 +46,7 @@
 
 #include <stdint.h>
 
+#include <mars/callback_types.h>
 #include <mars/mutex_types.h>
 #include <mars/workload_types.h>
 
@@ -290,6 +291,30 @@ int mars_module_host_signal_send(uint64_
 
 /**
  * \ingroup group_mars_workload_module
+ * \brief <b>[MPU]</b> Request host to call registered callback.
+ *
+ * \param[in] callback_ea	- ea of callback function
+ * \param[in] in		- pointer to input args in MPU storage
+ *
+ * \return
+ *	MARS_SUCCESS		- callback requested to host
+ */
+int mars_module_host_callback_set(uint64_t callback_ea,
+				  const struct mars_callback_args *in);
+
+/**
+ * \ingroup group_mars_workload_module
+ * \brief <b>[MPU]</b> Resets a host callback request and requests result.
+ *
+ * \param[out] out		- pointer to output args to store result
+ *
+ * \return
+ *	MARS_SUCCESS		- callback request reset
+ */
+int mars_module_host_callback_reset(struct mars_callback_args *out);
+
+/**
+ * \ingroup group_mars_workload_module
  * \brief <b>[MPU]</b> Locks a mutex.
  *
  * This function locks a mutex and blocks other requests to lock it.
--- /dev/null
+++ b/base/src/common/callback_internal_types.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008 Sony Corporation of America
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this Library and associated documentation files (the
+ * "Library"), to deal in the Library without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Library, and to
+ * permit persons to whom the Library is furnished to do so, subject to
+ * the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be
+ *  included in all copies or substantial portions of the Library.
+ *
+ *  If you modify the Library, you may copy and distribute your modified
+ *  version of the Library in object code or as an executable provided
+ *  that you also do one of the following:
+ *
+ *   Accompany the modified version of the Library with the complete
+ *   corresponding machine-readable source code for the modified version
+ *   of the Library; or,
+ *
+ *   Accompany the modified version of the Library with a written offer
+ *   for a complete machine-readable copy of the corresponding source
+ *   code of the modified version of the Library.
+ *
+ *
+ * THE LIBRARY IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * LIBRARY OR THE USE OR OTHER DEALINGS IN THE LIBRARY.
+ */
+
+#ifndef MARS_CALLBACK_INTERNAL_TYPES_H
+#define MARS_CALLBACK_INTERNAL_TYPES_H
+
+#define MARS_CALLBACK_QUEUE_SIZE	128		/* size of 128 bytes */
+#define MARS_CALLBACK_QUEUE_ALIGN	128		/* align to 128 bytes */
+#define MARS_CALLBACK_QUEUE_MAX		54		/* max depth of queue */
+
+#define MARS_CALLBACK_QUEUE_FLAG_NONE	0x0		/* no flag set */
+#define MARS_CALLBACK_QUEUE_FLAG_EXIT	0x1		/* exit flag */
+#define MARS_CALLBACK_QUEUE_FLAG_PUSH   0x2		/* push flag */
+
+/* 128 byte callback queue structure */
+struct mars_callback_queue {
+	uint32_t lock;
+	uint32_t flag;
+	uint32_t count;
+	uint32_t head;
+	uint32_t tail;
+	uint16_t workload_id[MARS_CALLBACK_QUEUE_MAX];
+} __attribute__((aligned(MARS_CALLBACK_QUEUE_ALIGN)));
+
+#endif
--- a/base/src/common/kernel_internal_types.h
+++ b/base/src/common/kernel_internal_types.h
@@ -42,6 +42,7 @@
 
 #include "mars/mutex_types.h"
 
+#include "callback_internal_types.h"
 #include "workload_internal_types.h"
 
 #define MARS_KERNEL_ID_NONE			0xffff
@@ -54,11 +55,11 @@
 #define MARS_KERNEL_TICKS_FLAG_SYNC_BEGIN	0x1
 #define MARS_KERNEL_TICKS_FLAG_SYNC_END		0x2
 
+#define MARS_KERNEL_DMA_TAG			31
+
 #define MARS_KERNEL_PARAMS_ALIGN		128
 #define MARS_KERNEL_PARAMS_SIZE			128
 
-#define MARS_KERNEL_DMA_TAG			31
-
 /* mars kernel syscalls */
 struct mars_kernel_syscalls {
 	uint32_t                       (*get_ticks)(void);
@@ -80,6 +81,9 @@ struct mars_kernel_syscalls {
 	int  (*workload_schedule_cancel)(uint16_t id);
 
 	int  (*host_signal_send)(uint64_t watch_point_ea);
+	int  (*host_callback_set)(uint64_t callback_ea,
+				  const struct mars_callback_args *in);
+	int  (*host_callback_reset)(struct mars_callback_args *out);
 
 	int  (*mutex_lock_get)(uint64_t mutex_ea, struct mars_mutex *mutex);
 	int  (*mutex_unlock_put)(uint64_t mutex_ea, struct mars_mutex *mutex);
@@ -98,22 +102,21 @@ struct mars_kernel_ticks {
 
 /* mars kernel parameters */
 struct mars_kernel_params {
-	uint64_t mars_context_ea;
-	uint64_t workload_queue_ea;
 	struct mars_kernel_ticks kernel_ticks;
 	uint16_t kernel_id;
-	uint8_t pad[MARS_KERNEL_PARAMS_SIZE - 26];
+	uint64_t mars_context_ea;
+	uint64_t workload_queue_ea;
+	uint64_t callback_queue_ea;
+	uint8_t pad[MARS_KERNEL_PARAMS_SIZE - 48];
 } __attribute__((aligned(MARS_KERNEL_PARAMS_ALIGN)));
 
 /* mars kernel buffer */
 union mars_kernel_buffer {
-	struct mars_mutex mutex;
+	struct mars_callback_queue callback_queue;
 	struct mars_workload_queue_header workload_queue_header;
 	struct mars_workload_queue_block workload_queue_block;
 };
 
-extern union mars_kernel_buffer kernel_buffer;
-
 /* mars kernel mutex */
 int mutex_lock_get(uint64_t mutex_ea, struct mars_mutex *mutex);
 int mutex_unlock_put(uint64_t mutex_ea, struct mars_mutex *mutex);
--- a/base/src/common/workload_internal_types.h
+++ b/base/src/common/workload_internal_types.h
@@ -40,6 +40,7 @@
 
 #include <stdint.h>
 
+#include "mars/callback_types.h"
 #include "mars/workload_types.h"
 
 #define MARS_WORKLOAD_STATE_NONE		0x00	/* workload undefined */
@@ -142,6 +143,9 @@
 #define MARS_WORKLOAD_MODULE_SIZE		64
 #define MARS_WORKLOAD_MODULE_ALIGN		16
 
+#define MARS_WORKLOAD_CALLBACK_SIZE		64
+#define MARS_WORKLOAD_CALLBACK_ALIGN		16
+
 /* 128 byte workload queue header structure */
 struct mars_workload_queue_header {
 	uint32_t lock;
@@ -178,4 +182,12 @@ struct mars_workload_module {
 	uint8_t name[MARS_WORKLOAD_MODULE_NAME_LEN_MAX + 1];
 } __attribute__((aligned(MARS_WORKLOAD_MODULE_ALIGN)));
 
+/* mars workload callback structure */
+struct mars_workload_callback {
+	struct mars_callback_args callback_args;
+	uint64_t callback_ea;
+	uint32_t callback_ret;
+	uint32_t pad;
+} __attribute__((aligned(MARS_WORKLOAD_CALLBACK_ALIGN)));
+
 #endif
--- a/base/src/host/lib/Makefile.am
+++ b/base/src/host/lib/Makefile.am
@@ -50,6 +50,7 @@ endif
 
 if MARS_PLATFORM_CELL
 MARS_PLATFORM_SPECIFIC_SOURCES = \
+	callback_cell.c \
 	cond_cell.c \
 	ea_cell.c \
 	host_mutex_linux.c \
@@ -63,6 +64,7 @@ endif
 MAINTAINERCLEANFILES = Makefile.in
 
 pkginclude_HEADERS = \
+	$(srcdir)/../../../include/common/mars/callback_types.h \
 	$(srcdir)/../../../include/common/mars/error.h \
 	$(srcdir)/../../../include/common/mars/mutex_types.h \
 	$(srcdir)/../../../include/common/mars/workload_types.h \
--- /dev/null
+++ b/base/src/host/lib/callback_cell.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2008 Sony Corporation of America
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this Library and associated documentation files (the
+ * "Library"), to deal in the Library without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Library, and to
+ * permit persons to whom the Library is furnished to do so, subject to
+ * the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be
+ *  included in all copies or substantial portions of the Library.
+ *
+ *  If you modify the Library, you may copy and distribute your modified
+ *  version of the Library in object code or as an executable provided
+ *  that you also do one of the following:
+ *
+ *   Accompany the modified version of the Library with the complete
+ *   corresponding machine-readable source code for the modified version
+ *   of the Library; or,
+ *
+ *   Accompany the modified version of the Library with a written offer
+ *   for a complete machine-readable copy of the corresponding source
+ *   code of the modified version of the Library.
+ *
+ *
+ * THE LIBRARY IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * LIBRARY OR THE USE OR OTHER DEALINGS IN THE LIBRARY.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "config.h"
+
+#include "mars/base.h"
+#include "mars/error.h"
+#include "mars/mutex.h"
+#include "mars/workload_queue.h"
+
+#include "callback_internal_types.h"
+#include "kernel_internal_types.h"
+#include "workload_internal_types.h"
+
+#include "context_internal.h"
+
+static inline uint64_t get_workload_ea(uint64_t queue_ea, int workload_id)
+{
+	uint64_t context_ea =
+		mars_ea_get_uint64(queue_ea +
+				   offsetof(struct mars_workload_queue_header,
+				   context_ea));
+
+	return context_ea + workload_id * MARS_WORKLOAD_CONTEXT_SIZE;
+}
+
+static void callback_process(struct mars_context *mars, uint16_t workload_id)
+{
+	uint64_t workload_callback_ea;
+	struct mars_workload_callback *workload_callback;
+	struct mars_callback_args out;
+
+	/* busy loop until workload is put into wait state */
+	while (!mars_workload_queue_query(mars, workload_id,
+					  MARS_WORKLOAD_QUERY_IS_WAITING)) {
+	}
+
+	/* get ea of workload callback structure */
+	workload_callback_ea =
+		get_workload_ea(mars->workload_queue_ea, workload_id) +
+		MARS_WORKLOAD_MODULE_SIZE;
+
+	/* prepare work area for queue */
+	workload_callback =
+		mars_ea_work_area_get(workload_callback_ea,
+				      MARS_WORKLOAD_CALLBACK_ALIGN,
+				      MARS_WORKLOAD_CALLBACK_SIZE);
+
+	/* get workload callback structure from ea */
+	mars_ea_get(workload_callback_ea, workload_callback,
+		    MARS_WORKLOAD_CALLBACK_SIZE);
+
+	/* call the callback and store the return value */
+	workload_callback->callback_ret =
+		((mars_callback)
+			mars_ea_to_ptr(workload_callback->callback_ea))
+				(&workload_callback->callback_args, &out);
+
+	/* copy output args back into callback structure */
+	workload_callback->callback_args = out;
+
+	/* update workload data on ea */
+	mars_ea_put(workload_callback_ea, workload_callback,
+		    MARS_WORKLOAD_CALLBACK_SIZE);
+}
+
+static int callback_queue_pop(uint64_t queue_ea, uint16_t *workload_id)
+{
+	struct mars_callback_queue *queue;
+
+	/* prepare work area for queue */
+	queue = mars_ea_work_area_get(queue_ea,
+				      MARS_CALLBACK_QUEUE_ALIGN,
+				      MARS_CALLBACK_QUEUE_SIZE);
+
+	/* lock the queue */
+	mars_mutex_lock_get(queue_ea, (struct mars_mutex *)queue);
+
+	/* queue is empty (false signal?) */
+	if (!queue->count) {
+		mars_mutex_unlock(queue_ea);
+		return MARS_ERROR_STATE;
+	}
+
+	/* get workload id from head of queue */
+	*workload_id = queue->workload_id[queue->head];
+
+	/* decrement count */
+	queue->count--;
+
+	/* increment head */
+	queue->head++;
+
+	/* wrap head to front of queue if necessary */
+	if (queue->head == MARS_CALLBACK_QUEUE_MAX)
+		queue->head = 0;
+
+	/* if queue is empty reset the queue flag */
+	if (!queue->count)
+		queue->flag = MARS_CALLBACK_QUEUE_FLAG_NONE;
+
+	/* unlock the queue */
+	mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)queue);
+
+	return MARS_SUCCESS;
+}
+
+static int callback_queue_state(uint32_t flag, void *param)
+{
+	(void)param;
+
+	/* exit flag is set so return */
+	switch (flag) {
+	case MARS_CALLBACK_QUEUE_FLAG_EXIT:
+		return MARS_ERROR_STATE;
+	case MARS_CALLBACK_QUEUE_FLAG_PUSH:
+		return MARS_SUCCESS;
+	default:
+		return -1;
+	}
+}
+
+static void *callback_handler_thread(void *arg)
+{
+	struct mars_context *mars = (struct mars_context *)arg;
+	uint64_t queue_ea = mars->callback_queue_ea;
+	uint16_t workload_id;
+	int ret;
+
+	while (1) {
+		/* wait until kernel requests callback processing */
+		ret = mars_ea_cond_wait(
+			queue_ea + offsetof(struct mars_callback_queue, flag),
+			callback_queue_state, NULL);
+		if (ret != MARS_SUCCESS)
+			break;
+
+		/* pop the workload id requesting callback */
+		ret = callback_queue_pop(queue_ea, &workload_id);
+		if (ret != MARS_SUCCESS)
+			continue;
+
+		/* process the callback requested by workload */
+		callback_process(mars, workload_id);
+
+		/* signal the workload for completion of callback */
+		mars_workload_queue_signal_send(mars, workload_id);
+	}
+
+	return (void *)(uintptr_t)MARS_SUCCESS;
+}
+
+int mars_callback_queue_create(struct mars_context *mars)
+{
+	int ret;
+	int i;
+	uint64_t queue_ea;
+	struct mars_callback_queue *queue;
+
+	/* check function params */
+	if (!mars)
+		return MARS_ERROR_NULL;
+	if (mars->callback_queue_ea)
+		return MARS_ERROR_STATE;
+
+	/* allocate queue instance */
+	queue_ea = mars_ea_memalign(MARS_CALLBACK_QUEUE_ALIGN,
+				    MARS_CALLBACK_QUEUE_SIZE);
+	if (!queue_ea)
+		return MARS_ERROR_MEMORY;
+
+	/* prepare work area for queue */
+	queue = mars_ea_work_area_get(queue_ea,
+				      MARS_CALLBACK_QUEUE_ALIGN,
+				      MARS_CALLBACK_QUEUE_SIZE);
+
+	/* initialize queue structure */
+	queue->flag = MARS_CALLBACK_QUEUE_FLAG_NONE;
+	queue->count = 0;
+	queue->head = 0;
+	queue->tail = 0;
+
+	for (i = 0; i < MARS_CALLBACK_QUEUE_MAX; i++)
+		queue->workload_id[i] = MARS_WORKLOAD_ID_NONE;
+
+	/* update queue on EA */
+	mars_ea_put(queue_ea, queue, MARS_CALLBACK_QUEUE_SIZE);
+
+	/* reset mutex portion of queue header */
+	mars_mutex_reset(queue_ea);
+
+	/* sync EA */
+	mars_ea_sync();
+
+	/* set the host callback queue instance in the mars context */
+	mars->callback_queue_ea = queue_ea;
+
+	/* create the host callback handler thread */
+	ret = pthread_create(&mars->callback_handler, NULL,
+			     callback_handler_thread, (void *)mars);
+	if (ret) {
+		mars_ea_free(queue_ea);
+		return MARS_ERROR_INTERNAL;
+	}
+
+	return MARS_SUCCESS;
+}
+
+int mars_callback_queue_destroy(struct mars_context *mars)
+{
+	int ret;
+	uint64_t queue_ea;
+	struct mars_callback_queue *queue;
+
+	/* check function params */
+	if (!mars)
+		return MARS_ERROR_NULL;
+	if (!mars->callback_queue_ea)
+		return MARS_ERROR_PARAMS;
+
+	queue_ea = mars->callback_queue_ea;
+
+	/* prepare work area for queue */
+	queue = mars_ea_work_area_get(mars->callback_queue_ea,
+				      MARS_CALLBACK_QUEUE_ALIGN,
+				      MARS_CALLBACK_QUEUE_SIZE);
+
+	/* get queue from ea */
+	mars_ea_get(queue_ea, queue, MARS_CALLBACK_QUEUE_SIZE);
+
+	/* make sure queue is empty */
+	if (queue->count)
+		return MARS_ERROR_STATE;
+
+	/* join the host callback handler thread */
+	ret = pthread_join(mars->callback_handler, NULL);
+	if (ret)
+		return MARS_ERROR_INTERNAL;
+
+	/* free host callback queue instance */
+	mars_ea_free(queue_ea);
+
+	/* set the workload queue to NULL for error checking */
+	mars->callback_queue_ea = 0;
+
+	return MARS_SUCCESS;
+}
+
+int mars_callback_queue_exit(struct mars_context *mars)
+{
+	uint64_t queue_ea;
+
+	/* check function params */
+	if (!mars)
+		return MARS_ERROR_NULL;
+	if (!mars->callback_queue_ea)
+		return MARS_ERROR_PARAMS;
+
+	queue_ea = mars->callback_queue_ea;
+
+	/* set callback queue exit flag */
+	mars_ea_put_uint32(
+		queue_ea + offsetof(struct mars_callback_queue, flag),
+		MARS_CALLBACK_QUEUE_FLAG_EXIT);
+
+	/* signal callback handler to wake up from wait */
+	mars_ea_cond_signal(
+		queue_ea + offsetof(struct mars_callback_queue, flag), 1);
+
+	return MARS_SUCCESS;
+}
--- a/base/src/host/lib/context.c
+++ b/base/src/host/lib/context.c
@@ -92,6 +92,7 @@ static int kernel_params_init(struct mar
 	params->kernel_id = kernel_id;
 	params->mars_context_ea = mars_ptr_to_ea(mars);
 	params->workload_queue_ea = mars->workload_queue_ea;
+	params->callback_queue_ea = mars->callback_queue_ea;
 
 	/* update params on EA */
 	mars_ea_put(params_ea, params, sizeof(struct mars_kernel_params));
@@ -223,6 +224,11 @@ int mars_context_create(struct mars_cont
 	if (ret != MARS_SUCCESS)
 		goto error_workload_queue_create;
 
+	/* create callback queue */
+	ret = mars_callback_queue_create(mars);
+	if (ret != MARS_SUCCESS)
+		goto error_callback_queue_create;
+
 	/* create mpu contexts */
 	ret = mpu_contexts_create(mars, num_mpus);
 	if (ret != MARS_SUCCESS)
@@ -249,6 +255,8 @@ done:
 error_shared_context_unlock:
 	mpu_contexts_destroy(mars);
 error_mpu_contexts_create:
+	mars_callback_queue_destroy(mars);
+error_callback_queue_create:
 	mars_workload_queue_destroy(mars);
 error_workload_queue_create:
 	mars_free(mars->mpu_contexts);
@@ -287,6 +295,11 @@ int mars_context_destroy(struct mars_con
 	if (ret != MARS_SUCCESS)
 		return ret;
 
+	/* shutdown the callback queue so callback handler threads exit */
+	ret = mars_callback_queue_exit(mars);
+	if (ret != MARS_SUCCESS)
+		return ret;
+
 	/* destroy mpu contexts */
 	if (mars->mpu_context_count) {
 		ret = mpu_contexts_destroy(mars);
@@ -294,6 +307,13 @@ int mars_context_destroy(struct mars_con
 			goto error;
 	}
 
+	/* destroy callback queue */
+	if (mars->callback_queue_ea) {
+		ret = mars_callback_queue_destroy(mars);
+		if (ret != MARS_SUCCESS)
+			goto error;
+	}
+
 	/* destroy workload queue */
 	if (mars->workload_queue_ea) {
 		ret = mars_workload_queue_destroy(mars);
--- a/base/src/host/lib/context_internal.h
+++ b/base/src/host/lib/context_internal.h
@@ -52,19 +52,24 @@ typedef pthread_t mars_mpu_context_t;
 
 #ifdef HAVE_LIBPTHREAD
 typedef pthread_mutex_t mars_host_mutex_t;
+typedef pthread_t mars_callback_t;
 #endif
 
 struct mars_context {
 	/* parameters for the MARS kernel */
 	uint64_t kernel_params_ea;
-	/* process queue where process requests are added */
+	/* workload queue where workloads are added */
 	uint64_t workload_queue_ea;
-	/* array of mpu context threads */
-	mars_mpu_context_t *mpu_contexts;
-	/* num of mpu context threads */
-	uint32_t mpu_context_count;
+	/* callback queue where host callback requests are added */
+	uint64_t callback_queue_ea;
 	/* reference count */
 	uint32_t reference_count;
+	/* num of mpu context threads */
+	uint32_t mpu_context_count;
+	/* array of mpu contexts */
+	mars_mpu_context_t *mpu_contexts;
+	/* callback handler */
+	mars_callback_t callback_handler;
 };
 
 int mars_mpu_max(int *num);
@@ -79,9 +84,13 @@ int mars_workload_queue_create(struct ma
 int mars_workload_queue_destroy(struct mars_context *mars);
 int mars_workload_queue_exit(struct mars_context *mars);
 
-extern mars_host_mutex_t mars_shared_context_lock;
+int mars_callback_queue_create(struct mars_context *mars);
+int mars_callback_queue_destroy(struct mars_context *mars);
+int mars_callback_queue_exit(struct mars_context *mars);
 
 int mars_host_mutex_lock(mars_host_mutex_t *mutex);
 int mars_host_mutex_unlock(mars_host_mutex_t *mutex);
 
+extern mars_host_mutex_t mars_shared_context_lock;
+
 #endif
--- a/base/src/mpu/kernel/kernel.c
+++ b/base/src/mpu/kernel/kernel.c
@@ -44,12 +44,14 @@
 #include "mars/error.h"
 #include "mars/module.h"
 
+#include "callback_internal_types.h"
 #include "kernel_internal_types.h"
 #include "workload_internal_types.h"
 
 /* kernel */
 union mars_kernel_buffer kernel_buffer;
 static struct mars_kernel_params kernel_params;
+static uint64_t kernel_params_ea;
 
 /* workload queue */
 static struct mars_workload_queue_header queue_header;
@@ -514,6 +516,84 @@ static int host_signal_send(uint64_t wat
 	return MARS_SUCCESS;
 }
 
+static int host_callback_queue_push(void)
+{
+	uint64_t queue_ea = kernel_params.callback_queue_ea;
+	struct mars_callback_queue *queue = &kernel_buffer.callback_queue;
+
+	/* lock the queue */
+	mutex_lock_get(queue_ea, (struct mars_mutex *)queue);
+
+	/* check if queue is full */
+	if (queue->count == MARS_CALLBACK_QUEUE_MAX) {
+		mutex_unlock_put(queue_ea, (struct mars_mutex *)queue);
+		return MARS_ERROR_LIMIT;
+	}
+
+	/* set the push flag to signal host of new item */
+	queue->flag = MARS_CALLBACK_QUEUE_FLAG_PUSH;
+
+	/* put workload id at tail of queue */
+	queue->workload_id[queue->tail] = workload_id;
+
+	/* increment count */
+	queue->count++;
+
+	/* increment tail */
+	queue->tail++;
+
+	/* wrap tail to front of queue if necessary */
+	if (queue->tail == MARS_CALLBACK_QUEUE_MAX)
+		queue->tail = 0;
+
+	/* unlock the queue */
+	mutex_unlock_put(queue_ea, (struct mars_mutex *)queue);
+
+	return MARS_SUCCESS;
+}
+
+static int host_callback_set(uint64_t callback_ea,
+			     const struct mars_callback_args *in)
+{
+	int ret;
+	struct mars_workload_callback *callback =
+		(struct mars_workload_callback *)
+			((void *)&workload + MARS_WORKLOAD_MODULE_SIZE);
+
+	/* set the callback function pointer into workload callback area */
+	callback->callback_ea = callback_ea;
+
+	/* input args specified so copy into workload data area */
+	if (in)
+		kernel_memcpy(&callback->callback_args, in,
+			      MARS_CALLBACK_ARGS_SIZE);
+
+	/* push workload id to callback queue */
+	ret = host_callback_queue_push();
+	if (ret != MARS_SUCCESS)
+		return ret;
+
+	/* notify host to process callback */
+	host_signal_send(kernel_params.callback_queue_ea +
+			 offsetof(struct mars_callback_queue, flag));
+
+	return MARS_SUCCESS;
+}
+
+static int host_callback_reset(struct mars_callback_args *out)
+{
+	struct mars_workload_callback *callback =
+		(struct mars_workload_callback *)
+			((void *)&workload + MARS_WORKLOAD_MODULE_SIZE);
+
+	/* output requested so dma from workload data area */
+	if (out)
+		kernel_memcpy(out, &callback->callback_args,
+			      MARS_CALLBACK_ARGS_SIZE);
+
+	return callback->callback_ret;
+}
+
 static struct mars_kernel_syscalls kernel_syscalls =
 {
 	get_ticks,
@@ -532,6 +612,8 @@ static struct mars_kernel_syscalls kerne
 	workload_schedule_end,
 	workload_schedule_cancel,
 	host_signal_send,
+	host_callback_set,
+	host_callback_reset,
 	mutex_lock_get,
 	mutex_unlock_put,
 	dma_get,
@@ -870,7 +952,7 @@ static void scheduler_idle_wait(void)
 	spu_write_event_ack(MFC_LLR_LOST_EVENT);
 }
 
-static void get_params(uint64_t kernel_params_ea)
+static void get_params(void)
 {
 	int mask;
 
@@ -922,14 +1004,15 @@ static void get_params(uint64_t kernel_p
 	spu_write_event_ack(MFC_LLR_LOST_EVENT);
 }
 
-int main(unsigned long long mpu_context_id,
-	 unsigned long long kernel_params_ea)
+int main(uint64_t mpu_context_id, uint64_t params_ea)
 {
 	(void)mpu_context_id;
 
 	int exit_flag = 0;
 
-	get_params(kernel_params_ea);
+	kernel_params_ea = params_ea;
+
+	get_params();
 
 	while (!exit_flag) {
 		int status = scheduler();
--- a/base/src/mpu/kernel/mutex.c
+++ b/base/src/mpu/kernel/mutex.c
@@ -46,6 +46,8 @@
 #define MARS_MUTEX_STATE_NONE	0
 #define MARS_MUTEX_STATE_DONE	2
 
+static struct mars_mutex mutex_buffer;
+
 int mutex_lock_get(uint64_t mutex_ea, struct mars_mutex *mutex)
 {
 	int mask;
@@ -110,7 +112,6 @@ int mutex_lock_get(uint64_t mutex_ea, st
 int mutex_unlock_put(uint64_t mutex_ea, struct mars_mutex *mutex)
 {
 	int status, mask;
-	struct mars_mutex *mutex_buffer = &kernel_buffer.mutex;
 
 	/* check function params */
 	if (!mutex_ea)
@@ -133,10 +134,10 @@ int mutex_unlock_put(uint64_t mutex_ea, 
 	spu_write_event_mask(MFC_LLR_LOST_EVENT);
 
 	do {
-		mfc_getllar(mutex_buffer, mutex_ea, 0, 0);
+		mfc_getllar(&mutex_buffer, mutex_ea, 0, 0);
 		mfc_read_atomic_status();
 
-		mutex->status = mutex_buffer->status;
+		mutex->status = mutex_buffer.status;
 		mutex->status.lock = MARS_MUTEX_UNLOCKED;
 
 		spu_dsync();
--- a/base/src/mpu/lib/Makefile.am
+++ b/base/src/mpu/lib/Makefile.am
@@ -57,6 +57,7 @@ endif
 MAINTAINERCLEANFILES = Makefile.in
 
 pkginclude_HEADERS = \
+	$(srcdir)/../../../include/common/mars/callback_types.h \
 	$(srcdir)/../../../include/common/mars/error.h \
 	$(srcdir)/../../../include/common/mars/mutex_types.h \
 	$(srcdir)/../../../include/common/mars/workload_types.h \
--- a/base/src/mpu/lib/module.c
+++ b/base/src/mpu/lib/module.c
@@ -155,6 +155,17 @@ int mars_module_host_signal_send(uint64_
 	return (*kernel_syscalls->host_signal_send)(watch_point_ea);
 }
 
+int mars_module_host_callback_set(uint64_t callback_ea,
+				  const struct mars_callback_args *in)
+{
+	return (*kernel_syscalls->host_callback_set)(callback_ea, in);
+}
+
+int mars_module_host_callback_reset(struct mars_callback_args *out)
+{
+	return (*kernel_syscalls->host_callback_reset)(out);
+}
+
 int mars_module_mutex_lock_get(uint64_t mutex_ea, struct mars_mutex *mutex)
 {
 	return (*kernel_syscalls->mutex_lock_get)(mutex_ea, mutex);






More information about the cbe-oss-dev mailing list