summaryrefslogtreecommitdiff
path: root/cesar/hal/phy/soft/bridgedma
diff options
context:
space:
mode:
Diffstat (limited to 'cesar/hal/phy/soft/bridgedma')
-rw-r--r--cesar/hal/phy/soft/bridgedma/Module1
-rw-r--r--cesar/hal/phy/soft/bridgedma/bridgedma_crc.h25
-rw-r--r--cesar/hal/phy/soft/bridgedma/inc/bridgedma.h42
-rw-r--r--cesar/hal/phy/soft/bridgedma/src/bridgedma.c375
4 files changed, 443 insertions, 0 deletions
diff --git a/cesar/hal/phy/soft/bridgedma/Module b/cesar/hal/phy/soft/bridgedma/Module
new file mode 100644
index 0000000000..07f8b7cb3c
--- /dev/null
+++ b/cesar/hal/phy/soft/bridgedma/Module
@@ -0,0 +1 @@
+SOURCES:=bridgedma.c
diff --git a/cesar/hal/phy/soft/bridgedma/bridgedma_crc.h b/cesar/hal/phy/soft/bridgedma/bridgedma_crc.h
new file mode 100644
index 0000000000..970a4e2adf
--- /dev/null
+++ b/cesar/hal/phy/soft/bridgedma/bridgedma_crc.h
@@ -0,0 +1,25 @@
+#ifndef hal_phy_soft_bridgedma_bridgedma_crc_h
+#define hal_phy_soft_bridgedma_bridgedma_crc_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2009 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/phy/soft/bridgedma/bridgedma_crc.h
+ * \brief Context for the bridge DMA soft version.
+ * \ingroup hal_phy
+ */
+
+/* Defines for bridge DMA crc computation on PC or SPARC. */
+#ifdef __sparc__
+ #define bridgedma_crc_compute_continue_block crc_compute_continue_block_le
+ #define bridgedma_crc_compute_block crc_compute_block_le
+#else
+ #define bridgedma_crc_compute_continue_block crc_compute_continue_block
+ #define bridgedma_crc_compute_block crc_compute_block
+#endif
+
+#endif /* hal_phy_soft_bridgedma_bridgedma_crc_h */
diff --git a/cesar/hal/phy/soft/bridgedma/inc/bridgedma.h b/cesar/hal/phy/soft/bridgedma/inc/bridgedma.h
new file mode 100644
index 0000000000..79fd9aedbf
--- /dev/null
+++ b/cesar/hal/phy/soft/bridgedma/inc/bridgedma.h
@@ -0,0 +1,42 @@
+#ifndef hal_phy_soft_bridgedma_inc_bridgedma_h
+#define hal_phy_soft_bridgedma_inc_bridgedma_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/phy/soft/bridgedma/inc/bridgedma.h
+ * \brief Context for the bridge DMA soft version.
+ * \ingroup hal_phy
+ *
+ */
+#include "lib/crc.h"
+#include "hal/phy/inc/bridgedma_common.h"
+
+typedef enum
+{
+ HAL_PHY_BRIDGEDMA_PB_TO_MACFRAME,
+ HAL_PHY_BRIDGEDMA_MACFRAME_TO_PB
+} bridgedma_copy_dir_t;
+
+struct phy_bridgedma_t
+{
+ /* Bridge DMA context. */
+ phy_bridgedma_common_t bridge;
+
+ /** crc context. */
+ crc_t crc_ctx;
+ uint icv_substitution;
+ uint icv_current;
+
+ /** Bridge DMA status. */
+ phy_bridgedma_status_t status;
+
+ /** Bridge job current. */
+ phy_bridgedma_job_t *job_current;
+};
+
+#endif /* hal_phy_soft_bridgedma_inc_bridgedma_h */
diff --git a/cesar/hal/phy/soft/bridgedma/src/bridgedma.c b/cesar/hal/phy/soft/bridgedma/src/bridgedma.c
new file mode 100644
index 0000000000..a484193c14
--- /dev/null
+++ b/cesar/hal/phy/soft/bridgedma/src/bridgedma.c
@@ -0,0 +1,375 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/phy/soft/bridgedma/src/bridgedma.c
+ * \brief HAL Phy Bridge DMA functions for the prototype.
+ * \ingroup hal_phy
+ */
+#include "common/std.h"
+#include "common/defs/ethernet.h"
+#include "common/defs/homeplugAV.h"
+#include "lib/bitstream.h"
+
+#include "hal/phy/soft/bridgedma/bridgedma_crc.h"
+#include "hal/phy/soft/bridgedma/inc/bridgedma.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define ETH_BUFFER_MASK(job) (~((job)->eth_buffer_mask << 7))
+#define ETH_BUFFER_SIZE(job) (ETH_BUFFER_MASK(job) + 1)
+#define ETH_BUFFER_ADDR(job) \
+ (unsigned char *)((unsigned long)job->data_addr & ~ETH_BUFFER_MASK(job))
+
+phy_bridgedma_t *
+phy_bridgedma_init (void *user_data, phy_bridgedma_cb_t bridgedma_cb,
+ phy_deferred_cb_t deferred_cb)
+{
+ static phy_bridgedma_t bridgedma_ctx;
+ static u32 enc_tab[256];
+
+ memset(&bridgedma_ctx, '\0', sizeof(phy_bridgedma_t));
+ bridgedma_ctx.bridge.user_data = user_data;
+ bridgedma_ctx.bridge.bridgedma_cb = bridgedma_cb;
+ bridgedma_ctx.bridge.deferred_cb = deferred_cb;
+ bridgedma_ctx.status.stop = true;
+ bridgedma_ctx.status.running = false;
+
+ /* init the crc context */
+ bridgedma_ctx.crc_ctx.width = 32;
+ bridgedma_ctx.crc_ctx.generator = HPAV_CRC32_GENERATOR;
+ bridgedma_ctx.crc_ctx.init = HPAV_CRC32_INIT;
+ bridgedma_ctx.crc_ctx.refin = true;
+ bridgedma_ctx.crc_ctx.refout = true;
+ bridgedma_ctx.crc_ctx.xorout = 0xffffffff;
+ bridgedma_ctx.crc_ctx.reg_init = 0;
+ bridgedma_ctx.crc_ctx.table.t32 = enc_tab;
+ crc_init(&bridgedma_ctx.crc_ctx);
+
+ return &bridgedma_ctx;
+}
+
+/**
+ * Reset and uninitialise the Bridge DMA.
+ * \param ctx Bridge DMA context
+ */
+void
+phy_bridgedma_uninit (phy_bridgedma_t *ctx)
+{
+ dbg_assert (ctx);
+}
+
+/**
+ * Fragment a mac_frame data into one or several PBs.
+ * Mac frame data MUST NOT cross the mac frame buffer boundary
+ * (going at beginning of circular buffer)
+ * ie: we must have mac_ptr + mac_len <= end_of_mac_buffer
+ * \param pb_current pointer of pointer to first pb to store data
+ * \param pb_data_ptr pointer of pointer to data beginning into first pb
+ * \param pb_size size of pb data (128 or 512)
+ * \param mac_ptr pointer to mac_frame data
+ * \param mac_len length of mac frame data
+ * \param direction data copy direction: HAL_PHY_BRIDGEDMA_MACFRAME_TO_PB or HAL_PHY_BRIDGEDMA_PB_TO_MACFRAME
+ * \return 0
+ */
+
+static uint _pb_data_add(
+ blk_t **pb_current,
+ unsigned char **pb_data_ptr,
+ unsigned int pb_size,
+ unsigned char *mac_ptr,
+ unsigned int mac_len,
+ bridgedma_copy_dir_t direction)
+{
+ unsigned int mac_cnt;
+
+ mac_cnt = 0;
+
+ while((mac_len - mac_cnt) > pb_size
+ - (*pb_data_ptr - (*pb_current)->data))
+ {
+ if(direction == HAL_PHY_BRIDGEDMA_MACFRAME_TO_PB)
+ bitstream_memcpy(*pb_data_ptr,
+ mac_ptr + mac_cnt,
+ pb_size - (*pb_data_ptr - (*pb_current)->data));
+ else
+ bitstream_memcpy(mac_ptr + mac_cnt,
+ *pb_data_ptr,
+ pb_size - (*pb_data_ptr - (*pb_current)->data));
+
+ mac_cnt += pb_size - (*pb_data_ptr - (*pb_current)->data);
+ *pb_current = (*pb_current)->next;
+ dbg_assert(*pb_current);
+ *pb_data_ptr = (*pb_current)->data;
+ }
+
+ if(direction == HAL_PHY_BRIDGEDMA_MACFRAME_TO_PB)
+ bitstream_memcpy(*pb_data_ptr, mac_ptr + mac_cnt, mac_len - mac_cnt);
+ else
+ bitstream_memcpy(mac_ptr + mac_cnt, *pb_data_ptr, mac_len - mac_cnt);
+ *pb_data_ptr += mac_len - mac_cnt;
+ return 0;
+}
+
+/**
+ * Process 1 job for fragmentation or reassembly
+ * \param ctx Bridge DMA context
+ * \param job job to process
+ * \return 0
+ * */
+static int
+_job_process(phy_bridgedma_t *ctx, phy_bridgedma_job_t *job)
+{
+ unsigned char * mac_ptr, *data_ptr;
+ blk_t *pb_current;
+ unsigned long icv_final, icv_compare;
+
+ ctx->job_current = job;
+
+ dbg_assert(job->data_addr);
+ dbg_assert((job->header_len == 0) || (job->header_len == 2) ||
+ (job->header_len == 6));
+ dbg_assert(job->data_len <= ETH_PACKET_MAX_SIZE);
+ dbg_assert(job->first_pb_desc);
+ dbg_assert(job->first_pb_offset < job->segment_len);
+ dbg_assert((job->segment_len == 128) || (job->segment_len == 512));
+
+ /* check icv reset */
+ if(job->crc_reset)
+ ctx->icv_current =
+ crc_compute_begin(&ctx->crc_ctx);
+
+ pb_current = job->first_pb_desc;
+ data_ptr = pb_current->data + job->first_pb_offset;
+ mac_ptr = job->data_addr;
+
+ if(job->direction == 0)
+ {
+ /* segmentation processing */
+ if(job->header_len > 0)
+ {
+ /* add header */
+ _pb_data_add(&pb_current,
+ &data_ptr,
+ job->segment_len,
+ (unsigned char *)&job->mf_header1,
+ 2,
+ HAL_PHY_BRIDGEDMA_MACFRAME_TO_PB);
+ if(job->header_len == 6)
+ {
+ _pb_data_add(&pb_current,
+ &data_ptr,
+ job->segment_len,
+ ((unsigned char *)&job->mf_header1) + 2,
+ 4, HAL_PHY_BRIDGEDMA_MACFRAME_TO_PB);
+ }
+ }
+
+ /* check if mac data must be separated into 2 parts
+ * (circular buffer rollover) */
+ if((job->eth_buffer_mask != 0)
+ && (job->data_addr + job->data_len
+ >= ETH_BUFFER_ADDR(job) + ETH_BUFFER_SIZE(job)))
+ {
+ _pb_data_add(&pb_current, &data_ptr, job->segment_len,
+ job->data_addr,
+ ETH_BUFFER_ADDR(job) + ETH_BUFFER_SIZE(job)
+ - job->data_addr,
+ HAL_PHY_BRIDGEDMA_MACFRAME_TO_PB);
+ if(!job->crc_error)
+ ctx->icv_current =
+ bridgedma_crc_compute_continue_block(
+ &ctx->crc_ctx,
+ ctx->icv_current,
+ job->data_addr,
+ ETH_BUFFER_ADDR(job) + ETH_BUFFER_SIZE(job)
+ - job->data_addr);
+ _pb_data_add(&pb_current, &data_ptr, job->segment_len,
+ job->data_addr,
+ ((unsigned long)(job->data_addr) + job->data_len)
+ & ETH_BUFFER_MASK(job),
+ HAL_PHY_BRIDGEDMA_MACFRAME_TO_PB);
+ if(!job->crc_error)
+ ctx->icv_current =
+ bridgedma_crc_compute_continue_block(
+ &ctx->crc_ctx,
+ ctx->icv_current,
+ job->data_addr,
+ ((unsigned long)(job->data_addr) + job->data_len)
+ & ETH_BUFFER_MASK(job));
+ }
+ else
+ {
+ _pb_data_add(&pb_current, &data_ptr, job->segment_len,
+ job->data_addr, job->data_len,
+ HAL_PHY_BRIDGEDMA_MACFRAME_TO_PB);
+ if(!job->crc_error)
+ ctx->icv_current =
+ bridgedma_crc_compute_continue_block(
+ &ctx->crc_ctx,
+ ctx->icv_current,
+ job->data_addr, job->data_len);
+ }
+ if(job->crc_store)
+ {
+ /* add crc */
+ if(!job->crc_error)
+ icv_final = crc_compute_end(
+ &ctx->crc_ctx,
+ ctx->icv_current);
+ else
+ icv_final = ctx->icv_substitution;
+ _pb_data_add(&pb_current, &data_ptr,
+ job->segment_len,
+ (unsigned char *)&icv_final, 4,
+ HAL_PHY_BRIDGEDMA_MACFRAME_TO_PB);
+ }
+ if(job->append_zero)
+ {
+ /* add zeroed padding */
+ memset(data_ptr, '\0', job->segment_len
+ - (data_ptr - pb_current->data));
+ }
+ }
+ else /* job->direction != 0 */
+ {
+ /* reassembly processing */
+ if(job->header_len > 0)
+ {
+ /* get the mac frame header */
+ _pb_data_add(&pb_current,
+ &data_ptr,
+ job->segment_len,
+ (unsigned char *)&job->mf_header1, 2,
+ HAL_PHY_BRIDGEDMA_PB_TO_MACFRAME);
+ if(job->header_len == 6)
+ {
+ /* add ATS */
+ _pb_data_add(&pb_current,
+ &data_ptr,
+ job->segment_len,
+ ((unsigned char *)&job->mf_header1) + 2, 4,
+ HAL_PHY_BRIDGEDMA_PB_TO_MACFRAME);
+ }
+ }
+ /* check if mac data must be separated into 2 parts
+ * (circular buffer rollover) */
+ if((job->eth_buffer_mask != 0)
+ && (job->data_addr + job->data_len >= ETH_BUFFER_ADDR(job)
+ + ETH_BUFFER_SIZE(job)))
+ {
+ _pb_data_add(&pb_current, &data_ptr, job->segment_len,
+ job->data_addr, ETH_BUFFER_ADDR(job)
+ + ETH_BUFFER_SIZE(job) - job->data_addr,
+ HAL_PHY_BRIDGEDMA_PB_TO_MACFRAME);
+ ctx->icv_current =
+ bridgedma_crc_compute_continue_block (&ctx->crc_ctx,
+ ctx->icv_current,
+ job->data_addr,
+ ETH_BUFFER_ADDR(job)
+ + ETH_BUFFER_SIZE(job)
+ - job->data_addr);
+ _pb_data_add(&pb_current, &data_ptr, job->segment_len,
+ (unsigned char *)((unsigned long)job->data_addr
+ & ~ETH_BUFFER_MASK(job)),
+ ((unsigned long)(job->data_addr) + job->data_len)
+ & ETH_BUFFER_MASK(job),
+ HAL_PHY_BRIDGEDMA_PB_TO_MACFRAME);
+ ctx->icv_current = bridgedma_crc_compute_continue_block (
+ &ctx->crc_ctx,
+ ctx->icv_current,
+ (unsigned char *)((unsigned long)job->data_addr
+ & ~ETH_BUFFER_MASK(job)),
+ ((unsigned long)(job->data_addr) + job->data_len)
+ & ETH_BUFFER_MASK(job));
+ }
+ else
+ {
+ _pb_data_add(&pb_current, &data_ptr, job->segment_len,
+ job->data_addr, job->data_len,
+ HAL_PHY_BRIDGEDMA_PB_TO_MACFRAME);
+ ctx->icv_current =
+ bridgedma_crc_compute_continue_block(
+ &ctx->crc_ctx,
+ ctx->icv_current,
+ job->data_addr,
+ job->data_len);
+ }
+ if(job->crc_store)
+ {
+ /* check crc */
+ icv_final = crc_compute_end (&ctx->crc_ctx, ctx->icv_current);
+ _pb_data_add(&pb_current, &data_ptr, job->segment_len,
+ (unsigned char *)&icv_compare, 4,
+ HAL_PHY_BRIDGEDMA_PB_TO_MACFRAME);
+ job->crc_error = (icv_compare != icv_final);
+ }
+ }
+
+ /* Any job to process after ? */
+ if (!ctx->job_current->next)
+ ctx->status.running = false;
+
+ if(ctx->job_current->job_it)
+ {
+ /* Process interruption. */
+ if (ctx->bridge.bridgedma_cb (ctx->bridge.user_data,
+ ctx->status.running))
+ /* simulate a DSR call. */
+ ctx->bridge.deferred_cb (ctx->bridge.user_data);
+ }
+ ctx->job_current = ctx->job_current->next;
+
+ return true;
+}
+
+/**
+ * Launch the job process.
+ * \param ctx the module context.
+ */
+static void
+phy_bridgedma_process (phy_bridgedma_t *ctx)
+{
+ dbg_assert (ctx);
+
+ while (ctx->job_current)
+ _job_process(ctx, ctx->job_current);
+ /* refresh bridge dma status */
+ ctx->status.running = false;
+ ctx->status.stop = true;
+}
+
+void
+phy_bridgedma_start (phy_bridgedma_t *ctx, phy_bridgedma_job_t *job_first,
+ phy_bridgedma_job_t *job_last)
+{
+ dbg_assert (ctx);
+ dbg_assert (job_first);
+ dbg_assert (job_last);
+ dbg_assert (job_last->next == NULL);
+
+ ctx->job_current = job_first;
+ ctx->bridge.job_tail = job_last;
+ memset(&ctx->status, '\0', sizeof(phy_bridgedma_status_t));
+ ctx->status.running = true;
+ phy_bridgedma_process (ctx);
+}
+
+phy_bridgedma_job_t *
+phy_bridgedma_current_job (phy_bridgedma_t *ctx)
+{
+ dbg_assert (ctx);
+
+ return ctx->job_current;
+}
+
+bool
+phy_bridgedma_status (phy_bridgedma_t *ctx)
+{
+ dbg_assert (ctx);
+ return ctx->status.running;
+}