summaryrefslogtreecommitdiff
path: root/cesar/bufmgr
diff options
context:
space:
mode:
authorIPMbox Team2012-02-03 14:32:28 +0100
committerNicolas Schodet2012-02-20 10:08:46 +0100
commit3ed571f9d933e5c5dadef650c07e20e8aad06213 (patch)
tree761bfe80d4660605e00f52afb8532d9a2ef847b6 /cesar/bufmgr
parent89328e8cc096f8c9f340a3eb8910d06748a3e572 (diff)
cesar, cleopatre, common: new ipmbox design, closes #848
Diffstat (limited to 'cesar/bufmgr')
-rw-r--r--cesar/bufmgr/Module4
-rw-r--r--cesar/bufmgr/bufmgr.h96
-rw-r--r--cesar/bufmgr/inc/context.h69
-rw-r--r--cesar/bufmgr/inc/trace.h56
-rw-r--r--cesar/bufmgr/src/bufmgr.c180
-rw-r--r--cesar/bufmgr/src/trace.c42
-rw-r--r--cesar/bufmgr/stub/Module1
-rw-r--r--cesar/bufmgr/stub/src/bufmgr.c76
-rw-r--r--cesar/bufmgr/test/utest/Config1
-rw-r--r--cesar/bufmgr/test/utest/Makefile11
-rw-r--r--cesar/bufmgr/test/utest/inc/scenario_defs.h84
-rw-r--r--cesar/bufmgr/test/utest/inc/test_bufmgr.h20
-rw-r--r--cesar/bufmgr/test/utest/src/bufmgr.c260
-rw-r--r--cesar/bufmgr/test/utest/src/ipmbox.c48
-rw-r--r--cesar/bufmgr/test/utest/src/scenario_defs.c90
15 files changed, 1038 insertions, 0 deletions
diff --git a/cesar/bufmgr/Module b/cesar/bufmgr/Module
new file mode 100644
index 0000000000..7054f922ce
--- /dev/null
+++ b/cesar/bufmgr/Module
@@ -0,0 +1,4 @@
+SOURCES := bufmgr.c
+ifeq ($(CONFIG_TRACE),y)
+SOURCES += trace.c
+endif
diff --git a/cesar/bufmgr/bufmgr.h b/cesar/bufmgr/bufmgr.h
new file mode 100644
index 0000000000..b4cf912fd0
--- /dev/null
+++ b/cesar/bufmgr/bufmgr.h
@@ -0,0 +1,96 @@
+#ifndef bufmgr_bufmgr_h
+#define bufmgr_bufmgr_h
+
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file bufmgr/bufmgr.h
+ * \brief Public interfaces for buffer manager.
+ * \ingroup bufmgr
+ *
+ * The buffer manager is responsible for passing empty buffers coming from
+ * Linux to other cesar components and returning used buffers from those
+ * components to Linux.
+ *
+ * Buffer manager is responsible for informing clients after a try get that
+ * new buffers are available. For that, clients must register.
+ */
+#include "hal/ipmbox/ipmbox.h"
+
+/* Forward declaration. */
+typedef struct bufmgr_t bufmgr_t;
+
+/**
+ * Callback prototype.
+ * \param user_data the user_data to give with the callback
+ */
+typedef void (*bufmgr_callback_t) (void *user_data);
+
+BEGIN_DECLS
+
+/**
+ * Get a buffer from the buffer manager.
+ * \param ctx module context
+ * \return a buffer, NULL if none available
+ */
+u8 *
+bufmgr_get (bufmgr_t *ctx);
+
+/**
+ * Get a buffer from the buffer manager and wait it for a certain delay or
+ * until it gets it.
+ * \param ctx module context
+ * \param delay_ms delay of wait in ms, 0 if client wants to wait forever
+ * \return a buffer, NULL if no buffer available and the delay expired
+ */
+u8 *
+bufmgr_get_wait (bufmgr_t *ctx, uint delay_rtc);
+
+/**
+ * Give back a buffer.
+ * \param ctx module context
+ * \param buffer buffer to return
+ */
+void
+bufmgr_give_back (bufmgr_t *ctx, u8 *buffer);
+
+/**
+ * Give the buffer to buffer manager to keep it.
+ * \param ctx module context
+ * \param buffer buffer to return
+ */
+void
+bufmgr_keep_buffer (bufmgr_t *ctx, u8 *buffer);
+
+/**
+ * Register a client to the buffer manager.
+ * \param ctx module context
+ * \param cb the callback to call
+ * \param user_data the user data to provide
+ */
+void
+bufmgr_client_register (bufmgr_t *ctx, bufmgr_callback_t cb, void *user_data);
+
+/**
+ * Initialise the module.
+ * \param ipmbox the ipmbox context
+ * \return buffer manager context
+ */
+bufmgr_t *
+bufmgr_init (ipmbox_t *ipmbox);
+
+/**
+ * Uninitialise the module.
+ * \param ctx module context
+ */
+void
+bufmgr_uninit (bufmgr_t *ctx);
+
+END_DECLS
+
+#endif /* bufmgr_bufmgr_h */
diff --git a/cesar/bufmgr/inc/context.h b/cesar/bufmgr/inc/context.h
new file mode 100644
index 0000000000..1f2d59e75c
--- /dev/null
+++ b/cesar/bufmgr/inc/context.h
@@ -0,0 +1,69 @@
+#ifndef bufmgr_inc_context_h
+#define bufmgr_inc_context_h
+
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file bufmgr/inc/context.h
+ * \brief Buffer manager context structure definition.
+ * \ingroup bufmgr
+ */
+#include "common/ipmbox/protocol.h"
+#include "hal/ipmbox/ipmbox.h"
+#include "hal/arch/sem.h"
+
+#include "bufmgr/inc/trace.h"
+
+/* Size of the local buffer list. */
+#define BUFMGR_BUFFER_LIST_SIZE \
+ (IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_EMPTY_BUF / 2)
+
+/* Number of required local buffers in local list.
+ * The list is bigger to store empty buffers received from the PLC to the CP.
+ * Those buffers are empty buffers given by linux and must be kept in the
+ * buffer manager. */
+#define BUFMGR_BUFFER_LIST_NB (BUFMGR_BUFFER_LIST_SIZE / 2)
+
+/* Number of buffer reserved for blocking clients. */
+#define BUFMGR_RESERVED_BUFFER_NB 4
+
+/* Number of registered clients. */
+#define BUFMGR_CLIENT_NB 5
+
+/* Client callback. */
+struct bufmgr_client_t
+{
+ /** Callback. */
+ bufmgr_callback_t cb;
+ /** User data. */
+ void *user_data;
+};
+typedef struct bufmgr_client_t bufmgr_client_t;
+
+/* Context structure. */
+struct bufmgr_t
+{
+ /* IPMbox context. */
+ ipmbox_t *ipmbox;
+ /** Table of client callback. */
+ bufmgr_client_t client[BUFMGR_CLIENT_NB];
+ /** Number of clients registered. */
+ uint client_nb;
+ /** List of buffers. */
+ u32 buffers [BUFMGR_BUFFER_LIST_SIZE];
+ /** Number of available buffers. */
+ uint buffers_nb;
+ /** Semaphore for reserved buffers. */
+ hal_arch_sem_t sem;
+#if CONFIG_TRACE
+ /** Buffer Manager Trace */
+ trace_buffer_t trace;
+#endif
+};
+
+#endif /*bufmgr_inc_context_h*/
diff --git a/cesar/bufmgr/inc/trace.h b/cesar/bufmgr/inc/trace.h
new file mode 100644
index 0000000000..bb9600eb92
--- /dev/null
+++ b/cesar/bufmgr/inc/trace.h
@@ -0,0 +1,56 @@
+#ifndef bufmgr_inc_trace_h
+#define bufmgr_inc_trace_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file cesar/bufmgr/inc/trace.h
+ * \brief Buffer manager traces.
+ * \ingroup bufmgr
+ */
+
+#include "lib/trace.h"
+
+/** Shortcut for tracing inside buffer manager . */
+#define BUFMGR_TRACE(id, args...) \
+ TRACE_FAST_SHORT (BUFMGR_TRACE_, &ctx->trace, id, ## args)
+
+#if CONFIG_TRACE
+
+enum
+{
+ BUFMGR_TRACE_BUFFER_GET,
+ BUFMGR_TRACE_BUFFER_GET_WAIT,
+ BUFMGR_TRACE_BUFFER_GIVE_BACK,
+ BUFMGR_TRACE_BUFFER_NEW,
+ BUFMGR_TRACE_BUFFER_KEEP,
+};
+
+/**
+ * Initialize the trace system
+ * \param ctx the bufmgr context.
+ */
+void
+bufmgr_trace_init (bufmgr_t *ctx);
+
+/**
+ * Uninitialise the trace system
+ * \param ctx the bufmgr context
+ */
+void
+bufmgr_trace_uninit (bufmgr_t *ctx);
+
+END_DECLS
+
+#else /* !CONFIG_TRACE */
+
+#define bufmgr_trace_init(ctx) ((void) 0)
+#define bufmgr_trace_uninit(ctx) ((void) 0)
+
+#endif /* !CONFIG_TRACE */
+
+#endif /* bufmgr_inc_trace_h */
diff --git a/cesar/bufmgr/src/bufmgr.c b/cesar/bufmgr/src/bufmgr.c
new file mode 100644
index 0000000000..73ff9d8e7b
--- /dev/null
+++ b/cesar/bufmgr/src/bufmgr.c
@@ -0,0 +1,180 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file bufmgr/src/bufmgr.c
+ * \brief Buffer Manager
+ * \ingroup bufmgr
+ */
+#include "common/std.h"
+
+#include "common/ipmbox/msg.h"
+
+#include "hal/ipmbox/ipmbox.h"
+
+#include "bufmgr/bufmgr.h"
+#include "bufmgr/inc/context.h"
+#include "bufmgr/inc/trace.h"
+
+static bufmgr_t bufmgr_global;
+
+/**
+ * Fill buffer cache table.
+ * \param ctx module context
+ *
+ * Must be called DSR locked.
+ */
+PRIVATE inline void
+bufmgr_fill_cache (bufmgr_t *ctx)
+{
+ /* This is OK as DSR is locked. */
+ uint reserved_buf_nb = hal_arch_sem_peek (&ctx->sem);
+ uint missing_reserved_buffers = BUFMGR_RESERVED_BUFFER_NB
+ - reserved_buf_nb;
+ if (ctx->buffers_nb < BUFMGR_BUFFER_LIST_NB)
+ {
+ uint nb_got = ipmbox_empty_buf_get (
+ ctx->ipmbox, &ctx->buffers[ctx->buffers_nb],
+ BUFMGR_BUFFER_LIST_NB - ctx->buffers_nb);
+ ctx->buffers_nb += nb_got;
+ }
+ /* Try to convert cached buffers into reserved buffers. */
+ missing_reserved_buffers =
+ MIN (missing_reserved_buffers, ctx->buffers_nb - reserved_buf_nb);
+ for ( ; missing_reserved_buffers; missing_reserved_buffers--)
+ hal_arch_sem_post (&ctx->sem);
+}
+
+u8 *
+bufmgr_get (bufmgr_t *ctx)
+{
+ dbg_claim (ctx);
+ u8 *buffer = NULL;
+ arch_dsr_lock ();
+ if (ctx->buffers_nb <= BUFMGR_RESERVED_BUFFER_NB)
+ bufmgr_fill_cache (ctx);
+ /* Give a buffer is possible. */
+ if (ctx->buffers_nb > BUFMGR_RESERVED_BUFFER_NB)
+ {
+ buffer = (u8 *) ctx->buffers[ctx->buffers_nb - 1];
+ ctx->buffers_nb--;
+ }
+ BUFMGR_TRACE (BUFFER_GET, buffer);
+ arch_dsr_unlock ();
+ return buffer;
+}
+
+static inline u8 *
+bufmgr_reserved_get (bufmgr_t *ctx)
+{
+ u8 *buffer = NULL;
+ arch_dsr_lock ();
+ buffer = (u8 *) ctx->buffers[ctx->buffers_nb - 1];
+ ctx->buffers_nb--;
+ arch_dsr_unlock ();
+ return buffer;
+}
+
+u8 *
+bufmgr_get_wait (bufmgr_t *ctx, uint delay_rtc)
+{
+ u8 *buffer = NULL;
+ do
+ {
+ buffer = bufmgr_get (ctx);
+ if (buffer)
+ break;
+ if (delay_rtc)
+ {
+ if (hal_arch_sem_timed_wait (&ctx->sem, delay_rtc))
+ buffer = bufmgr_reserved_get (ctx);
+ break;
+ }
+ else
+ {
+ hal_arch_sem_wait (&ctx->sem);
+ buffer = bufmgr_reserved_get (ctx);
+ }
+ } while (!buffer);
+ BUFMGR_TRACE (BUFFER_GET_WAIT, buffer, delay_rtc);
+ return buffer;
+}
+
+void
+bufmgr_give_back (bufmgr_t *ctx, u8 *buffer)
+{
+ dbg_claim (ctx);
+ dbg_claim (buffer);
+ BUFMGR_TRACE (BUFFER_GIVE_BACK, buffer);
+ ipmbox_msg_empty_buf_t msg = { .buffer_addr = (u32) buffer };
+ ipmbox_tx_empty_buf (ctx->ipmbox, (u32 *) &msg,
+ IPMBOX_MSG_EMPTY_BUF_WORDS);
+}
+
+void
+bufmgr_keep_buffer (bufmgr_t *ctx, u8 *buffer)
+{
+ dbg_claim (ctx);
+ dbg_claim (buffer);
+ arch_dsr_lock ();
+ BUFMGR_TRACE (BUFFER_KEEP, buffer);
+ dbg_assert (ctx->buffers_nb < BUFMGR_BUFFER_LIST_SIZE);
+ ctx->buffers[ctx->buffers_nb] = (u32) buffer;
+ ctx->buffers_nb++;
+ if (hal_arch_sem_peek (&ctx->sem) < BUFMGR_RESERVED_BUFFER_NB)
+ hal_arch_sem_post (&ctx->sem);
+ arch_dsr_unlock ();
+}
+
+/**
+ * Call each client that has asked to be recalled on a lack of buffers.
+ * \param ctx module context
+ */
+static void
+bufmgr_handle_new_buf (bufmgr_t *ctx)
+{
+ uint i;
+ bufmgr_fill_cache (ctx);
+ /* Call each registered client's callback. */
+ for (i = 0; i < ctx->client_nb; i++)
+ ctx->client[i].cb (ctx->client[i].user_data);
+ BUFMGR_TRACE (BUFFER_NEW);
+}
+
+void
+bufmgr_client_register (bufmgr_t *ctx, bufmgr_callback_t cb, void *user_data)
+{
+ dbg_assert (ctx);
+ dbg_assert (cb);
+ dbg_assert (ctx->client_nb < BUFMGR_CLIENT_NB);
+ ctx->client[ctx->client_nb].cb = cb;
+ ctx->client[ctx->client_nb].user_data = user_data;
+ ctx->client_nb++;
+}
+
+bufmgr_t *
+bufmgr_init (ipmbox_t *ipmbox)
+{
+ bufmgr_t *ctx = &bufmgr_global;
+ ctx->ipmbox = ipmbox;
+ ctx->client_nb = 0;
+ ctx->buffers_nb = 0;
+ hal_arch_sem_init (&ctx->sem, 0);
+ /* Register a callback for empty_buf IT. */
+ ipmbox_register_empty_buf_cb (ipmbox, ctx,
+ (ipmbox_empty_buf_cb_t) bufmgr_handle_new_buf);
+ bufmgr_trace_init (ctx);
+ return ctx;
+}
+
+void
+bufmgr_uninit (bufmgr_t *ctx)
+{
+ dbg_assert (ctx);
+ ctx->client_nb = 0;
+ ctx->buffers_nb = 0;
+}
diff --git a/cesar/bufmgr/src/trace.c b/cesar/bufmgr/src/trace.c
new file mode 100644
index 0000000000..54b3f549ad
--- /dev/null
+++ b/cesar/bufmgr/src/trace.c
@@ -0,0 +1,42 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file bufmgr/src/trace.c
+ * \brief Buffer manager traces.
+ * \ingroup bufmgr
+ */
+#include "common/std.h"
+#include "bufmgr/bufmgr.h"
+#include "bufmgr/inc/trace.h"
+#include "bufmgr/inc/context.h"
+
+void
+bufmgr_trace_init (bufmgr_t *ctx)
+{
+ static trace_namespace_t namespace;
+ static const trace_event_id_t event_ids[] =
+ {
+ TRACE_EVENT (BUFMGR_TRACE_BUFFER_GET, "Buffer get %x"),
+ TRACE_EVENT (BUFMGR_TRACE_BUFFER_GET_WAIT,
+ "Buffer get wait %x delay_rtc %d"),
+ TRACE_EVENT (BUFMGR_TRACE_BUFFER_GIVE_BACK,
+ "Buffer give back %x"),
+ TRACE_EVENT (BUFMGR_TRACE_BUFFER_NEW, "new buffers"),
+ TRACE_EVENT (BUFMGR_TRACE_BUFFER_KEEP, "Buffer keep %x"),
+ };
+ dbg_assert (ctx);
+ trace_namespace_init (&namespace, event_ids, COUNT (event_ids));
+ trace_buffer_add (&ctx->trace, "bufmgr", 8, 4, true, &namespace);
+}
+
+void
+bufmgr_trace_uninit (bufmgr_t *ctx)
+{
+ dbg_assert (ctx);
+ trace_buffer_remove (&ctx->trace);
+}
diff --git a/cesar/bufmgr/stub/Module b/cesar/bufmgr/stub/Module
new file mode 100644
index 0000000000..d4846f1daf
--- /dev/null
+++ b/cesar/bufmgr/stub/Module
@@ -0,0 +1 @@
+SOURCES := bufmgr.c \ No newline at end of file
diff --git a/cesar/bufmgr/stub/src/bufmgr.c b/cesar/bufmgr/stub/src/bufmgr.c
new file mode 100644
index 0000000000..fd61d8725d
--- /dev/null
+++ b/cesar/bufmgr/stub/src/bufmgr.c
@@ -0,0 +1,76 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file bufmgr/stub/src/bufmgr.c
+ * \brief Buffer Manager stub functions
+ * \ingroup bufmgr_stub
+ */
+#include "common/std.h"
+
+#include "bufmgr/bufmgr.h"
+
+u8*
+bufmgr_get (bufmgr_t *ctx) __attribute__((weak));
+
+u8*
+bufmgr_get (bufmgr_t *ctx)
+{
+ return NULL;
+}
+
+u8*
+bufmgr_get_wait (bufmgr_t *ctx, uint delay_rtc) __attribute__((weak));
+
+u8*
+bufmgr_get_wait (bufmgr_t *ctx, uint delay_rtc)
+{
+ return NULL;
+}
+
+void
+bufmgr_give_back (bufmgr_t *ctx, u8 *buffer) __attribute__((weak));
+
+void
+bufmgr_give_back (bufmgr_t *ctx, u8 *buffer)
+{
+}
+
+void
+bufmgr_client_register (bufmgr_t *ctx, bufmgr_callback_t cb,
+ void *user_data) __attribute__((weak));
+
+void
+bufmgr_client_register (bufmgr_t *ctx, bufmgr_callback_t cb,
+ void *user_data)
+{
+}
+
+bufmgr_t*
+bufmgr_init (ipmbox_t *ipmbox) __attribute__((weak));
+
+bufmgr_t*
+bufmgr_init (ipmbox_t *ipmbox)
+{
+ return NULL;
+}
+
+void
+bufmgr_uninit (bufmgr_t *ctx) __attribute__((weak));
+
+void
+bufmgr_uninit (bufmgr_t *ctx)
+{
+}
+
+void
+bufmgr_keep_buffer (bufmgr_t *ctx, u8 *buffer) __attribute__((weak));
+
+void
+bufmgr_keep_buffer (bufmgr_t *ctx, u8 *buffer)
+{
+}
diff --git a/cesar/bufmgr/test/utest/Config b/cesar/bufmgr/test/utest/Config
new file mode 100644
index 0000000000..dbdade324f
--- /dev/null
+++ b/cesar/bufmgr/test/utest/Config
@@ -0,0 +1 @@
+CONFIG_DEBUG_FATAL_CATCH=y
diff --git a/cesar/bufmgr/test/utest/Makefile b/cesar/bufmgr/test/utest/Makefile
new file mode 100644
index 0000000000..e3ece7526e
--- /dev/null
+++ b/cesar/bufmgr/test/utest/Makefile
@@ -0,0 +1,11 @@
+BASE = ../../..
+
+INCLUDES = bufmgr bufmgr/test/utest
+
+DEFS=-DNO_PRIVATE
+
+HOST_PROGRAMS = test_bufmgr
+test_bufmgr_SOURCES = bufmgr.c ipmbox.c scenario_defs.c
+test_bufmgr_MODULES = lib lib/scenario bufmgr
+
+include $(BASE)/common/make/top.mk
diff --git a/cesar/bufmgr/test/utest/inc/scenario_defs.h b/cesar/bufmgr/test/utest/inc/scenario_defs.h
new file mode 100644
index 0000000000..eb80cd6984
--- /dev/null
+++ b/cesar/bufmgr/test/utest/inc/scenario_defs.h
@@ -0,0 +1,84 @@
+#ifndef inc_scenario_defs_h
+#define inc_scenario_defs_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/scenario_defs.h
+ * \brief Scenario entries definition.
+ * \ingroup test
+ */
+#include "bufmgr/bufmgr.h"
+
+/* Scenario globals. */
+#define SCENARIO_DEFS_GLOBALS \
+ bufmgr_t *bufmgr;
+
+/* Scenario actions. */
+#define SCENARIO_DEFS_ACTIONS \
+ bufmgr_fill_cache, \
+ bufmgr_get, \
+ bufmgr_get_wait, \
+ bufmgr_give_back, \
+ bufmgr_keep_buffer
+
+typedef struct
+{
+ uint ipmbox_buf_available;
+} scenario_action_bufmgr_fill_cache_t;
+
+void
+scenario_action_bufmgr_fill_cache_cb (scenario_globals_t *globals,
+ scenario_params_t *params);
+
+typedef struct
+{
+ u8 *buf_expected;
+} scenario_action_bufmgr_get_t;
+
+void
+scenario_action_bufmgr_get_cb (scenario_globals_t *globals,
+ scenario_params_t *params);
+
+typedef scenario_action_bufmgr_get_t scenario_action_bufmgr_get_wait_t;
+
+void
+scenario_action_bufmgr_get_wait_cb (scenario_globals_t *globals,
+ scenario_params_t *params);
+
+typedef struct
+{
+ u8 *buffer;
+} scenario_action_bufmgr_keep_buffer_t;
+
+void
+scenario_action_bufmgr_keep_buffer_cb(scenario_globals_t *globals,
+ scenario_params_t *params);
+
+typedef scenario_empty_t scenario_action_bufmgr_give_back_t;
+
+void
+scenario_action_bufmgr_give_back_cb (scenario_globals_t *globals,
+ scenario_params_t *params);
+
+/* Scenario events. */
+#define SCENARIO_DEFS_EVENTS \
+ ipmbox_empty_buf_get, \
+ ipmbox_tx_empty_buf
+
+typedef struct
+{
+ uint nb_req;
+ uint nb_return;
+} scenario_event_ipmbox_empty_buf_get_t;
+
+typedef struct
+{
+ uint length;
+} scenario_event_ipmbox_tx_empty_buf_t;
+
+#endif /* inc_scenario_defs_h */
diff --git a/cesar/bufmgr/test/utest/inc/test_bufmgr.h b/cesar/bufmgr/test/utest/inc/test_bufmgr.h
new file mode 100644
index 0000000000..50a16da254
--- /dev/null
+++ b/cesar/bufmgr/test/utest/inc/test_bufmgr.h
@@ -0,0 +1,20 @@
+#ifndef inc_test_bufmgr_h
+#define inc_test_bufmgr_h
+
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file inc/test_bufmgr.h
+ * \brief Buffer manager unitary test private data
+ * \ingroup test
+ */
+
+/* Define a fake buffer address for tests. */
+#define BUFMGR_TEST_FAKE_BUFFER_ADDRESS 0x42
+
+#endif /* inc_test_bufmgr_h */
diff --git a/cesar/bufmgr/test/utest/src/bufmgr.c b/cesar/bufmgr/test/utest/src/bufmgr.c
new file mode 100644
index 0000000000..3274fa0ebe
--- /dev/null
+++ b/cesar/bufmgr/test/utest/src/bufmgr.c
@@ -0,0 +1,260 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file bufmgr/test/utest/src/bufmgr.c
+ * \brief Buffer Manager unitary test
+ * \ingroup bufmgr_test
+ */
+#include "common/std.h"
+
+#include "lib/test.h"
+#include "lib/scenario/scenario.h"
+#include "lib/blk.h"
+#include "lib/rnd.h"
+
+#include "bufmgr/bufmgr.h"
+#include "bufmgr/inc/context.h"
+
+#include "inc/test_bufmgr.h"
+
+void
+bufmgr_fill_cache_test_case (test_t t)
+{
+ test_case_begin (t, "Fill cache buffer");
+ test_begin (t, "all cases.")
+ {
+ bufmgr_t *bufmgr = bufmgr_init (NULL);
+ uint i, j;
+ scenario_globals_t globals = {
+ .bufmgr = bufmgr
+ };
+ for (i = 0; i < BUFMGR_BUFFER_LIST_SIZE; i++)
+ {
+ for (j = 0; j < BUFMGR_BUFFER_LIST_SIZE; j++)
+ {
+
+ bufmgr->sem = MIN (i, (uint) BUFMGR_RESERVED_BUFFER_NB);
+ bufmgr->buffers_nb = i;
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (bufmgr_fill_cache,
+ .ipmbox_buf_available = j),
+ SCENARIO_EVENT_COND (i < BUFMGR_BUFFER_LIST_NB,
+ ipmbox_empty_buf_get,
+ .nb_req = BUFMGR_BUFFER_LIST_NB - i,
+ .nb_return =
+ MIN (BUFMGR_BUFFER_LIST_NB - i, j)),
+ SCENARIO_END
+ };
+ scenario_run (t, entries, &globals);
+ }
+ }
+ bufmgr_uninit (bufmgr);
+ }
+ test_end;
+}
+
+void
+bufmgr_get_test_case (test_t t)
+{
+ test_case_begin (t, "Get buffer");
+ test_begin (t, "all cases.")
+ {
+ bufmgr_t *bufmgr = bufmgr_init (NULL);
+ scenario_globals_t globals = {
+ .bufmgr = bufmgr
+ };
+ bufmgr->sem = bufmgr->buffers_nb = 0;
+ scenario_entry_t entries[] = {
+ /* No buffers. */
+ SCENARIO_ACTION (bufmgr_get,
+ .buf_expected = NULL),
+ SCENARIO_EVENT (ipmbox_empty_buf_get,
+ .nb_req = BUFMGR_BUFFER_LIST_NB,
+ .nb_return = 0),
+ /* Get only buffers for reserved list. */
+ SCENARIO_ACTION (bufmgr_get,
+ .buf_expected = NULL),
+ SCENARIO_EVENT (ipmbox_empty_buf_get,
+ .nb_req = BUFMGR_BUFFER_LIST_NB,
+ .nb_return = BUFMGR_RESERVED_BUFFER_NB),
+ /* Get a buffer. */
+ SCENARIO_ACTION (bufmgr_get,
+ .buf_expected = (u8*) BUFMGR_TEST_FAKE_BUFFER_ADDRESS),
+ SCENARIO_EVENT (ipmbox_empty_buf_get,
+ .nb_req = BUFMGR_BUFFER_LIST_NB
+ - BUFMGR_RESERVED_BUFFER_NB,
+ .nb_return = 1),
+ /* Only reserved buffers available. */
+ SCENARIO_ACTION (bufmgr_get,
+ .buf_expected = NULL),
+ SCENARIO_EVENT (ipmbox_empty_buf_get,
+ .nb_req = BUFMGR_BUFFER_LIST_NB
+ - BUFMGR_RESERVED_BUFFER_NB,
+ .nb_return = 0),
+ SCENARIO_END
+ };
+ scenario_run (t, entries, &globals);
+ bufmgr_uninit (bufmgr);
+ }
+ test_end;
+}
+
+void
+bufmgr_get_wait_test_case (test_t t)
+{
+ test_case_begin (t, "Wait to get buffer");
+ test_begin (t, "all cases.")
+ {
+ bufmgr_t *bufmgr = bufmgr_init (NULL);
+ scenario_globals_t globals = {
+ .bufmgr = bufmgr
+ };
+ bufmgr->sem = bufmgr->buffers_nb = 0;
+ scenario_entry_t entries[] = {
+ /* No buffers. */
+ SCENARIO_ACTION (bufmgr_get_wait,
+ .buf_expected = NULL),
+ SCENARIO_EVENT (ipmbox_empty_buf_get,
+ .nb_req = BUFMGR_BUFFER_LIST_NB,
+ .nb_return = 0),
+ /* Get a buffer from reserved list. */
+ SCENARIO_ACTION (bufmgr_get_wait,
+ .buf_expected =
+ (u8*) BUFMGR_TEST_FAKE_BUFFER_ADDRESS),
+ SCENARIO_EVENT (ipmbox_empty_buf_get,
+ .nb_req = BUFMGR_BUFFER_LIST_NB,
+ .nb_return = BUFMGR_RESERVED_BUFFER_NB),
+ /* Get a buffer from cached list. */
+ SCENARIO_ACTION (bufmgr_get_wait,
+ .buf_expected = (u8*) BUFMGR_TEST_FAKE_BUFFER_ADDRESS),
+ SCENARIO_EVENT (ipmbox_empty_buf_get,
+ .nb_req = BUFMGR_BUFFER_LIST_NB
+ - BUFMGR_RESERVED_BUFFER_NB + 1,
+ .nb_return = 2),
+ SCENARIO_END
+ };
+ scenario_run (t, entries, &globals);
+ test_fail_unless (bufmgr->sem == BUFMGR_RESERVED_BUFFER_NB - 1);
+ bufmgr_uninit (bufmgr);
+ }
+ test_end;
+}
+
+void
+bufmgr_give_back_test_case (test_t t)
+{
+ test_case_begin (t, "Give back an empty buffer");
+ bufmgr_t *bufmgr;
+ /* Context init. */
+ bufmgr = bufmgr_init (NULL);
+ test_begin (t, "Nominal")
+ {
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (bufmgr_give_back),
+ SCENARIO_EVENT (ipmbox_tx_empty_buf, .length = 1),
+ SCENARIO_END
+ };
+ scenario_globals_t globals = {
+ .bufmgr = bufmgr
+ };
+ scenario_run (t, entries, &globals);
+ } test_end;
+ test_begin (t, "Keep buffer, to not give back to linux")
+ {
+ bufmgr->buffers_nb = BUFMGR_BUFFER_LIST_NB;
+ scenario_entry_t entries[] = {
+ SCENARIO_ACTION (bufmgr_keep_buffer,
+ .buffer = (u8*) BUFMGR_TEST_FAKE_BUFFER_ADDRESS),
+ SCENARIO_END
+ };
+ scenario_globals_t globals = {
+ .bufmgr = bufmgr
+ };
+ scenario_run (t, entries, &globals);
+ test_fail_unless (bufmgr->buffers_nb == BUFMGR_BUFFER_LIST_NB + 1);
+ /* Get a buffer. */
+ scenario_entry_t entries_get_buffer[] = {
+ SCENARIO_ACTION (bufmgr_get_wait,
+ .buf_expected =
+ (u8*) BUFMGR_TEST_FAKE_BUFFER_ADDRESS),
+ SCENARIO_END
+ };
+ scenario_run (t, entries_get_buffer, &globals);
+ test_fail_unless (bufmgr->buffers_nb == BUFMGR_BUFFER_LIST_NB);
+ } test_end;
+ bufmgr_uninit (bufmgr);
+}
+
+void
+bufmgr_callback_test_case (test_t t)
+{
+ test_case_begin (t, "Register callbacks");
+ test_begin (t, "Register callback.")
+ {
+ lib_rnd_t rand;
+ lib_rnd_init (&rand, 0x12afe);
+ bufmgr_client_t client[BUFMGR_CLIENT_NB];
+ bufmgr_t *bufmgr;
+ bufmgr = bufmgr_init (NULL);
+ test_fail_unless (!bufmgr->client_nb);
+ uint i;
+ for (i = 0; i < BUFMGR_CLIENT_NB; i++)
+ {
+ client[i].cb = INVALID_PTR + i;
+ client[i].user_data = INVALID_PTR + i + 1;
+ bufmgr_client_register (bufmgr, client[i].cb,
+ client[i].user_data);
+ }
+ /* Add a new one... */
+ dbg_fatal_try_begin
+ {
+ bufmgr_client_register (bufmgr, (void*)0x42, (void*)0x43);
+ test_fail_unless (false);
+ }
+ dbg_fatal_try_catch (const char *fatal_message)
+ {
+ test_verbose_print (fatal_message);
+ test_fail_unless (true);
+ }
+ dbg_fatal_try_end;
+ /* Check values. */
+ for (i = 0; i < BUFMGR_CLIENT_NB; i++)
+ {
+ test_fail_unless (bufmgr->client[i].cb == client[i].cb);
+ test_fail_unless (bufmgr->client[i].user_data ==
+ client[i].user_data);
+ }
+ bufmgr_uninit (bufmgr);
+ } test_end;
+}
+
+void
+bufmger_test_suite (test_t t)
+{
+ test_suite_begin (t, "buffer manager");
+ bufmgr_fill_cache_test_case (t);
+ bufmgr_get_test_case (t);
+ bufmgr_get_wait_test_case (t);
+ bufmgr_give_back_test_case (t);
+ bufmgr_callback_test_case (t);
+ test_case_begin (t, "memory");
+ test_begin (t, "memory")
+ {
+ test_fail_unless (blk_check_memory ());
+ } test_end;
+}
+
+int
+main (int argc, char **argv)
+{
+ test_t t;
+ test_init (t, argc, argv);
+ bufmger_test_suite (t);
+ test_result (t);
+ return test_nb_failed (t) == 0 ? 0 : 1;
+}
diff --git a/cesar/bufmgr/test/utest/src/ipmbox.c b/cesar/bufmgr/test/utest/src/ipmbox.c
new file mode 100644
index 0000000000..bae1c46f2c
--- /dev/null
+++ b/cesar/bufmgr/test/utest/src/ipmbox.c
@@ -0,0 +1,48 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file bufmgr/test/utest/src/ipmbox.c
+ * \brief Override IPMbox functions.
+ * \ingroup bufmgr_test
+ */
+#include "common/std.h"
+
+#include "lib/test.h"
+#include "lib/scenario/scenario.h"
+
+#include "hal/ipmbox/ipmbox.h"
+
+#include "inc/test_bufmgr.h"
+
+uint
+ipmbox_empty_buf_get (ipmbox_t *ctx, u32 *msg_buf, uint nb)
+{
+ scenario_event (ipmbox_empty_buf_get, params);
+ test_fail_unless (nb == params->nb_req);
+ if (params->nb_return)
+ {
+ *msg_buf = (u32) BUFMGR_TEST_FAKE_BUFFER_ADDRESS;
+ }
+ else
+ *msg_buf = (u32) NULL;
+ return params->nb_return;
+}
+
+void
+ipmbox_tx_empty_buf (ipmbox_t *ctx, u32 *first_msg, uint length)
+{
+ scenario_event (ipmbox_tx_empty_buf, params);
+ test_fail_unless (*first_msg == BUFMGR_TEST_FAKE_BUFFER_ADDRESS);
+ test_fail_unless (length == params->length);
+}
+
+void
+ipmbox_register_empty_buf_cb (ipmbox_t *ctx, void *user_data,
+ ipmbox_empty_buf_cb_t empty_buf_cb)
+{
+}
diff --git a/cesar/bufmgr/test/utest/src/scenario_defs.c b/cesar/bufmgr/test/utest/src/scenario_defs.c
new file mode 100644
index 0000000000..c2b0cad991
--- /dev/null
+++ b/cesar/bufmgr/test/utest/src/scenario_defs.c
@@ -0,0 +1,90 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file src/scenario_defs.c
+ * \brief Scenario actions.
+ * \ingroup test
+ */
+#include "common/std.h"
+
+#include "lib/test.h"
+#include "lib/scenario/scenario.h"
+
+#include "bufmgr/bufmgr.h"
+#include "bufmgr/inc/context.h"
+
+#include "inc/test_bufmgr.h"
+
+void
+bufmgr_fill_cache (bufmgr_t *ctx);
+
+void
+scenario_action_bufmgr_fill_cache_cb (scenario_globals_t *globals,
+ scenario_params_t *params)
+{
+ test_within (scenario.t);
+ bufmgr_t *ctx = globals->bufmgr;
+ scenario_action_bufmgr_fill_cache_t *p =
+ &params->action_bufmgr_fill_cache;
+ uint buffers_init_nb = ctx->buffers_nb;
+ uint reserved_buf_init_nb = ctx->sem;
+ uint ipmbox_buf_available = p->ipmbox_buf_available;
+ uint reserved_buf_added =
+ MIN (BUFMGR_RESERVED_BUFFER_NB - reserved_buf_init_nb,
+ ipmbox_buf_available);
+ uint buffers_end_nb = buffers_init_nb;
+ if (buffers_init_nb < BUFMGR_BUFFER_LIST_NB)
+ {
+ buffers_end_nb +=
+ MIN ((uint) BUFMGR_BUFFER_LIST_NB - buffers_init_nb,
+ ipmbox_buf_available);
+ }
+ bufmgr_fill_cache (ctx);
+ test_fail_unless (ctx->sem == reserved_buf_init_nb + reserved_buf_added);
+ test_fail_unless (ctx->buffers_nb == buffers_end_nb);
+}
+
+void
+scenario_action_bufmgr_get_cb (scenario_globals_t *globals,
+ scenario_params_t *params)
+{
+ test_within (scenario.t);
+ bufmgr_t *ctx = globals->bufmgr;
+ scenario_action_bufmgr_get_t *p = &params->action_bufmgr_get;
+ u8 *buf = bufmgr_get (ctx);
+ test_fail_unless (buf == p->buf_expected);
+}
+
+void
+scenario_action_bufmgr_get_wait_cb (scenario_globals_t *globals,
+ scenario_params_t *params)
+{
+ test_within (scenario.t);
+ bufmgr_t *ctx = globals->bufmgr;
+ scenario_action_bufmgr_get_wait_t *p = &params->action_bufmgr_get_wait;
+ u8 *buf = bufmgr_get_wait (ctx, 10);
+ test_fail_unless (buf == p->buf_expected);
+}
+
+void
+scenario_action_bufmgr_keep_buffer_cb (scenario_globals_t *globals,
+ scenario_params_t *params)
+{
+ bufmgr_t *ctx = globals->bufmgr;
+ scenario_action_bufmgr_keep_buffer_t *p =
+ &params->action_bufmgr_keep_buffer;
+ bufmgr_keep_buffer (ctx, p->buffer);
+}
+
+void
+scenario_action_bufmgr_give_back_cb (scenario_globals_t *globals,
+ scenario_params_t *params)
+{
+ bufmgr_t *ctx = globals->bufmgr;
+ bufmgr_give_back (ctx, (u8 *) BUFMGR_TEST_FAKE_BUFFER_ADDRESS);
+}