📄 if_ne.c
字号:
#ifndef lintstatic char *sccsid = "@(#)if_ne.c 4.7 (ULTRIX) 2/26/91";#endif lint/************************************************************************ * * * Copyright (c) 1984-1989 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//*----------------------------------------------------------------------- * Modification History: * * 24-Feb-91 jsd * Allow loopback packets if COPYALL mode is set * * 9-Aug-90 chc (Chran-Ham Chang) * Fixed the SIOCRPHYSADDR ioctl problem. * * 25-Sep-89 chc (Chran-Ham Chang) * Created this Second Generation Ethernet Controller (SGEC) * network driver for mipsfairII * * 08-Mar-90 chc * reworked on the neinit routine * fixed the mbuf free problem * * --------------------------------------------------------------------*//* * Digital SGEC Network Interface */#include "ne.h"#include "packetfilter.h" /* NPACKETFILTER */#include "../data/if_ne_data.c"extern struct protosw *iftype_to_proto(), *iffamily_to_proto();extern int net_output();extern struct timeval time;int neprobe(), neattach(), neintr(),nereset();int neinit(),nestart(),neioctl(),newatch();extern int cpu;u_short nestd[] = { 0 };struct uba_driver nedriver = { neprobe, 0, neattach, 0, nestd, "ne", neinfo };u_char ne_unused_multi[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };u_char ne_multi[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 };#ifdef vax#define svtopte(x) (unsigned long)(&Sysmap[btop((int)x&~VA_SYS)])#define ptetosv(x) (unsigned long)((unsigned)ptob((struct pte *)(x)-&Sysmap[0])|VA_SYS)#define vaddr(y) (char *)(ptetosv((y)->pt_addr)+(y)->offset)#endifint nedebug = 0;#define NEMCLGET(m) { \ register struct mbuf *p ; \ MGET((m), M_DONTWAIT, MT_DATA); \ if ((m)) { \ MCLGET((m), p); \ m->m_len = CLBYTES; \ if (p == 0) { \ m_freem((m)); \ (m) = (struct mbuf *)NULL; \ } \ } \}#define NEALIGN(start,align) (((int)start&align) ? \ (caddr_t)((((int)start)&(~align))+ \ align+1): \ (caddr_t)(start))/* * Probe the SGEC to see if it's there */neprobe(reg,ui) caddr_t reg; struct uba_device *ui;{ int unit = ui->ui_unit; register struct ne_softc *sc = &ne_softc[unit]; register struct nesw *nesw; /* ptr to switch struct */ int i,j; caddr_t ringaddr,mp; struct mbuf **mbp; /* * CPU identifiers */ switch (cpu) { case DS_5500: /* mipsfair 2 */ sc->nesw = nesw = ds5500sw; sc->ne_narom = (u_char *)PHYS_TO_K1(nesw->ne_phys_narom); sc->ne_csrs = (NECSRS *)PHYS_TO_K1(nesw->ne_phys_csr); sc->ne_initcsr = (u_long)( nesw->ne_ipl | nesw->ne_vec | nesw->ne_mode | 0x1fff0003 ); sc->ne_cmdcsr = nesw->ne_burst << NE_BURST_SHIFT | nesw->ne_sigle | NE_CSR6_DC ; sc->ntring = nesw->ntdesc; sc->nrring = nesw->nrdesc; sc->is_if.if_sysid_type = 111; break; default: printf("neprobe : cpu type %d unknown",cpu); return(0); } /* * reset the SGEC and check the self test result */ if(!nesoftreset(sc,unit)) return(0); /* self test fail */ /* * Initial the CSR0 */ if(!nesetcsr0(sc,unit)) return(0); /* csr0 write error */ /* * Load the System Base Register for VAX arch. */#ifdef vax csrpt->csr7 = (u_long) mfpr(SBR);#endif /* * Allocate contigous, octaword aligned (performance purpose) * space for both descriptor rings */ KM_ALLOC(ringaddr, caddr_t, sizeof(NEDESC) * (sc->ntring + sc->nrring + 3), KM_DEVBUF,KM_NOW_CL_CO_CA); if(ringaddr == 0 ) { printf(" ne %d: couldn't allocate memory for descriptor ring\n",unit); return(0); } /* make the OCTAWORD alignment to increase performance */ sc->tring = (NEDESC *)NEALIGN(ringaddr,NE_OCTAWORD); sc->tring = (NEDESC *)PHYS_TO_K1(svtophy(sc->tring)); /* chain back the ring */ sc->tring[sc->ntring].ne_bfaddr = svtophy(sc->tring); sc->tring[sc->ntring].ne_info = NE_CA; sc->tring[sc->ntring].ne_own = NE_OWN; sc->rring = sc->tring + sc->ntring + 1; sc->rring = (NEDESC *)PHYS_TO_K1(svtophy(sc->rring)); /* chain back the ring */ sc->rring[sc->nrring].ne_bfaddr = svtophy(sc->rring); sc->rring[sc->nrring].ne_info = NE_CA; sc->rring[sc->nrring].ne_own = NE_OWN; /* * Allocate mbuf pointer for transmit and receive buffer * * tmbuf : mbuf pointer which points the transmit * data buffer * smbuf : mbuf chained point which is passed by * higher network layer * rmbuf : mbuf pointer which points the receive buffer */ KM_ALLOC(sc->tmbuf, struct mbuf ** , sizeof(struct mbuf *) * (sc->ntring * 2 + sc->nrring), KM_DEVBUF, KM_NOW_CL_CO_CA); if(sc->tmbuf == 0 ) { printf(" ne %d: couldn't allocate memory for buffer pointer\n",unit); KM_FREE(ringaddr,KM_DEVBUF); return(0); } /* clean the mbuf pointer */ bzero(sc->tmbuf,((sizeof(struct mbuf *) * (sc->ntring *2 + sc->nrring)))); sc->smbuf = sc->tmbuf + sc->ntring ; sc->rmbuf = sc->smbuf + sc->ntring ; /* setup buffer must be word aligned */ KM_ALLOC(mp,caddr_t ,SETUPSIZE+1, KM_DEVBUF,KM_NOW_CL_CO_CA); if(mp == 0) { printf(" ne%d: couldn't allocate setup buffer \n",unit); KM_FREE(ringaddr,KM_DEVBUF); KM_FREE(sc->tmbuf,KM_DEVBUF); return(0); } sc->ne_setup = (struct ne_setup *)NEALIGN(mp,NE_WORD); /* * initialize multicast address table */ for (i=0; i<NMULTI; i++) { sc->muse[i] = 0; bcopy(ne_multi, &sc->multi[i],MULTISIZE); } /* * fill out the station address from narom */ for ( i = j = 0; i < 6 ; i++, j +=4 ) { sc->ne_setup[0].setup_char[i]=sc->is_addr[i]=sc->ne_narom[j]; } return(sizeof(struct ne_softc));}/* * Interface exeists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */neattach(ui) struct uba_device *ui;{ register struct ne_softc *sc = &ne_softc[ui->ui_unit]; register struct ifnet *ifp = &sc->is_if; register int i; register struct sockaddr_in *sin; register NECSRS *csrpt = sc->ne_csrs; int delay; ifp->if_unit = ui->ui_unit; ifp->if_name = "ne"; ifp->if_mtu = ETHERMTU; ifp->if_type = IFT_ETHER; ifp->if_flags |= IFF_BROADCAST | IFF_DYNPROTO | IFF_NOTRAILERS; ((struct arpcom *)ifp)->ac_ipaddr.s_addr = 0; sin = (struct sockaddr_in *)&ifp->if_addr; sin->sin_family = AF_INET; ifp->if_init = neinit; ifp->if_output = net_output; ifp->if_start = nestart; ifp->if_ioctl = neioctl; ifp->if_timer = 0; ifp->if_watchdog = newatch; ifp->if_reset = nereset; /* * Get the SGEC version */ sc->ne_rev = csrpt->csr10; for (delay = 100000; delay && !(csrpt->csr5 & NE_CSR5_DN); delay--); if(!delay) { printf("ne%d: timeout accessing virtual CSR10 \n",ui->ui_unit);/* XXX */ sc->ne_rev = 3; } sc->ne_rev = csrpt->csr10 >> NE_RE_SHIFT ; bcopy("DEC SGEC Ethernet Interface", ifp->if_version, 27); ifp->if_version[28] = '\0'; printf("ne%d: %s, V%d hardware address: %s \n", ui->ui_unit, ifp->if_version,sc->ne_rev,ether_sprintf(sc->is_addr)); #if NPACKETFILTER > 0 attachpfilter(&(sc->is_ed));#endif NPACKETFILTER > 0 if_attach(ifp);}/* * Initialization of interface, allocate the mbuf for reveive ring, * fill up the setup frame and start the interface */neinit(unit) int unit;{ register struct ne_softc *sc = &ne_softc[unit]; register struct ifnet *ifp = &sc->is_if; register NEDESC *rp; register struct mbuf *m; register s; NECSRS *csrpt = sc->ne_csrs; int i,status,delay; /* address not known */ if (ifp->if_addrlist == (struct ifaddr *)0) return; if (ifp->if_flags & IFF_RUNNING) return; s = splimp(); if ( ifp->if_flags & IFF_PROMISC ) { sc->ne_cmdcsr |= NE_AF_PRO ; csrpt->csr6 &= ~(NE_CSR6_SR | NE_CSR6_ST); } else { sc->ne_cmdcsr &= ~NE_AF_PRO ; /* prepare the setup frame */ nesetup( sc , NE_SETUP_IC); sc->tring[0].ne_bfaddr = svtophy(sc->ne_setup); sc->tring[0].ne_bsize = SETUPSIZE ; sc->tring[0].ne_info = NE_DT_TSET | NE_SETUP_IC; sc->tring[0].ne_own = NE_OWN; /* startup the setup packet and wait for interrupt */ csrpt->csr4 = svtophy(sc->tring); csrpt->csr6 = sc->ne_cmdcsr | NE_CSR6_ST | NE_CSR6_IE ; csrpt->csr1 = NE_CSR1_PD; wbflush(); for (delay = 100; delay > 0 && !(csrpt->csr5 & NE_CSR5_TI); delay--) DELAY(10000); if(!delay) { printf("ne%d : setup frame transmit timeout \n",unit); status = EIO; splx(s); return (status); } else { if (sc->tring[0].ne_flag & NE_SETUP_SE) { printf("ne%d : setup frame error \n",unit); status = EIO; splx(s); return (status); } sc->setupqueued = 0; } /* clear the csr5 */ csrpt->csr5 = csrpt->csr5; wbflush(); } /* set up the receive buffer */ for ( i=0,rp=sc->rring ; i < sc->nrring; i++,rp++) { if(!(sc->rmbuf[i])) { NEMCLGET(m); } else { m = sc->rmbuf[i]; } if(m) { neinitdesc(rp,m,1); rp->ne_own = NE_OWN; sc->rmbuf[i]=m; } else { printf("ne%d: couldn't allocate receive buffer\n",unit); status = EIO; splx(s); return (status); } } /* set up the transmit buffer */ for ( i=0,rp=sc->tring ; i < sc->ntring; i++,rp++) { if(!(sc->tmbuf[i])) { NEMCLGET(m); } else { m = sc->tmbuf[i]; } if(m) { neinitdesc(rp,m,0); sc->tmbuf[i]=m; } else { printf("ne%d: couldn't allocate transmit buffer\n",unit); status = EIO; splx(s); return (status); } } sc->nxmit = sc->tindex = sc->otindex = sc->rindex = 0; /* fill out the descriptor address list */ csrpt->csr3 = svtophy(sc->rring); csrpt->csr4 = svtophy(sc->tring); if ( ifp->if_flags & IFF_ALLMULTI ) sc->ne_cmdcsr |= NE_AF_MUL ; if ((ifp->if_flags & IFF_LOOPBACK)) /* if this is a internal loop back */ csrpt->csr6 = sc->ne_cmdcsr | NE_CSR6_SR | NE_CSR6_ST | NE_CSR6_IE | NE_OM6_EXL ; else csrpt->csr6 = sc->ne_cmdcsr | NE_CSR6_SR | NE_CSR6_ST | NE_CSR6_IE | NE_OM6_NOR ; /* * mark the interface up; place the setup frame in the xmit list */ ifp->if_flags |= IFF_UP | IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; nestart( unit ); sc->ztime = time.tv_sec; splx(s);} /* * Start output on the interface */nestart(unit) int unit;{ register struct ne_softc *sc = &ne_softc[unit]; register NEDESC *rp; register int index; struct mbuf *m,*m0; int bufaddr,tlen,s; int nNENXMT=sc->ntring; NECSRS *csrpt = sc->ne_csrs; for ( index = sc->tindex; sc->tring[index].ne_own == 0 && sc->nxmit < ( nNENXMT - 1 ) ; sc->tindex = index = ++index % nNENXMT ){ rp = &sc->tring[index]; if(sc->setupqueued){ rp->ne_bfaddr = svtophy(sc->ne_setup); tlen = SETUPSIZE; rp->ne_info = NE_DT_TSET; sc->setupqueued = 0; if(sc->ne_setup_ic) { rp->ne_info |= NE_SETUP_IC ; sc->ne_setup_ic = 0; } } else { IF_DEQUEUE(&sc->is_if.if_snd, m); if(m == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -