diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-23 09:53:31 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-23 15:18:44 +0200 |
commit | 031df3914990db0336a0d386fb53558b05de467e (patch) | |
tree | 4661e22f0cdb3f9d06879f0194b77c75f62bac79 /bsps/m68k/csb360/net/network.c | |
parent | bsps: Move interrupt controller support to bsps (diff) | |
download | rtems-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/csb360/net/network.c')
-rw-r--r-- | bsps/m68k/csb360/net/network.c | 984 |
1 files changed, 984 insertions, 0 deletions
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; +}; + + |