📄 if_med.c
字号:
/* if_med.c - Matrix DB-ETH Ethernet network interface driver *//* "Copyright 1989, Matrix Corporation" *//* Copyright 1984-1997 Wind River Systems, Inc. *//*modification history--------------------02m,15jul97,spm removed driver initialization from ioctl support (SPR #8831); cleaned up handling of promiscuous mode02l,07apr97,spm code cleanup, corrected statistics, and upgraded to BSD 4.402k,16dec96,dat fixed SPR 3026, incorrect test in medNIC_AwaitStop. Removed compiler warnings.02j,05may93,caf tweaked for ansi.02i,11aug93,jmm Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h02h,09sep92,gae documentation tweaks.02g,26may92,rrr the tree shuffle -changed includes to have absolute path from h/02f,04oct91,rrr passed through the ansification filter -changed functions to ansi style -changed includes to have absolute path from h/ -fixed #else and #endif -changed VOID to void -changed copyright notice02e,20sep90,dab made medInit() return int.02d,10aug90,dnw added include of if_subr.h.02c,11jul90,hjb changed references to do_protocol() to use do_protocol_with_type(). de-linted.02b,26jun90,hjb upgrade to use cluster and if_subr routines; +dab integrated in the new distribution from Matrix.02a,05may90,dab cleanup of Matrix version 01t.01a,25sep89,srm written by modifying if_ln.c.*//*DESCRIPTIONThis module implements theMatrix DB-ETH Ethernet network interface driver.There is one user-callable routine: medattach().BOARD LAYOUTThis device is onboard. No jumpering diagram required.SEE ALSO: ifLib*/#include "vxWorks.h"#include "net/mbuf.h"#include "net/protosw.h"#include "sys/ioctl.h"#include "sys/socket.h"#include "errno.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 "net/if_subr.h"#include "etherLib.h"#include "vme.h"#include "iv.h"#include "iosLib.h"#include "ioLib.h"#include "memLib.h"#include "net/systm.h"#include "sys/types.h"#include "drv/netif/if_med.h"#include "intLib.h"#include "logLib.h"#include "stdio.h"#include "sysLib.h"#include "netLib.h"#include "net/if_subr.h"IMPORT void sysDbusEtherIntEnable ();IMPORT ULONG tickGet ();#define NIC_INTERRUPTS_HANDLED (nic_PKT_RECV_NO_ERRORS \ | nic_PKT_RECV_ERROR \ | nic_PKT_XMIT_NO_ERRORS \ | nic_PKT_XMIT_ERROR \ | nic_RECV_BFR_OVF_WARN \ | nic_NET_STATS_CNTR_OVF)/* Actual arguments for medSetNIC_IMR() */#define MASK_NONE 0#define UNMASK_NONE 0/* DB-ETH addresses as seen from the CPU */#define ETH_ADRS_PROM_ADRS ((u_long)dbeth_ETH_ADDR_ROM \ + ((u_long)es->nicAddr & 0xfff00000))#define NIC_XMIT_BFR_ADRS ((u_long)dbeth_NIC_XMIT_BFR \ + ((u_long)es->nicAddr & 0xfff00000))#define NIC_RECV_BFR_ADRS(R) ((u_long)dbeth_NIC_RECV_BFR \ + ((u_long)es->nicAddr & 0xfff00000) \ + ((u_long)(R) << 8))#define END_OF_RECV_BFR ((u_long)dbeth_NIC_RECV_BFR_END \ + ((u_long)es->nicAddr & 0xfff00000))/* NIC register initial values */#define PSTART (u_char) (dbeth_NIC_RECV_BFR >> 8)#define PSTOP (u_char) ((dbeth_NIC_RECV_BFR + dbeth_NIC_RECV_BFR_SIZE) >> 8)#define BNRY (u_char) (PSTART)#define CURR (u_char) (BNRY + 1)/* kludge, to force compilation of IP interface code */#ifndef INET#define INET#endif /* INET *//* globals */u_int medLogCount = 50; /* log every medLogCount number of errors *//* locals */LOCAL med_Stats_s med_Stats;LOCAL struct med_softc *med_softc [NNIC];/* forward static functions */static void medRecv (struct med_softc *es, struct ether_header *eh, int len);static nic_RecvHdr_s *medGetRecvPacket (struct med_softc *es);static void medRecvIntrHandler (struct med_softc *es);static int medIoctl (struct ifnet *ifp, int cmd, caddr_t data);static void medXmitIntrHandler (struct med_softc *es, u_char xmitStatus);static void medIntr (int unit);static void medRecordRecvError (struct med_softc *es);static void medIntEnable (BOOL bEnable);static void medReset (int unit);static int medInit (int unit);static u_char bitReverse (u_char in);static void medEthAddrGet (int unit);static void medConfigNIC (int unit);#ifdef BSD43_DRIVERstatic int medOutput (struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst);static void medStartOutput (int unit);#elsestatic void medStartOutput (struct med_softc *es);#endifstatic xmitBCB_s *medXmitBfrAlloc (struct med_softc *es);static STATUS medXmitPacket (struct med_softc *es, char *pPacket, u_short packetLen);static void medReadTallyCntrs (struct med_softc *es);static void medMoveWrappedPacket (struct med_softc *es, nic_RecvHdr_s *pRecvPacket, u_long pktSize);static void medSetNIC_IMR (struct med_softc *es, u_char unmaskBits, u_char maskBits);static void medNIC_AwaitStop (NIC_DEVICE *pNIC);static void medXmitBfrDealloc (xmitQCB_s *pXmitQCB);static STATUS medXmtrLock (lockID_t *pLock);static void medXmtrUnlock (lockID_t *pLock);/********************************************************************************* medattach - publish the interface, and initialize the driver and device** The routine publishes `med' the interface by filling in a network interface* record and adding this record to the system list. This routine also* initializes the driver and the device to the operational state.** RETURNS: OK or ERROR*/STATUS medattach ( int unit, /* unit number */ char *addr, /* address of Dbus Ethernet board */ int ivec, /* interrupt vector to connect to */ int ilevel /* interrupt level */ ) { FAST struct med_softc *es; FAST NIC_DEVICE *pNicDev = (NIC_DEVICE *) (addr + (u_long) dbeth_NIC_ADDR); /* allocate and initialize med descriptor (med_softc) */ if ((es = (struct med_softc *) calloc (1, sizeof (struct med_softc))) == NULL) { printErr ("med%d: ERROR - malloc failed.\n", es->es_if.if_unit); return (ERROR); } med_softc [unit] = es; /* set ptr to med descriptor in array */ /* allocate and initialize overflow buffer for wrapped receive packets */ if ((es->pOvfRecvBfr = (nic_RecvHdr_s *)calloc (1, OVERFLOW_BFR_SIZE)) == 0) { printErr ("med%d: ERROR - malloc failed.\n", es->es_if.if_unit); return (ERROR); } es->bFirstInit = TRUE; /* Unit 'unit' not yet initialized */ es->nicAddr = pNicDev; es->nicIntLevel = ilevel; es->nicIntVec = ivec; (void) intConnect (INUM_TO_IVEC (ivec), medIntr, unit); medReset (unit);#ifdef BSD43_DRIVER ether_attach ( (struct ifnet *)&es->es_if, unit, "med", medInit, medIoctl, medOutput, (FUNCPTR) medReset);#else ether_attach ( &es->es_if, unit, "med", (FUNCPTR) medInit, (FUNCPTR) medIoctl, (FUNCPTR) ether_output, (FUNCPTR) medReset ); es->es_if.if_start = (FUNCPTR)medStartOutput;#endif medIntEnable (TRUE); /* enable the DB-ETH interrupt */ medInit (unit); return (OK); }/********************************************************************************* medRecv - receive packet processing** Process Ethernet receive completion:* If input error, just drop packet. (This is handled in medRecvIntrHandler.)* Otherwise purge input buffered data path and examine* packet to determine type. If can't determine length* from type, then have to drop packet. Otherwise decapsulate* packet based on type and pass to type-specific higher-level* input routine.*/LOCAL void medRecv ( FAST struct med_softc *es, FAST struct ether_header *eh, /* ether header followed by packet data */ int len ) { FAST struct mbuf *m; FAST u_char *pData; int off; es->es_if.if_ipackets++; /* call input hook if any */ if (etherInputHookRtn != NULL && (*etherInputHookRtn) (&es->es_if, (char *) eh, len)) { return; /* input hook has already processed this packet */ }#ifdef BSD43_DRIVER /* This legacy code is not correct for the BSD 4.4 stack. It would * also treat multicast addresses like alien packets, and not send * them up the stack. The higher-level protocols in the new stack * can handle these addresses, and will discard them if they do not * match an existing multicast group. */ /* do software filter if controller is in promiscuous mode */ if (es->bPromisc) { if ((bcmp ((char *) eh->ether_dhost, /* not our adrs? */ (char *) es->es_enaddr, sizeof (eh->ether_dhost)) != 0) && (bcmp ((char *) eh->ether_dhost, /* not broadcast? */ (char *) etherbroadcastaddr, sizeof (eh->ether_dhost)) != 0)) { return; /* not for us */ } }#endif if (len >= sizeof (struct ether_header)) len -= sizeof (struct ether_header); else len = 0; pData = ((u_char *) eh) + (sizeof (struct ether_header));#ifdef BSD43_DRIVER /* * Deal with trailer protocol: if type is trailer * get true type from first 16-bit word past data. * Remember that type was trailer by setting off. */ check_trailer (eh, pData, &len, &off, &es->es_if); if (len == 0) return; /* sanity */#endif m = copy_to_mbufs (pData, len, off, (struct ifnet *) &es->es_if); if (m == NULL) { es->es_if.if_ierrors++; return; }#ifdef BSD43_DRIVER do_protocol_with_type (eh->ether_type, m, &es->es_ac, len);#else do_protocol (eh, m, &es->es_ac, len);#endif return; }/********************************************************************************* medGetRecvPacket - return the address of the next packet received** If a packet is available in the NIC receive buffer, return its address.* Otherwise, return NULL.*/LOCAL nic_RecvHdr_s *medGetRecvPacket ( FAST struct med_softc *es ) { FAST u_char currNIC_WritePage; FAST NIC_DEVICE *pNIC = es->nicAddr; FAST int oldLevel; /* * Select NIC register page 1, and retrieve the CURR register, * re-select NIC register page 0. */ oldLevel = intLock(); pNIC->Cr = (u_char) (RPAGE1 | ABORT | STA); currNIC_WritePage = pNIC->Curr; pNIC->Cr = (u_char) (RPAGE0 | ABORT | STA); intUnlock (oldLevel); if (es->pktNextToRead == currNIC_WritePage) /* No new packets. */ { return ((nic_RecvHdr_s *) NULL); } return ((nic_RecvHdr_s *) NIC_RECV_BFR_ADRS (es->pktNextToRead)); }/********************************************************************************* medRecvIntrHandler - task level interrupt service for input packets** This routine is called at task level indirectly by the interrupt* service routine to do any message received processing.*/LOCAL void medRecvIntrHandler ( FAST struct med_softc *es ) { FAST nic_RecvHdr_s *pRecvPacket; FAST u_char recvStatus; FAST u_long pktSize; FAST NIC_DEVICE *pNIC = es->nicAddr; if (es->bRecvBfrOvfl) /* Ignore packets on receive buffer overflow; */ return; /* they all will be dropped. */ while (TRUE) { while ((pRecvPacket = medGetRecvPacket (es)) != (nic_RecvHdr_s *) NULL) { if (es->bRecvBfrOvfl) return; recvStatus = pRecvPacket->recvStatus; if ((recvStatus & PRX) == nic_RECV_NO_ERROR) { pktSize = (u_long) pRecvPacket->byteCntL | (u_long) (pRecvPacket->byteCntH << 8); /* * If the packet is wrapped around in the receive buffer, * move it to a contiguous buffer. */ if (((u_long) pRecvPacket + pktSize) > (u_long) END_OF_RECV_BFR) { medMoveWrappedPacket (es, pRecvPacket, pktSize); medRecv (es, &(es->pOvfRecvBfr->eh), (int) pktSize); } else medRecv (es, &(pRecvPacket->eh), (int) pktSize); es->pktNextToRead = pRecvPacket->nextPkt; /* * Ensure that the "boundry" register is maintained one page * behind the "current" register. */ if (es->pktNextToRead == ((u_char) ((u_short) dbeth_NIC_RECV_BFR) >> 8)) { pNIC->Bnry = PSTOP - 1; } else pNIC->Bnry = es->pktNextToRead - 1; } else { if ((recvStatus & DIS) == nic_RCVR_DISABLED) logMsg("med%d: receiver disabled\n", es->es_if.if_unit, 0,0,0,0,0); if ((recvStatus & DFR) == nic_RCVR_DEFERRING) logMsg("med%d: receiver deferring\n", es->es_if.if_unit, 0,0,0,0,0); } } /* while ((pRecvPacket ... */ if (pNIC->Isr & PRX) /* pending recv interrupt ? */ { pNIC->Isr = PRX; /* clear interrupt flag */ med_Stats.PRX_intrCount++; /* update statistics monitor */ } else if (pNIC->Isr & RXE) /* pending recv error interrupt ? */ { pNIC->Isr = RXE; /* clear interrupt flag */ medRecordRecvError (es); } else { /* no recv interrupt */ /* Re-enable PRX and RXE interrupts. */ medSetNIC_IMR (es, nic_PKT_RECV_NO_ERRORS | nic_PKT_RECV_ERROR, MASK_NONE); break; /* break from while (TRUE) */ } } /* while (TRUE) */ }/********************************************************************************* medIoctl - process an ioctl request.*/LOCAL int medIoctl ( FAST struct ifnet *ifp, int cmd, caddr_t data ) { int unit = ifp->if_unit; FAST struct med_softc * es = med_softc [unit]; int s = splimp (); int error = 0; short flags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -