summaryrefslogtreecommitdiffstats
path: root/bsps/m68k
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-23 09:53:31 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-23 15:18:44 +0200
commit031df3914990db0336a0d386fb53558b05de467e (patch)
tree4661e22f0cdb3f9d06879f0194b77c75f62bac79 /bsps/m68k
parentbsps: Move interrupt controller support to bsps (diff)
downloadrtems-031df3914990db0336a0d386fb53558b05de467e.tar.bz2
bsps: Move legacy network drivers to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/m68k')
-rw-r--r--bsps/m68k/av5282/net/network.c940
-rw-r--r--bsps/m68k/csb360/net/network.c984
-rw-r--r--bsps/m68k/gen68360/net/network.c1062
-rw-r--r--bsps/m68k/genmcf548x/net/network.c1696
-rw-r--r--bsps/m68k/mcf5235/net/network.c879
-rw-r--r--bsps/m68k/mcf5329/net/network.c857
-rw-r--r--bsps/m68k/mvme167/net/network.c3099
-rw-r--r--bsps/m68k/mvme167/net/uti596.h369
-rw-r--r--bsps/m68k/uC5282/net/network.c1013
9 files changed, 10899 insertions, 0 deletions
diff --git a/bsps/m68k/av5282/net/network.c b/bsps/m68k/av5282/net/network.c
new file mode 100644
index 0000000000..457b43c5d6
--- /dev/null
+++ b/bsps/m68k/av5282/net/network.c
@@ -0,0 +1,940 @@
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+
+#include <bsp.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+
+/*
+ * Number of interfaces supported by this driver
+ */
+#define NIFACES 1
+
+#define FEC_INTC0_TX_VECTOR (64+23)
+#define FEC_INTC0_RX_VECTOR (64+27)
+
+#define FEC_INTC0_TX_VECTOR (64+23)
+#define FEC_INTC0_RX_VECTOR (64+27)
+#define MII_VECTOR (64+7) /* IRQ7* pin connected to external transceiver */
+#define MII_EPPAR MCF5282_EPORT_EPPAR_EPPA7_LEVEL
+#define MII_EPDDR MCF5282_EPORT_EPDDR_EPDD7
+#define MII_EPIER MCF5282_EPORT_EPIER_EPIE7
+#define MII_EPPDR MCF5282_EPORT_EPPDR_EPPD7
+/*
+ * Default number of buffer descriptors set aside for this driver.
+ * The number of transmit buffer descriptors has to be quite large
+ * since a single frame often uses three or more buffer descriptors.
+ */
+#define RX_BUF_COUNT 32
+#define TX_BUF_COUNT 20
+#define TX_BD_PER_BUF 3
+
+#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
+
+/*
+ * RTEMS event used by interrupt handler to signal daemons.
+ * This must *not* be the same event used by the TCP/IP task synchronization.
+ */
+#define TX_INTERRUPT_EVENT RTEMS_EVENT_1
+#define RX_INTERRUPT_EVENT RTEMS_EVENT_1
+
+/*
+ * RTEMS event used to start transmit daemon.
+ * This must not be the same as INTERRUPT_EVENT.
+ */
+#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+
+/*
+ * Receive buffer size -- Allow for a full ethernet packet plus CRC (1518).
+ * Round off to nearest multiple of RBUF_ALIGN.
+ */
+#define MAX_MTU_SIZE 1518
+#define RBUF_ALIGN 4
+#define RBUF_SIZE ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN)
+
+#if (MCLBYTES < RBUF_SIZE)
+ #error "Driver must have MCLBYTES > RBUF_SIZE"
+#endif
+
+typedef struct mcf5282BufferDescriptor_ {
+ volatile uint16_t status;
+ uint16_t length;
+ volatile void *buffer;
+} mcf5282BufferDescriptor_t;
+
+/*
+ * Per-device data
+ */
+struct mcf5282_enet_struct {
+ struct arpcom arpcom;
+ struct mbuf **rxMbuf;
+ struct mbuf **txMbuf;
+ int acceptBroadcast;
+ int rxBdCount;
+ int txBdCount;
+ int txBdHead;
+ int txBdTail;
+ int txBdActiveCount;
+ mcf5282BufferDescriptor_t *rxBdBase;
+ mcf5282BufferDescriptor_t *txBdBase;
+ rtems_id rxDaemonTid;
+ rtems_id txDaemonTid;
+
+ /*
+ * Statistics
+ */
+ unsigned long rxInterrupts;
+ unsigned long txInterrupts;
+ unsigned long miiInterrupts;
+ unsigned long txRawWait;
+ unsigned long txRealign;
+ unsigned long txRealignDrop;
+ uint16_t mii_sr2;
+};
+static struct mcf5282_enet_struct enet_driver[NIFACES];
+
+static int
+getMII(int phyNumber, int regNumber);
+
+
+static rtems_isr
+mcf5282_fec_rx_interrupt_handler( rtems_vector_number v )
+{
+ MCF5282_FEC_EIR = MCF5282_FEC_EIR_RXF;
+ MCF5282_FEC_EIMR &= ~MCF5282_FEC_EIMR_RXF;
+ enet_driver[0].rxInterrupts++;
+ rtems_bsdnet_event_send(enet_driver[0].rxDaemonTid, RX_INTERRUPT_EVENT);
+}
+
+static rtems_isr
+mcf5282_fec_tx_interrupt_handler( rtems_vector_number v )
+{
+ MCF5282_FEC_EIR = MCF5282_FEC_EIR_TXF;
+ MCF5282_FEC_EIMR &= ~MCF5282_FEC_EIMR_TXF;
+ enet_driver[0].txInterrupts++;
+ rtems_bsdnet_event_send(enet_driver[0].txDaemonTid, TX_INTERRUPT_EVENT);
+}
+
+static rtems_isr
+mcf5282_mii_interrupt_handler( rtems_vector_number v )
+{
+ uint16_t sr2;
+
+ enet_driver[0].miiInterrupts++;
+ getMII(1, 19); /* Read and clear interrupt status bits */
+ enet_driver[0].mii_sr2 = sr2 = getMII(1, 17);
+ if (((sr2 & 0x200) != 0)
+ && ((MCF5282_FEC_TCR & MCF5282_FEC_TCR_FDEN) == 0))
+ MCF5282_FEC_TCR |= MCF5282_FEC_TCR_FDEN;
+ else if (((sr2 & 0x200) == 0)
+ && ((MCF5282_FEC_TCR & MCF5282_FEC_TCR_FDEN) != 0))
+ MCF5282_FEC_TCR &= ~MCF5282_FEC_TCR_FDEN;
+}
+
+/*
+ * Allocate buffer descriptors from (non-cached) on-chip static RAM
+ * Ensure 128-bit (16-byte) alignment
+ */
+extern char __SRAMBASE[];
+
+static mcf5282BufferDescriptor_t *
+mcf5282_bd_allocate(unsigned int count)
+{
+ static mcf5282BufferDescriptor_t *bdp = (mcf5282BufferDescriptor_t *)__SRAMBASE;
+ mcf5282BufferDescriptor_t *p = bdp;
+
+ bdp += count;
+ if ((int)bdp & 0xF)
+ bdp = (mcf5282BufferDescriptor_t *)((char *)bdp + (16 - ((int)bdp & 0xF)));
+ return p;
+}
+
+
+/*
+ * Read MII register
+ * Busy-waits, but transfer time should be short!
+ */
+static int
+getMII(int phyNumber, int regNumber)
+{
+ MCF5282_FEC_MMFR = (0x1 << 30) |
+ (0x2 << 28) |
+ (phyNumber << 23) |
+ (regNumber << 18) |
+ (0x2 << 16);
+ while ((MCF5282_FEC_EIR & MCF5282_FEC_EIR_MII) == 0);
+ MCF5282_FEC_EIR = MCF5282_FEC_EIR_MII;
+ return MCF5282_FEC_MMFR & 0xFFFF;
+}
+
+
+/*
+ * Write MII register
+ * Busy-waits, but transfer time should be short!
+ */
+static void
+setMII(int phyNumber, int regNumber, int value)
+{
+ MCF5282_FEC_MMFR = (0x1 << 30) |
+ (0x1 << 28) |
+ (phyNumber << 23) |
+ (regNumber << 18) |
+ (0x2 << 16) |
+ (value & 0xFFFF);
+ while ((MCF5282_FEC_EIR & MCF5282_FEC_EIR_MII) == 0);
+ MCF5282_FEC_EIR = MCF5282_FEC_EIR_MII;
+}
+
+static void
+mcf5282_fec_initialize_hardware(struct mcf5282_enet_struct *sc)
+{
+ int i;
+ const unsigned char *hwaddr;
+ rtems_status_code status;
+ rtems_isr_entry old_handler;
+ uint32_t clock_speed = get_CPU_clock_speed();
+
+ /*
+ * Issue reset to FEC
+ */
+ MCF5282_FEC_ECR = MCF5282_FEC_ECR_RESET;
+ rtems_task_wake_after(1);
+ MCF5282_FEC_ECR = 0;
+
+ /*
+ * Configuration of I/O ports is done outside of this function
+ */
+#if 0
+ imm->gpio.pbcnt |= MCF5282_GPIO_PBCNT_SET_FEC; /* Set up port b FEC pins */
+#endif
+
+ /*
+ * Set our physical address
+ */
+ hwaddr = sc->arpcom.ac_enaddr;
+ MCF5282_FEC_PALR = (hwaddr[0] << 24) | (hwaddr[1] << 16) |
+ (hwaddr[2] << 8) | (hwaddr[3] << 0);
+ MCF5282_FEC_PAUR = (hwaddr[4] << 24) | (hwaddr[5] << 16);
+
+
+ /*
+ * Clear the hash table
+ */
+ MCF5282_FEC_GAUR = 0;
+ MCF5282_FEC_GALR = 0;
+
+ /*
+ * Set up receive buffer size
+ */
+ MCF5282_FEC_EMRBR = 1520; /* Standard Ethernet */
+
+ /*
+ * Allocate mbuf pointers
+ */
+ sc->rxMbuf = malloc(sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
+ sc->txMbuf = malloc(sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
+ if (!sc->rxMbuf || !sc->txMbuf)
+ rtems_panic("No memory for mbuf pointers");
+
+ /*
+ * Set receiver and transmitter buffer descriptor bases
+ */
+ sc->rxBdBase = mcf5282_bd_allocate(sc->rxBdCount);
+ sc->txBdBase = mcf5282_bd_allocate(sc->txBdCount);
+ MCF5282_FEC_ERDSR = (int)sc->rxBdBase;
+ MCF5282_FEC_ETDSR = (int)sc->txBdBase;
+
+ /*
+ * Set up Receive Control Register:
+ * Not promiscuous
+ * MII mode
+ * Full duplex
+ * No loopback
+ */
+ MCF5282_FEC_RCR = MCF5282_FEC_RCR_MAX_FL(MAX_MTU_SIZE) |
+ MCF5282_FEC_RCR_MII_MODE;
+
+ /*
+ * Set up Transmit Control Register:
+ * Full duplex
+ * No heartbeat
+ */
+ MCF5282_FEC_TCR = MCF5282_FEC_TCR_FDEN;
+
+ /*
+ * Initialize statistic counters
+ */
+ MCF5282_FEC_MIBC = MCF5282_FEC_MIBC_MIB_DISABLE;
+ {
+ vuint32 *vuip = &MCF5282_FEC_RMON_T_DROP;
+ while (vuip <= &MCF5282_FEC_IEEE_R_OCTETS_OK)
+ *vuip++ = 0;
+ }
+ MCF5282_FEC_MIBC = 0;
+
+ /*
+ * Set MII speed to <= 2.5 MHz
+ */
+ i = (clock_speed + 5000000 - 1) / 5000000;
+ MCF5282_FEC_MSCR = MCF5282_FEC_MSCR_MII_SPEED(i);
+
+ /*
+ * Set PHYS to 100 Mb/s, full duplex
+ */
+ setMII(1, 0, 0x2100);
+ setMII(1, 4, 0x0181);
+ setMII(1, 0, 0x0000);
+ rtems_task_wake_after(2);
+ sc->mii_sr2 = getMII(1, 17);
+ setMII(1, 18, 0x0072);
+ setMII(1, 0, 0x1000);
+ /*
+ * Set up receive buffer descriptors
+ */
+ for (i = 0 ; i < sc->rxBdCount ; i++)
+ (sc->rxBdBase + i)->status = 0;
+
+ /*
+ * Set up transmit buffer descriptors
+ */
+ for (i = 0 ; i < sc->txBdCount ; i++) {
+ sc->txBdBase[i].status = 0;
+ sc->txMbuf[i] = NULL;
+ }
+ sc->txBdHead = sc->txBdTail = 0;
+ sc->txBdActiveCount = 0;
+
+ /*
+ * Set up interrupts
+ */
+ status = rtems_interrupt_catch( mcf5282_fec_tx_interrupt_handler, FEC_INTC0_TX_VECTOR, &old_handler );
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't attach MCF5282 FEC TX interrupt handler: %s\n",
+ rtems_status_text(status));
+ status = rtems_interrupt_catch(mcf5282_fec_rx_interrupt_handler, FEC_INTC0_RX_VECTOR, &old_handler);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't attach MCF5282 FEC RX interrupt handler: %s\n",
+ rtems_status_text(status));
+ MCF5282_INTC0_ICR23 = MCF5282_INTC_ICR_IL(FEC_IRQ_LEVEL) |
+ MCF5282_INTC_ICR_IP(FEC_IRQ_TX_PRIORITY);
+ MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT23 | MCF5282_INTC_IMRL_MASKALL);
+ MCF5282_INTC0_ICR27 = MCF5282_INTC_ICR_IL(FEC_IRQ_LEVEL) |
+ MCF5282_INTC_ICR_IP(FEC_IRQ_RX_PRIORITY);
+ MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT27 | MCF5282_INTC_IMRL_MASKALL);
+
+ status = rtems_interrupt_catch(mcf5282_mii_interrupt_handler, MII_VECTOR, &old_handler);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't attach MCF5282 FEC MII interrupt handler: %s\n",
+ rtems_status_text(status));
+ MCF5282_EPORT_EPPAR &= ~MII_EPPAR;
+ MCF5282_EPORT_EPDDR &= ~MII_EPDDR;
+ MCF5282_EPORT_EPIER |= MII_EPIER;
+ MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT7 | MCF5282_INTC_IMRL_MASKALL);
+}
+
+/*
+ * Soak up buffer descriptors that have been sent.
+ */
+void
+fec_retire_tx_bd(volatile struct mcf5282_enet_struct *sc )
+{
+ struct mbuf *m, *n;
+ uint16_t status;
+
+ while ((sc->txBdActiveCount != 0)
+ && (((status = sc->txBdBase[sc->txBdTail].status) & MCF5282_FEC_TxBD_R) == 0)) {
+ if ((status & MCF5282_FEC_TxBD_TO1) == 0) {
+ m = sc->txMbuf[sc->txBdTail];
+ MFREE(m, n);
+ }
+ if (++sc->txBdTail == sc->txBdCount)
+ sc->txBdTail = 0;
+ sc->txBdActiveCount--;
+ }
+}
+
+static void
+fec_rxDaemon (void *arg)
+{
+ volatile struct mcf5282_enet_struct *sc = (volatile struct mcf5282_enet_struct *)arg;
+ struct ifnet *ifp = (struct ifnet* )&sc->arpcom.ac_if;
+ struct mbuf *m;
+ volatile uint16_t status;
+ volatile mcf5282BufferDescriptor_t *rxBd;
+ int rxBdIndex;
+
+ /*
+ * Allocate space for incoming packets and start reception
+ */
+ for (rxBdIndex = 0 ; ;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+ MGETHDR(m, M_WAIT, MT_DATA);
+ MCLGET(m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->buffer = mtod(m, void *);
+ rxBd->status = MCF5282_FEC_RxBD_E;
+ if (++rxBdIndex == sc->rxBdCount) {
+ rxBd->status |= MCF5282_FEC_RxBD_W;
+ break;
+ }
+ }
+
+ /*
+ * Input packet handling loop
+ */
+ /* Indicate we have some ready buffers available */
+ MCF5282_FEC_RDAR = 0;
+
+ rxBdIndex = 0;
+ for (;;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+
+ /*
+ * Wait for packet if there's not one ready
+ */
+ if ((status = rxBd->status) & MCF5282_FEC_RxBD_E) {
+ /*
+ * Clear old events.
+ */
+ MCF5282_FEC_EIR = MCF5282_FEC_EIR_RXF;
+
+ /*
+ * Wait for packet to arrive.
+ * Check the buffer descriptor before waiting for the event.
+ * This catches the case when a packet arrives between the
+ * `if' above, and the clearing of the RXF bit in the EIR.
+ */
+ while ((status = rxBd->status) & MCF5282_FEC_RxBD_E) {
+ rtems_event_set events;
+ int level;
+
+ rtems_interrupt_disable(level);
+ MCF5282_FEC_EIMR |= MCF5282_FEC_EIMR_RXF;
+ rtems_interrupt_enable(level);
+ rtems_bsdnet_event_receive (RX_INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ }
+ }
+
+ /*
+ * Check that packet is valid
+ */
+ if (status & MCF5282_FEC_RxBD_L) {
+ /*
+ * Pass the packet up the chain.
+ * FIXME: Packet filtering hook could be done here.
+ */
+ struct ether_header *eh;
+ int len = rxBd->length - sizeof(uint32_t);
+
+ /*
+ * Invalidate the cache and push the packet up.
+ * The cache is so small that it's more efficient to just
+ * invalidate the whole thing unless the packet is very small.
+ */
+ m = sc->rxMbuf[rxBdIndex];
+ if (len < 128)
+ rtems_cache_invalidate_multiple_data_lines(m->m_data, len);
+ else
+ rtems_cache_invalidate_entire_data();
+ m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);
+ eh = mtod(m, struct ether_header *);
+ m->m_data += sizeof(struct ether_header);
+ ether_input(ifp, eh, m);
+
+ /*
+ * Allocate a new mbuf
+ */
+ MGETHDR(m, M_WAIT, MT_DATA);
+ MCLGET(m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->buffer = mtod(m, void *);
+ }
+
+ /*
+ * Reenable the buffer descriptor
+ */
+ rxBd->status = (status & MCF5282_FEC_RxBD_W) | MCF5282_FEC_RxBD_E;
+ MCF5282_FEC_RDAR = 0;
+
+ /*
+ * Move to next buffer descriptor
+ */
+ if (++rxBdIndex == sc->rxBdCount)
+ rxBdIndex = 0;
+ }
+}
+
+static void
+fec_sendpacket(struct ifnet *ifp, struct mbuf *m)
+{
+ struct mcf5282_enet_struct *sc = ifp->if_softc;
+ volatile mcf5282BufferDescriptor_t *firstTxBd, *txBd;
+ int nAdded;
+ uint16_t status;
+
+ /*
+ * Free up buffer descriptors
+ */
+ fec_retire_tx_bd(sc);
+
+ /*
+ * Set up the transmit buffer descriptors.
+ * No need to pad out short packets since the
+ * hardware takes care of that automatically.
+ * No need to copy the packet to a contiguous buffer
+ * since the hardware is capable of scatter/gather DMA.
+ */
+ nAdded = 0;
+ firstTxBd = sc->txBdBase + sc->txBdHead;
+
+ while(m != NULL) {
+ /*
+ * Wait for buffer descriptor to become available
+ */
+ if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ /*
+ * Clear old events.
+ */
+ MCF5282_FEC_EIR = MCF5282_FEC_EIR_TXF;
+
+ /*
+ * Wait for buffer descriptor to become available.
+ * Check for buffer descriptors before waiting for the event.
+ * This catches the case when a buffer became available between
+ * the `if' above, and the clearing of the TXF bit in the EIR.
+ */
+ fec_retire_tx_bd(sc);
+ while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ rtems_event_set events;
+ int level;
+
+ rtems_interrupt_disable(level);
+ MCF5282_FEC_EIMR |= MCF5282_FEC_EIMR_TXF;
+ rtems_interrupt_enable(level);
+ sc->txRawWait++;
+ rtems_bsdnet_event_receive(TX_INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ fec_retire_tx_bd(sc);
+ }
+ }
+
+ /*
+ * Don't set the READY flag on the first fragment
+ * until the whole packet has been readied.
+ */
+ status = nAdded ? MCF5282_FEC_TxBD_R : 0;
+
+ /*
+ * The IP fragmentation routine in ip_output
+ * can produce fragments with zero length.
+ */
+ if (m->m_len){
+ char *p = mtod(m, char *);
+ int offset = (int) p & 0x3;
+ txBd = sc->txBdBase + sc->txBdHead;
+ if (offset == 0) {
+ txBd->buffer = p;
+ txBd->length = m->m_len;
+ sc->txMbuf[sc->txBdHead] = m;
+ m = m->m_next;
+ }
+ else {
+ /*
+ * Stupid FEC can't handle misaligned data!
+ * Move offending bytes to a local buffer.
+ * Use buffer descriptor TO1 bit to indicate this.
+ */
+ int nmove = 4 - offset;
+ char *d = (char *)&sc->txMbuf[sc->txBdHead];
+ status |= MCF5282_FEC_TxBD_TO1;
+ sc->txRealign++;
+ if (nmove > m->m_len)
+ nmove = m->m_len;
+ m->m_data += nmove;
+ m->m_len -= nmove;
+ txBd->buffer = d;
+ txBd->length = nmove;
+ while (nmove--)
+ *d++ = *p++;
+ if (m->m_len == 0) {
+ struct mbuf *n;
+ sc->txRealignDrop++;
+ MFREE(m, n);
+ m = n;
+ }
+ }
+ nAdded++;
+ if (++sc->txBdHead == sc->txBdCount) {
+ status |= MCF5282_FEC_TxBD_W;
+ sc->txBdHead = 0;
+ }
+ txBd->status = status;
+ }
+ else {
+ /*
+ * Just toss empty mbufs
+ */
+ struct mbuf *n;
+ MFREE(m, n);
+ m = n;
+ }
+ }
+ if (nAdded) {
+ txBd->status = status | MCF5282_FEC_TxBD_R
+ | MCF5282_FEC_TxBD_L
+ | MCF5282_FEC_TxBD_TC;
+ if (nAdded > 1)
+ firstTxBd->status |= MCF5282_FEC_TxBD_R;
+ MCF5282_FEC_TDAR = 0;
+ sc->txBdActiveCount += nAdded;
+ }
+}
+
+void
+fec_txDaemon(void *arg)
+{
+ struct mcf5282_enet_struct *sc = (struct mcf5282_enet_struct *)arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_event_set events;
+
+ for (;;) {
+ /*
+ * Wait for packet
+ */
+ rtems_bsdnet_event_receive(START_TRANSMIT_EVENT,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT,
+ &events);
+
+ /*
+ * Send packets till queue is empty
+ */
+ for (;;) {
+ /*
+ * Get the next mbuf chain to transmit.
+ */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (!m)
+ break;
+ fec_sendpacket(ifp, m);
+ }
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+}
+
+
+/*
+ * Send packet (caller provides header).
+ */
+static void
+mcf5282_enet_start(struct ifnet *ifp)
+{
+ struct mcf5282_enet_struct *sc = ifp->if_softc;
+
+ rtems_bsdnet_event_send(sc->txDaemonTid, START_TRANSMIT_EVENT);
+ ifp->if_flags |= IFF_OACTIVE;
+}
+
+static void
+fec_init(void *arg)
+{
+ struct mcf5282_enet_struct *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ if (sc->txDaemonTid == 0) {
+ /*
+ * Set up hardware
+ */
+ mcf5282_fec_initialize_hardware(sc);
+
+ /*
+ * Start driver tasks
+ */
+ sc->txDaemonTid = rtems_bsdnet_newproc("FECtx", 4096, fec_txDaemon, sc);
+ sc->rxDaemonTid = rtems_bsdnet_newproc("FECrx", 4096, fec_rxDaemon, sc);
+ }
+
+ /*
+ * Set flags appropriately
+ */
+ if (ifp->if_flags & IFF_PROMISC)
+ MCF5282_FEC_RCR |= MCF5282_FEC_RCR_PROM;
+ else
+ MCF5282_FEC_RCR &= ~MCF5282_FEC_RCR_PROM;
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+
+ /*
+ * Enable receiver and transmitter
+ */
+ MCF5282_FEC_ECR = MCF5282_FEC_ECR_ETHER_EN;
+}
+
+
+static void
+fec_stop(struct mcf5282_enet_struct *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ /*
+ * Shut down receiver and transmitter
+ */
+ MCF5282_FEC_ECR = 0x0;
+}
+
+/*
+ * Show interface statistics
+ */
+static void
+enet_stats(struct mcf5282_enet_struct *sc)
+{
+ printf(" Rx Interrupts:%-10lu", sc->rxInterrupts);
+ printf("Rx Packet Count:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_PACKETS);
+ printf(" Rx Broadcast:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_BC_PKT);
+ printf(" Rx Multicast:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_MC_PKT);
+ printf("CRC/Align error:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_CRC_ALIGN);
+ printf(" Rx Undersize:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_UNDERSIZE);
+ printf(" Rx Oversize:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_OVERSIZE);
+ printf(" Rx Fragment:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_FRAG);
+ printf(" Rx Jabber:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_JAB);
+ printf(" Rx 64:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_P64);
+ printf(" Rx 65-127:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_P65T0127);
+ printf(" Rx 128-255:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_P128TO255);
+ printf(" Rx 256-511:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_P256TO511);
+ printf(" Rx 511-1023:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_P512TO1023);
+ printf(" Rx 1024-2047:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_P1024TO2047);
+ printf(" Rx >=2048:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_GTE2048);
+ printf(" Rx Octets:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_OCTETS);
+ printf(" Rx Dropped:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_R_DROP);
+ printf(" Rx frame OK:%-10lu", (uint32_t) MCF5282_FEC_IEEE_R_FRAME_OK);
+ printf(" Rx CRC error:%-10lu", (uint32_t) MCF5282_FEC_IEEE_R_CRC);
+ printf(" Rx Align error:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_R_ALIGN);
+ printf(" FIFO Overflow:%-10lu", (uint32_t) MCF5282_FEC_IEEE_R_MACERR);
+ printf("Rx Pause Frames:%-10lu", (uint32_t) MCF5282_FEC_IEEE_R_FDXFC);
+ printf(" Rx Octets OK:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_R_OCTETS_OK);
+ printf(" Tx Interrupts:%-10lu", sc->txInterrupts);
+ printf("Tx Output Waits:%-10lu", sc->txRawWait);
+ printf("Tx mbuf realign:%-10lu\n", sc->txRealign);
+ printf("Tx realign drop:%-10lu", sc->txRealignDrop);
+ printf(" Tx Unaccounted:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_DROP);
+ printf("Tx Packet Count:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_PACKETS);
+ printf(" Tx Broadcast:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_BC_PKT);
+ printf(" Tx Multicast:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_MC_PKT);
+ printf("CRC/Align error:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_CRC_ALIGN);
+ printf(" Tx Undersize:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_UNDERSIZE);
+ printf(" Tx Oversize:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_OVERSIZE);
+ printf(" Tx Fragment:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_FRAG);
+ printf(" Tx Jabber:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_JAB);
+ printf(" Tx Collisions:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_COL);
+ printf(" Tx 64:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_P64);
+ printf(" Tx 65-127:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_P65TO127);
+ printf(" Tx 128-255:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_P128TO255);
+ printf(" Tx 256-511:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_P256TO511);
+ printf(" Tx 511-1023:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_P512TO1023);
+ printf(" Tx 1024-2047:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_P1024TO2047);
+ printf(" Tx >=2048:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_P_GTE2048);
+ printf(" Tx Octets:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_OCTETS);
+ printf(" Tx Dropped:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_DROP);
+ printf(" Tx Frame OK:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_T_FRAME_OK);
+ printf(" Tx 1 Collision:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_1COL);
+ printf("Tx >1 Collision:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_MCOL);
+ printf(" Tx Deferred:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_T_DEF);
+ printf(" Late Collision:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_LCOL);
+ printf(" Excessive Coll:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_EXCOL);
+ printf(" FIFO Underrun:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_T_MACERR);
+ printf(" Carrier Error:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_CSERR);
+ printf(" Tx SQE Error:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_SQE);
+ printf("Tx Pause Frames:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_T_FDXFC);
+ printf(" Tx Octets OK:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_OCTETS_OK);
+ printf(" MII interrupts:%-10lu\n", sc->miiInterrupts);
+
+ printf(" EIR:%8.8lx ", (uint32_t) MCF5282_FEC_EIR);
+ printf("EIMR:%8.8lx ", (uint32_t) MCF5282_FEC_EIMR);
+ printf("RDAR:%8.8lx ", (uint32_t) MCF5282_FEC_RDAR);
+ printf("TDAR:%8.8lx\n", (uint32_t) MCF5282_FEC_TDAR);
+ printf(" ECR:%8.8lx ", (uint32_t) MCF5282_FEC_ECR);
+ printf(" RCR:%8.8lx ", (uint32_t) MCF5282_FEC_RCR);
+ printf(" TCR:%8.8lx\n", (uint32_t) MCF5282_FEC_TCR);
+ printf("FRBR:%8.8lx ", (uint32_t) MCF5282_FEC_FRBR);
+ printf("FRSR:%8.8lx\n", (uint32_t) MCF5282_FEC_FRSR);
+ if (sc->txBdActiveCount != 0) {
+ int i, n;
+ /*
+ * Yes, there are races here with adding and retiring descriptors,
+ * but this diagnostic is more for when things have backed up.
+ */
+ printf("Transmit Buffer Descriptors (Tail %d, Head %d, Unretired %d):\n",
+ sc->txBdTail,
+ sc->txBdHead,
+ sc->txBdActiveCount);
+ i = sc->txBdTail;
+ for (n = 0 ; n < sc->txBdCount ; n++) {
+ if ((sc->txBdBase[i].status & MCF5282_FEC_TxBD_R) != 0)
+ printf(" %3d: status:%4.4x length:%-4d buffer:%p\n",
+ i,
+ sc->txBdBase[i].status,
+ sc->txBdBase[i].length,
+ sc->txBdBase[i].buffer);
+ if (++i == sc->txBdCount)
+ i = 0;
+ }
+ }
+}
+
+static int
+fec_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
+{
+ struct mcf5282_enet_struct *sc = ifp->if_softc;
+ int error = 0;
+
+ switch (command) {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ ether_ioctl(ifp, command, data);
+ break;
+
+ case SIOCSIFFLAGS:
+ switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
+ case IFF_RUNNING:
+ fec_stop(sc);
+ break;
+
+ case IFF_UP:
+ fec_init(sc);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ fec_stop(sc);
+ fec_init(sc);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ enet_stats(sc);
+ break;
+
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+int
+rtems_fec_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching )
+{
+ struct mcf5282_enet_struct *sc;
+ struct ifnet *ifp;
+ int mtu;
+ int unitNumber;
+ char *unitName;
+ unsigned char *hwaddr;
+
+ /*
+ * Parse driver name
+ */
+ if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
+ return 0;
+
+ /*
+ * Is driver free?
+ */
+ if ((unitNumber <= 0) || (unitNumber > NIFACES)) {
+ printf("Bad FEC unit number.\n");
+ return 0;
+ }
+ sc = &enet_driver[unitNumber - 1];
+ ifp = &sc->arpcom.ac_if;
+ if (ifp->if_softc != NULL) {
+ printf("Driver already in use.\n");
+ return 0;
+ }
+
+ /*
+ * Process options
+ */
+ printf("%s%d: Ethernet address: ", unitName, unitNumber );
+ if (config->hardware_address) {
+ hwaddr = config->hardware_address;
+ printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+ hwaddr[0], hwaddr[1], hwaddr[2],
+ hwaddr[3], hwaddr[4], hwaddr[5]);
+ memcpy(sc->arpcom.ac_enaddr, hwaddr, ETHER_ADDR_LEN);
+ } else {
+ printf("UNKNOWN\n");
+ }
+
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+ if (config->rbuf_count)
+ sc->rxBdCount = config->rbuf_count;
+ else
+ sc->rxBdCount = RX_BUF_COUNT;
+ if (config->xbuf_count)
+ sc->txBdCount = config->xbuf_count;
+ else
+ sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
+
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+ /*
+ * Set up network interface values
+ */
+ ifp->if_softc = sc;
+ ifp->if_unit = unitNumber;
+ ifp->if_name = unitName;
+ ifp->if_mtu = mtu;
+ ifp->if_init = fec_init;
+ ifp->if_ioctl = fec_ioctl;
+ ifp->if_start = mcf5282_enet_start;
+ ifp->if_output = ether_output;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ /*
+ * Attach the interface
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ return 1;
+};
+
diff --git a/bsps/m68k/csb360/net/network.c b/bsps/m68k/csb360/net/network.c
new file mode 100644
index 0000000000..47e0adb44d
--- /dev/null
+++ b/bsps/m68k/csb360/net/network.c
@@ -0,0 +1,984 @@
+/*
+ * RTEMS/TCPIP driver for MCF5272 Ethernet
+ *
+ * Modified for MPC860 by Jay Monkman (jmonkman@lopingdog.com)
+ *
+ * This supports Ethernet on either SCC1 or the FEC of the MPC860T.
+ * Right now, we only do 10 Mbps, even with the FEC. The function
+ * rtems_enet_driver_attach determines which one to use. Currently,
+ * only one may be used at a time.
+ *
+ * Based on the MC68360 network driver by
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ *
+ * This supports ethernet on SCC1. Right now, we only do 10 Mbps.
+ *
+ * Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
+ * and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>
+ * Copyright (c) 1999, National Research Council of Canada
+ */
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+
+#include <bsp.h>
+#include <stdio.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/*
+ * Number of interfaces supported by this driver
+ */
+#define NIFACES 1
+
+/*
+ * Default number of buffer descriptors set aside for this driver.
+ * The number of transmit buffer descriptors has to be quite large
+ * since a single frame often uses four or more buffer descriptors.
+ */
+#define RX_BUF_COUNT 32
+#define TX_BUF_COUNT 16
+#define TX_BD_PER_BUF 4
+
+#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
+
+
+/*
+ * RTEMS event used by interrupt handler to signal daemons.
+ * This must *not* be the same event used by the TCP/IP task synchronization.
+ */
+#define INTERRUPT_EVENT RTEMS_EVENT_1
+
+/*
+ * RTEMS event used to start transmit daemon.
+ * This must not be the same as INTERRUPT_EVENT.
+ */
+#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+
+/*
+ * Receive buffer size -- Allow for a full ethernet packet plus CRC (1518).
+ * Round off to nearest multiple of RBUF_ALIGN.
+ */
+#define MAX_MTU_SIZE 1518
+#define RBUF_ALIGN 4
+#define RBUF_SIZE ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN)
+
+#if (MCLBYTES < RBUF_SIZE)
+# error "Driver must have MCLBYTES > RBUF_SIZE"
+#endif
+
+typedef struct {
+ uint16_t status;
+ uint16_t length;
+ void *buffer;
+} bd_t;
+#define MCF5272_BD_READY (bit(15))
+#define MCF5272_BD_TO1 (bit(14))
+#define MCF5272_BD_WRAP (bit(13))
+#define MCF5272_BD_TO2 (bit(12))
+#define MCF5272_BD_LAST (bit(11))
+#define MCF5272_BD_TX_CRC (bit(10))
+#define MCF5272_BD_DEFER (bit(9))
+#define MCF5272_BD_HEARTBEAT (bit(8))
+#define MCF5272_BD_LATE_COLLISION (bit(7))
+#define MCF5272_BD_RETRY_LIMIT (bit(6))
+#define MCF5272_BD_UNDERRUN (bit(1))
+#define MCF5272_BD_CARRIER_LOST (bit(0))
+
+#define MCF5272_BD_EMPTY (bit(15))
+#define MCF5272_BD_RO1 (bit(14))
+#define MCF5272_BD_WRAP (bit(13))
+#define MCF5272_BD_RO2 (bit(12))
+#define MCF5272_BD_M (bit(8))
+#define MCF5272_BD_BC (bit(7))
+#define MCF5272_BD_MC (bit(6))
+#define MCF5272_BD_LONG (bit(5))
+#define MCF5272_BD_NONALIGNED (bit(4))
+#define MCF5272_BD_SHORT (bit(3))
+#define MCF5272_BD_CRC_ERROR (bit(2))
+#define MCF5272_BD_OVERRUN (bit(1))
+#define MCF5272_BD_TRUNCATED (bit(0))
+
+
+/*
+ * Per-device data
+ */
+struct mcf5272_enet_struct {
+ struct arpcom arpcom;
+ struct mbuf **rxMbuf;
+ struct mbuf **txMbuf;
+ int acceptBroadcast;
+ int rxBdCount;
+ int txBdCount;
+ int txBdHead;
+ int txBdTail;
+ int txBdActiveCount;
+ bd_t *rxBdBase;
+ bd_t *txBdBase;
+ rtems_id rxDaemonTid;
+ rtems_id txDaemonTid;
+
+ /*
+ * Statistics
+ */
+ unsigned long rxInterrupts;
+ unsigned long rxNotFirst;
+ unsigned long rxNotLast;
+ unsigned long rxGiant;
+ unsigned long rxNonOctet;
+ unsigned long rxRunt;
+ unsigned long rxBadCRC;
+ unsigned long rxOverrun;
+ unsigned long rxTruncated;
+
+ unsigned long txInterrupts;
+ unsigned long txDeferred;
+ unsigned long txHeartbeat;
+ unsigned long txLateCollision;
+ unsigned long txRetryLimit;
+ unsigned long txUnderrun;
+ unsigned long txLostCarrier;
+ unsigned long txRawWait;
+};
+static struct mcf5272_enet_struct enet_driver[NIFACES];
+
+
+void dump_enet_regs(void)
+{
+ printf("**************************************************************\n");
+ printf("ecr: 0x%08x eir: 0x%08x eimr: 0x%08x ivsr: 0x%08x\n\r",
+ g_enet_regs->ecr, g_enet_regs->eir,
+ g_enet_regs->eimr, g_enet_regs->ivsr);
+ printf("rdar: 0x%08x tdar: 0x%08x mmfr: 0x%08x mscr: 0x%08x\n\r",
+ g_enet_regs->rdar, g_enet_regs->tdar,
+ g_enet_regs->mmfr, g_enet_regs->mscr);
+ printf("frbr: 0x%08x frsr: 0x%08x tfwr: 0x%08x tfsr: 0x%08x\n\r",
+ g_enet_regs->frbr, g_enet_regs->frsr,
+ g_enet_regs->tfwr, g_enet_regs->tfsr);
+ printf("rcr: 0x%08x mflr: 0x%08x tcr: 0x%08x malr: 0x%08x\n\r",
+ g_enet_regs->rcr, g_enet_regs->mflr,
+ g_enet_regs->tcr, g_enet_regs->malr);
+ printf("maur: 0x%08x htur: 0x%08x htlr: 0x%08x erdsr: 0x%08x\n\r",
+ g_enet_regs->maur, g_enet_regs->htur,
+ g_enet_regs->htlr, g_enet_regs->erdsr);
+ printf("etdsr: 0x%08x emrbr: 0x%08x\n\r",
+ g_enet_regs->etdsr, g_enet_regs->emrbr);
+}
+
+
+
+
+/*#define cp printk("%s:%d\n\r", __FUNCTION__, __LINE__) */
+#define cp
+#define mcf5272_bd_allocate(_n_) malloc((_n_) * sizeof(bd_t), 0, M_NOWAIT)
+
+
+
+rtems_isr enet_rx_isr(rtems_vector_number vector)
+{
+ cp;
+ /*
+ * Frame received?
+ */
+ if (g_enet_regs->eir & MCF5272_ENET_EIR_RXF) {
+ cp;
+ g_enet_regs->eir = MCF5272_ENET_EIR_RXF;
+ enet_driver[0].rxInterrupts++;
+ rtems_bsdnet_event_send (enet_driver[0].rxDaemonTid, INTERRUPT_EVENT);
+ }
+ cp;
+}
+
+rtems_isr enet_tx_isr(rtems_vector_number vector)
+{
+ cp;
+ /*
+ * Buffer transmitted or transmitter error?
+ */
+ if (g_enet_regs->eir & MCF5272_ENET_EIR_TXF) {
+ cp;
+ g_enet_regs->eir = MCF5272_ENET_EIR_TXF;
+ enet_driver[0].txInterrupts++;
+ rtems_bsdnet_event_send (enet_driver[0].txDaemonTid, INTERRUPT_EVENT);
+ }
+ cp;
+}
+
+
+/*
+ * Initialize the ethernet hardware
+ */
+
+
+static void
+mcf5272_enet_initialize_hardware (struct mcf5272_enet_struct *sc)
+{
+ int i;
+ unsigned char *hwaddr;
+ uint32_t icr;
+ /*
+ * Issue reset to FEC
+ */
+ g_enet_regs->ecr=0x1;
+
+ /*
+ * Set the TX and RX fifo sizes. For now, we'll split it evenly
+ */
+ /* If you uncomment these, the FEC will not work right.
+ g_enet_regs->r_fstart = ((g_enet_regs->r_bound & 0x3ff) >> 2) & 0x3ff;
+ g_enet_regs->x_fstart = 0;
+ */
+
+ /* Copy mac address to device */
+
+ hwaddr = sc->arpcom.ac_enaddr;
+
+ g_enet_regs->malr = (hwaddr[0] << 24 |
+ hwaddr[1] << 16 |
+ hwaddr[2] << 8 |
+ hwaddr[3]);
+ g_enet_regs->maur = (hwaddr[4] << 24 |
+ hwaddr[5] << 16);
+
+ /*
+ * Clear the hash table
+ */
+ g_enet_regs->htlr = 0;
+ g_enet_regs->htur = 0;
+
+ /*
+ * Set up receive buffer size
+ */
+ g_enet_regs->emrbr = 0x5f0; /* set to 1520 */
+
+ /*
+ * Allocate mbuf pointers
+ */
+ sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf,
+ M_MBUF, M_NOWAIT);
+ sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf,
+ M_MBUF, M_NOWAIT);
+ if (!sc->rxMbuf || !sc->txMbuf) {
+ rtems_panic ("No memory for mbuf pointers");
+ }
+
+ /*
+ * Set receiver and transmitter buffer descriptor bases
+ */
+ sc->rxBdBase = mcf5272_bd_allocate(sc->rxBdCount);
+ sc->txBdBase = mcf5272_bd_allocate(sc->txBdCount);
+ g_enet_regs->erdsr = (int)sc->rxBdBase;
+ g_enet_regs->etdsr = (int)sc->txBdBase;
+
+ /*
+ * Set up Receive Control Register:
+ * Not promiscuous mode
+ * MII mode
+ * Full duplex
+ * No loopback
+ */
+ g_enet_regs->rcr = 0x00000004;
+
+ /*
+ * Set up Transmit Control Register:
+ * Full duplex
+ * No heartbeat
+ */
+ g_enet_regs->tcr = 0x00000004;
+
+ /*
+ * Set MII speed to 2.5 MHz for 25 Mhz system clock
+ */
+ g_enet_regs->mscr = 0x0a;
+ g_enet_regs->mmfr = 0x58021000;
+
+ /*
+ * Set up receive buffer descriptors
+ */
+ for (i = 0 ; i < sc->rxBdCount ; i++) {
+ (sc->rxBdBase + i)->status = 0;
+ }
+
+ /*
+ * Set up transmit buffer descriptors
+ */
+ for (i = 0 ; i < sc->txBdCount ; i++) {
+ (sc->txBdBase + i)->status = 0;
+ sc->txMbuf[i] = NULL;
+ }
+
+ sc->txBdHead = sc->txBdTail = 0;
+ sc->txBdActiveCount = 0;
+
+ /*
+ * Mask all FEC interrupts and clear events
+ */
+ g_enet_regs->eimr = (MCF5272_ENET_EIR_TXF |
+ MCF5272_ENET_EIR_RXF);
+ g_enet_regs->eir = ~0;
+
+ /*
+ * Set up interrupts
+ */
+ set_vector(enet_rx_isr, BSP_INTVEC_ERX, 1);
+ set_vector(enet_tx_isr, BSP_INTVEC_ETX, 1);
+
+ /* Configure ethernet interrupts */
+ icr = g_intctrl_regs->icr3;
+ icr = icr & ~((MCF5272_ICR3_ERX_MASK | MCF5272_ICR3_ERX_PI) |
+ (MCF5272_ICR3_ETX_MASK | MCF5272_ICR3_ETX_PI));
+ icr |= ((MCF5272_ICR3_ERX_IPL(BSP_INTLVL_ERX) | MCF5272_ICR3_ERX_PI)|
+ (MCF5272_ICR3_ETX_IPL(BSP_INTLVL_ETX) | MCF5272_ICR3_ETX_PI));
+ g_intctrl_regs->icr3 = icr;
+
+}
+
+
+/*
+ * Soak up buffer descriptors that have been sent.
+ * Note that a buffer descriptor can't be retired as soon as it becomes
+ * ready. The MPC860 manual (MPC860UM/AD 07/98 Rev.1) and the MPC821
+ * manual state that, "If an Ethernet frame is made up of multiple
+ * buffers, the user should not reuse the first buffer descriptor until
+ * the last buffer descriptor of the frame has had its ready bit cleared
+ * by the CPM".
+ */
+static void
+mcf5272_enet_retire_tx_bd (struct mcf5272_enet_struct *sc)
+{
+ uint16_t status;
+ int i;
+ int nRetired;
+ struct mbuf *m, *n;
+
+ i = sc->txBdTail;
+ nRetired = 0;
+ while ((sc->txBdActiveCount != 0) &&
+ (((status = sc->txBdBase[i].status) & MCF5272_BD_READY) == 0)) {
+ /*
+ * See if anything went wrong
+ */
+ if (status & (MCF5272_BD_DEFER |
+ MCF5272_BD_HEARTBEAT |
+ MCF5272_BD_LATE_COLLISION |
+ MCF5272_BD_RETRY_LIMIT |
+ MCF5272_BD_UNDERRUN |
+ MCF5272_BD_CARRIER_LOST)) {
+ /*
+ * Check for errors which stop the transmitter.
+ */
+ if (status & (MCF5272_BD_LATE_COLLISION |
+ MCF5272_BD_RETRY_LIMIT |
+ MCF5272_BD_UNDERRUN)) {
+ if (status & MCF5272_BD_LATE_COLLISION) {
+ enet_driver[0].txLateCollision++;
+ }
+ if (status & MCF5272_BD_RETRY_LIMIT) {
+ enet_driver[0].txRetryLimit++;
+ }
+ if (status & MCF5272_BD_UNDERRUN) {
+ enet_driver[0].txUnderrun++;
+ }
+ }
+ if (status & MCF5272_BD_DEFER) {
+ enet_driver[0].txDeferred++;
+ }
+ if (status & MCF5272_BD_HEARTBEAT) {
+ enet_driver[0].txHeartbeat++;
+ }
+ if (status & MCF5272_BD_CARRIER_LOST) {
+ enet_driver[0].txLostCarrier++;
+ }
+ }
+ nRetired++;
+ if (status & MCF5272_BD_LAST) {
+ /*
+ * A full frame has been transmitted.
+ * Free all the associated buffer descriptors.
+ */
+ sc->txBdActiveCount -= nRetired;
+ while (nRetired) {
+ nRetired--;
+ m = sc->txMbuf[sc->txBdTail];
+ MFREE (m, n);
+ if (++sc->txBdTail == sc->txBdCount)
+ sc->txBdTail = 0;
+ }
+ }
+ if (++i == sc->txBdCount) {
+ i = 0;
+ }
+ }
+}
+
+static void
+mcf5272_enet_rxDaemon (void *arg)
+{
+ struct mcf5272_enet_struct *sc = (struct mcf5272_enet_struct *)arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+ uint16_t status;
+ bd_t *rxBd;
+ int rxBdIndex;
+
+ /*
+ * Allocate space for incoming packets and start reception
+ */
+ for (rxBdIndex = 0 ; ;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+ MGETHDR (m, M_WAIT, MT_DATA);
+ MCLGET (m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->buffer = mtod (m, void *);
+ rxBd->status = MCF5272_BD_EMPTY;
+ g_enet_regs->rdar = 0x1000000;
+ if (++rxBdIndex == sc->rxBdCount) {
+ rxBd->status |= MCF5272_BD_WRAP;
+ break;
+ }
+ }
+
+ /*
+ * Input packet handling loop
+ */
+ rxBdIndex = 0;
+ for (;;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+
+ /*
+ * Wait for packet if there's not one ready
+ */
+ if ((status = rxBd->status) & MCF5272_BD_EMPTY) {
+ /*
+ * Clear old events
+ */
+ g_enet_regs->eir = MCF5272_ENET_EIR_RXF;
+
+ /*
+ * Wait for packet
+ * Note that the buffer descriptor is checked
+ * *before* the event wait -- this catches the
+ * possibility that a packet arrived between the
+ * `if' above, and the clearing of the event register.
+ */
+ while ((status = rxBd->status) & MCF5272_BD_EMPTY) {
+ rtems_event_set events;
+
+ /*
+ * Unmask RXF (Full frame received) event
+ */
+ g_enet_regs->eir |= MCF5272_ENET_EIR_RXF;
+
+ rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ cp;
+ }
+ }
+ cp;
+
+ /*
+ * Check that packet is valid
+ */
+ if (status & MCF5272_BD_LAST) {
+ /*
+ * Pass the packet up the chain.
+ * FIXME: Packet filtering hook could be done here.
+ */
+ struct ether_header *eh;
+
+ m = sc->rxMbuf[rxBdIndex];
+ m->m_len = m->m_pkthdr.len = (rxBd->length -
+ sizeof(uint32_t) -
+ sizeof(struct ether_header));
+ eh = mtod (m, struct ether_header *);
+ m->m_data += sizeof(struct ether_header);
+ ether_input (ifp, eh, m);
+
+ /*
+ * Allocate a new mbuf
+ */
+ MGETHDR (m, M_WAIT, MT_DATA);
+ MCLGET (m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->buffer = mtod (m, void *);
+ }
+ else {
+ /*
+ * Something went wrong with the reception
+ */
+ if (!(status & MCF5272_BD_LAST)) {
+ sc->rxNotLast++;
+ }
+ if (status & MCF5272_BD_LONG) {
+ sc->rxGiant++;
+ }
+ if (status & MCF5272_BD_NONALIGNED) {
+ sc->rxNonOctet++;
+ }
+ if (status & MCF5272_BD_SHORT) {
+ sc->rxRunt++;
+ }
+ if (status & MCF5272_BD_CRC_ERROR) {
+ sc->rxBadCRC++;
+ }
+ if (status & MCF5272_BD_OVERRUN) {
+ sc->rxOverrun++;
+ }
+ if (status & MCF5272_BD_TRUNCATED) {
+ sc->rxTruncated++;
+ }
+ }
+ /*
+ * Reenable the buffer descriptor
+ */
+ rxBd->status = (status & MCF5272_BD_WRAP) | MCF5272_BD_EMPTY;
+ g_enet_regs->rdar = 0x1000000;
+ /*
+ * Move to next buffer descriptor
+ */
+ if (++rxBdIndex == sc->rxBdCount) {
+ rxBdIndex = 0;
+ }
+ }
+}
+
+static void
+mcf5272_enet_sendpacket (struct ifnet *ifp, struct mbuf *m)
+{
+ struct mcf5272_enet_struct *sc = ifp->if_softc;
+ volatile bd_t *firstTxBd, *txBd;
+ /* struct mbuf *l = NULL; */
+ uint16_t status;
+ int nAdded;
+ cp;
+
+ /*
+ * Free up buffer descriptors
+ */
+ mcf5272_enet_retire_tx_bd (sc);
+
+ /*
+ * Set up the transmit buffer descriptors.
+ * No need to pad out short packets since the
+ * hardware takes care of that automatically.
+ * No need to copy the packet to a contiguous buffer
+ * since the hardware is capable of scatter/gather DMA.
+ */
+ nAdded = 0;
+ txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
+ for (;;) {
+ cp;
+ /*
+ * Wait for buffer descriptor to become available.
+ */
+ if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ /*
+ * Clear old events
+ */
+ g_enet_regs->eir = MCF5272_ENET_EIR_TXF;
+
+ /*
+ * Wait for buffer descriptor to become available.
+ * Note that the buffer descriptors are checked
+ * *before* * entering the wait loop -- this catches
+ * the possibility that a buffer descriptor became
+ * available between the `if' above, and the clearing
+ * of the event register.
+ * This is to catch the case where the transmitter
+ * stops in the middle of a frame -- and only the
+ * last buffer descriptor in a frame can generate
+ * an interrupt.
+ */
+ mcf5272_enet_retire_tx_bd (sc);
+ while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ rtems_event_set events;
+
+ cp;
+ /*
+ * Unmask TXB (buffer transmitted) and
+ * TXE (transmitter error) events.
+ */
+ g_enet_regs->eir |= MCF5272_ENET_EIR_TXF;
+ rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ cp;
+ mcf5272_enet_retire_tx_bd (sc);
+ }
+ }
+
+ /*
+ * Don't set the READY flag till the
+ * whole packet has been readied.
+ */
+ status = nAdded ? MCF5272_BD_READY : 0;
+ cp;
+
+ /*
+ * FIXME: Why not deal with empty mbufs at at higher level?
+ * The IP fragmentation routine in ip_output
+ * can produce packet fragments with zero length.
+ * I think that ip_output should be changed to get
+ * rid of these zero-length mbufs, but for now,
+ * I'll deal with them here.
+ */
+ if (m->m_len) {
+ cp;
+ /*
+ * Fill in the buffer descriptor
+ */
+ txBd->buffer = mtod (m, void *);
+ txBd->length = m->m_len;
+
+ sc->txMbuf[sc->txBdHead] = m;
+ nAdded++;
+ if (++sc->txBdHead == sc->txBdCount) {
+ status |= MCF5272_BD_WRAP;
+ sc->txBdHead = 0;
+ }
+ /* l = m;*/
+ m = m->m_next;
+ }
+ else {
+ /*
+ * Just toss empty mbufs
+ */
+ struct mbuf *n;
+ cp;
+ MFREE (m, n);
+ m = n;
+ /*
+ if (l != NULL)
+ l->m_next = m;
+ */
+ }
+
+ /*
+ * Set the transmit buffer status.
+ * Break out of the loop if this mbuf is the last in the frame.
+ */
+ if (m == NULL) {
+ cp;
+ if (nAdded) {
+ cp;
+ status |= MCF5272_BD_LAST | MCF5272_BD_TX_CRC;
+ txBd->status = status;
+ firstTxBd->status |= MCF5272_BD_READY;
+ g_enet_regs->tdar = 0x1000000;
+ sc->txBdActiveCount += nAdded;
+ }
+ break;
+ }
+ txBd->status = status;
+ txBd = sc->txBdBase + sc->txBdHead;
+ }
+ cp;
+/*
+ dump_enet_regs();
+ dump_intctrl;
+*/
+
+}
+
+
+void
+mcf5272_enet_txDaemon (void *arg)
+{
+ struct mcf5272_enet_struct *sc = (struct mcf5272_enet_struct *)arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_event_set events;
+
+ cp;
+ for (;;) {
+ /*
+ * Wait for packet
+ */
+ rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ cp;
+ /*
+ * Send packets till queue is empty
+ */
+ cp;
+ for (;;) {
+ cp;
+ /*
+ * Get the next mbuf chain to transmit.
+ */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (!m)
+ break;
+ mcf5272_enet_sendpacket (ifp, m);
+ }
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+}
+
+
+/*
+ * Send packet (caller provides header).
+ */
+static void
+mcf5272_enet_start (struct ifnet *ifp)
+{
+ struct mcf5272_enet_struct *sc = ifp->if_softc;
+
+ cp;
+ rtems_bsdnet_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
+ cp;
+ ifp->if_flags |= IFF_OACTIVE;
+}
+
+
+static void
+mcf5272_enet_init (void *arg)
+{
+ struct mcf5272_enet_struct *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ if (sc->txDaemonTid == 0) {
+
+ /*
+ * Set up SCC hardware
+ */
+ mcf5272_enet_initialize_hardware (sc);
+
+ /*
+ * Start driver tasks
+ */
+ sc->txDaemonTid = rtems_bsdnet_newproc("SCtx",
+ 4096,
+ mcf5272_enet_txDaemon,
+ sc);
+ sc->rxDaemonTid = rtems_bsdnet_newproc("SCrx",
+ 4096,
+ mcf5272_enet_rxDaemon,
+ sc);
+
+ }
+
+ /*
+ * Set flags appropriately
+ */
+ if (ifp->if_flags & IFF_PROMISC) {
+ g_enet_regs->rcr |= 0x8;
+ } else {
+ g_enet_regs->rcr &= ~0x8;
+ }
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+
+ /*
+ * Enable receiver and transmitter
+ */
+ g_enet_regs->ecr = 0x2;
+}
+
+
+static void
+mcf5272_enet_stop (struct mcf5272_enet_struct *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ /*
+ * Shut down receiver and transmitter
+ */
+ g_enet_regs->ecr = 0x0;
+}
+
+
+/*
+ * Show interface statistics
+ */
+static void
+enet_stats (struct mcf5272_enet_struct *sc)
+{
+ printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
+ printf (" Not First:%-8lu", sc->rxNotFirst);
+ printf (" Not Last:%-8lu\n", sc->rxNotLast);
+ printf (" Giant:%-8lu", sc->rxGiant);
+ printf (" Runt:%-8lu", sc->rxRunt);
+ printf (" Non-octet:%-8lu\n", sc->rxNonOctet);
+ printf (" Bad CRC:%-8lu", sc->rxBadCRC);
+ printf (" Overrun:%-8lu", sc->rxOverrun);
+ printf (" Truncated:%-8lu\n", sc->rxTruncated);
+/* printf (" Discarded:%-8lu\n", (unsigned long)mcf5272.scc1p.un.ethernet.disfc); */
+
+ printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
+ printf (" Deferred:%-8lu", sc->txDeferred);
+ printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
+ printf (" No Carrier:%-8lu", sc->txLostCarrier);
+ printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
+ printf (" Late Collision:%-8lu\n", sc->txLateCollision);
+ printf (" Underrun:%-8lu", sc->txUnderrun);
+ printf (" Raw output wait:%-8lu\n", sc->txRawWait);
+}
+
+
+/*
+ * Driver ioctl handler
+ */
+static int
+mcf5272_enet_ioctl (struct ifnet *ifp, int command, caddr_t data)
+{
+ struct mcf5272_enet_struct *sc = ifp->if_softc;
+ int error = 0;
+
+ switch (command) {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ ether_ioctl (ifp, command, data);
+ break;
+
+ case SIOCSIFFLAGS:
+ switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
+ case IFF_RUNNING:
+ mcf5272_enet_stop (sc);
+ break;
+
+ case IFF_UP:
+ mcf5272_enet_init (sc);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ mcf5272_enet_stop (sc);
+ mcf5272_enet_init (sc);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ enet_stats (sc);
+ break;
+
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+
+int
+rtems_enet_driver_attach (struct rtems_bsdnet_ifconfig *config)
+{
+ struct mcf5272_enet_struct *sc;
+ struct ifnet *ifp;
+ int mtu;
+ int unitNumber;
+ char *unitName;
+
+ /*
+ * Parse driver name
+ */
+ unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName);
+ if (unitNumber < 0){
+ return 0;
+ }
+
+ /*
+ * Is driver free?
+ */
+ if ((unitNumber < 0) || (unitNumber > NIFACES)) {
+ printf ("Bad unit number: %d.\n", unitNumber);
+ return 0;
+ }
+
+ sc = &enet_driver[unitNumber];
+ ifp = &sc->arpcom.ac_if;
+ if (ifp->if_softc != NULL) {
+ printf ("Driver already in use.\n");
+ return 0;
+ }
+
+ /*
+ * Process options
+ */
+
+ sc->arpcom.ac_enaddr[0] = (g_enet_regs->malr >> 24) & 0xff;
+ sc->arpcom.ac_enaddr[1] = (g_enet_regs->malr >> 16) & 0xff;
+ sc->arpcom.ac_enaddr[2] = (g_enet_regs->malr >> 8) & 0xff;
+ sc->arpcom.ac_enaddr[3] = (g_enet_regs->malr >> 0) & 0xff;
+ sc->arpcom.ac_enaddr[4] = (g_enet_regs->maur >> 24) & 0xff;
+ sc->arpcom.ac_enaddr[5] = (g_enet_regs->maur >> 16) & 0xff;
+
+ if (config->mtu) {
+ mtu = config->mtu;
+ } else {
+ mtu = ETHERMTU;
+ }
+
+ if (config->rbuf_count) {
+ sc->rxBdCount = config->rbuf_count;
+ } else {
+ sc->rxBdCount = RX_BUF_COUNT;
+ }
+ if (config->xbuf_count) {
+ sc->txBdCount = config->xbuf_count;
+ } else {
+ sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
+ }
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+ /*
+ * Set up network interface values
+ */
+ ifp->if_softc = sc;
+ ifp->if_unit = unitNumber;
+ ifp->if_name = unitName;
+ ifp->if_mtu = mtu;
+ ifp->if_init = mcf5272_enet_init;
+ ifp->if_ioctl = mcf5272_enet_ioctl;
+ ifp->if_start = mcf5272_enet_start;
+ ifp->if_output = ether_output;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+ if (ifp->if_snd.ifq_maxlen == 0) {
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+ }
+
+ /*
+ * Attach the interface
+ */
+ if_attach (ifp);
+ cp;
+ ether_ifattach (ifp);
+ cp;
+ return 1;
+};
+
+
diff --git a/bsps/m68k/gen68360/net/network.c b/bsps/m68k/gen68360/net/network.c
new file mode 100644
index 0000000000..0a038d3348
--- /dev/null
+++ b/bsps/m68k/gen68360/net/network.c
@@ -0,0 +1,1062 @@
+/*
+ * RTEMS driver for M68360 SCC1 Ethernet
+ *
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ */
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+
+#include <bsp.h>
+#include <rtems/m68k/m68360.h>
+#include <stdio.h>
+#include <errno.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+/*
+ * Number of SCCs supported by this driver
+ */
+#define NSCCDRIVER 1
+
+/*
+ * Default number of buffer descriptors set aside for this driver.
+ * The number of transmit buffer descriptors has to be quite large
+ * since a single frame often uses four or more buffer descriptors.
+ */
+#define RX_BUF_COUNT 15
+#define TX_BUF_COUNT 4
+#define TX_BD_PER_BUF 4
+
+/*
+ * RTEMS event used by interrupt handler to signal driver tasks.
+ * This must not be any of the events used by the network task synchronization.
+ */
+#define INTERRUPT_EVENT RTEMS_EVENT_1
+
+/*
+ * RTEMS event used to start transmit daemon.
+ * This must not be the same as INTERRUPT_EVENT.
+ */
+#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+
+/*
+ * Receive buffer size -- Allow for a full ethernet packet including CRC
+ */
+#define RBUF_SIZE 1520
+
+#if (MCLBYTES < RBUF_SIZE)
+# error "Driver must have MCLBYTES > RBUF_SIZE"
+#endif
+
+/*
+ * Per-device data
+ */
+struct scc_softc {
+ struct arpcom arpcom;
+ struct mbuf **rxMbuf;
+ struct mbuf **txMbuf;
+ int acceptBroadcast;
+ int rxBdCount;
+ int txBdCount;
+ int txBdHead;
+ int txBdTail;
+ int txBdActiveCount;
+ m360BufferDescriptor_t *rxBdBase;
+ m360BufferDescriptor_t *txBdBase;
+ rtems_id rxDaemonTid;
+ rtems_id txDaemonTid;
+
+ /*
+ * Statistics
+ */
+ unsigned long rxInterrupts;
+ unsigned long rxNotFirst;
+ unsigned long rxNotLast;
+ unsigned long rxGiant;
+ unsigned long rxNonOctet;
+ unsigned long rxRunt;
+ unsigned long rxBadCRC;
+ unsigned long rxOverrun;
+ unsigned long rxCollision;
+
+ unsigned long txInterrupts;
+ unsigned long txDeferred;
+ unsigned long txHeartbeat;
+ unsigned long txLateCollision;
+ unsigned long txRetryLimit;
+ unsigned long txUnderrun;
+ unsigned long txLostCarrier;
+ unsigned long txRawWait;
+ unsigned long txCoalesced;
+ unsigned long txCoalesceFailed;
+ unsigned long txRetry;
+};
+static struct scc_softc scc_softc[NSCCDRIVER];
+
+extern void *_RomBase; /* From linkcmds */
+
+/*
+ * SCC1 interrupt handler
+ */
+static rtems_isr
+m360Enet_interrupt_handler (rtems_vector_number v)
+{
+ /*
+ * Frame received?
+ */
+ if ((m360.scc1.sccm & 0x8) && (m360.scc1.scce & 0x8)) {
+ m360.scc1.scce = 0x8;
+ m360.scc1.sccm &= ~0x8;
+ scc_softc[0].rxInterrupts++;
+ rtems_bsdnet_event_send (scc_softc[0].rxDaemonTid, INTERRUPT_EVENT);
+ }
+
+ /*
+ * Buffer transmitted or transmitter error?
+ */
+ if ((m360.scc1.sccm & 0x12) && (m360.scc1.scce & 0x12)) {
+ m360.scc1.scce = 0x12;
+ m360.scc1.sccm &= ~0x12;
+ scc_softc[0].txInterrupts++;
+ rtems_bsdnet_event_send (scc_softc[0].txDaemonTid, INTERRUPT_EVENT);
+ }
+ m360.cisr = 1UL << 30; /* Clear SCC1 interrupt-in-service bit */
+}
+
+/*
+ * Initialize the ethernet hardware
+ */
+static void
+m360Enet_initialize_hardware (struct scc_softc *sc)
+{
+ int i;
+ unsigned char *hwaddr;
+ rtems_status_code status;
+ rtems_isr_entry old_handler;
+
+ /*
+ * Configure port A CLK1, CLK2, TXD1 and RXD1 pins
+ */
+ m360.papar |= 0x303;
+ m360.padir &= ~0x303;
+ m360.paodr &= ~0x303;
+
+ /*
+ * Configure port C CTS1* and CD1* pins
+ */
+ m360.pcpar &= ~0x30;
+ m360.pcdir &= ~0x30;
+ m360.pcso |= 0x30;
+
+ /*
+ * Connect CLK1 and CLK2 to SCC1
+ */
+ m360.sicr &= ~0xFF;
+ m360.sicr |= (5 << 3) | 4;
+
+ /*
+ * Allocate mbuf pointers
+ */
+ sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
+ sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
+ if (!sc->rxMbuf || !sc->txMbuf)
+ rtems_panic ("No memory for mbuf pointers");
+
+ /*
+ * Set receiver and transmitter buffer descriptor bases
+ */
+ sc->rxBdBase = M360AllocateBufferDescriptors(sc->rxBdCount);
+ sc->txBdBase = M360AllocateBufferDescriptors(sc->txBdCount);
+ m360.scc1p.rbase = (char *)sc->rxBdBase - (char *)&m360;
+ m360.scc1p.tbase = (char *)sc->txBdBase - (char *)&m360;
+
+ /*
+ * Send "Init parameters" command
+ */
+ M360ExecuteRISC (M360_CR_OP_INIT_RX_TX | M360_CR_CHAN_SCC1);
+
+ /*
+ * Set receive and transmit function codes
+ */
+ m360.scc1p.rfcr = M360_RFCR_MOT | M360_RFCR_DMA_SPACE;
+ m360.scc1p.tfcr = M360_TFCR_MOT | M360_TFCR_DMA_SPACE;
+
+ /*
+ * Set maximum receive buffer length
+ */
+ m360.scc1p.mrblr = RBUF_SIZE;
+
+ /*
+ * Set CRC parameters
+ */
+ m360.scc1p.un.ethernet.c_pres = 0xFFFFFFFF;
+ m360.scc1p.un.ethernet.c_mask = 0xDEBB20E3;
+
+ /*
+ * Clear diagnostic counters
+ */
+ m360.scc1p.un.ethernet.crcec = 0;
+ m360.scc1p.un.ethernet.alec = 0;
+ m360.scc1p.un.ethernet.disfc = 0;
+
+ /*
+ * Set pad value
+ */
+ m360.scc1p.un.ethernet.pads = 0x8888;
+
+ /*
+ * Set retry limit
+ */
+ m360.scc1p.un.ethernet.ret_lim = 15;
+
+ /*
+ * Set maximum and minimum frame length
+ */
+ m360.scc1p.un.ethernet.mflr = 1518;
+ m360.scc1p.un.ethernet.minflr = 64;
+ m360.scc1p.un.ethernet.maxd1 = RBUF_SIZE;
+ m360.scc1p.un.ethernet.maxd2 = RBUF_SIZE;
+
+ /*
+ * Clear group address hash table
+ */
+ m360.scc1p.un.ethernet.gaddr1 = 0;
+ m360.scc1p.un.ethernet.gaddr2 = 0;
+ m360.scc1p.un.ethernet.gaddr3 = 0;
+ m360.scc1p.un.ethernet.gaddr4 = 0;
+
+ /*
+ * Set our physical address
+ */
+ hwaddr = sc->arpcom.ac_enaddr;
+ m360.scc1p.un.ethernet.paddr_h = (hwaddr[5] << 8) | hwaddr[4];
+ m360.scc1p.un.ethernet.paddr_m = (hwaddr[3] << 8) | hwaddr[2];
+ m360.scc1p.un.ethernet.paddr_l = (hwaddr[1] << 8) | hwaddr[0];
+
+ /*
+ * Aggressive retry
+ */
+ m360.scc1p.un.ethernet.p_per = 0;
+
+ /*
+ * Clear individual address hash table
+ */
+ m360.scc1p.un.ethernet.iaddr1 = 0;
+ m360.scc1p.un.ethernet.iaddr2 = 0;
+ m360.scc1p.un.ethernet.iaddr3 = 0;
+ m360.scc1p.un.ethernet.iaddr4 = 0;
+
+ /*
+ * Set up receive buffer descriptors
+ */
+ for (i = 0 ; i < sc->rxBdCount ; i++)
+ (sc->rxBdBase + i)->status = 0;
+
+ /*
+ * Set up transmit buffer descriptors
+ */
+ for (i = 0 ; i < sc->txBdCount ; i++) {
+ (sc->txBdBase + i)->status = 0;
+ sc->txMbuf[i] = NULL;
+ }
+ sc->txBdHead = sc->txBdTail = 0;
+ sc->txBdActiveCount = 0;
+
+ /*
+ * Clear any outstanding events
+ */
+ m360.scc1.scce = 0xFFFF;
+
+ /*
+ * Set up interrupts
+ */
+ status = rtems_interrupt_catch (m360Enet_interrupt_handler,
+ (m360.cicr & 0xE0) | 0x1E,
+ &old_handler);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't attach M360 SCC1 interrupt handler: %s\n",
+ rtems_status_text (status));
+ m360.scc1.sccm = 0; /* No interrupts unmasked till necessary */
+ m360.cimr |= (1UL << 30); /* Enable SCC1 interrupt */
+
+ /*
+ * Set up General SCC Mode Register
+ * Ethernet configuration
+ */
+ m360.scc1.gsmr_h = 0x0;
+ m360.scc1.gsmr_l = 0x1088000c;
+
+ /*
+ * Set up data synchronization register
+ * Ethernet synchronization pattern
+ */
+ m360.scc1.dsr = 0xd555;
+
+ /*
+ * Set up protocol-specific mode register
+ * Heartbeat check
+ * No force collision
+ * Discard short frames
+ * Individual address mode
+ * Ethernet CRC
+ * Not promisuous
+ * Ignore/accept broadcast packets as specified
+ * Normal backoff timer
+ * No loopback
+ * No input sample at end of frame
+ * 64-byte limit for late collision
+ * Wait 22 bits before looking for start of frame delimiter
+ * Disable full-duplex operation
+ */
+ m360.scc1.psmr = 0x880A | (sc->acceptBroadcast ? 0 : 0x100);
+
+ /*
+ * Enable the TENA (RTS1*) pin
+ */
+#if (defined (M68360_ATLAS_HSB))
+ m360.pbpar |= 0x1000;
+ m360.pbdir |= 0x1000;
+#else
+ m360.pcpar |= 0x1;
+ m360.pcdir &= ~0x1;
+#endif
+}
+
+/*
+ * Soak up buffer descriptors that have been sent
+ * Note that a buffer descriptor can't be retired as soon as it becomes
+ * ready. The MC68360 Errata (May 96) says that, "If an Ethernet frame is
+ * made up of multiple buffers, the user should not reuse the first buffer
+ * descriptor until the last buffer descriptor of the frame has had its
+ * ready bit cleared by the CPM".
+ */
+static void
+m360Enet_retire_tx_bd (struct scc_softc *sc)
+{
+ uint16_t status;
+ int i;
+ int nRetired;
+ struct mbuf *m, *n;
+ int retries = 0;
+ int saveStatus = 0;
+
+ i = sc->txBdTail;
+ nRetired = 0;
+ while ((sc->txBdActiveCount != 0)
+ && (((status = (sc->txBdBase + i)->status) & M360_BD_READY) == 0)) {
+ /*
+ * Check for errors which stop the transmitter.
+ */
+ if (status & (M360_BD_LATE_COLLISION |
+ M360_BD_RETRY_LIMIT |
+ M360_BD_UNDERRUN)) {
+ int j;
+
+ if (status & M360_BD_LATE_COLLISION)
+ sc->txLateCollision++;
+ if (status & M360_BD_RETRY_LIMIT)
+ sc->txRetryLimit++;
+ if (status & M360_BD_UNDERRUN)
+ sc->txUnderrun++;
+
+ /*
+ * Reenable buffer descriptors
+ */
+ j = sc->txBdTail;
+ for (;;) {
+ status = (sc->txBdBase + j)->status;
+ if (status & M360_BD_READY)
+ break;
+ (sc->txBdBase + j)->status = M360_BD_READY |
+ (status & (M360_BD_PAD |
+ M360_BD_WRAP |
+ M360_BD_INTERRUPT |
+ M360_BD_LAST |
+ M360_BD_TX_CRC));
+ if (status & M360_BD_LAST)
+ break;
+ if (++j == sc->txBdCount)
+ j = 0;
+ }
+
+ /*
+ * Move transmitter back to the first
+ * buffer descriptor in the frame.
+ */
+ m360.scc1p._tbptr = m360.scc1p.tbase +
+ sc->txBdTail * sizeof (m360BufferDescriptor_t);
+
+ /*
+ * Restart the transmitter
+ */
+ M360ExecuteRISC (M360_CR_OP_RESTART_TX | M360_CR_CHAN_SCC1);
+ continue;
+ }
+ saveStatus |= status;
+ retries += (status >> 2) & 0xF;
+ nRetired++;
+ if (status & M360_BD_LAST) {
+ /*
+ * A full frame has been transmitted.
+ * Free all the associated buffer descriptors.
+ */
+ if (saveStatus & M360_BD_DEFER)
+ sc->txDeferred++;
+ if (saveStatus & M360_BD_HEARTBEAT)
+ sc->txHeartbeat++;
+ if (saveStatus & M360_BD_CARRIER_LOST)
+ sc->txLostCarrier++;
+ saveStatus = 0;
+ sc->txRetry += retries;
+ retries = 0;
+ sc->txBdActiveCount -= nRetired;
+ while (nRetired) {
+ nRetired--;
+ m = sc->txMbuf[sc->txBdTail];
+ MFREE (m, n);
+ if (++sc->txBdTail == sc->txBdCount)
+ sc->txBdTail = 0;
+ }
+ }
+ if (++i == sc->txBdCount)
+ i = 0;
+ }
+}
+
+/*
+ * SCC reader task
+ */
+static void
+scc_rxDaemon (void *arg)
+{
+ struct scc_softc *sc = (struct scc_softc *)arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+ uint16_t status;
+ volatile m360BufferDescriptor_t *rxBd;
+ int rxBdIndex;
+
+ /*
+ * Allocate space for incoming packets and start reception
+ */
+ for (rxBdIndex = 0 ; ;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+ MGETHDR (m, M_WAIT, MT_DATA);
+ MCLGET (m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->buffer = mtod (m, void *);
+ if (++rxBdIndex == sc->rxBdCount) {
+ rxBd->status = M360_BD_EMPTY | M360_BD_INTERRUPT | M360_BD_WRAP;
+ break;
+ }
+ rxBd->status = M360_BD_EMPTY | M360_BD_INTERRUPT;
+ }
+
+ /*
+ * Input packet handling loop
+ */
+ rxBdIndex = 0;
+ for (;;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+
+ /*
+ * Wait for packet if there's not one ready
+ */
+ if ((status = rxBd->status) & M360_BD_EMPTY) {
+ /*
+ * Clear old events
+ */
+ m360.scc1.scce = 0x8;
+
+ /*
+ * Wait for packet
+ * Note that the buffer descriptor is checked
+ * *before* the event wait -- this catches the
+ * possibility that a packet arrived between the
+ * `if' above, and the clearing of the event register.
+ */
+ while ((status = rxBd->status) & M360_BD_EMPTY) {
+ rtems_interrupt_level level;
+ rtems_event_set events;
+
+ /*
+ * Unmask RXF (Full frame received) event
+ */
+ rtems_interrupt_disable (level);
+ m360.scc1.sccm |= 0x8;
+ rtems_interrupt_enable (level);
+
+ rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ }
+ }
+
+ /*
+ * Check that packet is valid
+ */
+ if ((status & (M360_BD_LAST |
+ M360_BD_FIRST_IN_FRAME |
+ M360_BD_LONG |
+ M360_BD_NONALIGNED |
+ M360_BD_SHORT |
+ M360_BD_CRC_ERROR |
+ M360_BD_OVERRUN |
+ M360_BD_COLLISION)) ==
+ (M360_BD_LAST |
+ M360_BD_FIRST_IN_FRAME)) {
+ /*
+ * Pass the packet up the chain.
+ * FIXME: Packet filtering hook could be done here.
+ */
+ struct ether_header *eh;
+
+ m = sc->rxMbuf[rxBdIndex];
+ m->m_len = m->m_pkthdr.len = rxBd->length -
+ sizeof(uint32_t) -
+ sizeof(struct ether_header);
+ eh = mtod (m, struct ether_header *);
+ m->m_data += sizeof(struct ether_header);
+ ether_input (ifp, eh, m);
+
+ /*
+ * Allocate a new mbuf
+ */
+ MGETHDR (m, M_WAIT, MT_DATA);
+ MCLGET (m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->buffer = mtod (m, void *);
+ }
+ else {
+ /*
+ * Something went wrong with the reception
+ */
+ if (!(status & M360_BD_LAST))
+ sc->rxNotLast++;
+ if (!(status & M360_BD_FIRST_IN_FRAME))
+ sc->rxNotFirst++;
+ if (status & M360_BD_LONG)
+ sc->rxGiant++;
+ if (status & M360_BD_NONALIGNED)
+ sc->rxNonOctet++;
+ if (status & M360_BD_SHORT)
+ sc->rxRunt++;
+ if (status & M360_BD_CRC_ERROR)
+ sc->rxBadCRC++;
+ if (status & M360_BD_OVERRUN)
+ sc->rxOverrun++;
+ if (status & M360_BD_COLLISION)
+ sc->rxCollision++;
+ }
+
+ /*
+ * Reenable the buffer descriptor
+ */
+ rxBd->status = (status & (M360_BD_WRAP | M360_BD_INTERRUPT)) | M360_BD_EMPTY;
+
+ /*
+ * Move to next buffer descriptor
+ */
+ if (++rxBdIndex == sc->rxBdCount)
+ rxBdIndex = 0;
+ }
+}
+
+static void
+sendpacket (struct ifnet *ifp, struct mbuf *m)
+{
+ struct scc_softc *sc = ifp->if_softc;
+ volatile m360BufferDescriptor_t *firstTxBd, *txBd;
+ struct mbuf *l = NULL;
+ uint16_t status;
+ int nAdded;
+
+ /*
+ * Free up buffer descriptors
+ */
+ m360Enet_retire_tx_bd (sc);
+
+ /*
+ * Set up the transmit buffer descriptors.
+ * No need to pad out short packets since the
+ * hardware takes care of that automatically.
+ * No need to copy the packet to a contiguous buffer
+ * since the hardware is capable of scatter/gather DMA.
+ */
+ status = 0;
+ nAdded = 0;
+ txBd = firstTxBd = sc->txBdBase + sc->txBdHead;
+ while (m) {
+ /*
+ * There are more mbufs in the packet than there
+ * are transmit buffer descriptors.
+ * Coalesce into a single buffer.
+ */
+ if (nAdded == sc->txBdCount) {
+ struct mbuf *nm;
+ int j;
+ char *dest;
+
+ /*
+ * Get the pointer to the first mbuf of the packet
+ */
+ if (sc->txBdTail != sc->txBdHead)
+ rtems_panic ("sendpacket coalesce");
+ m = sc->txMbuf[sc->txBdTail];
+
+ /*
+ * Rescind the buffer descriptor READY bits
+ */
+ for (j = 0 ; j < sc->txBdCount ; j++)
+ (sc->txBdBase + j)->status = 0;
+
+ /*
+ * Allocate an mbuf cluster
+ * Toss the packet if allocation fails
+ */
+ MGETHDR (nm, M_DONTWAIT, MT_DATA);
+ if (nm == NULL) {
+ sc->txCoalesceFailed++;
+ m_freem (m);
+ return;
+ }
+ MCLGET (nm, M_DONTWAIT);
+ if (nm->m_ext.ext_buf == NULL) {
+ sc->txCoalesceFailed++;
+ m_freem (m);
+ m_free (nm);
+ return;
+ }
+ nm->m_pkthdr = m->m_pkthdr;
+ nm->m_len = nm->m_pkthdr.len;
+
+ /*
+ * Copy data from packet chain to mbuf cluster
+ */
+ sc->txCoalesced++;
+ dest = nm->m_ext.ext_buf;
+ while (m) {
+ struct mbuf *n;
+
+ if (m->m_len) {
+ memcpy (dest, mtod(m, caddr_t), m->m_len);
+ dest += m->m_len;
+ }
+ MFREE (m, n);
+ m = n;
+ }
+
+ /*
+ * Redo the send with the new mbuf cluster
+ */
+ m = nm;
+ nAdded = 0;
+ status = 0;
+ continue;
+ }
+
+ /*
+ * Wait for buffer descriptor to become available.
+ */
+ if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ /*
+ * Clear old events
+ */
+ m360.scc1.scce = 0x12;
+
+ /*
+ * Wait for buffer descriptor to become available.
+ * Note that the buffer descriptors are checked
+ * *before* entering the wait loop -- this catches
+ * the possibility that a buffer descriptor became
+ * available between the `if' above, and the clearing
+ * of the event register.
+ * This is to catch the case where the transmitter
+ * stops in the middle of a frame -- and only the
+ * last buffer descriptor in a frame can generate
+ * an interrupt.
+ */
+ m360Enet_retire_tx_bd (sc);
+ while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ rtems_interrupt_level level;
+ rtems_event_set events;
+
+ /*
+ * Unmask TXB (buffer transmitted) and
+ * TXE (transmitter error) events.
+ */
+ rtems_interrupt_disable (level);
+ m360.scc1.sccm |= 0x12;
+ rtems_interrupt_enable (level);
+ rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ m360Enet_retire_tx_bd (sc);
+ }
+ }
+
+ /*
+ * The IP fragmentation routine in ip_output
+ * can produce packet fragments with zero length.
+ */
+ if (m->m_len) {
+ /*
+ * Fill in the buffer descriptor.
+ * Don't set the READY flag in the first buffer
+ * descriptor till the whole packet has been readied.
+ */
+ txBd = sc->txBdBase + sc->txBdHead;
+ txBd->buffer = mtod (m, void *);
+ txBd->length = m->m_len;
+ sc->txMbuf[sc->txBdHead] = m;
+ status = nAdded ? M360_BD_READY : 0;
+ if (++sc->txBdHead == sc->txBdCount) {
+ status |= M360_BD_WRAP;
+ sc->txBdHead = 0;
+ }
+ txBd->status = status;
+ l = m;
+ m = m->m_next;
+ nAdded++;
+ }
+ else {
+ /*
+ * Just toss empty mbufs
+ */
+ struct mbuf *n;
+ MFREE (m, n);
+ m = n;
+ if (l != NULL)
+ l->m_next = m;
+ }
+ }
+ if (nAdded) {
+ /*
+ * Send the packet
+ */
+ txBd->status = status | M360_BD_PAD | M360_BD_LAST | M360_BD_TX_CRC | M360_BD_INTERRUPT;
+ firstTxBd->status |= M360_BD_READY;
+ sc->txBdActiveCount += nAdded;
+ }
+}
+
+/*
+ * Driver transmit daemon
+ */
+void
+scc_txDaemon (void *arg)
+{
+ struct scc_softc *sc = (struct scc_softc *)arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_event_set events;
+
+ for (;;) {
+ /*
+ * Wait for packet
+ */
+ rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
+
+ /*
+ * Send packets till queue is empty
+ */
+ for (;;) {
+ /*
+ * Get the next mbuf chain to transmit.
+ */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (!m)
+ break;
+ sendpacket (ifp, m);
+ }
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+}
+
+/*
+ * Send packet (caller provides header).
+ */
+static void
+scc_start (struct ifnet *ifp)
+{
+ struct scc_softc *sc = ifp->if_softc;
+
+ rtems_bsdnet_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
+ ifp->if_flags |= IFF_OACTIVE;
+}
+
+/*
+ * Initialize and start the device
+ */
+static void
+scc_init (void *arg)
+{
+ struct scc_softc *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ if (sc->txDaemonTid == 0) {
+
+ /*
+ * Set up SCC hardware
+ */
+ m360Enet_initialize_hardware (sc);
+
+ /*
+ * Start driver tasks
+ */
+ sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc);
+ sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc);
+
+ }
+
+ /*
+ * Set flags appropriately
+ */
+ if (ifp->if_flags & IFF_PROMISC)
+ m360.scc1.psmr |= 0x200;
+ else
+ m360.scc1.psmr &= ~0x200;
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+
+ /*
+ * Enable receiver and transmitter
+ */
+ m360.scc1.gsmr_l |= 0x30;
+}
+
+/*
+ * Stop the device
+ */
+static void
+scc_stop (struct scc_softc *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ /*
+ * Shut down receiver and transmitter
+ */
+ m360.scc1.gsmr_l &= ~0x30;
+}
+
+/*
+ * Show interface statistics
+ */
+static void
+scc_stats (struct scc_softc *sc)
+{
+ printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
+ printf (" Not First:%-8lu", sc->rxNotFirst);
+ printf (" Not Last:%-8lu\n", sc->rxNotLast);
+ printf (" Giant:%-8lu", sc->rxGiant);
+ printf (" Runt:%-8lu", sc->rxRunt);
+ printf (" Non-octet:%-8lu\n", sc->rxNonOctet);
+ printf (" Bad CRC:%-8lu", sc->rxBadCRC);
+ printf (" Overrun:%-8lu", sc->rxOverrun);
+ printf (" Collision:%-8lu\n", sc->rxCollision);
+ printf (" Discarded:%-8lu\n", (unsigned long)m360.scc1p.un.ethernet.disfc);
+
+ printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
+ printf (" Deferred:%-8lu", sc->txDeferred);
+ printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
+ printf (" No Carrier:%-8lu", sc->txLostCarrier);
+ printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
+ printf (" Late Collision:%-8lu\n", sc->txLateCollision);
+ printf (" Underrun:%-8lu", sc->txUnderrun);
+ printf (" Raw output wait:%-8lu", sc->txRawWait);
+ printf (" Coalesced:%-8lu\n", sc->txCoalesced);
+ printf (" Coalesce failed:%-8lu", sc->txCoalesceFailed);
+ printf (" Retries:%-8lu\n", sc->txRetry);
+}
+
+/*
+ * Driver ioctl handler
+ */
+static int
+scc_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
+{
+ struct scc_softc *sc = ifp->if_softc;
+ int error = 0;
+
+ switch (command) {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ ether_ioctl (ifp, command, data);
+ break;
+
+ case SIOCSIFFLAGS:
+ switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
+ case IFF_RUNNING:
+ scc_stop (sc);
+ break;
+
+ case IFF_UP:
+ scc_init (sc);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ scc_stop (sc);
+ scc_init (sc);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ scc_stats (sc);
+ break;
+
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+/*
+ * Attach an SCC driver to the system
+ */
+int
+rtems_scc1_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching)
+{
+ struct scc_softc *sc;
+ struct ifnet *ifp;
+ int mtu;
+ int unitNumber;
+ char *unitName;
+
+ /*
+ * Make sure we're really being attached
+ */
+ if (!attaching) {
+ printf ("SCC1 driver can not be detached.\n");
+ return 0;
+ }
+
+ /*
+ * Parse driver name
+ */
+ if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
+ return 0;
+
+ /*
+ * Is driver free?
+ */
+ if ((unitNumber <= 0) || (unitNumber > NSCCDRIVER)) {
+ printf ("Bad SCC unit number.\n");
+ return 0;
+ }
+ sc = &scc_softc[unitNumber - 1];
+ ifp = &sc->arpcom.ac_if;
+ if (ifp->if_softc != NULL) {
+ printf ("Driver already in use.\n");
+ return 0;
+ }
+
+ /*
+ * Process options
+ */
+ if (config->hardware_address) {
+ memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+ }
+ else {
+ /*
+ * The first 4 bytes of the bootstrap prom
+ * contain the value loaded into the stack
+ * pointer as part of the CPU32's hardware
+ * reset exception handler. The following
+ * 4 bytes contain the value loaded into the
+ * program counter. The boards' Ethernet
+ * address is stored in the six bytes
+ * immediately preceding this initial
+ * program counter value.
+ *
+ * See start360/start360.s.
+ */
+ const unsigned long *ExceptionVectors;
+ const unsigned char *entryPoint;
+
+ /*
+ * Sanity check -- assume entry point must be
+ * within 1 MByte of beginning of boot ROM.
+ */
+ ExceptionVectors = (const unsigned long *)&_RomBase;
+ entryPoint = (const unsigned char *)ExceptionVectors[1];
+ if (((unsigned long)entryPoint - (unsigned long)ExceptionVectors)
+ >= (1 * 1024 * 1024)) {
+ printf ("Warning -- Ethernet address can not be found in bootstrap PROM.\n");
+ sc->arpcom.ac_enaddr[0] = 0x08;
+ sc->arpcom.ac_enaddr[1] = 0xF3;
+ sc->arpcom.ac_enaddr[2] = 0x3E;
+ sc->arpcom.ac_enaddr[3] = 0xC2;
+ sc->arpcom.ac_enaddr[4] = 0x7E;
+ sc->arpcom.ac_enaddr[5] = 0x38;
+ }
+ else {
+ memcpy (sc->arpcom.ac_enaddr, entryPoint - ETHER_ADDR_LEN, ETHER_ADDR_LEN);
+ }
+ }
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+ if (config->rbuf_count)
+ sc->rxBdCount = config->rbuf_count;
+ else
+ sc->rxBdCount = RX_BUF_COUNT;
+ if (config->xbuf_count)
+ sc->txBdCount = config->xbuf_count;
+ else
+ sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+ /*
+ * Set up network interface values
+ */
+ ifp->if_softc = sc;
+ ifp->if_unit = unitNumber;
+ ifp->if_name = unitName;
+ ifp->if_mtu = mtu;
+ ifp->if_init = scc_init;
+ ifp->if_ioctl = scc_ioctl;
+ ifp->if_start = scc_start;
+ ifp->if_output = ether_output;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ /*
+ * Attach the interface
+ */
+ if_attach (ifp);
+ ether_ifattach (ifp);
+ return 1;
+}
diff --git a/bsps/m68k/genmcf548x/net/network.c b/bsps/m68k/genmcf548x/net/network.c
new file mode 100644
index 0000000000..13cb5fbdce
--- /dev/null
+++ b/bsps/m68k/genmcf548x/net/network.c
@@ -0,0 +1,1696 @@
+/*===============================================================*\
+| Project: RTEMS generic MCF548X BSP |
++-----------------------------------------------------------------+
+| Partially based on the code references which are named below. |
+| Adaptions, modifications, enhancements and any recent parts of |
+| the code are: |
+| Copyright (c) 2009 |
+| Embedded Brains GmbH |
+| Obere Lagerstr. 30 |
+| D-82178 Puchheim |
+| Germany |
+| rtems@embedded-brains.de |
++-----------------------------------------------------------------+
+| The license and distribution terms for this file may be |
+| found in the file LICENSE in this distribution or at |
+| |
+| http://www.rtems.org/license/LICENSE. |
+| |
++-----------------------------------------------------------------+
+| this file contains the networking driver |
+\*===============================================================*/
+/*
+ * RTEMS/TCPIP driver for MCF548X FEC Ethernet
+ *
+ * Modified for Motorola MPC5200 by Thomas Doerfler, <Thomas.Doerfler@imd-systems.de>
+ * COPYRIGHT (c) 2003, IMD
+ *
+ * Modified for Motorola IceCube (mgt5100) by Peter Rasmussen <prasmus@ipr-engineering.de>
+ * COPYRIGHT (c) 2003, IPR Engineering
+ *
+ * Parts of code are also under property of Driver Information Systems and based
+ * on Motorola Proprietary Information.
+ * COPYRIGHT (c) 2002 MOTOROLA INC.
+ *
+ * Modified for Motorola MCF548X by Thomas Doerfler, <Thomas.Doerfler@imd-systems.de>
+ * COPYRIGHT (c) 2009, IMD
+ *
+ */
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <net/if_var.h>
+
+#include <bsp.h>
+#include <bsp/irq-generic.h>
+#include <mcf548x/mcf548x.h>
+#include <rtems/rtems_mii_ioctl.h>
+#include <errno.h>
+
+/* freescale-api-specifics... */
+#include <mcf548x/MCD_dma.h>
+#include <mcf548x/mcdma_glue.h>
+
+/*
+ * Number of interfaces supported by this driver
+ */
+#define NIFACES 2
+
+#define FEC_WATCHDOG_TIMEOUT 5 /* check media every 5 seconds */
+
+#define DMA_BD_RX_NUM 32 /* Number of receive buffer descriptors */
+#define DMA_BD_TX_NUM 32 /* Number of transmit buffer descriptors */
+
+#define FEC_EVENT RTEMS_EVENT_0
+
+/*
+ * internal SRAM
+ * Layout:
+ * - RxBD channel 0
+ * - TxBD channel 0
+ * - RxBD channel 1
+ * - TxBD channel 1
+ * - DMA task memory
+ */
+extern char _SysSramBase[];
+#define SRAM_RXBD_BASE(base,chan) (((MCD_bufDescFec*)(base)) \
+ +((chan) \
+ *(DMA_BD_RX_NUM+DMA_BD_TX_NUM)))
+
+#define SRAM_TXBD_BASE(base,chan) (((MCD_bufDescFec*)(base)) \
+ +((chan) \
+ *(DMA_BD_RX_NUM+DMA_BD_TX_NUM) \
+ +DMA_BD_RX_NUM))
+
+#define SRAM_DMA_BASE(base) ((void *)SRAM_RXBD_BASE(base,NIFACES+1))
+
+
+#undef ETH_DEBUG
+
+/*
+ * Default number of buffer descriptors set aside for this driver.
+ * The number of transmit buffer descriptors has to be quite large
+ * since a single frame often uses four or more buffer descriptors.
+ */
+#define RX_BUF_COUNT DMA_BD_RX_NUM
+#define TX_BUF_COUNT DMA_BD_TX_NUM
+#define TX_BD_PER_BUF 1
+
+#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
+
+#define MCF548X_FEC0_IRQ_VECTOR (39+64)
+#define MCF548X_FEC1_IRQ_VECTOR (38+64)
+
+#define MCF548X_FEC_IRQ_VECTOR(chan) (MCF548X_FEC0_IRQ_VECTOR \
+ +(chan)*(MCF548X_FEC1_IRQ_VECTOR \
+ -MCF548X_FEC0_IRQ_VECTOR))
+
+#define MCF548X_FEC_VECTOR2CHAN(vector) (((int)(vector)-MCF548X_FEC0_IRQ_VECTOR) \
+ /(MCF548X_FEC1_IRQ_VECTOR \
+ -MCF548X_FEC0_IRQ_VECTOR))
+
+#define MCDMA_FEC_RX_CHAN(chan) (0 + NIFACES*(chan))
+#define MCDMA_FEC_TX_CHAN(chan) (1 + NIFACES*(chan))
+
+#define MCF548X_FEC0_RX_INITIATOR (16)
+#define MCF548X_FEC1_RX_INITIATOR (30)
+#define MCF548X_FEC_RX_INITIATOR(chan) (MCF548X_FEC0_RX_INITIATOR \
+ +(chan)*(MCF548X_FEC1_RX_INITIATOR \
+ -MCF548X_FEC0_RX_INITIATOR))
+#define MCF548X_FEC0_TX_INITIATOR (17)
+#define MCF548X_FEC1_TX_INITIATOR (31)
+#define MCF548X_FEC_TX_INITIATOR(chan) (MCF548X_FEC0_TX_INITIATOR \
+ +(chan)*(MCF548X_FEC1_TX_INITIATOR \
+ -MCF548X_FEC0_TX_INITIATOR))
+
+/* BD and parameters are stored in SRAM(refer to sdma.h) */
+#define MCF548X_FEC_BD_BASE ETH_BD_BASE
+
+/* RBD bits definitions */
+#define MCF548X_FEC_RBD_EMPTY 0x8000 /* Buffer is empty */
+#define MCF548X_FEC_RBD_WRAP 0x2000 /* Last BD in ring */
+#define MCF548X_FEC_RBD_INT 0x1000 /* Interrupt */
+#define MCF548X_FEC_RBD_LAST 0x0800 /* Buffer is last in frame(useless) */
+#define MCF548X_FEC_RBD_MISS 0x0100 /* Miss bit for prom mode */
+#define MCF548X_FEC_RBD_BC 0x0080 /* The received frame is broadcast frame */
+#define MCF548X_FEC_RBD_MC 0x0040 /* The received frame is multicast frame */
+#define MCF548X_FEC_RBD_LG 0x0020 /* Frame length violation */
+#define MCF548X_FEC_RBD_NO 0x0010 /* Nonoctet align frame */
+#define MCF548X_FEC_RBD_SH 0x0008 /* Short frame, FEC does not support SH and this bit is always cleared */
+#define MCF548X_FEC_RBD_CR 0x0004 /* CRC error */
+#define MCF548X_FEC_RBD_OV 0x0002 /* Receive FIFO overrun */
+#define MCF548X_FEC_RBD_TR 0x0001 /* The receive frame is truncated */
+#define MCF548X_FEC_RBD_ERR (MCF548X_FEC_RBD_LG | \
+ MCF548X_FEC_RBD_NO | \
+ MCF548X_FEC_RBD_CR | \
+ MCF548X_FEC_RBD_OV | \
+ MCF548X_FEC_RBD_TR)
+
+/* TBD bits definitions */
+#define MCF548X_FEC_TBD_READY 0x8000 /* Buffer is ready */
+#define MCF548X_FEC_TBD_WRAP 0x2000 /* Last BD in ring */
+#define MCF548X_FEC_TBD_INT 0x1000 /* Interrupt */
+#define MCF548X_FEC_TBD_LAST 0x0800 /* Buffer is last in frame */
+#define MCF548X_FEC_TBD_TC 0x0400 /* Transmit the CRC */
+#define MCF548X_FEC_TBD_ABC 0x0200 /* Append bad CRC */
+
+#define FEC_INTR_MASK_USED \
+(MCF548X_FEC_EIMR_LC | MCF548X_FEC_EIMR_RL | \
+ MCF548X_FEC_EIMR_XFUN | MCF548X_FEC_EIMR_XFERR | MCF548X_FEC_EIMR_RFERR)
+
+typedef enum {
+ FEC_STATE_RESTART_0,
+ FEC_STATE_RESTART_1,
+ FEC_STATE_NORMAL,
+} fec_state;
+
+/*
+ * Device data
+ */
+struct mcf548x_enet_struct {
+ struct arpcom arpcom;
+ struct mbuf **rxMbuf;
+ struct mbuf **txMbuf;
+ int chan;
+ fec_state state;
+ int acceptBroadcast;
+ int rxBdCount;
+ int txBdCount;
+ MCD_bufDescFec *rxBd;
+ MCD_bufDescFec *txBd;
+ int rxDmaChan; /* dma task */
+ int txDmaChan; /* dma task */
+ rtems_id rxDaemonTid;
+ rtems_id txDaemonTid;
+
+ /*
+ * MDIO/Phy info
+ */
+ struct rtems_mdio_info mdio_info;
+ int phy_default;
+ int phy_chan; /* which fec channel services this phy access? */
+ int media_state; /* (last detected) state of media */
+
+ unsigned long rxInterrupts;
+ unsigned long rxNotLast;
+ unsigned long rxGiant;
+ unsigned long rxNonOctet;
+ unsigned long rxBadCRC;
+ unsigned long rxFIFOError;
+ unsigned long rxCollision;
+
+ unsigned long txInterrupts;
+ unsigned long txDeferred;
+ unsigned long txLateCollision;
+ unsigned long txUnderrun;
+ unsigned long txFIFOError;
+ unsigned long txMisaligned;
+ unsigned long rxNotFirst;
+ unsigned long txRetryLimit;
+ };
+
+static struct mcf548x_enet_struct enet_driver[NIFACES];
+
+static void mcf548x_fec_restart(struct mcf548x_enet_struct *sc, rtems_id otherDaemon);
+
+static void fec_send_event(rtems_id task)
+{
+ rtems_bsdnet_event_send(task, FEC_EVENT);
+}
+
+static void fec_wait_for_event(void)
+{
+ rtems_event_set out;
+ rtems_bsdnet_event_receive(
+ FEC_EVENT,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT,
+ &out
+ );
+}
+
+static void mcf548x_fec_request_restart(struct mcf548x_enet_struct *sc)
+{
+ sc->state = FEC_STATE_RESTART_0;
+ fec_send_event(sc->txDaemonTid);
+ fec_send_event(sc->rxDaemonTid);
+}
+
+/*
+ * Function: MCF548X_eth_addr_filter_set
+ *
+ * Description: Set individual address filter for unicast address and
+ * set physical address registers.
+ *
+ * Returns: void
+ *
+ * Notes:
+ *
+ */
+static void mcf548x_eth_addr_filter_set(struct mcf548x_enet_struct *sc) {
+ unsigned char *mac;
+ unsigned char currByte; /* byte for which to compute the CRC */
+ int byte; /* loop - counter */
+ int bit; /* loop - counter */
+ unsigned long crc = 0xffffffff; /* initial value */
+ int chan = sc->chan;
+
+ /*
+ * Get the mac address of ethernet controller
+ */
+ mac = (unsigned char *)(&sc->arpcom.ac_enaddr);
+
+ /*
+ * The algorithm used is the following:
+ * we loop on each of the six bytes of the provided address,
+ * and we compute the CRC by left-shifting the previous
+ * value by one position, so that each bit in the current
+ * byte of the address may contribute the calculation. If
+ * the latter and the MSB in the CRC are different, then
+ * the CRC value so computed is also ex-ored with the
+ * "polynomium generator". The current byte of the address
+ * is also shifted right by one bit at each iteration.
+ * This is because the CRC generatore in hardware is implemented
+ * as a shift-register with as many ex-ores as the radixes
+ * in the polynomium. This suggests that we represent the
+ * polynomiumm itsc as a 32-bit constant.
+ */
+ for(byte = 0; byte < 6; byte++)
+ {
+
+ currByte = mac[byte];
+
+ for(bit = 0; bit < 8; bit++)
+ {
+
+ if((currByte & 0x01) ^ (crc & 0x01))
+ {
+
+ crc >>= 1;
+ crc = crc ^ 0xedb88320;
+
+ }
+ else
+ {
+
+ crc >>= 1;
+
+ }
+
+ currByte >>= 1;
+
+ }
+
+ }
+
+ crc = crc >> 26;
+
+ /*
+ * Set individual hash table register
+ */
+ if(crc >= 32)
+ {
+
+ MCF548X_FEC_IAUR(chan) = (1 << (crc - 32));
+ MCF548X_FEC_IALR(chan) = 0;
+
+ }
+ else
+ {
+
+ MCF548X_FEC_IAUR(chan) = 0;
+ MCF548X_FEC_IALR(chan) = (1 << crc);
+
+ }
+
+ /*
+ * Set physical address
+ */
+ MCF548X_FEC_PALR(chan) = ((mac[0] << 24) +
+ (mac[1] << 16) +
+ (mac[2] << 8) +
+ mac[3]);
+ MCF548X_FEC_PAUR(chan) = ((mac[4] << 24)
+ + (mac[5] << 16)) + 0x8808;
+
+ }
+
+
+/*
+ * Function: mcf548x_eth_mii_read
+ *
+ * Description: Read a media independent interface (MII) register on an
+ * 18-wire ethernet tranceiver (PHY). Please see your PHY
+ * documentation for the register map.
+ *
+ * Returns: 0 if ok
+ *
+ * Notes:
+ *
+ */
+int mcf548x_eth_mii_read(
+ int phyAddr, /* PHY number to access or -1 */
+ void *uarg, /* unit argument */
+ unsigned regAddr, /* register address */
+ uint32_t *retVal) /* ptr to read buffer */
+{
+ struct mcf548x_enet_struct *sc = uarg;
+ int timeout = 0xffff;
+ int chan = sc->phy_chan;
+
+ /*
+ * reading from any PHY's register is done by properly
+ * programming the FEC's MII data register.
+ */
+ MCF548X_FEC_MMFR(chan) = (MCF548X_FEC_MMFR_ST_01 |
+ MCF548X_FEC_MMFR_OP_READ |
+ MCF548X_FEC_MMFR_TA_10 |
+ MCF548X_FEC_MMFR_PA(phyAddr) |
+ MCF548X_FEC_MMFR_RA(regAddr));
+
+ /*
+ * wait for the related interrupt
+ */
+ while ((timeout--) && (!(MCF548X_FEC_EIR(chan) & MCF548X_FEC_EIR_MII)));
+
+ if(timeout == 0) {
+
+#ifdef ETH_DEBUG
+ iprintf ("Read MDIO failed..." "\r\n");
+#endif
+
+ return 1;
+
+ }
+
+ /*
+ * clear mii interrupt bit
+ */
+ MCF548X_FEC_EIR(chan) = MCF548X_FEC_EIR_MII;
+
+ /*
+ * it's now safe to read the PHY's register
+ */
+ *retVal = (unsigned short) MCF548X_FEC_MMFR(chan);
+
+ return 0;
+
+}
+
+/*
+ * Function: mcf548x_eth_mii_write
+ *
+ * Description: Write a media independent interface (MII) register on an
+ * 18-wire ethernet tranceiver (PHY). Please see your PHY
+ * documentation for the register map.
+ *
+ * Returns: Success (boolean)
+ *
+ * Notes:
+ *
+ */
+static int mcf548x_eth_mii_write(
+ int phyAddr, /* PHY number to access or -1 */
+ void *uarg, /* unit argument */
+ unsigned regAddr, /* register address */
+ uint32_t data) /* write data */
+{
+ struct mcf548x_enet_struct *sc = uarg;
+ int chan = sc->phy_chan;
+ int timeout = 0xffff;
+
+ MCF548X_FEC_MMFR(chan) = (MCF548X_FEC_MMFR_ST_01 |
+ MCF548X_FEC_MMFR_OP_WRITE |
+ MCF548X_FEC_MMFR_TA_10 |
+ MCF548X_FEC_MMFR_PA(phyAddr) |
+ MCF548X_FEC_MMFR_RA(regAddr) |
+ MCF548X_FEC_MMFR_DATA(data));
+
+ /*
+ * wait for the MII interrupt
+ */
+ while ((timeout--) && (!(MCF548X_FEC_EIR(chan) & MCF548X_FEC_EIR_MII)));
+
+ if(timeout == 0)
+ {
+
+#ifdef ETH_DEBUG
+ iprintf ("Write MDIO failed..." "\r\n");
+#endif
+
+ return 1;
+
+ }
+
+ /*
+ * clear MII interrupt bit
+ */
+ MCF548X_FEC_EIR(chan) = MCF548X_FEC_EIR_MII;
+
+ return 0;
+
+ }
+
+
+/*
+ * Function: mcf548x_fec_reset
+ *
+ * Description: Reset a running ethernet driver including the hardware
+ * FIFOs and the FEC.
+ *
+ * Returns: Success (boolean)
+ *
+ * Notes:
+ *
+ */
+static void mcf548x_fec_reset(struct mcf548x_enet_struct *sc) {
+ volatile int delay;
+ int chan = sc->chan;
+ /*
+ * Clear FIFO status registers
+ */
+ MCF548X_FEC_FECRFSR(chan) = ~0;
+ MCF548X_FEC_FECTFSR(chan) = ~0;
+
+ /*
+ * reset the FIFOs
+ */
+ MCF548X_FEC_FRST(chan) = 0x03000000;
+
+ for (delay = 0;delay < 16*4;delay++) {};
+
+ MCF548X_FEC_FRST(chan) = 0x01000000;
+
+ /*
+ * Issue a reset command to the FEC chip
+ */
+ MCF548X_FEC_ECR(chan) |= MCF548X_FEC_ECR_RESET;
+
+ /*
+ * wait at least 16 clock cycles
+ */
+ for (delay = 0;delay < 16*4;delay++) {};
+}
+
+
+/*
+ * Function: mcf548x_fec_off
+ *
+ * Description: Stop the FEC and disable the ethernet SmartComm tasks.
+ * This function "turns off" the driver.
+ *
+ * Returns: void
+ *
+ * Notes:
+ *
+ */
+void mcf548x_fec_off(struct mcf548x_enet_struct *sc)
+ {
+ int counter = 0xffff;
+ int chan = sc->chan;
+
+
+#if defined(ETH_DEBUG)
+ uint32_t phyStatus;
+ int i;
+
+ for(i = 0; i < 9; i++)
+ {
+
+ mcf548x_eth_mii_read(sc->phy_default, sc, i, &phyStatus);
+ iprintf ("Mii reg %d: 0x%04lx" "\r\n", i, phyStatus);
+
+ }
+
+ for(i = 16; i < 21; i++)
+ {
+
+ mcf548x_eth_mii_read(sc->phy_default, sc, i, &phyStatus);
+ iprintf ("Mii reg %d: 0x%04lx" "\r\n", i, phyStatus);
+
+ }
+ for(i = 0; i < 32; i++)
+ {
+
+ mcf548x_eth_mii_read(i, sc, 0, &phyStatus);
+ iprintf ("Mii Phy=%d, reg 0: 0x%04lx" "\r\n", i, phyStatus);
+
+ }
+#endif /* ETH_DEBUG */
+
+ /*
+ * block FEC chip interrupts
+ */
+ MCF548X_FEC_EIMR(chan) = 0;
+
+ /*
+ * issue graceful stop command to the FEC transmitter if necessary
+ */
+ MCF548X_FEC_TCR(chan) |= MCF548X_FEC_TCR_GTS;
+
+ /*
+ * wait for graceful stop to register
+ * FIXME: add rtems_task_wake_after here, if it takes to long
+ */
+ while((counter--) && (!( MCF548X_FEC_EIR(chan) & MCF548X_FEC_EIR_GRA)));
+
+ /*
+ * Disable the SmartDMA transmit and receive tasks.
+ */
+ MCD_killDma( sc->rxDmaChan );
+ MCD_killDma( sc->txDmaChan );
+ /*
+ * Disable transmit / receive interrupts
+ */
+ mcdma_glue_irq_disable(sc->txDmaChan);
+ mcdma_glue_irq_disable(sc->rxDmaChan);
+
+ /*
+ * Disable the Ethernet Controller
+ */
+ MCF548X_FEC_ECR(chan) &= ~(MCF548X_FEC_ECR_ETHER_EN);
+}
+
+/*
+ * MCF548X FEC interrupt handler
+ */
+void mcf548x_fec_irq_handler(rtems_vector_number vector)
+{
+ struct mcf548x_enet_struct *sc;
+ volatile uint32_t ievent;
+ int chan;
+
+ sc = &(enet_driver[MCF548X_FEC_VECTOR2CHAN(vector)]);
+ chan = sc->chan;
+ ievent = MCF548X_FEC_EIR(chan);
+
+ MCF548X_FEC_EIR(chan) = ievent;
+ /*
+ * check errors, update statistics
+ */
+ if (ievent & MCF548X_FEC_EIR_LC) {
+ sc->txLateCollision++;
+ }
+ if (ievent & MCF548X_FEC_EIR_RL) {
+ sc->txRetryLimit++;
+ }
+ if (ievent & MCF548X_FEC_EIR_XFUN) {
+ sc->txUnderrun++;
+ }
+ if (ievent & MCF548X_FEC_EIR_XFERR) {
+ sc->txFIFOError++;
+ }
+ if (ievent & MCF548X_FEC_EIR_RFERR) {
+ sc->rxFIFOError++;
+ }
+ /*
+ * fatal error ocurred?
+ */
+ if (ievent & (MCF548X_FEC_EIR_RFERR | MCF548X_FEC_EIR_XFERR)) {
+ MCF548X_FEC_EIMR(chan) &=~(MCF548X_FEC_EIMR_RFERR | MCF548X_FEC_EIMR_XFERR);
+ printk("fifo\n");
+ mcf548x_fec_request_restart(sc);
+ }
+}
+
+/*
+ * MCF548X DMA ethernet interrupt handler
+ */
+void mcf548x_mcdma_rx_irq_handler(void * param)
+{
+ struct mcf548x_enet_struct *sc = (struct mcf548x_enet_struct *)param;
+ /* Frame received? */
+ if(MCDMA_GET_PENDING(sc->rxDmaChan)) {
+ MCDMA_CLR_PENDING(sc->rxDmaChan);
+
+ mcdma_glue_irq_disable(sc->rxDmaChan);/*Disable receive ints*/
+ sc->rxInterrupts++; /* Rx int has occurred */
+ fec_send_event(sc->rxDaemonTid);
+ }
+}
+
+/*
+ * MCF548X DMA ethernet interrupt handler
+ */
+void mcf548x_mcdma_tx_irq_handler(void * param)
+{
+ struct mcf548x_enet_struct *sc = (struct mcf548x_enet_struct *)param;
+
+ /* Buffer transmitted or transmitter error? */
+ if(MCDMA_GET_PENDING(sc->txDmaChan)) {
+
+ MCDMA_CLR_PENDING(sc->txDmaChan);
+
+ mcdma_glue_irq_disable(sc->txDmaChan);/*Disable tx ints*/
+
+ sc->txInterrupts++; /* Tx int has occurred */
+
+ fec_send_event(sc->txDaemonTid);
+ }
+}
+
+/*
+ * Function: mcf548x_fec_initialize_hardware
+ *
+ * Description: Configure the MCF548X FEC registers and enable the
+ * SmartComm tasks. This function "turns on" the driver.
+ *
+ * Returns: void
+ *
+ * Notes:
+ *
+ */
+static void mcf548x_fec_initialize_hardware(struct mcf548x_enet_struct *sc)
+ {
+ int chan = sc->chan;
+
+ /*
+ * Reset mcf548x FEC
+ */
+ mcf548x_fec_reset(sc);
+
+ /*
+ * Clear FEC-Lite interrupt event register (IEVENT)
+ */
+ MCF548X_FEC_EIR(chan) = MCF548X_FEC_EIR_CLEAR_ALL;
+
+ /*
+ * Set interrupt mask register
+ */
+ MCF548X_FEC_EIMR(chan) = FEC_INTR_MASK_USED;
+ /*
+ * Set FEC-Lite receive control register (R_CNTRL)
+ * frame length=1518, MII mode for 18-wire-transceiver
+ */
+ MCF548X_FEC_RCR(chan) = (MCF548X_FEC_RCR_MAX_FL(ETHER_MAX_LEN)
+ | MCF548X_FEC_RCR_FCE
+ | MCF548X_FEC_RCR_MII_MODE);
+
+ /*
+ * Set FEC-Lite transmit control register (X_CNTRL)
+ * full-duplex, heartbeat disabled
+ */
+ MCF548X_FEC_TCR(chan) = MCF548X_FEC_TCR_FDEN;
+
+
+
+ /*
+ * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock(33Mhz)
+ * and do not drop the Preamble.
+ */
+ MCF548X_FEC_MSCR(chan) = MCF548X_FEC_MSCR_MII_SPEED(7); /* ipb_clk = 33 MHz */
+
+ /*
+ * Set Opcode/Pause Duration Register
+ */
+ MCF548X_FEC_PAUR(chan) = 0x00010020;
+
+ /*
+ * Set Rx FIFO alarm and granularity value
+ */
+ MCF548X_FEC_FECRFCR(chan) = (MCF548X_FEC_FECRFCR_FRM
+ | MCF548X_FEC_FECRFCR_GR(0x7));
+ MCF548X_FEC_FECRFAR(chan) = MCF548X_FEC_FECRFAR_ALARM(256);
+
+ /*
+ * Set Tx FIFO granularity value
+ */
+ MCF548X_FEC_FECTFCR(chan) = (MCF548X_FEC_FECTFCR_FRM
+ | MCF548X_FEC_FECTFCR_GR(7));
+
+ /*
+ * Set transmit fifo watermark register (X_WMRK), default = 64
+ */
+ MCF548X_FEC_FECTFAR(chan) = MCF548X_FEC_FECTFAR_ALARM(512);
+ MCF548X_FEC_FECTFWR(chan) = MCF548X_FEC_FECTFWR_X_WMRK_256;
+
+ /*
+ * Set individual address filter for unicast address
+ * and set physical address registers.
+ */
+ mcf548x_eth_addr_filter_set(sc);
+
+ /*
+ * Set multicast address filter
+ */
+ MCF548X_FEC_GAUR(chan) = 0x00000000;
+ MCF548X_FEC_GALR(chan) = 0x00000000;
+
+ /*
+ * enable CRC in finite state machine register
+ */
+ MCF548X_FEC_CTCWR(chan) = MCF548X_FEC_CTCWR_TFCW | MCF548X_FEC_CTCWR_CRC;
+ }
+
+
+/*
+ * Send packet (caller provides header).
+ */
+static void mcf548x_fec_tx_start(struct ifnet *ifp)
+ {
+
+ struct mcf548x_enet_struct *sc = ifp->if_softc;
+
+ ifp->if_flags |= IFF_OACTIVE;
+
+ fec_send_event(sc->txDaemonTid);
+
+ }
+
+static void fec_start_dma_and_controller(struct mcf548x_enet_struct *sc)
+{
+ int chan = sc->chan;
+ int mcdma_rc;
+ /*
+ * Enable the SmartDMA receive task.
+ */
+ mcdma_rc = MCD_startDma
+ (sc->rxDmaChan, /* the channel on which to run the DMA */
+ (void *)sc->rxBd, /* the address to move data from, or buffer-descriptor addr */
+ 0, /* the amount to increment the source address per transfer */
+ (void *)&MCF548X_FEC_FECRFDR(chan), /* the address to move data to */
+ 0, /* the amount to increment the destination address per transfer */
+ ETHER_MAX_LEN, /* the number of bytes to transfer independent of the transfer size */
+ 0, /* the number bytes in of each data movement (1, 2, or 4) */
+ MCF548X_FEC_RX_INITIATOR(chan), /* what device initiates the DMA */
+ 2, /* priority of the DMA */
+ 0 /* flags describing the DMA */
+ | MCD_FECRX_DMA
+ | MCD_INTERRUPT
+ | MCD_TT_FLAGS_CW
+ | MCD_TT_FLAGS_RL
+ | MCD_TT_FLAGS_SP
+ ,
+ 0 /* a description of byte swapping, bit swapping, and CRC actions */
+ | MCD_NO_CSUM
+ | MCD_NO_BYTE_SWAP
+ );
+ if (mcdma_rc != MCD_OK) {
+ rtems_panic("FEC: cannot start rx DMA");
+ }
+ mcdma_rc = MCD_startDma
+ (sc->txDmaChan, /* the channel on which to run the DMA */
+ (void *)sc->txBd, /* the address to move data from, or buffer-descriptor addr */
+ 0, /* the amount to increment the source address per transfer */
+ (void *)&MCF548X_FEC_FECTFDR(chan), /* the address to move data to */
+ 0, /* the amount to increment the destination address per transfer */
+ ETHER_MAX_LEN, /* the number of bytes to transfer independent of the transfer size */
+ 0, /* the number bytes in of each data movement (1, 2, or 4) */
+ MCF548X_FEC_TX_INITIATOR(chan), /* what device initiates the DMA */
+ 1, /* priority of the DMA */
+ 0 /* flags describing the DMA */
+ | MCD_FECTX_DMA
+ | MCD_INTERRUPT
+ | MCD_TT_FLAGS_CW
+ | MCD_TT_FLAGS_RL
+ | MCD_TT_FLAGS_SP
+ ,
+ 0 /* a description of byte swapping, bit swapping, and CRC actions */
+ | MCD_NO_CSUM
+ | MCD_NO_BYTE_SWAP
+ );
+ if (mcdma_rc != MCD_OK) {
+ rtems_panic("FEC: cannot start tx DMA");
+ }
+
+ /*
+ * Enable FEC-Lite controller
+ */
+ MCF548X_FEC_ECR(chan) |= MCF548X_FEC_ECR_ETHER_EN;
+}
+
+static void mcf548x_fec_restart(struct mcf548x_enet_struct *sc, rtems_id otherDaemon)
+{
+ if (sc->state == FEC_STATE_RESTART_1) {
+ mcf548x_fec_initialize_hardware(sc);
+ fec_start_dma_and_controller(sc);
+ sc->state = FEC_STATE_NORMAL;
+ } else {
+ sc->state = FEC_STATE_RESTART_1;
+ }
+
+ fec_send_event(otherDaemon);
+ while (sc->state != FEC_STATE_NORMAL) {
+ fec_wait_for_event();
+ }
+}
+
+static void fec_reset_bd_and_discard_tx_frames(
+ int bdCount,
+ MCD_bufDescFec *bdRing,
+ struct mbuf **mbufs
+)
+{
+ int bdIndex = 0;
+
+ for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
+ bool bdIsLast = bdIndex == bdCount - 1;
+ struct mbuf *m = mbufs[bdIndex];
+
+ bdRing[bdIndex].statCtrl = bdIsLast ? MCF548X_FEC_TBD_WRAP : 0;
+
+ if (m != NULL) {
+ mbufs[bdIndex] = NULL;
+ m_free(m);
+ }
+ }
+}
+
+static void fec_reset_tx_dma(
+ int dmaChan,
+ int bdCount,
+ MCD_bufDescFec *bdRing,
+ struct mbuf **mbufs,
+ struct mbuf *m
+)
+{
+ if (m != NULL) {
+ m_freem(m);
+ }
+
+ MCD_killDma(dmaChan);
+
+ fec_reset_bd_and_discard_tx_frames(bdCount, bdRing, mbufs);
+}
+
+static struct mbuf *fec_next_fragment(
+ struct ifnet *ifp,
+ struct mbuf *m,
+ bool *isFirst
+)
+{
+ struct mbuf *n = NULL;
+
+ *isFirst = false;
+
+ while (true) {
+ if (m == NULL) {
+ IF_DEQUEUE(&ifp->if_snd, m);
+
+ if (m != NULL) {
+ *isFirst = true;
+ } else {
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ return NULL;
+ }
+ }
+
+ if (m->m_len > 0) {
+ break;
+ } else {
+ m = m_free(m);
+ }
+ }
+
+ n = m->m_next;
+ while (n != NULL && n->m_len <= 0) {
+ n = m_free(n);
+ }
+ m->m_next = n;
+
+ return m;
+}
+
+static bool fec_transmit(
+ struct ifnet *ifp,
+ int dmaChan,
+ int bdCount,
+ MCD_bufDescFec *bdRing,
+ struct mbuf **mbufs,
+ int *bdIndexPtr,
+ struct mbuf **mPtr,
+ MCD_bufDescFec **firstPtr
+)
+{
+ bool bdShortage = false;
+ int bdIndex = *bdIndexPtr;
+ struct mbuf *m = *mPtr;
+ MCD_bufDescFec *first = *firstPtr;
+
+ while (true) {
+ MCD_bufDescFec *bd = &bdRing[bdIndex];
+
+ MCDMA_CLR_PENDING(dmaChan);
+ if ((bd->statCtrl & MCF548X_FEC_TBD_READY) == 0) {
+ struct mbuf *done = mbufs[bdIndex];
+ bool isFirst = false;
+
+ if (done != NULL) {
+ m_free(done);
+ mbufs[bdIndex] = NULL;
+ }
+
+ m = fec_next_fragment(ifp, m, &isFirst);
+ if (m != NULL) {
+ bool bdIsLast = bdIndex == bdCount - 1;
+ u16 status = bdIsLast ? MCF548X_FEC_TBD_WRAP : 0;
+
+ bd->length = (u16) m->m_len;
+ bd->dataPointer = mtod(m, u32);
+
+ mbufs[bdIndex] = m;
+
+ rtems_cache_flush_multiple_data_lines(mtod(m, void *), m->m_len);
+
+ if (isFirst) {
+ first = bd;
+ } else {
+ status |= MCF548X_FEC_TBD_READY;
+ }
+
+ if (m->m_next != NULL) {
+ bd->statCtrl = status;
+ } else {
+ bd->statCtrl = status | MCF548X_FEC_TBD_INT | MCF548X_FEC_TBD_LAST;
+ first->statCtrl |= MCF548X_FEC_TBD_READY;
+ MCD_continDma(dmaChan);
+ }
+
+ m = m->m_next;
+ } else {
+ break;
+ }
+ } else {
+ bdShortage = true;
+ break;
+ }
+
+ if (bdIndex < bdCount - 1) {
+ ++bdIndex;
+ } else {
+ bdIndex = 0;
+ }
+ }
+
+ *bdIndexPtr = bdIndex;
+ *mPtr = m;
+ *firstPtr = first;
+
+ return bdShortage;
+}
+
+static MCD_bufDescFec *fec_init_tx_dma(
+ MCD_bufDescFec *bdRing,
+ int bdCount
+)
+{
+ int bdIndex;
+
+ for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
+ bool bdIsLast = bdIndex == bdCount - 1;
+
+ bdRing[bdIndex].dataPointer = 0;
+ bdRing[bdIndex].length = 0;
+ bdRing[bdIndex].statCtrl = bdIsLast ? MCF548X_FEC_RBD_WRAP : 0;
+ }
+
+ return bdRing;
+}
+
+static void mcf548x_fec_txDaemon(void *arg)
+{
+ struct mcf548x_enet_struct *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int dmaChan = sc->txDmaChan;
+ int bdIndex = 0;
+ int bdCount = sc->txBdCount;
+ struct mbuf **mbufs = &sc->txMbuf[0];
+ struct mbuf *m = NULL;
+ MCD_bufDescFec *bdRing = fec_init_tx_dma(sc->txBd, bdCount);
+ MCD_bufDescFec *first = NULL;
+ bool bdShortage = false;
+
+ memset(mbufs, 0, bdCount * sizeof(*mbufs));
+
+ while (true) {
+ if (bdShortage) {
+ mcdma_glue_irq_enable(dmaChan);
+ }
+ fec_wait_for_event();
+
+ if (sc->state != FEC_STATE_NORMAL) {
+ fec_reset_tx_dma(dmaChan, bdCount, bdRing, mbufs, m);
+ mcf548x_fec_restart(sc, sc->rxDaemonTid);
+ bdIndex = 0;
+ m = NULL;
+ first = NULL;
+ }
+
+ bdShortage = fec_transmit(
+ ifp,
+ dmaChan,
+ bdCount,
+ bdRing,
+ mbufs,
+ &bdIndex,
+ &m,
+ &first
+ );
+ }
+}
+
+static struct mbuf *fec_add_mbuf(
+ int how,
+ struct ifnet *ifp,
+ MCD_bufDescFec *bd,
+ bool bdIsLast
+)
+{
+ struct mbuf *m;
+
+ MGETHDR(m, how, MT_DATA);
+ if (m != NULL) {
+ MCLGET(m, how);
+ if ((m->m_flags & M_EXT) != 0) {
+ m->m_pkthdr.rcvif = ifp;
+
+ rtems_cache_invalidate_multiple_data_lines(mtod(m, void *), ETHER_MAX_LEN);
+
+ bd->dataPointer = mtod(m, u32);
+ bd->length = ETHER_MAX_LEN;
+ bd->statCtrl = MCF548X_FEC_RBD_EMPTY
+ | MCF548X_FEC_RBD_INT
+ | (bdIsLast ? MCF548X_FEC_RBD_WRAP : 0);
+ } else {
+ m_free(m);
+ }
+ }
+
+ return m;
+}
+
+static MCD_bufDescFec *fec_init_rx_dma(
+ MCD_bufDescFec *bdRing,
+ struct ifnet *ifp,
+ int bdCount,
+ struct mbuf **mbufs
+)
+{
+ int bdIndex;
+
+ for (bdIndex = 0; bdIndex < bdCount; ++bdIndex) {
+ bool bdIsLast = bdIndex == bdCount - 1;
+
+ mbufs[bdIndex] = fec_add_mbuf(M_WAIT, ifp, &bdRing[bdIndex], bdIsLast);
+ }
+
+ return bdRing;
+}
+
+static void fec_reset_rx_dma(
+ int dmaChan,
+ int bdCount,
+ MCD_bufDescFec *bdRing
+)
+{
+ int bdIndex;
+
+ MCD_killDma(dmaChan);
+
+ for (bdIndex = 0; bdIndex < bdCount - 1; ++bdIndex) {
+ bdRing[bdIndex].length = ETHER_MAX_LEN;
+ bdRing[bdIndex].statCtrl = MCF548X_FEC_RBD_EMPTY | MCF548X_FEC_RBD_INT;
+ }
+
+ bdRing[bdIndex].length = ETHER_MAX_LEN;
+ bdRing[bdIndex].statCtrl = MCF548X_FEC_RBD_EMPTY | MCF548X_FEC_RBD_INT | MCF548X_FEC_RBD_WRAP;
+}
+
+static int fec_ether_input(
+ struct ifnet *ifp,
+ int dmaChan,
+ int bdIndex,
+ int bdCount,
+ MCD_bufDescFec *bdRing,
+ struct mbuf **mbufs
+)
+{
+ while (true) {
+ bool bdIsLast = bdIndex == bdCount - 1;
+ MCD_bufDescFec *bd = &bdRing[bdIndex];
+ struct mbuf *m = mbufs[bdIndex];
+ struct mbuf *n;
+ u16 status;
+
+ MCDMA_CLR_PENDING(dmaChan);
+ status = bd->statCtrl;
+
+ if ((status & MCF548X_FEC_RBD_EMPTY) != 0) {
+ break;
+ }
+
+ n = fec_add_mbuf(0, ifp, bd, bdIsLast);
+ if (n != NULL) {
+ int len = bd->length - ETHER_HDR_LEN - ETHER_CRC_LEN;
+ struct ether_header *eh = mtod(m, struct ether_header *);
+
+ m->m_len = len;
+ m->m_pkthdr.len = len;
+ m->m_data = mtod(m, char *) + ETHER_HDR_LEN;
+
+ ether_input(ifp, eh, m);
+ } else {
+ n = m;
+ }
+
+ mbufs[bdIndex] = n;
+
+ if (bdIndex < bdCount - 1) {
+ ++bdIndex;
+ } else {
+ bdIndex = 0;
+ }
+ }
+
+ return bdIndex;
+}
+
+static void mcf548x_fec_rxDaemon(void *arg)
+{
+ struct mcf548x_enet_struct *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int dmaChan = sc->rxDmaChan;
+ int bdIndex = 0;
+ int bdCount = sc->rxBdCount;
+ struct mbuf **mbufs = &sc->rxMbuf[0];
+ MCD_bufDescFec *bdRing = fec_init_rx_dma(sc->rxBd, ifp, bdCount, mbufs);
+
+ while (true) {
+ mcdma_glue_irq_enable(dmaChan);
+ fec_wait_for_event();
+
+ bdIndex = fec_ether_input(ifp, dmaChan, bdIndex, bdCount, bdRing, mbufs);
+
+ if (sc->state != FEC_STATE_NORMAL) {
+ fec_reset_rx_dma(dmaChan, bdCount, bdRing);
+ mcf548x_fec_restart(sc, sc->txDaemonTid);
+ bdIndex = 0;
+ }
+ }
+}
+
+/*
+ * Initialize and start the device
+ */
+static void mcf548x_fec_init(void *arg)
+{
+ struct mcf548x_enet_struct *sc = (struct mcf548x_enet_struct *)arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int chan = sc->chan;
+ rtems_isr_entry old_handler;
+ char *txTaskName = "FTx0";
+ char *rxTaskName = "FRx0";
+ if(sc->txDaemonTid == 0)
+ {
+ /*
+ * Allocate a set of BDs
+ */
+ sc->rxBd = SRAM_RXBD_BASE(_SysSramBase,chan);
+ sc->txBd = SRAM_TXBD_BASE(_SysSramBase,chan);
+
+ if(!sc->rxBd || !sc->txBd)
+ rtems_panic ("No memory for BDs");
+ /*
+ * clear the BDs
+ */
+ memset((void *)sc->rxBd,0,sc->rxBdCount * sizeof *(sc->rxBd));
+ memset((void *)sc->txBd,0,sc->txBdCount * sizeof *(sc->txBd));
+ /*
+ * Allocate a set of mbuf pointers
+ */
+ sc->rxMbuf =
+ malloc(sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
+ sc->txMbuf =
+ malloc(sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
+
+ if(!sc->rxMbuf || !sc->txMbuf)
+ rtems_panic ("No memory for mbuf pointers");
+
+ sc->txDmaChan = MCDMA_FEC_TX_CHAN(chan);
+ sc->rxDmaChan = MCDMA_FEC_RX_CHAN(chan);
+
+ mcdma_glue_init(SRAM_DMA_BASE(_SysSramBase));
+
+ /*
+ * Set up interrupts
+ */
+ mcdma_glue_irq_install(sc->rxDmaChan,
+ mcf548x_mcdma_rx_irq_handler,
+ sc);
+ mcdma_glue_irq_install(sc->txDmaChan,
+ mcf548x_mcdma_tx_irq_handler,
+ sc);
+ if(rtems_interrupt_catch(mcf548x_fec_irq_handler,
+ MCF548X_FEC_IRQ_VECTOR(chan),
+ &old_handler)) {
+ rtems_panic ("Can't attach MFC54xx FEX interrupt handler\n");
+ }
+
+ bsp_interrupt_vector_enable(MCF548X_IRQ_FEC(chan));
+
+ MCF548X_FEC_EIMR(chan) = FEC_INTR_MASK_USED;
+
+ /*
+ * Start driver tasks
+ */
+ txTaskName[3] = '0'+chan;
+ rxTaskName[3] = '0'+chan;
+ sc->txDaemonTid = rtems_bsdnet_newproc(txTaskName, 4096,
+ mcf548x_fec_txDaemon, sc);
+ sc->rxDaemonTid = rtems_bsdnet_newproc(rxTaskName, 4096,
+ mcf548x_fec_rxDaemon, sc);
+ }
+
+ mcf548x_fec_request_restart(sc);
+
+ /*
+ * Set flags appropriately
+ */
+ if(ifp->if_flags & IFF_PROMISC)
+ MCF548X_FEC_RCR(chan) |= MCF548X_FEC_RCR_PROM;
+ else
+ MCF548X_FEC_RCR(chan) &= ~MCF548X_FEC_RCR_PROM;
+
+ /*
+ * init timer so the "watchdog function gets called periodically
+ */
+ ifp->if_timer = 1;
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+}
+
+
+static void enet_stats (struct mcf548x_enet_struct *sc)
+{
+ printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
+ printf (" Rx Not First:%-8lu", sc->rxNotFirst);
+ printf (" Rx Not Last:%-8lu\n", sc->rxNotLast);
+ printf (" Rx Giant:%-8lu", sc->rxGiant);
+ printf (" Rx Non-octet:%-8lu", sc->rxNonOctet);
+ printf (" Rx Bad CRC:%-8lu\n", sc->rxBadCRC);
+ printf (" Rx FIFO Error:%-8lu", sc->rxFIFOError);
+ printf (" Rx Collision:%-8lu", sc->rxCollision);
+
+ printf (" Tx Interrupts:%-8lu\n", sc->txInterrupts);
+ printf (" Tx Deferred:%-8lu", sc->txDeferred);
+ printf (" Tx Late Collision:%-8lu", sc->txLateCollision);
+ printf (" Tx Retransmit Limit:%-8lu\n", sc->txRetryLimit);
+ printf (" Tx Underrun:%-8lu", sc->txUnderrun);
+ printf (" Tx FIFO Error:%-8lu", sc->txFIFOError);
+ printf (" Tx Misaligned:%-8lu\n", sc->txMisaligned);
+
+}
+
+int32_t mcf548x_fec_setMultiFilter(struct ifnet *ifp)
+{
+ /*struct mcf548x_enet_struct *sc = ifp->if_softc; */
+ /* XXX anything to do? */
+ return 0;
+}
+
+
+/*
+ * Driver ioctl handler
+ */
+static int mcf548x_fec_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
+ {
+ struct mcf548x_enet_struct *sc = ifp->if_softc;
+ int error = 0;
+
+ switch(command)
+ {
+
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ rtems_mii_ioctl (&(sc->mdio_info),sc,command,(void *)data);
+ break;
+
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+
+ ether_ioctl(ifp, command, data);
+
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI: {
+ struct ifreq* ifr = (struct ifreq*) data;
+ error = (command == SIOCADDMULTI)
+ ? ether_addmulti(ifr, &sc->arpcom)
+ : ether_delmulti(ifr, &sc->arpcom);
+
+ if (error == ENETRESET) {
+ if (ifp->if_flags & IFF_RUNNING)
+ error = mcf548x_fec_setMultiFilter(ifp);
+ else
+ error = 0;
+ }
+ break;
+ }
+
+ case SIOCSIFFLAGS:
+
+ switch(ifp->if_flags & (IFF_UP | IFF_RUNNING))
+ {
+
+ case IFF_RUNNING:
+
+ mcf548x_fec_off(sc);
+
+ break;
+
+ case IFF_UP:
+
+ mcf548x_fec_init(sc);
+
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+
+ mcf548x_fec_off(sc);
+ mcf548x_fec_init(sc);
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+
+ enet_stats(sc);
+
+ break;
+
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+
+ error = EINVAL;
+
+ break;
+
+ }
+
+ return error;
+
+ }
+
+
+/*
+ * init the PHY and adapt FEC settings
+ */
+int mcf548x_fec_mode_adapt(struct ifnet *ifp)
+{
+ int result = 0;
+ struct mcf548x_enet_struct *sc = ifp->if_softc;
+ int media = IFM_MAKEWORD( 0, 0, 0, sc->phy_default);
+ int chan = sc->chan;
+
+ /*
+ * fetch media status
+ */
+ result = mcf548x_fec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media);
+ if (result != 0) {
+ return result;
+ }
+ /*
+ * status is unchanged? then do nothing
+ */
+ if (media == sc->media_state) {
+ return 0;
+ }
+ /*
+ * otherwise: for the first call, try to negotiate mode
+ */
+ if (sc->media_state == 0) {
+ /*
+ * set media status: set auto negotiation -> start auto-negotiation
+ */
+ media = IFM_MAKEWORD(0,IFM_AUTO,0,sc->phy_default);
+ result = mcf548x_fec_ioctl(ifp,SIOCSIFMEDIA,(caddr_t)&media);
+ if (result != 0) {
+ return result;
+ }
+ /*
+ * wait for auto-negotiation to terminate
+ */
+ do {
+ media = IFM_MAKEWORD(0,0,0,sc->phy_default);
+ result = mcf548x_fec_ioctl(ifp,SIOCGIFMEDIA,(caddr_t)&media);
+ if (result != 0) {
+ return result;
+ }
+ } while (IFM_NONE == IFM_SUBTYPE(media));
+ }
+
+ /*
+ * now set HW according to media results:
+ */
+
+ /*
+ * if we are half duplex then switch to half duplex
+ */
+ if (0 == (IFM_FDX & IFM_OPTIONS(media))) {
+ MCF548X_FEC_TCR(chan) &= ~MCF548X_FEC_TCR_FDEN;
+ }
+ else {
+ MCF548X_FEC_TCR(chan) |= MCF548X_FEC_TCR_FDEN;
+ }
+ /*
+ * store current media state for future compares
+ */
+ sc->media_state = media;
+
+ return 0;
+}
+
+/*
+ * periodically poll the PHY. if mode has changed,
+ * then adjust the FEC settings
+ */
+static void mcf548x_fec_watchdog( struct ifnet *ifp)
+{
+ mcf548x_fec_mode_adapt(ifp);
+ ifp->if_timer = FEC_WATCHDOG_TIMEOUT;
+}
+
+/*
+ * Attach the MCF548X fec driver to the system
+ */
+int rtems_mcf548x_fec_driver_attach(struct rtems_bsdnet_ifconfig *config)
+ {
+ struct mcf548x_enet_struct *sc;
+ struct ifnet *ifp;
+ int mtu;
+ int unitNumber;
+ char *unitName;
+
+ /*
+ * Parse driver name
+ */
+ if((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0)
+ return 0;
+
+ /*
+ * Is driver free?
+ */
+ if ((unitNumber <= 0) || (unitNumber > NIFACES))
+ {
+
+ printf ("Bad FEC unit number.\n");
+ return 0;
+
+ }
+
+ sc = &enet_driver[unitNumber - 1];
+ sc->chan = unitNumber-1;
+ ifp = &sc->arpcom.ac_if;
+
+ if(ifp->if_softc != NULL)
+ {
+
+ printf ("Driver already in use.\n");
+ return 0;
+
+ }
+
+ /*
+ * Process options
+ */
+#if NVRAM_CONFIGURE == 1
+
+ /* Configure from NVRAM */
+ if(addr = nvram->ipaddr)
+ {
+
+ /* We have a non-zero entry, copy the value */
+ if(pAddr = malloc(INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT))
+ config->ip_address = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1);
+ else
+ rtems_panic("Can't allocate ip_address buffer!\n");
+
+ }
+
+ if(addr = nvram->netmask)
+ {
+
+ /* We have a non-zero entry, copy the value */
+ if (pAddr = malloc (INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT))
+ config->ip_netmask = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1);
+ else
+ rtems_panic("Can't allocate ip_netmask buffer!\n");
+
+ }
+
+ /* Ethernet address requires special handling -- it must be copied into
+ * the arpcom struct. The following if construct serves only to give the
+ * User Area NVRAM parameter the highest priority.
+ *
+ * If the ethernet address is specified in NVRAM, go ahead and copy it.
+ * (ETHER_ADDR_LEN = 6 bytes).
+ */
+ if(nvram->enaddr[0] || nvram->enaddr[1] || nvram->enaddr[2])
+ {
+
+ /* Anything in the first three bytes indicates a non-zero entry, copy value */
+ memcpy((void *)sc->arpcom.ac_enaddr, &nvram->enaddr, ETHER_ADDR_LEN);
+
+ }
+ else
+ if(config->hardware_address)
+ {
+
+ /* There is no entry in NVRAM, but there is in the ifconfig struct, so use it. */
+ memcpy((void *)sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+ }
+
+#else /* NVRAM_CONFIGURE != 1 */
+
+ if(config->hardware_address)
+ {
+
+ memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+
+ }
+
+#endif /* NVRAM_CONFIGURE != 1 */
+#ifdef HAS_UBOOT
+ if ((sc->arpcom.ac_enaddr[0] == 0) &&
+ (sc->arpcom.ac_enaddr[1] == 0) &&
+ (sc->arpcom.ac_enaddr[2] == 0)) {
+ memcpy(
+ (void *)sc->arpcom.ac_enaddr,
+ bsp_uboot_board_info.bi_enetaddr,
+ ETHER_ADDR_LEN
+ );
+ }
+#endif
+#ifdef HAS_DBUG
+ if ((sc->arpcom.ac_enaddr[0] == 0) &&
+ (sc->arpcom.ac_enaddr[1] == 0) &&
+ (sc->arpcom.ac_enaddr[2] == 0)) {
+ memcpy(
+ (void *)sc->arpcom.ac_enaddr,
+ DBUG_SETTINGS.macaddr,
+ ETHER_ADDR_LEN
+ );
+ }
+#endif
+ if ((sc->arpcom.ac_enaddr[0] == 0) &&
+ (sc->arpcom.ac_enaddr[1] == 0) &&
+ (sc->arpcom.ac_enaddr[2] == 0)) {
+ /* There is no ethernet address provided, so it could be read
+ * from the Ethernet protocol block of SCC1 in DPRAM.
+ */
+ rtems_panic("No Ethernet address specified!\n");
+ }
+ if(config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+
+ if(config->rbuf_count)
+ sc->rxBdCount = config->rbuf_count;
+ else
+ sc->rxBdCount = RX_BUF_COUNT;
+
+ if(config->xbuf_count)
+ sc->txBdCount = config->xbuf_count;
+ else
+ sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
+
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+ /*
+ * setup info about mdio interface
+ */
+ sc->mdio_info.mdio_r = mcf548x_eth_mii_read;
+ sc->mdio_info.mdio_w = mcf548x_eth_mii_write;
+ sc->mdio_info.has_gmii = 0; /* we do not support gigabit IF */
+
+ /*
+ * XXX: Although most hardware builders will assign the PHY addresses
+ * like this, this should be more configurable
+ */
+ sc->phy_default = unitNumber-1;
+ sc->phy_chan = 0; /* assume all MII accesses are via FEC0 */
+
+ /*
+ * Set up network interface values
+ */
+ ifp->if_softc = sc;
+ ifp->if_unit = unitNumber;
+ ifp->if_name = unitName;
+ ifp->if_mtu = mtu;
+ ifp->if_init = mcf548x_fec_init;
+ ifp->if_ioctl = mcf548x_fec_ioctl;
+ ifp->if_start = mcf548x_fec_tx_start;
+ ifp->if_output = ether_output;
+ ifp->if_watchdog = mcf548x_fec_watchdog; /* XXX: timer is set in "init" */
+ ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
+ /*ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;*/
+
+ if(ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ /*
+ * Attach the interface
+ */
+ if_attach(ifp);
+
+ ether_ifattach(ifp);
+
+ return 1;
+ }
+
+
+int rtems_mcf548x_fec_driver_attach_detach(struct rtems_bsdnet_ifconfig *config, int attaching)
+{
+ if (attaching) {
+ return rtems_mcf548x_fec_driver_attach(config);
+ }
+ else {
+ return 0;
+ }
+}
+
+
diff --git a/bsps/m68k/mcf5235/net/network.c b/bsps/m68k/mcf5235/net/network.c
new file mode 100644
index 0000000000..6c8fa88be2
--- /dev/null
+++ b/bsps/m68k/mcf5235/net/network.c
@@ -0,0 +1,879 @@
+/*
+ * RTEMS/TCPIP driver for MCF5235 Fast Ethernet Controller
+ *
+ * TO DO: Check network stack code -- force longword alignment of all tx mbufs?
+ */
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+
+#include <bsp.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+
+/*
+ * Number of interfaces supported by this driver
+ */
+#define NIFACES 1
+
+#define FEC_INTC0_TX_VECTOR (64+23)
+#define FEC_INTC0_RX_VECTOR (64+27)
+
+/*
+ * Default number of buffer descriptors set aside for this driver.
+ * The number of transmit buffer descriptors has to be quite large
+ * since a single frame often uses three or more buffer descriptors.
+ */
+#define RX_BUF_COUNT 32
+#define TX_BUF_COUNT 20
+#define TX_BD_PER_BUF 3
+
+#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
+
+/*
+ * RTEMS event used by interrupt handler to signal daemons.
+ * This must *not* be the same event used by the TCP/IP task synchronization.
+ */
+#define TX_INTERRUPT_EVENT RTEMS_EVENT_1
+#define RX_INTERRUPT_EVENT RTEMS_EVENT_1
+
+/*
+ * RTEMS event used to start transmit daemon.
+ * This must not be the same as INTERRUPT_EVENT.
+ */
+#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+
+/*
+ * Receive buffer size -- Allow for a full ethernet packet plus CRC (1518).
+ * Round off to nearest multiple of RBUF_ALIGN.
+ */
+#define MAX_MTU_SIZE 1518
+#define RBUF_ALIGN 4
+#define RBUF_SIZE ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN)
+
+#if (MCLBYTES < RBUF_SIZE)
+ #error "Driver must have MCLBYTES > RBUF_SIZE"
+#endif
+
+typedef struct mcf5235BufferDescriptor_ {
+ volatile uint16_t status;
+ uint16_t length;
+ volatile void *buffer;
+} mcf5235BufferDescriptor_t;
+
+/*
+ * Per-device data
+ */
+struct mcf5235_enet_struct {
+ struct arpcom arpcom;
+ struct mbuf **rxMbuf;
+ struct mbuf **txMbuf;
+ int acceptBroadcast;
+ int rxBdCount;
+ int txBdCount;
+ int txBdHead;
+ int txBdTail;
+ int txBdActiveCount;
+ mcf5235BufferDescriptor_t *rxBdBase;
+ mcf5235BufferDescriptor_t *txBdBase;
+ rtems_id rxDaemonTid;
+ rtems_id txDaemonTid;
+
+ /*
+ * Statistics
+ */
+ unsigned long rxInterrupts;
+ unsigned long txInterrupts;
+ unsigned long txRawWait;
+ unsigned long txRealign;
+};
+static struct mcf5235_enet_struct enet_driver[NIFACES];
+
+static rtems_isr
+mcf5235_fec_rx_interrupt_handler( rtems_vector_number v )
+{
+ MCF5235_FEC_EIR = MCF5235_FEC_EIR_RXF;
+ MCF5235_FEC_EIMR &= ~MCF5235_FEC_EIMR_RXF;
+ enet_driver[0].rxInterrupts++;
+ rtems_bsdnet_event_send(enet_driver[0].rxDaemonTid, RX_INTERRUPT_EVENT);
+}
+
+static rtems_isr
+mcf5235_fec_tx_interrupt_handler( rtems_vector_number v )
+{
+ MCF5235_FEC_EIR = MCF5235_FEC_EIR_TXF;
+ MCF5235_FEC_EIMR &= ~MCF5235_FEC_EIMR_TXF;
+ enet_driver[0].txInterrupts++;
+ rtems_bsdnet_event_send(enet_driver[0].txDaemonTid, TX_INTERRUPT_EVENT);
+}
+
+/*
+ * Allocate buffer descriptors from (non-cached) on-chip static RAM
+ * Ensure 128-bit (16-byte) alignment
+ */
+extern char __SRAMBASE[];
+
+static mcf5235BufferDescriptor_t *
+mcf5235_bd_allocate(unsigned int count)
+{
+ static mcf5235BufferDescriptor_t *bdp = (mcf5235BufferDescriptor_t *)__SRAMBASE;
+ mcf5235BufferDescriptor_t *p = bdp;
+
+ bdp += count;
+ if ((int)bdp & 0xF)
+ bdp = (mcf5235BufferDescriptor_t *)((char *)bdp + (16 - ((int)bdp & 0xF)));
+ return p;
+}
+
+#if UNUSED
+/*
+ * Read MII register
+ * Busy-waits, but transfer time should be short!
+ */
+static int
+getMII(int phyNumber, int regNumber)
+{
+ MCF5235_FEC_MMFR = (0x1 << 30) |
+ (0x2 << 28) |
+ (phyNumber << 23) |
+ (regNumber << 18) |
+ (0x2 << 16);
+ while ((MCF5235_FEC_EIR & MCF5235_FEC_EIR_MII) == 0);
+ MCF5235_FEC_EIR = MCF5235_FEC_EIR_MII;
+ return MCF5235_FEC_MMFR & 0xFFFF;
+}
+#endif
+
+/*
+ * Write MII register
+ * Busy-waits, but transfer time should be short!
+ */
+static void
+setMII(int phyNumber, int regNumber, int value)
+{
+ MCF5235_FEC_MMFR = (0x1 << 30) |
+ (0x1 << 28) |
+ (phyNumber << 23) |
+ (regNumber << 18) |
+ (0x2 << 16) |
+ (value & 0xFFFF);
+ while ((MCF5235_FEC_EIR & MCF5235_FEC_EIR_MII) == 0);
+ MCF5235_FEC_EIR = MCF5235_FEC_EIR_MII;
+}
+
+static void
+mcf5235_fec_initialize_hardware(struct mcf5235_enet_struct *sc)
+{
+ int i;
+ const unsigned char *hwaddr = 0;
+ rtems_status_code status;
+ rtems_isr_entry old_handler;
+ uint32_t clock_speed = get_CPU_clock_speed();
+
+ /*
+ * Issue reset to FEC
+ */
+ MCF5235_FEC_ECR = MCF5235_FEC_ECR_RESET;
+ rtems_task_wake_after(1);
+ MCF5235_FEC_ECR = 0;
+
+ /*
+ * Configuration of I/O ports is done outside of this function
+ */
+#if 0
+ imm->gpio.pbcnt |= MCF5235_GPIO_PBCNT_SET_FEC; /* Set up port b FEC pins */
+#endif
+
+ /*
+ * Set our physical address
+ */
+ hwaddr = sc->arpcom.ac_enaddr;
+ MCF5235_FEC_PALR = (hwaddr[0] << 24) | (hwaddr[1] << 16) |
+ (hwaddr[2] << 8) | (hwaddr[3] << 0);
+ MCF5235_FEC_PAUR = (hwaddr[4] << 24) | (hwaddr[5] << 16);
+
+
+ /*
+ * Clear the hash table
+ */
+ MCF5235_FEC_GAUR = 0;
+ MCF5235_FEC_GALR = 0;
+
+ /*
+ * Set up receive buffer size
+ */
+ MCF5235_FEC_EMRBR = 1520; /* Standard Ethernet */
+
+ /*
+ * Allocate mbuf pointers
+ */
+ sc->rxMbuf = malloc(sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
+ sc->txMbuf = malloc(sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
+ if (!sc->rxMbuf || !sc->txMbuf)
+ rtems_panic("No memory for mbuf pointers");
+
+ /*
+ * Set receiver and transmitter buffer descriptor bases
+ */
+ sc->rxBdBase = mcf5235_bd_allocate(sc->rxBdCount);
+ sc->txBdBase = mcf5235_bd_allocate(sc->txBdCount);
+ MCF5235_FEC_ERDSR = (int)sc->rxBdBase;
+ MCF5235_FEC_ETDSR = (int)sc->txBdBase;
+
+ /*
+ * Set up Receive Control Register:
+ * Not promiscuous
+ * MII mode
+ * Full duplex
+ * No loopback
+ */
+ MCF5235_FEC_RCR = MCF5235_FEC_RCR_MAX_FL(MAX_MTU_SIZE) |
+ MCF5235_FEC_RCR_MII_MODE;
+
+ /*
+ * Set up Transmit Control Register:
+ * Full duplex
+ * No heartbeat
+ */
+ MCF5235_FEC_TCR = MCF5235_FEC_TCR_FDEN;
+
+ /*
+ * Initialize statistic counters
+ */
+ MCF5235_FEC_MIBC = MCF5235_FEC_MIBC_MIB_DISABLE;
+ {
+ vuint32 *vuip = &MCF5235_FEC_RMON_T_DROP;
+ while (vuip <= &MCF5235_FEC_IEEE_R_OCTETS_OK)
+ *vuip++ = 0;
+ }
+ MCF5235_FEC_MIBC = 0;
+
+ /*
+ * Set MII speed to <= 2.5 MHz
+ */
+ i = (clock_speed + 5000000 - 1) / 5000000;
+ MCF5235_FEC_MSCR = MCF5235_FEC_MSCR_MII_SPEED(i);
+
+ /*
+ * Set PHYS to 100 Mb/s, full duplex
+ */
+ setMII(1, 0, 0x2100);
+
+ /*
+ * Set up receive buffer descriptors
+ */
+ for (i = 0 ; i < sc->rxBdCount ; i++)
+ (sc->rxBdBase + i)->status = 0;
+
+ /*
+ * Set up transmit buffer descriptors
+ */
+ for (i = 0 ; i < sc->txBdCount ; i++) {
+ sc->txBdBase[i].status = 0;
+ sc->txMbuf[i] = NULL;
+ }
+ sc->txBdHead = sc->txBdTail = 0;
+ sc->txBdActiveCount = 0;
+
+ /*
+ * Set up interrupts
+ */
+ status = rtems_interrupt_catch( mcf5235_fec_tx_interrupt_handler, FEC_INTC0_TX_VECTOR, &old_handler );
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't attach MCF5235 FEC TX interrupt handler: %s\n",
+ rtems_status_text(status));
+ status = rtems_interrupt_catch(mcf5235_fec_rx_interrupt_handler, FEC_INTC0_RX_VECTOR, &old_handler);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't attach MCF5235 FEC RX interrupt handler: %s\n",
+ rtems_status_text(status));
+ MCF5235_INTC0_ICR23 = MCF5235_INTC_ICR_IL(FEC_IRQ_LEVEL) |
+ MCF5235_INTC_ICR_IP(FEC_IRQ_TX_PRIORITY);
+ MCF5235_INTC0_IMRL &= ~(MCF5235_INTC0_IMRL_INT23 | MCF5235_INTC0_IMRL_MASKALL);
+ MCF5235_INTC0_ICR27 = MCF5235_INTC_ICR_IL(FEC_IRQ_LEVEL) |
+ MCF5235_INTC_ICR_IP(FEC_IRQ_RX_PRIORITY);
+ MCF5235_INTC0_IMRL &= ~(MCF5235_INTC0_IMRL_INT27 | MCF5235_INTC0_IMRL_MASKALL);
+}
+
+/*
+ * Get the MAC address from the hardware.
+ */
+static void
+fec_get_mac_address(volatile struct mcf5235_enet_struct *sc, unsigned char* hwaddr)
+{
+ unsigned long addr;
+
+ addr = MCF5235_FEC_PALR;
+
+ hwaddr[0] = (addr >> 24) & 0xff;
+ hwaddr[1] = (addr >> 16) & 0xff;
+ hwaddr[2] = (addr >> 8) & 0xff;
+ hwaddr[3] = (addr >> 0) & 0xff;
+
+ addr = MCF5235_FEC_PAUR;
+
+ hwaddr[4] = (addr >> 24) & 0xff;
+ hwaddr[5] = (addr >> 16) & 0xff;
+}
+
+
+/*
+ * Soak up buffer descriptors that have been sent.
+ */
+static void
+fec_retire_tx_bd(volatile struct mcf5235_enet_struct *sc )
+{
+ struct mbuf *m, *n;
+
+ while ((sc->txBdActiveCount != 0)
+ && ((sc->txBdBase[sc->txBdTail].status & MCF5235_FEC_TxBD_R) == 0)) {
+ m = sc->txMbuf[sc->txBdTail];
+ MFREE(m, n);
+ if (++sc->txBdTail == sc->txBdCount)
+ sc->txBdTail = 0;
+ sc->txBdActiveCount--;
+ }
+}
+
+static void
+fec_rxDaemon (void *arg)
+{
+ volatile struct mcf5235_enet_struct *sc = (volatile struct mcf5235_enet_struct *)arg;
+ struct ifnet *ifp = (struct ifnet* )&sc->arpcom.ac_if;
+ struct mbuf *m;
+ volatile uint16_t status;
+ volatile mcf5235BufferDescriptor_t *rxBd;
+ int rxBdIndex;
+
+ /*
+ * Allocate space for incoming packets and start reception
+ */
+ for (rxBdIndex = 0 ; ;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+ MGETHDR(m, M_WAIT, MT_DATA);
+ MCLGET(m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->buffer = mtod(m, void *);
+ rxBd->status = MCF5235_FEC_RxBD_E;
+ if (++rxBdIndex == sc->rxBdCount) {
+ rxBd->status |= MCF5235_FEC_RxBD_W;
+ break;
+ }
+ }
+
+ /*
+ * Input packet handling loop
+ */
+ /* Indicate we have some ready buffers available */
+ MCF5235_FEC_RDAR = MCF5235_FEC_RDAR_R_DES_ACTIVE;
+
+ rxBdIndex = 0;
+ for (;;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+
+ /*
+ * Wait for packet if there's not one ready
+ */
+ if ((status = rxBd->status) & MCF5235_FEC_RxBD_E) {
+ /*
+ * Clear old events.
+ */
+ MCF5235_FEC_EIR = MCF5235_FEC_EIR_RXF;
+
+ /*
+ * Wait for packet to arrive.
+ * Check the buffer descriptor before waiting for the event.
+ * This catches the case when a packet arrives between the
+ * `if' above, and the clearing of the RXF bit in the EIR.
+ */
+ while ((status = rxBd->status) & MCF5235_FEC_RxBD_E) {
+ rtems_event_set events;
+ int level;
+
+ rtems_interrupt_disable(level);
+ MCF5235_FEC_EIMR |= MCF5235_FEC_EIMR_RXF;
+ rtems_interrupt_enable(level);
+ rtems_bsdnet_event_receive (RX_INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ }
+ }
+
+ /*
+ * Check that packet is valid
+ */
+ if (status & MCF5235_FEC_RxBD_L) {
+ /*
+ * Pass the packet up the chain.
+ * FIXME: Packet filtering hook could be done here.
+ */
+ struct ether_header *eh;
+ int len = rxBd->length - sizeof(uint32_t);
+
+ /*
+ * Invalidate the cache and push the packet up.
+ * The cache is so small that it's more efficient to just
+ * invalidate the whole thing unless the packet is very small.
+ */
+ m = sc->rxMbuf[rxBdIndex];
+ if (len < 128)
+ rtems_cache_invalidate_multiple_data_lines(m->m_data, len);
+ else
+ rtems_cache_invalidate_entire_data();
+ m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);
+ eh = mtod(m, struct ether_header *);
+ m->m_data += sizeof(struct ether_header);
+ ether_input(ifp, eh, m);
+
+ /*
+ * Allocate a new mbuf
+ */
+ MGETHDR(m, M_WAIT, MT_DATA);
+ MCLGET(m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->buffer = mtod(m, void *);
+ }
+
+ /*
+ * Reenable the buffer descriptor
+ */
+ rxBd->status = (status & MCF5235_FEC_RxBD_W) | MCF5235_FEC_RxBD_E;
+ MCF5235_FEC_RDAR = MCF5235_FEC_RDAR_R_DES_ACTIVE;
+
+ /*
+ * Move to next buffer descriptor
+ */
+ if (++rxBdIndex == sc->rxBdCount)
+ rxBdIndex = 0;
+ }
+}
+
+static void
+fec_sendpacket(struct ifnet *ifp, struct mbuf *m)
+{
+ struct mcf5235_enet_struct *sc = ifp->if_softc;
+ volatile mcf5235BufferDescriptor_t *firstTxBd, *txBd;
+ uint16_t status;
+ int nAdded;
+
+ /*
+ * Free up buffer descriptors
+ */
+ fec_retire_tx_bd(sc);
+
+ /*
+ * Set up the transmit buffer descriptors.
+ * No need to pad out short packets since the
+ * hardware takes care of that automatically.
+ * No need to copy the packet to a contiguous buffer
+ * since the hardware is capable of scatter/gather DMA.
+ */
+ nAdded = 0;
+ firstTxBd = sc->txBdBase + sc->txBdHead;
+
+ for (;;) {
+ /*
+ * Wait for buffer descriptor to become available
+ */
+ if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ /*
+ * Clear old events.
+ */
+ MCF5235_FEC_EIR = MCF5235_FEC_EIR_TXF;
+
+ /*
+ * Wait for buffer descriptor to become available.
+ * Check for buffer descriptors before waiting for the event.
+ * This catches the case when a buffer became available between
+ * the `if' above, and the clearing of the TXF bit in the EIR.
+ */
+ fec_retire_tx_bd(sc);
+ while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ rtems_event_set events;
+ int level;
+
+ rtems_interrupt_disable(level);
+ MCF5235_FEC_EIMR |= MCF5235_FEC_EIMR_TXF;
+ rtems_interrupt_enable(level);
+ sc->txRawWait++;
+ rtems_bsdnet_event_receive(TX_INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ fec_retire_tx_bd(sc);
+ }
+ }
+
+ /*
+ * Don't set the READY flag on the first fragment
+ * until the whole packet has been readied.
+ */
+ status = nAdded ? MCF5235_FEC_TxBD_R : 0;
+
+ /*
+ * The IP fragmentation routine in ip_output
+ * can produce fragments with zero length.
+ */
+ txBd = sc->txBdBase + sc->txBdHead;
+ if (m->m_len) {
+ char *p = mtod(m, char *);
+ /*
+ * Stupid FEC can't handle misaligned data!
+ * Given the way that mbuf's are layed out it should be
+ * safe to shuffle the data down like this.....
+ * Perhaps this code could be improved with a "Duff's Device".
+ */
+ if ((int)p & 0x3) {
+ int l = m->m_len;
+ char *dest = p - ((int)p & 0x3);
+ uint16_t *o = (uint16_t *)dest, *i = (uint16_t *)p;
+ while (l > 0) {
+ *o++ = *i++;
+ l -= sizeof(uint16_t);
+ }
+ p = dest;
+ sc->txRealign++;
+ }
+ txBd->buffer = p;
+ txBd->length = m->m_len;
+ sc->txMbuf[sc->txBdHead] = m;
+ nAdded++;
+ if (++sc->txBdHead == sc->txBdCount) {
+ status |= MCF5235_FEC_TxBD_W;
+ sc->txBdHead = 0;
+ }
+ m = m->m_next;
+ }
+ else {
+ /*
+ * Just toss empty mbufs
+ */
+ struct mbuf *n;
+ MFREE(m, n);
+ m = n;
+ }
+ if (m == NULL) {
+ if (nAdded) {
+ txBd->status = status | MCF5235_FEC_TxBD_R
+ | MCF5235_FEC_TxBD_L
+ | MCF5235_FEC_TxBD_TC;
+ if (nAdded > 1)
+ firstTxBd->status |= MCF5235_FEC_TxBD_R;
+ MCF5235_FEC_TDAR = MCF5235_FEC_TDAR_X_DES_ACTIVE;
+ sc->txBdActiveCount += nAdded;
+ }
+ break;
+ }
+ txBd->status = status;
+ }
+}
+
+void
+fec_txDaemon(void *arg)
+{
+ struct mcf5235_enet_struct *sc = (struct mcf5235_enet_struct *)arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_event_set events;
+
+ for (;;) {
+ /*
+ * Wait for packet
+ */
+ rtems_bsdnet_event_receive(START_TRANSMIT_EVENT,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT,
+ &events);
+
+ /*
+ * Send packets till queue is empty
+ */
+ for (;;) {
+ /*
+ * Get the next mbuf chain to transmit.
+ */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (!m)
+ break;
+ fec_sendpacket(ifp, m);
+ }
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+}
+
+
+/*
+ * Send packet (caller provides header).
+ */
+static void
+mcf5235_enet_start(struct ifnet *ifp)
+{
+ struct mcf5235_enet_struct *sc = ifp->if_softc;
+
+ rtems_bsdnet_event_send(sc->txDaemonTid, START_TRANSMIT_EVENT);
+ ifp->if_flags |= IFF_OACTIVE;
+}
+
+static void
+fec_init(void *arg)
+{
+ struct mcf5235_enet_struct *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ if (sc->txDaemonTid == 0) {
+ /*
+ * Set up hardware
+ */
+ mcf5235_fec_initialize_hardware(sc);
+
+ /*
+ * Start driver tasks
+ */
+ sc->txDaemonTid = rtems_bsdnet_newproc("FECtx", 4096, fec_txDaemon, sc);
+ sc->rxDaemonTid = rtems_bsdnet_newproc("FECrx", 4096, fec_rxDaemon, sc);
+ }
+
+ /*
+ * Set flags appropriately
+ */
+ if (ifp->if_flags & IFF_PROMISC)
+ MCF5235_FEC_RCR |= MCF5235_FEC_RCR_PROM;
+ else
+ MCF5235_FEC_RCR &= ~MCF5235_FEC_RCR_PROM;
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+
+ /*
+ * Enable receiver and transmitter
+ */
+ MCF5235_FEC_ECR = MCF5235_FEC_ECR_ETHER_EN;
+}
+
+
+static void
+fec_stop(struct mcf5235_enet_struct *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ /*
+ * Shut down receiver and transmitter
+ */
+ MCF5235_FEC_ECR = 0x0;
+}
+
+/*
+ * Show interface statistics
+ */
+static void
+enet_stats(struct mcf5235_enet_struct *sc)
+{
+ printf(" Rx Interrupts:%-10lu", sc->rxInterrupts);
+ printf("Rx Packet Count:%-10lu", MCF5235_FEC_RMON_R_PACKETS);
+ printf(" Rx Broadcast:%-10lu\n", MCF5235_FEC_RMON_R_BC_PKT);
+ printf(" Rx Multicast:%-10lu", MCF5235_FEC_RMON_R_MC_PKT);
+ printf("CRC/Align error:%-10lu", MCF5235_FEC_RMON_R_CRC_ALIGN);
+ printf(" Rx Undersize:%-10lu\n", MCF5235_FEC_RMON_R_UNDERSIZE);
+ printf(" Rx Oversize:%-10lu", MCF5235_FEC_RMON_R_OVERSIZE);
+ printf(" Rx Fragment:%-10lu", MCF5235_FEC_RMON_R_FRAG);
+ printf(" Rx Jabber:%-10lu\n", MCF5235_FEC_RMON_R_JAB);
+ printf(" Rx 64:%-10lu", MCF5235_FEC_RMON_R_P64);
+ printf(" Rx 65-127:%-10lu", MCF5235_FEC_RMON_R_P65T0127);
+ printf(" Rx 128-255:%-10lu\n", MCF5235_FEC_RMON_R_P128TO255);
+ printf(" Rx 256-511:%-10lu", MCF5235_FEC_RMON_R_P256TO511);
+ printf(" Rx 511-1023:%-10lu", MCF5235_FEC_RMON_R_P512TO1023);
+ printf(" Rx 1024-2047:%-10lu\n", MCF5235_FEC_RMON_R_P1024TO2047);
+ printf(" Rx >=2048:%-10lu", MCF5235_FEC_RMON_R_GTE2048);
+ printf(" Rx Octets:%-10lu", MCF5235_FEC_RMON_R_OCTETS);
+ printf(" Rx Dropped:%-10lu\n", MCF5235_FEC_IEEE_R_DROP);
+ printf(" Rx frame OK:%-10lu", MCF5235_FEC_IEEE_R_FRAME_OK);
+ printf(" Rx CRC error:%-10lu", MCF5235_FEC_IEEE_R_CRC);
+ printf(" Rx Align error:%-10lu\n", MCF5235_FEC_IEEE_R_ALIGN);
+ printf(" FIFO Overflow:%-10lu", MCF5235_FEC_IEEE_R_MACERR);
+ printf("Rx Pause Frames:%-10lu", MCF5235_FEC_IEEE_R_FDXFC);
+ printf(" Rx Octets OK:%-10lu\n", MCF5235_FEC_IEEE_R_OCTETS_OK);
+ printf(" Tx Interrupts:%-10lu", sc->txInterrupts);
+ printf("Tx Output Waits:%-10lu", sc->txRawWait);
+ printf("Tx Realignments:%-10lu\n", sc->txRealign);
+ printf(" Tx Unaccounted:%-10lu", MCF5235_FEC_RMON_T_DROP);
+ printf("Tx Packet Count:%-10lu", MCF5235_FEC_RMON_T_PACKETS);
+ printf(" Tx Broadcast:%-10lu\n", MCF5235_FEC_RMON_T_BC_PKT);
+ printf(" Tx Multicast:%-10lu", MCF5235_FEC_RMON_T_MC_PKT);
+ printf("CRC/Align error:%-10lu", MCF5235_FEC_RMON_T_CRC_ALIGN);
+ printf(" Tx Undersize:%-10lu\n", MCF5235_FEC_RMON_T_UNDERSIZE);
+ printf(" Tx Oversize:%-10lu", MCF5235_FEC_RMON_T_OVERSIZE);
+ printf(" Tx Fragment:%-10lu", MCF5235_FEC_RMON_T_FRAG);
+ printf(" Tx Jabber:%-10lu\n", MCF5235_FEC_RMON_T_JAB);
+ printf(" Tx Collisions:%-10lu", MCF5235_FEC_RMON_T_COL);
+ printf(" Tx 64:%-10lu", MCF5235_FEC_RMON_T_P64);
+ printf(" Tx 65-127:%-10lu\n", MCF5235_FEC_RMON_T_P65TO127);
+ printf(" Tx 128-255:%-10lu", MCF5235_FEC_RMON_T_P128TO255);
+ printf(" Tx 256-511:%-10lu", MCF5235_FEC_RMON_T_P256TO511);
+ printf(" Tx 511-1023:%-10lu\n", MCF5235_FEC_RMON_T_P512TO1023);
+ printf(" Tx 1024-2047:%-10lu", MCF5235_FEC_RMON_T_P1024TO2047);
+ printf(" Tx >=2048:%-10lu", MCF5235_FEC_RMON_T_P_GTE2048);
+ printf(" Tx Octets:%-10lu\n", MCF5235_FEC_RMON_T_OCTETS);
+ printf(" Tx Dropped:%-10lu", MCF5235_FEC_IEEE_T_DROP);
+ printf(" Tx Frame OK:%-10lu", MCF5235_FEC_IEEE_T_FRAME_OK);
+ printf(" Tx 1 Collision:%-10lu\n", MCF5235_FEC_IEEE_T_1COL);
+ printf("Tx >1 Collision:%-10lu", MCF5235_FEC_IEEE_T_MCOL);
+ printf(" Tx Deferred:%-10lu", MCF5235_FEC_IEEE_T_DEF);
+ printf(" Late Collision:%-10lu\n", MCF5235_FEC_IEEE_T_LCOL);
+ printf(" Excessive Coll:%-10lu", MCF5235_FEC_IEEE_T_EXCOL);
+ printf(" FIFO Underrun:%-10lu", MCF5235_FEC_IEEE_T_MACERR);
+ printf(" Carrier Error:%-10lu\n", MCF5235_FEC_IEEE_T_CSERR);
+ printf(" Tx SQE Error:%-10lu", MCF5235_FEC_IEEE_T_SQE);
+ printf("Tx Pause Frames:%-10lu", MCF5235_FEC_IEEE_T_FDXFC);
+ printf(" Tx Octets OK:%-10lu\n", MCF5235_FEC_IEEE_T_OCTETS_OK);
+}
+
+static int
+fec_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
+{
+ struct mcf5235_enet_struct *sc = ifp->if_softc;
+ int error = 0;
+
+ switch (command) {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ ether_ioctl(ifp, command, data);
+ break;
+
+ case SIOCSIFFLAGS:
+ switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
+ case IFF_RUNNING:
+ fec_stop(sc);
+ break;
+
+ case IFF_UP:
+ fec_init(sc);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ fec_stop(sc);
+ fec_init(sc);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ enet_stats(sc);
+ break;
+
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+int
+rtems_fec_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching )
+{
+ struct mcf5235_enet_struct *sc;
+ struct ifnet *ifp;
+ int mtu;
+ int unitNumber;
+ char *unitName;
+ unsigned char *hwaddr;
+
+ /*
+ * Parse driver name
+ */
+ if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
+ return 0;
+
+ /*
+ * Is driver free?
+ */
+ if ((unitNumber < 0) || (unitNumber >= NIFACES)) {
+ printf("mcf5235: bad FEC unit number.\n");
+ return 0;
+ }
+ sc = &enet_driver[unitNumber];
+ ifp = &sc->arpcom.ac_if;
+ if (ifp->if_softc != NULL) {
+ printf("mcf5235: driver already in use.\n");
+ return 0;
+ }
+
+ /*
+ * Process options
+ */
+ if (config->hardware_address)
+ memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+ else
+ fec_get_mac_address(sc, sc->arpcom.ac_enaddr);
+
+ hwaddr = config->hardware_address;
+ printf("%s%d: mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ unitName, unitNumber,
+ hwaddr[0], hwaddr[1], hwaddr[2],
+ hwaddr[3], hwaddr[4], hwaddr[5]);
+
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+ if (config->rbuf_count)
+ sc->rxBdCount = config->rbuf_count;
+ else
+ sc->rxBdCount = RX_BUF_COUNT;
+ if (config->xbuf_count)
+ sc->txBdCount = config->xbuf_count;
+ else
+ sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
+
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+ /*
+ * Set up network interface values
+ */
+ ifp->if_softc = sc;
+ ifp->if_unit = unitNumber;
+ ifp->if_name = unitName;
+ ifp->if_mtu = mtu;
+ ifp->if_init = fec_init;
+ ifp->if_ioctl = fec_ioctl;
+ ifp->if_start = mcf5235_enet_start;
+ ifp->if_output = ether_output;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ /*
+ * Attach the interface
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ return 1;
+};
+
diff --git a/bsps/m68k/mcf5329/net/network.c b/bsps/m68k/mcf5329/net/network.c
new file mode 100644
index 0000000000..c752f8d669
--- /dev/null
+++ b/bsps/m68k/mcf5329/net/network.c
@@ -0,0 +1,857 @@
+/*
+ * RTEMS/TCPIP driver for MCF5329 Fast Ethernet Controller
+ *
+ * TO DO: Check network stack code -- force longword alignment of all tx mbufs?
+ */
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+
+#include <bsp.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+/*
+ * Number of interfaces supported by this driver
+ */
+#define NIFACES 1
+
+#define FEC_INTC0_TX_VECTOR (64+36)
+#define FEC_INTC0_RX_VECTOR (64+40)
+
+/*
+ * Default number of buffer descriptors set aside for this driver.
+ * The number of transmit buffer descriptors has to be quite large
+ * since a single frame often uses three or more buffer descriptors.
+ */
+#define RX_BUF_COUNT 32
+#define TX_BUF_COUNT 20
+#define TX_BD_PER_BUF 3
+
+#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
+
+/*
+ * RTEMS event used by interrupt handler to signal daemons.
+ * This must *not* be the same event used by the TCP/IP task synchronization.
+ */
+#define TX_INTERRUPT_EVENT RTEMS_EVENT_1
+#define RX_INTERRUPT_EVENT RTEMS_EVENT_1
+
+/*
+ * RTEMS event used to start transmit daemon.
+ * This must not be the same as INTERRUPT_EVENT.
+ */
+#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+
+/*
+ * Receive buffer size -- Allow for a full ethernet packet plus CRC (1518).
+ * Round off to nearest multiple of RBUF_ALIGN.
+ */
+#define MAX_MTU_SIZE 1518
+#define RBUF_ALIGN 4
+#define RBUF_SIZE ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN)
+
+#if (MCLBYTES < RBUF_SIZE)
+# error "Driver must have MCLBYTES > RBUF_SIZE"
+#endif
+
+typedef struct mcf5329BufferDescriptor_
+{
+ volatile uint16_t status;
+ uint16_t length;
+ volatile void *buffer;
+} mcf5329BufferDescriptor_t;
+
+/*
+ * Per-device data
+ */
+struct mcf5329_enet_struct
+{
+ struct arpcom arpcom;
+ struct mbuf **rxMbuf;
+ struct mbuf **txMbuf;
+ int acceptBroadcast;
+ int rxBdCount;
+ int txBdCount;
+ int txBdHead;
+ int txBdTail;
+ int txBdActiveCount;
+ mcf5329BufferDescriptor_t *rxBdBase;
+ mcf5329BufferDescriptor_t *txBdBase;
+ rtems_id rxDaemonTid;
+ rtems_id txDaemonTid;
+
+ /*
+ * Statistics
+ */
+ unsigned long rxInterrupts;
+ unsigned long txInterrupts;
+ unsigned long txRawWait;
+ unsigned long txRealign;
+};
+static struct mcf5329_enet_struct enet_driver[NIFACES];
+
+static rtems_isr mcf5329_fec_rx_interrupt_handler(rtems_vector_number v)
+{
+ MCF_FEC_EIR = MCF_FEC_EIR_RXF;
+ MCF_FEC_EIMR &= ~MCF_FEC_EIMR_RXF;
+ enet_driver[0].rxInterrupts++;
+ rtems_bsdnet_event_send(enet_driver[0].rxDaemonTid, RX_INTERRUPT_EVENT);
+}
+
+static rtems_isr mcf5329_fec_tx_interrupt_handler(rtems_vector_number v)
+{
+ MCF_FEC_EIR = MCF_FEC_EIR_TXF;
+ MCF_FEC_EIMR &= ~MCF_FEC_EIMR_TXF;
+ enet_driver[0].txInterrupts++;
+ rtems_bsdnet_event_send(enet_driver[0].txDaemonTid, TX_INTERRUPT_EVENT);
+}
+
+extern char _CoreSRamBase[];
+
+/*
+ * Allocate buffer descriptors from (non-cached) on-chip static RAM
+ * Ensure 128-bit (16-byte) alignment
+ */
+static mcf5329BufferDescriptor_t *mcf5329_bd_allocate(unsigned int count)
+{
+ static mcf5329BufferDescriptor_t *bdp =
+ (mcf5329BufferDescriptor_t *) _CoreSRamBase;
+ mcf5329BufferDescriptor_t *p = bdp;
+
+ bdp += count;
+ if ((int) bdp & 0xF)
+ bdp =
+ (mcf5329BufferDescriptor_t *) ((char *) bdp + (16 - ((int) bdp & 0xF)));
+ return p;
+}
+
+#if UNUSED
+
+/*
+ * Read MII register
+ * Busy-waits, but transfer time should be short!
+ */
+static int getMII(int phyNumber, int regNumber)
+{
+ MCF_FEC_MMFR = (0x1 << 30) |
+ (0x2 << 28) | (phyNumber << 23) | (regNumber << 18) | (0x2 << 16);
+ while ((MCF_FEC_EIR & MCF_FEC_EIR_MII) == 0) ;
+ MCF_FEC_EIR = MCF_FEC_EIR_MII;
+ return MCF_FEC_MMFR & 0xFFFF;
+}
+#endif
+
+/*
+ * Write MII register
+ * Busy-waits, but transfer time should be short!
+ */
+static void setMII(int phyNumber, int regNumber, int value)
+{
+ MCF_FEC_MMFR = (0x1 << 30) |
+ (0x1 << 28) |
+ (phyNumber << 23) | (regNumber << 18) | (0x2 << 16) | (value & 0xFFFF);
+ while ((MCF_FEC_EIR & MCF_FEC_EIR_MII) == 0) ;
+ MCF_FEC_EIR = MCF_FEC_EIR_MII;
+}
+
+static void mcf5329_fec_initialize_hardware(struct mcf5329_enet_struct *sc)
+{
+ int i;
+ const unsigned char *hwaddr = 0;
+ rtems_status_code status;
+ rtems_isr_entry old_handler;
+ uint32_t clock_speed = bsp_get_BUS_clock_speed();
+
+ /*
+ * Issue reset to FEC
+ */
+ MCF_FEC_ECR = MCF_FEC_ECR_RESET;
+ rtems_task_wake_after(1);
+ MCF_FEC_ECR = 0;
+
+ /*
+ * Configuration of I/O ports is done outside of this function
+ */
+#if 0
+ imm->gpio.pbcnt |= MCF_GPIO_PBCNT_SET_FEC; /* Set up port b FEC pins */
+#endif
+
+ /*
+ * Set our physical address
+ */
+ hwaddr = sc->arpcom.ac_enaddr;
+ MCF_FEC_PALR = (hwaddr[0] << 24) | (hwaddr[1] << 16) |
+ (hwaddr[2] << 8) | (hwaddr[3] << 0);
+ MCF_FEC_PAUR = (hwaddr[4] << 24) | (hwaddr[5] << 16);
+
+ /*
+ * Clear the hash table
+ */
+ MCF_FEC_GAUR = 0;
+ MCF_FEC_GALR = 0;
+
+ /*
+ * Set up receive buffer size
+ */
+ MCF_FEC_EMRBR = 1520; /* Standard Ethernet */
+
+ /*
+ * Allocate mbuf pointers
+ */
+ sc->rxMbuf = malloc(sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
+ sc->txMbuf = malloc(sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
+ if (!sc->rxMbuf || !sc->txMbuf)
+ rtems_panic("No memory for mbuf pointers");
+
+ /*
+ * Set receiver and transmitter buffer descriptor bases
+ */
+ sc->rxBdBase = mcf5329_bd_allocate(sc->rxBdCount);
+ sc->txBdBase = mcf5329_bd_allocate(sc->txBdCount);
+ MCF_FEC_ERDSR = (int) sc->rxBdBase;
+ MCF_FEC_ETDSR = (int) sc->txBdBase;
+
+ /*
+ * Set up Receive Control Register:
+ * Not promiscuous
+ * MII mode
+ * Full duplex
+ * No loopback
+ */
+ MCF_FEC_RCR = MCF_FEC_RCR_MAX_FL(MAX_MTU_SIZE) | MCF_FEC_RCR_MII_MODE;
+
+ /*
+ * Set up Transmit Control Register:
+ * Full duplex
+ * No heartbeat
+ */
+ MCF_FEC_TCR = MCF_FEC_TCR_FDEN;
+
+ /*
+ * Initialize statistic counters
+ */
+ MCF_FEC_MIBC = MCF_FEC_MIBC_MIB_DISABLE;
+ {
+ vuint32 *vuip = &MCF_FEC_RMON_T_DROP;
+
+ while (vuip <= &MCF_FEC_IEEE_R_OCTETS_OK)
+ *vuip++ = 0;
+ }
+ MCF_FEC_MIBC = 0;
+
+ /*
+ * Set MII speed to <= 2.5 MHz
+ */
+ i = (clock_speed + 5000000 - 1) / 5000000;
+ MCF_FEC_MSCR = MCF_FEC_MSCR_MII_SPEED(i);
+
+ /*
+ * Set PHYS to 100 Mb/s, full duplex
+ */
+ setMII(1, 0, 0x2100);
+
+ /*
+ * Set up receive buffer descriptors
+ */
+ for (i = 0; i < sc->rxBdCount; i++)
+ (sc->rxBdBase + i)->status = 0;
+
+ /*
+ * Set up transmit buffer descriptors
+ */
+ for (i = 0; i < sc->txBdCount; i++) {
+ sc->txBdBase[i].status = 0;
+ sc->txMbuf[i] = NULL;
+ }
+ sc->txBdHead = sc->txBdTail = 0;
+ sc->txBdActiveCount = 0;
+
+ /*
+ * Set up interrupts
+ */
+ status =
+ rtems_interrupt_catch(mcf5329_fec_tx_interrupt_handler,
+ FEC_INTC0_TX_VECTOR, &old_handler);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic("Can't attach MCF FEC TX interrupt handler: %s\n",
+ rtems_status_text(status));
+ status =
+ rtems_interrupt_catch(mcf5329_fec_rx_interrupt_handler,
+ FEC_INTC0_RX_VECTOR, &old_handler);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic("Can't attach MCF FEC RX interrupt handler: %s\n",
+ rtems_status_text(status));
+ MCF_INTC0_ICR36 = MCF_INTC_ICR_IL(FEC_IRQ_LEVEL);
+ MCF_INTC0_IMRH &= ~(MCF_INTC_IMRH_INT_MASK36);
+ MCF_INTC0_ICR40 = MCF_INTC_ICR_IL(FEC_IRQ_LEVEL);
+ MCF_INTC0_IMRH &= ~(MCF_INTC_IMRH_INT_MASK40);
+}
+
+/*
+ * Get the MAC address from the hardware.
+ */
+static void
+fec_get_mac_address(volatile struct mcf5329_enet_struct *sc,
+ unsigned char *hwaddr)
+{
+ unsigned long addr;
+
+ addr = MCF_FEC_PALR;
+
+ hwaddr[0] = (addr >> 24) & 0xff;
+ hwaddr[1] = (addr >> 16) & 0xff;
+ hwaddr[2] = (addr >> 8) & 0xff;
+ hwaddr[3] = (addr >> 0) & 0xff;
+
+ addr = MCF_FEC_PAUR;
+
+ hwaddr[4] = (addr >> 24) & 0xff;
+ hwaddr[5] = (addr >> 16) & 0xff;
+}
+
+/*
+ * Soak up buffer descriptors that have been sent.
+ */
+static void fec_retire_tx_bd(volatile struct mcf5329_enet_struct *sc)
+{
+ struct mbuf *m, *n;
+
+ while ((sc->txBdActiveCount != 0)
+ && ((sc->txBdBase[sc->txBdTail].status & MCF_FEC_TxBD_R) == 0)) {
+ m = sc->txMbuf[sc->txBdTail];
+ MFREE(m, n);
+ if (++sc->txBdTail == sc->txBdCount)
+ sc->txBdTail = 0;
+ sc->txBdActiveCount--;
+ }
+}
+
+static void fec_rxDaemon(void *arg)
+{
+ volatile struct mcf5329_enet_struct *sc =
+ (volatile struct mcf5329_enet_struct *) arg;
+ struct ifnet *ifp = (struct ifnet *) &sc->arpcom.ac_if;
+ struct mbuf *m;
+ volatile uint16_t status;
+ volatile mcf5329BufferDescriptor_t *rxBd;
+ int rxBdIndex;
+
+ /*
+ * Allocate space for incoming packets and start reception
+ */
+ for (rxBdIndex = 0;;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+ MGETHDR(m, M_WAIT, MT_DATA);
+ MCLGET(m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->buffer = mtod(m, void *);
+
+ rxBd->status = MCF_FEC_RxBD_E;
+ if (++rxBdIndex == sc->rxBdCount) {
+ rxBd->status |= MCF_FEC_RxBD_W;
+ break;
+ }
+ }
+
+ /*
+ * Input packet handling loop
+ */
+ /* Indicate we have some ready buffers available */
+ MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
+
+ rxBdIndex = 0;
+ for (;;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+
+ /*
+ * Wait for packet if there's not one ready
+ */
+ if ((status = rxBd->status) & MCF_FEC_RxBD_E) {
+ /*
+ * Clear old events.
+ */
+ MCF_FEC_EIR = MCF_FEC_EIR_RXF;
+
+ /*
+ * Wait for packet to arrive.
+ * Check the buffer descriptor before waiting for the event.
+ * This catches the case when a packet arrives between the
+ * `if' above, and the clearing of the RXF bit in the EIR.
+ */
+ while ((status = rxBd->status) & MCF_FEC_RxBD_E) {
+ rtems_event_set events;
+ int level;
+
+ rtems_interrupt_disable(level);
+ MCF_FEC_EIMR |= MCF_FEC_EIMR_RXF;
+ rtems_interrupt_enable(level);
+ rtems_bsdnet_event_receive(RX_INTERRUPT_EVENT,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT, &events);
+ }
+ }
+
+ /*
+ * Check that packet is valid
+ */
+ if (status & MCF_FEC_RxBD_L) {
+ /*
+ * Pass the packet up the chain.
+ * FIXME: Packet filtering hook could be done here.
+ */
+ struct ether_header *eh;
+ int len = rxBd->length - sizeof(uint32_t);
+
+ m = sc->rxMbuf[rxBdIndex];
+
+ rtems_cache_invalidate_multiple_data_lines(m->m_data, len);
+
+ m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);
+ eh = mtod(m, struct ether_header *);
+ m->m_data += sizeof(struct ether_header);
+ ether_input(ifp, eh, m);
+
+ /*
+ * Allocate a new mbuf
+ */
+ MGETHDR(m, M_WAIT, MT_DATA);
+ MCLGET(m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->buffer = mtod(m, void *);
+ }
+
+ /*
+ * Reenable the buffer descriptor
+ */
+ rxBd->status = (status & MCF_FEC_RxBD_W) | MCF_FEC_RxBD_E;
+ MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;
+
+ /*
+ * Move to next buffer descriptor
+ */
+ if (++rxBdIndex == sc->rxBdCount)
+ rxBdIndex = 0;
+ }
+}
+
+static void fec_sendpacket(struct ifnet *ifp, struct mbuf *m)
+{
+ struct mcf5329_enet_struct *sc = ifp->if_softc;
+ volatile mcf5329BufferDescriptor_t *firstTxBd, *txBd;
+ uint16_t status;
+ int nAdded;
+
+ /*
+ * Free up buffer descriptors
+ */
+ fec_retire_tx_bd(sc);
+
+ /*
+ * Set up the transmit buffer descriptors.
+ * No need to pad out short packets since the
+ * hardware takes care of that automatically.
+ * No need to copy the packet to a contiguous buffer
+ * since the hardware is capable of scatter/gather DMA.
+ */
+ nAdded = 0;
+ firstTxBd = sc->txBdBase + sc->txBdHead;
+
+ for (;;) {
+ /*
+ * Wait for buffer descriptor to become available
+ */
+ if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ /*
+ * Clear old events.
+ */
+ MCF_FEC_EIR = MCF_FEC_EIR_TXF;
+
+ /*
+ * Wait for buffer descriptor to become available.
+ * Check for buffer descriptors before waiting for the event.
+ * This catches the case when a buffer became available between
+ * the `if' above, and the clearing of the TXF bit in the EIR.
+ */
+ fec_retire_tx_bd(sc);
+ while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ rtems_event_set events;
+ int level;
+
+ rtems_interrupt_disable(level);
+ MCF_FEC_EIMR |= MCF_FEC_EIMR_TXF;
+ rtems_interrupt_enable(level);
+ sc->txRawWait++;
+ rtems_bsdnet_event_receive(TX_INTERRUPT_EVENT,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT, &events);
+ fec_retire_tx_bd(sc);
+ }
+ }
+
+ /*
+ * Don't set the READY flag on the first fragment
+ * until the whole packet has been readied.
+ */
+ status = nAdded ? MCF_FEC_TxBD_R : 0;
+
+ /*
+ * The IP fragmentation routine in ip_output
+ * can produce fragments with zero length.
+ */
+ txBd = sc->txBdBase + sc->txBdHead;
+ if (m->m_len) {
+ char *p = mtod(m, char *);
+
+ /*
+ * Stupid FEC can't handle misaligned data!
+ * Given the way that mbuf's are layed out it should be
+ * safe to shuffle the data down like this.....
+ * Perhaps this code could be improved with a "Duff's Device".
+ */
+ if ((int) p & 0x3) {
+ int l = m->m_len;
+ char *dest = p - ((int) p & 0x3);
+ uint16_t *o = (uint16_t *) dest, *i = (uint16_t *) p;
+
+ while (l > 0) {
+ *o++ = *i++;
+ l -= sizeof(uint16_t);
+ }
+ p = dest;
+ sc->txRealign++;
+ }
+
+ txBd->buffer = p;
+ txBd->length = m->m_len;
+
+ rtems_cache_flush_multiple_data_lines(txBd->buffer, txBd->length);
+
+ sc->txMbuf[sc->txBdHead] = m;
+ nAdded++;
+ if (++sc->txBdHead == sc->txBdCount) {
+ status |= MCF_FEC_TxBD_W;
+ sc->txBdHead = 0;
+ }
+ m = m->m_next;
+ } else {
+ /*
+ * Just toss empty mbufs
+ */
+ struct mbuf *n;
+
+ MFREE(m, n);
+ m = n;
+ }
+ if (m == NULL) {
+ if (nAdded) {
+ txBd->status = status | MCF_FEC_TxBD_R
+ | MCF_FEC_TxBD_L | MCF_FEC_TxBD_TC;
+ if (nAdded > 1)
+ firstTxBd->status |= MCF_FEC_TxBD_R;
+ MCF_FEC_TDAR = MCF_FEC_TDAR_X_DES_ACTIVE;
+ sc->txBdActiveCount += nAdded;
+ }
+ break;
+ }
+ txBd->status = status;
+ }
+}
+
+void fec_txDaemon(void *arg)
+{
+ struct mcf5329_enet_struct *sc = (struct mcf5329_enet_struct *) arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_event_set events;
+
+ for (;;) {
+ /*
+ * Wait for packet
+ */
+ rtems_bsdnet_event_receive(START_TRANSMIT_EVENT,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT, &events);
+
+ /*
+ * Send packets till queue is empty
+ */
+ for (;;) {
+ /*
+ * Get the next mbuf chain to transmit.
+ */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (!m)
+ break;
+ fec_sendpacket(ifp, m);
+ }
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+}
+
+/*
+ * Send packet (caller provides header).
+ */
+static void mcf5329_enet_start(struct ifnet *ifp)
+{
+ struct mcf5329_enet_struct *sc = ifp->if_softc;
+
+ rtems_bsdnet_event_send(sc->txDaemonTid, START_TRANSMIT_EVENT);
+ ifp->if_flags |= IFF_OACTIVE;
+}
+
+static void fec_init(void *arg)
+{
+ struct mcf5329_enet_struct *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ if (sc->txDaemonTid == 0) {
+ /*
+ * Set up hardware
+ */
+ mcf5329_fec_initialize_hardware(sc);
+
+ /*
+ * Start driver tasks
+ */
+ sc->txDaemonTid = rtems_bsdnet_newproc("FECtx", 4096, fec_txDaemon, sc);
+ sc->rxDaemonTid = rtems_bsdnet_newproc("FECrx", 4096, fec_rxDaemon, sc);
+ }
+
+ /*
+ * Set flags appropriately
+ */
+ if (ifp->if_flags & IFF_PROMISC)
+ MCF_FEC_RCR |= MCF_FEC_RCR_PROM;
+ else
+ MCF_FEC_RCR &= ~MCF_FEC_RCR_PROM;
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+
+ /*
+ * Enable receiver and transmitter
+ */
+ MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
+}
+
+static void fec_stop(struct mcf5329_enet_struct *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ /*
+ * Shut down receiver and transmitter
+ */
+ MCF_FEC_ECR = 0x0;
+}
+
+/*
+ * Show interface statistics
+ */
+static void enet_stats(struct mcf5329_enet_struct *sc)
+{
+ printf(" Rx Interrupts:%-10lu", sc->rxInterrupts);
+ printf("Rx Packet Count:%-10lu", MCF_FEC_RMON_R_PACKETS);
+ printf(" Rx Broadcast:%-10lu\n", MCF_FEC_RMON_R_BC_PKT);
+ printf(" Rx Multicast:%-10lu", MCF_FEC_RMON_R_MC_PKT);
+ printf("CRC/Align error:%-10lu", MCF_FEC_RMON_R_CRC_ALIGN);
+ printf(" Rx Undersize:%-10lu\n", MCF_FEC_RMON_R_UNDERSIZE);
+ printf(" Rx Oversize:%-10lu", MCF_FEC_RMON_R_OVERSIZE);
+ printf(" Rx Fragment:%-10lu", MCF_FEC_RMON_R_FRAG);
+ printf(" Rx Jabber:%-10lu\n", MCF_FEC_RMON_R_JAB);
+ printf(" Rx 64:%-10lu", MCF_FEC_RMON_R_P64);
+ printf(" Rx 65-127:%-10lu", MCF_FEC_RMON_R_P65TO127);
+ printf(" Rx 128-255:%-10lu\n", MCF_FEC_RMON_R_P128TO255);
+ printf(" Rx 256-511:%-10lu", MCF_FEC_RMON_R_P256TO511);
+ printf(" Rx 511-1023:%-10lu", MCF_FEC_RMON_R_512TO1023);
+ printf(" Rx 1024-2047:%-10lu\n", MCF_FEC_RMON_R_1024TO2047);
+ printf(" Rx >=2048:%-10lu", MCF_FEC_RMON_R_P_GTE2048);
+ printf(" Rx Octets:%-10lu", MCF_FEC_RMON_R_OCTETS);
+ printf(" Rx Dropped:%-10lu\n", MCF_FEC_IEEE_R_DROP);
+ printf(" Rx frame OK:%-10lu", MCF_FEC_IEEE_R_FRAME_OK);
+ printf(" Rx CRC error:%-10lu", MCF_FEC_IEEE_R_CRC);
+ printf(" Rx Align error:%-10lu\n", MCF_FEC_IEEE_R_ALIGN);
+ printf(" FIFO Overflow:%-10lu", MCF_FEC_IEEE_R_MACERR);
+ printf("Rx Pause Frames:%-10lu", MCF_FEC_IEEE_R_FDXFC);
+ printf(" Rx Octets OK:%-10lu\n", MCF_FEC_IEEE_R_OCTETS_OK);
+ printf(" Tx Interrupts:%-10lu", sc->txInterrupts);
+ printf("Tx Output Waits:%-10lu", sc->txRawWait);
+ printf("Tx Realignments:%-10lu\n", sc->txRealign);
+ printf(" Tx Unaccounted:%-10lu", MCF_FEC_RMON_T_DROP);
+ printf("Tx Packet Count:%-10lu", MCF_FEC_RMON_T_PACKETS);
+ printf(" Tx Broadcast:%-10lu\n", MCF_FEC_RMON_T_BC_PKT);
+ printf(" Tx Multicast:%-10lu", MCF_FEC_RMON_T_MC_PKT);
+ printf("CRC/Align error:%-10lu", MCF_FEC_RMON_T_CRC_ALIGN);
+ printf(" Tx Undersize:%-10lu\n", MCF_FEC_RMON_T_UNDERSIZE);
+ printf(" Tx Oversize:%-10lu", MCF_FEC_RMON_T_OVERSIZE);
+ printf(" Tx Fragment:%-10lu", MCF_FEC_RMON_T_FRAG);
+ printf(" Tx Jabber:%-10lu\n", MCF_FEC_RMON_T_JAB);
+ printf(" Tx Collisions:%-10lu", MCF_FEC_RMON_T_COL);
+ printf(" Tx 64:%-10lu", MCF_FEC_RMON_T_P64);
+ printf(" Tx 65-127:%-10lu\n", MCF_FEC_RMON_T_P65TO127);
+ printf(" Tx 128-255:%-10lu", MCF_FEC_RMON_T_P128TO255);
+ printf(" Tx 256-511:%-10lu", MCF_FEC_RMON_T_P256TO511);
+ printf(" Tx 511-1023:%-10lu\n", MCF_FEC_RMON_T_P512TO1023);
+ printf(" Tx 1024-2047:%-10lu", MCF_FEC_RMON_T_P1024TO2047);
+ printf(" Tx >=2048:%-10lu", MCF_FEC_RMON_T_P_GTE2048);
+ printf(" Tx Octets:%-10lu\n", MCF_FEC_RMON_T_OCTETS);
+ printf(" Tx Dropped:%-10lu", MCF_FEC_IEEE_T_DROP);
+ printf(" Tx Frame OK:%-10lu", MCF_FEC_IEEE_T_FRAME_OK);
+ printf(" Tx 1 Collision:%-10lu\n", MCF_FEC_IEEE_T_1COL);
+ printf("Tx >1 Collision:%-10lu", MCF_FEC_IEEE_T_MCOL);
+ printf(" Tx Deferred:%-10lu", MCF_FEC_IEEE_T_DEF);
+ printf(" Late Collision:%-10lu\n", MCF_FEC_IEEE_T_LCOL);
+ printf(" Excessive Coll:%-10lu", MCF_FEC_IEEE_T_EXCOL);
+ printf(" FIFO Underrun:%-10lu", MCF_FEC_IEEE_T_MACERR);
+ printf(" Carrier Error:%-10lu\n", MCF_FEC_IEEE_T_CSERR);
+ printf(" Tx SQE Error:%-10lu", MCF_FEC_IEEE_T_SQE);
+ printf("Tx Pause Frames:%-10lu", MCF_FEC_IEEE_T_FDXFC);
+ printf(" Tx Octets OK:%-10lu\n", MCF_FEC_IEEE_T_OCTETS_OK);
+}
+
+static int fec_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
+{
+ struct mcf5329_enet_struct *sc = ifp->if_softc;
+ int error = 0;
+
+ switch (command) {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ ether_ioctl(ifp, command, data);
+ break;
+
+ case SIOCSIFFLAGS:
+ switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
+ case IFF_RUNNING:
+ fec_stop(sc);
+ break;
+
+ case IFF_UP:
+ fec_init(sc);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ fec_stop(sc);
+ fec_init(sc);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ enet_stats(sc);
+ break;
+
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+int
+rtems_fec_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching)
+{
+ struct mcf5329_enet_struct *sc;
+ struct ifnet *ifp;
+ int mtu;
+ int unitNumber;
+ char *unitName;
+ unsigned char *hwaddr;
+
+ /*
+ * Parse driver name
+ */
+ if ((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0)
+ return 0;
+
+ /*
+ * Is driver free?
+ */
+ if ((unitNumber < 0) || (unitNumber >= NIFACES)) {
+ printf("mcf5329: bad FEC unit number.\n");
+ return 0;
+ }
+ sc = &enet_driver[unitNumber];
+ ifp = &sc->arpcom.ac_if;
+ if (ifp->if_softc != NULL) {
+ printf("mcf5329: driver already in use.\n");
+ return 0;
+ }
+
+ /*
+ * Process options
+ */
+ if (config->hardware_address)
+ memcpy(sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+ else
+ fec_get_mac_address(sc, sc->arpcom.ac_enaddr);
+
+ hwaddr = config->hardware_address;
+ printf("%s%d: mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ unitName, unitNumber,
+ hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
+
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+ if (config->rbuf_count)
+ sc->rxBdCount = config->rbuf_count;
+ else
+ sc->rxBdCount = RX_BUF_COUNT;
+ if (config->xbuf_count)
+ sc->txBdCount = config->xbuf_count;
+ else
+ sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
+
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+ /*
+ * Set up network interface values
+ */
+ ifp->if_softc = sc;
+ ifp->if_unit = unitNumber;
+ ifp->if_name = unitName;
+ ifp->if_mtu = mtu;
+ ifp->if_init = fec_init;
+ ifp->if_ioctl = fec_ioctl;
+ ifp->if_start = mcf5329_enet_start;
+ ifp->if_output = ether_output;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ /*
+ * Attach the interface
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ return 1;
+};
diff --git a/bsps/m68k/mvme167/net/network.c b/bsps/m68k/mvme167/net/network.c
new file mode 100644
index 0000000000..06bcbfa84a
--- /dev/null
+++ b/bsps/m68k/mvme167/net/network.c
@@ -0,0 +1,3099 @@
+/* network.c: An 82596 ethernet driver for rtems-bsd.
+ */
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+#define KERNEL
+
+/*
+ * Selectively define to debug the network driver. If you define any of these
+ * you must run with polled console I/O.
+ */
+
+/*
+#define DBG_ADD_CMD
+#define DBG_WAIT
+#define DBG_SEND
+#define DBG_MEM
+#define DBG_SELFTEST_CMD
+#define DBG_DUMP_CMD
+#define DBG_RESET
+#define DBG_ATTACH
+#define DBG_START
+#define DBG_INIT
+#define DBG_STOP
+#define DBG_RX
+#define DBG_ISR
+#define DBG_IOCTL
+#define DBG_STAT
+#define DBG_PACKETS
+*/
+
+#define IGNORE_SPURIOUS_IRQ
+#define IGNORE_NO_RFA
+#define IGNORE_MULTIPLE_RF
+
+/*
+ * Default number of buffer descriptors and buffer sizes.
+ */
+#define RX_BUF_COUNT 15
+#define TX_BUF_COUNT 4
+#define TX_BD_PER_BUF 4
+
+#define RBUF_SIZE 1520
+
+#define UTI_596_ETH_MIN_SIZE 60
+
+#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
+
+/*
+ * RTEMS events
+ */
+#define INTERRUPT_EVENT RTEMS_EVENT_1
+#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+#define NIC_RESET_EVENT RTEMS_EVENT_3
+
+#include <bsp.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <rtems/error.h>
+#include <rtems/bspIo.h>
+#include <rtems/rtems_bsdnet.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/types.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include "uti596.h"
+
+/* If we are running interrupt driven I/O no debug output is printed */
+#if CD2401_IO_MODE == 0
+ #define printk(arglist) do { printk arglist; printk("\r"); } while (0);
+#else
+ #define printk(arglist)
+#endif
+
+#define UTI_596_ASSERT( condition, str ) if (!( condition ) ) { printk((str)) }
+
+/* Types of PORT commands */
+#define UTI596_RESET_PORT_FUNCTION 0
+#define UTI596_SELFTEST_PORT_FUNCTION 1
+#define UTI596_SCP_PORT_FUNCTION 2
+#define UTI596_DUMP_PORT_FUNCTION 3
+
+/* Types of waiting for commands */
+#define UTI596_NO_WAIT 0
+#define UTI596_WAIT_FOR_CU_ACCEPT 1
+#define UTI596_WAIT_FOR_INITIALIZATION 2
+#define UTI596_WAIT_FOR_STAT_C 3
+
+/* Device dependent data structure */
+static uti596_softc_ uti596_softc;
+
+/* Globals */
+int count_rx = 0;
+static int scbStatus;
+static rtems_status_code sc;
+static i596_cmd *pIsrCmd;
+static i596_rfd *pIsrRfd;
+
+/*
+ * Initial 596 configuration
+ */
+char uti596initSetup[] = {
+ 0x0E, /* Byte 0: length, prefetch off ( no RBD's ) */
+ 0xC8, /* Byte 1: fifo to 8, monitor off */
+ 0x40, /* Byte 2: don't save bad frames ( was save= 80, use intel's 40 )*/
+ 0x2E, /* Byte 3: No source address insertion, 8 byte preamble */
+ 0x00, /* Byte 4: priority and backoff defaults */
+ 0x60, /* Byte 5: interframe spacing */
+ 0x00, /* Byte 6: slot time LSB */
+ 0xf2, /* Byte 7: slot time and retries */
+ 0x0C, /* Byte 8: not promisc, enable bcast, tx no crs, crc inserted 32bit, 802.3 framing */
+ 0x08, /* Byte 9: collision detect */
+ 0x40, /* Byte 10: minimum frame length */
+ 0xfb, /* Byte 11: tried C8 same as byte 1 in bits 6-7, else ignored*/
+ 0x00, /* Byte 12: disable full duplex */
+ 0x3f /* Byte 13: no multi IA, backoff enabled */
+};
+
+/* Local Routines */
+
+static unsigned long word_swap ( unsigned long );
+static void * malloc_16byte_aligned ( void **, void ** adjusted_pointer, size_t );
+RTEMS_INLINE_ROUTINE void uti596_writePortFunction ( volatile void *, unsigned long );
+/* currently unused by RTEMS */
+#if 0
+RTEMS_INLINE_ROUTINE void uti596_portReset( void );
+static unsigned long uti596_portSelfTest( i596_selftest * );
+static int uti596_portDump ( i596_dump_result * );
+static void uti596_CU_dump ( i596_dump_result * );
+#endif
+static int uti596_wait ( uti596_softc_ *, uint8_t);
+static int uti596_issueCA ( uti596_softc_ *, uint8_t);
+static void uti596_addCmd ( i596_cmd * );
+static void uti596_addPolledCmd ( i596_cmd * );
+static int uti596_setScpAndScb ( uti596_softc_ * );
+static int uti596_diagnose ( void );
+static int uti596_configure ( uti596_softc_ * );
+static int uti596_IAsetup ( uti596_softc_ * );
+static int uti596_initTBD ( uti596_softc_ * );
+static int uti596_initRFA ( int );
+static void uti596_initMem ( uti596_softc_ * );
+static void uti596_initialize ( uti596_softc_ * );
+static void uti596_initialize_hardware ( uti596_softc_ * );
+static void uti596_reset_hardware ( uti596_softc_ *);
+static void uti596_reset ( void );
+static void uti596_clearListStatus ( i596_rfd * );
+static i596_rfd * uti596_dequeue ( i596_rfd ** );
+static void uti596_append ( i596_rfd ** , i596_rfd * );
+static void uti596_supplyFD ( i596_rfd * );
+static void send_packet ( struct ifnet *, struct mbuf * );
+
+/* Required RTEMS network driver functions and tasks (plus reset daemon) */
+
+static void uti596_start ( struct ifnet * );
+void uti596_init ( void * );
+void uti596_stop ( uti596_softc_ * );
+void uti596_txDaemon ( void * );
+void uti596_rxDaemon ( void * );
+void uti596_resetDaemon( void * );
+rtems_isr uti596_DynamicInterruptHandler ( rtems_vector_number );
+static int uti596_ioctl ( struct ifnet *, u_long, caddr_t );
+void uti596_stats ( uti596_softc_ * );
+
+#ifdef DBG_PACKETS
+static void dumpQ( void );
+static void show_buffers( void );
+static void show_queues( void );
+static void print_eth ( unsigned char * );
+static void print_hdr ( unsigned char * );
+static void print_pkt ( unsigned char * );
+static void print_echo ( unsigned char * );
+#endif
+
+/*
+ * word_swap
+ *
+ * Return a 32 bit value, swapping the upper and lower words first.
+ *
+ * Input parameters:
+ * val - 32 bit value to swap
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * Input value with upper and lower 16-bit words swapped
+ */
+static unsigned long word_swap(
+ unsigned long val
+)
+{
+ return (((val >> 16)&(0x0000ffff)) | ((val << 16)&(0xffff0000)));
+}
+
+/*
+ * malloc_16byte_aligned
+ *
+ * Allocate a block of a least nbytes aligned on a 16-byte boundary.
+ * Clients are responsible to store both the real address and the adjusted
+ * address. The real address must be used to free the block.
+ *
+ * Input parameters:
+ * real_pointer - pointer to a void * pointer in which to store the starting
+ * address of the block. Required for free.
+ * adjusted_pointer - pointer to a void * pointer in which to store the
+ * starting address of the block rounded up to the next
+ * 16 byte boundary.
+ * nbytes - number of bytes of storage requested
+ *
+ * Output parameters:
+ * real_pointer - starting address of the block.
+ * adjusted_pointer - starting address of the block rounded up to the next
+ * 16 byte boundary.
+ *
+ * Return value:
+ * starting address of the block rounded up to the next 16 byte boundary.
+ * NULL if no storage was allocated.
+ */
+static void * malloc_16byte_aligned(
+ void ** real_pointer,
+ void ** adjusted_pointer,
+ size_t nbytes
+)
+{
+ *real_pointer = malloc( nbytes + 0xF, 0, M_NOWAIT );
+ *adjusted_pointer = (void *)(((unsigned long)*real_pointer + 0xF ) & 0xFFFFFFF0 );
+ return *adjusted_pointer;
+}
+
+/*
+ * uti596_scp_alloc
+ *
+ * Allocate a new scp, possibly freeing a previously allocated one.
+ *
+ * Input parameters:
+ * sc - pointer to the global uti596_softc in which to store pointers
+ * to the newly allocated block.
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * Pointer to the newly allocated, 16-byte aligned scp.
+ */
+static i596_scp * uti596_scp_alloc(
+ uti596_softc_ * sc
+)
+{
+ if( sc->base_scp != NULL ) {
+ #ifdef DBG_MEM
+ printk(("uti596_scp_alloc: Already have an SCP at %p\n", sc->base_scp))
+ #endif
+ return sc->pScp;
+ }
+
+ /* allocate enough memory for the Scp block to be aligned on 16 byte boundary */
+ malloc_16byte_aligned( (void *)&(sc->base_scp), (void *)&(sc->pScp), sizeof( i596_scp ) );
+
+ #ifdef DBG_MEM
+ printk(("uti596_scp_alloc: Scp base address is %p\n", sc->base_scp))
+ printk(("uti596_scp_alloc: Scp aligned address is : %p\n",sc->pScp))
+ #endif
+
+ return sc->pScp;
+}
+
+/*
+ * uti596_writePortFunction
+ *
+ * Write the command into the PORT.
+ *
+ * Input parameters:
+ * addr - 16-byte aligned address to write into the PORT.
+ * cmd - 4-bit cmd to write into the PORT
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ *
+ * The Motorola manual swapped the high and low registers.
+ */
+RTEMS_INLINE_ROUTINE void uti596_writePortFunction(
+ volatile void * addr,
+ unsigned long cmd
+)
+{
+ i82596->port_lower = (unsigned short)(((unsigned long)addr & 0xFFF0) | cmd);
+ i82596->port_upper = (unsigned short)(((unsigned long)addr >> 16 ) & 0xFFFF);
+}
+
+/*
+ * uti596_portReset
+ *
+ * Issue a port Reset to the uti596
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+RTEMS_INLINE_ROUTINE void uti596_portReset( void )
+{
+ uti596_writePortFunction( NULL, UTI596_RESET_PORT_FUNCTION );
+}
+
+/* currently unused by RTEMS */
+#if 0
+/*
+ * uti596_portSelfTest
+ *
+ * Perform a self-test. Wait for up to 1 second for the test to
+ * complete. Normally, the test should complete in a very short time,
+ * so busy waiting is not an issue.
+ *
+ * Input parameters:
+ * stp - pointer to a 16-byte aligned uti596_selftest structure.
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * 32-bit result field if successful, -1 otherwise.
+ */
+static unsigned long uti596_portSelfTest(
+ i596_selftest * stp
+)
+{
+ rtems_interval ticks_per_second, start_ticks, end_ticks;
+
+ stp->results = 0xFFFFFFFF;
+ uti596_writePortFunction( stp, UTI596_SELFTEST_PORT_FUNCTION );
+
+ ticks_per_second = rtems_clock_get_ticks_per_second();
+
+ start_ticks = rtems_clock_get_ticks_since_boot();
+ end_ticks = start_ticks + ticks_per_second;
+
+ do {
+ if( stp->results != 0xFFFFFFFF )
+ break;
+ else
+ start_ticks = rtems_clock_get_ticks_since_boot();
+ } while (start_ticks <= end_ticks);
+
+ if (start_ticks > end_ticks ) {
+ #ifdef DBG_SELFTEST_CMD
+ printk(("uti596_selftest: Timed out\n" ))
+ #endif
+ return -1;
+ }
+ else {
+ #ifdef DBG_SELFTEST_CMD
+ printk(("uti596_selftest: Succeeded with signature = 0x%08x, result = 0x%08x\n",
+ stp->signature,
+ stp->results))
+ #endif
+ return stp->results;
+ }
+}
+#endif
+
+/* currently unused by RTEMS */
+#if 0
+/*
+ * uti596_portDump
+ *
+ * Perform a dump Wait for up to 1 second for the test to
+ * complete. Normally, the test should complete in a very short time,
+ * so busy waiting is not an issue.
+ *
+ * Input parameters:
+ * dp - pointer to a 16-byte aligned uti596_dump structure.
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * 16-bit dump_status field if successful, -1 otherwise.
+ */
+static int uti596_portDump(
+ i596_dump_result * dp
+)
+{
+ rtems_interval ticks_per_second, start_ticks, end_ticks;
+
+ dp->dump_status = 0;
+ uti596_writePortFunction( dp, UTI596_DUMP_PORT_FUNCTION );
+
+ ticks_per_second = rtems_clock_get_ticks_per_second();
+ start_ticks = rtems_clock_get_ticks_since_boot();
+ end_ticks = start_ticks + ticks_per_second;
+
+ do {
+ if( dp->dump_status != 0xA006 )
+ break;
+ else
+ start_ticks = rtems_clock_get_ticks_since_boot();
+ } while (start_ticks <= end_ticks);
+
+ if (start_ticks > end_ticks ) {
+ #ifdef DBG_DUMP_CMD
+ printk(("uti596_dump: Timed out with dump at 0x%08x\n", (unsigned long)dp ))
+ #endif
+ return -1;
+ }
+ else {
+ #ifdef DBG_DUMP_CMD
+ printk(("uti596_dump: Succeeded with dump at = 0x%08x\n", (unsigned long)dp ))
+ #endif
+ return dp->dump_status;
+ }
+}
+#endif
+
+/*
+ * uti596_wait
+ *
+ * Wait for a certain condition.
+ *
+ * Input parameters:
+ * sc - pointer to the uti596_softc struct
+ * wait_type - UTI596_NO_WAIT
+ * UTI596_WAIT
+ * UTI596_WAIT_FOR_CU_ACCEPT
+ * UTI596_WAIT_FOR_INITIALIZATION
+ * UTI596_WAIT_FOR_STAT_C
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * 0 if successful, -1 otherwise.
+ */
+static int uti596_wait(
+ uti596_softc_ *sc,
+ uint8_t waitType
+)
+{
+ rtems_interval ticks_per_second, start_ticks, end_ticks;
+
+ ticks_per_second = rtems_clock_get_ticks_per_second();
+ start_ticks = rtems_clock_get_ticks_since_boot();
+ end_ticks = start_ticks + ticks_per_second;
+
+ switch( waitType ) {
+
+ case UTI596_NO_WAIT:
+ return 0;
+
+ case UTI596_WAIT_FOR_CU_ACCEPT:
+ do {
+ if (sc->scb.command == 0)
+ break;
+ else
+
+ start_ticks = rtems_clock_get_ticks_since_boot();
+
+ } while (start_ticks <= end_ticks);
+
+ if( (sc->scb.command != 0) || (start_ticks > end_ticks) ) {
+ printf("i82596 timed out with status %x, cmd %x.\n",
+ sc->scb.status, sc->scb.command);
+ return -1;
+ }
+ else
+ return 0;
+
+ case UTI596_WAIT_FOR_INITIALIZATION:
+ do {
+ if( !sc->iscp.busy )
+ break;
+ else
+ start_ticks = rtems_clock_get_ticks_since_boot();
+ } while (start_ticks <= end_ticks);
+
+ if (start_ticks > end_ticks ) {
+ #ifdef DBG_WAIT
+ printk(("uti596_setScpAndScb: Timed out\n" ))
+ #endif
+ return -1;
+ }
+ else {
+ #ifdef DBG_WAIT
+ printk(("uti596_setScpAndScb: Succeeded\n" ))
+ #endif
+ return 0;
+ }
+
+ case UTI596_WAIT_FOR_STAT_C:
+ do {
+ if( *sc->pCurrent_command_status & STAT_C )
+ break;
+ else
+ start_ticks = rtems_clock_get_ticks_since_boot();
+ } while (start_ticks <= end_ticks);
+
+ if (start_ticks > end_ticks ) {
+ #ifdef DBG_WAIT
+ printk(("uti596_initMem: timed out - STAT_C not obtained\n" ))
+ #endif
+ return -1;
+ }
+ else {
+ #ifdef DBG_WAIT
+ printk(("uti596_initMem: STAT_C obtained OK\n" ))
+ #endif
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/*
+ * uti596_issueCA
+ *
+ * Issue a Channel Attention command. Possibly wait for the
+ * command to start or complete.
+ *
+ * Input parameters:
+ * sc - pointer to the uti596_softc
+ * wait_type - UTI596_NO_WAIT
+ * UTI596_WAIT_BEGIN
+ * UTI596_WAIT_COMPLETION
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * 0 if successful, -1 otherwise.
+ */
+static int uti596_issueCA(
+ uti596_softc_ *sc,
+ uint8_t waitType
+)
+{
+ /* Issue Channel Attention */
+ i82596->chan_attn = 0x00000000;
+
+ return (uti596_wait ( sc, waitType ));
+}
+
+/*
+ * uti596_addCmd
+ *
+ * Add a uti596_cmd onto the end of the CBL command chain,
+ * or to the start if the chain is empty.
+ *
+ * Input parameters:
+ * pCmd - a pointer to the command to be added.
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+static void uti596_addCmd(
+ i596_cmd *pCmd
+)
+{
+ ISR_Level level;
+
+ #ifdef DBG_ADD_CMD
+ printk(("uti596_addCmd: Adding command 0x%x\n", pCmd -> command ))
+ #endif
+
+ /* Mark command as last in list, to return an interrupt */
+ pCmd->command |= (CMD_EOL | CMD_INTR );
+ pCmd->status = 0;
+ pCmd->next = I596_NULL;
+
+ _ISR_Local_disable(level);
+
+ if (uti596_softc.pCmdHead == I596_NULL) {
+ uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = pCmd;
+ uti596_softc.scb.cmd_pointer = word_swap ((unsigned long)pCmd);
+
+ uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT );
+ uti596_softc.scb.command = CUC_START;
+ uti596_issueCA ( &uti596_softc, UTI596_NO_WAIT );
+
+ _ISR_Local_enable(level);
+ }
+ else {
+ uti596_softc.pCmdTail->next = (i596_cmd *) word_swap ((unsigned long)pCmd);
+ uti596_softc.pCmdTail = pCmd;
+ _ISR_Local_enable(level);
+ }
+
+ #ifdef DBG_ADD_CMD
+ printk(("uti596_addCmd: Scb status & command 0x%x 0x%x\n",
+ uti596_softc.scb.status,
+ uti596_softc.scb.command ))
+ #endif
+}
+
+/*
+ * uti596_addPolledCmd
+ *
+ * Add a single uti596_cmd to the end of the command block list
+ * for processing, send a CU_START and wait for its acceptance
+ *
+ * Input parameters:
+ * sc - a pointer to the uti596_softc struct
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+void uti596_addPolledCmd(
+ i596_cmd *pCmd
+)
+{
+
+ #ifdef DBG_ADD_CMD
+ printk(("uti596_addPolledCmd: Adding command 0x%x\n", pCmd -> command ))
+ #endif
+
+ pCmd->status = 0;
+ pCmd->command |= CMD_EOL ; /* only command in list*/
+ pCmd->next = I596_NULL;
+
+ uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT );
+
+ uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = pCmd;
+ uti596_softc.scb.cmd_pointer = word_swap((unsigned long)pCmd);
+ uti596_softc.scb.command = CUC_START;
+ uti596_issueCA ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT );
+
+ uti596_softc.pCmdHead = uti596_softc.pCmdTail = uti596_softc.scb.pCmd = I596_NULL;
+ uti596_softc.scb.cmd_pointer = (unsigned long) I596_NULL;
+
+ #ifdef DBG_ADD_CMD
+ printk(("uti596_addPolledCmd: Scb status & command 0x%x 0x%x\n",
+ uti596_softc.scb.status,
+ uti596_softc.scb.command ))
+ #endif
+}
+
+/* currently unused by RTEMS */
+#if 0
+/*
+ * uti596_CU_dump
+ *
+ * Dump the LANC 82596 registers
+ * The outcome is the same as the portDump() but executed
+ * via the CU instead of via a PORT access.
+ *
+ * Input parameters:
+ * drp - a pointer to a i596_dump_result structure.
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+static void uti596_CU_dump ( i596_dump_result * drp)
+{
+ i596_dump dumpCmd;
+
+ dumpCmd.cmd.command = CmdDump;
+ dumpCmd.cmd.next = I596_NULL;
+ dumpCmd.pData = (char *) drp;
+ uti596_softc.cmdOk = 0;
+ uti596_addCmd ( (i596_cmd *) &dumpCmd );
+
+}
+#endif
+
+#if defined(DBG_STAT) || !defined(IGNORE_NO_RFA)
+/*
+ * uti596_dump_scb
+ *
+ * Dump the system control block
+ * This function expands to nothing when using interrupt driven I/O
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+static void uti596_dump_scb ( void )
+{
+ printk(("status 0x%x\n",uti596_softc.scb.status))
+ printk(("command 0x%x\n",uti596_softc.scb.command))
+ printk(("cmd 0x%x\n",(int)uti596_softc.scb.pCmd))
+ printk(("rfd 0x%x\n",(int)uti596_softc.scb.pRfd))
+ printk(("crc_err 0x%" PRIx32 "\n",uti596_softc.scb.crc_err))
+ printk(("align_err 0x%" PRIx32 "\n",uti596_softc.scb.align_err))
+ printk(("resource_err 0x%" PRIx32 "\n",uti596_softc.scb.resource_err ))
+ printk(("over_err 0x%" PRIx32 "\n",uti596_softc.scb.over_err))
+ printk(("rcvdt_err 0x%" PRIx32 "\n",uti596_softc.scb.rcvdt_err))
+ printk(("short_err 0x%" PRIx32 "\n",uti596_softc.scb.short_err))
+ printk(("t_on 0x%x\n",uti596_softc.scb.t_on))
+ printk(("t_off 0x%x\n",uti596_softc.scb.t_off))
+}
+#endif
+
+/*
+ * uti596_setScpAndScb
+ *
+ * Issue the first channel attention after reset and wait for the busy
+ * field to clear in the iscp.
+ *
+ * Input parameters:
+ * sc - pointer to the global uti596_softc
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * 0 if successful, -1 otherwise.
+ */
+static int uti596_setScpAndScb(
+ uti596_softc_ * sc
+)
+{
+ /* set the busy flag in the iscp */
+ sc->iscp.busy = 1;
+
+ /* the command block list (CBL) is empty */
+ sc->scb.command = 0;
+ sc->scb.cmd_pointer = (unsigned long) I596_NULL; /* all 1's */
+ sc->pCmdHead = sc->scb.pCmd = I596_NULL; /* all 1's */
+
+ uti596_writePortFunction( sc->pScp, UTI596_SCP_PORT_FUNCTION );
+
+ /* Issue CA: pass the scb address to the 596 */
+ return ( uti596_issueCA ( sc, UTI596_WAIT_FOR_INITIALIZATION ) );
+}
+
+/*
+ * uti596_diagnose
+ *
+ * Send a diagnose command to the CU
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * 0 if successful, -1 otherwise
+ */
+static int uti596_diagnose( void )
+{
+ i596_cmd diagnose;
+
+ diagnose.command = CmdDiagnose;
+ diagnose.status = 0;
+ uti596_softc.pCurrent_command_status = (unsigned short *)&diagnose.status;
+ uti596_addPolledCmd(&diagnose);
+ return (uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_STAT_C ));
+
+ #ifdef DBG_INIT
+ printk(("Status diagnostic: 0xa000 is a success ... 0x%2.2x\n", diagnose.status))
+ #endif
+}
+
+/*
+ * uti596_configure
+ *
+ * Send the CU a configure command with the desired
+ * configuration structure
+ *
+ * Input parameters:
+ * sc - a pointer to the uti596_softc struct
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * 0 if successful, -1 otherwise
+ */
+static int uti596_configure (
+ uti596_softc_ * sc
+)
+{
+ sc->set_conf.cmd.command = CmdConfigure;
+ memcpy ( (void *)sc->set_conf.data, uti596initSetup, 14);
+ uti596_addPolledCmd( (i596_cmd *) &sc->set_conf);
+
+ /* Poll for successful command completion */
+ sc->pCurrent_command_status = (unsigned short *)&(sc->set_conf.cmd.status);
+ return ( uti596_wait ( sc, UTI596_WAIT_FOR_STAT_C ) );
+}
+
+/*
+ * uti596_IAsetup
+ *
+ * Send the CU an Individual Address setup command with
+ * the ethernet hardware address
+ *
+ * Input parameters:
+ * sc - a pointer to the uti596_softc struct
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * 0 if successful, -1 otherwise
+ */
+static int uti596_IAsetup (
+ uti596_softc_ * sc
+)
+{
+ int i;
+
+ sc->set_add.cmd.command = CmdSASetup;
+ for ( i=0; i<6; i++) {
+ sc->set_add.data[i]=sc->arpcom.ac_enaddr[i];
+ }
+ sc->cmdOk = 0;
+ uti596_addPolledCmd((i596_cmd *)&sc->set_add);
+
+ /* Poll for successful command completion */
+ sc->pCurrent_command_status = (unsigned short *)&(sc->set_add.cmd.status);
+ return ( uti596_wait ( sc, UTI596_WAIT_FOR_STAT_C ) );
+}
+
+/*
+ * uti596_initTBD
+ *
+ * Initialize transmit buffer descriptors
+ * dynamically allocate mem for the number of tbd's required
+ *
+ * Input parameters:
+ * sc - a pointer to the uti596_softc struct
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * 0 if successful, -1 otherwise
+ */
+static int uti596_initTBD ( uti596_softc_ * sc )
+{
+ int i;
+ i596_tbd *pTbd, *pPrev;
+
+ /* Set up a transmit command with a tbd ready */
+ sc->pLastUnkRFD = I596_NULL;
+ sc->pTxCmd = (i596_tx *) calloc (1,sizeof (struct i596_tx) );
+ sc->pTbd = (i596_tbd *) calloc (1,sizeof (struct i596_tbd) );
+ if ((sc->pTxCmd == NULL) || (sc->pTbd == NULL)) {
+ return -1;
+ }
+ sc->pTxCmd->pTbd = (i596_tbd *) word_swap ((unsigned long) sc->pTbd);
+ sc->pTxCmd->cmd.command = CMD_FLEX|CmdTx;
+ sc->pTxCmd->pad = 0;
+ sc->pTxCmd->count = 0; /* all bytes are in list of TBD's */
+
+ pPrev = pTbd = sc->pTbd;
+
+ /* Allocate a linked list of tbd's each with it's 'next' field written
+ * with upper and lower words swapped (for big endian), and mark the end.
+ */
+ for ( i=0; i<sc->txBdCount; i++) {
+ if ( (pTbd = (i596_tbd *) calloc (1,sizeof (struct i596_tbd) )) == NULL ) {
+ return -1;
+ }
+ pPrev->next = (i596_tbd *) word_swap ((unsigned long) pTbd);
+ pPrev = pTbd;
+ }
+ pTbd->next = I596_NULL;
+ return 0;
+}
+
+/*
+ * uti596_initRFA
+ *
+ * Initialize the Receive Frame Area
+ * dynamically allocate mem for the number of rfd's required
+ *
+ * Input parameters:
+ * sc - a pointer to the uti596_softc struct
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * # of buffer descriptors successfully allocated
+ */
+static int uti596_initRFA( int num )
+{
+ i596_rfd *pRfd;
+ int i = 0;
+
+ #ifdef DBG_INIT
+ printk(("uti596_initRFA: begins\n Requested frame descriptors ... %d.\n", num))
+ #endif
+
+ /*
+ * Create the first RFD in the RFA
+ */
+ pRfd = (i596_rfd *) calloc (1, sizeof (struct i596_rfd));
+ if ( !pRfd ) {
+ printk(("Can't allocate first buffer.\n"))
+ return 0;
+ }
+ else {
+ uti596_softc.countRFD = 1;
+ uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd;
+ }
+
+ /* Create remaining RFDs */
+ for (i = 1; i < num; i++) {
+ pRfd = (i596_rfd *) calloc (1, sizeof (struct i596_rfd) );
+ if ( pRfd != NULL ) {
+ uti596_softc.countRFD++; /* update count */
+ uti596_softc.pEndRFA->next =
+ (i596_rfd *) word_swap ((unsigned long) pRfd); /* write the link */
+ uti596_softc.pEndRFA = pRfd; /* move the end */
+ }
+ else {
+ printk(("Can't allocate all buffers: only %d allocated\n", i))
+ break;
+ }
+ } /* end for */
+
+ uti596_softc.pEndRFA->next = I596_NULL;
+ UTI_596_ASSERT(uti596_softc.countRFD == num,"INIT:WRONG RFD COUNT\n" )
+
+ #ifdef DBG_INIT
+ printk (("uti596_initRFA: Head of RFA is buffer %p \n\
+ uti596_initRFA: End of RFA is buffer %p \n",
+ uti596_softc.pBeginRFA, uti596_softc.pEndRFA ))
+ #endif
+
+ /* Walk and initialize the RFD's */
+ for ( pRfd = uti596_softc.pBeginRFA;
+ pRfd != I596_NULL;
+ pRfd = (i596_rfd *) word_swap ((unsigned long)pRfd->next) )
+ {
+ pRfd->cmd = 0x0000;
+ pRfd->stat = 0x0000;
+ pRfd->pRbd = I596_NULL;
+ pRfd->count = 0; /* number of bytes in buffer: usually less than size */
+ pRfd->size = 1532; /* was 1532; buffer size ( All RBD ) */
+ } /* end for */
+
+ /* mark the last RFD as the last one in the RDL */
+ uti596_softc.pEndRFA -> cmd = CMD_EOL;
+ uti596_softc.pSavedRfdQueue =
+ uti596_softc.pEndSavedQueue = I596_NULL; /* initially empty */
+
+ uti596_softc.savedCount = 0;
+ uti596_softc.nop.cmd.command = CmdNOp; /* initialize the nop command */
+
+ return (i); /* the number of allocated buffers */
+}
+
+/*
+ * uti596_initMem
+ *
+ * Initialize the 82596 memory structures for Tx and Rx
+ * dynamically allocate mem for the number of tbd's required
+ *
+ * Input parameters:
+ * sc - a pointer to the uti596_softc struct
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+void uti596_initMem(
+ uti596_softc_ * sc
+)
+{
+ int i;
+
+ #ifdef DBG_INIT
+ printk(("uti596_initMem: begins\n"))
+ #endif
+
+ sc->resetDone = 0;
+
+ /*
+ * Set up receive frame area (RFA)
+ */
+ i = uti596_initRFA( sc->rxBdCount );
+ if ( i < sc->rxBdCount ) {
+ printk(("init_rfd: only able to allocate %d receive frame descriptors\n", i))
+ }
+
+ /*
+ * Write the SCB with a pointer to the receive frame area
+ * and keep a pointer for our use.
+ */
+ sc->scb.rfd_pointer = word_swap((unsigned long)sc->pBeginRFA);
+ sc->scb.pRfd = sc->pBeginRFA;
+
+ /*
+ * Diagnose the health of the board
+ */
+ uti596_diagnose();
+
+ /*
+ * Configure the 82596
+ */
+ uti596_configure( sc );
+
+ /*
+ * Set up the Individual (hardware) Address
+ */
+ uti596_IAsetup ( sc );
+
+ /*
+ * Initialize the transmit buffer descriptors
+ */
+ uti596_initTBD( sc );
+
+ /* Padding used to fill short tx frames */
+ memset ( RTEMS_DEVOLATILE( char *, sc->zeroes ), 0, 64);
+
+ /* now need ISR */
+ sc->resetDone = 1;
+}
+
+/*
+ * uti596_initialize
+ *
+ * Reset the 82596 and initialize it with a new SCP.
+ *
+ * Input parameters:
+ * sc - pointer to the uti596_softc
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+void uti596_initialize(
+ uti596_softc_ *sc
+)
+{
+ /* Reset the device. Stops it from doing whatever it might be doing. */
+ uti596_portReset();
+
+ /* Get a new System Configuration Pointer */
+ uti596_scp_alloc( sc );
+
+ /* write the SYSBUS: interrupt pin active high, LOCK disabled,
+ * internal triggering, linear mode
+ */
+ sc->pScp->sysbus = 0x44;
+
+ /* provide the iscp to the scp, keep a pointer for our use */
+ sc->pScp->iscp_pointer = word_swap((unsigned long)&sc->iscp);
+ sc->pScp->iscp = &sc->iscp;
+
+ /* provide the scb to the iscp, keep a pointer for our use */
+ sc->iscp.scb_pointer = word_swap((unsigned long)&sc->scb);
+ sc->iscp.scb = &sc->scb;
+
+ #ifdef DBG_INIT
+ printk(("uti596_initialize: Starting i82596.\n"))
+ #endif
+
+ /* Set up the 82596 */
+ uti596_setScpAndScb( sc );
+
+ /* clear the scb command word */
+ sc->scb.command = 0;
+}
+
+/*
+ * uti596_initialize_hardware
+ *
+ * Reset the 82596 and initialize it with a new SCP. Enable bus snooping.
+ * Install the interrupt handlers.
+ *
+ * Input parameters:
+ * sc - pointer to the uti596_softc
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+void uti596_initialize_hardware(
+ uti596_softc_ *sc
+)
+{
+ printk(("uti596_initialize_hardware: begins\n"))
+
+ /* Get the PCCChip2 to assert bus snooping signals on behalf of the i82596 */
+ pccchip2->LANC_berr_ctl = 0x40;
+
+ uti596_initialize( sc );
+
+ /*
+ * Configure interrupt control in PCCchip2
+ */
+ pccchip2->LANC_error = 0xff; /* clear status register */
+ pccchip2->LANC_int_ctl = 0x5d; /* lvl 5, enabled, edge-sensitive rising */
+ pccchip2->LANC_berr_ctl = 0x5d; /* bus error: lvl 5, enabled, snoop control
+ * will supply dirty data and leave dirty data
+ * on read access and sink any data on write
+ */
+ /*
+ * Install the interrupt handler
+ * calls rtems_interrupt_catch
+ */
+ set_vector( uti596_DynamicInterruptHandler, 0x57, 1 );
+
+ /* Initialize the 82596 memory */
+ uti596_initMem(sc);
+
+ #ifdef DBG_INIT
+ printk(("uti596_initialize_hardware: After attach, status of board = 0x%x\n", sc->scb.status ))
+ #endif
+}
+
+/*
+ * uti596_reset_hardware
+ *
+ * Reset the 82596 and initialize it with an SCP.
+ *
+ * Input parameters:
+ * sc - pointer to the uti596_softc
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+void uti596_reset_hardware(
+ uti596_softc_ *sc
+)
+{
+ rtems_status_code status_code;
+ i596_cmd *pCmd;
+
+ pCmd = sc->pCmdHead; /* This is a tx command for sure (99.99999%) */
+
+ /* the command block list (CBL) is empty */
+ sc->scb.cmd_pointer = (unsigned long) I596_NULL; /* all 1's */
+ sc->pCmdHead = sc->scb.pCmd = I596_NULL; /* all 1's */
+
+ #ifdef DBG_RESET
+ printk(("uti596_reset_hardware\n"))
+ #endif
+ uti596_initialize( sc );
+
+ /*
+ * Wake the transmitter if needed.
+ */
+ if ( sc->txDaemonTid && pCmd != I596_NULL ) {
+ printk(("****RESET: wakes transmitter!\n"))
+ status_code = rtems_bsdnet_event_send (sc->txDaemonTid,
+ INTERRUPT_EVENT);
+
+ if ( status_code != RTEMS_SUCCESSFUL ) {
+ printk(("****ERROR:Could NOT send event to tid 0x%" PRIx32 " : %s\n",
+ sc->txDaemonTid, rtems_status_text (status_code) ))
+ }
+ }
+
+ #ifdef DBG_RESET
+ printk(("uti596_reset_hardware: After reset_hardware, status of board = 0x%x\n", sc->scb.status ))
+ #endif
+}
+
+/*
+ * uti596_clearListStatus
+ *
+ * Clear the stat fields for all RFDs
+ *
+ * Input parameters:
+ * pRfd - a pointer to the head of the RFA
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+void uti596_clearListStatus(
+ i596_rfd *pRfd
+)
+{
+ while ( pRfd != I596_NULL ) {
+ pRfd -> stat = 0;
+ pRfd = (i596_rfd *) word_swap((unsigned long)pRfd-> next);
+ }
+}
+
+/*
+ * uti596_reset
+ *
+ * Reset the 82596 and reconfigure
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+void uti596_reset( void )
+{
+ uti596_softc_ *sc = &uti596_softc;
+
+ #ifdef DBG_RESET
+ printk(("uti596_reset: begin\n"))
+ #endif
+
+ /* Wait for the CU to be available, then
+ * reset the ethernet hardware. Must re-config.
+ */
+ sc->resetDone = 0;
+ uti596_wait ( sc, UTI596_WAIT_FOR_CU_ACCEPT );
+ uti596_reset_hardware ( &uti596_softc );
+
+ #ifdef DBG_RESET
+ uti596_diagnose();
+ #endif
+
+ /*
+ * Configure the 82596
+ */
+ uti596_configure( sc );
+
+ /*
+ * Set up the Individual (hardware) Address
+ */
+ uti596_IAsetup ( sc );
+
+ sc->pCmdHead = sc->pCmdTail = sc->scb.pCmd = I596_NULL;
+
+ /* restore the RFA */
+
+ if ( sc->pLastUnkRFD != I596_NULL ) {
+ sc-> pEndRFA = sc->pLastUnkRFD; /* The end position can be updated */
+ sc-> pLastUnkRFD = I596_NULL;
+ }
+
+ sc->pEndRFA->next = (i596_rfd*)word_swap((uint32_t)sc->pSavedRfdQueue);
+ if ( sc->pSavedRfdQueue != I596_NULL ) {
+ sc->pEndRFA = sc->pEndSavedQueue;
+ sc->pSavedRfdQueue = sc->pEndSavedQueue = I596_NULL;
+ sc -> countRFD = sc->rxBdCount ;
+ }
+
+ /* Re-address the head of the RFA in the SCB */
+ sc->scb.pRfd = sc->pBeginRFA;
+ sc->scb.rfd_pointer = word_swap((unsigned long)sc->pBeginRFA);
+
+ /* Clear the status of all RFDs */
+ uti596_clearListStatus( sc->pBeginRFA );
+
+ printk(("uti596_reset: Starting NIC\n"))
+
+ /* Start the receiver */
+ sc->scb.command = RX_START;
+ sc->started = 1; /* assume that the start is accepted */
+ sc->resetDone = 1;
+ uti596_issueCA ( sc, UTI596_WAIT_FOR_CU_ACCEPT );
+
+ UTI_596_ASSERT(sc->pCmdHead == I596_NULL, "Reset: CMD not cleared\n")
+
+ #ifdef DBG_RESET
+ printk(("uti596_reset: completed\n"))
+ #endif
+}
+
+/*
+ * uti596_dequeue
+ *
+ * Remove an RFD from the received fram queue
+ *
+ * Input parameters:
+ * ppQ - a pointer to a i596_rfd pointer
+ *
+ * Output parameters: NONE
+ *
+ * Return value:
+ * pRfd - a pointer to the dequeued RFD
+ */
+i596_rfd * uti596_dequeue(
+ i596_rfd ** ppQ
+)
+{
+ ISR_Level level;
+ i596_rfd * pRfd;
+
+ _ISR_Local_disable(level);
+
+ /* invalid address, or empty queue or emptied queue */
+ if( ppQ == NULL || *ppQ == NULL || *ppQ == I596_NULL) {
+ _ISR_Local_enable(level);
+ return I596_NULL;
+ }
+
+ /*
+ * Point to the dequeued buffer, then
+ * adjust the queue pointer and detach the buffer
+ */
+ pRfd = *ppQ;
+ *ppQ = (i596_rfd *) word_swap ((unsigned long) pRfd->next);
+ pRfd->next = I596_NULL; /* unlink the rfd being returned */
+
+ _ISR_Local_enable(level);
+ return pRfd;
+}
+
+/*
+ * uti596_append
+ *
+ * Remove an RFD buffer from the RFA and tack it on to
+ * the received frame queue for processing.
+ *
+ * Input parameters:
+ * ppQ - a pointer to the queue pointer
+ * pRfd - a pointer to the buffer to be returned
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+
+void uti596_append(
+ i596_rfd ** ppQ,
+ i596_rfd * pRfd
+)
+{
+
+ i596_rfd *p;
+
+ if ( pRfd != NULL && pRfd != I596_NULL) {
+ pRfd -> next = I596_NULL;
+ pRfd -> cmd |= CMD_EOL; /* set EL bit */
+
+ if ( *ppQ == NULL || *ppQ == I596_NULL ) {
+ /* empty list */
+ *ppQ = pRfd;
+ }
+ else {
+ /* walk to the end of the list */
+ for ( p=*ppQ;
+ p->next != I596_NULL;
+ p=(i596_rfd *) word_swap ((unsigned long)p->next) );
+
+ /* append the rfd */
+ p->cmd &= ~CMD_EOL; /* Clear EL bit at end */
+ p->next = (i596_rfd *) word_swap ((unsigned long)pRfd);
+ }
+ }
+ else {
+ printk(("Illegal attempt to append: %p\n", pRfd))
+ }
+}
+
+/*
+ * uti596_supplyFD
+ *
+ * Return a buffer (RFD) to the receive frame area (RFA).
+ * Call with interrupts disabled.
+ *
+ * Input parameters:
+ * pRfd - a pointer to the buffer to be returned
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+void uti596_supplyFD (
+ i596_rfd * pRfd
+)
+{
+ i596_rfd *pLastRfd;
+
+ UTI_596_ASSERT(pRfd != I596_NULL, "Supplying NULL RFD!\n")
+
+ pRfd -> cmd = CMD_EOL;
+ pRfd -> pRbd = I596_NULL;
+ pRfd -> next = I596_NULL;
+ pRfd -> stat = 0x0000; /* clear STAT_C and STAT_B bits */
+
+ /*
+ * Check if the list is empty:
+ */
+ if ( uti596_softc.pBeginRFA == I596_NULL ) {
+
+ /* Start a list with one entry */
+ uti596_softc.pBeginRFA = uti596_softc.pEndRFA = pRfd;
+ UTI_596_ASSERT(uti596_softc.countRFD == 0, "Null begin, but non-zero count\n")
+ if ( uti596_softc.pLastUnkRFD != I596_NULL ) {
+ printk(("LastUnkRFD is NOT NULL!!\n"))
+ }
+ uti596_softc.countRFD = 1;
+ return;
+ }
+
+ /*
+ * Check if the last RFD is used/read by the 596.
+ */
+ pLastRfd = uti596_softc.pEndRFA;
+
+ /* C = complete, B = busy (prefetched) */
+ if ( pLastRfd != I596_NULL && ! (pLastRfd -> stat & ( STAT_C | STAT_B ) )) {
+
+ /*
+ * Not yet too late to add it
+ */
+ pLastRfd -> next = (i596_rfd *) word_swap ((unsigned long)pRfd);
+ pLastRfd -> cmd &= ~CMD_EOL; /* RESET_EL : reset EL bit to 0 */
+ uti596_softc.countRFD++; /* Lets assume we add it successfully
+ If not, the RFD may be used, and may
+ decrement countRFD < 0 !! */
+ /*
+ * Check if the last RFD was used while appending.
+ */
+ if ( pLastRfd -> stat & ( STAT_C | STAT_B ) ) { /* completed or was prefetched */
+ /*
+ * Either the EL bit of the last rfd has been read by the 82596,
+ * and it will stop after reception,( true when RESET_EL not reached ) or
+ * the EL bit was NOT read by the 82596 and it will use the linked
+ * RFD for the next reception. ( true when RESET_EL was reached )
+ * So, it is unknown whether or not the linked rfd will be used.
+ * Therefore, the end of list CANNOT be updated.
+ */
+ UTI_596_ASSERT ( uti596_softc.pLastUnkRFD == I596_NULL, "Too many Unk RFD's\n" )
+ uti596_softc.pLastUnkRFD = pRfd;
+ return;
+ }
+ else {
+ /*
+ * The RFD being added was not touched by the 82596
+ */
+ if (uti596_softc.pLastUnkRFD != I596_NULL ) {
+
+ uti596_append((i596_rfd **)&uti596_softc.pSavedRfdQueue, pRfd); /* Only here! saved Q */
+ uti596_softc.pEndSavedQueue = pRfd;
+ uti596_softc.savedCount++;
+ uti596_softc.countRFD--;
+
+ }
+ else {
+
+ uti596_softc.pEndRFA = pRfd; /* the RFA has been extended */
+
+ if ( ( uti596_softc.scb.status & SCB_STAT_RNR ||
+ uti596_softc.scb.status & RU_NO_RESOURCES ) &&
+ uti596_softc.countRFD > 1 ) {
+
+ /* Ensure that beginRFA is not EOL */
+ uti596_softc.pBeginRFA -> cmd &= ~CMD_EOL;
+
+ UTI_596_ASSERT(uti596_softc.pEndRFA -> next == I596_NULL, "supply: List buggered\n")
+ UTI_596_ASSERT(uti596_softc.pEndRFA -> cmd & CMD_EOL, "supply: No EOL at end.\n")
+ UTI_596_ASSERT(uti596_softc.scb.command == 0, "Supply: scb command must be zero\n")
+
+ #ifdef DBG_MEM
+ printk(("uti596_supplyFD: starting receiver"))
+ #endif
+
+ /* start the receiver */
+ UTI_596_ASSERT(uti596_softc.pBeginRFA != I596_NULL, "rx start w/ NULL begin! \n")
+ uti596_softc.scb.pRfd = uti596_softc.pBeginRFA;
+ uti596_softc.scb.rfd_pointer = word_swap ((unsigned long) uti596_softc.pBeginRFA);
+
+ /* Don't ack RNR! The receiver should be stopped in this case */
+ uti596_softc.scb.command = RX_START | SCB_STAT_RNR;
+
+ UTI_596_ASSERT( !(uti596_softc.scb.status & SCB_STAT_FR),"FRAME RECEIVED INT COMING!\n")
+
+ /* send CA signal */
+ uti596_issueCA ( &uti596_softc, UTI596_NO_WAIT );
+ }
+ }
+ return;
+ }
+ }
+ else {
+ /*
+ * too late , pLastRfd in use ( or NULL ),
+ * in either case, EL bit has been read, and RNR condition will occur
+ */
+ uti596_append( (i596_rfd **)&uti596_softc.pSavedRfdQueue, pRfd); /* save it for RNR */
+
+ uti596_softc.pEndSavedQueue = pRfd; /* reset end of saved queue */
+ uti596_softc.savedCount++;
+
+ return;
+ }
+}
+
+/*
+ * send_packet
+ *
+ * Send a raw ethernet packet, add a
+ * transmit command to the CBL
+ *
+ * Input parameters:
+ * ifp - a pointer to the ifnet structure
+ * m - a pointer to the mbuf being sent
+ *
+ * Output parameters: NONE
+ *
+ * Return value: NONE
+ */
+void send_packet(
+ struct ifnet *ifp, struct mbuf *m
+)
+{
+ i596_tbd *pPrev = I596_NULL;
+ i596_tbd *pRemainingTbdList;
+ i596_tbd *pTbd;
+ struct mbuf *n, *input_m = m;
+ uti596_softc_ *sc = ifp->if_softc;
+ struct mbuf *l = NULL;
+ unsigned int length = 0;
+ rtems_status_code status;
+ int bd_count = 0;
+ rtems_event_set events;
+
+ /*
+ * For all mbufs in the chain,
+ * fill a transmit buffer descriptor for each
+ */
+ pTbd = (i596_tbd*) word_swap ((unsigned long)sc->pTxCmd->pTbd);
+
+ do {
+ if (m->m_len) {
+ /*
+ * Fill in the buffer descriptor
+ */
+ length += m->m_len;
+ pTbd->data = (char *) word_swap ((unsigned long) mtod (m, void *));
+ pTbd->size = m->m_len;
+ pPrev = pTbd;
+ pTbd = (i596_tbd *) word_swap ((unsigned long) pTbd->next);
+ l = m;
+ m = m->m_next;
+ }
+ else {
+ /*
+ * Just toss empty mbufs
+ */
+ MFREE (m, n);
+ m = n;
+ if (l != NULL)
+ l->m_next = m;
+ }
+ } while( m != NULL && ++bd_count < 16 );
+
+ if ( length < UTI_596_ETH_MIN_SIZE ) {
+ pTbd->data = (char *) word_swap ((unsigned long) sc->zeroes); /* add padding to pTbd */
+ pTbd->size = UTI_596_ETH_MIN_SIZE - length; /* zeroes have no effect on the CRC */
+ }
+ else /* Don't use pTbd in the send routine */
+ pTbd = pPrev;
+
+ /* Disconnect the packet from the list of Tbd's */
+ pRemainingTbdList = (i596_tbd *) word_swap ((unsigned long)pTbd->next);
+ pTbd->next = I596_NULL;
+ pTbd->size |= UTI_596_END_OF_FRAME;
+
+ sc->rawsndcnt++;
+
+ #ifdef DBG_SEND
+ printk(("send_packet: sending packet\n"))
+ #endif
+
+ /* Sending Zero length packet: shouldn't happen */
+ if (pTbd->size <= 0) return;
+
+ #ifdef DBG_PACKETS
+ printk (("\nsend_packet: Transmitter adds packet\n"))
+ print_hdr ( sc->pTxCmd->pTbd->data ); /* print the first part */
+ print_pkt ( sc->pTxCmd->pTbd->next->data ); /* print the first part */
+ print_echo (sc->pTxCmd->pTbd->data);
+ #endif
+
+ /* add the command to the output command queue */
+ uti596_addCmd ( (i596_cmd *) sc->pTxCmd );
+
+ /* sleep until the command has been processed or Timeout encountered. */
+ status= rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+
+ if ( status != RTEMS_SUCCESSFUL ) {
+ printk(("Could not sleep %s\n", rtems_status_text(status)))
+ }
+
+ #ifdef DBG_SEND
+ printk(("send_packet: RAW - wake\n"))
+ #endif
+
+ sc->txInterrupts++;
+
+ if ( sc->pTxCmd -> cmd.status & STAT_OK ) {
+ sc->stats.tx_packets++;
+ }
+ else {
+
+ printk(("*** send_packet: Driver Error 0x%x\n", sc->pTxCmd -> cmd.status ))
+
+ sc->stats.tx_errors++;
+ if ( sc->pTxCmd->cmd.status & 0x0020 )
+ sc->stats.tx_retries_exceeded++;
+ if (!(sc->pTxCmd->cmd.status & 0x0040))
+ sc->stats.tx_heartbeat_errors++;
+ if ( sc->pTxCmd->cmd.status & 0x0400 )
+ sc->stats.tx_carrier_errors++;
+ if ( sc->pTxCmd->cmd.status & 0x0800 )
+ sc->stats.collisions++;
+ if ( sc->pTxCmd->cmd.status & 0x1000 )
+ sc->stats.tx_aborted_errors++;
+ } /* end if stat_ok */
+
+ /*
+ * Restore the transmitted buffer descriptor chain.
+ */
+ pTbd -> next = (i596_tbd *) word_swap ((unsigned long)pRemainingTbdList);
+
+ /*
+ * Free the mbufs used by the sender.
+ */
+ m = input_m;
+ while ( m != NULL ) {
+ MFREE(m,n);
+ m = n;
+ }
+}
+
+/***********************************************************************
+ * Function: uti596_attach
+ *
+ * Description:
+ * Configure the driver, and connect to the network stack
+ *
+ * Algorithm:
+ *
+ * Check parameters in the ifconfig structure, and
+ * set driver parameters accordingly.
+ * Initialize required rx and tx buffers.
+ * Link driver data structure onto device list.
+ * Return 1 on successful completion.
+ *
+ ***********************************************************************/
+
+int uti596_attach(
+ struct rtems_bsdnet_ifconfig * pConfig,
+ int attaching
+)
+{
+ uti596_softc_ *sc = &uti596_softc; /* device dependent data structure */
+ struct ifnet * ifp = (struct ifnet *)&sc->arpcom.ac_if; /* ifnet structure */
+ int unitNumber;
+ char *unitName;
+#if defined(mvme167)
+ unsigned char j1; /* State of J1 jumpers */
+ char *pAddr;
+ int addr;
+#endif
+
+ #ifdef DBG_ATTACH
+ printk(("uti596_attach: begins\n"))
+ #endif
+
+ /* The NIC is not started yet */
+ sc->started = 0;
+
+ /* Indicate to ULCS that this is initialized */
+ ifp->if_softc = (void *)sc;
+ sc->pScp = NULL;
+
+ /* Parse driver name */
+ if ((unitNumber = rtems_bsdnet_parse_driver_name (pConfig, &unitName)) < 0)
+ return 0;
+
+ ifp->if_name = unitName;
+ ifp->if_unit = unitNumber;
+
+ /* Assign mtu */
+ if ( pConfig -> mtu )
+ ifp->if_mtu = pConfig -> mtu;
+ else
+ ifp->if_mtu = ETHERMTU;
+
+ /*
+ * Check whether parameters should be obtained from NVRAM. If
+ * yes, and if an IP address, netmask, or ethernet address are
+ * provided in NVRAM, cheat, and stuff them into the ifconfig
+ * structure, OVERRIDING and existing or NULL values.
+ *
+ * Warning: If values are provided in NVRAM, the ifconfig entries
+ * must be NULL because buffer memory allocated to hold the
+ * structure values is unrecoverable and would be lost here.
+ */
+
+#if defined(mvme167)
+ /* Read the J1 header */
+ j1 = (unsigned char)(lcsr->vector_base & 0xFF);
+
+ if ( !(j1 & 0x10) ) {
+ /* Jumper J1-4 is on, configure from NVRAM */
+
+ if ( (addr = nvram->ipaddr) ) {
+ /* We have a non-zero entry, copy the value */
+ if ( (pAddr = malloc ( INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT )) )
+ pConfig->ip_address = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1 );
+ else
+ rtems_panic("Can't allocate ip_address buffer!\n");
+ }
+
+ if ( (addr = nvram->netmask) ) {
+ /* We have a non-zero entry, copy the value */
+ if ( (pAddr = malloc ( INET_ADDR_MAX_BUF_SIZE, 0, M_NOWAIT )) )
+ pConfig->ip_netmask = (char *)inet_ntop(AF_INET, &addr, pAddr, INET_ADDR_MAX_BUF_SIZE -1 );
+ else
+ rtems_panic("Can't allocate ip_netmask buffer!\n");
+ }
+
+ /* Ethernet address requires special handling -- it must be copied into
+ * the arpcom struct. The following if construct serves only to give the
+ * NVRAM parameter the highest priority if J1-4 indicates we are configuring
+ * from NVRAM.
+ *
+ * If the ethernet address is specified in NVRAM, go ahead and copy it.
+ * (ETHER_ADDR_LEN = 6 bytes).
+ */
+ if ( nvram->enaddr[0] || nvram->enaddr[1] || nvram->enaddr[2] ) {
+ /* Anything in the first three bytes indicates a non-zero entry, copy value */
+ memcpy ((void *)sc->arpcom.ac_enaddr, &nvram->enaddr, ETHER_ADDR_LEN);
+ }
+ else if ( pConfig->hardware_address) {
+ /* There is no entry in NVRAM, but there is in the ifconfig struct, so use it. */
+ memcpy ((void *)sc->arpcom.ac_enaddr, pConfig->hardware_address, ETHER_ADDR_LEN);
+ }
+ else {
+ /* There is no ethernet address provided, so it will be read
+ * from BBRAM at $FFFC1F2C by default. [mvme167 manual p. 1-47]
+ */
+ memcpy ((void *)sc->arpcom.ac_enaddr, (char *)0xFFFC1F2C, ETHER_ADDR_LEN);
+ }
+ }
+ else if ( pConfig->hardware_address) {
+ /* We are not configuring from NVRAM (J1-4 is off), and the ethernet address
+ * is given in the ifconfig structure. Copy it.
+ */
+ memcpy ((void *)sc->arpcom.ac_enaddr, pConfig->hardware_address, ETHER_ADDR_LEN);
+ }
+ else
+#endif
+ {
+ /* We are not configuring from NVRAM (J1-4 is off), and there is no ethernet
+ * address provided in the ifconfig struct, so it will be read from BBRAM at
+ * $FFFC1F2C by default. [mvme167 manual p. 1-47]
+ */
+ memcpy ((void *)sc->arpcom.ac_enaddr, (char *)0xFFFC1F2C, ETHER_ADDR_LEN);
+ }
+
+ /* Possibly override default acceptance of broadcast packets */
+ if (pConfig->ignore_broadcast)
+ uti596initSetup[8] |= 0x02;
+
+ /* Assign requested receive buffer descriptor count */
+ if (pConfig->rbuf_count)
+ sc->rxBdCount = pConfig->rbuf_count;
+ else
+ sc->rxBdCount = RX_BUF_COUNT;
+
+ /* Assign requested tx buffer descriptor count */
+ if (pConfig->xbuf_count)
+ sc->txBdCount = pConfig->xbuf_count;
+ else
+ sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
+
+ /* Set up fields in the ifnet structure*/
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+ ifp->if_init = uti596_init;
+ ifp->if_ioctl = uti596_ioctl;
+ ifp->if_start = uti596_start;
+ ifp->if_output = ether_output;
+
+ /* uti596_softc housekeeping */
+ sc->started = 1;
+ sc->pInboundFrameQueue = I596_NULL;
+ sc->scb.command = 0;
+
+ /*
+ * Attach the interface
+ */
+ if_attach (ifp);
+ ether_ifattach (ifp);
+ return 1;
+}
+
+/***********************************************************************
+ * Function: uti596_start
+ *
+ * Description:
+ * start the driver
+ *
+ * Algorithm:
+ * send an event to the tx task
+ * set the if_flags
+ *
+ ***********************************************************************/
+static void uti596_start(
+ struct ifnet *ifp
+)
+{
+ uti596_softc_ *sc = ifp->if_softc;
+
+ #ifdef DBG_START
+ printk(("uti596_start: begins\n"))
+ #endif
+
+ rtems_bsdnet_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
+ ifp->if_flags |= IFF_OACTIVE;
+}
+
+/***********************************************************************
+ * Function: uti596_init
+ *
+ * Description:
+ * driver initialization
+ *
+ * Algorithm:
+ * initialize the 82596
+ * start driver tx and rx tasks, and reset task
+ * send the RX_START command the the RU
+ * set if_flags
+ *
+ *
+ ***********************************************************************/
+void uti596_init(
+ void * arg
+)
+{
+ uti596_softc_ *sc = arg;
+ struct ifnet *ifp = (struct ifnet *)&sc->arpcom.ac_if;
+
+ if (sc->txDaemonTid == 0) {
+
+ /*
+ * Initialize the 82596
+ */
+ #ifdef DBG_INIT
+ printk(("uti596_init: begins\nuti596_init: initializing the 82596...\n"))
+ #endif
+ uti596_initialize_hardware(sc);
+
+ /*
+ * Start driver tasks
+ */
+ #ifdef DBG_INIT
+ printk(("uti596_init: starting driver tasks...\n"))
+ #endif
+ sc->txDaemonTid = rtems_bsdnet_newproc ("UTtx", 2*4096, uti596_txDaemon, (void *)sc);
+ sc->rxDaemonTid = rtems_bsdnet_newproc ("UTrx", 2*4096, uti596_rxDaemon, (void *)sc);
+ sc->resetDaemonTid = rtems_bsdnet_newproc ("UTrt", 2*4096, uti596_resetDaemon, (void *)sc);
+
+ #ifdef DBG_INIT
+ printk(("uti596_init: After attach, status of board = 0x%x\n", sc->scb.status ))
+ #endif
+ }
+
+ /*
+ * In case the ISR discovers there are no resources it reclaims
+ * them and restarts
+ */
+ sc->started = 1;
+
+ /*
+ * Enable receiver
+ */
+ #ifdef DBG_INIT
+ printk(("uti596_init: enabling the reciever...\n" ))
+ #endif
+ sc->scb.command = RX_START;
+ uti596_issueCA ( sc, UTI596_WAIT_FOR_CU_ACCEPT );
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+ #ifdef DBG_INIT
+ printk(("uti596_init: completed.\n"))
+ #endif
+}
+
+/***********************************************************************
+ * Function: uti596stop
+ *
+ * Description:
+ * stop the driver
+ *
+ * Algorithm:
+ * mark driver as not started,
+ * mark transmitter as busy
+ * abort any transmissions/receptions
+ * clean-up all buffers ( RFD's et. al. )
+ *
+ *
+ ***********************************************************************/
+
+/* static */ void uti596_stop(
+ uti596_softc_ *sc
+)
+{
+ struct ifnet *ifp = (struct ifnet *)&sc->arpcom.ac_if;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+ sc->started = 0;
+
+ #ifdef DBG_STOP
+ printk(("uti596stop: %s: Shutting down ethercard, status was %4.4x.\n",
+ uti596_softc.arpcom.ac_if.if_name, uti596_softc.scb.status))
+ #endif
+
+ printk(("Stopping interface\n"))
+ sc->scb.command = CUC_ABORT | RX_ABORT;
+ i82596->chan_attn = 0x00000000;
+}
+
+/***********************************************************************
+ * Function: void uti596_txDaemon
+ *
+ * Description: Transmit task
+ *
+ * Algorithm: Get mbufs to be transmitted, stuff into RFDs, send
+ *
+ ***********************************************************************/
+
+void uti596_txDaemon(
+ void *arg
+)
+{
+ uti596_softc_ *sc = (uti596_softc_ *)arg;
+ struct ifnet *ifp = (struct ifnet *)&sc->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_event_set events;
+
+ for (;;) {
+ /*
+ * Wait for packet from stack
+ */
+ rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT, &events);
+
+ /*
+ * Send packets till queue is empty.
+ * Ensure that irq is on before sending.
+ */
+ for (;;) {
+ /* Get the next mbuf chain to transmit. */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (!m)
+ break;
+
+ send_packet (ifp, m); /* blocks */
+ }
+ ifp->if_flags &= ~IFF_OACTIVE; /* no more to send, mark output inactive */
+ }
+}
+
+/***********************************************************************
+ * Function: uti596_rxDaemon
+ *
+ * Description: Receiver task
+ *
+ * Algorithm: Extract the packet from an RFD, and place into an
+ * mbuf chain. Place the mbuf chain in the network task
+ * queue. Assumes that the frame check sequence is removed
+ * by the 82596.
+ *
+ ***********************************************************************/
+
+/* static */ void uti596_rxDaemon(
+ void *arg
+)
+{
+ uti596_softc_ *sc = (uti596_softc_ *)arg;
+ struct ifnet *ifp = (struct ifnet *)&sc->arpcom.ac_if;
+ struct mbuf *m;
+
+ i596_rfd *pRfd;
+ ISR_Level level;
+ rtems_id tid;
+ rtems_event_set events;
+ struct ether_header *eh;
+
+ int frames = 0;
+
+ #ifdef DBG_RX
+ printk(("uti596_rxDaemon: begin\n"))
+ printk(("&scb = %p, pRfd = %p\n", &sc->scb,sc->scb.pRfd))
+ #endif
+
+ rtems_task_ident (0, 0, &tid);
+
+ for(;;) {
+ /*
+ * Wait for packet.
+ */
+ #ifdef DBG_RX
+ printk(("uti596_rxDaemon: Receiver sleeps\n"))
+ #endif
+
+ rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+
+ #ifdef DBG_RX
+ printk(("uti596_rxDaemon: Receiver wakes\n"))
+ #endif
+ /*
+ * While received frames are available. Note that the frame may be
+ * a fragment, so it is NOT a complete packet.
+ */
+ pRfd = uti596_dequeue( (i596_rfd **)&sc->pInboundFrameQueue);
+ while ( pRfd &&
+ pRfd != I596_NULL &&
+ pRfd -> stat & STAT_C )
+ {
+
+ if ( pRfd->stat & STAT_OK) { /* a good frame */
+ int pkt_len = pRfd->count & 0x3fff; /* the actual # of bytes received */
+
+ #ifdef DBG_RX
+ printk(("uti596_rxDaemon: Good frame, @%p, data @%p length %d\n", pRfd, pRfd -> data , pkt_len))
+ #endif
+ frames++;
+
+ /*
+ * Allocate an mbuf to give to the stack
+ * The format of the data portion of the RFD is:
+ * <ethernet header, payload>.
+ * The FRAME CHECK SEQUENCE / CRC is stripped by the uti596.
+ * This is to be optimized later.... should not have to memcopy!
+ */
+ MGETHDR(m, M_WAIT, MT_DATA);
+ MCLGET(m, M_WAIT);
+
+ m->m_pkthdr.rcvif = ifp;
+ /* move everything into an mbuf */
+ memcpy(m->m_data, (const char *)pRfd->data, pkt_len);
+ m->m_len = m->m_pkthdr.len = pkt_len - sizeof(struct ether_header) - 4;
+
+ /* move the header to an mbuf */
+ eh = mtod (m, struct ether_header *);
+ m->m_data += sizeof(struct ether_header);
+
+ #ifdef DBG_PACKETS
+ {
+ int i;
+ printk(("uti596_rxDaemon: mbuf contains:\n"))
+ print_eth( (char *) (((int)m->m_data)-sizeof(struct ether_header)));
+ for ( i = 0; i<20; i++) {
+ printk(("."))
+ }
+ }
+ #endif
+
+ ether_input (ifp, eh, m);
+
+ } /* end if STAT_OK */
+
+ else {
+ /*
+ * A bad frame is present: Note that this could be the last RFD!
+ */
+ #ifdef DBG_RX
+ printk(("uti596_rxDaemon: Bad frame\n"))
+ #endif
+ /*
+ * FIX ME: use the statistics from the SCB
+ */
+ sc->stats.rx_errors++;
+ if ((sc->scb.pRfd->stat) & 0x0001)
+ sc->stats.collisions++;
+ if ((sc->scb.pRfd->stat) & 0x0080)
+ sc->stats.rx_length_errors++;
+ if ((sc->scb.pRfd->stat) & 0x0100)
+ sc->stats.rx_over_errors++;
+ if ((sc->scb.pRfd->stat) & 0x0200)
+ sc->stats.rx_fifo_errors++;
+ if ((sc->scb.pRfd->stat) & 0x0400)
+ sc->stats.rx_frame_errors++;
+ if ((sc->scb.pRfd->stat) & 0x0800)
+ sc->stats.rx_crc_errors++;
+ if ((sc->scb.pRfd->stat) & 0x1000)
+ sc->stats.rx_length_errors++;
+ }
+
+ UTI_596_ASSERT(pRfd != I596_NULL, "Supplying NULL RFD\n")
+
+ _ISR_Local_disable(level);
+ uti596_supplyFD ( pRfd ); /* Return RFD to RFA. */
+ _ISR_Local_enable(level);
+
+ pRfd = uti596_dequeue( (i596_rfd **)&sc->pInboundFrameQueue); /* grab next frame */
+
+ } /* end while */
+ } /* end for() */
+
+ #ifdef DBG_RX
+ printk (("uti596_rxDaemon: frames ... %d\n", frames))
+ #endif
+}
+
+/***********************************************************************
+ * Function: void uti596_resetDaemon
+ *
+ * Description:
+ ***********************************************************************/
+void uti596_resetDaemon(
+ void *arg
+)
+{
+ uti596_softc_ *sc = (uti596_softc_ *)arg;
+ rtems_event_set events;
+ rtems_time_of_day tm_struct;
+
+ /* struct ifnet *ifp = &sc->arpcom.ac_if; */
+
+ for (;;) {
+ /* Wait for reset event from ISR */
+ rtems_bsdnet_event_receive (NIC_RESET_EVENT,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT, &events);
+
+ rtems_clock_get_tod(&tm_struct);
+ printk(("reset daemon: Resetting NIC @ %" PRIu32 ":%" PRIu32 ":%" PRIu32 " \n",
+ tm_struct.hour, tm_struct.minute, tm_struct.second))
+
+ sc->stats.nic_reset_count++;
+ /* Reinitialize the LANC */
+ rtems_bsdnet_semaphore_obtain ();
+ uti596_reset();
+ rtems_bsdnet_semaphore_release ();
+ }
+}
+
+/***********************************************************************
+ * Function: uti596_DynamicInterruptHandler
+ *
+ * Description:
+ * This is the interrupt handler for the uti596 board
+ *
+ ***********************************************************************/
+
+/* static */ rtems_isr uti596_DynamicInterruptHandler(
+ rtems_vector_number irq
+)
+{
+int fullStatus;
+
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: begins"))
+ #endif
+
+ uti596_wait (&uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT);
+
+ scbStatus = (fullStatus = uti596_softc.scb.status) & 0xf000;
+
+ if ( scbStatus ) {
+ /* acknowledge interrupts */
+
+ /* Write to the ICLR bit in the PCCchip2 control registers to clear
+ * the INT status bit. Clearing INT here *before* sending the CA signal
+ * to the 82596 should ensure that interrupts won't be lost.
+ */
+ pccchip2->LANC_int_ctl |=0x08;
+ pccchip2->LANC_berr_ctl |=0x08;
+
+ /* printk(("***INFO: ACK %x\n", scbStatus))*/
+
+ /* Send the CA signal to acknowledge interrupt */
+ uti596_softc.scb.command = scbStatus;
+ uti596_issueCA ( &uti596_softc, UTI596_NO_WAIT );
+
+ if( uti596_softc.resetDone ) {
+ /* stack is attached */
+ uti596_wait ( &uti596_softc, UTI596_WAIT_FOR_CU_ACCEPT );
+ }
+ else {
+ printk(("***INFO: ACK'd w/o processing. status = %x\n", scbStatus))
+ return;
+ }
+ }
+ else {
+#ifndef IGNORE_SPURIOUS_IRQ
+ printk(("\n***ERROR: Spurious interrupt (full status 0x%x). Resetting...\n", fullStatus))
+ uti596_softc.nic_reset = 1;
+#endif
+ }
+
+ if ( (scbStatus & SCB_STAT_CX) && !(scbStatus & SCB_STAT_CNA) ) {
+ printk(("\n*****ERROR: Command Complete, and CNA available: 0x%x\nResetting...", scbStatus))
+ uti596_softc.nic_reset = 1;
+ return;
+ }
+
+ if ( !(scbStatus & SCB_STAT_CX) && (scbStatus & SCB_STAT_CNA) ) {
+ printk(("\n*****ERROR: CNA, NO CX:0x%x\nResetting...",scbStatus))
+ uti596_softc.nic_reset = 1;
+ return;
+ }
+
+ if ( scbStatus & SCB_CUS_SUSPENDED ) {
+ printk(("\n*****ERROR: Command unit suspended!:0x%x\nResetting...",scbStatus))
+ uti596_softc.nic_reset = 1;
+ return;
+ }
+
+ if ( scbStatus & RU_SUSPENDED ) {
+ printk(("\n*****ERROR: Receive unit suspended!:0x%x\nResetting...",scbStatus))
+ uti596_softc.nic_reset = 1;
+ return;
+ }
+
+ if ( scbStatus & SCB_STAT_RNR ) {
+ printk(("\n*****WARNING: RNR %x\n",scbStatus))
+ if (uti596_softc.pBeginRFA != I596_NULL) {
+ printk(("*****INFO: RFD cmd: %x status:%x\n", uti596_softc.pBeginRFA->cmd,
+ uti596_softc.pBeginRFA->stat))
+ }
+ else {
+ printk(("*****WARNING: RNR condition with NULL BeginRFA\n"))
+ }
+ }
+
+ /*
+ * Receive Unit Control
+ * a frame is received
+ */
+ if ( scbStatus & SCB_STAT_FR ) {
+ uti596_softc.rxInterrupts++;
+
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: Frame received\n"))
+ #endif
+ if ( uti596_softc.pBeginRFA == I596_NULL ||
+ !( uti596_softc.pBeginRFA -> stat & STAT_C)) {
+#ifndef IGNORE_NO_RFA
+ uti596_dump_scb();
+ uti596_softc.nic_reset = 1;
+#endif
+ }
+ else {
+ while ( uti596_softc.pBeginRFA != I596_NULL &&
+ ( uti596_softc.pBeginRFA -> stat & STAT_C)) {
+
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: pBeginRFA != NULL\n"))
+ #endif
+ count_rx ++;
+#ifndef IGNORE_MULTIPLE_RF
+ if ( count_rx > 1) {
+ printk(("****WARNING: Received %i frames on 1 interrupt \n", count_rx))
+ }
+#endif
+ /* Give Received Frame to the ULCS */
+ uti596_softc.countRFD--;
+
+ if ( uti596_softc.countRFD < 0 ) {
+ printk(("ISR: Count < 0 !!! count == %d, beginRFA = %p\n",
+ uti596_softc.countRFD, uti596_softc.pBeginRFA))
+ }
+ uti596_softc.stats.rx_packets++;
+ /* the rfd next link is stored with upper and lower words swapped so read it that way */
+ pIsrRfd = (i596_rfd *) word_swap ((unsigned long)uti596_softc.pBeginRFA->next);
+ /* the append destroys the link */
+ uti596_append( (i596_rfd **)&uti596_softc.pInboundFrameQueue , uti596_softc.pBeginRFA );
+
+ /*
+ * if we have just received the a frame in the last unknown RFD,
+ * then it is certain that the RFA is empty.
+ */
+ if ( uti596_softc.pLastUnkRFD == uti596_softc.pBeginRFA ) {
+ UTI_596_ASSERT(uti596_softc.pLastUnkRFD != I596_NULL,"****ERROR:LastUnk is NULL, begin ptr @ end!\n")
+ uti596_softc.pEndRFA = uti596_softc.pLastUnkRFD = I596_NULL;
+ }
+
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: Wake %#x\n",uti596_softc.rxDaemonTid))
+ #endif
+ sc = rtems_bsdnet_event_send(uti596_softc.rxDaemonTid, INTERRUPT_EVENT);
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ rtems_panic("Can't notify rxDaemon: %s\n",
+ rtems_status_text (sc));
+ }
+ #ifdef DBG_ISR
+ else {
+ printk(("uti596_DynamicInterruptHandler: Rx Wake: %#x\n",uti596_softc.rxDaemonTid))
+ }
+ #endif
+
+ uti596_softc.pBeginRFA = pIsrRfd;
+ } /* end while */
+ } /* end if */
+
+ if ( uti596_softc.pBeginRFA == I596_NULL ) {
+ /* adjust the pEndRFA to reflect an empty list */
+ if ( uti596_softc.pLastUnkRFD == I596_NULL && uti596_softc.countRFD != 0 ) {
+ printk(("Last Unk is NULL, BeginRFA is null, and count == %d\n",
+ uti596_softc.countRFD))
+ }
+ uti596_softc.pEndRFA = I596_NULL;
+ if ( uti596_softc.countRFD != 0 ) {
+ printk(("****ERROR:Count is %d, but begin ptr is NULL\n",
+ uti596_softc.countRFD ))
+ }
+ }
+ } /* end if ( scbStatus & SCB_STAT_FR ) */
+
+ /*
+ * Command Unit Control
+ * a command is completed
+ */
+ if ( scbStatus & SCB_STAT_CX ) {
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: CU\n"))
+ #endif
+
+ pIsrCmd = uti596_softc.pCmdHead;
+
+ /* For ALL completed commands */
+ if ( pIsrCmd != I596_NULL && pIsrCmd->status & STAT_C ) {
+
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: pIsrCmd != NULL\n"))
+ #endif
+
+ /* Adjust the command block list */
+ uti596_softc.pCmdHead = (i596_cmd *) word_swap ((unsigned long)pIsrCmd->next);
+
+ /*
+ * If there are MORE commands to process,
+ * the serialization in the raw routine has failed.
+ * ( Perhaps AddCmd is bad? )
+ */
+ UTI_596_ASSERT(uti596_softc.pCmdHead == I596_NULL, "****ERROR: command serialization failed\n")
+
+ /* What if the command did not complete OK? */
+ switch ( pIsrCmd->command & 0x7) {
+ case CmdConfigure:
+
+ uti596_softc.cmdOk = 1;
+ break;
+
+ case CmdDump:
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: dump!\n"))
+ #endif
+ uti596_softc.cmdOk = 1;
+ break;
+
+ case CmdDiagnose:
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: diagnose!\n"))
+ #endif
+ uti596_softc.cmdOk = 1;
+ break;
+
+ case CmdSASetup:
+ /* printk(("****INFO:Set address interrupt\n")) */
+ if ( pIsrCmd -> status & STAT_OK ) {
+ uti596_softc.cmdOk = 1;
+ }
+ else {
+ printk(("****ERROR:SET ADD FAILED\n"))
+ }
+ break;
+
+ case CmdTx:
+ UTI_596_ASSERT(uti596_softc.txDaemonTid, "****ERROR:Null txDaemonTid\n")
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: wake TX:0x%x\n",uti596_softc.txDaemonTid))
+ #endif
+ if ( uti596_softc.txDaemonTid ) {
+ /* Ensure that the transmitter is present */
+ sc = rtems_bsdnet_event_send (uti596_softc.txDaemonTid,
+ INTERRUPT_EVENT);
+
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ printk(("****ERROR:Could NOT send event to tid 0x%" PRIu32 " : %s\n",
+ uti596_softc.txDaemonTid, rtems_status_text (sc) ))
+ }
+ #ifdef DBG_ISR
+ else {
+ printk(("****INFO:Tx wake: %#x\n",uti596_softc.txDaemonTid))
+ }
+ #endif
+ }
+ break;
+
+ case CmdMulticastList:
+ printk(("***ERROR:Multicast?!\n"))
+ pIsrCmd->next = I596_NULL;
+ break;
+
+ case CmdTDR: {
+ unsigned long status = *( (unsigned long *)pIsrCmd)+1;
+ printk(("****ERROR:TDR?!\n"))
+
+ if (status & STAT_C) {
+ /* mark the TDR command successful */
+ uti596_softc.cmdOk = 1;
+ }
+ else {
+ if (status & 0x4000) {
+ printk(("****WARNING:Transceiver problem.\n"))
+ }
+ if (status & 0x2000) {
+ printk(("****WARNING:Termination problem.\n"))
+ }
+ if (status & 0x1000) {
+ printk(("****WARNING:Short circuit.\n"))
+ /* printk(("****INFO:Time %ld.\n", status & 0x07ff)) */
+ }
+ }
+ }
+ break;
+
+ default: {
+ /*
+ * This should never be reached
+ */
+ printk(("CX but NO known command\n"))
+ }
+ } /* end switch */
+
+ pIsrCmd = uti596_softc.pCmdHead; /* next command */
+ if ( pIsrCmd != I596_NULL ) {
+ printk(("****WARNING: more commands in list, but no start to NIC\n"))
+ }
+ } /* end if pIsrCmd != NULL && pIsrCmd->stat & STAT_C */
+
+ else {
+ if ( pIsrCmd != I596_NULL ) {
+ /* The command MAY be NULL from a RESET */
+ /* Reset the ethernet card, and wake the transmitter (if necessary) */
+ printk(("****INFO: Request board reset ( tx )\n"))
+ uti596_softc.nic_reset = 1;
+ if ( uti596_softc.txDaemonTid) {
+ /* Ensure that a transmitter is present */
+ sc = rtems_bsdnet_event_send (uti596_softc.txDaemonTid,
+ INTERRUPT_EVENT);
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ printk(("****ERROR:Could NOT send event to tid 0x%" PRIu32 " : %s\n",
+ uti596_softc.txDaemonTid, rtems_status_text (sc) ))
+ }
+ #ifdef DBG_ISR
+ else {
+ printk(("uti596_DynamicInterruptHandler: ****INFO:Tx wake: %#x\n",
+ uti596_softc.txDaemonTid))
+ }
+ #endif
+ }
+ }
+ }
+ } /* end if command complete */
+
+ /*
+ * If the receiver has stopped,
+ * check if this is a No Resources scenario,
+ * Try to add more RFD's ( no RBDs are used )
+ */
+ if ( uti596_softc.started ) {
+ if ( scbStatus & SCB_STAT_RNR ) {
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: INFO:RNR: status %#x \n",
+ uti596_softc.scb.status ))
+ #endif
+ /*
+ * THE RECEIVER IS OFF!
+ */
+ if ( uti596_softc.pLastUnkRFD != I596_NULL ) {
+ /* We have an unknown RFD, it is not inbound */
+ if ( uti596_softc.pLastUnkRFD -> stat & (STAT_C | STAT_B )) { /* in use */
+ uti596_softc.pEndRFA = uti596_softc.pLastUnkRFD; /* update end */
+ }
+ else {
+ /*
+ * It is NOT in use, and since RNR, we know EL bit of pEndRFA was read!
+ * So, unlink it from the RFA and move it to the saved queue.
+ * But pBegin can equal LastUnk!
+ */
+
+ if ( uti596_softc.pEndRFA != I596_NULL ) {
+ /* check added feb24. */
+ #ifdef DBG_ISR
+ if ((i596_rfd *)word_swap((unsigned long)uti596_softc.pEndRFA->next) != uti596_softc.pLastUnkRFD) {
+ printk(("***ERROR:UNK: %p not end->next: %p, end: %p\n",
+ uti596_softc.pLastUnkRFD,
+ uti596_softc.pEndRFA -> next,
+ uti596_softc.pEndRFA))
+ printk(("***INFO:countRFD now %d\n",
+ uti596_softc.countRFD))
+ printk(("\n\n"))
+ }
+ #endif
+ uti596_softc.pEndRFA -> next = I596_NULL; /* added feb 16 */
+ }
+ uti596_append( (i596_rfd **)&uti596_softc.pSavedRfdQueue, uti596_softc.pLastUnkRFD );
+ uti596_softc.savedCount++;
+ uti596_softc.pEndSavedQueue = uti596_softc.pLastUnkRFD;
+ uti596_softc.countRFD--; /* It was not in the RFA */
+ /*
+ * The Begin pointer CAN advance this far. We must resynch the CPU side
+ * with the chip.
+ */
+ if ( uti596_softc.pBeginRFA == uti596_softc.pLastUnkRFD ) {
+ #ifdef DBG_ISR
+ if ( uti596_softc.countRFD != 0 ) {
+ printk(("****INFO:About to set begin to NULL, with count == %d\n\n",
+ uti596_softc.countRFD ))
+ }
+ #endif
+ uti596_softc.pBeginRFA = I596_NULL;
+ UTI_596_ASSERT(uti596_softc.countRFD == 0, "****ERROR:Count must be zero here!\n")
+ }
+ }
+ uti596_softc.pLastUnkRFD = I596_NULL;
+ } /* end if exists UnkRFD */
+
+ /*
+ * Append the saved queue to the RFA.
+ * Any further RFD's being supplied will be added to
+ * this new list.
+ */
+ if ( uti596_softc.pSavedRfdQueue != I596_NULL ) {
+ /* entries to add */
+ if ( uti596_softc.pBeginRFA == I596_NULL ) {
+ /* add at beginning to list */
+ #ifdef DBG_ISR
+ if(uti596_softc.countRFD != 0) {
+ printk(("****ERROR:Begin pointer is NULL, but count == %d\n",
+ uti596_softc.countRFD))
+ }
+ #endif
+ uti596_softc.pBeginRFA = uti596_softc.pSavedRfdQueue;
+ uti596_softc.pEndRFA = uti596_softc.pEndSavedQueue;
+ uti596_softc.pSavedRfdQueue = uti596_softc.pEndSavedQueue = I596_NULL; /* Reset the End */
+ }
+ else {
+ #ifdef DBG_ISR
+ if ( uti596_softc.countRFD <= 0) {
+ printk(("****ERROR:Begin pointer is not NULL, but count == %d\n",
+ uti596_softc.countRFD))
+ }
+ #endif
+ UTI_596_ASSERT( uti596_softc.pEndRFA != I596_NULL, "****WARNING: END RFA IS NULL\n")
+ UTI_596_ASSERT( uti596_softc.pEndRFA->next == I596_NULL, "****ERROR:END RFA -> next must be NULL\n")
+
+ uti596_softc.pEndRFA->next = (i596_rfd *)word_swap((unsigned long)uti596_softc.pSavedRfdQueue);
+ uti596_softc.pEndRFA->cmd &= ~CMD_EOL; /* clear the end of list */
+ uti596_softc.pEndRFA = uti596_softc.pEndSavedQueue;
+ uti596_softc.pSavedRfdQueue = uti596_softc.pEndSavedQueue = I596_NULL; /* Reset the End */
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: count... %d, saved ... %d \n",
+ uti596_softc.countRFD,
+ uti596_softc.savedCount))
+ #endif
+ }
+ /* printk(("Isr: countRFD = %d\n",uti596_softc.countRFD)) */
+ uti596_softc.countRFD += uti596_softc.savedCount;
+ /* printk(("Isr: after countRFD = %d\n",uti596_softc.countRFD)) */
+ uti596_softc.savedCount = 0;
+ }
+
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: The list starts here %p\n",uti596_softc.pBeginRFA ))
+ #endif
+
+ if ( uti596_softc.countRFD > 1) {
+ printk(("****INFO: pBeginRFA -> stat = 0x%x\n",uti596_softc.pBeginRFA -> stat))
+ printk(("****INFO: pBeginRFA -> cmd = 0x%x\n",uti596_softc.pBeginRFA -> cmd))
+ uti596_softc.pBeginRFA -> stat = 0;
+ UTI_596_ASSERT(uti596_softc.scb.command == 0, "****ERROR:scb command must be zero\n")
+ uti596_softc.scb.pRfd = uti596_softc.pBeginRFA;
+ uti596_softc.scb.rfd_pointer = word_swap((unsigned long)uti596_softc.pBeginRFA);
+ /* start RX here */
+ printk(("****INFO: ISR Starting receiver\n"))
+ uti596_softc.scb.command = RX_START; /* should this also be CU start? */
+ i82596->chan_attn = 0x00000000;
+ }
+ } /* end stat_rnr */
+ } /* end if receiver started */
+
+ #ifdef DBG_ISR
+ printk(("uti596_DynamicInterruptHandler: X\n"))
+ #endif
+ count_rx=0;
+
+ /* Do this last, to ensure that the reset is called at the right time. */
+ if ( uti596_softc.nic_reset ) {
+ uti596_softc.nic_reset = 0;
+ sc = rtems_bsdnet_event_send(uti596_softc.resetDaemonTid, NIC_RESET_EVENT);
+ if ( sc != RTEMS_SUCCESSFUL )
+ rtems_panic ("Can't notify resetDaemon: %s\n", rtems_status_text (sc));
+ }
+ return;
+}
+
+/***********************************************************************
+ * Function: uti596_ioctl
+ *
+ * Description:
+ * driver ioctl function
+ * handles SIOCGIFADDR, SIOCSIFADDR, SIOCSIFFLAGS
+ *
+ ***********************************************************************/
+
+static int uti596_ioctl(
+ struct ifnet *ifp,
+ u_long command,
+ caddr_t data
+)
+{
+ uti596_softc_ *sc = ifp->if_softc;
+ int error = 0;
+
+ #ifdef DBG_IOCTL
+ printk(("uti596_ioctl: begins\n", sc->pScp))
+ #endif
+
+ switch (command) {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ printk(("SIOCSIFADDR\n"))
+ ether_ioctl (ifp, command, data);
+ break;
+
+ case SIOCSIFFLAGS:
+ printk(("SIOCSIFFLAGS\n"))
+ switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
+ case IFF_RUNNING:
+ printk(("IFF_RUNNING\n"))
+ uti596_stop (sc);
+ break;
+
+ case IFF_UP:
+ printk(("IFF_UP\n"))
+ uti596_init ( (void *)sc);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ printk(("IFF_UP and RUNNING\n"))
+ uti596_stop (sc);
+ uti596_init ( (void *)sc);
+ break;
+
+ default:
+ printk(("default\n"))
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ printk(("show stats\n"))
+ uti596_stats (sc);
+ break;
+
+ /* FIXME: All sorts of multicast commands need to be added here! */
+ default:
+ printk(("default: EINVAL\n"))
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+/***********************************************************************
+ * Function: uti596_stats
+ *
+ * Description:
+ * print out the collected data
+ *
+ * Algorithm:
+ * use printf
+ *
+ ***********************************************************************/
+
+void uti596_stats(
+ uti596_softc_ *sc
+)
+{
+ printf ("CPU Reports:\n");
+ printf (" Tx raw send count:%-8lu", sc->rawsndcnt);
+ printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
+ printf (" Tx Interrupts:%-8lu\n", sc->txInterrupts);
+ printf (" Rx Packets:%-8u", sc->stats.rx_packets);
+ printf (" Tx Attempts:%-u\n", sc->stats.tx_packets);
+
+ printf (" Rx Dropped:%-8u", sc->stats.rx_dropped);
+ printf (" Rx IP Packets:%-8u", sc->stats.rx_packets);
+ printf (" Tx Errors:%-8u\n", sc->stats.tx_errors);
+ printf (" Tx aborted:%-8u", sc->stats.tx_aborted_errors);
+ printf (" Tx Dropped:%-8u\n", sc->stats.tx_dropped);
+ printf (" Tx IP packets:%-8u", sc->stats.tx_packets);
+
+ printf (" Collisions Detected:%-8u\n", sc->stats.collisions);
+ printf (" Tx Heartbeat Errors:%-8u", sc->stats.tx_heartbeat_errors);
+ printf (" Tx Carrier Errors:%-8u\n", sc->stats.tx_carrier_errors);
+ printf (" Tx Aborted Errors:%-8u", sc->stats.tx_aborted_errors);
+ printf (" Rx Length Errors:%-8u\n", sc->stats.rx_length_errors);
+ printf (" Rx Overrun Errors:%-8u", sc->stats.rx_over_errors);
+ printf (" Rx Fifo Errors:%-8u\n", sc->stats.rx_fifo_errors);
+ printf (" Rx Framing Errors:%-8u", sc->stats.rx_frame_errors);
+ printf (" Rx crc errors:%-8u\n", sc->stats.rx_crc_errors);
+
+ printf (" TX WAITS: %-8lu\n", sc->txRawWait);
+
+ printf (" NIC resets: %-8u\n", sc->stats.nic_reset_count);
+
+ printf (" NIC reports\n");
+
+ #ifdef DBG_STAT
+ uti596_dump_scb();
+ #endif
+}
+
+/************************ PACKET DEBUG ROUTINES ************************/
+
+#ifdef DBG_PACKETS
+
+/*
+ * dumpQ
+ *
+ * Dumps frame queues for debugging
+ */
+static void dumpQ( void )
+{
+ i596_rfd *pRfd;
+
+ printk(("savedQ:\n"))
+
+ for( pRfd = uti596_softc.pSavedRfdQueue;
+ pRfd != I596_NULL;
+ pRfd = (i596_rfd*)word_swap((uint32_t)pRfd -> next)) {
+ printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd))
+ }
+
+ printk(("Inbound:\n"))
+
+ for( pRfd = uti596_softc.pInboundFrameQueue;
+ pRfd != I596_NULL;
+ pRfd = (i596_rfd*)word_swap((uint32_t)pRfd -> next)) {
+ printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd))
+ }
+
+ printk(("Last Unk: %p\n", uti596_softc.pLastUnkRFD ))
+ printk(("RFA:\n"))
+
+ for( pRfd = uti596_softc.pBeginRFA;
+ pRfd != I596_NULL;
+ pRfd = (i596_rfd*)word_swap((uint32_t)pRfd -> next)) {
+ printk(("pRfd: %p, stat: 0x%x cmd: 0x%x\n",pRfd,pRfd -> stat,pRfd -> cmd))
+ }
+}
+
+/*
+ * show_buffers
+ *
+ * Print out the RFA and frame queues
+ */
+static void show_buffers (void)
+{
+ i596_rfd *pRfd;
+
+ printk(("82596 cmd: 0x%x, status: 0x%x RFA len: %d\n",
+ uti596_softc.scb.command,
+ uti596_softc.scb.status,
+ uti596_softc.countRFD))
+
+ printk(("\nRFA: \n"))
+
+ for ( pRfd = uti596_softc.pBeginRFA;
+ pRfd != I596_NULL;
+ pRfd = (i596_rfd *)word_swap((uint32_t)pRfd->next) ) {
+ printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n",
+ pRfd, pRfd->stat, pRfd->cmd))
+ }
+ printk(("\nInbound: \n"))
+
+ for ( pRfd = uti596_softc.pInboundFrameQueue;
+ pRfd != I596_NULL;
+ pRfd = (i596_rfd *)word_swap((uint32_t)pRfd->next) ) {
+ printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n",
+ pRfd, pRfd->stat, pRfd->cmd))
+ }
+
+ printk(("\nSaved: \n"))
+
+ for ( pRfd = uti596_softc.pSavedRfdQueue;
+ pRfd != I596_NULL;
+ pRfd = (i596_rfd *)word_swap((uint32_t)pRfd->next) ) {
+ printk(("Frame @ %p, status: %2.2x, cmd: %2.2x\n",
+ pRfd, pRfd->stat, pRfd->cmd))
+ }
+
+ printk(("\nUnknown: %p\n",uti596_softc.pLastUnkRFD))
+}
+
+/*
+ * show_queues
+ *
+ * Print out the saved frame queue and the RFA
+ */
+static void show_queues(void)
+{
+ i596_rfd *pRfd;
+
+ printk(("CMD: 0x%x, Status: 0x%x\n",
+ uti596_softc.scb.command,
+ uti596_softc.scb.status))
+ printk(("saved Q\n"))
+
+ for ( pRfd = uti596_softc.pSavedRfdQueue;
+ pRfd != I596_NULL &&
+ pRfd != NULL;
+ pRfd = (i596_rfd *)word_swap((uint32_t)pRfd->next) ) {
+ printk(("0x%p\n", pRfd))
+ }
+
+ printk(("End saved Q 0x%p\n", uti596_softc.pEndSavedQueue))
+
+ printk(("\nRFA:\n"))
+
+ for ( pRfd = uti596_softc.pBeginRFA;
+ pRfd != I596_NULL &&
+ pRfd != NULL;
+ pRfd = (i596_rfd *)word_swap((uint32_t)pRfd->next) ) {
+ printk(("0x%p\n", pRfd))
+ }
+
+ printk(("uti596_softc.pEndRFA: %p\n",uti596_softc.pEndRFA))
+}
+
+/*
+ * print_eth
+ *
+ * Print the contents of an ethernet packet
+ * CANNOT BE CALLED FROM ISR
+ */
+static void print_eth(
+ unsigned char *add
+)
+{
+ int i;
+ short int length;
+
+ printk (("Packet Location %p\n", add))
+ printk (("Dest "))
+
+ for (i = 0; i < 6; i++) {
+ printk ((" %2.2X", add[i]))
+ }
+ printk (("\n"))
+ printk (("Source"))
+
+ for (i = 6; i < 12; i++) {
+ printk ((" %2.2X", add[i]))
+ }
+
+ printk (("\n"))
+ printk (("frame type %2.2X%2.2X\n", add[12], add[13]))
+
+ if ( add[12] == 0x08 && add[13] == 0x06 ) {
+ /* an ARP */
+ printk (("Hardware type : %2.2X%2.2X\n", add[14],add[15]))
+ printk (("Protocol type : %2.2X%2.2X\n", add[16],add[17]))
+ printk (("Hardware size : %2.2X\n", add[18]))
+ printk (("Protocol size : %2.2X\n", add[19]))
+ printk (("op : %2.2X%2.2X\n", add[20],add[21]))
+ printk (("Sender Enet addr: "))
+
+ for ( i=0; i< 5 ; i++) {
+ printk (("%x:", add[22 + i]))
+ }
+ printk (("%x\n", add[27]))
+ printk (("Sender IP addr: "))
+
+ for ( i=0; i< 3 ; i++) {
+ printk (("%u.", add[28 + i]))
+ }
+ printk (("%u\n", add[31]))
+ printk (("Target Enet addr: "))
+
+ for ( i=0; i< 5 ; i++) {
+ printk (( "%x:", add[32 + i]))
+ }
+ printk (("%x\n", add[37]))
+ printk (("Target IP addr: "))
+
+ for ( i=0; i< 3 ; i++) {
+ printk (( "%u.", add[38 + i]))
+ }
+ printk (("%u\n", add[41]))
+ }
+
+ if ( add[12] == 0x08 && add[13] == 0x00 ) {
+ /* an IP packet */
+ printk (("*********************IP HEADER******************\n"))
+ printk (("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15]))
+ printk (("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] )))
+ printk (("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n",
+ add[18],add[19], add[20], add[21]))
+ printk (("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n",
+ add[22],add[23],add[24],add[25]))
+ printk (("IP packet type: %2.2X code %2.2X\n", add[34],add[35]))
+ printk (("Source IP address: "))
+
+ for ( i=0; i< 3 ; i++) {
+ printk (("%u.", add[26 + i]))
+ }
+ printk (("%u\n", add[29]))
+ printk (("Destination IP address: "))
+
+ for ( i=0; i< 3 ; i++) {
+ printk (("%u.", add[30 + i]))
+ }
+ printk (("%u\n", add[33]))
+ }
+}
+
+/*
+ * print_hdr
+ *
+ * Print the contents of an ethernet packet header
+ * CANNOT BE CALLED FROM ISR
+ */
+static void print_hdr(
+ unsigned char *add
+)
+{
+ int i;
+
+ printk (("print_hdr: begins\n"))
+ printk (("Header Location %p\n", add))
+ printk (("Dest "))
+
+ for (i = 0; i < 6; i++) {
+ printk ((" %2.2X", add[i]))
+ }
+ printk (("\nSource"))
+
+ for (i = 6; i < 12; i++) {
+ printk ((" %2.2X", add[i]))
+ }
+ printk (("\nframe type %2.2X%2.2X\n", add[12], add[13]))
+ printk (("print_hdr: completed"))
+}
+
+/*
+ * Function: print_pkt
+ *
+ * Print the contents of an ethernet packet & data
+ * CANNOT BE CALLED FROM ISR
+ */
+static void print_pkt(
+ unsigned char *add
+)
+{
+ int i;
+ short int length;
+
+ printk (("print_pkt: begins"))
+ printk (("Data Location %p\n", add))
+
+ if ( add[0] == 0x08 && add[1] == 0x06 ) {
+ /* an ARP */
+ printk (("Hardware type : %2.2X%2.2X\n", add[14],add[15]))
+ printk (("Protocol type : %2.2X%2.2X\n", add[16],add[17]))
+ printk (("Hardware size : %2.2X\n", add[18]))
+ printk (("Protocol size : %2.2X\n", add[19]))
+ printk (("op : %2.2X%2.2X\n", add[20],add[21]))
+ printk (("Sender Enet addr: "))
+
+ for ( i=0; i< 5 ; i++) {
+ printk (( "%x:", add[22 + i]))
+ }
+ printk (("%x\n", add[27]))
+ printk (("Sender IP addr: "))
+
+ for ( i=0; i< 3 ; i++) {
+ printk (("%u.", add[28 + i]))
+ }
+ printk (("%u\n", add[31]))
+ printk (("Target Enet addr: "))
+
+ for ( i=0; i< 5 ; i++) {
+ printk (( "%x:", add[32 + i]))
+ }
+ printk (("%x\n", add[37]))
+ printk (("Target IP addr: "))
+
+ for ( i=0; i< 3 ; i++) {
+ printk (( "%u.", add[38 + i]))
+ }
+ printk (("%u\n", add[41]))
+ }
+
+ if ( add[0] == 0x08 && add[1] == 0x00 ) {
+ /* an IP packet */
+ printk (("*********************IP HEADER******************\n"))
+ printk (("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15]))
+ printk (("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] )))
+ printk (("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n",
+ add[18],add[19], add[20], add[21]))
+ printk (("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n",
+ add[22],add[23],add[24],add[25]))
+ printk (("IP packet type: %2.2X code %2.2X\n", add[34],add[35]))
+ printk (("Source IP address: "))
+
+ for ( i=0; i< 3 ; i++) {
+ printk(( "%u.", add[26 + i]))
+ }
+ printk(("%u\n", add[29]))
+ printk(("Destination IP address: "))
+
+ for ( i=0; i< 3 ; i++) {
+ printk(( "%u.", add[30 + i]))
+ }
+ printk(("%u\n", add[33]))
+ printk(("********************IP Packet Data*******************\n"))
+ length -=20;
+
+ for ( i=0; i < length ; i++) {
+ printk(("0x%2.2x ", add[34+i]))
+ }
+ printk(("\n"))
+ printk(("ICMP checksum: %2.2x %2.2x\n", add[36], add[37]))
+ printk(("ICMP identifier: %2.2x %2.2x\n", add[38], add[39]))
+ printk(("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41]))
+ printk(("print_pkt: completed"))
+ }
+}
+
+/*
+ * print_echo
+ *
+ * Print the contents of an echo packet
+ * CANNOT BE CALLED FROM ISR
+ */
+static void print_echo(
+ unsigned char *add
+)
+{
+ int i;
+ short int length;
+
+ printk (("print_echo: begins"))
+
+ if ( add[12] == 0x08 && add[13] == 0x00 ) {
+ /* an IP packet */
+ printk (("Packet Location %p\n", add))
+ printk (("Dest "))
+
+ for (i = 0; i < 6; i++) {
+ printk ((" %2.2X", add[i]))
+ }
+ printk (("\n"))
+ printk (("Source"))
+
+ for (i = 6; i < 12; i++) {
+ printk ((" %2.2X", add[i]))
+ }
+ printk (("\n"))
+ printk (("frame type %2.2X%2.2X\n", add[12], add[13]))
+
+ printk (("*********************IP HEADER******************\n"))
+ printk (("IP version/IPhdr length: %2.2X TOS: %2.2X\n", add[14] , add[15]))
+ printk (("IP total length: %2.2X %2.2X, decimal %d\n", add[16], add[17], length = (add[16]<<8 | add[17] )))
+ printk (("IP identification: %2.2X %2.2X, 3-bit flags and offset %2.2X %2.2X\n",
+ add[18],add[19], add[20], add[21]))
+ printk (("IP TTL: %2.2X, protocol: %2.2X, checksum: %2.2X %2.2X \n",
+ add[22],add[23],add[24],add[25]))
+ printk (("IP packet type: %2.2X code %2.2X\n", add[34],add[35]))
+ printk (("Source IP address: "))
+
+ for ( i=0; i< 3 ; i++) {
+ printk (("%u.", add[26 + i]))
+ }
+ printk (("%u\n", add[29]))
+ printk (("Destination IP address: "))
+
+ for ( i=0; i< 3 ; i++) {
+ printk (("%u.", add[30 + i]))
+ }
+ printk (("%u\n", add[33]))
+ printk(("********************IP Packet Data*******************\n"))
+ length -=20;
+
+ for ( i=0; i < length ; i++) {
+ printk(("0x%2.2x ", add[34+i]))
+ }
+ printk(("\n"))
+ printk(("ICMP checksum: %2.2x %2.2x\n", add[36], add[37]))
+ printk(("ICMP identifier: %2.2x %2.2x\n", add[38], add[39]))
+ printk(("ICMP sequence nbr: %2.2x %2.2x\n", add[40], add[41]))
+ printk(("print_echo: completed"))
+ }
+}
+
+#endif
diff --git a/bsps/m68k/mvme167/net/uti596.h b/bsps/m68k/mvme167/net/uti596.h
new file mode 100644
index 0000000000..29e4fed299
--- /dev/null
+++ b/bsps/m68k/mvme167/net/uti596.h
@@ -0,0 +1,369 @@
+/* uti596.h: Contains the defines and structures used by the uti596 driver */
+
+/*
+ * EII: March 11: Created v. 0.0
+ */
+
+#ifndef UTI596_H
+#define UTI596_H
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+/* Ethernet statistics */
+
+struct enet_statistics{
+ int rx_packets; /* total packets received */
+ int tx_packets; /* total packets transmitted */
+ int rx_errors; /* bad packets received */
+ int tx_errors; /* packet transmit problems */
+ int rx_dropped; /* no space in buffers */
+ int tx_dropped;
+ int tx_retries_exceeded; /* excessive retries */
+ int multicast; /* multicast packets received */
+ int collisions;
+
+ /* detailed rx_errors: */
+ int rx_length_errors;
+ int rx_over_errors; /* receiver ring buff overflow */
+ int rx_crc_errors; /* recved pkt with crc error */
+ int rx_frame_errors; /* recv'd frame alignment error */
+ int rx_fifo_errors; /* recv'r fifo overrun */
+ int rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ int tx_aborted_errors;
+ int tx_carrier_errors;
+ int tx_fifo_errors;
+ int tx_heartbeat_errors;
+ int tx_window_errors;
+
+ /* NIC reset errors */
+ int nic_reset_count; /* The number of times uti596reset() has been called. */
+};
+
+#define CMD_EOL 0x8000 /* The last command of the list, stop. */
+#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
+#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
+
+#define CMD_FLEX 0x0008 /* Enable flexible memory model */
+
+#define SCB_STAT_CX 0x8000 /* Cmd completes with 'I' bit set */
+#define SCB_STAT_FR 0x4000 /* Frame Received */
+#define SCB_STAT_CNA 0x2000 /* Cmd unit Not Active */
+#define SCB_STAT_RNR 0x1000 /* Receiver Not Ready */
+
+#define SCB_CUS_SUSPENDED 0x0100
+#define SCB_CUS_ACTIVE 0x0200
+
+#define STAT_C 0x8000 /* Set to 1 after execution */
+#define STAT_B 0x4000 /* 1 : Cmd being executed, 0 : Cmd done. */
+#define STAT_OK 0x2000 /* 1: Command executed ok 0 : Error */
+#define STAT_A 0x1000 /* command has been aborted */
+
+#define STAT_S11 0x0800
+#define STAT_S10 0x0400
+#define STAT_S9 0x0200
+#define STAT_S8 0x0100
+#define STAT_S7 0x0080
+#define STAT_S6 0x0040
+#define STAT_S5 0x0020
+#define STAT_MAX_COLLS 0x000F
+
+#define RBD_STAT_P 0x4000 /* prefetch */
+#define RBD_STAT_F 0x4000 /* used */
+
+#define CUC_START 0x0100
+#define CUC_RESUME 0x0200
+#define CUC_SUSPEND 0x0300
+#define CUC_ABORT 0x0400
+#define RX_START 0x0010
+#define RX_RESUME 0x0020
+#define RX_SUSPEND 0x0030
+#define RX_ABORT 0x0040
+
+#define RU_SUSPENDED 0x0010
+#define RU_NO_RESOURCES 0x0020
+#define RU_READY 0x0040
+
+#define I596_NULL ( ( void * ) 0xffffffff)
+#define UTI_596_END_OF_FRAME 0x8000
+
+struct i596_tbd; /* necessary forward declaration */
+
+enum commands {
+ CmdNOp = 0,
+ CmdSASetup = 1,
+ CmdConfigure = 2,
+ CmdMulticastList = 3,
+ CmdTx = 4,
+ CmdTDR = 5,
+ CmdDump = 6,
+ CmdDiagnose = 7
+};
+
+/*
+ * 82596 Dump Command Result
+ */
+typedef volatile struct i596_dump_result {
+ unsigned char bf;
+ unsigned char config_bytes[11];
+ unsigned char reserved1[2];
+ unsigned char ia_bytes[6];
+ unsigned short last_tx_status;
+ unsigned short tx_crc_byte01;
+ unsigned short tx_crc_byte23;
+ unsigned short rx_crc_byte01;
+ unsigned short rx_crc_byte23;
+ unsigned short rx_temp_mem01;
+ unsigned short rx_temp_mem23;
+ unsigned short rx_temp_mem45;
+ unsigned short last_rx_status;
+ unsigned short hash_reg01;
+ unsigned short hash_reg23;
+ unsigned short hash_reg45;
+ unsigned short hash_reg67;
+ unsigned short slot_time_counter;
+ unsigned short wait_time_counter;
+ unsigned short rx_frame_length;
+ unsigned long reserved2;
+ unsigned long cb_in3;
+ unsigned long cb_in2;
+ unsigned long cb_in1;
+ unsigned long la_cb_addr;
+ unsigned long rdb_pointer;
+ unsigned long int_memory;
+ unsigned long rfd_size;
+ unsigned long tbd_pointer;
+ unsigned long base_addr;
+ unsigned long ru_temp_reg;
+ unsigned long tcb_count;
+ unsigned long next_rb_size;
+ unsigned long next_rb_addr;
+ unsigned long curr_rb_size;
+ unsigned long la_rbd_addr;
+ unsigned long next_rbd_addr;
+ unsigned long curr_rbd_addr;
+ unsigned long curr_rb_count;
+ unsigned long next_fd_addr;
+ unsigned long curr_fd_add;
+ unsigned long temp_cu_reg;
+ unsigned long next_tb_count;
+ unsigned long buffer_addr;
+ unsigned long la_tbd_addr;
+ unsigned long next_tbd_addr;
+ unsigned long cb_command;
+ unsigned long next_cb_addr;
+ unsigned long curr_cb_addr;
+ unsigned long scb_cmd_word;
+ unsigned long scb_pointer;
+ unsigned long cb_stat_word;
+ unsigned long mm_lfsr;
+ unsigned char micro_machine_bit_array[28];
+ unsigned char cu_port[16];
+ unsigned long mm_alu;
+ unsigned long reserved3;
+ unsigned long mm_temp_a_rr;
+ unsigned long mm_temp_a;
+ unsigned long tx_dma_b_cnt;
+ unsigned long mm_input_port_addr_reg;
+ unsigned long tx_dma_addr;
+ unsigned long mm_port_reg1;
+ unsigned long rx_dma_b_cnt;
+ unsigned long mm_port_reg2;
+ unsigned long rx_dma_addr;
+ unsigned long reserved4;
+ unsigned long bus_t_timers;
+ unsigned long diu_cntrl_reg;
+ unsigned long reserved5;
+ unsigned long sysbus;
+ unsigned long biu_cntrl_reg;
+ unsigned long mm_disp_reg;
+ unsigned long mm_status_reg;
+ unsigned short dump_status;
+} i596_dump_result;
+
+typedef volatile struct i596_selftest {
+ unsigned long rom_signature;
+ unsigned long results;
+} i596_selftest;
+
+/*
+ * Action commands
+ * (big endian, linear mode)
+ */
+typedef volatile struct i596_cmd {
+ unsigned short status;
+ unsigned short command;
+ volatile struct i596_cmd *next;
+} i596_cmd;
+
+typedef volatile struct i596_nop {
+ i596_cmd cmd;
+} i596_nop;
+
+typedef volatile struct i596_set_add {
+ i596_cmd cmd;
+ char data[8];
+} i596_set_add;
+
+typedef volatile struct i596_configure {
+ i596_cmd cmd;
+ char data[16];
+} i596_configure;
+
+typedef volatile struct i596_tx {
+ i596_cmd cmd;
+ volatile struct i596_tbd *pTbd;
+ unsigned short count;
+ unsigned short pad;
+ char data[6];
+ unsigned short length;
+} i596_tx;
+
+typedef volatile struct i596_tdr {
+ i596_cmd cmd;
+ unsigned long data;
+} i596_tdr;
+
+typedef volatile struct i596_dump {
+ i596_cmd cmd;
+ char *pData;
+} i596_dump;
+
+/*
+ * Transmit buffer descriptor
+ */
+typedef volatile struct i596_tbd {
+ unsigned short size;
+ unsigned short pad;
+ volatile struct i596_tbd *next;
+ char *data;
+} i596_tbd;
+
+/*
+ * Receive buffer descriptor
+ * (flexible memory structure)
+ */
+typedef volatile struct i596_rbd {
+ unsigned short count;
+ unsigned short offset;
+ volatile struct i596_rbd *next;
+ char *data;
+ unsigned short size;
+ unsigned short pad;
+} i596_rbd;
+
+/*
+ * Receive Frame Descriptor
+ */
+typedef volatile struct i596_rfd {
+ unsigned short stat;
+ unsigned short cmd;
+ volatile struct i596_rfd *next;
+ i596_rbd *pRbd;
+ unsigned short count;
+ unsigned short size;
+ char data [1532];
+} i596_rfd;
+
+/*
+ * System Control Block
+ */
+typedef volatile struct i596_scb {
+ unsigned short status;
+ unsigned short command;
+ unsigned long cmd_pointer;
+ unsigned long rfd_pointer;
+ unsigned long crc_err;
+ unsigned long align_err;
+ unsigned long resource_err;
+ unsigned long over_err;
+ unsigned long rcvdt_err;
+ unsigned long short_err;
+ unsigned short t_off;
+ unsigned short t_on;
+ i596_cmd *pCmd;
+ i596_rfd *pRfd;
+} i596_scb;
+
+/*
+ * Intermediate System Configuration Pointer
+ */
+typedef volatile struct i596_iscp {
+ uint8_t null1; /* Always zero */
+ uint8_t busy; /* Busy byte */
+ unsigned short scb_offset; /* Not used in linear mode */
+ unsigned long scb_pointer; /* Swapped pointer to scb */
+ i596_scb *scb; /* Real pointer to scb */
+} i596_iscp;
+
+/*
+ * System Configuration Pointer
+ */
+typedef volatile struct i596_scp {
+ unsigned long sysbus; /* Only low 8 bits are used */
+ unsigned long pad; /* Must be zero */
+ unsigned long iscp_pointer; /* Swapped pointer to iscp */
+ i596_iscp *iscp; /* Real pointer to iscp */
+} i596_scp;
+
+/*
+ * Device Dependent Data Structure
+ */
+typedef volatile struct uti596_softc {
+ struct arpcom arpcom;
+ i596_scp *pScp; /* Block aligned on 16 byte boundary */
+ i596_scp *base_scp; /* Unaligned block. Need for free() */
+ i596_iscp iscp;
+ i596_scb scb;
+ i596_set_add set_add;
+ i596_configure set_conf;
+ i596_tdr tdr;
+ i596_nop nop;
+ i596_tx *pTxCmd;
+ i596_tbd *pTbd;
+
+ i596_rfd *pBeginRFA;
+ i596_rfd *pEndRFA;
+ i596_rfd *pLastUnkRFD;
+ i596_rbd *pLastUnkRBD;
+ i596_rfd *pEndSavedQueue;
+ i596_cmd *pCmdHead;
+ i596_cmd *pCmdTail; /* unneeded, as chaining not used, but implemented */
+
+ rtems_id rxDaemonTid;
+ rtems_id txDaemonTid;
+ rtems_id resetDaemonTid;
+
+ struct enet_statistics stats;
+ int started;
+ unsigned long rxInterrupts;
+ unsigned long txInterrupts;
+ volatile int cmdOk;
+ unsigned short * pCurrent_command_status;
+ int resetDone;
+ unsigned long txRawWait;
+ i596_rfd *pInboundFrameQueue;
+ short int rxBdCount;
+ short int txBdCount;
+ short int countRFD;
+ short int savedCount;
+ i596_rfd *pSavedRfdQueue;
+ rtems_name semaphore_name;
+ rtems_id semaphore_id;
+ char zeroes[64];
+ unsigned long rawsndcnt;
+ int nic_reset; /* flag for requesting that ISR issue a reset quest */
+} uti596_softc_;
+
+#endif /* UTI596_H */
diff --git a/bsps/m68k/uC5282/net/network.c b/bsps/m68k/uC5282/net/network.c
new file mode 100644
index 0000000000..b8afa0b968
--- /dev/null
+++ b/bsps/m68k/uC5282/net/network.c
@@ -0,0 +1,1013 @@
+/*
+ * RTEMS driver for MCF5282 Fast Ethernet Controller
+ *
+ * Author: W. Eric Norum <norume@aps.anl.gov>
+ *
+ * COPYRIGHT (c) 2005.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#define __INSIDE_RTEMS_BSD_TCPIP_STACK__
+
+#include <bsp.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+
+/*
+ * Number of interfaces supported by this driver
+ */
+#define NIFACES 1
+
+#define FEC_INTC0_TX_VECTOR (64+23)
+#define FEC_INTC0_RX_VECTOR (64+27)
+#define MII_VECTOR (64+7) /* IRQ7* pin connected to external transceiver */
+#define MII_EPPAR MCF5282_EPORT_EPPAR_EPPA7_LEVEL
+#define MII_EPDDR MCF5282_EPORT_EPDDR_EPDD7
+#define MII_EPIER MCF5282_EPORT_EPIER_EPIE7
+#define MII_EPPDR MCF5282_EPORT_EPPDR_EPPD7
+
+/*
+ * Default number of buffer descriptors set aside for this driver.
+ * The number of transmit buffer descriptors has to be quite large
+ * since a single frame often uses three or more buffer descriptors.
+ */
+#define RX_BUF_COUNT 32
+#define TX_BUF_COUNT 20
+#define TX_BD_PER_BUF 3
+
+#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")
+
+/*
+ * RTEMS event used by interrupt handler to signal daemons.
+ * This must *not* be the same event used by the TCP/IP task synchronization.
+ */
+#define TX_INTERRUPT_EVENT RTEMS_EVENT_1
+#define RX_INTERRUPT_EVENT RTEMS_EVENT_1
+
+/*
+ * RTEMS event used to start transmit daemon.
+ * This must not be the same as INTERRUPT_EVENT.
+ */
+#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+
+/*
+ * Receive buffer size -- Allow for a full ethernet packet plus CRC (1518).
+ * Round off to nearest multiple of RBUF_ALIGN.
+ */
+#define MAX_MTU_SIZE 1518
+#define RBUF_ALIGN 4
+#define RBUF_SIZE ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN)
+
+#if (MCLBYTES < RBUF_SIZE)
+ #error "Driver must have MCLBYTES > RBUF_SIZE"
+#endif
+
+/*
+ * Per-device data
+ */
+struct mcf5282_enet_struct {
+ struct arpcom arpcom;
+ struct mbuf **rxMbuf;
+ struct mbuf **txMbuf;
+ int acceptBroadcast;
+ int rxBdCount;
+ int txBdCount;
+ int txBdHead;
+ int txBdTail;
+ int txBdActiveCount;
+ mcf5282BufferDescriptor_t *rxBdBase;
+ mcf5282BufferDescriptor_t *txBdBase;
+ rtems_id rxDaemonTid;
+ rtems_id txDaemonTid;
+
+ /*
+ * Statistics
+ */
+ unsigned long rxInterrupts;
+ unsigned long txInterrupts;
+ unsigned long miiInterrupts;
+ unsigned long txRawWait;
+ unsigned long txRealign;
+ unsigned long txRealignDrop;
+
+ /*
+ * Link parameters
+ */
+ enum { link_auto, link_100Full, link_10Half } link;
+ uint16_t mii_cr;
+ uint16_t mii_sr2;
+};
+static struct mcf5282_enet_struct enet_driver[NIFACES];
+
+/*
+ * Read MII register
+ * Busy-waits, but transfer time should be short!
+ */
+static int
+getMII(int phyNumber, int regNumber)
+{
+ MCF5282_FEC_MMFR = (0x1 << 30) |
+ (0x2 << 28) |
+ (phyNumber << 23) |
+ (regNumber << 18) |
+ (0x2 << 16);
+ while ((MCF5282_FEC_EIR & MCF5282_FEC_EIR_MII) == 0);
+ MCF5282_FEC_EIR = MCF5282_FEC_EIR_MII;
+ return MCF5282_FEC_MMFR & 0xFFFF;
+}
+
+/*
+ * Write MII register
+ * Busy-waits, but transfer time should be short!
+ */
+static void
+setMII(int phyNumber, int regNumber, int value)
+{
+ MCF5282_FEC_MMFR = (0x1 << 30) |
+ (0x1 << 28) |
+ (phyNumber << 23) |
+ (regNumber << 18) |
+ (0x2 << 16) |
+ (value & 0xFFFF);
+ while ((MCF5282_FEC_EIR & MCF5282_FEC_EIR_MII) == 0);
+ MCF5282_FEC_EIR = MCF5282_FEC_EIR_MII;
+}
+
+static rtems_isr
+mcf5282_fec_rx_interrupt_handler( rtems_vector_number v )
+{
+ MCF5282_FEC_EIR = MCF5282_FEC_EIR_RXF;
+ MCF5282_FEC_EIMR &= ~MCF5282_FEC_EIMR_RXF;
+ enet_driver[0].rxInterrupts++;
+ rtems_bsdnet_event_send(enet_driver[0].rxDaemonTid, RX_INTERRUPT_EVENT);
+}
+
+static rtems_isr
+mcf5282_fec_tx_interrupt_handler( rtems_vector_number v )
+{
+ MCF5282_FEC_EIR = MCF5282_FEC_EIR_TXF;
+ MCF5282_FEC_EIMR &= ~MCF5282_FEC_EIMR_TXF;
+ enet_driver[0].txInterrupts++;
+ rtems_bsdnet_event_send(enet_driver[0].txDaemonTid, TX_INTERRUPT_EVENT);
+}
+
+static rtems_isr
+mcf5282_mii_interrupt_handler( rtems_vector_number v )
+{
+ uint16 sr2;
+
+ enet_driver[0].miiInterrupts++;
+ getMII(1, 19); /* Read and clear interrupt status bits */
+ enet_driver[0].mii_sr2 = sr2 = getMII(1, 17);
+ if (((sr2 & 0x200) != 0)
+ && ((MCF5282_FEC_TCR & MCF5282_FEC_TCR_FDEN) == 0))
+ MCF5282_FEC_TCR |= MCF5282_FEC_TCR_FDEN;
+ else if (((sr2 & 0x200) == 0)
+ && ((MCF5282_FEC_TCR & MCF5282_FEC_TCR_FDEN) != 0))
+ MCF5282_FEC_TCR &= ~MCF5282_FEC_TCR_FDEN;
+}
+
+/*
+ * Allocate buffer descriptors from (non-cached) on-chip static RAM
+ * Ensure 128-bit (16-byte) alignment
+ * Allow some space at the beginning for other diagnostic counters
+ */
+static mcf5282BufferDescriptor_t *
+mcf5282_bd_allocate(unsigned int count)
+{
+ static mcf5282BufferDescriptor_t *bdp = __SRAMBASE.fec_descriptors;
+ mcf5282BufferDescriptor_t *p = bdp;
+
+ bdp += count;
+ if ((int)bdp & 0xF)
+ bdp = (mcf5282BufferDescriptor_t *)((char *)bdp + (16 - ((int)bdp & 0xF)));
+ return p;
+}
+
+static void
+mcf5282_fec_initialize_hardware(struct mcf5282_enet_struct *sc)
+{
+ int i;
+ const unsigned char *hwaddr;
+ rtems_status_code status;
+ rtems_isr_entry old_handler;
+ uint32_t clock_speed = bsp_get_CPU_clock_speed();
+
+ /*
+ * Issue reset to FEC
+ */
+ MCF5282_FEC_ECR = MCF5282_FEC_ECR_RESET;
+ rtems_task_wake_after(2);
+ MCF5282_FEC_ECR = 0;
+
+ /*
+ * Configuration of I/O ports is done outside of this function
+ */
+#if 0
+ imm->gpio.pbcnt |= MCF5282_GPIO_PBCNT_SET_FEC; /* Set up port b FEC pins */
+#endif
+
+ /*
+ * Set our physical address
+ */
+ hwaddr = sc->arpcom.ac_enaddr;
+ MCF5282_FEC_PALR = (hwaddr[0] << 24) | (hwaddr[1] << 16) |
+ (hwaddr[2] << 8) | (hwaddr[3] << 0);
+ MCF5282_FEC_PAUR = (hwaddr[4] << 24) | (hwaddr[5] << 16);
+
+
+ /*
+ * Clear the hash table
+ */
+ MCF5282_FEC_GAUR = 0;
+ MCF5282_FEC_GALR = 0;
+
+ /*
+ * Set up receive buffer size
+ */
+ MCF5282_FEC_EMRBR = 1520; /* Standard Ethernet */
+
+ /*
+ * Allocate mbuf pointers
+ */
+ sc->rxMbuf = malloc(sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);
+ sc->txMbuf = malloc(sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);
+ if (!sc->rxMbuf || !sc->txMbuf)
+ rtems_panic("No memory for mbuf pointers");
+
+ /*
+ * Set receiver and transmitter buffer descriptor bases
+ */
+ sc->rxBdBase = mcf5282_bd_allocate(sc->rxBdCount);
+ sc->txBdBase = mcf5282_bd_allocate(sc->txBdCount);
+ MCF5282_FEC_ERDSR = (int)sc->rxBdBase;
+ MCF5282_FEC_ETDSR = (int)sc->txBdBase;
+
+ /*
+ * Set up Receive Control Register:
+ * Not promiscuous
+ * MII mode
+ * Full duplex
+ * No loopback
+ */
+ MCF5282_FEC_RCR = MCF5282_FEC_RCR_MAX_FL(MAX_MTU_SIZE) |
+ MCF5282_FEC_RCR_MII_MODE;
+
+ /*
+ * Set up Transmit Control Register:
+ * Full or half duplex
+ * No heartbeat
+ */
+ if (sc->link == link_10Half)
+ MCF5282_FEC_TCR = 0;
+ else
+ MCF5282_FEC_TCR = MCF5282_FEC_TCR_FDEN;
+
+ /*
+ * Initialize statistic counters
+ */
+ MCF5282_FEC_MIBC = MCF5282_FEC_MIBC_MIB_DISABLE;
+ {
+ vuint32 *vuip = &MCF5282_FEC_RMON_T_DROP;
+ while (vuip <= &MCF5282_FEC_IEEE_R_OCTETS_OK)
+ *vuip++ = 0;
+ }
+ MCF5282_FEC_MIBC = 0;
+
+ /*
+ * Set MII speed to <= 2.5 MHz
+ */
+ i = (clock_speed + 5000000 - 1) / 5000000;
+ MCF5282_FEC_MSCR = MCF5282_FEC_MSCR_MII_SPEED(i);
+
+ /*
+ * Set PHYS
+ * LED1 receive status, LED2 link status, LEDs stretched
+ * Advertise 100 Mb/s, full-duplex, IEEE-802.3
+ * Turn off auto-negotiate
+ * Clear status
+ */
+ setMII(1, 20, 0x24F2);
+ setMII(1, 4, 0x0181);
+ setMII(1, 0, 0x0);
+ rtems_task_wake_after(2);
+ sc->mii_sr2 = getMII(1, 17);
+ switch (sc->link) {
+ case link_auto:
+ /*
+ * Enable speed-change, duplex-change and link-status-change interrupts
+ * Enable auto-negotiate (start at 100/FULL)
+ */
+ setMII(1, 18, 0x0072);
+ setMII(1, 0, 0x3100);
+ break;
+
+ case link_10Half:
+ /*
+ * Force 10/HALF
+ */
+ setMII(1, 0, 0x0);
+ break;
+
+ case link_100Full:
+ /*
+ * Force 100/FULL
+ */
+ setMII(1, 0, 0x2100);
+ break;
+ }
+ sc->mii_cr = getMII(1, 0);
+
+ /*
+ * Set up receive buffer descriptors
+ */
+ for (i = 0 ; i < sc->rxBdCount ; i++)
+ (sc->rxBdBase + i)->status = 0;
+
+ /*
+ * Set up transmit buffer descriptors
+ */
+ for (i = 0 ; i < sc->txBdCount ; i++) {
+ sc->txBdBase[i].status = 0;
+ sc->txMbuf[i] = NULL;
+ }
+ sc->txBdHead = sc->txBdTail = 0;
+ sc->txBdActiveCount = 0;
+
+ /*
+ * Set up interrupts
+ */
+ status = rtems_interrupt_catch( mcf5282_fec_tx_interrupt_handler, FEC_INTC0_TX_VECTOR, &old_handler );
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't attach MCF5282 FEC TX interrupt handler: %s\n",
+ rtems_status_text(status));
+ bsp_allocate_interrupt(FEC_IRQ_LEVEL, FEC_IRQ_TX_PRIORITY);
+ MCF5282_INTC0_ICR23 = MCF5282_INTC_ICR_IL(FEC_IRQ_LEVEL) |
+ MCF5282_INTC_ICR_IP(FEC_IRQ_TX_PRIORITY);
+ MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT23 | MCF5282_INTC_IMRL_MASKALL);
+
+ status = rtems_interrupt_catch(mcf5282_fec_rx_interrupt_handler, FEC_INTC0_RX_VECTOR, &old_handler);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't attach MCF5282 FEC RX interrupt handler: %s\n",
+ rtems_status_text(status));
+ bsp_allocate_interrupt(FEC_IRQ_LEVEL, FEC_IRQ_RX_PRIORITY);
+ MCF5282_INTC0_ICR27 = MCF5282_INTC_ICR_IL(FEC_IRQ_LEVEL) |
+ MCF5282_INTC_ICR_IP(FEC_IRQ_RX_PRIORITY);
+ MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT27 | MCF5282_INTC_IMRL_MASKALL);
+
+ status = rtems_interrupt_catch(mcf5282_mii_interrupt_handler, MII_VECTOR, &old_handler);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_panic ("Can't attach MCF5282 FEC MII interrupt handler: %s\n",
+ rtems_status_text(status));
+ MCF5282_EPORT_EPPAR &= ~MII_EPPAR;
+ MCF5282_EPORT_EPDDR &= ~MII_EPDDR;
+ MCF5282_EPORT_EPIER |= MII_EPIER;
+ MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT7 | MCF5282_INTC_IMRL_MASKALL);
+}
+
+/*
+ * Soak up buffer descriptors that have been sent.
+ */
+static void
+fec_retire_tx_bd(volatile struct mcf5282_enet_struct *sc )
+{
+ struct mbuf *m, *n;
+ uint16_t status;
+
+ while ((sc->txBdActiveCount != 0)
+ && (((status = sc->txBdBase[sc->txBdTail].status) & MCF5282_FEC_TxBD_R) == 0)) {
+ if ((status & MCF5282_FEC_TxBD_TO1) == 0) {
+ m = sc->txMbuf[sc->txBdTail];
+ MFREE(m, n);
+ }
+ if (++sc->txBdTail == sc->txBdCount)
+ sc->txBdTail = 0;
+ sc->txBdActiveCount--;
+ }
+}
+
+static void
+fec_rxDaemon (void *arg)
+{
+ volatile struct mcf5282_enet_struct *sc = (volatile struct mcf5282_enet_struct *)arg;
+ struct ifnet *ifp = (struct ifnet* )&sc->arpcom.ac_if;
+ struct mbuf *m;
+ uint16_t status;
+ volatile mcf5282BufferDescriptor_t *rxBd;
+ int rxBdIndex;
+
+ /*
+ * Allocate space for incoming packets and start reception
+ */
+ for (rxBdIndex = 0 ; ;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+ MGETHDR(m, M_WAIT, MT_DATA);
+ MCLGET(m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->buffer = mtod(m, void *);
+ rxBd->status = MCF5282_FEC_RxBD_E;
+ if (++rxBdIndex == sc->rxBdCount) {
+ rxBd->status |= MCF5282_FEC_RxBD_W;
+ break;
+ }
+ }
+
+ /*
+ * Input packet handling loop
+ */
+ MCF5282_FEC_RDAR = 0;
+
+ rxBdIndex = 0;
+ for (;;) {
+ rxBd = sc->rxBdBase + rxBdIndex;
+
+ /*
+ * Wait for packet if there's not one ready
+ */
+ if ((status = rxBd->status) & MCF5282_FEC_RxBD_E) {
+ /*
+ * Clear old events.
+ */
+ MCF5282_FEC_EIR = MCF5282_FEC_EIR_RXF;
+
+ /*
+ * Wait for packet to arrive.
+ * Check the buffer descriptor before waiting for the event.
+ * This catches the case when a packet arrives between the
+ * `if' above, and the clearing of the RXF bit in the EIR.
+ */
+ while ((status = rxBd->status) & MCF5282_FEC_RxBD_E) {
+ rtems_event_set events;
+ int level;
+
+ rtems_interrupt_disable(level);
+ MCF5282_FEC_EIMR |= MCF5282_FEC_EIMR_RXF;
+ rtems_interrupt_enable(level);
+ rtems_bsdnet_event_receive (RX_INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ }
+ }
+
+ /*
+ * Check that packet is valid
+ */
+ if (status & MCF5282_FEC_RxBD_L) {
+ /*
+ * Pass the packet up the chain.
+ * FIXME: Packet filtering hook could be done here.
+ */
+ struct ether_header *eh;
+ int len = rxBd->length - sizeof(uint32_t);
+
+ m = sc->rxMbuf[rxBdIndex];
+#ifdef RTEMS_MCF5282_BSP_ENABLE_DATA_CACHE
+ /*
+ * Invalidate the cache. The cache is so small that it's
+ * reasonable to simply invalidate the whole thing.
+ */
+ rtems_cache_invalidate_entire_data();
+#endif
+ m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header);
+ eh = mtod(m, struct ether_header *);
+ m->m_data += sizeof(struct ether_header);
+ ether_input(ifp, eh, m);
+
+ /*
+ * Allocate a new mbuf
+ */
+ MGETHDR(m, M_WAIT, MT_DATA);
+ MCLGET(m, M_WAIT);
+ m->m_pkthdr.rcvif = ifp;
+ sc->rxMbuf[rxBdIndex] = m;
+ rxBd->buffer = mtod(m, void *);
+ }
+
+ /*
+ * Reenable the buffer descriptor
+ */
+ rxBd->status = (status & MCF5282_FEC_RxBD_W) | MCF5282_FEC_RxBD_E;
+ MCF5282_FEC_RDAR = 0;
+
+ /*
+ * Move to next buffer descriptor
+ */
+ if (++rxBdIndex == sc->rxBdCount)
+ rxBdIndex = 0;
+ }
+}
+
+static void
+fec_sendpacket(struct ifnet *ifp, struct mbuf *m)
+{
+ struct mcf5282_enet_struct *sc = ifp->if_softc;
+ volatile mcf5282BufferDescriptor_t *firstTxBd, *txBd;
+ uint16_t status;
+ int nAdded;
+
+ /*
+ * Free up buffer descriptors
+ */
+ fec_retire_tx_bd(sc);
+
+ /*
+ * Set up the transmit buffer descriptors.
+ * No need to pad out short packets since the
+ * hardware takes care of that automatically.
+ * No need to copy the packet to a contiguous buffer
+ * since the hardware is capable of scatter/gather DMA.
+ */
+ nAdded = 0;
+ firstTxBd = sc->txBdBase + sc->txBdHead;
+
+ while (m != NULL) {
+ /*
+ * Wait for buffer descriptor to become available
+ */
+ if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ /*
+ * Clear old events.
+ */
+ MCF5282_FEC_EIR = MCF5282_FEC_EIR_TXF;
+
+ /*
+ * Wait for buffer descriptor to become available.
+ * Check for buffer descriptors before waiting for the event.
+ * This catches the case when a buffer became available between
+ * the `if' above, and the clearing of the TXF bit in the EIR.
+ */
+ fec_retire_tx_bd(sc);
+ while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) {
+ rtems_event_set events;
+ int level;
+
+ rtems_interrupt_disable(level);
+ MCF5282_FEC_EIMR |= MCF5282_FEC_EIMR_TXF;
+ rtems_interrupt_enable(level);
+ sc->txRawWait++;
+ rtems_bsdnet_event_receive(TX_INTERRUPT_EVENT,
+ RTEMS_WAIT|RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT,
+ &events);
+ fec_retire_tx_bd(sc);
+ }
+ }
+
+ /*
+ * Don't set the READY flag on the first fragment
+ * until the whole packet has been readied.
+ */
+ status = nAdded ? MCF5282_FEC_TxBD_R : 0;
+
+ /*
+ * The IP fragmentation routine in ip_output
+ * can produce fragments with zero length.
+ */
+ txBd = sc->txBdBase + sc->txBdHead;
+ if (m->m_len) {
+ char *p = mtod(m, char *);
+ int offset = (int)p & 0x3;
+ if (offset == 0) {
+ txBd->buffer = p;
+ txBd->length = m->m_len;
+ sc->txMbuf[sc->txBdHead] = m;
+ m = m->m_next;
+ }
+ else {
+ /*
+ * Stupid FEC can't handle misaligned data!
+ * Move offending bytes to a local buffer.
+ * Use buffer descriptor TO1 bit to indicate this.
+ */
+ int nmove = 4 - offset;
+ char *d = (char *)&sc->txMbuf[sc->txBdHead];
+ status |= MCF5282_FEC_TxBD_TO1;
+ sc->txRealign++;
+ if (nmove > m->m_len)
+ nmove = m->m_len;
+ m->m_data += nmove;
+ m->m_len -= nmove;
+ txBd->buffer = d;
+ txBd->length = nmove;
+ while (nmove--)
+ *d++ = *p++;
+ if (m->m_len == 0) {
+ struct mbuf *n;
+ sc->txRealignDrop++;
+ MFREE(m, n);
+ m = n;
+ }
+ }
+ nAdded++;
+ if (++sc->txBdHead == sc->txBdCount) {
+ status |= MCF5282_FEC_TxBD_W;
+ sc->txBdHead = 0;
+ }
+ txBd->status = status;
+ }
+ else {
+ /*
+ * Toss empty mbufs.
+ */
+ struct mbuf *n;
+ MFREE(m, n);
+ m = n;
+ }
+ }
+ if (nAdded) {
+ txBd->status = status | MCF5282_FEC_TxBD_R
+ | MCF5282_FEC_TxBD_L
+ | MCF5282_FEC_TxBD_TC;
+ if (nAdded > 1)
+ firstTxBd->status |= MCF5282_FEC_TxBD_R;
+ MCF5282_FEC_TDAR = 0;
+ sc->txBdActiveCount += nAdded;
+ }
+}
+
+void
+fec_txDaemon(void *arg)
+{
+ struct mcf5282_enet_struct *sc = (struct mcf5282_enet_struct *)arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_event_set events;
+
+ for (;;) {
+ /*
+ * Wait for packet
+ */
+ rtems_bsdnet_event_receive(START_TRANSMIT_EVENT,
+ RTEMS_EVENT_ANY | RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT,
+ &events);
+
+ /*
+ * Send packets till queue is empty
+ */
+ for (;;) {
+ /*
+ * Get the next mbuf chain to transmit.
+ */
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (!m)
+ break;
+ fec_sendpacket(ifp, m);
+ }
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+}
+
+
+/*
+ * Send packet (caller provides header).
+ */
+static void
+mcf5282_enet_start(struct ifnet *ifp)
+{
+ struct mcf5282_enet_struct *sc = ifp->if_softc;
+
+ rtems_bsdnet_event_send(sc->txDaemonTid, START_TRANSMIT_EVENT);
+ ifp->if_flags |= IFF_OACTIVE;
+}
+
+static void
+fec_init(void *arg)
+{
+ struct mcf5282_enet_struct *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ if (sc->txDaemonTid == 0) {
+ /*
+ * Set up hardware
+ */
+ mcf5282_fec_initialize_hardware(sc);
+
+ /*
+ * Start driver tasks
+ */
+ sc->txDaemonTid = rtems_bsdnet_newproc("FECtx", 4096, fec_txDaemon, sc);
+ sc->rxDaemonTid = rtems_bsdnet_newproc("FECrx", 4096, fec_rxDaemon, sc);
+ }
+
+ /*
+ * Set flags appropriately
+ */
+ if (ifp->if_flags & IFF_PROMISC)
+ MCF5282_FEC_RCR |= MCF5282_FEC_RCR_PROM;
+ else
+ MCF5282_FEC_RCR &= ~MCF5282_FEC_RCR_PROM;
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+
+ /*
+ * Enable receiver and transmitter
+ */
+ MCF5282_FEC_ECR = MCF5282_FEC_ECR_ETHER_EN;
+}
+
+
+static void
+fec_stop(struct mcf5282_enet_struct *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ /*
+ * Shut down receiver and transmitter
+ */
+ MCF5282_FEC_ECR = 0x0;
+}
+
+/*
+ * Show interface statistics
+ */
+static void
+enet_stats(struct mcf5282_enet_struct *sc)
+{
+ printf(" Rx Interrupts:%-10lu", sc->rxInterrupts);
+ printf("Rx Packet Count:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_PACKETS);
+ printf(" Rx Broadcast:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_BC_PKT);
+ printf(" Rx Multicast:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_MC_PKT);
+ printf("CRC/Align error:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_CRC_ALIGN);
+ printf(" Rx Undersize:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_UNDERSIZE);
+ printf(" Rx Oversize:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_OVERSIZE);
+ printf(" Rx Fragment:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_FRAG);
+ printf(" Rx Jabber:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_JAB);
+ printf(" Rx 64:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_P64);
+ printf(" Rx 65-127:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_P65T0127);
+ printf(" Rx 128-255:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_P128TO255);
+ printf(" Rx 256-511:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_P256TO511);
+ printf(" Rx 511-1023:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_P512TO1023);
+ printf(" Rx 1024-2047:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_R_P1024TO2047);
+ printf(" Rx >=2048:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_GTE2048);
+ printf(" Rx Octets:%-10lu", (uint32_t) MCF5282_FEC_RMON_R_OCTETS);
+ printf(" Rx Dropped:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_R_DROP);
+ printf(" Rx frame OK:%-10lu", (uint32_t) MCF5282_FEC_IEEE_R_FRAME_OK);
+ printf(" Rx CRC error:%-10lu", (uint32_t) MCF5282_FEC_IEEE_R_CRC);
+ printf(" Rx Align error:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_R_ALIGN);
+ printf(" FIFO Overflow:%-10lu", (uint32_t) MCF5282_FEC_IEEE_R_MACERR);
+ printf("Rx Pause Frames:%-10lu", (uint32_t) MCF5282_FEC_IEEE_R_FDXFC);
+ printf(" Rx Octets OK:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_R_OCTETS_OK);
+ printf(" Tx Interrupts:%-10lu", sc->txInterrupts);
+ printf("Tx Output Waits:%-10lu", sc->txRawWait);
+ printf("Tx mbuf realign:%-10lu\n", sc->txRealign);
+ printf("Tx realign drop:%-10lu", sc->txRealignDrop);
+ printf(" Tx Unaccounted:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_DROP);
+ printf("Tx Packet Count:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_PACKETS);
+ printf(" Tx Broadcast:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_BC_PKT);
+ printf(" Tx Multicast:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_MC_PKT);
+ printf("CRC/Align error:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_CRC_ALIGN);
+ printf(" Tx Undersize:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_UNDERSIZE);
+ printf(" Tx Oversize:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_OVERSIZE);
+ printf(" Tx Fragment:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_FRAG);
+ printf(" Tx Jabber:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_JAB);
+ printf(" Tx Collisions:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_COL);
+ printf(" Tx 64:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_P64);
+ printf(" Tx 65-127:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_P65TO127);
+ printf(" Tx 128-255:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_P128TO255);
+ printf(" Tx 256-511:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_P256TO511);
+ printf(" Tx 511-1023:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_P512TO1023);
+ printf(" Tx 1024-2047:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_P1024TO2047);
+ printf(" Tx >=2048:%-10lu\n", (uint32_t) MCF5282_FEC_RMON_T_P_GTE2048);
+ printf(" Tx Octets:%-10lu", (uint32_t) MCF5282_FEC_RMON_T_OCTETS);
+ printf(" Tx Dropped:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_DROP);
+ printf(" Tx Frame OK:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_T_FRAME_OK);
+ printf(" Tx 1 Collision:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_1COL);
+ printf("Tx >1 Collision:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_MCOL);
+ printf(" Tx Deferred:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_T_DEF);
+ printf(" Late Collision:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_LCOL);
+ printf(" Excessive Coll:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_EXCOL);
+ printf(" FIFO Underrun:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_T_MACERR);
+ printf(" Carrier Error:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_CSERR);
+ printf(" Tx SQE Error:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_SQE);
+ printf("Tx Pause Frames:%-10lu\n", (uint32_t) MCF5282_FEC_IEEE_T_FDXFC);
+ printf(" Tx Octets OK:%-10lu", (uint32_t) MCF5282_FEC_IEEE_T_OCTETS_OK);
+ printf(" MII interrupts:%-10lu\n", sc->miiInterrupts);
+ if ((sc->mii_sr2 & 0x400) == 0) {
+ printf("LINK DOWN!\n");
+ }
+ else {
+ int speed;
+ int full;
+ int fixed;
+ if (sc->mii_cr & 0x1000) {
+ fixed = 0;
+ speed = sc->mii_sr2 & 0x4000 ? 100 : 10;
+ full = sc->mii_sr2 & 0x200 ? 1 : 0;
+ }
+ else {
+ fixed = 1;
+ speed = sc->mii_cr & 0x2000 ? 100 : 10;
+ full = sc->mii_cr & 0x100 ? 1 : 0;
+ }
+ printf("Link %s %d Mb/s, %s-duplex.\n",
+ fixed ? "fixed" : "auto-negotiate",
+ speed,
+ full ? "full" : "half");
+ }
+ printf(" EIR:%8.8lx ", (uint32_t) MCF5282_FEC_EIR);
+ printf("EIMR:%8.8lx ", (uint32_t) MCF5282_FEC_EIMR);
+ printf("RDAR:%8.8lx ", (uint32_t) MCF5282_FEC_RDAR);
+ printf("TDAR:%8.8lx\n", (uint32_t) MCF5282_FEC_TDAR);
+ printf(" ECR:%8.8lx ", (uint32_t) MCF5282_FEC_ECR);
+ printf(" RCR:%8.8lx ", (uint32_t) MCF5282_FEC_RCR);
+ printf(" TCR:%8.8lx\n", (uint32_t) MCF5282_FEC_TCR);
+ printf("FRBR:%8.8lx ", (uint32_t) MCF5282_FEC_FRBR);
+ printf("FRSR:%8.8lx\n", (uint32_t) MCF5282_FEC_FRSR);
+ if (sc->txBdActiveCount != 0) {
+ int i, n;
+ /*
+ * Yes, there are races here with adding and retiring descriptors,
+ * but this diagnostic is more for when things have backed up.
+ */
+ printf("Transmit Buffer Descriptors (Tail %d, Head %d, Unretired %d):\n",
+ sc->txBdTail,
+ sc->txBdHead,
+ sc->txBdActiveCount);
+ i = sc->txBdTail;
+ for (n = 0 ; n < sc->txBdCount ; n++) {
+ if ((sc->txBdBase[i].status & MCF5282_FEC_TxBD_R) != 0)
+ printf(" %3d: status:%4.4x length:%-4d buffer:%p\n",
+ i,
+ sc->txBdBase[i].status,
+ sc->txBdBase[i].length,
+ sc->txBdBase[i].buffer);
+ if (++i == sc->txBdCount)
+ i = 0;
+ }
+ }
+}
+
+static int
+fec_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
+{
+ struct mcf5282_enet_struct *sc = ifp->if_softc;
+ int error = 0;
+
+ switch (command) {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ ether_ioctl(ifp, command, data);
+ break;
+
+ case SIOCSIFFLAGS:
+ switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
+ case IFF_RUNNING:
+ fec_stop(sc);
+ break;
+
+ case IFF_UP:
+ fec_init(sc);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ fec_stop(sc);
+ fec_init(sc);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ enet_stats(sc);
+ break;
+
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+int
+rtems_fec_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching )
+{
+ struct mcf5282_enet_struct *sc;
+ struct ifnet *ifp;
+ int mtu;
+ int unitNumber;
+ char *unitName;
+ const unsigned char *hwaddr;
+ const char *env;
+
+ /*
+ * Parse driver name
+ */
+ if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
+ return 0;
+
+ /*
+ * Is driver free?
+ */
+ if ((unitNumber <= 0) || (unitNumber > NIFACES)) {
+ printf("Bad FEC unit number.\n");
+ return 0;
+ }
+ sc = &enet_driver[unitNumber - 1];
+ ifp = &sc->arpcom.ac_if;
+ if (ifp->if_softc != NULL) {
+ printf("Driver already in use.\n");
+ return 0;
+ }
+
+ /*
+ * Process options
+ */
+ if (config->hardware_address) {
+ hwaddr = config->hardware_address;
+ } else if ((hwaddr = bsp_gethwaddr(unitNumber - 1)) == NULL) {
+ /* Locally-administered address */
+ static const unsigned char defaultAddress[ETHER_ADDR_LEN] = {
+ 0x06, 'R', 'T', 'E', 'M', 'S'};
+ printf ("WARNING -- No %s%d Ethernet address specified "
+ "-- Using default address.\n", unitName, unitNumber);
+ hwaddr = defaultAddress;
+ }
+ printf("%s%d: Ethernet address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ unitName, unitNumber,
+ hwaddr[0], hwaddr[1], hwaddr[2],
+ hwaddr[3], hwaddr[4], hwaddr[5]);
+ memcpy(sc->arpcom.ac_enaddr, hwaddr, ETHER_ADDR_LEN);
+
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+ if (config->rbuf_count)
+ sc->rxBdCount = config->rbuf_count;
+ else
+ sc->rxBdCount = RX_BUF_COUNT;
+ if (config->xbuf_count)
+ sc->txBdCount = config->xbuf_count;
+ else
+ sc->txBdCount = TX_BUF_COUNT * TX_BD_PER_BUF;
+
+ sc->acceptBroadcast = !config->ignore_broadcast;
+
+ /*
+ * Set up network interface values
+ */
+ ifp->if_softc = sc;
+ ifp->if_unit = unitNumber;
+ ifp->if_name = unitName;
+ ifp->if_mtu = mtu;
+ ifp->if_init = fec_init;
+ ifp->if_ioctl = fec_ioctl;
+ ifp->if_start = mcf5282_enet_start;
+ ifp->if_output = ether_output;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ /*
+ * Check for environment overrides
+ */
+ if (((env = bsp_getbenv("IPADDR0_100FULL")) != NULL)
+ && ((*env == 'y') || (*env == 'Y')))
+ sc->link = link_100Full;
+ else if (((env = bsp_getbenv("IPADDR0_10HALF")) != NULL)
+ && ((*env == 'y') || (*env == 'Y')))
+ sc->link = link_10Half;
+ else
+ sc->link = link_auto;
+
+ /*
+ * Attach the interface
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ return 1;
+};