From c0438adde978a8b66e82ce9509e338dc1d714ccc Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 18 Feb 1999 21:09:25 +0000 Subject: Renamed network to wd8003. --- c/src/lib/libbsp/i386/pc386/wd8003/Makefile.in | 57 +++ c/src/lib/libbsp/i386/pc386/wd8003/wd8003.c | 657 +++++++++++++++++++++++++ 2 files changed, 714 insertions(+) create mode 100644 c/src/lib/libbsp/i386/pc386/wd8003/Makefile.in create mode 100644 c/src/lib/libbsp/i386/pc386/wd8003/wd8003.c (limited to 'c/src/lib/libbsp/i386/pc386/wd8003') diff --git a/c/src/lib/libbsp/i386/pc386/wd8003/Makefile.in b/c/src/lib/libbsp/i386/pc386/wd8003/Makefile.in new file mode 100644 index 0000000000..b02e724894 --- /dev/null +++ b/c/src/lib/libbsp/i386/pc386/wd8003/Makefile.in @@ -0,0 +1,57 @@ +# +# $Id$ +# + +@SET_MAKE@ +srcdir = @srcdir@ +VPATH = @srcdir@ +RTEMS_ROOT = @top_srcdir@ +PROJECT_ROOT = @PROJECT_ROOT@ + +INSTALL = @INSTALL@ + +PGM=${ARCH}/wd8003.rel + +# C source names, if any, go here -- minus the .c +C_PIECES=wd8003 +C_FILES=$(C_PIECES:%=%.c) +C_O_FILES=$(C_PIECES:%=${ARCH}/%.o) + +H_FILES= + +SRCS=$(C_FILES) $(H_FILES) +OBJS=$(C_O_FILES) + +include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg +include $(RTEMS_ROOT)/make/leaf.cfg + +# +# (OPTIONAL) Add local stuff here using += +# + +DEFINES += -D_COMPILING_BSD_KERNEL_ -DKERNEL -DINET -DNFS \ + -DDIAGNOSTIC -DBOOTP_COMPAT +CPPFLAGS += +CFLAGS += + +LD_PATHS += +LD_LIBS += +LDFLAGS += + +# +# Add your list of files to delete here. The config files +# already know how to delete some stuff, so you may want +# to just run 'make clean' first to see what gets missed. +# 'make clobber' already includes 'make clean' +# + +CLEAN_ADDITIONS += +CLOBBER_ADDITIONS += + +${PGM}: ${SRCS} ${OBJS} + $(make-rel) + +all: ${ARCH} $(SRCS) $(PGM) + +# the .rel file built here will be put into libbsp.a by ../wrapup/Makefile +install: all diff --git a/c/src/lib/libbsp/i386/pc386/wd8003/wd8003.c b/c/src/lib/libbsp/i386/pc386/wd8003/wd8003.c new file mode 100644 index 0000000000..e897435f7a --- /dev/null +++ b/c/src/lib/libbsp/i386/pc386/wd8003/wd8003.c @@ -0,0 +1,657 @@ +/* + * RTEMS driver for WD800x + * + * Based on the 68360 Network Driver by: + * W. Eric Norum + * Saskatchewan Accelerator Laboratory + * University of Saskatchewan + * Saskatoon, Saskatchewan, CANADA + * eric@skatter.usask.ca + * + * $Id$ + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#define ET_MINLEN 60 /* minimum message length */ + +/* + * Number of WDs supported by this driver + */ +#define NWDDRIVER 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 wd_softc { + struct arpcom arpcom; + rtems_irq_connect_data irqInfo; + struct mbuf **rxMbuf; + struct mbuf **txMbuf; + int acceptBroadcast; + int rxBdCount; + int txBdCount; + int txBdHead; + int txBdTail; + int txBdActiveCount; + rtems_id rxDaemonTid; + rtems_id txDaemonTid; + + unsigned int port; + unsigned char *base; + unsigned long bpar; + + /* + * 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; +}; + +#define RO 0x10 + +#define SHATOT (8*1024) /* size of shared memory */ +#define SHAPAGE 256 /* shared memory information */ +#define MAXSIZ 1536 /*(MAXBUF - MESSH_SZ)*/ +#define OUTPAGE ((SHATOT-(MAXSIZ+SHAPAGE-1))/SHAPAGE) + +static volatile unsigned long overrun; +static volatile unsigned long resend; +static struct wd_softc wd_softc[NWDDRIVER]; + +/* + * WD interrupt handler + */ +static rtems_isr +wd8003Enet_interrupt_handler (rtems_vector_number v) +{ + unsigned int tport; + unsigned char status, status2; + + tport = wd_softc[0].port ; + + /* + * Read status + */ + inport_byte(tport+ISR, status); + outport_byte(tport+IMR, 0x00); + + /* + * Ring overwrite + */ + + if (status & MSK_OVW){ + outport_byte(tport+CMDR, MSK_STP + MSK_RD2); /* stop 8390 */ + Wait_X_ms(2); + outport_byte(tport+RBCR0, 0); /* clear byte count */ + outport_byte(tport+RBCR1, 0); + inport_byte(tport+ISR, status2); + status |= (status2 & (MSK_PTX+MSK_TXE)) ; /* TX status */ + outport_byte(tport+TCR, MSK_LOOP); /* loopback mode */ + outport_byte(tport+CMDR, MSK_STA + MSK_RD2); /* start */ + overrun = 1 ; + if ((status & (MSK_PTX+MSK_TXE)) == 0) + resend = 1; + } + + /* + * Frame received? + */ + if (status & (MSK_PRX+MSK_RXE)) { + outport_byte(tport+ISR, status & (MSK_PRX+MSK_RXE)); + wd_softc[0].rxInterrupts++; + rtems_event_send (wd_softc[0].rxDaemonTid, INTERRUPT_EVENT); + } + +} + +static void nopOn(const rtems_irq_connect_data* notUsed) +{ + /* + * code should be moved from wd8003Enet_initialize_hardware + * to this location + */ +} + +static int wdIsOn(const rtems_irq_connect_data* irq) +{ + return BSP_irq_enabled_at_i8259s (irq->name); +} + +/* + * Initialize the ethernet hardware + */ +static void +wd8003Enet_initialize_hardware (struct wd_softc *sc) +{ + int i1, ultra; + char cc1, cc2; + unsigned char temp; + rtems_status_code st; + unsigned int tport; + unsigned char *hwaddr; + + tport = sc->port; + + /* address from board ROM */ + inport_byte(tport+0x04, temp); + outport_byte(tport+0x04, temp & 0x7f); + + hwaddr = sc->arpcom.ac_enaddr; + for (i1=cc2=0; i1<8; i1++) { + inport_byte(tport + ADDROM + i1, cc1); + cc2 += cc1; + if (i1 < 6) + hwaddr[i1] = cc1; + } + + inport_byte(tport+0x04, temp); + outport_byte(tport+0x04, temp | 0x80); /* alternate registers */ + outport_byte(tport+W83CREG, MSK_RESET); /* reset board, set buffer */ + outport_byte(tport+W83CREG, 0); + outport_byte(tport+W83CREG, MSK_ENASH + (int)((sc->bpar>>13)&0x3f)); + + outport_byte(tport+CMDR, MSK_PG0 + MSK_RD2); + cc1 = MSK_BMS + MSK_FT10; /* configure 8 or 16 bits */ + + inport_byte(tport+0x07, temp) ; + + ultra = ((temp & 0xf0) == 0x20 || (temp & 0xf0) == 0x40); + if (ultra) + cc1 = MSK_WTS + MSK_BMS + MSK_FT10; + outport_byte(tport+DCR, cc1); + outport_byte(tport+RBCR0, 0); + outport_byte(tport+RBCR1, 0); + outport_byte(tport+RCR, MSK_MON); /* disable the rxer */ + outport_byte(tport+TCR, 0); /* normal operation */ + outport_byte(tport+PSTOP, OUTPAGE); /* init PSTOP */ + outport_byte(tport+PSTART, 0); /* init PSTART */ + outport_byte(tport+BNRY, -1); /* init BNRY */ + outport_byte(tport+ISR, -1); /* clear IR's */ + outport_byte(tport+IMR, 0x15); /* enable interrupt */ + + outport_byte(tport+CMDR, MSK_PG1 + MSK_RD2); + + for (i1=0; i1<6; i1++) /* initial physical addr */ + outport_byte(tport+PAR+i1, hwaddr[i1]); + + for (i1=0; i1irqInfo.hdl = wd8003Enet_interrupt_handler; + sc->irqInfo.on = nopOn; + sc->irqInfo.off = nopOn; + sc->irqInfo.isOn = wdIsOn; + + st = BSP_install_rtems_irq_handler (&sc->irqInfo); + if (!st) + rtems_panic ("Can't attach WD interrupt handler for irq %d\n", + sc->irqInfo.name); +} + +static void +wd_rxDaemon (void *arg) +{ + unsigned int tport; + struct ether_header *eh; + struct wd_softc *dp = (struct wd_softc *)&wd_softc[0]; + struct ifnet *ifp = &dp->arpcom.ac_if; + struct mbuf *m; + unsigned int i2; + unsigned int len; + volatile unsigned char start, next, current; + char *shp, *temp; + rtems_event_set events; + + tport = wd_softc[0].port ; + + for (;;){ + + + rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + + for (;;){ + inport_byte(tport+BNRY, start); + + outport_byte(tport+CMDR, MSK_PG1 + MSK_RD2); + inport_byte(tport+CURR, current); + outport_byte(tport+CMDR, MSK_PG0 + MSK_RD2); + + start += 1; + if (start >= OUTPAGE){ + start = 0; + } + + if (current == start) + break; + + shp = dp->base + 1 + (SHAPAGE * start); + next = *shp++; + len = *((short *)shp)++ - 4; + + if (next >= OUTPAGE){ + next = 0; + } + + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + + temp = m->m_data; + m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header); + + if ((i2 = (OUTPAGE - start) * SHAPAGE - 4) < len){ + memcpy(temp, shp, i2); + len -= i2; + temp += i2; + shp = dp->base; + } + memcpy(temp, shp, len); + + eh = mtod (m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + ether_input (ifp, eh, m); + + outport_byte(tport+BNRY, next-1); + } + + /* + * Ring overwrite + */ + if (overrun){ + outport_byte(tport+ISR, MSK_OVW); /* reset IR */ + outport_byte(tport+TCR, 0); /* out of loopback */ + if (resend == 1) + outport_byte(tport+CMDR, MSK_TXP + MSK_RD2); /* resend */ + resend = 0; + overrun = 0; + } + + outport_byte(tport+IMR, 0x15); /* re-enable IT rx */ + } +} + +static void +sendpacket (struct ifnet *ifp, struct mbuf *m) +{ + struct wd_softc *dp = ifp->if_softc; + struct mbuf *n; + unsigned int len, tport; + char *shp, txReady; + + tport = dp->port; + + /* + * Waiting for Transmitter ready + */ + inport_byte(tport+CMDR, txReady); + while(txReady & MSK_TXP) + inport_byte(tport+CMDR, txReady); + + len = 0; + shp = dp->base + (SHAPAGE * OUTPAGE); + + n = m; + + for (;;){ + len += m->m_len; + memcpy(shp, (char *)m->m_data, m->m_len); + shp += m->m_len ; + if ((m = m->m_next) == NULL) + break; + } + + m_freem(n); + + if (len < ET_MINLEN) len = ET_MINLEN; + outport_byte(tport+TBCR0, len); + outport_byte(tport+TBCR1, (len >> 8) ); + outport_byte(tport+TPSR, OUTPAGE); + outport_byte(tport+CMDR, MSK_TXP + MSK_RD2); +} + +/* + * Driver transmit daemon + */ +void +wd_txDaemon (void *arg) +{ + struct wd_softc *sc = (struct wd_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 +wd_start (struct ifnet *ifp) +{ + struct wd_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 +wd_init (void *arg) +{ + struct wd_softc *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + + if (sc->txDaemonTid == 0) { + + /* + * Set up WD hardware + */ + wd8003Enet_initialize_hardware (sc); + + /* + * Start driver tasks + */ + sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, wd_txDaemon, sc); + sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, wd_rxDaemon, sc); + } + + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; + +} + +/* + * Stop the device + */ +static void +wd_stop (struct wd_softc *sc) +{ + unsigned int tport; + unsigned char temp; + struct ifnet *ifp = &sc->arpcom.ac_if; + + ifp->if_flags &= ~IFF_RUNNING; + + /* + * Stop the transmitter + */ + tport=wd_softc[0].port ; + inport_byte(tport+0x04,temp); + outport_byte(tport+0x04, temp & 0x7f); + outport_byte(tport + CMDR, MSK_STP + MSK_RD2); + +} + + +/* + * Show interface statistics + */ +static void +wd_stats (struct wd_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 (" 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 +wd_ioctl (struct ifnet *ifp, int command, caddr_t data) +{ + struct wd_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: + wd_stop (sc); + break; + + case IFF_UP: + wd_init (sc); + break; + + case IFF_UP | IFF_RUNNING: + wd_stop (sc); + wd_init (sc); + break; + + default: + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + wd_stats (sc); + break; + + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + error = EINVAL; + break; + } + return error; +} + +/* + * Attach an WD driver to the system + */ +int +rtems_wd_driver_attach (struct rtems_bsdnet_ifconfig *config) +{ + struct wd_softc *sc; + struct ifnet *ifp; + int mtu; + int i; + + /* + * Find a free driver + */ + for (i = 0 ; i < NWDDRIVER ; i++) { + sc = &wd_softc[i]; + ifp = &sc->arpcom.ac_if; + if (ifp->if_softc == NULL) + break; + } + if (i >= NWDDRIVER) { + printf ("Too many WD drivers.\n"); + return 0; + } + + /* + * Process options + */ + 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; + + + if (config->irno) + sc->irqInfo.name = config->irno; + else + sc->irqInfo.name = 5; + + if (config->port) + sc->port = config->port; + else + sc->port = 0x240; + + if (config->bpar) { + sc->bpar = config->bpar; + sc->base = (unsigned char*) config->bpar; + } + else { + sc->bpar = 0xD0000; + sc->base = (unsigned char*) 0xD0000; + } + + sc->acceptBroadcast = !config->ignore_broadcast; + + /* + * Set up network interface values + */ + ifp->if_softc = sc; + ifp->if_unit = i + 1; + ifp->if_name = "wd"; + ifp->if_mtu = mtu; + ifp->if_init = wd_init; + ifp->if_ioctl = wd_ioctl; + ifp->if_start = wd_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; + + /* + * init some variables + */ + overrun = 0; + resend = 0; + + /* + * Attach the interface + */ + if_attach (ifp); + ether_ifattach (ifp); + return 1; +}; -- cgit v1.2.3