summaryrefslogtreecommitdiff
path: root/cesar/hal/ipmbox
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/hal/ipmbox
parent89328e8cc096f8c9f340a3eb8910d06748a3e572 (diff)
cesar, cleopatre, common: new ipmbox design, closes #848
Diffstat (limited to 'cesar/hal/ipmbox')
-rw-r--r--cesar/hal/ipmbox/Module2
-rw-r--r--cesar/hal/ipmbox/doc/claudia_ipmbox.odtbin0 -> 200409 bytes
-rw-r--r--cesar/hal/ipmbox/inc/ecos.h50
-rw-r--r--cesar/hal/ipmbox/inc/ipmbox.h48
-rw-r--r--cesar/hal/ipmbox/inc/regs.h19
-rw-r--r--cesar/hal/ipmbox/ipmbox.h133
-rw-r--r--cesar/hal/ipmbox/maximus/Module1
-rw-r--r--cesar/hal/ipmbox/maximus/inc/maximus_ether.h67
-rw-r--r--cesar/hal/ipmbox/maximus/inc/maximus_interrupts.h22
-rw-r--r--cesar/hal/ipmbox/maximus/inc/maximus_ipmbox_ctx.h108
-rw-r--r--cesar/hal/ipmbox/maximus/src/maximus_ether.c455
-rw-r--r--cesar/hal/ipmbox/maximus/src/maximus_ipmbox.c508
-rw-r--r--cesar/hal/ipmbox/maximus/test/Config2
-rw-r--r--cesar/hal/ipmbox/maximus/test/Makefile8
-rw-r--r--cesar/hal/ipmbox/maximus/test/src/test_maximus_ether.c628
-rw-r--r--cesar/hal/ipmbox/maximus/test/src/test_maximus_ipmbox.c337
-rw-r--r--cesar/hal/ipmbox/src/ipmbox.c411
-rw-r--r--cesar/hal/ipmbox/stub/Module1
-rw-r--r--cesar/hal/ipmbox/stub/src/ipmbox.c117
-rw-r--r--cesar/hal/ipmbox/test/Config1
-rw-r--r--cesar/hal/ipmbox/test/Makefile10
-rw-r--r--cesar/hal/ipmbox/test/override/hal/ipmbox/inc/ecos.h58
-rw-r--r--cesar/hal/ipmbox/test/override/hal/ipmbox/inc/regs.h21
-rw-r--r--cesar/hal/ipmbox/test/src/ipmbox.c502
24 files changed, 3509 insertions, 0 deletions
diff --git a/cesar/hal/ipmbox/Module b/cesar/hal/ipmbox/Module
new file mode 100644
index 0000000000..e00d0e596f
--- /dev/null
+++ b/cesar/hal/ipmbox/Module
@@ -0,0 +1,2 @@
+SOURCES := ipmbox.c
+MODULES := ../common/ipmbox
diff --git a/cesar/hal/ipmbox/doc/claudia_ipmbox.odt b/cesar/hal/ipmbox/doc/claudia_ipmbox.odt
new file mode 100644
index 0000000000..095ab88ce1
--- /dev/null
+++ b/cesar/hal/ipmbox/doc/claudia_ipmbox.odt
Binary files differ
diff --git a/cesar/hal/ipmbox/inc/ecos.h b/cesar/hal/ipmbox/inc/ecos.h
new file mode 100644
index 0000000000..d30f0d16ec
--- /dev/null
+++ b/cesar/hal/ipmbox/inc/ecos.h
@@ -0,0 +1,50 @@
+#ifndef hal_ipmbox_inc_ipmbox_ecos_h
+#define hal_ipmbox_inc_ipmbox_ecos_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/inc/ipmbox_ecos.h
+ * \brief HAL IPMBox eCos management data.
+ * \ingroup hal_ipmbox
+ */
+#if defined (ECOS) && ECOS
+#include <cyg/hal/drv_api.h>
+#include <cyg/hal/hal_intr.h>
+#include "hal/leon/itc2.h"
+
+/* eCos function is dawn too slow, use HAL_INTERRUPT_ACKNOWLEDGE instead of
+ * cyg_drv_interrupt_acknowledge. */
+# define ipmbox_interrupt_acknowledge HAL_INTERRUPT_ACKNOWLEDGE
+
+/** Rx IPMBox DATA and MBX interrupt number. */
+# define IPMBOX_RX_IT_NUM CYGNUM_HAL_INTERRUPT_GIC2_14
+/** Rx Empty buf interrupt number. */
+# define IPMBOX_EMPTY_BUF_IT_NUM CYGNUM_HAL_INTERRUPT_GIC2_13
+
+/* We need this undocumented eCos function for budget. */
+extern void cyg_interrupt_post_dsr (CYG_ADDRWORD intr_obj);
+
+/* eCos interrupt management structure. */
+typedef struct ipmbox_ecos_t
+{
+ cyg_interrupt rx_it;
+ cyg_handle_t rx_it_handle;
+ cyg_interrupt empty_buf_it;
+ cyg_handle_t empty_buf_it_handle;
+} ipmbox_ecos_t;
+
+#else /* ! eCos */
+
+/** Rx IPMBox DATA and MBX interrupt number. */
+# define IPMBOX_RX_IT_NUM 0
+/** Rx Empty buf interrupt number. */
+# define IPMBOX_EMPTY_BUF_IT_NUM 1
+
+#endif
+
+#endif /* hal_ipmbox_inc_ipmbox_ecos_h */
diff --git a/cesar/hal/ipmbox/inc/ipmbox.h b/cesar/hal/ipmbox/inc/ipmbox.h
new file mode 100644
index 0000000000..5d45127b7d
--- /dev/null
+++ b/cesar/hal/ipmbox/inc/ipmbox.h
@@ -0,0 +1,48 @@
+#ifndef hal_ipmbox_inc_ipmbox_h
+#define hal_ipmbox_inc_ipmbox_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/inc/ipmbox.h
+ * \brief HAL IPMBox private data.
+ * \ingroup hal_ipmbox
+ *
+ * This file defines IPMBox context structure.
+ */
+#include "common/ipmbox/queue.h"
+#include "common/ipmbox/registers.h"
+
+#include "hal/ipmbox/inc/ecos.h"
+
+/** RX DATA budget. Number of words which can be handled in one
+ * execution. */
+#define IPMBOX_RX_DATA_BUDGET 128
+
+/** Context structure definition */
+struct ipmbox_t {
+ /** Queues, by types & directions. */
+ ipmbox_queue_t queue[IPMBOX_QUEUE_TYPE_NB][IPMBOX_QUEUE_DIRECTION_NB];
+ /** IPMBox registers. */
+ volatile ipmbox_registers_t *regs;
+ /** RX DATA user data. */
+ void *rx_cb_data_user_data;
+ /** RX MBX user data. */
+ void *rx_cb_mbx_user_data;
+ /** RX DATA DSR callback. */
+ ipmbox_rx_cb_t rx_cb_data;
+ /** RX MBX DSR callback. */
+ ipmbox_rx_cb_t rx_cb_mbx;
+ /* Empty buffer user data callback. */
+ void *empty_buf_cb_user_data;
+ /* Empty buffer DSR callback. */
+ ipmbox_empty_buf_cb_t empty_buf_cb;
+ /* eCos context. */
+ ipmbox_ecos_t ecos;
+};
+
+#endif /* hal_ipmbox_inc_ipmbox_h */
diff --git a/cesar/hal/ipmbox/inc/regs.h b/cesar/hal/ipmbox/inc/regs.h
new file mode 100644
index 0000000000..ae14059ccb
--- /dev/null
+++ b/cesar/hal/ipmbox/inc/regs.h
@@ -0,0 +1,19 @@
+#ifndef hal_ipmbox_inc_ipmbox_regs_h
+#define hal_ipmbox_inc_ipmbox_regs_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/inc/ipmbox_regs.h
+ * \brief HAL IPMBox registers base address.
+ * \ingroup hal_ipmbox
+ */
+
+/* IPMBox registers base address. */
+#define IPMBOX_REG_BASE_ADDR (0xB4000000)
+
+#endif /* hal_ipmbox_inc_ipmbox_regs_h */
diff --git a/cesar/hal/ipmbox/ipmbox.h b/cesar/hal/ipmbox/ipmbox.h
new file mode 100644
index 0000000000..509a3e1a15
--- /dev/null
+++ b/cesar/hal/ipmbox/ipmbox.h
@@ -0,0 +1,133 @@
+#ifndef hal_ipmbox_ipmbox_h
+#define hal_ipmbox_ipmbox_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/ipmbox.h
+ * \brief HAL IPMbox public interface.
+ * \ingroup hal_ipmbox
+ */
+#include "common/ipmbox/queue.h"
+
+/* Context forward declaration. */
+typedef struct ipmbox_t ipmbox_t;
+
+/**
+ * RX DSR callback function.
+ * \param user_data user data
+ * \param first_msg pointer to the first received message header
+ * \param length total length (in word) of received messages
+ */
+typedef void (*ipmbox_rx_cb_t) (void *user_data, u32 *first_msg, uint length);
+
+/**
+ * Empty buf DSR callback function.
+ * \param user_data user data
+ */
+typedef void (*ipmbox_empty_buf_cb_t) (void *user_data);
+
+BEGIN_DECLS
+
+/**
+ * Initialise the HAL HLE.
+ * \return the newly created context
+ */
+ipmbox_t *
+ipmbox_init (void);
+
+/**
+ * Uninitialise the HAL HLE.
+ * \param ctx ipmbox context
+ */
+void
+ipmbox_uninit (ipmbox_t *ctx);
+
+/**
+ * Activate ipmbox interruptions.
+ * \param ctx ipmbox context
+ * \param activation indicates if interruptions are activated or deactivated
+ */
+void
+ipmbox_activate (ipmbox_t *ctx, bool activation);
+
+/**
+ * Register callbacks for DATA queue.
+ * \param ctx ipmbox context
+ * \param user_data the user_data
+ * \param rx_cb_data callback to handle DATA.
+ */
+void
+ipmbox_register_rx_data_cb (ipmbox_t *ctx, void *data_user_data,
+ ipmbox_rx_cb_t rx_cb_data);
+
+/**
+ * Register callbacks for MBX queue.
+ * \param ctx ipmbox context
+ * \param user_data the user_data
+ * \param rx_cb_mbx callback to handle MBox.
+ */
+void
+ipmbox_register_rx_mbx_cb (ipmbox_t *ctx, void *data_user_data,
+ ipmbox_rx_cb_t rx_cb_mbx);
+
+/**
+ * Register callbacks for empty buf queue.
+ * \param ctx ipmbox context
+ * \param user_data the user_data
+ * \param rx_cb_empty_buf callback to handle empty buffers.
+ */
+void
+ipmbox_register_empty_buf_cb (ipmbox_t *ctx, void *data_user_data,
+ ipmbox_empty_buf_cb_t empty_buf_cb);
+
+/** Transmit a message to DATA queue.
+ * \param ctx ipmbox context
+ * \param first_msg pointer to the first message header
+ * \param length total length (in word) of messages to transmit
+ */
+void
+ipmbox_tx_data (ipmbox_t *ctx, u32 *first_msg, uint length);
+
+/** Transmit a message to EMPTY_BUF queue.
+ * \param ctx ipmbox context
+ * \param first_msg pointer to the first message header
+ * \param length total length (in word) of messages to transmit
+ */
+void
+ipmbox_tx_empty_buf (ipmbox_t *ctx, u32 *first_msg, uint length);
+
+/** Transmit a message to MBX queue.
+ * \param ctx ipmbox context
+ * \param first_msg pointer to the first message header
+ * \param length total length (in word) of messages to transmit
+ */
+void
+ipmbox_tx_mbx (ipmbox_t *ctx, u32 *first_msg, uint length);
+
+/**
+ * Get nb empty buffers from the empty buf queue.
+ * \param ctx ipmbox context
+ * \param msg_buf destination array for the messages
+ * \param nb number of elements of msg_buf.
+ * \return number of copied element in msg_buf.
+ */
+uint
+ipmbox_empty_buf_get (ipmbox_t *ctx, u32 *msg_buf, uint nb);
+
+/**
+ * Receive message from mailbox, interrupts locked.
+ * \param ctx ipmbox context
+ * \param first_msg pointer to store first received message address
+ * \return total length (in word) of received messages
+ */
+uint
+ipmbox_rx_sync (ipmbox_t *ctx, const u32 **first_msg);
+
+END_DECLS
+
+#endif /* hal_ipmbox_ipmbox_h */
diff --git a/cesar/hal/ipmbox/maximus/Module b/cesar/hal/ipmbox/maximus/Module
new file mode 100644
index 0000000000..8b80d1ba66
--- /dev/null
+++ b/cesar/hal/ipmbox/maximus/Module
@@ -0,0 +1 @@
+SOURCES := maximus_ipmbox.c maximus_ether.c
diff --git a/cesar/hal/ipmbox/maximus/inc/maximus_ether.h b/cesar/hal/ipmbox/maximus/inc/maximus_ether.h
new file mode 100644
index 0000000000..fa8df3d8c3
--- /dev/null
+++ b/cesar/hal/ipmbox/maximus/inc/maximus_ether.h
@@ -0,0 +1,67 @@
+#ifndef hal_ipmbox_maximus_inc_maximus_ether_h
+#define hal_ipmbox_maximus_inc_maximus_ether_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/maximus/inc/maximus_ether.h
+ * \brief HAL IPMBox declarations for Maximus.
+ * \ingroup hal_ipmbox_maximus
+ */
+
+#include "host/fwd.h" // for 'sci_msg_t'
+#include "hal/ipmbox/ipmbox.h"
+
+/**
+ * Fill a blank ether header
+ * \param ctx current ipmbox context
+ * \param msg pointer to sci message to fill header
+ * \param type type of message (DATA, MME, BUFFER_ADD, or BUFFER_RELEASED)
+ * \param flags not used
+ * \return 0 if ok, -1 if it fails with errno =
+ * - EINVAL if ctx or msg are NULL, or if arguments are out-of-range
+ */
+int maximus_ether_fill_hdr(ipmbox_t *ctx, sci_msg_t *msg, u8 type, u8 flags);
+
+/**
+ * Process ether message received by the sci layer.
+ * This function must be registred to SCI layer with SCI_MSG_TYPE_ETHERNET type.
+ * \param msg message to process
+ * \param ipmbox ipmbox current context
+ * \return 0 if ok, -1 if it fails with errno =
+ * - EINVAL if msg or ctx are NULL
+ * - EPROTO if msg->hdr.ether is null, or if msg->hdr.ether values are out-of-range
+ */
+int maximus_ether_recv (sci_msg_t *msg, void *ipmbox);
+
+/**
+ * Process ether message received by the sci layer, depending on the ether header type.
+ * \param ctx ipmbox current context
+ * \param msg message to process
+ * \return 0 if ok, -1 if it fails with errno =
+ * - EINVAL if ctx, msg, msg->sci_hdr or ctx->rx_cb are null
+ * - EPROTO if msg->hdr.ether->type is incorrect, or if msg->hdr.ether values are out-of-range
+ */
+int maximus_ether_recv_invalid (ipmbox_t *ctx, sci_msg_t *msg);
+int maximus_ether_recv_data (ipmbox_t *ctx, sci_msg_t *msg);
+int maximus_ether_recv_mbx (ipmbox_t *ctx, sci_msg_t *msg);
+int maximus_ether_recv_empty_buf (ipmbox_t *ctx, sci_msg_t *msg);
+
+/**
+ * Send an Ether SCI message of type DATA, MME, or BUFFER_RELEASED to Maximus.
+ * \param ctx ipmbox current context
+ * \param type type of message (DATA, MME, or BUFFER_RELEASED)
+ * \param flags not used
+ * \param data_length sci message data length to send
+ * \param data pointer to sci message data to send
+ * \return 0 if ok, -1 if it fails with errno =
+ * - EINVAL if ctx or data are null, or of data length equals 0
+ * if 'sci_send()' fails, it sets errno
+ */
+int maximus_ether_send (ipmbox_t *ctx, u8 type, u8 flags, uint data_length, u32 *data);
+
+#endif /* hal_phy_maximus_inc_maximus_ether_h */
diff --git a/cesar/hal/ipmbox/maximus/inc/maximus_interrupts.h b/cesar/hal/ipmbox/maximus/inc/maximus_interrupts.h
new file mode 100644
index 0000000000..89685202d7
--- /dev/null
+++ b/cesar/hal/ipmbox/maximus/inc/maximus_interrupts.h
@@ -0,0 +1,22 @@
+#ifndef hal_ipmbox_maximus_inc_maximus_interrupts_h
+#define hal_ipmbox_maximus_inc_maximus_interrupts_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/maximus/inc/maximus_interrupts.h
+ * \brief HAL interrupt register definition for Maximus.
+ * \ingroup hal_ipmbox_maximus
+ */
+
+#define HAL_IPMBOX_RX_INTERRUPT 7
+
+#define HAL_IPMBOX_BUF_INTERRUPT 8
+
+#define HAL_IPMBOX_INTERRUPT_PRIORITY 1 /* is it the right value? */
+
+#endif /* hal_ipmbox_maximus_inc_maximus_interrupts_h */
diff --git a/cesar/hal/ipmbox/maximus/inc/maximus_ipmbox_ctx.h b/cesar/hal/ipmbox/maximus/inc/maximus_ipmbox_ctx.h
new file mode 100644
index 0000000000..54103eff29
--- /dev/null
+++ b/cesar/hal/ipmbox/maximus/inc/maximus_ipmbox_ctx.h
@@ -0,0 +1,108 @@
+#ifndef hal_ipmbox_maximus_inc_maximus_ipmbox_context_h
+#define hal_ipmbox_maximus_inc_maximus_ipmbox_context_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/maximus/inc/maximus_ipmbox_context.h
+ * \brief HAL ipmbox context for Maximus.
+ * \ingroup hal_ipmbox_maximus
+ */
+#include "hal/ipmbox/ipmbox.h" // for 'ipmbox_rx_cb_t', 'ipmbox_empty_buf_cb_t'
+#include "maximus/common/types/sci_types.h" // for 'SCI_MSG_MAX_SIZE'
+#include "common/ipmbox/protocol.h"
+#include <stdint.h> // for 'u32'
+#ifdef ECOS
+#include <cyg/hal/drv_api.h>
+#endif /* ECOS */
+
+/** Data queue structure for Maximus. */
+struct maximus_queue_data_t
+{
+ /** Total length (in word) of messages. */
+ uint length;
+ /** Mailbox. */
+ u32 mailbox[IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_DATA];
+};
+typedef struct maximus_queue_data_t maximus_queue_data_t;
+
+/** Mailbox queue structure for Maximus. */
+struct maximus_queue_mbx_t
+{
+ /** Total length (in word) of messages. */
+ uint length;
+ /** Mailbox. */
+ u32 mailbox[IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_MBX];
+};
+typedef struct maximus_queue_mbx_t maximus_queue_mbx_t;
+
+/** Empty Buffer queue structure for Maximus. */
+struct maximus_queue_empty_buf_t
+{
+ /** Total length (in word) of messages. */
+ uint length;
+ /** Mailbox. */
+ u32 mailbox[IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_EMPTY_BUF];
+};
+typedef struct maximus_queue_empty_buf_t maximus_queue_empty_buf_t;
+
+struct maximus_ipmbox_buffer_t
+{
+ /** Pointer to next allocated buffer. */
+ struct maximus_ipmbox_buffer_t *next;
+ /** Buffer id.*/
+ u32 id;
+ /** Pointer to data. */
+ u32 *data;
+};
+typedef struct maximus_ipmbox_buffer_t maximus_ipmbox_buffer_t;
+
+/** Ipmbox context structure for Maximus. */
+struct ipmbox_t
+{
+ /** Data reception queue structure. */
+ maximus_queue_data_t rx_data;
+ /** Mailbox reception queue structure. */
+ maximus_queue_mbx_t rx_mbx;
+ /** Empty buffer reception queue structure. */
+ maximus_queue_empty_buf_t rx_empty_buf;
+ /** Pointer to first element in linked list of allocated buffers. */
+ maximus_ipmbox_buffer_t *first_buffer;
+ /** Pointer to last element in linked list of allocated buffers. */
+ maximus_ipmbox_buffer_t *last_buffer;
+ /** User data passed to rx data callback. */
+ void *rx_data_user_data;
+ /** User data passed to rx mbx callback. */
+ void *rx_mbx_user_data;
+ /** User data passed to empty buffer callback. */
+ void *buf_user_data;
+ /** RX DSR callbacks. */
+ ipmbox_rx_cb_t rx_cb_data;
+ ipmbox_rx_cb_t rx_cb_mbx;
+ /** Pointer to current DSR callback. */
+ ipmbox_rx_cb_t rx_cb_current;
+ /** Empty buffer DSR callback. */
+ ipmbox_empty_buf_cb_t empty_buf_cb;
+#ifdef ECOS
+ /** Ipmbox interrupt descriptor for eCos: relates to RX data and RX
+ * mailbox. */
+ cyg_interrupt ipmbox_rx_interrupt;
+ /** Ipmbox interrupt handle for RX data and RX mailbox. */
+ cyg_handle_t ipmbox_rx_interrupt_handle;
+ /** Ipmbox interrupt descriptor for eCos: relates to empty buffer. */
+ cyg_interrupt ipmbox_buf_interrupt;
+ /** Ipmbox interrupt handle for empty buffer. */
+ cyg_handle_t ipmbox_buf_interrupt_handle;
+#endif /* ECOS */
+ /** For ether messages. */
+ unsigned char buffer[SCI_MSG_MAX_SIZE];
+ /** Set to true to enable assertions on WARNING messages. */
+ bool warning_assert;
+};
+/* Forward declaration in hal/ipmbox/forward.h. */
+
+#endif /* hal_ipmbox_maximus_inc_maximus_ipmbox_context_h */
diff --git a/cesar/hal/ipmbox/maximus/src/maximus_ether.c b/cesar/hal/ipmbox/maximus/src/maximus_ether.c
new file mode 100644
index 0000000000..29cfbbf87b
--- /dev/null
+++ b/cesar/hal/ipmbox/maximus/src/maximus_ether.c
@@ -0,0 +1,455 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/maximus/src/maximus_ether.c
+ * \brief HAL HLE functions for Maximus.
+ * \ingroup hal_hle_maximus
+ */
+
+#include "common/std.h"
+#include "hal/ipmbox/maximus/inc/maximus_ether.h"
+#include "hal/ipmbox/maximus/inc/maximus_ipmbox_ctx.h"
+#include "host/fwd.h" // for 'sci_msg_t' and 'ether_msg_hdr_t'
+#include "host/station/station.h" // for 'station_log()'
+#include "maximus/common/types/ethernet_types.h" // for 'ETHERNET_TYPE_...'
+#include "hal/ipmbox/maximus/inc/maximus_interrupts.h" // for 'HAL_HLE_INTERRUPT_IPMBOX'
+#include "common/ipmbox/msg.h"
+#include "ecos/packages/hal/maximus/arch/current/include/hal_host_intr.h"
+#include "common/defs/ethernet.h" // for 'ETH_PACKET_MAX_SIZE' and 'ETH_PACKET_MIN_SIZE'
+#include <stdlib.h> // for 'malloc'
+#include <errno.h>
+
+#include "common/defs/homeplugAV.h" // for 'HPAV_MTYPE_MME' and 'HPAV_M(M)TYPE_OFFSET'
+#include "lib/swap.h" // for 'swap16()'
+
+typedef int (*maximus_ether_recv_function)(ipmbox_t *ctx, sci_msg_t *msg);
+maximus_ether_recv_function maximus_ether_function_array[ETHERNET_TYPE_NB] = { &maximus_ether_recv_invalid, // (0) none
+ &maximus_ether_recv_data, // (1) data
+ &maximus_ether_recv_mbx, // (2) mme
+ &maximus_ether_recv_empty_buf, // (3) buffer add
+ &maximus_ether_recv_invalid }; // (4) buffer released
+
+int
+maximus_ether_fill_hdr(ipmbox_t *ctx, sci_msg_t *msg, u8 type, u8 flags)
+{
+ int ret = -1;
+
+ dbg_assert_ptr(ctx);
+ dbg_assert_ptr(msg);
+ dbg_assert((ETHERNET_TYPE_NB > type) && (ETHERNET_TYPE_NONE < type));
+ dbg_assert(ETHERNET_FLAG_MAX >= flags);
+ if ((NULL == ctx)
+ || (NULL == msg)
+ || ((ETHERNET_TYPE_NB <= type) || (ETHERNET_TYPE_NONE >= type))
+ || (ETHERNET_FLAG_MAX < flags))
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ // reserve space
+ if ((int)sizeof(ether_msg_hdr_t) != sci_msg_push(msg, sizeof(ether_msg_hdr_t)))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when pushing SCI message", errno);
+ }
+ else
+ {
+ // fill the reserved header
+ msg->hdr.ether = (ether_msg_hdr_t*)msg->data_begin;
+ msg->hdr.ether->version = ETHERNET_VERSION;
+ msg->hdr.ether->type = type;
+ msg->hdr.ether->flags = flags;
+ msg->hdr.ether->reserved = 0;
+
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+int
+maximus_ether_recv (sci_msg_t *msg, void *ipmbox)
+{
+ int ret = -1;
+ ipmbox_t *ctx;
+ ether_msg_hdr_t ether_hdr;
+
+ dbg_assert_ptr(msg);
+ dbg_assert_ptr(ipmbox);
+ if((NULL == msg) || (NULL == ipmbox))
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ // set ipmbox context
+ ctx = (ipmbox_t *)ipmbox;
+
+ // set header pointer in case of not already done
+ memcpy(&ether_hdr , msg->data_begin, sizeof(ether_msg_hdr_t));
+ if ((int)sizeof(ether_msg_hdr_t) != sci_msg_pop(msg, sizeof(ether_msg_hdr_t)))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when poping SCI message", errno);
+ }
+ else
+ {
+ msg->hdr.ether = &ether_hdr;
+
+ /* Check ether header. */
+
+ dbg_assert_ptr(msg->hdr.ether);
+ dbg_assert(ETHERNET_TYPE_NB > msg->hdr.ether->type);
+ dbg_assert(ETHERNET_FLAG_MAX >= msg->hdr.ether->flags);
+ if ((NULL == msg->hdr.ether)
+ || (ETHERNET_TYPE_NB <= msg->hdr.ether->type)
+ || (ETHERNET_FLAG_MAX < msg->hdr.ether->flags))
+ {
+ errno = EPROTO;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ // depending on the ether header type, different actions have to be done
+ ret = (*(maximus_ether_function_array[msg->hdr.ether->type]))(ctx, msg);
+ }
+ }
+ }
+
+ return ret;
+}
+
+int
+maximus_ether_recv_invalid (ipmbox_t *ctx, sci_msg_t *msg)
+{
+ errno = EPROTO;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d because ether hdr type is incorrect", errno);
+ return -1;
+}
+
+int
+maximus_ether_recv_data (ipmbox_t *ctx, sci_msg_t *msg)
+{
+ int ret = -1;
+
+ dbg_assert_ptr(ctx);
+ dbg_assert_ptr(msg);
+ dbg_assert_ptr(msg->hdr.ether);
+ dbg_assert_ptr(msg->sci_hdr);
+ dbg_assert((ETH_PACKET_MIN_SIZE_ALLOWED <= msg->length) && (ETH_PACKET_MAX_SIZE >= msg->length));
+ dbg_assert_ptr(msg->data_begin);
+ if((NULL == ctx)
+ || (NULL == msg)
+ || (NULL == msg->hdr.ether)
+ || (NULL == msg->sci_hdr)
+ || ((ETH_PACKET_MIN_SIZE_ALLOWED > msg->length) || (ETH_PACKET_MAX_SIZE < msg->length))
+ || (NULL == msg->data_begin))
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ ipmbox_msg_data_t msg_data;
+ u8 *data;
+ unsigned int msg_len = (unsigned int) msg->length;
+
+ // Get data from sci message.
+ data = (u8 *) calloc (2048, sizeof (u8));
+ memcpy (data, msg->data_begin, msg->length);
+ msg_data.buffer_addr = (u32) data;
+
+ if (msg->length != sci_msg_pop(msg, msg->length))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when poping SCI message", errno);
+ }
+ else
+ {
+ msg_data.header = ipmbox_msg_create_header_data (msg_len, 0 /* vlan prio */);
+
+ if (IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_DATA <= ctx->rx_data.length + 2)
+ {
+ errno = ENOSPC;
+ station_log(&my_station, STATION_LOG_WARNING, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d because data queue is full", __FUNCTION__, errno);
+ dbg_assert_print(!ctx->warning_assert, "errno = %d because data queue is full", errno);
+ // reset total length of messages
+ ctx->rx_data.length = 0;
+ }
+
+ /* Update data queue. */
+ // set hdr
+ memcpy(&ctx->rx_data.mailbox[ctx->rx_data.length], &msg_data, sizeof(ipmbox_msg_data_t));
+ // update total length of messages
+ ctx->rx_data.length += 2;
+
+ /* set callback for DSR */
+ ctx->rx_cb_current = ctx->rx_cb_data;
+ // raise interruption
+ maximus_pending_isrs |= (1 << HAL_IPMBOX_RX_INTERRUPT);
+
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+int
+maximus_ether_recv_mbx (ipmbox_t *ctx, sci_msg_t *msg)
+{
+ int ret = -1;
+
+ dbg_assert_ptr(ctx);
+ dbg_assert_ptr(msg);
+ dbg_assert_ptr(msg->hdr.ether);
+ dbg_assert_ptr(msg->sci_hdr);
+ dbg_assert((ETH_PACKET_MIN_SIZE_ALLOWED <= msg->length) && (ETH_PACKET_MAX_SIZE >= msg->length));
+ dbg_assert_ptr(msg->data_begin);
+ if((NULL == ctx)
+ || (NULL == msg)
+ || (NULL == msg->hdr.ether)
+ || (NULL == msg->sci_hdr)
+ || ((ETH_PACKET_MIN_SIZE_ALLOWED > msg->length) || (ETH_PACKET_MAX_SIZE < msg->length))
+ || (NULL == msg->data_begin))
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ ipmbox_msg_mbx_t msg_mbx;
+ unsigned int msg_len = (unsigned int) msg->length;
+ u8 *mme;
+
+ // Get MME from sci message.
+ mme = (u8 *) calloc (2048, sizeof (u8));
+ memcpy (mme, msg->data_begin, msg->length);
+ msg_mbx.buffer_addr = (u32) mme;
+
+ if (msg->length != sci_msg_pop(msg, msg->length))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when poping SCI message", errno);
+ }
+ else
+ {
+ msg_mbx.header = ipmbox_msg_create_header_mme_priv (msg_len);
+
+ if (IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_MBX <= ctx->rx_mbx.length + 2)
+ {
+ errno = ENOSPC;
+ station_log(&my_station, STATION_LOG_WARNING, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d because mailbox queue is full", __FUNCTION__, errno);
+ dbg_assert_print(!ctx->warning_assert, "errno = %d because mailbox queue is full", errno);
+ // reset total length of messages
+ ctx->rx_mbx.length = 0;
+ }
+
+ /* Update mailbox queue. */
+ // set hdr
+ memcpy (&ctx->rx_mbx.mailbox[ctx->rx_mbx.length], &msg_mbx,
+ sizeof (ipmbox_msg_mbx_t));
+ // update total length of messages
+ ctx->rx_mbx.length += 2;
+
+ /* set callback for DSR */
+ ctx->rx_cb_current = ctx->rx_cb_mbx;
+ // raise interruption
+ maximus_pending_isrs |= (1 << HAL_IPMBOX_RX_INTERRUPT);
+
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+int
+maximus_ether_recv_empty_buf (ipmbox_t *ctx, sci_msg_t *msg)
+{
+ int ret = -1;
+
+ dbg_assert_ptr(ctx);
+ dbg_assert_ptr(msg);
+ dbg_assert_ptr(msg->hdr.ether);
+ dbg_assert_ptr(msg->sci_hdr);
+ dbg_assert((int)(2 * sizeof(u32)) <= msg->length);
+ dbg_assert_ptr(msg->data_begin);
+ if((NULL == ctx)
+ || (NULL == msg)
+ || (NULL == msg->hdr.ether)
+ || (NULL == msg->sci_hdr)
+ || ((int)(2 * sizeof(u32)) > msg->length)
+ || (NULL == msg->data_begin))
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ ipmbox_msg_empty_buf_t msg_empty_buf;
+ u32 buffer_nb; // number of buffers to be allocated
+ uint i;
+
+ // get requested buffer nb
+ memcpy(&buffer_nb, msg->data_begin, sizeof(u32));
+ if ((int)sizeof(u32) != sci_msg_pop(msg, sizeof(u32)))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when poping SCI message", errno);
+ }
+ else
+ {
+ if (IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_EMPTY_BUF <= \
+ ctx->rx_empty_buf.length + buffer_nb)
+ {
+ errno = ENOSPC;
+ station_log(&my_station, STATION_LOG_WARNING, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d because empty buffer queue is full", __FUNCTION__, errno);
+ dbg_assert_print(!ctx->warning_assert, "errno = %d because empty buffer queue is full", errno);
+ // reset total length of messages
+ ctx->rx_empty_buf.length = 0;
+ }
+
+ /* Update empty buffer queue. */
+ for (i = ctx->rx_empty_buf.length; i < ctx->rx_empty_buf.length + buffer_nb; i ++)
+ {
+ u32 buffer_id;
+ maximus_ipmbox_buffer_t *buffer = (maximus_ipmbox_buffer_t *)malloc(sizeof(maximus_ipmbox_buffer_t));
+
+ // get buffer id
+ memcpy(&buffer_id, msg->data_begin, sizeof(u32));
+ if ((int)sizeof(u32) != sci_msg_pop(msg, sizeof(u32)))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when poping SCI message", errno);
+ }
+ else
+ {
+ // set buffer pointer (32 bits): pointer to allocated buffer
+ ctx->last_buffer->next = buffer;
+ ctx->last_buffer = buffer;
+ ctx->last_buffer->next = NULL;
+ ctx->last_buffer->id = buffer_id;
+ ctx->last_buffer->data = (u32 *) calloc (2048, sizeof (u8));
+ msg_empty_buf.buffer_addr = (u32)ctx->last_buffer->data;
+ memcpy (&ctx->rx_empty_buf.mailbox[i], &msg_empty_buf,
+ sizeof (ipmbox_msg_empty_buf_t));
+ }
+ }
+ // update total length of messages
+ ctx->rx_empty_buf.length += buffer_nb;
+
+ // raise interruption
+ maximus_pending_isrs |= (1 << HAL_IPMBOX_BUF_INTERRUPT);
+
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+int
+maximus_ether_send (ipmbox_t *ctx, u8 type, u8 flags, uint data_length, u32 *data)
+{
+ int ret = -1;
+
+ dbg_assert_ptr(ctx);
+ dbg_assert((ETHERNET_TYPE_NB > type)
+ && (ETHERNET_TYPE_NONE < type)
+ && (ETHERNET_TYPE_BUFFER_ADD != type));
+ dbg_assert(ETHERNET_FLAG_MAX >= flags);
+ dbg_assert(0 != data_length);
+ dbg_assert_ptr(data);
+ if ( (NULL == ctx)
+ || (ETHERNET_TYPE_NB <= type)
+ || (ETHERNET_TYPE_NONE >= type)
+ || (ETHERNET_TYPE_BUFFER_ADD == type)
+ || (ETHERNET_FLAG_MAX < flags)
+ || (0 == data_length)
+ || (NULL == data) )
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ // for ether message
+ sci_msg_t msg;
+
+ // init for ether message
+ memset(ctx->buffer, '\0', SCI_MSG_MAX_SIZE);
+ if (0 != sci_msg_init(&msg, ctx->buffer, SCI_MSG_MAX_SIZE))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when initializing SCI message", errno);
+ }
+ else
+ {
+ // fill sci data
+ if ((int)data_length != sci_msg_push(&msg, data_length))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when pushing SCI message", errno);
+ }
+ else
+ {
+ memcpy(msg.data_begin, data, data_length);
+
+ // fill ether and sci header
+ if ( (0 != maximus_ether_fill_hdr(ctx, &msg, type, flags))
+ || (0 != sci_fill_hdr(my_station.sci, &msg, SCI_MSG_TYPE_ETHERNET, 0 /* flags */)) )
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when filling header", errno);
+ }
+ else
+ {
+ // send the message
+ if (msg.length != sci_send(my_station.sci, &msg))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when sending an Ether SCI message", errno);
+ }
+ else
+ {
+ ret = 0;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/cesar/hal/ipmbox/maximus/src/maximus_ipmbox.c b/cesar/hal/ipmbox/maximus/src/maximus_ipmbox.c
new file mode 100644
index 0000000000..5e5b5e92c5
--- /dev/null
+++ b/cesar/hal/ipmbox/maximus/src/maximus_ipmbox.c
@@ -0,0 +1,508 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/maximus/src/maximus_ipmbox.c
+ * \brief HAL IPMBox functions for Maximus.
+ * \ingroup hal_ipmbox_maximus
+ */
+
+#include "common/std.h"
+#include "hal/ipmbox/ipmbox.h"
+#include "hal/ipmbox/maximus/inc/maximus_ipmbox_ctx.h"
+#include "hal/ipmbox/maximus/inc/maximus_ether.h" // for 'maximus_ether_recv()'
+#include "hal/ipmbox/maximus/inc/maximus_interrupts.h" // for 'HAL_IPMBOX_INTERRUPT_IPMBOX' and 'HAL_IPMBOX_INTERRUPT_PRIORITY'
+#include "maximus/common/types/ethernet_types.h" // for 'ETHERNET_TYPE_...'
+#include "host/station/station.h" // for 'station_log()'
+#include "common/ipmbox/msg.h"
+#include "ecos/packages/hal/maximus/arch/current/include/hal_host_intr.h"
+#include <string.h> // for 'memset'
+#include <stdlib.h> // for 'free'
+#include <errno.h>
+
+#include "interface/sniffer/mmtype.h"
+#include "common/defs/homeplugAV.h"
+
+#ifdef ECOS
+static cyg_uint32 _ipmbox_ecos_rx_isr(cyg_vector_t vector, cyg_addrword_t data)
+{
+ cyg_drv_interrupt_mask(HAL_IPMBOX_RX_INTERRUPT);
+ cyg_drv_interrupt_acknowledge(HAL_IPMBOX_RX_INTERRUPT);
+ return CYG_ISR_CALL_DSR; // cause DSR to be run
+}
+
+static cyg_uint32 _ipmbox_ecos_buf_isr(cyg_vector_t vector, cyg_addrword_t data)
+{
+ cyg_drv_interrupt_mask(HAL_IPMBOX_BUF_INTERRUPT);
+ cyg_drv_interrupt_acknowledge(HAL_IPMBOX_BUF_INTERRUPT);
+ return CYG_ISR_CALL_DSR; // cause DSR to be run
+}
+
+static void _ipmbox_ecos_buf_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+ /* nothing to do except calling the ipmbox dsr */
+ ipmbox_t *ctx = (ipmbox_t *)data;
+ dbg_assert_ptr(ctx);
+ dbg_assert_ptr(ctx->empty_buf_cb);
+ dbg_assert_ptr(ctx->buf_user_data);
+ if ((NULL != ctx)
+ && (NULL != ctx->empty_buf_cb)
+ && (NULL != ctx->buf_user_data))
+ {
+ (*ctx->empty_buf_cb)(ctx->buf_user_data);
+ }
+ /* HAL_IPMBOX_BUF_INTERRUPT will be unmasked in ipmbox_empty_buf_get */
+ return;
+}
+
+static void _ipmbox_ecos_rx_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+ /* Only one thing to do: calling the appropriate ipmbox dsr. */
+ ipmbox_t *ctx = (ipmbox_t *) data;
+ dbg_assert_ptr (ctx);
+ dbg_assert_ptr (ctx->rx_cb_data);
+ dbg_assert_ptr (ctx->rx_cb_mbx);
+ dbg_assert_ptr (ctx->rx_cb_current);
+ dbg_assert_ptr (ctx->rx_data_user_data);
+ dbg_assert_ptr (ctx->rx_mbx_user_data);
+ dbg_assert ((ctx->rx_cb_current == ctx->rx_cb_mbx)
+ || (ctx->rx_cb_current == ctx->rx_cb_data));
+
+ if ((NULL != ctx)
+ && (NULL != ctx->rx_cb_data)
+ && (NULL != ctx->rx_cb_mbx)
+ && (NULL != ctx->rx_cb_current)
+ && (NULL != ctx->rx_data_user_data)
+ && (NULL != ctx->rx_mbx_user_data))
+ {
+ if (ctx->rx_cb_current == ctx->rx_cb_mbx)
+ {
+ (*ctx->rx_cb_mbx) (ctx->rx_mbx_user_data, ctx->rx_mbx.mailbox,
+ ctx->rx_mbx.length);
+ /* Reset total length of messages. */
+ ctx->rx_mbx.length = 0;
+ }
+ else if (ctx->rx_cb_current == ctx->rx_cb_data)
+ {
+ (*ctx->rx_cb_data) (ctx->rx_data_user_data, ctx->rx_data.mailbox,
+ ctx->rx_data.length);
+ /* Reset total length of messages. */
+ ctx->rx_data.length = 0;
+ }
+
+ ctx->rx_cb_current = NULL;
+ }
+ cyg_drv_interrupt_unmask(HAL_IPMBOX_RX_INTERRUPT);
+ return;
+}
+#endif /* ECOS */
+
+ipmbox_t *
+ipmbox_init (void)
+{
+ static ipmbox_t ctx;
+ static maximus_ipmbox_buffer_t first_buffer;
+
+ memset(&ctx, '\0', sizeof(ipmbox_t));
+
+ // initialize linked list of allocated buffers
+ ctx.first_buffer = &first_buffer;
+ ctx.first_buffer->next = NULL;
+ ctx.first_buffer->id = 0;
+ ctx.first_buffer->data = NULL;
+ ctx.last_buffer = ctx.first_buffer;
+
+ // register ether_recv to the sci layer
+ sci_register_callback(my_station.sci, SCI_MSG_TYPE_ETHERNET, maximus_ether_recv, &ctx);
+
+#ifdef ECOS
+ // Register the ipmbox RX_ISR and DSR into eCos.
+ cyg_drv_interrupt_create(HAL_IPMBOX_RX_INTERRUPT,
+ HAL_IPMBOX_INTERRUPT_PRIORITY,
+ (cyg_addrword_t)&ctx,
+ _ipmbox_ecos_rx_isr,
+ _ipmbox_ecos_rx_dsr,
+ &ctx.ipmbox_rx_interrupt_handle,
+ &ctx.ipmbox_rx_interrupt);
+ cyg_drv_interrupt_attach(ctx.ipmbox_rx_interrupt_handle);
+ cyg_drv_interrupt_mask(HAL_IPMBOX_RX_INTERRUPT);
+
+ // Register the ipmbox empty buffer ISR and DSR into eCos.
+ cyg_drv_interrupt_create(HAL_IPMBOX_BUF_INTERRUPT,
+ HAL_IPMBOX_INTERRUPT_PRIORITY,
+ (cyg_addrword_t)&ctx,
+ _ipmbox_ecos_buf_isr,
+ _ipmbox_ecos_buf_dsr,
+ &ctx.ipmbox_buf_interrupt_handle,
+ &ctx.ipmbox_buf_interrupt);
+ cyg_drv_interrupt_attach(ctx.ipmbox_buf_interrupt_handle);
+ cyg_drv_interrupt_mask(HAL_IPMBOX_BUF_INTERRUPT);
+#endif /* ECOS */
+
+ return &ctx;
+}
+
+void
+ipmbox_register_rx_data_cb (ipmbox_t *ctx, void *data_user_data,
+ ipmbox_rx_cb_t rx_cb_data)
+{
+ dbg_assert (ctx);
+ dbg_assert (rx_cb_data);
+ ctx->rx_data_user_data = data_user_data;
+ ctx->rx_cb_data = rx_cb_data;
+}
+
+void
+ipmbox_register_rx_mbx_cb (ipmbox_t *ctx, void *user_data,
+ ipmbox_rx_cb_t rx_cb_mbx)
+{
+ dbg_assert (ctx);
+ dbg_assert (rx_cb_mbx);
+ ctx->rx_mbx_user_data = user_data;
+ ctx->rx_cb_mbx = rx_cb_mbx;
+}
+
+void
+ipmbox_register_empty_buf_cb (ipmbox_t *ctx, void *data_user_data,
+ ipmbox_empty_buf_cb_t empty_buf_cb)
+{
+ dbg_assert_ptr(ctx);
+ dbg_assert_ptr(data_user_data);
+ dbg_assert_ptr(empty_buf_cb);
+
+ if ((NULL == ctx)
+ || (NULL == data_user_data)
+ || (NULL == empty_buf_cb))
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ ctx->buf_user_data = data_user_data;
+ ctx->empty_buf_cb = empty_buf_cb;
+ }
+}
+
+/**
+ * Activate ipmbox interruptions.
+ * \param ctx ipmbox context
+ * \param activation indicates if interruptions are activated or deactivated
+ * set errno to:
+ * - EINVAL if ctx is NULL
+ */
+void
+ipmbox_activate (ipmbox_t *ctx, bool activation)
+{
+ dbg_assert_ptr(ctx);
+ if (NULL == ctx)
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+#ifdef ECOS
+ if (activation)
+ {
+ cyg_drv_interrupt_unmask(HAL_IPMBOX_RX_INTERRUPT);
+ /* HAL_IPMBOX_BUF_INTERRUPT will be unmasked in ipmbox_empty_buf_get */
+ }
+ else
+ {
+ cyg_drv_interrupt_mask(HAL_IPMBOX_RX_INTERRUPT);
+ cyg_drv_interrupt_mask(HAL_IPMBOX_BUF_INTERRUPT);
+ }
+#endif /* ECOS */
+ }
+}
+
+/**
+ * Uninitialise the HAL IPMBOX.
+ * \param ctx ipmbox context
+ * set errno to:
+ * - EINVAL if ctx is NULL
+ */
+void
+ipmbox_uninit (ipmbox_t *ctx)
+{
+ dbg_assert_ptr(ctx);
+ if (NULL == ctx)
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ // release allocated buffers
+ maximus_ipmbox_buffer_t *current_buffer = ctx->first_buffer->next;
+ maximus_ipmbox_buffer_t *next_buffer = NULL;
+ while (NULL != current_buffer)
+ {
+ next_buffer = current_buffer->next;
+ free(current_buffer->data);
+ free(current_buffer);
+ current_buffer = next_buffer;
+ }
+
+ // reset ipmbox context
+ memset(ctx, '\0', sizeof(ipmbox_t));
+ }
+}
+
+void
+ipmbox_tx_data (ipmbox_t *ctx, u32 *first_msg, uint length)
+{
+ dbg_assert_ptr(ctx);
+ dbg_assert_ptr(first_msg);
+ dbg_assert(2 == length); /* TODO: length always 2 ? */
+ if ((NULL == ctx)
+ || (NULL == first_msg)
+ || (2 != length)) /* TODO */
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ ipmbox_msg_data_t msg_data;
+ // to release buffer
+ bool found = false;
+ /* TODO : mme tag ?*/
+
+ // get buffer pointer
+ memcpy (&msg_data, first_msg, sizeof (ipmbox_msg_data_t));
+
+ maximus_ipmbox_buffer_t *current_buffer = ctx->first_buffer;
+ maximus_ipmbox_buffer_t *previous_buffer = current_buffer;
+
+ // send DATA to Maximus
+ if (0 != maximus_ether_send (ctx, ETHERNET_TYPE_DATA, ETHERNET_FLAG_NONE,
+ ipmbox_msg_get_data_length (msg_data.header),
+ (u32 *) msg_data.buffer_addr))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when transmitting an Ethernet packet", errno);
+ }
+
+ // check that this pointer is still allocated
+ while ((NULL != current_buffer->next) && !found)
+ {
+ previous_buffer = current_buffer;
+ current_buffer = current_buffer->next;
+ // pointer to buffer to release
+ found = (msg_data.buffer_addr == (u32) current_buffer->data);
+ }
+ dbg_assert(found);
+ if (!found)
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ // for BUFFER RELEASED message
+ u32 id = current_buffer->id;
+
+ // before deallocating buffer, link previous to next,
+ // and update last buffer if needed
+ previous_buffer->next = current_buffer->next;
+ if (current_buffer == ctx->last_buffer)
+ {
+ ctx->last_buffer = previous_buffer;
+ }
+ free(current_buffer->data);
+ free(current_buffer);
+
+ // send BUFFER RELEASED to Maximus
+ if (0 != maximus_ether_send(ctx, ETHERNET_TYPE_BUFFER_RELEASED,
+ ETHERNET_FLAG_NONE, sizeof(u32), &id))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when transmitting an Ethernet packet", errno);
+ }
+ }
+ }
+}
+
+void
+ipmbox_tx_empty_buf (ipmbox_t *ctx, u32 *first_msg, uint length)
+{
+ dbg_assert_ptr(ctx);
+ dbg_assert_ptr(first_msg);
+ dbg_assert(IPMBOX_MSG_EMPTY_BUF_WORDS == length);
+ if ((NULL == ctx)
+ || (NULL == first_msg)
+ || (IPMBOX_MSG_EMPTY_BUF_WORDS != length))
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ ipmbox_msg_empty_buf_t msg_empty_buf;
+ memcpy (&msg_empty_buf, first_msg, sizeof (ipmbox_msg_empty_buf_t));
+
+ /* Deallocate buffer. */
+ dbg_assert (msg_empty_buf.buffer_addr);
+ if (0 != msg_empty_buf.buffer_addr)
+ {
+ free ((u32 *) msg_empty_buf.buffer_addr);
+ }
+ else
+ {
+ errno = EINVAL;
+ station_log (&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ }
+}
+
+void
+ipmbox_tx_mbx (ipmbox_t *ctx, u32 *first_msg, uint length)
+{
+ dbg_assert_ptr(ctx);
+ dbg_assert_ptr(first_msg);
+ dbg_assert(2 == length); /* TODO: length always 2 ? */
+ if ((NULL == ctx)
+ || (NULL == first_msg)
+ || (2 != length)) /* TODO */
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ ipmbox_msg_mbx_t msg_mbx;
+ // to release buffer
+ bool found = false;
+
+ // get buffer pointer
+ memcpy (&msg_mbx, first_msg, sizeof (ipmbox_msg_mbx_t));
+ dbg_assert (ipmbox_msg_get_mbx_type (msg_mbx.header) == \
+ IPMBOX_MSG_MBX_TYPE_MME_PRIV); /* TODO : DBG DUMP message ?*/
+ maximus_ipmbox_buffer_t *current_buffer = ctx->first_buffer;
+ maximus_ipmbox_buffer_t *previous_buffer = current_buffer;
+
+ // send MME to Maximus
+ if (0 != maximus_ether_send (ctx, ETHERNET_TYPE_MME, ETHERNET_FLAG_NONE,
+ ipmbox_msg_get_mme_priv_length (msg_mbx.header),
+ (u32 *) msg_mbx.buffer_addr))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when transmitting an Ethernet packet", errno);
+ }
+
+ // check that this pointer is still allocated
+ while ((NULL != current_buffer->next) && !found)
+ {
+ previous_buffer = current_buffer;
+ current_buffer = current_buffer->next;
+ // pointer to buffer to release
+ found = (msg_mbx.buffer_addr == (u32) current_buffer->data);
+ }
+ dbg_assert(found);
+ if (!found)
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ // for BUFFER RELEASED message
+ u32 id = current_buffer->id;
+
+ // before deallocating buffer, link previous to next,
+ // and update last buffer if needed
+ previous_buffer->next = current_buffer->next;
+ if (current_buffer == ctx->last_buffer)
+ {
+ ctx->last_buffer = previous_buffer;
+ }
+ free(current_buffer->data);
+ free(current_buffer);
+
+ // send BUFFER RELEASED to Maximus
+ if (0 != maximus_ether_send(ctx, ETHERNET_TYPE_BUFFER_RELEASED,
+ ETHERNET_FLAG_NONE, sizeof(u32), &id))
+ {
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ dbg_assert_print(false, "errno = %d when transmitting an Ethernet packet", errno);
+ }
+ }
+ }
+}
+
+/**
+ * Get nb empty buffers from the empty buf queue.
+ * \param ctx ipmbox context
+ * \param msg_buf destination array for the messages
+ * \param nb number of elements of msg_buf.
+ * \return number of copied element in msg_buf.
+ */
+uint
+ipmbox_empty_buf_get (ipmbox_t *ctx, u32 *msg_buf, uint nb_requested)
+{
+ uint nb_copied = nb_requested;
+
+ dbg_assert_ptr (ctx);
+ dbg_assert_ptr (msg_buf);
+ dbg_assert (nb_requested <= IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_EMPTY_BUF);
+ if ((NULL == ctx)
+ || (NULL == msg_buf)
+ || (nb_requested > IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_EMPTY_BUF))
+ {
+ errno = EINVAL;
+ station_log(&my_station, STATION_LOG_ERROR, STATION_LOGTYPE_ETHER,
+ "%s: errno = %d", __FUNCTION__, errno);
+ }
+ else
+ {
+ uint i;
+
+ if (nb_requested > ctx->rx_empty_buf.length)
+ {
+ nb_copied = ctx->rx_empty_buf.length;
+#ifdef ECOS
+ /* Cesar needs more buffers.
+ * => Unmask IT to warn Cesar when new buffers are available. */
+ cyg_drv_interrupt_unmask (HAL_IPMBOX_BUF_INTERRUPT);
+#endif /* ECOS */
+ }
+
+ memcpy (msg_buf, ctx->rx_empty_buf.mailbox, nb_copied * sizeof (u32));
+
+ /* Move elements that were not copied into the beginning of the mailbox array. */
+ for (i = 0; i < (ctx->rx_empty_buf.length - nb_copied) ; i++)
+ {
+ ctx->rx_empty_buf.mailbox[i] = ctx->rx_empty_buf.mailbox[nb_copied + i];
+ }
+
+ // decrement total length of messages
+ ctx->rx_empty_buf.length -= nb_copied;
+ }
+
+ return nb_copied;
+}
+
+uint
+ipmbox_rx_sync (ipmbox_t *ctx, const u32 **first_msg)
+{
+ dbg_assert_print (0, "NOT IMPLEMENTED");
+}
diff --git a/cesar/hal/ipmbox/maximus/test/Config b/cesar/hal/ipmbox/maximus/test/Config
new file mode 100644
index 0000000000..5077dbafd3
--- /dev/null
+++ b/cesar/hal/ipmbox/maximus/test/Config
@@ -0,0 +1,2 @@
+CONFIG_DEBUG = y
+CONFIG_DEBUG_FATAL_CATCH = y
diff --git a/cesar/hal/ipmbox/maximus/test/Makefile b/cesar/hal/ipmbox/maximus/test/Makefile
new file mode 100644
index 0000000000..f4e0b01309
--- /dev/null
+++ b/cesar/hal/ipmbox/maximus/test/Makefile
@@ -0,0 +1,8 @@
+BASE = ../../../..
+EXTRA_HOST_CFLAGS+= -DUNIT_TEST
+HOST_PROGRAMS = test_maximus_hle
+test_maximus_hle_SOURCES = test_maximus_hle.c test_maximus_ipmbox.c test_maximus_ether.c
+test_maximus_hle_MODULES = lib hal/ipmbox/maximus host
+INCLUDES = hal/ipmbox/maximus/test/inc
+
+include $(BASE)/common/make/top.mk
diff --git a/cesar/hal/ipmbox/maximus/test/src/test_maximus_ether.c b/cesar/hal/ipmbox/maximus/test/src/test_maximus_ether.c
new file mode 100644
index 0000000000..266eb94700
--- /dev/null
+++ b/cesar/hal/ipmbox/maximus/test/src/test_maximus_ether.c
@@ -0,0 +1,628 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/maximus/test/src/test_maximus_ipmbox.c
+ * \brief HAL ipmbox test functions for Maximus.
+ * \ingroup hal_ipmbox_maximus
+ */
+
+#include "common/std.h"
+#include "lib/test.h"
+#include "hal/ipmbox/maximus/test/inc/test_maximus_hle.h"
+#include "hal/ipmbox/maximus/inc/maximus_ether.h"
+#include "hal/ipmbox/maximus/inc/maximus_ipmbox_ctx.h"
+#include "hal/ipmbox/maximus/inc/maximus_interrupts.h"
+#include "hal/ipmbox/ipmbox.h"
+#include "host/station/station.h" // for 'station_ctx_t'
+#include "maximus/common/types/ethernet_types.h" // for 'ETHERNET_TYPE_...'
+#include "common/defs/homeplugAV.h" // for 'HPAV_MTYPE_MME' and 'HPAV_M(M)TYPE_OFFSET'
+#include "common/ipmbox/msg.h"
+#include "lib/swap.h" // for 'swap16()'
+#include <stdio.h> // for 'printf'
+#include <string.h> // for 'memset'
+#include <unistd.h> // for 'read'
+#include <fcntl.h> // for 'read'
+#include <stdlib.h> // for 'free'
+#include <errno.h>
+
+extern uint32_t maximus_pending_isrs; // used in 'station.c'
+extern station_ctx_t my_station;
+ipmbox_t *ctx;
+
+void maximus_ether_fill_hdr_test_case(test_t t)
+{
+ test_case_begin(t, "fill hdr");
+
+ sci_msg_t msg;
+ unsigned char buffer[SCI_MSG_MAX_SIZE];
+ uint8_t type = ETHERNET_TYPE_DATA;
+ uint8_t flags = ETHERNET_FLAG_NONE;
+
+ test_begin(t, "sci init")
+ {
+ memset(buffer, '\0', SCI_MSG_MAX_SIZE);
+ test_fail_unless ((0 == sci_msg_init(&msg, buffer, SCI_MSG_MAX_SIZE))
+ && (EINVAL != errno));
+ msg.length = 0;
+ } test_end;
+
+ test_begin(t, "fill hdr")
+ {
+ test_fail_unless ((0 == maximus_ether_fill_hdr(ctx, &msg, type, flags))
+ && (EINVAL != errno)
+ && (ETHERNET_VERSION == msg.hdr.ether->version)
+ && (type == msg.hdr.ether->type)
+ && (flags == msg.hdr.ether->flags)
+ && (0 == msg.hdr.ether->reserved));
+ } test_end;
+
+ test_begin(t, "fill hdr with incorrect type")
+ {
+ type = ETHERNET_TYPE_NONE;
+
+ dbg_fatal_try_begin
+ {
+ test_fail_unless ((-1 == maximus_ether_fill_hdr(ctx, &msg, type, flags))
+ && (EINVAL == errno));
+ }
+ dbg_fatal_try_catch (const char *fatal_message)
+ {
+ printf("fill hdr with incorrect type\n%s\n", fatal_message);
+ }
+ dbg_fatal_try_end;
+
+ // reset errno
+ errno = 0;
+
+ // reset type to correct value
+ type = ETHERNET_TYPE_DATA;
+ } test_end;
+
+ test_begin(t, "fill hdr with incorrect flags")
+ {
+ flags = ETHERNET_FLAG_MAX + 1;
+
+ dbg_fatal_try_begin
+ {
+ test_fail_unless ((-1 == maximus_ether_fill_hdr(ctx, &msg, type, flags))
+ && (EINVAL == errno));
+ }
+ dbg_fatal_try_catch (const char *fatal_message)
+ {
+ printf("fill hdr with incorrect flags\n%s\n", fatal_message);
+ }
+ dbg_fatal_try_end;
+
+ // reset errno
+ errno = 0;
+ } test_end;
+}
+
+void maximus_ether_recv_test_case(test_t t)
+{
+ sci_msg_t msg;
+ unsigned char buffer[SCI_MSG_MAX_SIZE];
+
+ test_case_begin(t, "recv");
+
+ test_begin(t, "sci init")
+ {
+ memset(buffer, '\0', SCI_MSG_MAX_SIZE);
+ test_fail_unless ((0 == sci_msg_init(&msg, buffer, SCI_MSG_MAX_SIZE))
+ && (EINVAL != errno));
+ msg.length = 0;
+ } test_end;
+
+ test_begin(t, "NULL msg")
+ {
+ dbg_fatal_try_begin
+ {
+ test_fail_unless ((0 > (maximus_ether_recv(NULL, ctx)))
+ && (EINVAL == errno));
+ }
+ dbg_fatal_try_catch (const char *fatal_message)
+ {
+ printf("NULL msg\n%s\n", fatal_message);
+ }
+ dbg_fatal_try_end;
+
+ // reset errno
+ errno = 0;
+ } test_end;
+
+ test_begin(t, "NULL ipmbox")
+ {
+ dbg_fatal_try_begin
+ {
+ test_fail_unless ((0 > (maximus_ether_recv(&msg, NULL)))
+ && (EINVAL == errno));
+ }
+ dbg_fatal_try_catch (const char *fatal_message)
+ {
+ printf("NULL ipmbox\n%s\n", fatal_message);
+ }
+ dbg_fatal_try_end;
+
+ // reset errno
+ errno = 0;
+ } test_end;
+
+ test_begin(t, "recv")
+ {
+ u32 buf_id = 1;
+ u32 total_buf_nb = 10;
+ maximus_ipmbox_buffer_t *first_buffer = NULL;
+ maximus_ipmbox_buffer_t *current_buffer = NULL;
+
+ // ether header
+ ether_msg_hdr_t ether_hdr;
+
+ // sci header
+ sci_msg_hdr_t sci_hdr;
+
+ // sci data
+ uint data_length = 1500;
+ u8 data[data_length];
+
+ // initialize sci data
+ memset(data, '\0', data_length);
+
+ // set ether header values
+ ether_hdr.version = ETHERNET_VERSION;
+ ether_hdr.type = ETHERNET_TYPE_NONE;
+ ether_hdr.flags = ETHERNET_FLAG_NONE;
+ ether_hdr.reserved = 0;
+
+ for (ether_hdr.type = ETHERNET_TYPE_DATA;
+ ether_hdr.type < ETHERNET_TYPE_BUFFER_RELEASED;
+ ether_hdr.type++)
+ {
+ /* Fill sci data. */
+
+ // ether type data or mme
+ if ((ETHERNET_TYPE_DATA == ether_hdr.type)
+ || (ETHERNET_TYPE_MME == ether_hdr.type))
+ {
+ uint i;
+ for (i=0; i<data_length; i++)
+ {
+ data[i] = (u8)i;
+ }
+ test_fail_unless (((int)data_length == sci_msg_push(&msg, data_length))
+ && (EINVAL != errno)
+ && (ENOSPC != errno));
+ memcpy(msg.data_begin, data, data_length);
+ }
+
+ // ether type buffer add
+ else if (ETHERNET_TYPE_BUFFER_ADD == ether_hdr.type)
+ {
+ for (buf_id = total_buf_nb; buf_id > 0; buf_id--)
+ {
+ test_fail_unless (((int)sizeof(u32) == sci_msg_push(&msg, sizeof(u32)))
+ && (EINVAL != errno)
+ && (ENOSPC != errno));
+ memcpy(msg.data_begin, &buf_id, sizeof(u32));
+ }
+ test_fail_unless (((int)sizeof(u32) == sci_msg_push(&msg, sizeof(u32)))
+ && (EINVAL != errno)
+ && (ENOSPC != errno));
+ memcpy(msg.data_begin, &total_buf_nb, sizeof(u32));
+ }
+
+ // fill ether header
+ test_fail_unless (((int)sizeof(ether_msg_hdr_t) == sci_msg_push(&msg, sizeof(ether_msg_hdr_t)))
+ && (EINVAL != errno)
+ && (ENOSPC != errno));
+ memcpy(msg.data_begin, &ether_hdr, sizeof(ether_msg_hdr_t));
+
+ // fill sci header
+ memcpy((u8 *)&sci_hdr.magic_id, SCI_MSG_MAGIC, 4);
+ sci_hdr.version = SCI_MSG_VERSION;
+ sci_hdr.type = SCI_MSG_TYPE_ETHERNET;
+ sci_hdr.flags = 0;
+ sci_hdr.station_id = my_station.id;
+ sci_hdr.length = msg.length - sizeof(sci_msg_hdr_t);
+ sci_hdr.msg_id = my_station.sci->current_msg_id | SCI_MSG_ID_STATION;
+ sci_hdr.netclock_high = my_station.current_tick_tck >> 32;
+ sci_hdr.netclock_low = my_station.current_tick_tck & 0xffffffff;
+ msg.sci_hdr = &sci_hdr;
+
+ test_fail_unless ((0 <= (maximus_ether_recv(&msg, ctx)))
+ && (EINVAL != errno)
+ && (EPROTO != errno));
+
+ test_fail_unless ((ether_hdr.version == msg.hdr.ether->version)
+ && (ether_hdr.type == msg.hdr.ether->type)
+ && (ether_hdr.flags == msg.hdr.ether->flags)
+ && (ether_hdr.reserved == msg.hdr.ether->reserved));
+
+ /* Check results. */
+
+ // test ether type data or mme
+ if (ETHERNET_TYPE_DATA == ether_hdr.type)
+ {
+ ipmbox_msg_data_t msg_data;
+ msg_data.header = ipmbox_msg_create_header_data (data_length, 0);
+
+ test_begin(t, "ether type data")
+ {
+ test_fail_unless ((maximus_pending_isrs & (1 << HAL_IPMBOX_RX_INTERRUPT))
+ && (2 == ctx->rx_data.length)
+ && (ctx->rx_data.mailbox[0] == msg_data.header)
+ && (0 == memcmp ((u8 *) ctx->rx_data.mailbox[1], data,
+ data_length)));
+ (*ctx->rx_cb_data) (ctx->rx_data_user_data, ctx->rx_data.mailbox,
+ ctx->rx_data.length);
+ maximus_pending_isrs &= ~(1 << HAL_IPMBOX_RX_INTERRUPT);
+ ctx->rx_data.length = 0;
+
+ // release allocated buffer
+ test_fail_unless (NULL != (u32 *)ctx->rx_data.mailbox[1]);
+ free((u32 *)ctx->rx_data.mailbox[1]);
+ } test_end;
+ }
+
+ else if (ETHERNET_TYPE_MME == ether_hdr.type)
+ {
+ ipmbox_msg_mbx_t msg_mbx;
+ msg_mbx.header = ipmbox_msg_create_header_mme_priv (data_length);
+
+ test_begin(t, "ether type mme")
+ {
+ test_fail_unless ((maximus_pending_isrs & (1 << HAL_IPMBOX_RX_INTERRUPT))
+ && (2 == ctx->rx_mbx.length)
+ && (ctx->rx_mbx.mailbox[0] == msg_mbx.header)
+ && (0 == memcmp ((u8 *) ctx->rx_mbx.mailbox[1], data,
+ data_length)));
+ (*ctx->rx_cb_mbx) (ctx->rx_mbx_user_data, ctx->rx_mbx.mailbox,
+ ctx->rx_mbx.length);
+ maximus_pending_isrs &= ~(1 << HAL_IPMBOX_RX_INTERRUPT);
+ ctx->rx_mbx.length = 0;
+
+ // release allocated buffer
+ test_fail_unless (NULL != (u32 *)ctx->rx_mbx.mailbox[1]);
+ free((u32 *)ctx->rx_mbx.mailbox[1]);
+ } test_end;
+ }
+
+ // test ether type buffer add
+ else if (ETHERNET_TYPE_BUFFER_ADD == ether_hdr.type)
+ {
+ uint i;
+
+ test_begin(t, "ether type buffer add")
+ {
+ ipmbox_msg_empty_buf_t expected_msg[total_buf_nb];
+ first_buffer = ctx->first_buffer->next;
+ current_buffer = first_buffer;
+ for (i=0; i<total_buf_nb; i++)
+ {
+ expected_msg[i].buffer_addr = (u32) current_buffer->data;
+ current_buffer = current_buffer->next;
+ }
+
+ // check mailbox contents
+ test_fail_unless ((maximus_pending_isrs & (1 << HAL_IPMBOX_BUF_INTERRUPT))
+ && (total_buf_nb == ctx->rx_empty_buf.length)
+ && (0 == memcmp (ctx->rx_empty_buf.mailbox,
+ expected_msg, total_buf_nb * sizeof (u32))));
+
+ // check list of the 10 allocated buffers
+ current_buffer = first_buffer;
+ for (i=1; i<total_buf_nb; i++)
+ {
+ test_fail_unless ((NULL != current_buffer->next)
+ && (i == current_buffer->id)
+ && (NULL != current_buffer->data));
+ current_buffer = current_buffer->next;
+ }
+ test_fail_unless ((NULL == current_buffer->next)
+ && (total_buf_nb == current_buffer->id)
+ && (NULL != current_buffer->data));
+
+ (*ctx->empty_buf_cb)(ctx->buf_user_data);
+ maximus_pending_isrs &= ~(1 << HAL_IPMBOX_BUF_INTERRUPT);
+ test_fail_unless (ctx->rx_empty_buf.length != 0);
+ } test_end;
+
+ test_begin (t, "empty buf get")
+ {
+ uint nb_requested = 4;
+ u32 msg_buf[IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_EMPTY_BUF];
+ test_fail_unless (ipmbox_empty_buf_get (ctx, msg_buf, nb_requested) \
+ == nb_requested);
+ test_fail_unless (ctx->rx_empty_buf.length == total_buf_nb - nb_requested);
+ current_buffer = first_buffer;
+ for (i = 0; i < nb_requested; i++)
+ {
+ test_fail_unless ((u32) current_buffer->data == msg_buf[i]);
+ current_buffer = current_buffer->next;
+ }
+
+ uint remaining_length = ctx->rx_empty_buf.length;
+ nb_requested = 22;
+ test_fail_unless (ipmbox_empty_buf_get (ctx, msg_buf, nb_requested) \
+ == remaining_length);
+ for (i = 0; i < remaining_length; i++)
+ {
+ test_fail_unless ((u32) current_buffer->data == msg_buf[i]);
+ current_buffer = current_buffer->next;
+ }
+
+ test_fail_unless (ctx->rx_empty_buf.length == 0);
+ } test_end;
+
+ test_begin(t, "release allocated buffers")
+ {
+ uint rls_buf_nb = 0;
+ maximus_ipmbox_buffer_t *next_buffer = NULL;
+ current_buffer = ctx->first_buffer->next;
+ while (NULL != current_buffer)
+ {
+ next_buffer = current_buffer->next;
+ free(current_buffer->data);
+ free(current_buffer);
+ current_buffer = next_buffer;
+ rls_buf_nb++;
+ }
+ ctx->first_buffer->next = NULL;
+ test_fail_unless (total_buf_nb == rls_buf_nb);
+ } test_end;
+ }
+ }
+
+ // test ether type none
+ ether_hdr.type = ETHERNET_TYPE_NONE;
+
+ // fill ether header
+ test_fail_unless (((int)sizeof(ether_msg_hdr_t) == sci_msg_push(&msg, sizeof(ether_msg_hdr_t)))
+ && (EINVAL != errno)
+ && (ENOSPC != errno));
+ memcpy(msg.data_begin, &ether_hdr, sizeof(ether_msg_hdr_t));
+
+ test_begin(t, "ether type none")
+ {
+ dbg_fatal_try_begin
+ {
+ test_fail_unless ((0 > (maximus_ether_recv(&msg, ctx)))
+ && (EINVAL == errno));
+ }
+ dbg_fatal_try_catch (const char *fatal_message)
+ {
+ printf("ether type none\n%s\n", fatal_message);
+ }
+ dbg_fatal_try_end;
+
+ // reset errno
+ errno = 0;
+ } test_end;
+
+ // test ether type buffer released
+ ether_hdr.type = ETHERNET_TYPE_BUFFER_RELEASED;
+
+ // fill ether header
+ test_fail_unless (((int)sizeof(ether_msg_hdr_t) == sci_msg_push(&msg, sizeof(ether_msg_hdr_t)))
+ && (EINVAL != errno)
+ && (ENOSPC != errno));
+ memcpy(msg.data_begin, &ether_hdr, sizeof(ether_msg_hdr_t));
+
+ test_begin(t, "ether type buffer released")
+ {
+ dbg_fatal_try_begin
+ {
+ test_fail_unless ((0 > (maximus_ether_recv(&msg, ctx)))
+ && (EINVAL == errno));
+ }
+ dbg_fatal_try_catch (const char *fatal_message)
+ {
+ printf("ether type buffer released\n%s\n", fatal_message);
+ }
+ dbg_fatal_try_end;
+
+ // reset errno
+ errno = 0;
+ } test_end;
+ } test_end;
+}
+
+void maximus_ether_send_test_case(test_t t)
+{
+ // ether type
+ u8 type = ETHERNET_TYPE_DATA;
+ u8 flags = ETHERNET_FLAG_NONE;
+
+ // data
+ int data_length = 1500;
+ u8 data[1500];
+
+ // initialize data
+ memset(data, '\0', data_length);
+
+ test_case_begin(t, "send");
+
+ test_begin(t, "send incorrect flags")
+ {
+ flags = ETHERNET_FLAG_MAX + 1;
+
+ dbg_fatal_try_begin
+ {
+ test_fail_unless ((0 > (maximus_ether_send(ctx, type, flags, data_length, (u32 *)data)))
+ && (EINVAL == errno));
+ }
+ dbg_fatal_try_catch (const char *fatal_message)
+ {
+ printf("send incorrect flags\n%s\n", fatal_message);
+ }
+ dbg_fatal_try_end;
+
+ // reset errno
+ errno = 0;
+
+ // set flags to correct value
+ flags = ETHERNET_FLAG_MAX;
+ } test_end;
+
+ test_begin(t, "send incorrect data length")
+ {
+ dbg_fatal_try_begin
+ {
+ test_fail_unless ((0 > (maximus_ether_send(ctx, type, flags, 0, (u32 *)data)))
+ && (EINVAL == errno));
+ }
+ dbg_fatal_try_catch (const char *fatal_message)
+ {
+ printf("send incorrect data length\n%s\n", fatal_message);
+ }
+ dbg_fatal_try_end;
+
+ // reset errno
+ errno = 0;
+ } test_end;
+
+ test_begin(t, "send null data")
+ {
+ dbg_fatal_try_begin
+ {
+ test_fail_unless ((0 > (maximus_ether_send(ctx, type, flags, data_length, NULL)))
+ && (EINVAL == errno));
+ }
+ dbg_fatal_try_catch (const char *fatal_message)
+ {
+ printf("send null data\n%s\n", fatal_message);
+ }
+ dbg_fatal_try_end;
+
+ // reset errno
+ errno = 0;
+ } test_end;
+
+ for (type = ETHERNET_TYPE_NONE; type < ETHERNET_TYPE_NB; type++)
+ {
+ // ether type none, or buffer add
+ if ((ETHERNET_TYPE_NONE == type)
+ || (ETHERNET_TYPE_BUFFER_ADD == type))
+ {
+ test_begin(t, "send invalid")
+ {
+ dbg_fatal_try_begin
+ {
+ test_fail_unless ((0 > (maximus_ether_send(ctx, type, flags, data_length, (u32 *)data)))
+ && (EINVAL == errno));
+ }
+ dbg_fatal_try_catch (const char *fatal_message)
+ {
+ printf("send invalid\n%s\n", fatal_message);
+ }
+ dbg_fatal_try_end;
+
+ // reset errno
+ errno = 0;
+ } test_end;
+ }
+
+ // ether type data, mme, buffer released, or sniffer
+ else if ((ETHERNET_TYPE_DATA == type)
+ || (ETHERNET_TYPE_MME == type)
+ || (ETHERNET_TYPE_BUFFER_RELEASED == type))
+ {
+ // ether type data, mme, or sniffer
+ if ((ETHERNET_TYPE_DATA == type)
+ || (ETHERNET_TYPE_MME == type))
+ {
+ // set data
+ int i;
+ for (i=0; i<data_length; i++)
+ {
+ data[i] = (u8)i;
+ }
+ }
+
+ // ether type buffer released
+ else // ETHERNET_TYPE_BUFFER_RELEASED
+ {
+ // set data length and data
+ int i;
+ data_length = 4;
+ for (i=0; i<data_length; i++)
+ {
+ data[i] = i;
+ }
+ }
+
+ test_begin(t, "send ether")
+ {
+ test_fail_unless ((0 == maximus_ether_send(ctx, type, flags, data_length, (u32 *)data))
+ && (EINVAL != errno));
+ } test_end;
+
+ /* Check results. */
+
+ // check that the correct ether message has been sent to Maximus
+ test_begin(t, "ether message")
+ {
+ unsigned char buffer[SCI_MSG_MAX_SIZE];
+ ether_msg_hdr_t *ether_hdr;
+ int fd_in = -1;
+
+ // open pipe or socket
+ fd_in = maximus_ether_open(&my_station);
+
+ // read sci and ether headers
+ memset(buffer, '\0', SCI_MSG_MAX_SIZE);
+ test_fail_unless ((-1 != fd_in)
+ && (sizeof(sci_msg_hdr_t) == read(fd_in, buffer, sizeof(sci_msg_hdr_t)))
+ && (sizeof(ether_msg_hdr_t) == read(fd_in, buffer + sizeof(sci_msg_hdr_t), sizeof(ether_msg_hdr_t))));
+
+ // set sci and ether headers pointers
+ ether_hdr = (ether_msg_hdr_t *)(buffer + sizeof(sci_msg_hdr_t));
+
+ // check ether header
+ test_fail_unless ((type == ether_hdr->type)
+ && (flags == ether_hdr->flags));
+
+ // read the remaining part of message
+ test_fail_unless (data_length == read(fd_in, buffer + sizeof(sci_msg_hdr_t) + sizeof(ether_msg_hdr_t), data_length));
+
+ // check ether data
+ test_fail_unless (0 == memcmp(data, buffer + sizeof(sci_msg_hdr_t) + sizeof(ether_msg_hdr_t), data_length));
+
+ // close pipe
+ maximus_ether_close(fd_in);
+ } test_end;
+ }
+ }
+}
+
+void ether_test_suite(test_t t)
+{
+ int rx_user_data = 0x12345678;
+ int buf_user_data = 0xFFFFFFFF;
+
+ // reset errno
+ errno = 0;
+
+ station_init (&my_station);
+ station_log_set_level(&my_station, STATION_LOG_DEBUG);
+ station_log_set_mask(&my_station, STATION_LOGTYPE_ALL);
+
+ ctx = ipmbox_init ();
+ ctx->warning_assert = true;
+ ipmbox_register_rx_data_cb (ctx, (void *) &rx_user_data, &rx_cb_data);
+ ipmbox_register_rx_mbx_cb (ctx, (void *) &rx_user_data, &rx_cb_mbx);
+ ipmbox_register_empty_buf_cb (ctx, (void *) &buf_user_data, &empty_buf_cb);
+ ipmbox_activate (ctx, true);
+
+ test_suite_begin(t, "ether");
+ maximus_ether_fill_hdr_test_case(t);
+ maximus_ether_recv_test_case(t);
+ maximus_ether_send_test_case(t);
+
+ ipmbox_uninit (ctx);
+ station_down (&my_station);
+}
diff --git a/cesar/hal/ipmbox/maximus/test/src/test_maximus_ipmbox.c b/cesar/hal/ipmbox/maximus/test/src/test_maximus_ipmbox.c
new file mode 100644
index 0000000000..1b56f7c524
--- /dev/null
+++ b/cesar/hal/ipmbox/maximus/test/src/test_maximus_ipmbox.c
@@ -0,0 +1,337 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/maximus/test/src/test_maximus_ipmbox.c
+ * \brief HAL ipmbox test functions for Maximus.
+ * \ingroup hal_ipmbox_maximus
+ */
+
+#include "common/std.h"
+#include "lib/test.h"
+#include "hal/ipmbox/maximus/test/inc/test_maximus_hle.h"
+#include "hal/ipmbox/maximus/inc/maximus_ipmbox_ctx.h" // for 'ipmbox_t'
+#include "hal/ipmbox/ipmbox.h"
+#include "host/station/station.h" // for 'station_ctx_t'
+#include "host/fwd.h" // for 'sci_msg_t'
+#include "maximus/common/types/ethernet_types.h" // for 'ether_msg_hdr_t'
+#include "common/ipmbox/msg.h"
+#include <stdio.h> // for 'printf'
+#include <string.h> // for 'memset'
+#include <unistd.h> // for 'read'
+#include <fcntl.h> // for 'read'
+#include <stdlib.h> // for 'malloc'
+#include <errno.h>
+
+extern uint32_t maximus_pending_isrs; // used in 'station.c'
+extern station_ctx_t my_station;
+ipmbox_t *ctx;
+
+static void
+test_buffer_released (test_t t, u32 buffer_id)
+{
+ test_begin(t, "ether message BUFFER RELEASED")
+ {
+ unsigned char buffer[SCI_MSG_MAX_SIZE];
+ ether_msg_hdr_t *ether_hdr;
+ int fd_in = -1;
+
+ // open pipe or socket
+ fd_in = maximus_ether_open(&my_station);
+
+ // read sci and ether headers
+ memset(buffer, '\0', SCI_MSG_MAX_SIZE);
+ test_fail_unless ((-1 != fd_in)
+ && (sizeof(sci_msg_hdr_t) == read(fd_in, buffer, sizeof(sci_msg_hdr_t)))
+ && (sizeof(ether_msg_hdr_t) == read(fd_in, buffer + sizeof(sci_msg_hdr_t), sizeof(ether_msg_hdr_t))));
+
+ // set sci and ether headers pointers
+ ether_hdr = (ether_msg_hdr_t *)(buffer + sizeof(sci_msg_hdr_t));
+
+ // check ether header
+ test_fail_unless ((ETHERNET_TYPE_BUFFER_RELEASED == ether_hdr->type)
+ && (ETHERNET_FLAG_NONE == ether_hdr->flags));
+
+ // read the remaining part of message
+ test_fail_unless (sizeof(u32) == read(fd_in, buffer + sizeof(sci_msg_hdr_t) + sizeof(ether_msg_hdr_t), sizeof(u32)));
+
+ // check ether data
+ test_fail_unless (buffer_id == *(buffer + sizeof(sci_msg_hdr_t) + sizeof(ether_msg_hdr_t)));
+
+ // close pipe
+ maximus_ether_close(fd_in);
+ } test_end;
+}
+
+static void
+test_ether_msg (test_t t, u8 *frame, int frame_length, u8 ether_type)
+{
+ // check that the correct ether message has been sent to Maximus
+ test_begin(t, "ether message")
+ {
+ unsigned char buffer[SCI_MSG_MAX_SIZE];
+ ether_msg_hdr_t *ether_hdr;
+ int fd_in = -1;
+
+ // open pipe or socket
+ fd_in = maximus_ether_open(&my_station);
+
+ // read sci and ether headers
+ memset(buffer, '\0', SCI_MSG_MAX_SIZE);
+ test_fail_unless ((-1 != fd_in)
+ && (sizeof(sci_msg_hdr_t) == read(fd_in, buffer, sizeof(sci_msg_hdr_t)))
+ && (sizeof(ether_msg_hdr_t) == read(fd_in, buffer + sizeof(sci_msg_hdr_t), sizeof(ether_msg_hdr_t))));
+
+ // set sci and ether headers pointers
+ ether_hdr = (ether_msg_hdr_t *)(buffer + sizeof(sci_msg_hdr_t));
+
+ // check ether header
+ test_fail_unless ((ether_type == ether_hdr->type)
+ && (ETHERNET_FLAG_NONE == ether_hdr->flags));
+
+ // read the remaining part of message
+ test_fail_unless (frame_length == read(fd_in, buffer + sizeof(sci_msg_hdr_t) + sizeof(ether_msg_hdr_t), frame_length));
+
+ // check ether data
+ test_fail_unless (0 == memcmp(frame, buffer + sizeof(sci_msg_hdr_t) + sizeof(ether_msg_hdr_t), frame_length));
+
+ // close pipe
+ maximus_ether_close(fd_in);
+ } test_end;
+}
+
+void ipmbox_init_test_case(test_t t)
+{
+ test_case_begin(t, "init");
+
+ test_begin(t, "init")
+ {
+ ctx = ipmbox_init ();
+ test_fail_unless ((EINVAL != errno)
+ && (NULL != ctx)
+ && (NULL != ctx->first_buffer)
+ && (NULL == ctx->first_buffer->next)
+ && (0 == ctx->first_buffer->id)
+ && (NULL == ctx->first_buffer->data)
+ && (ctx->last_buffer == ctx->first_buffer)
+ && (0 == ctx->rx_data.length)
+ && (0 == ctx->rx_mbx.length)
+ && (0 == ctx->rx_empty_buf.length));
+ ctx->warning_assert = true;
+ } test_end;
+
+ maximus_pending_isrs = 0;
+
+ return;
+}
+
+void
+ipmbox_register_rx_cb_test_case (test_t t)
+{
+ test_case_begin (t, "register rx cb");
+
+ test_begin(t, "register rx cb")
+ {
+ int rx_user_data = 42;
+
+ ipmbox_register_rx_data_cb (ctx, (void *) &rx_user_data,
+ &rx_cb_data);
+ ipmbox_register_rx_mbx_cb (ctx, (void *) &rx_user_data,
+ &rx_cb_mbx);
+ test_fail_unless (ctx->rx_cb_data != NULL);
+ test_fail_unless (ctx->rx_cb_mbx != NULL);
+ test_fail_unless (*(int *) ctx->rx_data_user_data == 42);
+ /* Check that the correct callback is registered. */
+ (*ctx->rx_cb_data) ((void *) &rx_user_data, NULL, 0);
+ test_fail_unless (rx_user_data == RX_CB_DATA_USER_DATA);
+ /* Check that the correct callback is registered. */
+ (*ctx->rx_cb_mbx) ((void *) &rx_user_data, NULL, 0);
+ test_fail_unless (rx_user_data == RX_CB_MBX_USER_DATA);
+ } test_end;
+}
+
+void
+ipmbox_register_empty_buf_cb_test_case (test_t t)
+{
+ test_case_begin (t, "register empty buf cb");
+
+ test_begin(t, "register empty buf cb")
+ {
+ int buf_user_data = 24;
+
+ ipmbox_register_empty_buf_cb (ctx, (void *) &buf_user_data,
+ &empty_buf_cb);
+ test_fail_unless (ctx->empty_buf_cb != NULL);
+ test_fail_unless (*(int *) ctx->buf_user_data == 24);
+ /* Check that the correct callback is registered. */
+ (*ctx->empty_buf_cb) ((void *) &buf_user_data);
+ test_fail_unless (buf_user_data == EMPTY_BUF_CB_USER_DATA);
+ } test_end;
+}
+
+void ipmbox_activate_test_case(test_t t)
+{
+ test_case_begin(t, "activate");
+
+ test_begin(t, "NULL ipmbox")
+ {
+ dbg_fatal_try_begin
+ {
+ ipmbox_activate (NULL, false);
+ test_fail_unless (EINVAL == errno);
+ }
+ dbg_fatal_try_catch (const char *fatal_message)
+ {
+ printf("NULL ipmbox\n%s\n", fatal_message);
+ }
+ dbg_fatal_try_end;
+
+ // reset errno
+ errno = 0;
+ } test_end;
+
+ test_begin(t, "activate")
+ {
+ ipmbox_activate (ctx, true);
+ test_fail_unless (EINVAL != errno);
+ } test_end;
+
+ return;
+}
+
+void ipmbox_uninit_test_case(test_t t)
+{
+ test_case_begin(t, "uninit");
+
+ test_begin(t, "uninit")
+ {
+ ipmbox_uninit(ctx);
+ test_fail_unless (EINVAL != errno);
+ } test_end;
+
+ return;
+}
+
+void ipmbox_tx_data_test_case(test_t t)
+{
+ test_case_begin(t, "tx data");
+
+ // ethernet frame data
+ int frame_length = 1200;
+ u8 frame[1200];
+ memset(frame, '\0', frame_length); // init frame
+
+ // mailbox msg
+ ipmbox_msg_data_t msg_data;
+ int i;
+
+ maximus_ipmbox_buffer_t *second_buffer = (maximus_ipmbox_buffer_t *) \
+ calloc (1, sizeof (maximus_ipmbox_buffer_t));
+ second_buffer->next = NULL;
+ second_buffer->id = 32;
+ second_buffer->data = (u32 *) calloc (frame_length, sizeof(u8));
+ for (i=0; i<frame_length; i++)
+ {
+ frame[i] = (u8)i;
+ *((u8*)second_buffer->data+i) = frame[i];
+ }
+ ctx->first_buffer->next = second_buffer;
+
+ // fill data message to send
+ msg_data.header = ipmbox_msg_create_header_data (frame_length, 0);
+ msg_data.buffer_addr = (u32) second_buffer->data;
+
+ test_begin(t, "tx data")
+ {
+ ipmbox_tx_data (ctx, (u32 *) &msg_data, 2);
+ test_fail_unless (EINVAL != errno);
+ } test_end;
+
+ /* Check results. */
+ test_ether_msg (t, frame, frame_length, ETHERNET_TYPE_DATA);
+ test_buffer_released (t, second_buffer->id);
+}
+
+void ipmbox_tx_mbx_test_case(test_t t)
+{
+ test_case_begin(t, "tx mbx");
+
+ // ethernet frame data
+ int frame_length = 1200;
+ u8 frame[1200];
+ memset(frame, '\0', frame_length); // init frame
+
+ // mailbox msg
+ ipmbox_msg_mbx_t msg_mbx;
+ int i;
+
+ maximus_ipmbox_buffer_t *second_buffer = (maximus_ipmbox_buffer_t *) \
+ calloc (1, sizeof (maximus_ipmbox_buffer_t));
+ second_buffer->next = NULL;
+ second_buffer->id = 32;
+ second_buffer->data = (u32 *) calloc (frame_length, sizeof(u8));
+ for (i=0; i<frame_length; i++)
+ {
+ frame[i] = (u8)i;
+ *((u8*)second_buffer->data+i) = frame[i];
+ }
+ ctx->first_buffer->next = second_buffer;
+
+ // fill mailbox message to send
+ msg_mbx.header = ipmbox_msg_create_header_mme_priv (frame_length);
+ msg_mbx.buffer_addr = (u32) second_buffer->data;
+
+ test_begin(t, "tx mme")
+ {
+ ipmbox_tx_mbx (ctx, (u32 *) &msg_mbx, 2);
+ test_fail_unless (EINVAL != errno);
+ } test_end;
+
+ /* Check results. */
+ test_ether_msg (t, frame, frame_length, ETHERNET_TYPE_MME);
+ test_buffer_released (t, second_buffer->id);
+}
+
+void ipmbox_tx_empty_buf_test_case(test_t t)
+{
+ test_case_begin(t, "tx empty buf");
+
+ test_begin(t, "tx empty buf")
+ {
+ // allocate buffer
+ u32 *data = (u32 *) malloc (1500);
+
+ /* Fill empty buffer message to send. */
+ ipmbox_msg_empty_buf_t empty_buf_msg;
+ empty_buf_msg.buffer_addr = (u32) data;
+
+ ipmbox_tx_empty_buf (ctx, (u32 *) &empty_buf_msg, 1);
+ test_fail_unless (EINVAL != errno);
+ } test_end;
+}
+
+void ipmbox_test_suite(test_t t)
+{
+ // reset errno
+ errno = 0;
+
+ station_init (&my_station);
+ station_log_set_level(&my_station, STATION_LOG_DEBUG);
+ station_log_set_mask(&my_station, STATION_LOGTYPE_ALL);
+
+ test_suite_begin(t, "ipmbox");
+ ipmbox_init_test_case(t);
+ ipmbox_register_rx_cb_test_case(t);
+ ipmbox_register_empty_buf_cb_test_case(t);
+ ipmbox_activate_test_case(t);
+ ipmbox_tx_data_test_case(t);
+ ipmbox_tx_empty_buf_test_case(t);
+ ipmbox_tx_mbx_test_case(t);
+ ipmbox_uninit_test_case(t);
+
+ station_down (&my_station);
+}
diff --git a/cesar/hal/ipmbox/src/ipmbox.c b/cesar/hal/ipmbox/src/ipmbox.c
new file mode 100644
index 0000000000..e3d84f3bd8
--- /dev/null
+++ b/cesar/hal/ipmbox/src/ipmbox.c
@@ -0,0 +1,411 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/src/ipmbox.c
+ * \brief HAL mailbox layer.
+ * \ingroup hal_ipmbox
+ *
+ * this layer provide all mechanisms to manage mailboxes.
+ */
+#include "common/std.h"
+
+#include "common/ipmbox/protocol.h"
+
+#include "hal/ipmbox/ipmbox.h"
+#include "hal/ipmbox/inc/ipmbox.h"
+#include "hal/ipmbox/inc/regs.h"
+#include "hal/ipmbox/inc/ecos.h"
+#include "hal/arch/arch.h"
+
+/** RX message buffer size. It must be equal to the max of data budget
+ * or MBX queue size. */
+#define IPMBOX_RX_MSG_BUFFER_SIZE \
+ (IPMBOX_RX_DATA_BUDGET > IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_MBX \
+ ? IPMBOX_RX_DATA_BUDGET : IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_MBX)
+
+/** Global context variable. */
+static ipmbox_t ipmbox_global;
+/** Ipmbox RX buffer. */
+static u32 rx_msgs[IPMBOX_RX_MSG_BUFFER_SIZE];
+
+/**
+ * Transmit a message to mailbox.
+ * \param ctx ipmbox context
+ * \param queue the queue to add the message to.
+ * \param first_msg pointer to the first message header
+ * \param length total length (in word) of messages to transmit
+ */
+PRIVATE inline void
+ipmbox_tx (ipmbox_t *ctx, ipmbox_queue_t *queue, u32 *first_msg, uint length)
+{
+ /* Copy messages to the ring buffer and warn the ARM.
+ * Lock DSR to prevent mailbox corruption. */
+ arch_dsr_lock ();
+ dbg_assert (ipmbox_queue_get_free_space (queue) >= length);
+ ipmbox_queue_copy_to (queue, first_msg, length);
+ ctx->regs->l2a_it = IPMBOX_L2A_IT;
+ arch_dsr_unlock ();
+}
+
+void
+ipmbox_tx_data (ipmbox_t *ctx, u32 *first_msg, uint length)
+{
+ ipmbox_tx (ctx, &ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_L2A],
+ first_msg, length);
+}
+
+void
+ipmbox_tx_empty_buf (ipmbox_t *ctx, u32 *first_msg, uint length)
+{
+ ipmbox_tx (ctx, &ctx->queue[IPMBOX_QUEUE_EMPTY_BUF][IPMBOX_L2A],
+ first_msg, length);
+}
+
+void
+ipmbox_tx_mbx (ipmbox_t *ctx, u32 *first_msg, uint length)
+{
+ ipmbox_tx (ctx, &ctx->queue[IPMBOX_QUEUE_MBX][IPMBOX_L2A],
+ first_msg, length);
+}
+
+uint
+ipmbox_empty_buf_get (ipmbox_t *ctx, u32 *msg_buf, uint nb)
+{
+ dbg_claim (ctx);
+ dbg_claim (msg_buf);
+ dbg_claim (nb);
+ ipmbox_queue_t *queue = &ctx->queue[IPMBOX_QUEUE_EMPTY_BUF][IPMBOX_A2L];
+ /* Lock DSR because threads can call this function. */
+ arch_dsr_lock ();
+ /* Clear interruption. */
+ ctx->regs->a2l_it = IPMBOX_A2L_IT_ACK;
+ uint size = ipmbox_queue_get_used_space (queue);
+ /* We need to unmask the interruption to be aware of new buffers. */
+ if (size < nb)
+ ctx->regs->a2l_it_mask &= ~IPMBOX_A2L_IT_ACK;
+ uint nb_elements = MIN (size, nb);
+ if (size)
+ ipmbox_queue_copy_from (queue, msg_buf, nb_elements);
+ /* Unlock DSR. */
+ arch_dsr_unlock ();
+ return nb_elements;
+}
+
+/**
+ * IPMBox receive ISR handler function for empty buffers.
+ * \param vector interrupt vector number
+ * \param data user interrupt arguments
+ * \return isr status and if DSR is needed
+ */
+cyg_uint32
+ipmbox_empty_buf_isr (cyg_vector_t vector, cyg_addrword_t data)
+{
+ /* Get context. */
+ ipmbox_t *ctx = (ipmbox_t *) data;
+ dbg_claim (ctx);
+ /* Block this interrupt from occurring until the DSR completes. */
+ ctx->regs->a2l_it_mask = IPMBOX_A2L_IT_ACK;
+ /* Acknowledge interrupt (because of shared child interrupt). */
+ ipmbox_interrupt_acknowledge (IPMBOX_EMPTY_BUF_IT_NUM);
+ /* Tell the kernel that chained interrupt processing is done and the DSR
+ * needs to be executed next. */
+ return (CYG_ISR_HANDLED | CYG_ISR_CALL_DSR);
+}
+
+/**
+ * IPMBox receive DSR handler function.
+ * \param vector interrupt vector number
+ * \param count ?
+ * \param data user interrupt arguments
+ */
+void
+ipmbox_empty_buf_dsr (cyg_vector_t vector, cyg_ucount32 count,
+ cyg_addrword_t data)
+{
+ ipmbox_t *ctx = (ipmbox_t*) data;
+ dbg_claim (ctx);
+ /* Send all received messages to the upper layer. */
+ ctx->empty_buf_cb (ctx->empty_buf_cb_user_data);
+}
+
+/**
+ * IPMBox receive ISR handler function.
+ * \param vector interrupt vector number
+ * \param data user interrupt arguments
+ * \return isr status and if DSR is needed
+ */
+cyg_uint32
+ipmbox_rx_isr (cyg_vector_t vector, cyg_addrword_t data)
+{
+ /* Get context. */
+ ipmbox_t *ctx = (ipmbox_t *) data;
+ dbg_claim (ctx);
+ /* Block this interrupt from occurring until the DSR completes. */
+ ctx->regs->a2l_it_mask |= IPMBOX_A2L_IT;
+ /* Acknowledge interrupt (because of shared child interrupt). */
+ ipmbox_interrupt_acknowledge (IPMBOX_RX_IT_NUM);
+ /* Tell the kernel that chained interrupt processing is done and the DSR
+ * needs to be executed next. */
+ return (CYG_ISR_HANDLED | CYG_ISR_CALL_DSR);
+}
+
+/**
+ * IPMBox receive DSR handler function.
+ * \param vector interrupt vector number
+ * \param count ?
+ * \param data user interrupt arguments
+ */
+void
+ipmbox_rx_dsr (cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+ ipmbox_t *ctx = (ipmbox_t*) data;
+ uint budget_data = IPMBOX_RX_DATA_BUDGET;
+ uint size;
+ bool call_dsr = false;
+ ipmbox_queue_t *queue_data = &ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L];
+ ipmbox_queue_t *queue_mbx = &ctx->queue[IPMBOX_QUEUE_MBX][IPMBOX_A2L];
+ /* Check parameters. */
+ dbg_claim (ctx->rx_cb_data);
+ dbg_claim (ctx->rx_cb_mbx);
+ /* Process DATA queue. */
+ do
+ {
+ size = ipmbox_queue_get_used_space (queue_data);
+ if (size)
+ {
+ /* Check and update budget_data. */
+ if (budget_data == 0)
+ {
+ call_dsr = true;
+ break;
+ }
+ if (size > budget_data)
+ size = budget_data;
+ budget_data -= size;
+ /* Copy messages out of mailbox, because callback can not handle
+ * circular buffers. */
+ ipmbox_queue_copy_from (queue_data, rx_msgs, size);
+ /* Send all received messages to the upper layer. */
+ ctx->rx_cb_data (ctx->rx_cb_data_user_data, rx_msgs, size);
+ }
+ }
+ while (size);
+
+ /* Process MBX queue. */
+ do
+ {
+ /* Clear interrupt. We can do this for the IT because before leaving
+ * this function, the DATA queue size is checked. */
+ ctx->regs->a2l_it = IPMBOX_A2L_IT;
+ size = ipmbox_queue_get_used_space (queue_mbx);
+ if (size)
+ {
+ /* Copy messages out of mailbox, because callback can not handle
+ * circular buffers. */
+ ipmbox_queue_copy_from (queue_mbx, rx_msgs, size);
+ /* Send all received messages to the upper layer. */
+ ctx->rx_cb_mbx (ctx->rx_cb_mbx_user_data, rx_msgs, size);
+ }
+ }
+ while (size);
+
+ /* Check DATA QUEUE used space to avoid IT enabling. */
+ if (ipmbox_queue_get_used_space (queue_data))
+ call_dsr = true;
+
+ if (call_dsr)
+ /* Ask to be executed again, do not activate interrupts. */
+ cyg_interrupt_post_dsr (ctx->ecos.rx_it_handle);
+ else
+ /* Allow this interrupt to occur again. */
+ ctx->regs->a2l_it_mask &= ~IPMBOX_A2L_IT;
+}
+
+uint
+ipmbox_rx_sync (ipmbox_t *ctx, const u32 **first_msg)
+{
+ uint size;
+ /* Only if interrupt set. */
+ if (ctx->regs->a2l_it & IPMBOX_A2L_IT)
+ {
+ ipmbox_queue_t *queue = &ctx->queue[IPMBOX_QUEUE_MBX][IPMBOX_A2L];
+ /* Clear interrupt. */
+ ctx->regs->a2l_it = IPMBOX_A2L_IT;
+ size = ipmbox_queue_get_used_space (queue);
+ if (size)
+ {
+ /* Copy messages out of mailbox, because callback can not handle
+ * circular buffers. */
+ ipmbox_queue_copy_from (queue, rx_msgs, size);
+ /* Return received messages. */
+ *first_msg = rx_msgs;
+ return size;
+ }
+ }
+ /* Nothing. */
+ return 0;
+}
+
+ipmbox_t *
+ipmbox_init (void)
+{
+ ipmbox_t *ctx = &ipmbox_global;
+
+ /* Map IPMBox registers. */
+ ctx->regs = (ipmbox_registers_t *) IPMBOX_REG_BASE_ADDR;
+ /* Map init_info structure. */
+ ipmbox_protocol_init_t *init_info = (ipmbox_protocol_init_t *)
+ ctx->regs->l2a_head;
+ /* Check version number. */
+ dbg_assert (init_info->version == IPMBOX_PROTOCOL_VERSION);
+ /* Check queues' sizes. */
+ dbg_assert (init_info->queue_size[IPMBOX_QUEUE_DATA][IPMBOX_A2L]
+ == IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_DATA);
+ dbg_assert (init_info->queue_size[IPMBOX_QUEUE_DATA][IPMBOX_L2A]
+ == IPMBOX_PROTOCOL_QUEUE_SIZE_L2A_DATA);
+ dbg_assert (init_info->queue_size[IPMBOX_QUEUE_EMPTY_BUF][IPMBOX_A2L]
+ == IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_EMPTY_BUF);
+ dbg_assert (init_info->queue_size[IPMBOX_QUEUE_EMPTY_BUF][IPMBOX_L2A]
+ == IPMBOX_PROTOCOL_QUEUE_SIZE_L2A_EMPTY_BUF);
+ dbg_assert (init_info->queue_size[IPMBOX_QUEUE_MBX][IPMBOX_A2L]
+ == IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_MBX);
+ dbg_assert (init_info->queue_size[IPMBOX_QUEUE_MBX][IPMBOX_L2A]
+ == IPMBOX_PROTOCOL_QUEUE_SIZE_L2A_MBX);
+ /* Initialize DATA queues. */
+ /* Sizes. */
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L].size =
+ init_info->queue_size[IPMBOX_QUEUE_DATA][IPMBOX_A2L];
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_L2A].size =
+ init_info->queue_size[IPMBOX_QUEUE_DATA][IPMBOX_L2A];
+ /* Queue pointers. */
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L].ptr =
+ (ipmbox_queue_ptr_t *) &ctx->regs->a2l_tail;
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_L2A].ptr =
+ (ipmbox_queue_ptr_t *) &ctx->regs->l2a_tail;
+ /* Base pointers. */
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L].base_ptr =
+ (u32*) ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L].ptr->tail
+ - ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L].size + 1;
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_L2A].base_ptr =
+ (u32*) ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_L2A].ptr->head;
+ /* End pointers. */
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L].end_ptr =
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L].base_ptr
+ + ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L].size;
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_L2A].end_ptr =
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_L2A].base_ptr
+ + ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_L2A].size;
+ /* Get shared memory base address. */
+ volatile ipmbox_queue_ptr_t *shared_mem_ptr_zone = init_info->shared_mem;
+ /* Initialize other queues. */
+ uint i, j;
+ for (i = IPMBOX_QUEUE_MBX; i < IPMBOX_QUEUE_DATA; i++)
+ {
+ for (j = IPMBOX_A2L; j < IPMBOX_QUEUE_DIRECTION_NB; j++)
+ {
+ ctx->queue[i][j].ptr = shared_mem_ptr_zone;
+ shared_mem_ptr_zone++;
+ ctx->queue[i][j].base_ptr = (u32*) ctx->queue[i][j].ptr->head;
+ ctx->queue[i][j].size = init_info->queue_size[i][j];
+ ctx->queue[i][j].end_ptr = ctx->queue[i][j].base_ptr
+ + ctx->queue[i][j].size;
+ }
+ }
+ /* Reset the tail pointers for DATA queue. */
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L].ptr->head =
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L].ptr->tail;
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_L2A].ptr->tail =
+ ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_L2A].ptr->head;
+ /* Reset others queues. */
+ for (i = IPMBOX_QUEUE_MBX; i < IPMBOX_QUEUE_DATA; i++)
+ for (j = IPMBOX_A2L; j < IPMBOX_QUEUE_DIRECTION_NB; j++)
+ ctx->queue[i][j].ptr->tail = ctx->queue[i][j].ptr->head;
+ /* Stop all mailbox interrupts. */
+ ctx->regs->a2l_it_mask = (IPMBOX_A2L_IT | IPMBOX_A2L_IT_ACK);
+ /* Create interrupt for Rx messages. */
+ cyg_drv_interrupt_create (IPMBOX_RX_IT_NUM,
+ 0,
+ (cyg_addrword_t) ctx,
+ &ipmbox_rx_isr,
+ &ipmbox_rx_dsr,
+ &ctx->ecos.rx_it_handle,
+ &ctx->ecos.rx_it);
+ /* Attach this interrupt. */
+ cyg_drv_interrupt_attach (ctx->ecos.rx_it_handle);
+ /* Create interrupt for Empty buffers messages. */
+ cyg_drv_interrupt_create (IPMBOX_EMPTY_BUF_IT_NUM,
+ 0,
+ (cyg_addrword_t) ctx,
+ &ipmbox_empty_buf_isr,
+ &ipmbox_empty_buf_dsr,
+ &ctx->ecos.empty_buf_it_handle,
+ &ctx->ecos.empty_buf_it);
+ /* Attach this interrupt. */
+ cyg_drv_interrupt_attach (ctx->ecos.empty_buf_it_handle);
+ /* Unmask. */
+ cyg_drv_interrupt_unmask (IPMBOX_RX_IT_NUM);
+ cyg_drv_interrupt_unmask (IPMBOX_EMPTY_BUF_IT_NUM);
+ return ctx;
+}
+
+void
+ipmbox_uninit (ipmbox_t *ctx)
+{
+ /* Stop all mailbox interrupts. */
+ ctx->regs->a2l_it_mask = (IPMBOX_A2L_IT | IPMBOX_A2L_IT_ACK);
+ /* Mask. */
+ cyg_drv_interrupt_mask (IPMBOX_RX_IT_NUM);
+}
+
+void
+ipmbox_activate (ipmbox_t *ctx, bool activation)
+{
+ dbg_assert (ctx);
+ dbg_assert (ctx->rx_cb_mbx);
+ dbg_assert (ctx->rx_cb_data);
+ if (activation)
+ {
+ /* Enable the Arm to Leon Trigger Interrupt. */
+ ctx->regs->a2l_it_mask &= ~IPMBOX_A2L_IT;
+ }
+ else
+ {
+ /* Disable the Arm to Leon Trigger and Ack Interrupt. */
+ ctx->regs->a2l_it_mask |= (IPMBOX_A2L_IT | IPMBOX_A2L_IT_ACK);
+ }
+}
+
+void
+ipmbox_register_rx_data_cb (ipmbox_t *ctx, void *user_data,
+ ipmbox_rx_cb_t rx_cb_data)
+{
+ dbg_assert (ctx);
+ dbg_assert (rx_cb_data);
+ ctx->rx_cb_data = rx_cb_data;
+ ctx->rx_cb_data_user_data = user_data;
+}
+
+void
+ipmbox_register_rx_mbx_cb (ipmbox_t *ctx, void *user_data,
+ ipmbox_rx_cb_t rx_cb_mbx)
+{
+ dbg_assert (ctx);
+ dbg_assert (rx_cb_mbx);
+ ctx->rx_cb_mbx = rx_cb_mbx;
+ ctx->rx_cb_mbx_user_data = user_data;
+}
+
+void
+ipmbox_register_empty_buf_cb (ipmbox_t *ctx, void *user_data,
+ ipmbox_empty_buf_cb_t empty_buf_cb)
+{
+ dbg_assert (ctx);
+ dbg_assert (empty_buf_cb);
+ ctx->empty_buf_cb = empty_buf_cb;
+ ctx->empty_buf_cb_user_data = user_data;
+}
diff --git a/cesar/hal/ipmbox/stub/Module b/cesar/hal/ipmbox/stub/Module
new file mode 100644
index 0000000000..2a248a2de2
--- /dev/null
+++ b/cesar/hal/ipmbox/stub/Module
@@ -0,0 +1 @@
+SOURCES := ipmbox.c \ No newline at end of file
diff --git a/cesar/hal/ipmbox/stub/src/ipmbox.c b/cesar/hal/ipmbox/stub/src/ipmbox.c
new file mode 100644
index 0000000000..e1b221fb5f
--- /dev/null
+++ b/cesar/hal/ipmbox/stub/src/ipmbox.c
@@ -0,0 +1,117 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/stub/src/ipmbox.c
+ * \brief HAL IPMbox stub functions.
+ * \ingroup hal_ipmbox_stub
+ */
+#include "hal/ipmbox/ipmbox.h"
+
+ipmbox_t *
+ipmbox_init (void) __attribute__((weak));
+
+ipmbox_t *
+ipmbox_init (void)
+{
+ return NULL;
+}
+
+void
+ipmbox_uninit (ipmbox_t *ctx) __attribute__((weak));
+
+void
+ipmbox_uninit (ipmbox_t *ctx)
+{
+}
+
+void
+ipmbox_activate (ipmbox_t *ctx, bool activation) __attribute__((weak));
+
+void
+ipmbox_activate (ipmbox_t *ctx, bool activation)
+{
+}
+
+void
+ipmbox_register_rx_data_cb (ipmbox_t *ctx, void *data_user_data,
+ ipmbox_rx_cb_t rx_cb_data) __attribute__((weak));
+
+void
+ipmbox_register_rx_data_cb (ipmbox_t *ctx, void *data_user_data,
+ ipmbox_rx_cb_t rx_cb_data)
+{
+}
+
+void
+ipmbox_register_rx_mbx_cb (ipmbox_t *ctx, void *data_user_data,
+ ipmbox_rx_cb_t rx_cb_mbx) __attribute__((weak));
+
+void
+ipmbox_register_rx_mbx_cb (ipmbox_t *ctx, void *data_user_data,
+ ipmbox_rx_cb_t rx_cb_mbx)
+{
+}
+
+
+void
+ipmbox_register_empty_buf_cb (ipmbox_t *ctx, void *data_user_data,
+ ipmbox_empty_buf_cb_t empty_buf_cb)
+ __attribute__((weak));
+
+void
+ipmbox_register_empty_buf_cb (ipmbox_t *ctx, void *data_user_data,
+ ipmbox_empty_buf_cb_t empty_buf_cb)
+{
+}
+
+void
+ipmbox_tx_data (ipmbox_t *ctx, u32 *first_msg, uint length)
+ __attribute__((weak));
+
+void
+ipmbox_tx_data (ipmbox_t *ctx, u32 *first_msg, uint length)
+{
+}
+
+void
+ipmbox_tx_empty_buf (ipmbox_t *ctx, u32 *first_msg, uint length)
+ __attribute__((weak));
+
+void
+ipmbox_tx_empty_buf (ipmbox_t *ctx, u32 *first_msg, uint length)
+{
+}
+
+void
+ipmbox_tx_mbx (ipmbox_t *ctx, u32 *first_msg, uint length)
+ __attribute__((weak));
+
+void
+ipmbox_tx_mbx (ipmbox_t *ctx, u32 *first_msg, uint length)
+{
+}
+
+uint
+ipmbox_empty_buf_get (ipmbox_t *ctx, u32 *msg_buf, uint nb)
+ __attribute__((weak));
+
+uint
+ipmbox_empty_buf_get (ipmbox_t *ctx, u32 *msg_buf, uint nb)
+{
+ return 0;
+}
+
+uint
+ipmbox_rx_sync (ipmbox_t *ctx, const u32 **first_msg)
+ __attribute__((weak));
+
+uint
+ipmbox_rx_sync (ipmbox_t *ctx, const u32 **first_msg)
+{
+ return 0;
+}
diff --git a/cesar/hal/ipmbox/test/Config b/cesar/hal/ipmbox/test/Config
new file mode 100644
index 0000000000..dbdade324f
--- /dev/null
+++ b/cesar/hal/ipmbox/test/Config
@@ -0,0 +1 @@
+CONFIG_DEBUG_FATAL_CATCH=y
diff --git a/cesar/hal/ipmbox/test/Makefile b/cesar/hal/ipmbox/test/Makefile
new file mode 100644
index 0000000000..4820f10f9b
--- /dev/null
+++ b/cesar/hal/ipmbox/test/Makefile
@@ -0,0 +1,10 @@
+BASE = ../../..
+
+INCLUDES = hal/ipmbox/test/override/
+
+HOST_PROGRAMS = test_ipmbox
+
+test_ipmbox_SOURCES = ipmbox.c
+test_ipmbox_MODULES = lib hal/ipmbox ../common/ipmbox
+
+include $(BASE)/common/make/top.mk
diff --git a/cesar/hal/ipmbox/test/override/hal/ipmbox/inc/ecos.h b/cesar/hal/ipmbox/test/override/hal/ipmbox/inc/ecos.h
new file mode 100644
index 0000000000..82271c3c82
--- /dev/null
+++ b/cesar/hal/ipmbox/test/override/hal/ipmbox/inc/ecos.h
@@ -0,0 +1,58 @@
+#ifndef hal_ipmbox_inc_ipmbox_ecos_h
+#define hal_ipmbox_inc_ipmbox_ecos_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file override/hal/ipmbox/inc/ipmbox_ecos.h
+ * \brief HAL IPMBox eCos management data.
+ * \ingroup hal_ipmbox_test
+ */
+
+/* eCos stubs. */
+
+#define CYG_ISR_HANDLED 1
+#define CYG_ISR_CALL_DSR 1
+
+#define CYGNUM_HAL_INTERRUPT_GIC2_14 0x42
+#define CYGNUM_HAL_INTERRUPT_GIC2_13 0x42
+
+/* Types. */
+typedef unsigned long CYG_ADDRWORD;
+typedef unsigned long cyg_uint32;
+typedef unsigned long cyg_vector_t;
+typedef unsigned long cyg_addrword_t;
+typedef unsigned long cyg_ucount32;
+
+typedef struct ipmbox_ecos_t
+{
+ int rx_it;
+ int rx_it_handle;
+ int empty_buf_it;
+ int empty_buf_it_handle;
+} ipmbox_ecos_t;
+
+/* Functions. */
+#define ipmbox_interrupt_acknowledge(param) ((void) 0)
+
+#define cyg_drv_interrupt_create(...) ((void) 0)
+
+#define cyg_drv_interrupt_attach(...) ((void) 0)
+
+#define cyg_drv_interrupt_unmask(...) ((void) 0)
+
+#define cyg_drv_interrupt_mask(...) ((void) 0)
+
+extern bool dsr_posted;
+
+extern inline void
+cyg_interrupt_post_dsr (CYG_ADDRWORD intr_obj)
+{
+ dsr_posted = true;
+}
+
+#endif /* hal_ipmbox_inc_ipmbox_ecos_h */
diff --git a/cesar/hal/ipmbox/test/override/hal/ipmbox/inc/regs.h b/cesar/hal/ipmbox/test/override/hal/ipmbox/inc/regs.h
new file mode 100644
index 0000000000..ba5fd0bdc4
--- /dev/null
+++ b/cesar/hal/ipmbox/test/override/hal/ipmbox/inc/regs.h
@@ -0,0 +1,21 @@
+#ifndef hal_ipmbox_inc_ipmbox_regs_h
+#define hal_ipmbox_inc_ipmbox_regs_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2012 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file override/hal/ipmbox/inc/ipmbox_regs.h
+ * \brief HAL IPMBox registers base address.
+ * \ingroup hal_ipmbox_test
+ */
+
+extern ipmbox_registers_t regs;
+
+/* IPMBox registers base address. */
+#define IPMBOX_REG_BASE_ADDR (&regs)
+
+#endif /* hal_ipmbox_inc_ipmbox_regs_h */
diff --git a/cesar/hal/ipmbox/test/src/ipmbox.c b/cesar/hal/ipmbox/test/src/ipmbox.c
new file mode 100644
index 0000000000..d9ed882751
--- /dev/null
+++ b/cesar/hal/ipmbox/test/src/ipmbox.c
@@ -0,0 +1,502 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/ipmbox/test/src/ipmbox.c
+ * \brief HAL HLE unit test to test the ipmbox mechanisms.
+ * \ingroup hal_ipmbox
+ *
+ * This file will tests all ipmbox functions
+ */
+#include "common/std.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "lib/test.h"
+#include "lib/blk.h"
+
+#include "hal/ipmbox/ipmbox.h"
+#include "hal/ipmbox/inc/ipmbox.h"
+#include "hal/ipmbox/inc/regs.h"
+
+#include "common/ipmbox/protocol.h"
+
+bool dsr_posted;
+bool data_cb_called;
+bool mbx_cb_called;
+bool empty_buf_cb_called;
+
+/* Shared memory size (in 32 bits words). */
+#define SHARED_MEM_SIZE (IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_MBX \
+ + IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_DATA \
+ + IPMBOX_PROTOCOL_QUEUE_SIZE_L2A_EMPTY_BUF \
+ + IPMBOX_PROTOCOL_QUEUE_SIZE_L2A_MBX \
+ + IPMBOX_PROTOCOL_QUEUE_SIZE_L2A_DATA \
+ + IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_EMPTY_BUF \
+ + 8)
+
+/* Shared memory offsets. */
+#define SHMEM_PTR_ZONE 0
+#define SHMEM_A2L_MBX_QUEUE_BASE (SHMEM_PTR_ZONE + 8)
+#define SHMEM_L2A_MBX_QUEUE_BASE (SHMEM_A2L_MBX_QUEUE_BASE \
+ + IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_MBX)
+#define SHMEM_A2L_EMPTY_BUF_QUEUE_BASE (SHMEM_L2A_MBX_QUEUE_BASE \
+ + IPMBOX_PROTOCOL_QUEUE_SIZE_L2A_MBX)
+#define SHMEM_L2A_EMPTY_BUF_QUEUE_BASE (SHMEM_A2L_EMPTY_BUF_QUEUE_BASE \
+ + IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_EMPTY_BUF)
+#define SHMEM_A2L_DATA_QUEUE_BASE (SHMEM_L2A_EMPTY_BUF_QUEUE_BASE \
+ + IPMBOX_PROTOCOL_QUEUE_SIZE_L2A_EMPTY_BUF)
+#define SHMEM_L2A_DATA_QUEUE_BASE (SHMEM_A2L_DATA_QUEUE_BASE \
+ + IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_DATA)
+
+uint qsize [][IPMBOX_QUEUE_DIRECTION_NB] = {
+ {IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_MBX, IPMBOX_PROTOCOL_QUEUE_SIZE_L2A_MBX},
+ {IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_EMPTY_BUF,
+ IPMBOX_PROTOCOL_QUEUE_SIZE_L2A_EMPTY_BUF},
+ {IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_DATA,
+ IPMBOX_PROTOCOL_QUEUE_SIZE_L2A_DATA}
+ };
+
+/* Fake hardware registers. */
+ipmbox_registers_t regs;
+
+/* Fake shared memory between LEON and ARM. */
+u32 shared_mem[SHARED_MEM_SIZE];
+
+/* Prototype declarations. */
+void
+ipmbox_rx_dsr (cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
+
+void
+ipmbox_empty_buf_dsr (cyg_vector_t vector, cyg_ucount32 count,
+ cyg_addrword_t data);
+
+/* Callbacks test stub. */
+void
+ipmbox_test_data_cb (void *user_data, u32 *first_msg, uint length)
+{
+ data_cb_called = true;
+}
+
+void
+ipmbox_test_mbx_cb (void *user_data, u32 *first_msg, uint length)
+{
+ mbx_cb_called = true;
+}
+
+void
+ipmbox_test_empty_buf_cb (void *user_data)
+{
+ empty_buf_cb_called = true;
+}
+
+ipmbox_t *
+ipmbox_test_init (void)
+{
+ /* Init fake regs. */
+ regs.a2l_tail = (u32) &shared_mem[SHMEM_A2L_DATA_QUEUE_BASE
+ + qsize[IPMBOX_QUEUE_DATA][IPMBOX_A2L] - 1];
+ regs.a2l_head = (u32) INVALID_PTR;
+ regs.l2a_head = (u32) &shared_mem[SHMEM_L2A_DATA_QUEUE_BASE];
+ regs.l2a_tail = (u32) INVALID_PTR;
+ regs.a2l_it = 0;
+ regs.a2l_it_mask = 0;
+ regs.l2a_it = 0;
+ regs.l2a_it_mask = 0;
+ /* Init pointer in the shared memory ptr zone. */
+ u32 shmem_queue_base [] = {
+ SHMEM_A2L_MBX_QUEUE_BASE,
+ SHMEM_L2A_MBX_QUEUE_BASE,
+ SHMEM_A2L_EMPTY_BUF_QUEUE_BASE,
+ SHMEM_L2A_EMPTY_BUF_QUEUE_BASE,
+ };
+ ipmbox_queue_ptr_t *queue =
+ (ipmbox_queue_ptr_t*) &shared_mem[SHMEM_PTR_ZONE];
+ uint i;
+ for (i = 0; i < COUNT (shmem_queue_base); i++)
+ {
+ queue->head = (u32) &shared_mem[shmem_queue_base[i]];
+ queue->tail = (u32) INVALID_PTR;
+ queue++;
+ }
+ /* Initialise init info zone inside DATA L2A. */
+ ipmbox_protocol_init_t *init = (ipmbox_protocol_init_t*) regs.l2a_head;
+ init->version = IPMBOX_PROTOCOL_VERSION;
+ init->shared_mem = (ipmbox_queue_ptr_t*) shared_mem;
+ uint j;
+ for (i = 0; i < COUNT (qsize); i++)
+ for (j = 0; j < COUNT (qsize[i]); j++)
+ init->queue_size[i][j] = qsize[i][j];
+ ipmbox_t *ctx = ipmbox_init ();
+ /* Initialise callbacks. */
+ ipmbox_register_rx_data_cb (ctx, INVALID_PTR, ipmbox_test_data_cb);
+ ipmbox_register_rx_mbx_cb (ctx, INVALID_PTR, ipmbox_test_mbx_cb);
+ ipmbox_register_empty_buf_cb (ctx, INVALID_PTR, ipmbox_test_empty_buf_cb);
+ return ctx;
+}
+
+void
+ipmbox_init_test_case (test_t t)
+{
+ ipmbox_t *ctx = ipmbox_test_init ();
+ test_case_begin (t, "init/uninit/(de)activate");
+ test_begin (t, "init")
+ {
+ test_fail_unless (ctx->regs == IPMBOX_REG_BASE_ADDR);
+ /* Check mapping of queues' pointers. */
+ test_fail_unless (ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L].ptr
+ == (ipmbox_queue_ptr_t*) &ctx->regs->a2l_tail);
+ test_fail_unless (ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_L2A].ptr
+ == (ipmbox_queue_ptr_t*) &ctx->regs->l2a_tail);
+ test_fail_unless (
+ ctx->queue[IPMBOX_QUEUE_MBX][IPMBOX_A2L].ptr
+ == (ipmbox_queue_ptr_t*) &shared_mem[SHMEM_PTR_ZONE]);
+ test_fail_unless (
+ ctx->queue[IPMBOX_QUEUE_MBX][IPMBOX_L2A].ptr
+ == (ipmbox_queue_ptr_t*) &shared_mem[SHMEM_PTR_ZONE + 2]);
+ test_fail_unless (
+ ctx->queue[IPMBOX_QUEUE_EMPTY_BUF][IPMBOX_A2L].ptr
+ == (ipmbox_queue_ptr_t*) &shared_mem[SHMEM_PTR_ZONE + 4]);
+ test_fail_unless (
+ ctx->queue[IPMBOX_QUEUE_EMPTY_BUF][IPMBOX_L2A].ptr
+ == (ipmbox_queue_ptr_t*) &shared_mem[SHMEM_PTR_ZONE + 6]);
+
+ u32 shmem_queue_base [][IPMBOX_QUEUE_DIRECTION_NB] = {
+ {SHMEM_A2L_MBX_QUEUE_BASE, SHMEM_L2A_MBX_QUEUE_BASE},
+ {SHMEM_A2L_EMPTY_BUF_QUEUE_BASE, SHMEM_L2A_EMPTY_BUF_QUEUE_BASE},
+ {SHMEM_A2L_DATA_QUEUE_BASE, SHMEM_L2A_DATA_QUEUE_BASE}
+ };
+ uint i, j;
+ for (i = 0; i < COUNT (shmem_queue_base); i++)
+ {
+ for (j = 0; j < COUNT (shmem_queue_base[i]); j++)
+ {
+ test_fail_unless (ctx->queue[i][j].ptr->head
+ == ctx->queue[i][j].ptr->tail);
+ test_fail_unless (ctx->queue[i][j].base_ptr
+ == &shared_mem[shmem_queue_base[i][j]]);
+ test_fail_unless (ctx->queue[i][j].size == qsize[i][j]);
+ test_fail_unless (ctx->queue[i][j].end_ptr
+ == ctx->queue[i][j].base_ptr + qsize[i][j]);
+ }
+ }
+ /* Check registers. */
+ test_fail_unless (ctx->regs->a2l_it == 0);
+ test_fail_unless (ctx->regs->l2a_it == 0);
+ test_fail_unless (ctx->regs->a2l_it_mask
+ == (IPMBOX_A2L_IT | IPMBOX_A2L_IT_ACK));
+ test_fail_unless (ctx->regs->l2a_it_mask == 0);
+ }
+ test_end;
+ test_begin (t, "(de)activate")
+ {
+ ipmbox_activate (ctx, true);
+ test_fail_unless (ctx->regs->a2l_it_mask == IPMBOX_A2L_IT_ACK);
+ ipmbox_activate (ctx, false);
+ test_fail_unless (ctx->regs->a2l_it_mask
+ == (IPMBOX_A2L_IT | IPMBOX_A2L_IT_ACK));
+ }
+ test_end;
+ test_begin (t, "uninit")
+ {
+ ctx->regs->a2l_it_mask = 0;
+ ipmbox_uninit (ctx);
+ test_fail_unless (ctx->regs->a2l_it_mask
+ == (IPMBOX_A2L_IT | IPMBOX_A2L_IT_ACK));
+ }
+ test_end;
+}
+
+void
+ipmbox_callback_register_test_case (test_t t)
+{
+ test_case_begin (t, "Register callbacks");
+ test_begin (t, "all")
+ {
+ ipmbox_t *ctx = ipmbox_test_init ();
+ ipmbox_register_rx_data_cb (ctx, INVALID_PTR, ipmbox_test_data_cb);
+ ipmbox_register_rx_mbx_cb (ctx, INVALID_PTR, ipmbox_test_mbx_cb);
+ ipmbox_register_empty_buf_cb (
+ ctx, INVALID_PTR + 1, ipmbox_test_empty_buf_cb);
+ test_fail_unless (ctx->rx_cb_data_user_data == INVALID_PTR);
+ test_fail_unless (ctx->rx_cb_mbx_user_data == INVALID_PTR);
+ test_fail_unless (ctx->rx_cb_data == ipmbox_test_data_cb);
+ test_fail_unless (ctx->rx_cb_mbx == ipmbox_test_mbx_cb);
+ test_fail_unless (ctx->empty_buf_cb_user_data == INVALID_PTR + 1);
+ test_fail_unless (ctx->empty_buf_cb == ipmbox_test_empty_buf_cb);
+ ipmbox_uninit (ctx);
+ }
+ test_end;
+}
+
+void
+ipmbox_tx_test_case (test_t t)
+{
+ test_case_begin (t, "Tx to Arm");
+ test_begin (t, "DATA/MBX/EMPTY_BUF")
+ {
+ ipmbox_t *ctx = ipmbox_test_init ();
+ u32 msg[2];
+ /* First call each tx function and check after each call the IT is
+ * raised. */
+ ctx->regs->l2a_it = 0;
+ msg[0] = 0x42;
+ msg[1] = 0x43;
+ ipmbox_tx_data (ctx, msg, 2);
+ test_fail_unless (ctx->regs->l2a_it == IPMBOX_L2A_IT);
+ ctx->regs->l2a_it = 0;
+ msg[0] = 0x44;
+ msg[1] = 0x45;
+ ipmbox_tx_mbx (ctx, msg, 2);
+ test_fail_unless (ctx->regs->l2a_it == IPMBOX_L2A_IT);
+ ctx->regs->l2a_it = 0;
+ msg[0] = 0x46;
+ msg[1] = 0x47;
+ ipmbox_tx_empty_buf (ctx, msg, 2);
+ test_fail_unless (ctx->regs->l2a_it == IPMBOX_L2A_IT);
+ ctx->regs->l2a_it = 0;
+ /* Check the message is stored in each queue. */
+ test_fail_unless (shared_mem[SHMEM_L2A_DATA_QUEUE_BASE] == 0x42);
+ test_fail_unless (shared_mem[SHMEM_L2A_DATA_QUEUE_BASE + 1] == 0x43);
+ test_fail_unless (shared_mem[SHMEM_L2A_MBX_QUEUE_BASE] == 0x44);
+ test_fail_unless (shared_mem[SHMEM_L2A_MBX_QUEUE_BASE + 1] == 0x45);
+ test_fail_unless (shared_mem[SHMEM_L2A_EMPTY_BUF_QUEUE_BASE] == 0x46);
+ test_fail_unless (shared_mem[SHMEM_L2A_EMPTY_BUF_QUEUE_BASE + 1] == 0x47);
+ /* Test the assert. */
+ dbg_fatal_try_begin
+ {
+ ipmbox_tx_data (
+ ctx, msg, IPMBOX_PROTOCOL_QUEUE_SIZE_L2A_DATA + 1);
+ 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;
+ ipmbox_uninit (ctx);
+ }
+ test_end;
+}
+
+void
+ipmbox_empty_buf_get_test_case (test_t t)
+{
+ ipmbox_t *ctx = ipmbox_test_init ();
+ u32 buffs[10];
+ ipmbox_queue_copy_to (&ctx->queue[IPMBOX_QUEUE_EMPTY_BUF][IPMBOX_A2L],
+ buffs, 10);
+ ctx->regs->a2l_it = 0;
+ test_case_begin (t, "Empty buf get");
+ test_begin (t, "buffers available")
+ {
+ uint nb_got;
+ nb_got = ipmbox_empty_buf_get (ctx, buffs, 5);
+ test_fail_unless (ctx->regs->a2l_it == IPMBOX_A2L_IT_ACK);
+ test_fail_unless (nb_got == 5);
+ test_fail_unless (ctx->regs->a2l_it_mask & IPMBOX_A2L_IT_ACK);
+ }
+ test_end;
+ test_begin (t, "not enough buffers")
+ {
+ uint nb_got;
+ nb_got = ipmbox_empty_buf_get (ctx, buffs, 6);
+ test_fail_unless (nb_got == 5);
+ test_fail_unless ((ctx->regs->a2l_it_mask & IPMBOX_A2L_IT_ACK) == 0);
+ }
+ test_end;
+ test_begin (t, "no buffers")
+ {
+ uint nb_got;
+ ctx->regs->a2l_it_mask = IPMBOX_A2L_IT_ACK;
+ nb_got = ipmbox_empty_buf_get (ctx, buffs, 6);
+ test_fail_unless (nb_got == 0);
+ test_fail_unless ((ctx->regs->a2l_it_mask & IPMBOX_A2L_IT_ACK) == 0);
+ }
+ test_end;
+ test_begin (t, "just enough buffers")
+ {
+ uint nb_got;
+ ipmbox_queue_copy_to (&ctx->queue[IPMBOX_QUEUE_EMPTY_BUF][IPMBOX_A2L],
+ buffs, 10);
+ ctx->regs->a2l_it_mask = IPMBOX_A2L_IT_ACK;
+ nb_got = ipmbox_empty_buf_get (ctx, buffs, 10);
+ test_fail_unless (nb_got == 10);
+ test_fail_unless ((ctx->regs->a2l_it_mask & IPMBOX_A2L_IT_ACK));
+ }
+ test_end;
+ ipmbox_uninit (ctx);
+}
+
+void
+ipmbox_rx_sync_test_case (test_t t)
+{
+ ipmbox_t *ctx = ipmbox_test_init ();
+ test_case_begin (t, "RX sync");
+ test_begin (t, "Nothing to do")
+ {
+ u32 *first_msg = NULL;
+ uint nb_msg;
+ /* IT not set. */
+ ctx->regs->a2l_it = 0;
+ nb_msg = ipmbox_rx_sync (ctx, (const u32**) &first_msg);
+ test_fail_unless (!nb_msg);
+ test_fail_unless (!first_msg);
+ /* IT set. */
+ ctx->regs->a2l_it = -1;
+ nb_msg = ipmbox_rx_sync (ctx, (const u32**) &first_msg);
+ test_fail_unless (ctx->regs->a2l_it == IPMBOX_A2L_IT);
+ test_fail_unless (!nb_msg);
+ test_fail_unless (!first_msg);
+ }
+ test_end;
+ test_begin (t, "Messages to process")
+ {
+ ipmbox_queue_copy_to (&ctx->queue[IPMBOX_QUEUE_MBX][IPMBOX_A2L],
+ &shared_mem[SHMEM_A2L_EMPTY_BUF_QUEUE_BASE],
+ 10);
+ u32 *first_msg = NULL;
+ uint nb_msg;
+ ctx->regs->a2l_it = IPMBOX_A2L_IT;
+ nb_msg = ipmbox_rx_sync (ctx, (const u32**) &first_msg);
+ test_fail_unless (ctx->regs->a2l_it == IPMBOX_A2L_IT);
+ test_fail_unless (nb_msg == 10);
+ test_fail_unless (first_msg);
+ }
+ test_end;
+ ipmbox_uninit (ctx);
+}
+
+void
+ipmbox_rx_irq_test_case (test_t t)
+{
+ ipmbox_t *ctx = ipmbox_test_init ();
+ test_case_begin (t, "RX IRQ");
+ test_begin (t, "Really no work (data/mbx)")
+ {
+ data_cb_called = false;
+ mbx_cb_called = false;
+ dsr_posted = false;
+ ctx->regs->l2a_it = 0;
+ ctx->regs->a2l_it = 0;
+ ctx->regs->a2l_it_mask = IPMBOX_A2L_IT;
+ ipmbox_rx_dsr (0, 0, (cyg_addrword_t) ctx);
+ test_fail_unless (!ctx->regs->l2a_it);
+ test_fail_unless (!data_cb_called);
+ test_fail_unless (!mbx_cb_called);
+ test_fail_unless (!dsr_posted);
+ test_fail_unless ((ctx->regs->a2l_it_mask & IPMBOX_A2L_IT) == 0);
+ }
+ test_end;
+ test_begin (t, "Only MBX")
+ {
+ /* store some MBX messages. */
+ ipmbox_queue_copy_to (&ctx->queue[IPMBOX_QUEUE_MBX][IPMBOX_A2L],
+ &shared_mem[SHMEM_A2L_EMPTY_BUF_QUEUE_BASE],
+ IPMBOX_PROTOCOL_QUEUE_SIZE_A2L_MBX / 2);
+ data_cb_called = false;
+ mbx_cb_called = false;
+ dsr_posted = false;
+ ctx->regs->l2a_it = 0;
+ ctx->regs->a2l_it = 0;
+ ctx->regs->a2l_it_mask = IPMBOX_A2L_IT;
+ ipmbox_rx_dsr (0, 0, (cyg_addrword_t) ctx);
+ test_fail_unless (!ctx->regs->l2a_it);
+ test_fail_unless (!data_cb_called);
+ test_fail_unless (mbx_cb_called);
+ test_fail_unless (!dsr_posted);
+ test_fail_unless ((ctx->regs->a2l_it_mask & IPMBOX_A2L_IT) == 0);
+ }
+ test_end;
+ test_begin (t, "DATA <= BUDGET")
+ {
+ /* store some DATA messages. */
+ ipmbox_queue_copy_to (&ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L],
+ &shared_mem[SHMEM_A2L_EMPTY_BUF_QUEUE_BASE],
+ IPMBOX_RX_DATA_BUDGET);
+ data_cb_called = false;
+ mbx_cb_called = false;
+ dsr_posted = false;
+ ctx->regs->l2a_it = 0;
+ ctx->regs->a2l_it = 0;
+ ctx->regs->a2l_it_mask = IPMBOX_A2L_IT;
+ ipmbox_rx_dsr (0, 0, (cyg_addrword_t) ctx);
+ test_fail_unless (ctx->regs->l2a_it == 0);
+ test_fail_unless (data_cb_called);
+ test_fail_unless (!mbx_cb_called);
+ test_fail_unless (!dsr_posted);
+ test_fail_unless ((ctx->regs->a2l_it_mask & IPMBOX_A2L_IT) == 0);
+ }
+ test_end;
+ test_begin (t, "DATA > BUDGET")
+ {
+ /* store some DATA messages. */
+ ipmbox_queue_copy_to (&ctx->queue[IPMBOX_QUEUE_DATA][IPMBOX_A2L],
+ &shared_mem[SHMEM_A2L_EMPTY_BUF_QUEUE_BASE],
+ IPMBOX_RX_DATA_BUDGET + 1);
+ data_cb_called = false;
+ mbx_cb_called = false;
+ dsr_posted = false;
+ ctx->regs->l2a_it = 0;
+ ctx->regs->a2l_it = 0;
+ ctx->regs->a2l_it_mask = IPMBOX_A2L_IT;
+ ipmbox_rx_dsr (0, 0, (cyg_addrword_t) ctx);
+ test_fail_unless (ctx->regs->l2a_it == 0);
+ test_fail_unless (data_cb_called);
+ test_fail_unless (!mbx_cb_called);
+ test_fail_unless (dsr_posted);
+ test_fail_unless ((ctx->regs->a2l_it_mask & IPMBOX_A2L_IT));
+ }
+ test_end;
+ ipmbox_uninit (ctx);
+}
+
+void
+ipmbox_empty_buf_irq_test_case (test_t t)
+{
+ test_case_begin (t, "Empty buf IRQ");
+ test_begin (t, "Call the callback")
+ {
+ ipmbox_t *ctx = ipmbox_test_init ();
+ empty_buf_cb_called = false;
+ ipmbox_empty_buf_dsr (0, 0, (cyg_addrword_t) ctx);
+ test_fail_unless (empty_buf_cb_called);
+ ipmbox_uninit (ctx);
+ }
+ test_end;
+}
+
+void
+ipmbox_test_suite (test_t t)
+{
+ test_suite_begin (t, "IPMBox");
+ ipmbox_init_test_case (t);
+ ipmbox_callback_register_test_case (t);
+ ipmbox_tx_test_case (t);
+ ipmbox_empty_buf_get_test_case (t);
+ ipmbox_rx_sync_test_case (t);
+ ipmbox_rx_irq_test_case (t);
+ ipmbox_empty_buf_irq_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);
+ ipmbox_test_suite (t);
+ test_result (t);
+ return test_nb_failed (t) == 0 ? 0 : 1;
+}
+