📄 if_elc.c
字号:
/* if_elc.c - SMC 8013WC Ethernet network interface driver *//* Copyright 1984-1999 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------02b,11jan99,aeg fixed multiple semaphore inits in elcattach ().02a,15jul97,spm removed driver initialization from ioctl support (SPR #8831)01z,15may97,spm reverted to bcopy routines for mbufs in BSD 4.401y,07apr97,spm code cleanup, corrected statistics, and upgraded to BSD 4.401x,14jun95,hdn removed function declarations defined in sysLib.h.01w,01feb95,jdi doc cleanup; made elcShow() NOMANUAL.01v,29nov94,hdn added a semaphore in ultraPut().01u,12nov94,tmk removed some IMPORTed function decs and included unixLib.h01t,03oct94,hdn implemented two transmit buffers. enabled getting OUT2 bit of IRR in EEROM. deleted while loop in ultraPut().01s,03dec93,hdn added documentation.01r,29nov93,hdn removed netJobAdd (elcPut, ..) in elcIntr().01q,28nov93,hdn changed NELC to 1.01p,24nov93,hdn removed TXING and txreq flags. added checking TXP bit before the transmission. 01o,23nov93,hdn removed cacheInvalidate(). 01n,22nov93,hdn added elcdetach () for the warm start.01m,15nov93,hdn added support for Thin Ethernet(10Base2, BNC)01l,05nov93,hdn added cacheFlush() and cacheInvalidate().01k,04nov93,hdn cleaned up.01j,03nov93,hdn made RAM size 16Kbytes. cleaned up.01i,05sep93,hdn added sysIntEnablePIC ().01h,02sep93,hdn added macros about PIC.01g,11aug93,hdn changed a way of setting a handler for stray interrupt IRQ7.01f,23jun93,hdn made address, irq software configuarable.01e,17jun93,hdn updated to 5.1.01d,28may93,hdn deleted a zero wait bit. fixed a race condition.01c,23apr93,hdn fixed a bug which appears when a packet is wrapped. fixed a stray interrupt 15. moved a interrupt masking to the top of elcGet.01b,03jan93,hdn fixed bugs and cleaned up.01a,09jun92,hdn written.*//*DESCRIPTIONThis module implements the SMC 8013WC network interface driver.BOARD LAYOUTThe W1 jumper should be set in position SOFT.The W2 jumper should be set in position NONE/SOFT.CONFIGURATIONThe I/O address, RAM address, RAM size, and IRQ levels are defined in config.h.The I/O address must match the one stored in EEROM. The configuration software supplied by the manufacturer should be used to set the I/O address. IRQ levels 2,3,4,5,7,9,10,11,15 are supported. Thick Ethernet (AUI) andThin Ethernet (BNC) are configurable by changing the macro CONFIG_ELCin config.h.EXTERNAL INTERFACEThe only user-callable routines are elcattach() and elcShow():.iP elcattach() 14publishes the `elc' interface and initializes the driver and device..iP elcShow()displays statistics that are collected in the interrupt handler..LP*/#include "vxWorks.h"#include "net/mbuf.h"#include "net/protosw.h"#include "net/unixLib.h"#include "ioctl.h"#include "socket.h"#include "errnoLib.h"#include "net/uio.h"#include "net/if.h"#include "net/route.h"#include "netinet/in.h"#include "netinet/in_systm.h"#include "netinet/ip.h"#include "netinet/ip_var.h"#include "netinet/in_var.h"#include "netinet/if_ether.h"#include "etherLib.h"#include "vme.h"#include "iv.h"#include "iosLib.h"#include "ioLib.h"#include "memLib.h"#include "net/systm.h"#include "net/if_subr.h"#include "sysLib.h"#include "vxLib.h"#include "stdio.h"#include "intLib.h"#include "logLib.h"#include "string.h"#include "netLib.h"#include "stdlib.h"#include "semLib.h"#include "cacheLib.h"#include "drv/intrCtl/i8259a.h"#include "drv/netif/if_elc.h"/* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, * es_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... */#define NELC 1 /* max number of ELC controllers */LOCAL ELC_SOFTC elc_softc [NELC];LOCAL IRQ_TABLE irqTable [] = { {0xff, 0xff}, /* IRQ0 not supported */ {0xff, 0xff}, /* IRQ1 not supported */ {0x0, 0x0}, /* IRQ2 */ {0x0, 0x1}, /* IRQ3 */ {0x1, 0x3}, /* IRQ4 */ {0x0, 0x2}, /* IRQ5 */ {0xff, 0xff}, /* IRQ6 not supported */ {0x0, 0x3}, /* IRQ7 */ {0xff, 0xff}, /* IRQ8 not supported */ {0x0, 0x0}, /* IRQ9 */ {0x1, 0x0}, /* IRQ10 */ {0x1, 0x1}, /* IRQ11 */ {0xff, 0xff}, /* IRQ12 not supported */ {0xff, 0xff}, /* IRQ13 not supported */ {0xff, 0xff}, /* IRQ14 not supported */ {0x1, 0x2}, /* IRQ15 */ {0, 0}, };LOCAL BOOL elcAttached = FALSE;LOCAL SEMAPHORE elcSyncSem; /* syncronization semaphore *//* forward static functions */static void elcreset (int unit);static int elcinit (int unit);static void elcintr (int unit);static int elcioctl (struct ifnet *ifp, int cmd, caddr_t data);#ifdef BSD43_DRIVERstatic int elcoutput (struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst);#endifstatic void elcGet (int unit);#ifdef BSD43_DRIVERstatic void elcPut (int unit);#elsestatic void elcPut (ELC_SOFTC *sc);#endifstatic void elcReset (int unit);static void elcGetAddr (int unit);static void bicInit (int unit);static void elcInit (int unit);static UCHAR elcGetCurr (int unit); void elcShow (int unit, BOOL zap); void elcdetach (int unit);/********************************************************************************* elcattach - publish the `elc' network interface and initialize the driver and device** This routine attaches an `elc' Ethernet interface to the network if the* device exists. It makes the interface available by filling in the network* interface record. The system will initialize the interface when it is* ready to accept packets.** RETURNS: OK or ERROR.** SEE ALSO: ifLib, netShow*/STATUS elcattach ( int unit, /* unit number */ int ioAddr, /* address of elc's shared memory */ int ivec, /* interrupt vector to connect to */ int ilevel, /* interrupt level */ int memAddr, /* address of elc's shared memory */ int memSize, /* size of elc's shared memory */ int config /* 0: RJ45 + AUI(Thick) 1: RJ45 + BNC(Thin) */ ) { FAST ELC_SOFTC *sc = &elc_softc[unit]; if ((UINT)unit >= NELC) { errnoSet (S_iosLib_CONTROLLER_NOT_PRESENT); return (ERROR); } sc->bicAddr = ioAddr; sc->elcAddr = ioAddr + 0x10; sc->memAddr = memAddr; sc->memSize = memSize; if (ilevel == 0 || ilevel == 1 || ilevel == 6 || ilevel == 8 || ilevel == 12 || ilevel == 13 || ilevel == 14) ilevel = 3; /* default is IRQ3 */ sc->intLevel = ilevel; sc->intVec = ivec; sc->config = config; sc->transmitPage[0] = SMC8013WC_TSTART0; sc->transmitPage[1] = SMC8013WC_TSTART1; sc->transmitCnt = 0; /* synchronization semaphore must be initialized only once */ if (!elcAttached) semBInit (&elcSyncSem, SEM_Q_FIFO, SEM_FULL); bicInit (unit); /* initialize BIC */ elcInit (unit); /* initialize ELC */ elcGetAddr (unit); /* get ethernet address */ (void) intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (ivec), (VOIDFUNCPTR)elcintr, unit); /* enable interrupt */ sysOutByte (ELC_INTMASK (sc->elcAddr), IM_OVWE | IM_TXEE | IM_PTXE | IM_PRXE); sysIntEnablePIC (ilevel);#ifdef BSD43_DRIVER ether_attach (&sc->es_if, unit, "elc", (FUNCPTR)elcinit, (FUNCPTR)elcioctl, (FUNCPTR)elcoutput, (FUNCPTR)elcreset);#else ether_attach ( &sc->es_if, unit, "elc", (FUNCPTR)elcinit, (FUNCPTR)elcioctl, (FUNCPTR)ether_output, (FUNCPTR)elcreset ); sc->es_if.if_start = (FUNCPTR)elcPut;#endif elcinit (unit); elcAttached = TRUE; return (OK); }/********************************************************************************* elcreset - reset the interface*/LOCAL void elcreset ( int unit ) { elcReset (unit); }/********************************************************************************* elcinit - initialize elc** Restart the link level software on the board and mark the interface up.** RETURNS: 0*/LOCAL int elcinit ( int unit ) { FAST ELC_SOFTC *sc = &elc_softc[unit]; sc->es_if.if_flags |= IFF_UP|IFF_RUNNING; /* open for business*/ return (0); }/********************************************************************************* elcintr - Ethernet interface interrupt** Hand off reading of packets from the interface to task level.*/LOCAL void elcintr ( int unit ) { FAST ELC_SOFTC *sc = &elc_softc[unit]; sc->elcStat.interrupts++; sysBusIntAck (sc->intLevel); /* acknowledge int */ /* acknowledge interrupt, get Transmit/Receive status */ sc->istat = sysInByte (ELC_INTSTAT (sc->elcAddr)); sysOutByte (ELC_INTSTAT (sc->elcAddr), sc->istat); sc->tstat = sysInByte (ELC_TSTAT (sc->elcAddr)); sc->rstat = sysInByte (ELC_RSTAT (sc->elcAddr)); /* get xxxCount Reg that is cleared after read access */ sc->elcStat.collisions += sysInByte (ELC_COLCNT (sc->elcAddr)); sc->elcStat.aligns += sysInByte (ELC_ALICNT (sc->elcAddr)); sc->elcStat.crcs += sysInByte (ELC_CRCCNT (sc->elcAddr)); sc->elcStat.missed += sysInByte (ELC_MPCNT (sc->elcAddr)); if (sc->istat & ISTAT_OVW) /* Receive buffer ring overwrite */ { sysOutByte (ELC_BOUND(sc->elcAddr), sysInByte (ELC_BOUND(sc->elcAddr))); sc->elcStat.overwrite++; sc->es_if.if_ierrors++; } if (sc->istat & ISTAT_RXE) /* Receive-error */ { sc->es_if.if_ierrors++; sc->elcStat.rerror++; if (sc->rstat & RSTAT_OVER) sc->elcStat.overruns++; if (sc->rstat & RSTAT_DIS) sc->elcStat.disabled++; if (sc->rstat & RSTAT_DFR) sc->elcStat.deferring++; } if (sc->istat & ISTAT_PRX) /* Receive */ { sc->current = elcGetCurr (unit); if ((sc->flags & RXING) == 0) { sc->flags |= RXING; (void) netJobAdd ((FUNCPTR)elcGet, unit, 0,0,0,0); } if (sc->rstat & RSTAT_PRX) sc->elcStat.rnoerror++; } if (sc->istat & (ISTAT_TXE | ISTAT_PTX)) /* Transmit-error, Transmit */ { semGive (&elcSyncSem); if (sc->istat & ISTAT_TXE) { sc->es_if.if_oerrors++; sc->es_if.if_opackets--; sc->elcStat.terror++; } if (sc->tstat & TSTAT_ABORT) { sc->elcStat.aborts++; sc->elcStat.collisions += 16; } if (sc->tstat & TSTAT_UNDER) sc->elcStat.underruns++; if (sc->tstat & TSTAT_CDH) sc->elcStat.heartbeats++; if (sc->tstat & TSTAT_OWC) sc->elcStat.outofwindow++; if (sc->tstat & TSTAT_PTX) sc->elcStat.tnoerror++; } }/********************************************************************************* elcGet - read a packet off the interface** Copy packets from a RING into an mbuf and hand it to the next higher layer.*/LOCAL void elcGet ( int unit ) { FAST ELC_SOFTC *sc = &elc_softc[unit]; FAST ELC_HEADER *pH; FAST struct ether_header *eh; FAST struct mbuf *m; int len;#ifdef BSD43_DRIVER int off;#endif int ix = 0; USHORT wrapSize; USHORT packetSize; char *pSrc; char *pDst; UCHAR *pData; UCHAR uppByteCnt;unlucky: ix = 0; while ((sc->next != sc->current) && (ix++ < SMC8013WC_PSTOP)) { /* Invalidate cache */ cacheDrvInvalidate (&cacheDmaFuncs, (UCHAR *)(sc->memAddr + (SMC8013WC_PSTART << 8)), (sc->memSize - (SMC8013WC_PSTART << 8))); pH = (ELC_HEADER *)(sc->memAddr + (((UINT)sc->next << 8) & 0x0000ffff)); /* sanity check */ if ((pH->next < SMC8013WC_PSTART) || (pH->next >= SMC8013WC_PSTOP)) { sc->elcStat.badPacket++; pH->next = sc->next + sc->uppByteCnt + 1; if (pH->next >= SMC8013WC_PSTOP) pH->next = SMC8013WC_PSTART + (pH->next - SMC8013WC_PSTOP); } if (*(USHORT *)(&pH->lowByteCnt) < 64) { sc->elcStat.shortPacket++; goto doneGet; } sc->es_if.if_ipackets++; /* bump statistic */ /* get uppByteCnt from pH->next because of the bug of a chip */ if (pH->next > sc->next) { wrapSize = 0; uppByteCnt = pH->next - sc->next; } else { wrapSize = (SMC8013WC_PSTOP - sc->next) << 8; uppByteCnt = (SMC8013WC_PSTOP - sc->next) + (pH->next - SMC8013WC_PSTART); } if (pH->lowByteCnt > 0xfc) uppByteCnt -= 2; else uppByteCnt -= 1; packetSize = (uppByteCnt << 8) | pH->lowByteCnt; pH->uppByteCnt = uppByteCnt; if (wrapSize > packetSize) wrapSize = 0; /* copy separated frame to a temporary buffer */ if (wrapSize) { sc->elcStat.wrapped++; pSrc = (char *)pH; pDst = (char *)sc->receiveBuf; bcopy (pSrc, pDst, wrapSize); pSrc = (char *)(sc->memAddr + (SMC8013WC_PSTART << 8)); pDst += wrapSize; len = packetSize - wrapSize; if (len) bcopy (pSrc, pDst, len); } len = packetSize - 4; /* remove CRCs 4 bytes */ if (wrapSize) eh = (struct ether_header *)((UINT)sc->receiveBuf + sizeof (ELC_HEADER)); else eh = (struct ether_header *)((UINT)pH + sizeof (ELC_HEADER)); /* call input hook if any */ if ((etherInputHookRtn != NULL) && (* etherInputHookRtn) (&sc->es_if, (char *) eh, len)) { goto doneGet; } if (len >= SIZEOF_ETHERHEADER) len -= SIZEOF_ETHERHEADER; else { sc->es_if.if_ierrors++; /* bump error statistic */ goto doneGet; } pData = ((unsigned char *) eh) + SIZEOF_ETHERHEADER;#ifdef BSD43_DRIVER check_trailer (eh, pData, &len, &off, &sc->es_if); /* copy data from the ring buffer to mbuf a long-word at a time */ m = bcopy_to_mbufs (pData, len, off, (struct ifnet *) &sc->es_if, 2); if (m == NULL) { sc->es_if.if_ierrors++; /* bump error statistic */ goto doneGet; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -