summaryrefslogtreecommitdiff
path: root/cesar/hal/phy/src/bridgedma.c
diff options
context:
space:
mode:
authorsave2008-04-07 14:17:42 +0000
committersave2008-04-07 14:17:42 +0000
commit3d58a62727346b7ac1a6cb36fed1a06ed72228dd (patch)
treed7788c3cf9f76426aef0286d0202e2097f0fa0eb /cesar/hal/phy/src/bridgedma.c
parent095dca4b0a8d4924093bab424f71f588fdd84613 (diff)
Moved the complete svn base into the cesar directory.
git-svn-id: svn+ssh://pessac/svn/cesar/trunk@1769 017c9cb6-072f-447c-8318-d5b54f68fe89
Diffstat (limited to 'cesar/hal/phy/src/bridgedma.c')
-rw-r--r--cesar/hal/phy/src/bridgedma.c447
1 files changed, 447 insertions, 0 deletions
diff --git a/cesar/hal/phy/src/bridgedma.c b/cesar/hal/phy/src/bridgedma.c
new file mode 100644
index 0000000000..69a0d6d4e0
--- /dev/null
+++ b/cesar/hal/phy/src/bridgedma.c
@@ -0,0 +1,447 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/phy/src/bridgedma.c
+ * \brief HAL Phy Bridge DMA functions for the prototype.
+ * \ingroup hal_phy
+ *
+ * Add in the config file the CONFIG_BRIDGEDMA_PROTO = y to use this
+ * bridgedma, this can be done too in the Makefile with the DEFS flag like
+ * DEFS = -DCONFIG_BRIDGEDMA_PROTO
+ */
+
+#ifdef CONFIG_BRIDGEDMA_PROTO
+
+#include <cyg/kernel/kapi.h>
+#include "cyg/hal/hal_io.h"
+#include "common/std.h"
+#include "hal/phy/inc/bridgedma.h"
+#include "hal/phy/inc/bridgedma_proto.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include "lib/bitstream.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))
+
+static cyg_uint32 _bridgedma_ecos_isr(cyg_vector_t vector, cyg_addrword_t data)
+{
+ volatile uint* ecos_it_register = (uint*) BRIDGEDMA_PROTO_ECOS_IT_DISABLE_REGISTER;
+
+ /* nothing to do except calling the bridgedma callback */
+ phy_bridgedma_t *bridgedma_ctx;
+
+ /* Reset the IT interruption. */
+ *ecos_it_register &= ~BRIDGEDMA_ECOS_IT_MASK;
+ cyg_interrupt_mask(BRIDGEDMA_ECOS_IT);
+
+ bridgedma_ctx = (phy_bridgedma_t *)data;
+
+ if((*bridgedma_ctx->bridgedma_cb)(bridgedma_ctx->user_data, *((u32 *)((void *)&bridgedma_ctx->status))))
+ return CYG_ISR_CALL_DSR; // Cause DSR to be run
+ else
+ {
+ cyg_interrupt_unmask(BRIDGEDMA_ECOS_IT);
+ return CYG_ISR_HANDLED;
+ }
+}
+
+static void _bridgedma_ecos_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+ /* nothing to do except calling the phy dsr */
+ phy_bridgedma_t *bridgedma_ctx;
+ bridgedma_ctx = (phy_bridgedma_t *)data;
+ (*bridgedma_ctx->deferred_cb)(bridgedma_ctx->user_data);
+ cyg_interrupt_unmask(BRIDGEDMA_ECOS_IT);
+ return;
+}
+
+/**
+ * Initialise the Bridge DMA.
+ * \param user_data User data passed to any callback
+ * \param bridgedma_cb Bridge DMA interrupt callback
+ * \param deferred_cb DSR callback
+ * \return the newly created context
+ */
+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(bridgedma_ctx));
+ bridgedma_ctx.user_data = user_data;
+ bridgedma_ctx.bridgedma_cb = bridgedma_cb;
+ bridgedma_ctx.deferred_cb = deferred_cb;
+ bridgedma_ctx.status.stop = 1;
+
+ /* init the crc context */
+ bridgedma_ctx.proto_ctx.crc_ctx.width = 32;
+ bridgedma_ctx.proto_ctx.crc_ctx.generator = HPAV_CRC32_GENERATOR;
+ bridgedma_ctx.proto_ctx.crc_ctx.init = HPAV_CRC32_INIT;
+ bridgedma_ctx.proto_ctx.crc_ctx.refin = true;
+ bridgedma_ctx.proto_ctx.crc_ctx.refout = true;
+ bridgedma_ctx.proto_ctx.crc_ctx.xorout = 0xffffffff;
+ bridgedma_ctx.proto_ctx.crc_ctx.reg_init = 0;
+ bridgedma_ctx.proto_ctx.crc_ctx.table.t32 = enc_tab;
+ crc_init(&bridgedma_ctx.proto_ctx.crc_ctx);
+
+ /* register ISR et DSR to eCos */
+ cyg_interrupt_create(BRIDGEDMA_ECOS_IT,
+ PHY_HAL_INTERRUPT_PRIORITY,
+ (cyg_addrword_t)&bridgedma_ctx,
+ _bridgedma_ecos_isr,
+ _bridgedma_ecos_dsr,
+ &bridgedma_ctx.proto_ctx.interrupt_handle,
+ &bridgedma_ctx.proto_ctx.interrupt);
+ cyg_interrupt_attach(bridgedma_ctx.proto_ctx.interrupt_handle);
+
+ // Create the thread.
+ cyg_thread_create(BRIDGEDMA_THREAD_PRIORITY,
+ &phy_bridgedma_proto_process,
+ (cyg_addrword_t) &bridgedma_ctx,
+ "BRIDGEDMA_PROTO",
+ bridgedma_ctx.proto_ctx.thread_stack,
+ BRIDGEDMA_THREAD_STACK_SIZE,
+ &bridgedma_ctx.proto_ctx.thread_handle,
+ &bridgedma_ctx.proto_ctx.thread);
+
+ return &bridgedma_ctx;
+}
+
+
+/**
+ * Reset and uninitialise the Bridge DMA.
+ * \param ctx Bridge DMA context
+ */
+void
+phy_bridgedma_uninit (phy_bridgedma_t *ctx)
+{
+ cyg_thread_suspend (ctx->proto_ctx.thread_handle);
+ cyg_thread_delete (ctx->proto_ctx.thread_handle);
+}
+
+/**
+ * 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: MACFRAME_TO_PB or 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 == 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 == 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;
+
+ /* variable to write in the ecos raising it. */
+ volatile uint* ecos_enable_it = (uint*) BRIDGEDMA_PROTO_ECOS_IT_ENABLE_REGISTER;
+ 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 >= 60) && (job->data_len <= 1518));
+ 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->proto_ctx.icv_current =
+ crc_compute_begin(&ctx->proto_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, /* little endian !!! */
+ 2,
+ MACFRAME_TO_PB); /* we are in little endian for simulator... */
+ if(job->header_len == 6)
+ {
+ /* add ATS */
+ _pb_data_add(&pb_current,
+ &data_ptr,
+ job->segment_len,
+ ((unsigned char *)&job->mf_header1) + 2, /* little endian !!! */
+ 4,
+ MACFRAME_TO_PB); /* we are in little endian for simulator... */
+ if(!job->crc_error)
+ ctx->proto_ctx.icv_current =
+ crc_compute_continue_block(
+ &ctx->proto_ctx.crc_ctx,
+ ctx->proto_ctx.icv_current,
+ ((unsigned char *)&job->mf_header1) + 2, 4);
+ }
+ }
+
+ /* 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, MACFRAME_TO_PB);
+ if(!job->crc_error)
+ ctx->proto_ctx.icv_current =
+ crc_compute_continue_block(
+ &ctx->proto_ctx.crc_ctx,
+ ctx->proto_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), MACFRAME_TO_PB);
+ if(!job->crc_error)
+ ctx->proto_ctx.icv_current =
+ crc_compute_continue_block(
+ &ctx->proto_ctx.crc_ctx,
+ ctx->proto_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, MACFRAME_TO_PB);
+ if(!job->crc_error)
+ ctx->proto_ctx.icv_current =
+ crc_compute_continue_block(
+ &ctx->proto_ctx.crc_ctx,
+ ctx->proto_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->proto_ctx.crc_ctx,
+ ctx->proto_ctx.icv_current);
+ else
+ icv_final = ctx->proto_ctx.icv_substitution;
+ _pb_data_add(&pb_current, &data_ptr, job->segment_len, (unsigned char *)&icv_final, 4, MACFRAME_TO_PB); /* we are in little endian for simulator... */
+ }
+ 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, /* little endian !!! */
+ 2,
+ PB_TO_MACFRAME); /* we are in little endian for simulator... */
+ if(job->header_len == 6)
+ {
+ /* add ATS */
+ _pb_data_add(&pb_current,
+ &data_ptr,
+ job->segment_len,
+ ((unsigned char *)&job->mf_header1) + 2, /* little endian */
+ 4,
+ PB_TO_MACFRAME); /* we are in little endian for simulator... */
+ ctx->proto_ctx.icv_current =
+ crc_compute_continue_block(
+ &ctx->proto_ctx.crc_ctx,
+ ctx->proto_ctx.icv_current,
+ ((unsigned char *)&job->mf_header1) + 2, 4);
+ }
+ }
+
+ /* 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, PB_TO_MACFRAME);
+ ctx->proto_ctx.icv_current =
+ crc_compute_continue_block(
+ &ctx->proto_ctx.crc_ctx,
+ ctx->proto_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), PB_TO_MACFRAME);
+ ctx->proto_ctx.icv_current =
+ crc_compute_continue_block(
+ &ctx->proto_ctx.crc_ctx,
+ ctx->proto_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, PB_TO_MACFRAME);
+ ctx->proto_ctx.icv_current =
+ crc_compute_continue_block(
+ &ctx->proto_ctx.crc_ctx,
+ ctx->proto_ctx.icv_current,
+ job->data_addr,
+ job->data_len);
+ }
+ if(job->crc_store)
+ {
+ /* check crc */
+ icv_final = crc_compute_end(
+ &ctx->proto_ctx.crc_ctx,
+ ctx->proto_ctx.icv_current);
+ _pb_data_add(&pb_current, &data_ptr, job->segment_len, (unsigned char *)&icv_compare, 4, PB_TO_MACFRAME); /* we are in little endian for simulator... */
+ job->crc_error = (icv_compare != icv_final);
+ }
+ }
+
+ if(ctx->job_current->job_it)
+ {
+ *ecos_enable_it |= BRIDGEDMA_ECOS_IT_MASK;
+ cyg_interrupt_unmask(BRIDGEDMA_ECOS_IT);
+
+#ifndef __sparc__
+ cyg_hal_sys_kill (cyg_hal_sys_getpid(), CYG_HAL_SYS_SIGIO);
+#endif
+ }
+
+ return true;
+}
+
+
+/**
+ * Enqueue and start a list of jobs.
+ * \param ctx Bridge DMA context
+ * \param job_first first job to enqueue
+ * \param job_last last job to enqueue
+ *
+ * The new jobs are added to the Bridge DMA queue and the Bridge DMA is
+ * restarted if it was stopped. The \c last flag must be set in the last
+ * enqueued job.
+ */
+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);
+
+ /* check current job processing */
+ if(ctx->job_first == NULL)
+ {
+ /* no more job in queue */
+ ctx->job_first = job_first;
+ ctx->job_current = job_first;
+ ctx->job_last = job_last;
+ memset(&ctx->status, '\0', sizeof(phy_bridgedma_status_t));
+ ctx->status.running = 1;
+ }
+ else
+ {
+ /* there are still job inside */
+ dbg_assert(ctx->job_last);
+ ctx->job_last->next = job_first;
+ ctx->job_last = job_last;
+ }
+
+ /* Resume the bridge dma thread to process the jobs. */
+ cyg_thread_resume (ctx->proto_ctx.thread_handle);
+}
+
+void
+phy_bridgedma_proto_process (cyg_addrword_t data)
+{
+ phy_bridgedma_t *bridgedma_ctx;
+
+ dbg_assert (data);
+ bridgedma_ctx = (phy_bridgedma_t *) data;
+
+ while (true)
+ {
+ cyg_thread_yield();
+ if (bridgedma_ctx->job_current)
+ {
+ _job_process(bridgedma_ctx, bridgedma_ctx->job_current);
+ bridgedma_ctx->job_current = bridgedma_ctx->job_current->next;
+ }
+ else
+ {
+ /* refresh bridge dma status */
+ bridgedma_ctx->status.running = 0;
+ bridgedma_ctx->status.stop = 1;
+
+ /* Stop the thread. */
+ cyg_thread_suspend (bridgedma_ctx->proto_ctx.thread_handle);
+ }
+ }
+}
+
+#endif /* CONFIG_BRIDGEDMA_PROTO */