summaryrefslogtreecommitdiffstats
path: root/arch/m68k/mach-mcfv4e/fecbd.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/mach-mcfv4e/fecbd.c')
-rw-r--r--arch/m68k/mach-mcfv4e/fecbd.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/arch/m68k/mach-mcfv4e/fecbd.c b/arch/m68k/mach-mcfv4e/fecbd.c
new file mode 100644
index 0000000000..26fb16d98d
--- /dev/null
+++ b/arch/m68k/mach-mcfv4e/fecbd.c
@@ -0,0 +1,232 @@
+/*
+ * File: fecbd.c
+ * Purpose: Provide a simple buffer management driver
+ *
+ * Notes:
+ */
+#include <common.h>
+#include <linux/types.h>
+
+#include <asm/arch/mcf54xx-regs.h>
+#include <asm/proc/mcdapi/MCD_dma.h>
+#include <asm/proc/net/net.h>
+#include <asm/proc/fecbd.h>
+#include <asm/proc/fec.h>
+#include <asm/proc/dma_utils.h>
+
+#define ASSERT(x) if (!(x)) hang();
+
+/*
+ * This implements a simple static buffer descriptor
+ * ring for each channel and each direction
+ *
+ * FEC Buffer Descriptors need to be aligned to a 4-byte boundary.
+ * In order to accomplish this, data is over-allocated and manually
+ * aligned at runtime
+ *
+ * Enough space is allocated for each of the two FEC channels to have
+ * NRXBD Rx BDs and NTXBD Tx BDs
+ *
+ */
+FECBD unaligned_bds[(2 * NRXBD) + (2 * NTXBD) + 1];
+
+/*
+ * These pointers are used to reference into the chunck of data set
+ * aside for buffer descriptors
+ */
+FECBD *RxBD;
+FECBD *TxBD;
+
+/*
+ * Macros to easier access to the BD ring
+ */
+#define RxBD(ch,i) RxBD[(ch * NRXBD) + i]
+#define TxBD(ch,i) TxBD[(ch * NTXBD) + i]
+
+/*
+ * Buffer descriptor indexes
+ */
+static int iTxbd_new;
+static int iTxbd_old;
+static int iRxbd;
+
+/*
+ * Initialize the FEC Buffer Descriptor ring
+ * Buffer Descriptor format is defined by the MCDAPI
+ *
+ * Parameters:
+ * ch FEC channel
+ */
+void
+fecbd_init(uint8_t ch)
+{
+ NBUF *nbuf;
+ int i;
+
+ /*
+ * Align Buffer Descriptors to 4-byte boundary
+ */
+ RxBD = (FECBD *)(((int)unaligned_bds + 3) & 0xFFFFFFFC);
+ TxBD = (FECBD *)((int)RxBD + (sizeof(FECBD) * 2 * NRXBD));
+
+ /*
+ * Initialize the Rx Buffer Descriptor ring
+ */
+ for (i = 0; i < NRXBD; ++i)
+ {
+ /* Grab a network buffer from the free list */
+ nbuf = nbuf_alloc();
+ ASSERT(nbuf);
+
+ /* Initialize the BD */
+ RxBD(ch,i).status = RX_BD_E | RX_BD_INTERRUPT;
+ RxBD(ch,i).length = RX_BUF_SZ;
+ RxBD(ch,i).data = nbuf->data;
+
+ /* Add the network buffer to the Rx queue */
+ nbuf_add(NBUF_RX_RING, nbuf);
+ }
+
+ /*
+ * Set the WRAP bit on the last one
+ */
+ RxBD(ch,i-1).status |= RX_BD_W;
+
+ /*
+ * Initialize the Tx Buffer Descriptor ring
+ */
+ for (i = 0; i < NTXBD; ++i)
+ {
+ TxBD(ch,i).status = TX_BD_INTERRUPT;
+ TxBD(ch,i).length = 0;
+ TxBD(ch,i).data = NULL;
+ }
+
+ /*
+ * Set the WRAP bit on the last one
+ */
+ TxBD(ch,i-1).status |= TX_BD_W;
+
+ /*
+ * Initialize the buffer descriptor indexes
+ */
+ iTxbd_new = iTxbd_old = iRxbd = 0;
+}
+
+void
+fecbd_dump(uint8_t ch)
+{
+ #ifdef CONFIG_DRIVER_NET_MCF54XX_DEBUG
+ int i;
+
+ printf("\n------------ FEC%d BDs -----------\n",ch);
+ printf("RxBD Ring\n");
+ for (i=0; i<NRXBD; i++)
+ {
+ printf("%02d: BD Addr=0x%08x, Ctrl=0x%04x, Lgth=%04d, DataPtr=0x%08x\n",
+ i, &RxBD(ch,i),
+ RxBD(ch,i).status,
+ RxBD(ch,i).length,
+ RxBD(ch,i).data);
+ }
+ printf("TxBD Ring\n");
+ for (i=0; i<NTXBD; i++)
+ {
+ printf("%02d: BD Addr=0x%08x, Ctrl=0x%04x, Lgth=%04d, DataPtr=0x%08x\n",
+ i, &TxBD(ch,i),
+ TxBD(ch,i).status,
+ TxBD(ch,i).length,
+ TxBD(ch,i).data);
+ }
+ printf("--------------------------------\n\n");
+ #endif
+}
+
+/*
+ * Return the address of the first buffer descriptor in the ring.
+ *
+ * Parameters:
+ * ch FEC channel
+ * direction Rx or Tx Macro
+ *
+ * Return Value:
+ * The start address of the selected Buffer Descriptor ring
+ */
+uint32_t
+fecbd_get_start(uint8_t ch, uint8_t direction)
+{
+ switch (direction)
+ {
+ case Rx:
+ return (uint32_t)((int)RxBD + (ch * sizeof(FECBD) * NRXBD));
+ case Tx:
+ default:
+ return (uint32_t)((int)TxBD + (ch * sizeof(FECBD) * NTXBD));
+ }
+}
+
+FECBD *
+fecbd_rx_alloc(uint8_t ch)
+{
+ int i = iRxbd;
+
+ /* Check to see if the ring of BDs is full */
+ if (RxBD(ch,i).status & RX_BD_E)
+ return NULL;
+
+ /* Increment the circular index */
+ iRxbd = (uint8_t)((iRxbd + 1) % NRXBD);
+
+ return &RxBD(ch,i);
+}
+
+/*
+ * This function keeps track of the next available Tx BD in the ring
+ *
+ * Parameters:
+ * ch FEC channel
+ *
+ * Return Value:
+ * Pointer to next available buffer descriptor.
+ * NULL if the BD ring is full
+ */
+FECBD *
+fecbd_tx_alloc(uint8_t ch)
+{
+ int i = iTxbd_new;
+
+ /* Check to see if the ring of BDs is full */
+ if (TxBD(ch,i).status & TX_BD_R)
+ return NULL;
+
+ /* Increment the circular index */
+ iTxbd_new = (uint8_t)((iTxbd_new + 1) % NTXBD);
+
+ return &TxBD(ch,i);
+}
+
+/*
+ * This function keeps track of the Tx BDs that have already been
+ * processed by the FEC
+ *
+ * Parameters:
+ * ch FEC channel
+ *
+ * Return Value:
+ * Pointer to the oldest buffer descriptor that has already been sent
+ * by the FEC, NULL if the BD ring is empty
+ */
+FECBD *
+fecbd_tx_free(uint8_t ch)
+{
+ int i = iTxbd_old;
+
+ /* Check to see if the ring of BDs is empty */
+ if ((TxBD(ch,i).data == NULL) || (TxBD(ch,i).status & TX_BD_R))
+ return NULL;
+
+ /* Increment the circular index */
+ iTxbd_old = (uint8_t)((iTxbd_old + 1) % NTXBD);
+
+ return &TxBD(ch,i);
+}