home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!hoptoad!curt
- From: curt@hoptoad.uucp (Curt Mayer)
- Newsgroups: comp.unix.bsd
- Subject: Shitty NE2000 NFS performance problem fixed right (source code)
- Message-ID: <30089@hoptoad.uucp>
- Date: 18 Dec 92 21:20:25 GMT
- Distribution: world
- Organization: hardcore driver hackerz
- Lines: 854
- Summary: buggy driver, RTFM
-
- after playing with if_ne for a day or two, i have made 8K NFS mounts solid.
- ftp performance is twice what the previous driver was. NFS is now filesystem
- limited, the way it should be.
-
- bad buffer management, coupled with not using a high performance mode the
- ns8390, made the old driver lose bad when you got a lot of back to back
- packets.
-
- CAVEATS:
- ne1000 mode is untested, as I do not have one. I put the ne2000 clone
- I have into 8 bit mode, and tested the 8 bit stuff. because of this, consider
- this driver beta.
-
- anyway, the new driver:
-
- # This is a shell archive. Save it in a file, remove anything before
- # this line, and then unpack it by entering "sh file". Note, it may
- # create directories; files and directories will be owned by you and
- # have default permissions.
- #
- # This archive contains:
- #
- # if_ne.c
- #
- echo x - if_ne.c
- sed 's/^X//' >if_ne.c << 'END-of-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 * 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 * receive bottom end totally rewritten by Curt Mayer, Dec 1992.
- X * no longer loses back to back packets.
- X * note to driver writers: RTFM!
- 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
- 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/*
- 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 struct prhdr ns_ph; /* hardware header of incoming packet*/
- X u_char ns_pb[2048];
- X u_char ns_txstart; /* transmitter buffer start */
- X u_char ns_rxstart; /* receiver buffer start */
- X u_char ns_rxend; /* receiver buffer end */
- X short ns_port; /* i/o port base */
- X short ns_mode; /* word/byte mode */
- X} ne_softc[NNE] ;
- X#define ENBUFSIZE (sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN)
- X
- X#define PAT(n) (0xa55a + 37*(n))
- X
- Xu_short boarddata[16];
- X
- Xneprobe(dvp)
- X struct isa_device *dvp;
- X{
- X int val, i, s, sum, pat;
- X register struct ne_softc *ns = &ne_softc[0];
- X register nec;
- X
- X#ifdef lint
- X neintr(0);
- X#endif
- X
- X nec = ns->ns_port = dvp->id_iobase;
- X s = splimp();
- X
- X /* Byte Transfers, Burst Mode Select, Fifo at 8 bytes */
- X ns->ns_mode = DSDC_BMS|DSDC_FT1;
- X ns->ns_txstart = TBUF8 / DS_PGSIZE;
- X ns->ns_rxend = RBUFEND8 / DS_PGSIZE;
- X
- Xtryagain:
- X
- X ns->ns_rxstart = ns->ns_txstart + (PKTSZ / DS_PGSIZE);
- X
- X /* Reset the bastard */
- X val = inb(nec + ne_reset);
- X DELAY(200);
- X outb(nec + ne_reset, val);
- X DELAY(200);
- X
- X outb(nec + ds_cmd, DSCM_STOP|DSCM_NODMA);
- X
- X i = 10000;
- X while ((inb(nec + ds0_isr) & DSIS_RESET) == 0 && i-- > 0);
- X if (i < 0) return (0);
- X
- X outb(nec + ds0_isr, 0xff);
- X outb(nec + ds0_dcr, ns->ns_mode);
- X outb(nec + ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
- X DELAY(1000);
- X
- X /* Check cmd reg and fail if not right */
- X if ((i = inb(nec + ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP))
- X return(0);
- X
- X outb(nec + ds0_tcr, 0);
- X outb(nec + ds0_rcr, DSRC_MON);
- X outb(nec + ds0_pstart, ns->ns_rxstart);
- X outb(nec + ds0_pstop, ns->ns_rxend);
- X outb(nec + ds0_imr, 0);
- X outb(nec + ds0_isr, 0);
- X outb(nec + ds0_bnry, ns->ns_rxstart);
- X outb(nec + ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
- X outb(nec + ds1_curr, ns->ns_rxstart);
- X outb(nec + ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
- X
- X /*
- X * <groan> detect difference between units
- X * solely by where the RAM is decoded.
- X */
- X pat = PAT(0);
- X neput(ns, &pat, ns->ns_txstart * DS_PGSIZE, 4);
- X nefetch(ns, &pat, ns->ns_txstart * DS_PGSIZE, 4);
- X if (pat != PAT(0)) {
- X if (ns->ns_mode & DSDC_WTS)
- X return (0);
- X
- X /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
- X ns->ns_mode = DSDC_WTS|DSDC_BMS|DSDC_FT1;
- X ns->ns_txstart = TBUF16 / DS_PGSIZE;
- X ns->ns_rxend = RBUFEND16 / DS_PGSIZE;
- X goto tryagain;
- X }
- X
- X
- X /* Extract board address */
- X nefetch (ns, (caddr_t)boarddata, 0, sizeof(boarddata));
- X
- X for(i=0; i < 6; i++)
- X ns->ns_addr[i] = boarddata[i];
- X splx(s);
- X return (1);
- X}
- X
- X/*
- X * Fetch from onboard ROM/RAM
- X */
- Xnefetch (ns, up, ad, len) struct ne_softc *ns; caddr_t up; {
- X u_char cmd;
- X register nec = ns->ns_port;
- X int counter = 100000;
- X
- X cmd = inb (nec + ds_cmd);
- X outb (nec + ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
- X
- X /* Setup remote dma */
- X outb (nec + ds0_isr, DSIS_RDC);
- X
- X if ((ns->ns_mode & DSDC_WTS) && (len & 1))
- X len++; /* roundup to words */
- X
- X outb (nec+ds0_rbcr0, len);
- X outb (nec+ds0_rbcr1, len>>8);
- X outb (nec+ds0_rsar0, ad);
- X outb (nec+ds0_rsar1, ad>>8);
- X
- X /* Execute & extract from card */
- X outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
- X
- X if (ns->ns_mode & DSDC_WTS)
- X insw (nec+ne_data, up, len/2);
- X else
- X insb (nec+ne_data, up, len);
- X
- X /* Wait till done, then shutdown feature */
- X while ((inb (nec+ds0_isr) & DSIS_RDC) == 0 && counter-- > 0)
- X ;
- X outb (nec+ds0_isr, DSIS_RDC);
- X outb (nec+ds_cmd, cmd);
- X}
- X
- X/*
- X * Put to onboard RAM
- X */
- Xneput (ns, up, ad, len) struct ne_softc *ns; caddr_t up; {
- X u_char cmd;
- X register nec = ns->ns_port;
- X int counter = 100000;
- X
- X cmd = inb(nec+ds_cmd);
- X outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
- X
- X /* Setup for remote dma */
- X outb (nec+ds0_isr, DSIS_RDC);
- X
- X if ((ns->ns_mode & DSDC_WTS) && (len & 1))
- X len++; /* roundup to words */
- X
- X outb (nec+ds0_rbcr0, len);
- X outb (nec+ds0_rbcr1, len>>8);
- X outb (nec+ds0_rsar0, ad);
- X outb (nec+ds0_rsar1, ad>>8);
- X
- X /* Execute & stuff to card */
- X outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);
- X if (ns->ns_mode & DSDC_WTS)
- X outsw (nec+ne_data, up, len/2);
- X else
- X outsb (nec+ne_data, up, len);
- X
- X /* Wait till done, then shutdown feature */
- X while ((inb (nec+ds0_isr) & DSIS_RDC) == 0 && counter-- > 0)
- X ;
- X outb (nec+ds0_isr, DSIS_RDC);
- X outb (nec+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 (" ne%d, address %s",
- X (ns->ns_mode & DSDC_WTS) ? 2000 : 1000,
- X 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 int i; char *cp;
- X register nec = ns->ns_port;
- 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 (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
- X for (i=0 ; i < 6 ; i++) outb(nec+ds1_par0+i,ns->ns_addr[i]);
- X
- X /* clr logical address hash filter for now */
- X for (i=0 ; i < 8 ; i++) outb(nec+ds1_mar0+i,0xff);
- X
- X /* init regs */
- X outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
- X outb (nec+ds0_rbcr0, 0);
- X outb (nec+ds0_rbcr1, 0);
- X outb (nec+ds0_imr, 0);
- X outb (nec+ds0_isr, 0xff);
- X outb(nec+ds0_dcr, ns->ns_mode);
- X outb(nec+ds0_tcr, 0);
- X outb (nec+ds0_rcr, DSRC_MON);
- X outb (nec+ds0_tpsr, 0);
- X outb(nec+ds0_pstart, ns->ns_rxstart);
- X outb(nec+ds0_pstop, ns->ns_rxend);
- X outb(nec+ds0_bnry, ns->ns_rxstart);
- X outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
- X outb(nec+ds1_curr, ns->ns_rxstart);
- X outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
- X outb (nec+ds0_rcr, DSRC_AB);
- X outb(nec+ds0_dcr, ns->ns_mode);
- X outb (nec+ds0_imr, 0xff);
- X
- X ns->ns_if.if_flags |= IFF_RUNNING;
- X ns->ns_flags &= ~DSF_LOCK;
- 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 register nec = ns->ns_port;
- 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(nec+ds_cmd,DSCM_NODMA|DSCM_START);
- X
- X if (ns->ns_flags & DSF_LOCK)
- X return;
- X
- X if (inb(nec+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_txstart * DS_PGSIZE;
- X 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 neput(ns, mtod(m, caddr_t), buffer, m->m_len);
- X buffer += m->m_len;
- X t -= m->m_len;
- 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(nec+ds0_tbcr0,len&0xff);
- X outb(nec+ds0_tbcr1,(len>>8)&0xff);
- X outb(nec+ds0_tpsr, ns->ns_txstart);
- X outb(nec+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START);
- X}
- X
- X/*
- X * Controller interrupt.
- X */
- Xneintr(unit)
- X{
- X register struct ne_softc *ns = &ne_softc[unit];
- X u_char cmd,isr;
- X register nec = ns->ns_port;
- X u_char err;
- X
- X /* Save cmd, clear interrupt */
- X cmd = inb (nec+ds_cmd);
- Xloop:
- X isr = inb (nec+ds0_isr);
- X outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
- X outb(nec+ds0_isr, isr);
- X
- X /* Receiver error */
- X if (isr & DSIS_RXE) {
- X /* need to read these registers to clear status */
- X err = inb(nec+ ds0_rsr);
- X (void)inb(nec+0xD);
- X (void)inb(nec+0xE);
- X (void)inb(nec+0xF);
- X ns->ns_if.if_ierrors++;
- X }
- X
- X /* We received something */
- X if (isr & DSIS_RX) {
- X u_char bnry;
- X u_char curr;
- X int len;
- X int i;
- X unsigned char c;
- X
- X while (1) {
- X
- X outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
- X bnry = inb(nec+ds0_bnry);
- X outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
- X curr = inb(nec+ds1_curr);
- X
- X#ifdef NEDEBUG
- X printf("neintr: bnry %x curr %x\n", bnry, curr);
- X#endif
- X
- X /* if ring empty, done! */
- X if (bnry == curr) {
- X break;
- X }
- X
- X /* send packet with auto packet release */
- X outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
- X outb (nec+ds0_rbcr1, 0x0f);
- X outb(nec+ds0_dcr, ns->ns_mode | DSDC_AR);
- X outb (nec+ds_cmd, DSCM_SENDP|DSCM_PG0|DSCM_START);
- X
- X /* get length */
- X if ((ns->ns_mode & DSDC_WTS))
- X insw (nec+ne_data, (u_short *)&ns->ns_ph, 2);
- X else
- X insb (nec+ne_data, &ns->ns_ph, 4);
- X
- X#ifdef NEDEBUG
- X printf("neintr: sendp packet hdr: %x %x %x %x\n",
- X ns->ns_ph.pr_status,
- X ns->ns_ph.pr_nxtpg,
- X ns->ns_ph.pr_sz0,
- X ns->ns_ph.pr_sz1);
- X#endif
- 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 printf("neintr: bnry %x curr %x\n", bnry, curr);
- X printf("neintr: packet hdr: %x %x %x %x\n",
- X ns->ns_ph.pr_status,
- X ns->ns_ph.pr_nxtpg,
- X ns->ns_ph.pr_sz0,
- X ns->ns_ph.pr_sz1);
- X printf("isr = 0x%x reg_isr=0x%x\n",
- X isr, inb(nec+ds0_isr));
- X outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
- X bnry = inb(nec+ds0_bnry);
- X outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
- X curr = inb(nec+ds1_curr);
- X printf("neintr: new bnry %x curr %x\n", bnry, curr);
- X printf("neintr: bad len %d\n-hanging-\n",
- X len);
- X while (1) ;
- X }
- X
- X#ifdef NEDEBUG
- X printf("neintr: snarfing %d bytes\n", len);
- X#endif
- X
- X /* read packet */
- X if ((ns->ns_mode & DSDC_WTS)) {
- X insw (nec+ne_data, (u_short *)&ns->ns_pb,
- X len / 2);
- X if (len & 1)
- X ns->ns_pb[len-1] = inb(nec+ne_data);
- X } else {
- X insb (nec+ne_data, ns->ns_pb, len);
- X }
- X
- X if (!(inb (nec+ds0_isr) & DSIS_RDC)) {
- X printf("neintr: remote dma not done\nflushing...\n");
- X len = 0;
- X while (1) {
- X printf("%d %x\n", len, inb(nec+ne_data));
- X len++;
- X }
- X }
- X
- X /* clear RDC */
- X outb (nec + ds0_isr, DSIS_RDC);
- X
- X outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
- X
- X /* adjust for ether header and checksum */
- X len -= sizeof(struct ether_header) + sizeof(long);
- X
- X /* process packet */
- X neread(ns,(caddr_t)(ns->ns_pb), len);
- X }
- 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(nec+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(nec+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(nec+ds0_rbcr0, 0);
- X outb(nec+ds0_rbcr1, 0);
- X outb(nec+ds0_tcr, DSTC_LB0);
- X outb(nec+ds0_rcr, DSRC_MON);
- X outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
- X outb(nec+ds0_rcr, DSRC_AB);
- X outb(nec+ds0_tcr, 0);
- X }
- X
- X /* Any more to send? */
- X outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
- X nestart(&ns->ns_if);
- X outb (nec+ds_cmd, cmd);
- X outb (nec+ds0_imr, 0xff);
- X
- X /* Still more to do? */
- X isr = inb (nec+ds0_isr);
- X if(isr) goto loop;
- 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_port + 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
- END-of-if_ne.c
- exit
- --
- curt mayer
- curt@toad.com
- 415-387-0217 home
-