Return to BSD News archive
Received: by minnie.vk1xwt.ampr.org with NNTP id AA5581 ; Fri, 01 Jan 93 01:49:49 EST Newsgroups: comp.unix.bsd Path: sserve!manuel.anu.edu.au!munnari.oz.au!spool.mu.edu!wupost!zaphod.mps.ohio-state.edu!rpi!psinntp!psinntp!dg-rtp!ponds.uucp!rivers From: rivers@ponds.uucp (Thomas David Rivers) Subject: NE2000 test results (previous driver performs better). Summary: Here's a better driver (repost). Message-ID: <1992Dec27.181634.523@ponds.uucp> Keywords: ether, speed, 386bsd NE2000 Date: Sun, 27 Dec 1992 18:16:34 GMT Lines: 1078 Well, since Curt Mayer (curt@hoptoad.uucp) had re-written the NE2000 driver for us, I decided to take some time and give it a good shaking out. My test machines (ponds and lakes) are: ponds lakes 386DX, 33mhz 386DX, 33mhz NE2000 clone NE2000 clone 8-meg memory 12-meg memory Hercules ET4000 clone (running XFree86 1.1) IDE 240Meg. SCSI -663 meg Wangtek (EN2099) Wangtek (5150ES) 40-meg swap on wd0 40-meg swap on sd0 They are directly connected by 6 feet on ethernet cable, With a 50-ohm terminator on lakes, and a 50-ohm grounded terminator on ponds. There is nothing else on this "network". So, here are some timings from the driver posted to comp.unix.bsd by Ralf Friedl (PA Peter) <friedl@informatik.uni-kl.de>, on Jul 15th. These are arrived by moving a copy of the 386bsd kernel from lakes to ponds (444736 bytes) using binary ftp (no hash). Time to Transfer (seconds) Kbytes/Sec 4.3 1e+02 3.3 1.3e+02 3.4 1.3e+02 2.8 1.6e+02 4.2 1e+02 These appear to be rather good time, approaching what you would expect the bandwidth to be on such a network (few collisions...) Ok, so I installed the driver posted by Curt. My original intent was to install it on both machines, then only one. However, when that kernel came up on "lakes" the network didn't function (lots of overun-type errors from the driver: ne0 ... error: isr 15; ne0 ... error: isr 14, etc...) Thus, I was only able to get Curt's driver to run on "ponds". The following times reflect that situation (ponds is running Curt Mayer's driver, lakes is running the driver posted in July.) There was *no* other change in the test, hardware, etc... Since the times appeared so much worse, I ran more tests than before. Time to Transfer (seconds) Kbytes/Sec 10 42 10 42 11 39 10 42 15 29 6.3 69 9.4 46 These numbers don't approach those of the other driver. Also, just to get a feel for NFS mounts, rlogin, etc... I tried out several NFS configurations, rlogin'ing and so forth - generally it seemed to be much slower. OK, so I thought I may have seriously goofed things up, since these numbers were so much lower than the other driver. So, I rebooted ponds with the (saved) kernel containing the Friedl drivers, and ran some tests. Again, the only change I made was to reboot the machine - no other modifications. The test results returned to a set similar to above, indicating that it was indeed the NE2000 driver which explained the slowdown. I have sent this driver to several people (who had requested an improved driver from this news group.) But, I would like other people to do the same comparison (or a comparison in different circumstances) to validate my results. As such, I am *reposting* this same driver again.... (also, there were several people who requested this code, to whom I could not send mail (it bounced)) - Dave Rivers - (rivers@ponds.uucp) ----------------- cut here ---------------------------- Path: utnet-news!news.u-tokyo.ac.jp!ccut!wnoc-tyo-news!nec-tyo!nec-gw!mips!zaphod.mps.ohio-state.edu!uakari.primate.wisc.edu!ames!network.ucsd.edu!nosc!jadpc!Ralf Friedl (PA Peter) <friedl@informatik.uni-kl.de> From: friedl@informatik.uni-kl.de (PA Peter) Newsgroups: comp.unix.bsd Subject: Device driver for NE1000/NE2000 Message-ID: <9207152126.aa00382@superieur.informatik.uni-kl.de> Date: 15 Jul 92 19:53:32 GMT Sender: 386bsd-gate@jadpc.cts.com Reply-To: Ralf Friedl (PA Peter) <friedl@informatik.uni-kl.de> Organization: J. Deitch & Associates Lines: 212 Originator: 386bsd-gate@jadpc.cts.com Precedence: bulk Below is a diff for the original net2 NE2000 driver, so that the driver can be used with both NE1000 and NE2000 or compatible interface cards. The type of the card is determined during the boot in the autoconfiguration phase, so it is not necessary to specify it at compile time. The driver may also work with more that one card at the same time, but I didn't try it. The driver includes a file "machine/asm.h". This is used for inline versions of the in../out.. function. If you don't have something like that, just remove the line, and the functions in locore.s will be used. Enjoy ---- Ralf Friedl friedl@informatik.uni-kl.de #!/bin/sh # This is a shell archive (shar 3.32) # made 07/31/1992 07:20 UTC by shin@angora.nc.u-tokyo.ac.jp # Source directory /tmp # # existing files WILL be overwritten # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 24098 -rw-r--r-- if_ne.c # 2982 -rw-r--r-- if_nereg.h # if touch 2>&1 | fgrep 'amc' > /dev/null then TOUCH=touch else TOUCH=true fi # ============= if_ne.c ============== echo "x - extracting if_ne.c (Text)" sed 's/^X//' << 'SHAR_EOF' > if_ne.c && X/*- X * Copyright (c) 1990, 1991 William F. Jolitz. X * Copyright (c) 1990 The Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by the University of X * California, Berkeley and its contributors. X * 4. Neither the name of the University nor the names of its contributors X * may be used to endorse or promote products derived from this software X * without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X * SUCH DAMAGE. X * X * @(#)if_ne.c 7.4 (Berkeley) 5/21/91 X */ X X/* X * NE1000/NE2000 Ethernet driver X * X * Parts inspired from Tim Tucker's if_wd driver for the wd8003, X * insight on the ne2000 gained from Robert Clements PC/FTP driver. X */ X X#include "ne.h" X#if NNE > 0 X X#include "param.h" X#include "systm.h" X#include "mbuf.h" X#include "buf.h" X#include "protosw.h" X#include "socket.h" X#include "ioctl.h" X#include "errno.h" X#include "syslog.h" X X#include "net/if.h" X#include "net/netisr.h" X#include "net/route.h" X X#ifdef INET X#include "netinet/in.h" X#include "netinet/in_systm.h" X#include "netinet/in_var.h" X#include "netinet/ip.h" X#include "netinet/if_ether.h" X#endif X X#ifdef NS X#include "netns/ns.h" X#include "netns/ns_if.h" X#endif X X#include "i386/isa/isa_device.h" X#include "i386/isa/if_nereg.h" X#include "i386/isa/icu.h" X/* #include "machine/asm.h" */ X Xint neprobe(), neattach(), neintr(); Xint nestart(),neinit(), ether_output(), neioctl(); X Xstruct isa_driver nedriver = { X neprobe, neattach, "ne", X}; X Xstruct mbuf *neget(); X X#define ETHER_MIN_LEN 64 X#define ETHER_MAX_LEN 1536 X X/* Word Transfers, Burst Mode Select, Fifo at 8 bytes */ X#define DCR_CTRL2 DSDC_WTS|DSDC_BMS|DSDC_FT1 X/* No Word Transfers, Burst Mode Select, Fifo at 8 bytes */ X#define DCR_CTRL1 DSDC_BMS|DSDC_FT1 X X X/* X * Ethernet software status per interface. X * X * Each interface is referenced by a network interface structure, X * ns_if, which the routing code uses to locate the interface. X * This structure contains the output queue for the interface, its address, ... X */ Xstruct ne_softc { X struct arpcom ns_ac; /* Ethernet common part */ X#define ns_if ns_ac.ac_if /* network-visible interface */ X#define ns_addr ns_ac.ac_enaddr /* hardware Ethernet address */ X int ns_flags; X#define DSF_LOCK 1 /* block re-entering enstart */ X int ns_oactive ; X int ns_mask ; X int ns_ba; /* byte addr in buffer ram of inc pkt */ X int ns_cur; /* current page being filled */ X u_short ns_iobase; X u_short ns_board; /* Board-Type: 0:NE1000, 1:NE2000 */ X u_short ns_tbuf; X u_short ns_rbuf; X u_short ns_rbufend; X struct prhdr ns_ph; /* hardware header of incoming packet*/ X struct ether_header ns_eh; /* header of incoming packet */ X u_char ns_pb[2048 /*ETHERMTU+sizeof(long)*/]; X} ne_softc[NNE] ; X#define ENBUFSIZE (sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN) X Xu_char boarddata[16]; Xvoid nefetch (struct ne_softc *ns, void *up, u_int ad, u_int len); Xvoid neput (struct ne_softc *ns, void *up, u_int ad, u_int len); X X Xneprobe(dvp) X struct isa_device *dvp; X{ X int val,i, test, unit; X u_short iobase; X register struct ne_softc *ns; X X unit = dvp->id_unit; X if (unit >= NNE) X return (0); X ns = &ne_softc[unit]; X if (ns->ns_iobase) X /* Unit already configured */ X return (0); X iobase = ns->ns_iobase = dvp->id_iobase; X X /* Reset the bastard */ X val = inb(iobase+ne_reset); X /* DELAY(2000000); */ X outb(iobase+ne_reset,val); X X outb(iobase+ds_cmd, DSCM_STOP|DSCM_NODMA); X X if (inb (iobase + ds_cmd) != (DSCM_STOP | DSCM_NODMA)) X return (0); X i = 1000000; X while ((inb(iobase+ds0_isr)&DSIS_RESET) == 0 && i-- > 0); X if (i < 0) return (0); X X outb(iobase+ds0_isr, 0xff); X X /* No Word Transfers, Burst Mode Select, Fifo at 8 bytes */ X outb (iobase+ds0_dcr, DCR_CTRL1); X X outb(iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP); X DELAY(10000); X X /* Check cmd reg and fail if not right */ X if ((i=inb(iobase+ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP)) X return(0); X X outb(iobase+ds0_tcr, 0); X outb(iobase+ds0_rcr, DSRC_MON); X outb(iobase+ds0_pstart, RBUF1/DS_PGSIZE); X outb(iobase+ds0_pstop, RBUFEND1/DS_PGSIZE); X outb(iobase+ds0_bnry, RBUFEND1/DS_PGSIZE); X outb(iobase+ds0_imr, 0); X outb(iobase+ds0_isr, 0); X outb(iobase+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP); X outb(iobase+ds1_curr, RBUF1/DS_PGSIZE); X outb(iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP); X test = 0xA55A55AA; X neput (ns, &test, TBUF1, sizeof (test)); X nefetch (ns, &test, TBUF1, sizeof (test)); X if (test == 0xA55A55AA) { X ns->ns_board = 0; /* NE1000 */ X ns->ns_tbuf = TBUF1; X ns->ns_rbuf = RBUF1; X ns->ns_rbufend = RBUFEND1; X } X else { X ns->ns_board = 1; /* NE2000 */ X ns->ns_tbuf = TBUF2; X ns->ns_rbuf = RBUF2; X ns->ns_rbufend = RBUFEND2; X outb(iobase+ds0_dcr, DCR_CTRL2); X } X X#ifdef NEDEBUG X#define PAT(n) (0xa55a + 37*(n)) X#define RCON 37 X { int i, rom, pat; X X rom=1; X printf("ne ram "); X X for (i = 0; i < 0xfff0; i+=4) { X pat = PAT(i); X neput (ns, &pat,i,4); X nefetch (ns, &pat,i,4); X if (pat == PAT(i)) { X if (rom) { X rom=0; X printf(" %x", i); X } X } else { X if (!rom) { X rom=1; X printf("..%x ", i); X } X } X pat=0; X neput (ns, &pat,i,4); X } X printf("\n"); X } X#endif X X /* Extract board address */ X nefetch (ns, boarddata, 0, sizeof(boarddata)); X if (ns->ns_board) X for (i = 0; i < 6; i++) X ns->ns_addr[i] = boarddata[2 * i]; X else X for (i = 0; i < 6; i++) X ns->ns_addr[i] = boarddata[i]; X return (1); X} X X/* X * Fetch from onboard ROM/RAM X */ Xvoid nefetch (struct ne_softc *ns, void *up, u_int ad, u_int len) X{ X u_char cmd; X const u_short iobase = ns->ns_iobase; X X if (len == 0) X return; X cmd = inb(iobase+ds_cmd); X outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); X X /* Setup remote dma */ X outb (iobase+ds0_isr, DSIS_RDC); X outb (iobase+ds0_rbcr0, len); X outb (iobase+ds0_rbcr1, len>>8); X outb (iobase+ds0_rsar0, ad); X outb (iobase+ds0_rsar1, ad>>8); X X /* Execute & extract from card */ X outb (iobase+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START); X if (ns->ns_board) X insw (iobase+ne_data, up, len/2); X else X insb (iobase+ne_data, up, len/1); X X /* Wait till done, then shutdown feature */ X while ((inb (iobase+ds0_isr) & DSIS_RDC) == 0) X ; X outb (iobase+ds0_isr, DSIS_RDC); X outb (iobase+ds_cmd, cmd); X} X X/* X * Put to onboard RAM X */ Xvoid neput (struct ne_softc *ns, void *up, u_int ad, u_int len) X{ X u_char cmd; X const u_short iobase = ns->ns_iobase; X X if (len == 0) X return; X cmd = inb(iobase+ds_cmd); X outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); X X /* Setup for remote dma */ X outb (iobase+ds0_isr, DSIS_RDC); X if(len&1) len++; /* roundup to words */ X outb (iobase+ds0_rbcr0, len); X outb (iobase+ds0_rbcr1, len>>8); X outb (iobase+ds0_rsar0, ad); X outb (iobase+ds0_rsar1, ad>>8); X X /* Execute & stuff to card */ X outb (iobase+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START); X if (ns->ns_board) X outsw (iobase+ne_data, up, len/2); X else X outsb (iobase+ne_data, up, len/1); X X /* Wait till done, then shutdown feature */ X while ((inb (iobase+ds0_isr) & DSIS_RDC) == 0) X ; X outb (iobase+ds0_isr, DSIS_RDC); X outb (iobase+ds_cmd, cmd); X} X X/* X * Reset of interface. X */ Xnereset(unit, uban) X int unit, uban; X{ X if (unit >= NNE) X return; X printf("ne%d: reset\n", unit); X ne_softc[unit].ns_flags &= ~DSF_LOCK; X neinit(unit); X} X X/* X * Interface exists: make available by filling in network interface X * record. System will initialize the interface when it is ready X * to accept packets. We get the ethernet address here. X */ Xneattach(dvp) X struct isa_device *dvp; X{ X int unit = dvp->id_unit; X register struct ne_softc *ns = &ne_softc[unit]; X register struct ifnet *ifp = &ns->ns_if; X X ifp->if_unit = unit; X ifp->if_name = nedriver.name ; X ifp->if_mtu = ETHERMTU; X printf (" ethernet address %s", ether_sprintf(ns->ns_addr)) ; X ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; X ifp->if_init = neinit; X ifp->if_output = ether_output; X ifp->if_start = nestart; X ifp->if_ioctl = neioctl; X ifp->if_reset = nereset; X ifp->if_watchdog = 0; X if_attach(ifp); X} X X/* X * Initialization of interface; set up initialization block X * and transmit/receive descriptor rings. X */ Xneinit(unit) X int unit; X{ X register struct ne_softc *ns = &ne_softc[unit]; X struct ifnet *ifp = &ns->ns_if; X int s; X register i; char *cp; X const u_short iobase = ns->ns_iobase; X X if (ifp->if_addrlist == (struct ifaddr *)0) return; X if (ifp->if_flags & IFF_RUNNING) return; X X s = splimp(); X X /* set physical address on ethernet */ X outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP); X for (i=0 ; i < 6 ; i++) outb(iobase+ds1_par0+i,ns->ns_addr[i]); X X /* clr logical address hash filter for now */ X for (i=0 ; i < 8 ; i++) outb(iobase+ds1_mar0+i,0xff); X X /* init regs */ X outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP); X outb (iobase+ds0_rbcr0, 0); X outb (iobase+ds0_rbcr1, 0); X outb (iobase+ds0_imr, 0); X outb (iobase+ds0_isr, 0xff); X X outb(iobase+ds0_tcr, 0); X outb (iobase+ds0_rcr, DSRC_MON); X outb (iobase+ds0_tpsr, 0); X outb(iobase+ds0_pstart, ns->ns_rbuf/DS_PGSIZE); X outb(iobase+ds0_pstop, ns->ns_rbufend/DS_PGSIZE); X outb(iobase+ds0_bnry, ns->ns_rbuf/DS_PGSIZE); X outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP); X outb(iobase+ds1_curr, ns->ns_rbuf/DS_PGSIZE); X ns->ns_cur = ns->ns_rbuf/DS_PGSIZE; X outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); X outb (iobase+ds0_rcr, DSRC_AB); X if (ns->ns_board) X outb(iobase+ds0_dcr, DCR_CTRL2); X else X outb(iobase+ds0_dcr, DCR_CTRL1); X outb (iobase+ds0_imr, 0xff); X X ns->ns_if.if_flags |= IFF_RUNNING; X ns->ns_oactive = 0; ns->ns_mask = ~0; X nestart(ifp); X splx(s); X} X X/* X * Setup output on interface. X * Get another datagram to send off of the interface queue, X * and map it to the interface before starting the output. X * called only at splimp or interrupt level. X */ Xnestart(ifp) X struct ifnet *ifp; X{ X register struct ne_softc *ns = &ne_softc[ifp->if_unit]; X struct mbuf *m0, *m; X int buffer; X int len = 0, i, total,t; X const u_short iobase = ns->ns_iobase; X X /* X * The DS8390 has only one transmit buffer, if it is busy we X * must wait until the transmit interrupt completes. X */ X outb(iobase+ds_cmd,DSCM_NODMA|DSCM_START); X X if (ns->ns_flags & DSF_LOCK) X return; X X if (inb(iobase+ds_cmd) & DSCM_TRANS) X return; X X if ((ns->ns_if.if_flags & IFF_RUNNING) == 0) X return; X X IF_DEQUEUE(&ns->ns_if.if_snd, m); X X if (m == 0) X return; X X /* X * Copy the mbuf chain into the transmit buffer X */ X X ns->ns_flags |= DSF_LOCK; /* prevent entering nestart */ X buffer = ns->ns_tbuf; len = i = 0; X t = 0; X for (m0 = m; m != 0; m = m->m_next) X t += m->m_len; X X m = m0; X total = t; X for (m0 = m; m != 0; ) { X X if (m->m_len&1 && t > m->m_len) { X neput (ns, mtod(m, caddr_t), buffer, m->m_len - 1); X t -= m->m_len - 1; X buffer += m->m_len - 1; X m->m_data += m->m_len - 1; X m->m_len = 1; X m = m_pullup(m, 2); X } else { X if (m->m_len) { X neput (ns, mtod(m, caddr_t), buffer, m->m_len); X buffer += m->m_len; X t -= m->m_len; X } X MFREE(m, m0); X m = m0; X } X } X X /* X * Init transmit length registers, and set transmit start flag. X */ X X len = total; X if (len < ETHER_MIN_LEN) len = ETHER_MIN_LEN; X outb(iobase+ds0_tbcr0,len&0xff); X outb(iobase+ds0_tbcr1,(len>>8)&0xff); X outb(iobase+ds0_tpsr, ns->ns_tbuf/DS_PGSIZE); X outb(iobase+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START); X} X X/* buffer successor/predecessor in ring? */ X#define succ1(n) (((n)+1 >= RBUFEND1/DS_PGSIZE) ? RBUF1/DS_PGSIZE : (n)+1) X#define pred1(n) (((n)-1 < RBUF1/DS_PGSIZE) ? RBUFEND1/DS_PGSIZE-1 : (n)-1) X#define succ2(n) (((n)+1 >= RBUFEND2/DS_PGSIZE) ? RBUF2/DS_PGSIZE : (n)+1) X#define pred2(n) (((n)-1 < RBUF2/DS_PGSIZE) ? RBUFEND2/DS_PGSIZE-1 : (n)-1) X X/* X * Controller interrupt. X */ Xneintr(unit) X{ X register struct ne_softc *ns = &ne_softc[unit]; X u_char cmd,isr; X const u_short iobase = ns->ns_iobase; X X /* Save cmd, clear interrupt */ X cmd = inb (iobase+ds_cmd); Xloop: X isr = inb (iobase+ds0_isr); X outb(iobase+ds_cmd,DSCM_NODMA|DSCM_START); X outb(iobase+ds0_isr, isr); X X /* Receiver error */ X if (isr & DSIS_RXE) { X /* need to read these registers to clear status */ X (void) inb(iobase+ ds0_rsr); X (void) inb(iobase+ 0xD); X (void) inb(iobase + 0xE); X (void) inb(iobase + 0xF); X ns->ns_if.if_ierrors++; X } X X /* We received something; rummage thru tiny ring buffer */ X if (isr & (DSIS_RX|DSIS_RXE|DSIS_ROVRN)) { X u_char pend,lastfree; X X outb(iobase+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1); X pend = inb(iobase+ds1_curr); X outb(iobase+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0); X lastfree = inb(iobase+ds0_bnry); X X /* Have we wrapped? */ X if (lastfree >= ns->ns_rbufend/DS_PGSIZE) X lastfree = ns->ns_rbuf/DS_PGSIZE; X if (pend < lastfree && ns->ns_cur < pend) X lastfree = ns->ns_cur; X else if (ns->ns_cur > lastfree) X lastfree = ns->ns_cur; X X /* Something in the buffer? */ X while (pend != lastfree) { X u_char nxt; X X /* Extract header from microcephalic board */ X nefetch (ns, &ns->ns_ph,lastfree*DS_PGSIZE, X sizeof(ns->ns_ph)); X ns->ns_ba = lastfree*DS_PGSIZE+sizeof(ns->ns_ph); X X /* Incipient paranoia */ X if (ns->ns_ph.pr_status == DSRS_RPC || X /* for dequna's */ X ns->ns_ph.pr_status == 0x21) X nerecv (ns); X#ifdef NEDEBUG X else { X printf("cur %x pnd %x lfr %x ", X ns->ns_cur, pend, lastfree); X printf("nxt %x len %x ", ns->ns_ph.pr_nxtpg, X (ns->ns_ph.pr_sz1<<8)+ ns->ns_ph.pr_sz0); X printf("Bogus Sts %x\n", ns->ns_ph.pr_status); X } X#endif X X nxt = ns->ns_ph.pr_nxtpg ; X X /* Sanity check */ X if ( nxt >= ns->ns_rbuf/DS_PGSIZE && nxt <= ns->ns_rbufend/DS_PGSIZE X && nxt <= pend) X ns->ns_cur = nxt; X else ns->ns_cur = nxt = pend; X X /* Set the boundaries */ X lastfree = nxt; X if (ns->ns_board) X outb(iobase+ds0_bnry, pred2(nxt)); X else X outb(iobase+ds0_bnry, pred1(nxt)); X outb(iobase+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1); X pend = inb(iobase+ds1_curr); X outb(iobase+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0); X } X outb(iobase+ds_cmd, DSCM_START|DSCM_NODMA); X } X X /* Transmit error */ X if (isr & DSIS_TXE) { X ns->ns_flags &= ~DSF_LOCK; X /* Need to read these registers to clear status */ X ns->ns_if.if_collisions += inb(iobase+ds0_tbcr0); X ns->ns_if.if_oerrors++; X } X X /* Packet Transmitted */ X if (isr & DSIS_TX) { X ns->ns_flags &= ~DSF_LOCK; X ++ns->ns_if.if_opackets; X ns->ns_if.if_collisions += inb(iobase+ds0_tbcr0); X } X X /* Receiver ovverun? */ X if (isr & DSIS_ROVRN) { X log(LOG_ERR, "ne%d: error: isr %x\n", ns-ne_softc, isr X /*, DSIS_BITS*/); X outb(iobase+ds0_rbcr0, 0); X outb(iobase+ds0_rbcr1, 0); X outb(iobase+ds0_tcr, DSTC_LB0); X outb(iobase+ds0_rcr, DSRC_MON); X outb(iobase+ds_cmd, DSCM_START|DSCM_NODMA); X outb(iobase+ds0_rcr, DSRC_AB); X outb(iobase+ds0_tcr, 0); X } X X /* Any more to send? */ X outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); X nestart(&ns->ns_if); X outb (iobase+ds_cmd, cmd); X outb (iobase+ds0_imr, 0xff); X X X /* Still more to do? */ X isr = inb (iobase+ds0_isr); X if(isr) goto loop; X} X X/* X * Ethernet interface receiver interface. X * If input error just drop packet. X * Otherwise examine packet to determine type. If can't determine length X * from type, then have to drop packet. Othewise decapsulate X * packet based on type and pass to type specific higher-level X * input routine. X */ Xnerecv(ns) X register struct ne_softc *ns; X{ X int len,i; X X ns->ns_if.if_ipackets++; X len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1<<8); X if(len < ETHER_MIN_LEN || len > ETHER_MAX_LEN) X return; X X /* this need not be so torturous - one/two bcopys at most into mbufs */ X nefetch (ns, ns->ns_pb, ns->ns_ba, min(len,DS_PGSIZE-sizeof(ns->ns_ph))); X if (len > DS_PGSIZE-sizeof(ns->ns_ph)) { X int l = len - (DS_PGSIZE-sizeof(ns->ns_ph)), b, m; X u_char *p = ns->ns_pb + (DS_PGSIZE-sizeof(ns->ns_ph)); X X for (;;) { X if (ns->ns_board == 1) X ns->ns_cur = succ2 (ns->ns_cur); X else X ns->ns_cur = succ1 (ns->ns_cur); X b = ns->ns_cur*DS_PGSIZE; X if (l >= DS_PGSIZE) { X nefetch (ns, p, b, DS_PGSIZE); X p += DS_PGSIZE; l -= DS_PGSIZE; X continue; X } X if (l > 0) X nefetch (ns, p, b, l); X break; X } X } X /* don't forget checksum! */ X len -= sizeof(struct ether_header) + sizeof(long); X X neread(ns,(caddr_t)(ns->ns_pb), len); X} X X/* X * Pass a packet to the higher levels. X * We deal with the trailer protocol here. X */ Xneread(ns, buf, len) X register struct ne_softc *ns; X char *buf; X int len; X{ X register struct ether_header *eh; X struct mbuf *m; X int off, resid; X register struct ifqueue *inq; X X /* X * Deal with trailer protocol: if type is trailer type X * get true type from first 16-bit word past data. X * Remember that type was trailer by setting off. X */ X eh = (struct ether_header *)buf; X eh->ether_type = ntohs((u_short)eh->ether_type); X#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) X if (eh->ether_type >= ETHERTYPE_TRAIL && X eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { X off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; X if (off >= ETHERMTU) return; /* sanity */ X eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *)); X resid = ntohs(*(nedataaddr(eh, off+2, u_short *))); X if (off + resid > len) return; /* sanity */ X len = off + resid; X } else off = 0; X X if (len == 0) return; X X /* X * Pull packet off interface. Off is nonzero if packet X * has trailing header; neget will then force this header X * information to be at the front, but we still have to drop X * the type and length which are at the front of any trailer data. X */ X m = neget(buf, len, off, &ns->ns_if); X if (m == 0) return; X X ether_input(&ns->ns_if, eh, m); X} X X/* X * Supporting routines X */ X X/* X * Pull read data off a interface. X * Len is length of data, with local net header stripped. X * Off is non-zero if a trailer protocol was used, and X * gives the offset of the trailer information. X * We copy the trailer information and then all the normal X * data into mbufs. When full cluster sized units are present X * we copy into clusters. X */ Xstruct mbuf * Xneget(buf, totlen, off0, ifp) X caddr_t buf; X int totlen, off0; X struct ifnet *ifp; X{ X struct mbuf *top, **mp, *m, *p; X int off = off0, len; X register caddr_t cp = buf; X char *epkt; X X buf += sizeof(struct ether_header); X cp = buf; X epkt = cp + totlen; X X X if (off) { X cp += off + 2 * sizeof(u_short); X totlen -= 2 * sizeof(u_short); X } X X MGETHDR(m, M_DONTWAIT, MT_DATA); X if (m == 0) X return (0); X m->m_pkthdr.rcvif = ifp; X m->m_pkthdr.len = totlen; X m->m_len = MHLEN; X X top = 0; X mp = ⊤ X while (totlen > 0) { X if (top) { X MGET(m, M_DONTWAIT, MT_DATA); X if (m == 0) { X m_freem(top); X return (0); X } X m->m_len = MLEN; X } X len = min(totlen, epkt - cp); X if (len >= MINCLSIZE) { X MCLGET(m, M_DONTWAIT); X if (m->m_flags & M_EXT) X m->m_len = len = min(len, MCLBYTES); X else X len = m->m_len; X } else { X /* X * Place initial small packet/header at end of mbuf. X */ X if (len < m->m_len) { X if (top == 0 && len + max_linkhdr <= m->m_len) X m->m_data += max_linkhdr; X m->m_len = len; X } else X len = m->m_len; X } X bcopy(cp, mtod(m, caddr_t), (unsigned)len); X cp += len; X *mp = m; X mp = &m->m_next; X totlen -= len; X if (cp == epkt) X cp = buf; X } X return (top); X} X X/* X * Process an ioctl request. X */ Xneioctl(ifp, cmd, data) X register struct ifnet *ifp; X int cmd; X caddr_t data; X{ X register struct ifaddr *ifa = (struct ifaddr *)data; X struct ne_softc *ns = &ne_softc[ifp->if_unit]; X struct ifreq *ifr = (struct ifreq *)data; X int s = splimp(), error = 0; X X X switch (cmd) { X X case SIOCSIFADDR: X ifp->if_flags |= IFF_UP; X X switch (ifa->ifa_addr->sa_family) { X#ifdef INET X case AF_INET: X neinit(ifp->if_unit); /* before arpwhohas */ X ((struct arpcom *)ifp)->ac_ipaddr = X IA_SIN(ifa)->sin_addr; X arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); X break; X#endif X#ifdef NS X case AF_NS: X { X register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); X X if (ns_nullhost(*ina)) X ina->x_host = *(union ns_host *)(ns->ns_addr); X else { X /* X * The manual says we can't change the address X * while the receiver is armed, X * so reset everything X */ X ifp->if_flags &= ~IFF_RUNNING; X bcopy((caddr_t)ina->x_host.c_host, X (caddr_t)ns->ns_addr, sizeof(ns->ns_addr)); X } X neinit(ifp->if_unit); /* does ne_setaddr() */ X break; X } X#endif X default: X neinit(ifp->if_unit); X break; X } X break; X X case SIOCSIFFLAGS: X if ((ifp->if_flags & IFF_UP) == 0 && X ifp->if_flags & IFF_RUNNING) { X ifp->if_flags &= ~IFF_RUNNING; X outb(ns->ns_iobase+ds_cmd,DSCM_STOP|DSCM_NODMA); X } else if (ifp->if_flags & IFF_UP && X (ifp->if_flags & IFF_RUNNING) == 0) X neinit(ifp->if_unit); X break; X X#ifdef notdef X case SIOCGHWADDR: X bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data, X sizeof(ns->ns_addr)); X break; X#endif X X default: X error = EINVAL; X } X splx(s); X return (error); X} X#endif SHAR_EOF $TOUCH -am 0731160392 if_ne.c && chmod 0644 if_ne.c || echo "restore of if_ne.c failed" set `wc -c if_ne.c`;Wc_c=$1 if test "$Wc_c" != "24098"; then echo original size 24098, current size $Wc_c fi # ============= if_nereg.h ============== echo "x - extracting if_nereg.h (Text)" sed 's/^X//' << 'SHAR_EOF' > if_nereg.h && X/*- X * Copyright (c) 1991 The Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by the University of X * California, Berkeley and its contributors. X * 4. Neither the name of the University nor the names of its contributors X * may be used to endorse or promote products derived from this software X * without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X * SUCH DAMAGE. X * X * @(#)if_nereg.h 7.1 (Berkeley) 5/9/91 X */ X X/* X * NE2000 Ethernet Card registers X */ X X/* The NE1000/NE2000 uses a DS8390 Ethernet controller in at the beginning of X its i/o space */ X#include "ic/ds8390.h" X X#define ne_data 0x10 /* Data Transfer port */ X#define ne_reset 0x1f /* Card Reset port */ X X#define PKTSZ 0x600 X#define TBUF(board) (0x2000 * (board)) /* Starting location of Transmit Buffer */ X#define RBUF(board) (TBUF(board)+PKTSZ) /* Starting location of Receive Buffer */ X#define RBUFEND(board) (0x4000 * (board)) /* Ending location of Tr ansmit Buffer */ X X#define TBUF1 TBUF(1) /* Starting location of Transmit Buffer */ X#define RBUF1 RBUF(1) /* Starting location of Receive Buffer */ X#define RBUFEND1 RBUFEND(1) /* Ending location of Transmit Buffer */ X#define TBUF2 TBUF(2) /* Starting location of Transmit Buffer */ X#define RBUF2 RBUF(2) /* Starting location of Receive Buffer */ X#define RBUFEND2 RBUFEND(2) /* Ending location of Transmit Buffer */ X SHAR_EOF $TOUCH -am 0731160792 if_nereg.h && chmod 0644 if_nereg.h || echo "restore of if_nereg.h failed" set `wc -c if_nereg.h`;Wc_c=$1 if test "$Wc_c" != "2982"; then echo original size 2982, current size $Wc_c fi exit 0