📄 if_ns.c
字号:
/* * Copyright (c) 1994 Shantanu Goel * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. *//* * Written 1992,1993 by Donald Becker. * * Copyright 1993 United States Government as represented by the * Director, National Security Agency. This software may be used and * distributed according to the terms of the GNU Public License, * incorporated herein by reference. * * The Author may be reached as becker@super.org or * C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 */#include <ul.h>#include <wd.h>#include <hpp.h>#if NUL > 0 || NWD > 0 || NHPP > 0/* * Generic NS8390 routines. * Derived from the Linux driver by Donald Becker. * * Shantanu Goel (goel@cs.columbia.edu) */#include <sys/types.h>#include <device/device_types.h>#include <device/errno.h>#include <device/io_req.h>#include <device/if_hdr.h>#include <device/if_ether.h>#include <device/net_status.h>#include <device/net_io.h>#include <chips/busses.h>#include <i386/machspl.h>#include <i386/pio.h>#include <i386at/gpl/if_nsreg.h>#define IO_DELAY __asm__ __volatile__ ("outb %al,$0x80")#define outb_p(p, v) { outb(p, v); IO_DELAY; }#define inb_p(p) ({ unsigned char _v; _v = inb(p); IO_DELAY; _v; })#define NSDEBUG#ifdef NSDEBUGint nsdebug = 0;#define DEBUGF(stmt) { if (nsdebug) stmt; }#else#define DEBUGF(stmt)#endifvoid nsxint(struct nssoftc *);void nsrint(struct nssoftc *);void nsxmit(struct nssoftc *, unsigned, int);void nsrxoverrun(struct nssoftc *);/* * Initialize the NIC. * Must be called at splimp(). */voidnsinit(sc) struct nssoftc *sc;{ int port = sc->sc_port, i, rxconfig; int endcfg = sc->sc_word16 ? (0x48 | ENDCFG_WTS) : 0x48; struct ifnet *ifp = &sc->sc_if; /* * Reset the board. */ (*sc->sc_reset)(sc); sc->sc_oactive = 0; sc->sc_txing = 0; sc->sc_timer = 0; sc->sc_tx1 = sc->sc_tx2 = 0; sc->sc_curpg = sc->sc_rxstrtpg; /* * Follow National Semiconductor's recommendations for * initializing the DP83902. */ outb_p(port, E8390_NODMA+E8390_PAGE0+E8390_STOP); /* 0x21 */ outb_p(port + EN0_DCFG, endcfg); /* 0x48 or 0x49 */ /* * Clear remote byte count registers. */ outb_p(port + EN0_RCNTLO, 0); outb_p(port + EN0_RCNTHI, 0); /* * Set to monitor and loopback mode -- this is vital! */ outb_p(port + EN0_RXCR, E8390_RXOFF); /* 0x20 */ outb_p(port + EN0_TXCR, E8390_TXOFF); /* 0x02 */ /* * Set transmit page and receive ring. */ outb_p(port + EN0_TPSR, sc->sc_txstrtpg); outb_p(port + EN0_STARTPG, sc->sc_rxstrtpg); outb_p(port + EN0_BOUNDARY, sc->sc_stoppg - 1); outb_p(port + EN0_STOPPG, sc->sc_stoppg); /* * Clear pending interrupts and mask. */ outb_p(port + EN0_ISR, 0xff); /* * Enable the following interrupts: receive/transmit complete, * receive/transmit error, and Receiver OverWrite. * * Counter overflow and Remote DMA complete are *not* enabled. */ outb_p(port + EN0_IMR, ENISR_RX | ENISR_TX | ENISR_RX_ERR | ENISR_TX_ERR | ENISR_OVER ); /* * Copy station address into 8390 registers. */ outb_p(port, E8390_NODMA + E8390_PAGE1 + E8390_STOP); /* 0x61 */ for (i = 0; i < ETHER_ADDR_LEN; i++) outb_p(port + EN1_PHYS + i, sc->sc_addr[i]); /* * Set up to accept all multicast packets. */ for (i = 0; i < 8; i++) outb_p(port + EN1_MULT + i, 0xff); /* * Initialize CURRent pointer */ outb_p(port + EN1_CURPAG, sc->sc_rxstrtpg); /* * Program command register for page 0. */ outb_p(port, E8390_NODMA + E8390_PAGE0 + E8390_STOP);#if 0 outb_p(port + EN0_ISR, 0xff); outb_p(port + EN0_IMR, ENISR_ALL);#endif outb_p(port + E8390_CMD, E8390_NODMA + E8390_PAGE0 + E8390_START); outb_p(port + EN0_TXCR, E8390_TXCONFIG); /* xmit on */ /* 3c503 TechMan says rxconfig only after the NIC is started. */ rxconfig = E8390_RXCONFIG; if (ifp->if_flags & IFF_ALLMULTI) rxconfig |= 0x08; if (ifp->if_flags & IFF_PROMISC) rxconfig |= 0x10; outb_p(port + EN0_RXCR, rxconfig); /* rx on */ /* * Mark interface as up and start output. */ ifp->if_flags |= IFF_RUNNING; nsstart(sc);}/* * Start output on interface. * Must be called at splimp(). */voidnsstart(sc) struct nssoftc *sc;{ io_req_t ior; struct ifnet *ifp = &sc->sc_if; /* * Drop packets if interface is down. */ if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { while (1) { IF_DEQUEUE(&ifp->if_snd, ior); if (ior == 0) return; iodone(ior); } } /* * If transmitter is busy, bail out. */ if (sc->sc_oactive) return; /* * Dequeue a packet. */ IF_DEQUEUE(&ifp->if_snd, ior); if (ior == 0) return; /* Mask interrupts from the ethercard. */ outb( sc->sc_port + EN0_IMR, 0x00); if (sc->sc_pingpong) { int count, output_page; if (sc->sc_tx1 == 0) { output_page = sc->sc_txstrtpg; sc->sc_tx1 = count = (*sc->sc_output)(sc, ior->io_count, ior->io_data, sc->sc_txstrtpg); } else if (sc->sc_tx2 == 0) { output_page = sc->sc_txstrtpg + 6; sc->sc_tx2 = count = (*sc->sc_output)(sc, ior->io_count, ior->io_data, output_page); } else { sc->sc_oactive = 1; IF_PREPEND(&ifp->if_snd, ior); return; } DEBUGF({ struct ether_header *eh; eh = (struct ether_header *)ior->io_data; printf("send: %s%d: %x:%x:%x:%x:%x:%x, " "olen %d, len %d\n", sc->sc_name, sc->sc_unit, eh->ether_dhost[0], eh->ether_dhost[1], eh->ether_dhost[2], eh->ether_dhost[3], eh->ether_dhost[4], eh->ether_dhost[5], ior->io_count, count); }); if (!sc->sc_txing) { nsxmit(sc, count, output_page); if (output_page == sc->sc_txstrtpg) sc->sc_tx1 = -1, sc->sc_lasttx = -1; else sc->sc_tx2 = -1, sc->sc_lasttx = -2; } sc->sc_oactive = (sc->sc_tx1 && sc->sc_tx2); } else { int count; count = (*sc->sc_output)(sc, ior->io_count, ior->io_data, sc->sc_txstrtpg); DEBUGF({ struct ether_header *eh; eh = (struct ether_header *)ior->io_data; printf("send: %s%d: %x:%x:%x:%x:%x:%x, " "olen %d, len %d\n", sc->sc_name, sc->sc_unit, eh->ether_dhost[0], eh->ether_dhost[1], eh->ether_dhost[2], eh->ether_dhost[3], eh->ether_dhost[4], eh->ether_dhost[5], ior->io_count, count); }); nsxmit(sc, count, sc->sc_txstrtpg); sc->sc_oactive = 1; } /* reenable 8390 interrupts. */ outb_p(sc->sc_port + EN0_IMR, ENISR_ALL); iodone(ior);}/* * Interrupt routine. * Called by board level driver. */voidnsintr(sc) struct nssoftc *sc;{ int port = sc->sc_port; int interrupts, boguscount = 0; struct ifnet *ifp = &sc->sc_if; if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { DEBUGF(printf("nsintr: %s%d: interface down\n", sc->sc_name, sc->sc_unit)); return; } /* * Change to page 0 and read intr status reg. */ outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE0); while ((interrupts = inb_p(port + EN0_ISR)) != 0 && ++boguscount < 9) { if (interrupts & ENISR_RDC) { /* * Ack meaningless DMA complete. */ outb_p(port + EN0_ISR, ENISR_RDC); } if (interrupts & ENISR_OVER) nsrxoverrun(sc); else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) { nsrint(sc); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -