From 398ed76051383f5be5c73b4375add5297c68d2cf Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 3 Sep 2003 13:29:15 +0000 Subject: 2003-09-03 Jiri Gaisler PR 477/networking * network/Makefile.am: Add driver for OpenCores NIC. * network/README.open_eth, network/open_eth.c, network/open_eth.h: New files. --- c/src/libchip/ChangeLog | 7 + c/src/libchip/network/Makefile.am | 10 +- c/src/libchip/network/README.open_eth | 73 ++++ c/src/libchip/network/open_eth.c | 739 ++++++++++++++++++++++++++++++++++ c/src/libchip/network/open_eth.h | 173 ++++++++ 5 files changed, 998 insertions(+), 4 deletions(-) create mode 100644 c/src/libchip/network/README.open_eth create mode 100644 c/src/libchip/network/open_eth.c create mode 100644 c/src/libchip/network/open_eth.h (limited to 'c/src/libchip') diff --git a/c/src/libchip/ChangeLog b/c/src/libchip/ChangeLog index 65eb1c960a..1666e9f371 100644 --- a/c/src/libchip/ChangeLog +++ b/c/src/libchip/ChangeLog @@ -1,3 +1,10 @@ +2003-09-03 Jiri Gaisler + + PR 477/networking + * network/Makefile.am: Add driver for OpenCores NIC. + * network/README.open_eth, network/open_eth.c, network/open_eth.h: + New files. + 2003-08-21 Ralf Corsepius * ide/Makefile.am: Don't include @RTEMS_BSP@.cfg. diff --git a/c/src/libchip/network/Makefile.am b/c/src/libchip/network/Makefile.am index 5d228c98be..79f6c3cca1 100644 --- a/c/src/libchip/network/Makefile.am +++ b/c/src/libchip/network/Makefile.am @@ -6,7 +6,7 @@ LIBNAME = libnetchip LIB = $(ARCH)/$(LIBNAME).a -C_FILES = cs8900.c dec21140.c i82586.c sonic.c if_fxp.c elnk.c +C_FILES = cs8900.c dec21140.c i82586.c sonic.c if_fxp.c elnk.c open_eth.c OBJS = $(C_FILES:%.c=$(ARCH)/%.$(OBJEXT)) include $(top_srcdir)/automake/compile.am @@ -25,7 +25,8 @@ AM_CPPFLAGS += -D__INSIDE_RTEMS_BSD_TCPIP_STACK__ if LIBCHIP include_libchipdir = $(includedir)/libchip -include_libchip_HEADERS = cs8900.h i82586var.h if_fxpvar.h sonic.h if_media.h mii.h +include_libchip_HEADERS = cs8900.h i82586var.h if_fxpvar.h sonic.h if_media.h \ + mii.h open_eth.h $(LIB): $(OBJS) $(make-library) @@ -47,7 +48,8 @@ endif .PRECIOUS: $(LIB) -EXTRA_DIST = README README.cs8900 README.dec21140 README.i82586 README.sonic \ - cs8900.c cs8900.c.bsp dec21140.c i82586.c if_fxp.c sonic.c +EXTRA_DIST = README README.cs8900 README.dec21140 README.i82586 \ + README.open_eth README.sonic cs8900.c cs8900.c.bsp dec21140.c \ + i82586.c if_fxp.c open_eth.c sonic.c include $(top_srcdir)/automake/local.am diff --git a/c/src/libchip/network/README.open_eth b/c/src/libchip/network/README.open_eth new file mode 100644 index 0000000000..c96d2e5ab7 --- /dev/null +++ b/c/src/libchip/network/README.open_eth @@ -0,0 +1,73 @@ + +Driver for opencores ethernet MAC - README +------------------------------------------ + +The device name for the driver is 'open_eth1', the attach +function for the leon bsp is rtems_leon_open_eth_driver_attach(). + +No cache flushing is made when a frame is received. On leon, +this means that cache snooping must be configured in the +vhdl model and enabled by software. + +TX interrupts are not used and masked in the interrupt mask +register. + +For now, only 10 Mbit/s half-duplex is supported. +100 Mbit/s operations does not work reliably, the transmitter +locks up or skips frames. Seems to depend on the TX fifo +implementation in the opencores MAC. Send a mail to +jiri@gaisler.com if you know how to fix this. + +Tested only on leon, using the GR-PCI-XC2V board @ 40 MHz. +Output from ttcp receiving 1 Mbyte file: + +>>> ttcp -r -s +ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp +ttcp-r: socket +ttcp-r: accept from 192.168.0.2 +ttcp-r: 1145339 bytes in 1.18 real seconds = 947.88 KB/sec +++ +ttcp-r: 792 I/O calls, msec/call = 1.53, calls/sec = 671.19 +ttcp-r: 0.0user 1.1sys 0:01real 100% 0i+0d 0maxrss 0+0pf 0+0csw +************ MBUF STATISTICS ************ +mbufs:1024 clusters: 128 free: 112 +drops: 0 waits: 0 drains: 0 + free:1007 data:17 header:0 socket:0 + pcb:0 rtable:0 htable:0 atable:0 + soname:0 soopts:0 ftable:0 rights:0 + ifaddr:0 control:0 oobdata:0 + +************ INTERFACE STATISTICS ************ +***** open_eth1 ***** +Address:192.168.0.66 Broadcast Address:192.168.0.255 +Flags: Up Broadcast Running Simplex +Send queue limit:50 length:0 Dropped:0 + Rx Packets:796 Rx Interrupts:796 Length:0 + Bad CRC:0 Overrun:0 Miss:0 + Tx Interrupts:0 Deferred:0 Missed Hearbeat:0 + No Carrier:0 Retransmit Limit:0 Late Collision:0 + Underrun:0 Raw output wait:0 + +************ IP Statistics ************ + total packets received 795 + datagrams delivered to upper level 795 + total ip packets generated here 401 + +************ TCP Statistics ************ + connections accepted 1 + connections established 1 + conn. closed (includes drops) 1 + segs where we tried to get rtt 2 + times we succeeded 2 + delayed acks sent 4 + total packets sent 401 + ack-only packets sent 6 + window update-only packets sent 394 + control (SYN|FIN|RST) packets sent 1 + total packets received 795 + packets received in sequence 792 + bytes received in sequence 1145339 + rcvd ack packets 2 + bytes acked by rcvd acks 2 + times hdr predict ok for data pkts 791 + + diff --git a/c/src/libchip/network/open_eth.c b/c/src/libchip/network/open_eth.c new file mode 100644 index 0000000000..668fc92442 --- /dev/null +++ b/c/src/libchip/network/open_eth.c @@ -0,0 +1,739 @@ +/* + * RTEMS driver for Opencores Ethernet Controller + * + * Weakly based on dec21140 rtems driver and open_eth linux driver + * Written by Jiri Gaisler, Gaisler Research + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + */ + +#include + +#define OPEN_ETH_SUPPORTED +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#ifdef malloc +#undef malloc +#endif +#ifdef free +#undef free +#endif + + /* +#define OPEN_ETH_DEBUG + */ + +#ifdef CPU_U32_FIX +extern void ipalign(struct mbuf *m); +#endif + +/* message descriptor entry */ +struct MDTX +{ + char *buf; +}; + +struct MDRX +{ + struct mbuf *m; +}; + +/* + * Number of OCs supported by this driver + */ +#define NOCDRIVER 1 + +/* + * Receive buffer size -- Allow for a full ethernet packet including CRC + */ +#define RBUF_SIZE 1536 + +#define ET_MINLEN 64 /* minimum message length */ + +/* + * 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 + + /* event to send when tx buffers become available */ +#define OPEN_ETH_TX_WAIT_EVENT RTEMS_EVENT_3 + + /* suspend when all TX descriptors exhausted */ + /* +#define OETH_SUSPEND_NOTXBUF + */ + +#define OETH_RATE_10MHZ + +#if (MCLBYTES < RBUF_SIZE) +# error "Driver must have MCLBYTES > RBUF_SIZE" +#endif + +/* + * Per-device data + */ +struct open_eth_softc +{ + + struct arpcom arpcom; + + oeth_regs *regs; + + int acceptBroadcast; + rtems_id rxDaemonTid; + rtems_id txDaemonTid; + + unsigned int tx_ptr; + unsigned int rx_ptr; + unsigned int txbufs; + unsigned int rxbufs; + struct MDTX *txdesc; + struct MDRX *rxdesc; + rtems_vector_number vector; + + + /* + * Statistics + */ + unsigned long rxInterrupts; + unsigned long rxPackets; + unsigned long rxLengthError; + unsigned long rxNonOctet; + unsigned long rxBadCRC; + unsigned long rxOverrun; + unsigned long rxMiss; + 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; +}; + +static struct open_eth_softc oc; + +/* OPEN_ETH interrupt handler */ + +static rtems_isr +open_eth_interrupt_handler (rtems_vector_number v) +{ + unsigned32 status; + + /* read and clear interrupt cause */ + + status = oc.regs->int_src; + oc.regs->int_src = status; + + /* Frame received? */ + + if (status & (OETH_INT_RXF | OETH_INT_RXE)) + { + oc.rxInterrupts++; + rtems_event_send (oc.rxDaemonTid, INTERRUPT_EVENT); + } +#ifdef OETH_SUSPEND_NOTXBUF + if (status & (OETH_INT_MASK_TXB | OETH_INT_MASK_TXC | OETH_INT_MASK_TXE)) + { + oc.txInterrupts++; + rtems_event_send (oc.txDaemonTid, OPEN_ETH_TX_WAIT_EVENT); + } +#endif + /* +#ifdef __leon__ + LEON_Clear_interrupt(v-0x10); +#endif + */ +} + +static unsigned32 read_mii(unsigned32 addr) +{ + while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {} + oc.regs->miiaddress = addr << 8; + oc.regs->miicommand = OETH_MIICOMMAND_RSTAT; + while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {} + if (!(oc.regs->miistatus & OETH_MIISTATUS_NVALID)) + return(oc.regs->miirx_data); + else { + printf("open_eth: failed to read mii\n"); + return (0); + } +} + +static void write_mii(unsigned32 addr, unsigned32 data) +{ + while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {} + oc.regs->miiaddress = addr << 8; + oc.regs->miitx_data = data; + oc.regs->miicommand = OETH_MIICOMMAND_WCTRLDATA; + while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {} +} +/* + * Initialize the ethernet hardware + */ +static void +open_eth_initialize_hardware (struct open_eth_softc *sc) +{ + struct mbuf *m; + int i; + int mii_cr = 0; + + oeth_regs *regs; + + regs = sc->regs; + + /* Reset the controller. */ + + regs->ctrlmoder = 0; + regs->moder = OETH_MODER_RST; /* Reset ON */ + regs->moder = 0; /* Reset OFF */ + + /* reset PHY and wait for complettion */ + mii_cr = read_mii(0); + mii_cr = 0x3320; +#ifdef OETH_RATE_10MHZ + mii_cr = 0; +#endif + write_mii(0, mii_cr | 0x8000); + while (read_mii(0) & 0x8000) {} + write_mii(20, 0x1422); +#ifdef OETH_RATE_10MHZ + mii_cr = 0; +#endif + write_mii(0, mii_cr); + printf("open_eth: driver attached, PHY config : 0x%04x\n", read_mii(0)); + +#ifdef OPEN_ETH_DEBUG + printf("mii_cr: %04x\n", mii_cr); + for (i=0;i<21;i++) + printf("mii_reg %2d : 0x%04x\n", i, read_mii(i)); +#endif + + /* Setting TXBD base to sc->txbufs */ + + regs->tx_bd_num = sc->txbufs; + + /* Initialize rx/tx pointers. */ + + sc->rx_ptr = 0; + sc->tx_ptr = 0; + + /* Set min/max packet length */ + regs->packet_len = 0x00400600; + + /* Set IPGT register to recomended value */ + regs->ipgt = 0x00000015; + + /* Set IPGR1 register to recomended value */ + regs->ipgr1 = 0x0000000c; + + /* Set IPGR2 register to recomended value */ + regs->ipgr2 = 0x00000012; + + /* Set COLLCONF register to recomended value */ + regs->collconf = 0x000f003f; + + /* initialize TX descriptors */ + + sc->txdesc = calloc(sc->txbufs, sizeof(*sc->txdesc)); + for (i = 0; i < sc->txbufs; i++) + { + sc->regs->xd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; + sc->txdesc[i].buf = calloc(1, OETH_MAXBUF_LEN); +#ifdef OPEN_ETH_DEBUG + printf("TXBUF: %08x\n", (int) sc->txdesc[i].buf); +#endif + } + sc->regs->xd[sc->txbufs - 1].len_status |= OETH_TX_BD_WRAP; + + /* allocate RX buffers */ + + sc->rxdesc = calloc(sc->rxbufs, sizeof(*sc->rxdesc)); + for (i = 0; i < sc->rxbufs; i++) + { + + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = &sc->arpcom.ac_if; + sc->rxdesc[i].m = m; + sc->regs->xd[i + sc->txbufs].addr = mtod (m, unsigned32 *); + sc->regs->xd[i + sc->txbufs].len_status = + OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; +#ifdef OPEN_ETH_DEBUG + printf("RXBUF: %08x\n", (int) sc->rxdesc[i].m); +#endif + } + sc->regs->xd[sc->rxbufs + sc->txbufs - 1].len_status |= OETH_RX_BD_WRAP; + + + /* set ethernet address. */ + + regs->mac_addr1 = sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1]; + regs->mac_addr0 = sc->arpcom.ac_enaddr[2] << 24 | sc->arpcom.ac_enaddr[3] << 16 | + sc->arpcom.ac_enaddr[4] << 8 | sc->arpcom.ac_enaddr[5]; + + /* install interrupt vector */ + set_vector (open_eth_interrupt_handler, sc->vector, 1); + + /* clear all pending interrupts */ + + regs->int_src = 0xffffffff; + + /* MAC mode register: PAD, IFG, CRCEN */ + + regs->moder = OETH_MODER_PAD | OETH_MODER_CRCEN | ((mii_cr & 0x100) << 2); + + /* enable interrupts */ + + regs->int_mask = OETH_INT_MASK_RXF | OETH_INT_MASK_RXE | OETH_INT_MASK_RXC; + +#ifdef OETH_SUSPEND_NOTXBUF + regs->int_mask |= OETH_INT_MASK_TXB | OETH_INT_MASK_TXC | OETH_INT_MASK_TXE | OETH_INT_BUSY;*/ + sc->regs->xd[(sc->txbufs - 1)/2].len_status |= OETH_TX_BD_IRQ; + sc->regs->xd[sc->txbufs - 1].len_status |= OETH_TX_BD_IRQ; +#endif + + regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN; +} + +static void +open_eth_rxDaemon (void *arg) +{ + struct ether_header *eh; + struct open_eth_softc *dp = (struct open_eth_softc *) &oc; + struct ifnet *ifp = &dp->arpcom.ac_if; + struct mbuf *m; + unsigned int len, len_status, bad; + rtems_event_set events; + + + for (;;) + { + + rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT | RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, &events); +#ifdef OPEN_ETH_DEBUG + printf ("r\n"); +#endif + + while (! + ((len_status = + dp->regs->xd[dp->rx_ptr+dp->txbufs].len_status) & OETH_RX_BD_EMPTY)) + { + bad = 0; + if (len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) + { + dp->rxLengthError++; + bad = 1; + } + if (len_status & OETH_RX_BD_DRIBBLE) + { + dp->rxNonOctet++; + bad = 1; + } + if (len_status & OETH_RX_BD_CRCERR) + { + dp->rxBadCRC++; + bad = 1; + } + if (len_status & OETH_RX_BD_OVERRUN) + { + dp->rxOverrun++; + bad = 1; + } + if (len_status & OETH_RX_BD_MISS) + { + dp->rxMiss++; + bad = 1; + } + if (len_status & OETH_RX_BD_LATECOL) + { + dp->rxCollision++; + bad = 1; + } + + if (!bad) + { + /* pass on the packet in the receive buffer */ + len = len_status >> 16; + m = (struct mbuf *) (dp->rxdesc[dp->rx_ptr].m); + 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); +#ifdef CPU_U32_FIX + ipalign(m); /* Align packet on 32-bit boundary */ +#endif + + ether_input (ifp, eh, m); + + /* get a new mbuf */ + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + dp->rxdesc[dp->rx_ptr].m = m; + dp->regs->xd[dp->rx_ptr + dp->txbufs].addr = + (unsigned32 *) mtod (m, void *); + dp->rxPackets++; + } + + dp->regs->xd[dp->rx_ptr+dp->txbufs].len_status = + (dp->regs->xd[dp->rx_ptr+dp->txbufs].len_status & + ~OETH_TX_BD_STATS) | OETH_TX_BD_READY; + dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs; + } + } +} + +static int inside = 0; +static void +sendpacket (struct ifnet *ifp, struct mbuf *m) +{ + struct open_eth_softc *dp = ifp->if_softc; + unsigned char *temp; + struct mbuf *n; + unsigned int len, len_status; + + if (inside) printf ("error: sendpacket re-entered!!\n"); + inside = 1; + /* + * Waiting for Transmitter ready + */ + n = m; + + while (dp->regs->xd[dp->tx_ptr].len_status & OETH_TX_BD_READY) + { +#ifdef OETH_SUSPEND_NOTXBUF + rtems_event_set events; + rtems_bsdnet_event_receive (OPEN_ETH_TX_WAIT_EVENT, + RTEMS_WAIT | RTEMS_EVENT_ANY, + TOD_MILLISECONDS_TO_TICKS(500), &events); +#endif + } + + len = 0; + temp = (unsigned char *) dp->txdesc[dp->tx_ptr].buf; + dp->regs->xd[dp->tx_ptr].addr = (unsigned32 *) temp; + +#ifdef OPEN_ETH_DEBUG + printf("TXD: 0x%08x\n", (int) m->m_data); +#endif + for (;;) + { +#ifdef OPEN_ETH_DEBUG + int i; + printf("MBUF: 0x%08x : ", (int) m->m_data); + for (i=0;im_len;i++) + printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff); + printf("\n"); +#endif + len += m->m_len; + if (len <= RBUF_SIZE) + memcpy ((void *) temp, (char *) m->m_data, m->m_len); + temp += m->m_len; + if ((m = m->m_next) == NULL) + break; + } + + m_freem (n); + + /* don't send long packets */ + + if (len <= RBUF_SIZE) { + + /* Clear all of the status flags. */ + len_status = dp->regs->xd[dp->tx_ptr].len_status & ~OETH_TX_BD_STATS; + + /* If the frame is short, tell CPM to pad it. */ + if (len < ET_MINLEN) { + len_status |= OETH_TX_BD_PAD; + len = ET_MINLEN; + } + else + len_status &= ~OETH_TX_BD_PAD; + + /* write buffer descriptor length and status */ + len_status |= (len << 16) | (OETH_TX_BD_READY | OETH_TX_BD_CRC); + dp->regs->xd[dp->tx_ptr].len_status = len_status; + dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs; + + } + inside = 0; +} + +/* + * Driver transmit daemon + */ +void +open_eth_txDaemon (void *arg) +{ + struct open_eth_softc *sc = (struct open_eth_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); +#ifdef OPEN_ETH_DEBUG + printf ("t\n"); +#endif + + /* + * 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; + } +} + + +static void +open_eth_start (struct ifnet *ifp) +{ + struct open_eth_softc *sc = ifp->if_softc; + + rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; +} + +/* + * Initialize and start the device + */ +static void +open_eth_init (void *arg) +{ + struct open_eth_softc *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + + if (sc->txDaemonTid == 0) + { + + /* + * Set up OPEN_ETH hardware + */ + open_eth_initialize_hardware (sc); + + /* + * Start driver tasks + */ + sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096, + open_eth_rxDaemon, sc); + sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096, + open_eth_txDaemon, sc); + } + + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; + +} + +/* + * Stop the device + */ +static void +open_eth_stop (struct open_eth_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + + ifp->if_flags &= ~IFF_RUNNING; + + sc->regs->moder = 0; /* RX/TX OFF */ + sc->regs->moder = OETH_MODER_RST; /* Reset ON */ + sc->regs->moder = 0; /* Reset OFF */ +} + + +/* + * Show interface statistics + */ +static void +open_eth_stats (struct open_eth_softc *sc) +{ + printf (" Rx Packets:%-8lu", sc->rxPackets); + printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); + printf (" Length:%-8lu", sc->rxLengthError); + printf (" Non-octet:%-8lu\n", sc->rxNonOctet); + printf (" Bad CRC:%-8lu", sc->rxBadCRC); + printf (" Overrun:%-8lu", sc->rxOverrun); + printf (" Miss:%-8lu", sc->rxMiss); + printf (" Collision:%-8lu\n", sc->rxCollision); + + 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 +open_eth_ioctl (struct ifnet *ifp, int command, caddr_t data) +{ + struct open_eth_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: + open_eth_stop (sc); + break; + + case IFF_UP: + open_eth_init (sc); + break; + + case IFF_UP | IFF_RUNNING: + open_eth_stop (sc); + open_eth_init (sc); + break; + + default: + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + open_eth_stats (sc); + break; + + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + error = EINVAL; + break; + } + + return error; +} + +/* + * Attach an OPEN_ETH driver to the system + */ +int +rtems_open_eth_driver_attach (struct rtems_bsdnet_ifconfig *config, + open_eth_configuration_t * chip) +{ + struct open_eth_softc *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; + + sc = &oc; + ifp = &sc->arpcom.ac_if; + memset (sc, 0, sizeof (*sc)); + + if (config->hardware_address) + { + memcpy (sc->arpcom.ac_enaddr, config->hardware_address, + ETHER_ADDR_LEN); + } + else + { + memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN); + } + + if (config->mtu) + mtu = config->mtu; + else + mtu = ETHERMTU; + + sc->acceptBroadcast = !config->ignore_broadcast; + sc->regs = (void *) chip->base_address; + sc->vector = chip->vector; + sc->txbufs = chip->txd_count; + sc->rxbufs = chip->rxd_count; + + + /* + * Set up network interface values + */ + ifp->if_softc = sc; + ifp->if_unit = unitNumber; + ifp->if_name = unitName; + ifp->if_mtu = mtu; + ifp->if_init = open_eth_init; + ifp->if_ioctl = open_eth_ioctl; + ifp->if_start = open_eth_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); + +#ifdef OPEN_ETH_DEBUG + printf ("OPEN_ETH : driver has been attached\n"); +#endif + return 1; +}; diff --git a/c/src/libchip/network/open_eth.h b/c/src/libchip/network/open_eth.h new file mode 100644 index 0000000000..ca41dbe7df --- /dev/null +++ b/c/src/libchip/network/open_eth.h @@ -0,0 +1,173 @@ +/* Opencores ethernet MAC driver */ +/* adapted from linux driver by Jiri Gaisler */ + +#ifndef _OPEN_ETH_ +#define _OPEN_ETH_ + + +/* Configuration Information */ + +typedef struct { + unsigned32 base_address; + unsigned32 vector; + unsigned32 txd_count; + unsigned32 rxd_count; +} open_eth_configuration_t; + + +/* Ethernet buffer descriptor */ + +typedef struct _oeth_rxtxdesc { + volatile unsigned32 len_status; /* Length and status */ + volatile unsigned32 *addr; /* Buffer pointer */ +} oeth_rxtxdesc; + +/* Ethernet configuration registers */ + +typedef struct _oeth_regs { + volatile unsigned32 moder; /* Mode Register */ + volatile unsigned32 int_src; /* Interrupt Source Register */ + volatile unsigned32 int_mask; /* Interrupt Mask Register */ + volatile unsigned32 ipgt; /* Back to Bak Inter Packet Gap Register */ + volatile unsigned32 ipgr1; /* Non Back to Back Inter Packet Gap Register 1 */ + volatile unsigned32 ipgr2; /* Non Back to Back Inter Packet Gap Register 2 */ + volatile unsigned32 packet_len; /* Packet Length Register (min. and max.) */ + volatile unsigned32 collconf; /* Collision and Retry Configuration Register */ + volatile unsigned32 tx_bd_num; /* Transmit Buffer Descriptor Number Register */ + volatile unsigned32 ctrlmoder; /* Control Module Mode Register */ + volatile unsigned32 miimoder; /* MII Mode Register */ + volatile unsigned32 miicommand; /* MII Command Register */ + volatile unsigned32 miiaddress; /* MII Address Register */ + volatile unsigned32 miitx_data; /* MII Transmit Data Register */ + volatile unsigned32 miirx_data; /* MII Receive Data Register */ + volatile unsigned32 miistatus; /* MII Status Register */ + volatile unsigned32 mac_addr0; /* MAC Individual Address Register 0 */ + volatile unsigned32 mac_addr1; /* MAC Individual Address Register 1 */ + volatile unsigned32 hash_addr0; /* Hash Register 0 */ + volatile unsigned32 hash_addr1; /* Hash Register 1 */ + volatile unsigned32 txctrl; /* Transmitter control register */ + unsigned32 empty[235]; /* Unused space */ + oeth_rxtxdesc xd[128]; /* TX & RX descriptors */ +} oeth_regs; + +#define OETH_TOTAL_BD 128 +#define OETH_MAXBUF_LEN 0x610 + +/* Tx BD */ +#define OETH_TX_BD_READY 0x8000 /* Tx BD Ready */ +#define OETH_TX_BD_IRQ 0x4000 /* Tx BD IRQ Enable */ +#define OETH_TX_BD_WRAP 0x2000 /* Tx BD Wrap (last BD) */ +#define OETH_TX_BD_PAD 0x1000 /* Tx BD Pad Enable */ +#define OETH_TX_BD_CRC 0x0800 /* Tx BD CRC Enable */ + +#define OETH_TX_BD_UNDERRUN 0x0100 /* Tx BD Underrun Status */ +#define OETH_TX_BD_RETRY 0x00F0 /* Tx BD Retry Status */ +#define OETH_TX_BD_RETLIM 0x0008 /* Tx BD Retransmission Limit Status */ +#define OETH_TX_BD_LATECOL 0x0004 /* Tx BD Late Collision Status */ +#define OETH_TX_BD_DEFER 0x0002 /* Tx BD Defer Status */ +#define OETH_TX_BD_CARRIER 0x0001 /* Tx BD Carrier Sense Lost Status */ +#define OETH_TX_BD_STATS (OETH_TX_BD_UNDERRUN | \ + OETH_TX_BD_RETRY | \ + OETH_TX_BD_RETLIM | \ + OETH_TX_BD_LATECOL | \ + OETH_TX_BD_DEFER | \ + OETH_TX_BD_CARRIER) + +/* Rx BD */ +#define OETH_RX_BD_EMPTY 0x8000 /* Rx BD Empty */ +#define OETH_RX_BD_IRQ 0x4000 /* Rx BD IRQ Enable */ +#define OETH_RX_BD_WRAP 0x2000 /* Rx BD Wrap (last BD) */ + +#define OETH_RX_BD_MISS 0x0080 /* Rx BD Miss Status */ +#define OETH_RX_BD_OVERRUN 0x0040 /* Rx BD Overrun Status */ +#define OETH_RX_BD_INVSIMB 0x0020 /* Rx BD Invalid Symbol Status */ +#define OETH_RX_BD_DRIBBLE 0x0010 /* Rx BD Dribble Nibble Status */ +#define OETH_RX_BD_TOOLONG 0x0008 /* Rx BD Too Long Status */ +#define OETH_RX_BD_SHORT 0x0004 /* Rx BD Too Short Frame Status */ +#define OETH_RX_BD_CRCERR 0x0002 /* Rx BD CRC Error Status */ +#define OETH_RX_BD_LATECOL 0x0001 /* Rx BD Late Collision Status */ +#define OETH_RX_BD_STATS (OETH_RX_BD_MISS | \ + OETH_RX_BD_OVERRUN | \ + OETH_RX_BD_INVSIMB | \ + OETH_RX_BD_DRIBBLE | \ + OETH_RX_BD_TOOLONG | \ + OETH_RX_BD_SHORT | \ + OETH_RX_BD_CRCERR | \ + OETH_RX_BD_LATECOL) + +/* MODER Register */ +#define OETH_MODER_RXEN 0x00000001 /* Receive Enable */ +#define OETH_MODER_TXEN 0x00000002 /* Transmit Enable */ +#define OETH_MODER_NOPRE 0x00000004 /* No Preamble */ +#define OETH_MODER_BRO 0x00000008 /* Reject Broadcast */ +#define OETH_MODER_IAM 0x00000010 /* Use Individual Hash */ +#define OETH_MODER_PRO 0x00000020 /* Promiscuous (receive all) */ +#define OETH_MODER_IFG 0x00000040 /* Min. IFG not required */ +#define OETH_MODER_LOOPBCK 0x00000080 /* Loop Back */ +#define OETH_MODER_NOBCKOF 0x00000100 /* No Backoff */ +#define OETH_MODER_EXDFREN 0x00000200 /* Excess Defer */ +#define OETH_MODER_FULLD 0x00000400 /* Full Duplex */ +#define OETH_MODER_RST 0x00000800 /* Reset MAC */ +#define OETH_MODER_DLYCRCEN 0x00001000 /* Delayed CRC Enable */ +#define OETH_MODER_CRCEN 0x00002000 /* CRC Enable */ +#define OETH_MODER_HUGEN 0x00004000 /* Huge Enable */ +#define OETH_MODER_PAD 0x00008000 /* Pad Enable */ +#define OETH_MODER_RECSMALL 0x00010000 /* Receive Small */ + +/* Interrupt Source Register */ +#define OETH_INT_TXB 0x00000001 /* Transmit Buffer IRQ */ +#define OETH_INT_TXE 0x00000002 /* Transmit Error IRQ */ +#define OETH_INT_RXF 0x00000004 /* Receive Frame IRQ */ +#define OETH_INT_RXE 0x00000008 /* Receive Error IRQ */ +#define OETH_INT_BUSY 0x00000010 /* Busy IRQ */ +#define OETH_INT_TXC 0x00000020 /* Transmit Control Frame IRQ */ +#define OETH_INT_RXC 0x00000040 /* Received Control Frame IRQ */ + +/* Interrupt Mask Register */ +#define OETH_INT_MASK_TXB 0x00000001 /* Transmit Buffer IRQ Mask */ +#define OETH_INT_MASK_TXE 0x00000002 /* Transmit Error IRQ Mask */ +#define OETH_INT_MASK_RXF 0x00000004 /* Receive Frame IRQ Mask */ +#define OETH_INT_MASK_RXE 0x00000008 /* Receive Error IRQ Mask */ +#define OETH_INT_MASK_BUSY 0x00000010 /* Busy IRQ Mask */ +#define OETH_INT_MASK_TXC 0x00000020 /* Transmit Control Frame IRQ Mask */ +#define OETH_INT_MASK_RXC 0x00000040 /* Received Control Frame IRQ Mask */ + +/* Control Module Mode Register */ +#define OETH_CTRLMODER_PASSALL 0x00000001 /* Pass Control Frames */ +#define OETH_CTRLMODER_RXFLOW 0x00000002 /* Receive Control Flow Enable */ +#define OETH_CTRLMODER_TXFLOW 0x00000004 /* Transmit Control Flow Enable */ + +/* MII Mode Register */ +#define OETH_MIIMODER_CLKDIV 0x000000FF /* Clock Divider */ +#define OETH_MIIMODER_NOPRE 0x00000100 /* No Preamble */ +#define OETH_MIIMODER_RST 0x00000200 /* MIIM Reset */ + +/* MII Command Register */ +#define OETH_MIICOMMAND_SCANSTAT 0x00000001 /* Scan Status */ +#define OETH_MIICOMMAND_RSTAT 0x00000002 /* Read Status */ +#define OETH_MIICOMMAND_WCTRLDATA 0x00000004 /* Write Control Data */ + +/* MII Address Register */ +#define OETH_MIIADDRESS_FIAD 0x0000001F /* PHY Address */ +#define OETH_MIIADDRESS_RGAD 0x00001F00 /* RGAD Address */ + +/* MII Status Register */ +#define OETH_MIISTATUS_LINKFAIL 0x00000001 /* Link Fail */ +#define OETH_MIISTATUS_BUSY 0x00000002 /* MII Busy */ +#define OETH_MIISTATUS_NVALID 0x00000004 /* Data in MII Status Register is invalid */ + +/* Attatch routine */ + +int rtems_open_eth_driver_attach ( + struct rtems_bsdnet_ifconfig *config, + open_eth_configuration_t *chip +); + +/* +#ifdef CPU_U32_FIX +void ipalign(struct mbuf *m); +#endif + +*/ +#endif /* _OPEN_ETH_ */ + -- cgit v1.2.3