*BSD News Article 9328


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 = &top;
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