diff options
Diffstat (limited to 'sys/arch/sparc/dev')
-rw-r--r-- | sys/arch/sparc/dev/if_le.c | 997 | ||||
-rw-r--r-- | sys/arch/sparc/dev/if_lereg.h | 141 | ||||
-rw-r--r-- | sys/arch/sparc/dev/if_levar.h | 91 |
3 files changed, 209 insertions, 1020 deletions
diff --git a/sys/arch/sparc/dev/if_le.c b/sys/arch/sparc/dev/if_le.c index 4f7da131f0f..055e2a31a5c 100644 --- a/sys/arch/sparc/dev/if_le.c +++ b/sys/arch/sparc/dev/if_le.c @@ -1,9 +1,13 @@ -/* $NetBSD: if_le.c,v 1.20 1995/04/12 08:47:21 pk Exp $ */ +/* $NetBSD: if_le.c,v 1.24 1995/12/11 12:43:28 pk Exp $ */ /*- - * Copyright (c) 1982, 1992, 1993 + * Copyright (c) 1995 Charles M. Hannum. All rights reserved. + * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -32,179 +36,104 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)if_le.c 8.2 (Berkeley) 10/30/93 + * @(#)if_le.c 8.2 (Berkeley) 11/16/93 */ #include "bpfilter.h" -/* - * AMD 7990 LANCE - */ #include <sys/param.h> -#include <sys/device.h> #include <sys/systm.h> -#include <sys/kernel.h> #include <sys/mbuf.h> -#include <sys/buf.h> -#include <sys/socket.h> #include <sys/syslog.h> -#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/device.h> #include <sys/malloc.h> -#include <sys/errno.h> - -#include <vm/vm.h> #include <net/if.h> -#include <net/netisr.h> -#include <net/route.h> -#if NBPFILTER > 0 -#include <sys/select.h> -#include <net/bpf.h> -#include <net/bpfdesc.h> -#endif #ifdef INET #include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/in_var.h> -#include <netinet/ip.h> #include <netinet/if_ether.h> #endif -#ifdef NS -#include <netns/ns.h> -#include <netns/ns_if.h> -#endif - -#ifdef APPLETALK -#include <netddp/atalk.h> -#endif - #include <machine/autoconf.h> #include <machine/cpu.h> -#include <machine/pmap.h> -#include <sparc/dev/if_lereg.h> #include <sparc/dev/sbusvar.h> +#include <sparc/dev/dmareg.h> +#include <sparc/dev/dmavar.h> +#include <sparc/dev/if_lereg.h> +#include <sparc/dev/if_levar.h> +#include <dev/ic/am7990reg.h> +#define LE_NEED_BUF_CONTIG +#include <dev/ic/am7990var.h> -/* DVMA address to LANCE address -- the Sbus/MMU will resupply the 0xff */ -#define LANCE_ADDR(x) ((int)(x) & ~0xff000000) - -int ledebug = 0; /* console error messages */ +#define LE_SOFTC(unit) lecd.cd_devs[unit] +#define LE_DELAY(x) DELAY(x) -#ifdef PACKETSTATS -long lexpacketsizes[LEMTU+1]; -long lerpacketsizes[LEMTU+1]; -#endif +int lematch __P((struct device *, void *, void *)); +void leattach __P((struct device *, struct device *, void *)); +int leintr __P((void *)); -/* Per interface statistics */ -/* XXX this should go in something like if_levar.h */ -struct lestats { - long lexints; /* transmitter interrupts */ - long lerints; /* receiver interrupts */ - long lerbufs; /* total buffers received during interrupts */ - long lerhits; /* times current rbuf was full */ - long lerscans; /* rbufs scanned before finding first full */ +struct cfdriver lecd = { + NULL, "le", lematch, leattach, DV_IFNET, sizeof(struct le_softc) }; -/* - * Ethernet software status per interface. - * - * Each interface is referenced by a network interface structure, - * le_if, which the routing code uses to locate the interface. - * This structure contains the output queue for the interface, its address, ... - */ -struct le_softc { - struct device sc_dev; /* base device */ - struct sbusdev sc_sd; /* sbus device */ - struct intrhand sc_ih; /* interrupt vectoring */ - struct evcnt sc_intrcnt; /* # of interrupts, per le */ - struct evcnt sc_errcnt; /* # of errors, per le */ - - struct arpcom sc_ac; /* common Ethernet structures */ -#define sc_if sc_ac.ac_if /* network-visible interface */ -#define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ - volatile struct lereg1 *sc_r1; /* LANCE registers */ - volatile struct lereg2 *sc_r2; /* dual-port RAM */ - int sc_rmd; /* predicted next rmd to process */ - int sc_runt; - int sc_jab; - int sc_merr; - int sc_babl; - int sc_cerr; - int sc_miss; - int sc_xint; - int sc_xown; - int sc_uflo; - int sc_rxlen; - int sc_rxoff; - int sc_txoff; - int sc_busy; - short sc_iflags; - struct lestats sc_lestats; /* per interface statistics */ -}; +integrate void +lewrcsr(sc, port, val) + struct le_softc *sc; + u_int16_t port, val; +{ + register struct lereg1 *ler1 = sc->sc_r1; + ler1->ler1_rap = port; + ler1->ler1_rdp = val; +} -/* autoconfiguration driver */ -void leattach(struct device *, struct device *, void *); -int lematch(struct device *, void *, void *); -struct cfdriver lecd = - { NULL, "le", lematch, leattach, DV_IFNET, sizeof(struct le_softc) }; +integrate u_int16_t +lerdcsr(sc, port) + struct le_softc *sc; + u_int16_t port; +{ + register struct lereg1 *ler1 = sc->sc_r1; + u_int16_t val; -/* Forwards */ -void leattach(struct device *, struct device *, void *); -void lesetladrf(struct le_softc *); -void lereset(struct device *); -int leinit(int); -void lestart(struct ifnet *); -int leintr(void *); -void lexint(struct le_softc *); -void lerint(struct le_softc *); -void leread(struct le_softc *, char *, int); -int leput(char *, struct mbuf *); -struct mbuf *leget(char *, int, int, struct ifnet *); -int leioctl(struct ifnet *, u_long, caddr_t); -void leerror(struct le_softc *, int); -void lererror(struct le_softc *, char *); -void lexerror(struct le_softc *); + ler1->ler1_rap = port; + val = ler1->ler1_rdp; + return (val); +} int -lematch(parent, vcf, aux) +lematch(parent, match, aux) struct device *parent; - void *vcf, *aux; + void *match, *aux; { - struct cfdata *cf = vcf; - register struct confargs *ca = aux; + struct cfdata *cf = match; + struct confargs *ca = aux; register struct romaux *ra = &ca->ca_ra; if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); if (ca->ca_bustype == BUS_SBUS) return (1); + return (probeget(ra->ra_vaddr, 2) != -1); } -/* - * Interface exists: make available by filling in network interface - * record. System will initialize the interface when it is ready - * to accept packets. - */ void -leattach(parent, self, args) - struct device *parent; - struct device *self; - void *args; +leattach(parent, self, aux) + struct device *parent, *self; + void *aux; { - register struct le_softc *sc = (struct le_softc *)self; - register struct confargs *ca = args; - register volatile struct lereg2 *ler2; - struct ifnet *ifp = &sc->sc_if; - register struct bootpath *bp; - register int a, pri; + struct le_softc *sc = (void *)self; + struct confargs *ca = aux; + int pri; + struct bootpath *bp; + u_long laddr; + int dmachild = strncmp(parent->dv_xname, "ledma", 5) == 0; /* XXX the following declarations should be elsewhere */ extern void myetheraddr(u_char *); - extern caddr_t dvma_malloc(size_t); if (ca->ca_ra.ra_nintr != 1) { printf(": expected 1 interrupt, got %d\n", ca->ca_ra.ra_nintr); @@ -212,790 +141,76 @@ leattach(parent, self, args) } pri = ca->ca_ra.ra_intr[0].int_pri; printf(" pri %d", pri); - sc->sc_r1 = (volatile struct lereg1 *) - mapiodev(ca->ca_ra.ra_paddr, sizeof(struct lereg1), ca->ca_bustype); - ler2 = sc->sc_r2 = (volatile struct lereg2 *) - dvma_malloc(sizeof(struct lereg2)); - - myetheraddr(sc->sc_addr); - printf(": hardware address %s\n", ether_sprintf(sc->sc_addr)); - /* - * Setup for transmit/receive - * - * According to Van, some versions of the Lance only use this - * address to receive packets; it doesn't put them in - * output packets. We'll want to make sure that lestart() - * installs the address. - */ - ler2->ler2_padr[0] = sc->sc_addr[1]; - ler2->ler2_padr[1] = sc->sc_addr[0]; - ler2->ler2_padr[2] = sc->sc_addr[3]; - ler2->ler2_padr[3] = sc->sc_addr[2]; - ler2->ler2_padr[4] = sc->sc_addr[5]; - ler2->ler2_padr[5] = sc->sc_addr[4]; - a = LANCE_ADDR(&ler2->ler2_rmd); - ler2->ler2_rlen = LE_RLEN | (a >> 16); - ler2->ler2_rdra = a; - a = LANCE_ADDR(&ler2->ler2_tmd); - ler2->ler2_tlen = LE_TLEN | (a >> 16); - ler2->ler2_tdra = a; + sc->sc_r1 = (struct lereg1 *)mapiodev(ca->ca_ra.ra_reg, 0, + sizeof(struct lereg1), + ca->ca_bustype); + sc->sc_conf3 = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON; + laddr = (u_long)dvma_malloc(MEMSIZE, &sc->sc_mem, M_NOWAIT); +#if defined (SUN4M) + if ((laddr & 0xffffff) >= (laddr & 0xffffff) + MEMSIZE) + panic("if_le: Lance buffer crosses 16MB boundary"); +#endif + sc->sc_addr = laddr & 0xffffff; + sc->sc_memsize = MEMSIZE; - /* - * Link into sbus, and establish interrupt handler. - */ - sc->sc_sd.sd_reset = lereset; -#if defined(SUN4C) || defined(SUN4M) - if (ca->ca_bustype==BUS_SBUS) - sbus_establish(&sc->sc_sd, &sc->sc_dev); -#endif /* SUN4C || SUN4M */ + myetheraddr(sc->sc_arpcom.ac_enaddr); - sc->sc_ih.ih_fun = leintr; - sc->sc_ih.ih_arg = sc; - intr_establish(pri, &sc->sc_ih); + sc->sc_copytodesc = copytobuf_contig; + sc->sc_copyfromdesc = copyfrombuf_contig; + sc->sc_copytobuf = copytobuf_contig; + sc->sc_copyfrombuf = copyfrombuf_contig; + sc->sc_zerobuf = zerobuf_contig; - /* - * Set up event counters. - */ - evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt); - evcnt_attach(&sc->sc_dev, "errs", &sc->sc_errcnt); - - ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = "le"; - ifp->if_ioctl = leioctl; - ifp->if_start = lestart; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; -#ifdef IFF_NOTRAILERS - /* XXX still compile when the blasted things are gone... */ - ifp->if_flags |= IFF_NOTRAILERS; -#endif -#if NBPFILTER > 0 - bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); -#endif - if_attach(ifp); - ether_ifattach(ifp); + sc->sc_arpcom.ac_if.if_name = lecd.cd_name; + leconfig(sc); + bp = ca->ca_ra.ra_bp; + switch (ca->ca_bustype) { +#if defined(SUN4C) || defined(SUN4M) #define SAME_LANCE(bp, ca) \ ((bp->val[0] == ca->ca_slot && bp->val[1] == ca->ca_offset) || \ (bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit)) - bp = ca->ca_ra.ra_bp; - switch (ca->ca_bustype) { case BUS_SBUS: - if (bp != NULL && strcmp(bp->name, "le") == 0 && + sc->sc_sd.sd_reset = (void *)lereset; + if (dmachild) { +#ifdef notyet + sc->sc_dma = (struct dma_softc *)parent; + sc->sc_dma->sc_le = sc; + sc->sc_dma->sc_regs->en_bar = laddr & 0xff000000; + sbus_establish(&sc->sc_sd, parent); +#endif + } else { + sc->sc_dma = NULL; + sbus_establish(&sc->sc_sd, &sc->sc_dev); + } + + if (bp != NULL && strcmp(bp->name, lecd.cd_name) == 0 && SAME_LANCE(bp, ca)) bootdv = &sc->sc_dev; break; +#endif /* SUN4C || SUN4M */ + default: - if (bp != NULL && strcmp(bp->name, "le") == 0 && + if (bp != NULL && strcmp(bp->name, lecd.cd_name) == 0 && sc->sc_dev.dv_unit == bp->val[1]) bootdv = &sc->sc_dev; break; } -} - -/* - * Setup the logical address filter - */ -void -lesetladrf(sc) - register struct le_softc *sc; -{ - register volatile struct lereg2 *ler2 = sc->sc_r2; - register struct ifnet *ifp = &sc->sc_if; - register struct ether_multi *enm; - register u_char *cp, c; - register u_long crc; - register int i, len; - struct ether_multistep step; - - /* - * Set up multicast address filter by passing all multicast - * addresses through a crc generator, and then using the high - * order 6 bits as a index into the 64 bit logical address - * filter. The high order two bits select the word, while the - * rest of the bits select the bit within the word. - */ - ler2->ler2_ladrf[0] = 0; - ler2->ler2_ladrf[1] = 0; - ler2->ler2_ladrf[2] = 0; - ler2->ler2_ladrf[3] = 0; - ifp->if_flags &= ~IFF_ALLMULTI; - ETHER_FIRST_MULTI(step, &sc->sc_ac, enm); - while (enm != NULL) { - if (bcmp((caddr_t)&enm->enm_addrlo, - (caddr_t)&enm->enm_addrhi, sizeof(enm->enm_addrlo)) != 0) { - /* - * We must listen to a range of multicast - * addresses. For now, just accept all - * multicasts, rather than trying to set only - * those filter bits needed to match the range. - * (At this time, the only use of address - * ranges is for IP multicast routing, for - * which the range is big enough to require all - * bits set.) - */ - ler2->ler2_ladrf[0] = 0xffff; - ler2->ler2_ladrf[1] = 0xffff; - ler2->ler2_ladrf[2] = 0xffff; - ler2->ler2_ladrf[3] = 0xffff; - ifp->if_flags |= IFF_ALLMULTI; - return; - } - - /* - * One would think, given the AM7990 document's polynomial - * of 0x04c11db6, that this should be 0x6db88320 (the bit - * reversal of the AMD value), but that is not right. See - * the BASIC listing: bit 0 (our bit 31) must then be set. - */ - cp = (unsigned char *)&enm->enm_addrlo; - crc = 0xffffffff; - for (len = 6; --len >= 0;) { - c = *cp++; - for (i = 0; i < 8; i++) { - if ((c & 0x01) ^ (crc & 0x01)) { - crc >>= 1; - crc = crc ^ 0xedb88320; - } else - crc >>= 1; - c >>= 1; - } - } - /* Just want the 6 most significant bits. */ - crc = crc >> 26; - - /* Turn on the corresponding bit in the filter. */ - ler2->ler2_ladrf[crc >> 4] |= 1 << (crc & 0xf); - - ETHER_NEXT_MULTI(step, enm); - } -} - -void -lereset(dev) - struct device *dev; -{ - register struct le_softc *sc = (struct le_softc *)dev; - register volatile struct lereg1 *ler1 = sc->sc_r1; - register volatile struct lereg2 *ler2 = sc->sc_r2; - register int i, a, timo, stat; - -#if NBPFILTER > 0 - if (sc->sc_if.if_flags & IFF_PROMISC) - ler2->ler2_mode = LE_MODE_NORMAL | LE_MODE_PROM; - else -#endif - ler2->ler2_mode = LE_MODE_NORMAL; - ler1->ler1_rap = LE_CSR0; - ler1->ler1_rdp = LE_C0_STOP; - - /* Setup the logical address filter */ - lesetladrf(sc); - - /* init receive and transmit rings */ - for (i = 0; i < LERBUF; i++) { - a = LANCE_ADDR(&ler2->ler2_rbuf[i][0]); - ler2->ler2_rmd[i].rmd0 = a; - ler2->ler2_rmd[i].rmd1_hadr = a >> 16; - ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN; - ler2->ler2_rmd[i].rmd2 = -LEMTU | LE_XMD2_ONES; - ler2->ler2_rmd[i].rmd3 = 0; - } - for (i = 0; i < LETBUF; i++) { - a = LANCE_ADDR(&ler2->ler2_tbuf[i][0]); - ler2->ler2_tmd[i].tmd0 = a; - ler2->ler2_tmd[i].tmd1_hadr = a >> 16; - ler2->ler2_tmd[i].tmd1_bits = 0; - ler2->ler2_tmd[i].tmd2 = LE_XMD2_ONES; - ler2->ler2_tmd[i].tmd3 = 0; - } - - bzero((void *)&ler2->ler2_rbuf[0][0], (LERBUF + LETBUF) * LEMTU); - /* lance will stuff packet into receive buffer 0 next */ - sc->sc_rmd = 0; - - /* tell the chip where to find the initialization block */ - a = LANCE_ADDR(&ler2->ler2_mode); - ler1->ler1_rap = LE_CSR1; - ler1->ler1_rdp = a; - ler1->ler1_rap = LE_CSR2; - ler1->ler1_rdp = a >> 16; - ler1->ler1_rap = LE_CSR3; - ler1->ler1_rdp = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON; - ler1->ler1_rap = LE_CSR0; - ler1->ler1_rdp = LE_C0_INIT; - timo = 100000; - while (((stat = ler1->ler1_rdp) & (LE_C0_ERR | LE_C0_IDON)) == 0) { - if (--timo == 0) { - printf("%s: init timeout, stat=%b\n", - sc->sc_dev.dv_xname, stat, LE_C0_BITS); - break; - } - } - if (stat & LE_C0_ERR) - printf("%s: init failed, stat=%b\n", - sc->sc_dev.dv_xname, stat, LE_C0_BITS); - else - ler1->ler1_rdp = LE_C0_IDON; /* clear IDON */ - ler1->ler1_rdp = LE_C0_STRT | LE_C0_INEA; - sc->sc_if.if_flags &= ~IFF_OACTIVE; -} - -/* - * Initialization of interface - */ -int -leinit(unit) - int unit; -{ - register struct le_softc *sc = lecd.cd_devs[unit]; - register struct ifnet *ifp = &sc->sc_if; - register int s; - - if ((ifp->if_flags & IFF_RUNNING) == 0) { - s = splimp(); - ifp->if_flags |= IFF_RUNNING; - lereset(&sc->sc_dev); - lestart(ifp); - splx(s); - } - return (0); -} - -/* - * Start output on interface. Get another datagram to send - * off of the interface queue, and copy it to the interface - * before starting the output. - */ -void -lestart(ifp) - register struct ifnet *ifp; -{ - register struct le_softc *sc = lecd.cd_devs[ifp->if_unit]; - register volatile struct letmd *tmd; - register struct mbuf *m; - register int len; - - if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) - return; - IF_DEQUEUE(&sc->sc_if.if_snd, m); - if (m == 0) - return; - len = leput((char *)sc->sc_r2->ler2_tbuf[0], m); -#if NBPFILTER > 0 - /* - * If bpf is listening on this interface, let it - * see the packet before we commit it to the wire. - */ - if (sc->sc_if.if_bpf) - bpf_tap(sc->sc_if.if_bpf, (u_char *)sc->sc_r2->ler2_tbuf[0], len); -#endif - -#ifdef PACKETSTATS - if (len <= LEMTU) - lexpacketsizes[len]++; -#endif - tmd = sc->sc_r2->ler2_tmd; - tmd->tmd3 = 0; - tmd->tmd2 = -len | LE_XMD2_ONES; - tmd->tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP; - sc->sc_if.if_flags |= IFF_OACTIVE; - return; -} - -int -leintr(dev) - register void *dev; -{ - register struct le_softc *sc = dev; - register volatile struct lereg1 *ler1 = sc->sc_r1; - register int csr0; - - csr0 = ler1->ler1_rdp; - if ((csr0 & LE_C0_INTR) == 0) - return (0); - sc->sc_intrcnt.ev_count++; - - if (csr0 & LE_C0_ERR) { - sc->sc_errcnt.ev_count++; - leerror(sc, csr0); - if (csr0 & LE_C0_MERR) { - sc->sc_merr++; - lereset(&sc->sc_dev); - return (1); - } - if (csr0 & LE_C0_BABL) - sc->sc_babl++; - if (csr0 & LE_C0_CERR) - sc->sc_cerr++; - if (csr0 & LE_C0_MISS) - sc->sc_miss++; - ler1->ler1_rdp = LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_INEA; - } - if ((csr0 & LE_C0_RXON) == 0) { - sc->sc_rxoff++; - lereset(&sc->sc_dev); - return (1); - } - if ((csr0 & LE_C0_TXON) == 0) { - sc->sc_txoff++; - lereset(&sc->sc_dev); - return (1); - } - if (csr0 & LE_C0_RINT) { - /* interrupt is cleared in lerint */ - lerint(sc); - } - if (csr0 & LE_C0_TINT) { - ler1->ler1_rdp = LE_C0_TINT|LE_C0_INEA; - lexint(sc); - } - return (1); -} - -/* - * Ethernet interface transmitter interrupt. - * Start another output if more data to send. - */ -void -lexint(sc) - register struct le_softc *sc; -{ - register volatile struct letmd *tmd = sc->sc_r2->ler2_tmd; - - sc->sc_lestats.lexints++; - if ((sc->sc_if.if_flags & IFF_OACTIVE) == 0) { - sc->sc_xint++; - return; - } - if (tmd->tmd1_bits & LE_T1_OWN) { - sc->sc_xown++; - return; - } - if (tmd->tmd1_bits & LE_T1_ERR) { -err: - lexerror(sc); - sc->sc_if.if_oerrors++; - if (tmd->tmd3 & (LE_T3_BUFF|LE_T3_UFLO)) { - sc->sc_uflo++; - lereset(&sc->sc_dev); - } else if (tmd->tmd3 & LE_T3_LCOL) - sc->sc_if.if_collisions++; - else if (tmd->tmd3 & LE_T3_RTRY) - sc->sc_if.if_collisions += 16; - } - else if (tmd->tmd3 & LE_T3_BUFF) - /* XXX documentation says BUFF not included in ERR */ - goto err; - else if (tmd->tmd1_bits & LE_T1_ONE) - sc->sc_if.if_collisions++; - else if (tmd->tmd1_bits & LE_T1_MORE) - /* what is the real number? */ - sc->sc_if.if_collisions += 2; - else - sc->sc_if.if_opackets++; - sc->sc_if.if_flags &= ~IFF_OACTIVE; - lestart(&sc->sc_if); -} - -#define LENEXTRMP \ - if (++bix == LERBUF) bix = 0, rmd = sc->sc_r2->ler2_rmd; else ++rmd - -/* - * Ethernet interface receiver interrupt. - * If input error just drop packet. - * Decapsulate packet based on type and pass to type specific - * higher-level input routine. - */ -void -lerint(sc) - register struct le_softc *sc; -{ - register int bix = sc->sc_rmd; - register volatile struct lermd *rmd = &sc->sc_r2->ler2_rmd[bix]; - - sc->sc_lestats.lerints++; - /* - * Out of sync with hardware, should never happen? - */ - if (rmd->rmd1_bits & LE_R1_OWN) { - do { - sc->sc_lestats.lerscans++; - LENEXTRMP; - } while ((rmd->rmd1_bits & LE_R1_OWN) && bix != sc->sc_rmd); - if (bix == sc->sc_rmd) - printf("%s: RINT with no buffer\n", - sc->sc_dev.dv_xname); - } else - sc->sc_lestats.lerhits++; - - /* - * Process all buffers with valid data - */ - while ((rmd->rmd1_bits & LE_R1_OWN) == 0) { - int len = rmd->rmd3; - - /* Clear interrupt to avoid race condition */ - sc->sc_r1->ler1_rdp = LE_C0_RINT|LE_C0_INEA; - - if (rmd->rmd1_bits & LE_R1_ERR) { - sc->sc_rmd = bix; - lererror(sc, "bad packet"); - sc->sc_if.if_ierrors++; - } else if ((rmd->rmd1_bits & (LE_R1_STP|LE_R1_ENP)) != - (LE_R1_STP|LE_R1_ENP)) { - /* XXX make a define for LE_R1_STP|LE_R1_ENP? */ - /* - * Find the end of the packet so we can see how long - * it was. We still throw it away. - */ - do { - sc->sc_r1->ler1_rdp = LE_C0_RINT|LE_C0_INEA; - rmd->rmd3 = 0; - rmd->rmd1_bits = LE_R1_OWN; - LENEXTRMP; - } while (!(rmd->rmd1_bits & - (LE_R1_OWN|LE_R1_ERR|LE_R1_STP|LE_R1_ENP))); - sc->sc_rmd = bix; - lererror(sc, "chained buffer"); - sc->sc_rxlen++; - /* - * If search terminated without successful completion - * we reset the hardware (conservative). - */ - if ((rmd->rmd1_bits & - (LE_R1_OWN|LE_R1_ERR|LE_R1_STP|LE_R1_ENP)) != - LE_R1_ENP) { - lereset(&sc->sc_dev); - return; - } - } else { - leread(sc, (char *)sc->sc_r2->ler2_rbuf[bix], len); -#ifdef PACKETSTATS - lerpacketsizes[len]++; -#endif - sc->sc_lestats.lerbufs++; - } - rmd->rmd3 = 0; - rmd->rmd1_bits = LE_R1_OWN; - LENEXTRMP; - } - sc->sc_rmd = bix; -} - -void -leread(sc, pkt, len) - register struct le_softc *sc; - char *pkt; - int len; -{ - register struct ether_header *et; - register struct ifnet *ifp = &sc->sc_if; - struct mbuf *m; - struct ifqueue *inq; - int flags; - - ifp->if_ipackets++; - et = (struct ether_header *)pkt; - et->ether_type = ntohs((u_short)et->ether_type); - /* adjust input length to account for header and CRC */ - len -= sizeof(struct ether_header) + 4; - - if (len <= 0) { - if (ledebug) - log(LOG_WARNING, - "%s: ierror(runt packet): from %s: len=%d\n", - sc->sc_dev.dv_xname, - ether_sprintf(et->ether_shost), len); - sc->sc_runt++; - ifp->if_ierrors++; - return; - } - - /* Setup mbuf flags we'll need later */ - flags = 0; - if (bcmp((caddr_t)etherbroadcastaddr, - (caddr_t)et->ether_dhost, sizeof(etherbroadcastaddr)) == 0) - flags |= M_BCAST; - if (et->ether_dhost[0] & 1) - flags |= M_MCAST; - -#if NBPFILTER > 0 - /* - * Check if there's a bpf filter listening on this interface. - * If so, hand off the raw packet to enet, then discard things - * not destined for us (but be sure to keep broadcast/multicast). - */ - if (sc->sc_if.if_bpf) { - bpf_tap(sc->sc_if.if_bpf, pkt, - len + sizeof(struct ether_header)); - if ((flags & (M_BCAST | M_MCAST)) == 0 && - bcmp(et->ether_dhost, sc->sc_addr, - sizeof(et->ether_dhost)) != 0) - return; - } -#endif - m = leget(pkt, len, 0, ifp); - if (m == 0) - return; - ether_input(ifp, et, m); -} - -/* - * Routine to copy from mbuf chain to transmit - * buffer in board local memory. - * - * ### this can be done by remapping in some cases - */ -int -leput(lebuf, m) - register char *lebuf; - register struct mbuf *m; -{ - register struct mbuf *mp; - register int len, tlen = 0; - - for (mp = m; mp; mp = mp->m_next) { - len = mp->m_len; - if (len == 0) - continue; - tlen += len; - bcopy(mtod(mp, char *), lebuf, len); - lebuf += len; - } - m_freem(m); - if (tlen < LEMINSIZE) { - bzero(lebuf, LEMINSIZE - tlen); - tlen = LEMINSIZE; - } - return (tlen); -} - -/* - * Routine to copy from board local memory into mbufs. - */ -struct mbuf * -leget(lebuf, totlen, off0, ifp) - char *lebuf; - int totlen, off0; - struct ifnet *ifp; -{ - register struct mbuf *m; - struct mbuf *top = 0, **mp = ⊤ - register int off = off0, len; - register char *cp; - char *epkt; - - lebuf += sizeof(struct ether_header); - cp = lebuf; - epkt = cp + totlen; - if (off) { - cp += off + 2 * sizeof(u_short); - totlen -= 2 * sizeof(u_short); - } - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == 0) - return (0); - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = totlen; - m->m_len = MHLEN; - - while (totlen > 0) { - if (top) { - MGET(m, M_DONTWAIT, MT_DATA); - if (m == 0) { - m_freem(top); - return (0); - } - m->m_len = MLEN; - } - len = min(totlen, epkt - cp); - if (len >= MINCLSIZE) { - MCLGET(m, M_DONTWAIT); - if (m->m_flags & M_EXT) - m->m_len = len = min(len, MCLBYTES); - else - len = m->m_len; - } else { - /* - * Place initial small packet/header at end of mbuf. - */ - if (len < m->m_len) { - if (top == 0 && len + max_linkhdr <= m->m_len) - m->m_data += max_linkhdr; - m->m_len = len; - } else - len = m->m_len; - } - bcopy(cp, mtod(m, caddr_t), (unsigned)len); - cp += len; - *mp = m; - mp = &m->m_next; - totlen -= len; - if (cp == epkt) - cp = lebuf; - } - return (top); -} - -/* - * Process an ioctl request. - */ -int -leioctl(ifp, cmd, data) - register struct ifnet *ifp; - u_long cmd; - caddr_t data; -{ - register struct ifaddr *ifa; - register struct le_softc *sc = lecd.cd_devs[ifp->if_unit]; - register volatile struct lereg1 *ler1; - int s = splimp(), error = 0; - - switch (cmd) { - - case SIOCSIFADDR: - ifa = (struct ifaddr *)data; - ifp->if_flags |= IFF_UP; - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: - (void)leinit(ifp->if_unit); - arp_ifinit(&sc->sc_ac, ifa); - break; -#endif -#ifdef NS - case AF_NS: - { - register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); - - if (ns_nullhost(*ina)) - ina->x_host = *(union ns_host *)(sc->sc_addr); - else { - /* - * The manual says we can't change the address - * while the receiver is armed, - * so reset everything - */ - ifp->if_flags &= ~IFF_RUNNING; - bcopy((caddr_t)ina->x_host.c_host, - (caddr_t)sc->sc_addr, sizeof(sc->sc_addr)); - } - (void)leinit(ifp->if_unit); /* does le_setaddr() */ - break; - } + sc->sc_ih.ih_fun = leintr; +#if defined(SUN4M) && 0 + if (cputyp == CPU_SUN4M) + sc->sc_ih.ih_fun = myleintr; #endif - default: - (void)leinit(ifp->if_unit); - break; - } - break; - - case SIOCSIFFLAGS: - ler1 = sc->sc_r1; - if ((ifp->if_flags & IFF_UP) == 0 && - ifp->if_flags & IFF_RUNNING) { - ler1->ler1_rdp = LE_C0_STOP; - ifp->if_flags &= ~IFF_RUNNING; - } else if (ifp->if_flags & IFF_UP && - (ifp->if_flags & IFF_RUNNING) == 0) - (void)leinit(ifp->if_unit); - /* - * If the state of the promiscuous bit changes, the interface - * must be reset to effect the change. - */ - if (((ifp->if_flags ^ sc->sc_iflags) & IFF_PROMISC) && - (ifp->if_flags & IFF_RUNNING)) { - sc->sc_iflags = ifp->if_flags; - lereset(&sc->sc_dev); - lestart(ifp); - } - break; - - case SIOCADDMULTI: - error = ether_addmulti((struct ifreq *)data, &sc->sc_ac); - goto update_multicast; - - case SIOCDELMULTI: - error = ether_delmulti((struct ifreq *)data, &sc->sc_ac); - update_multicast: - if (error == ENETRESET) { - /* - * Multicast list has changed; set the hardware - * filter accordingly. - */ - lereset(&sc->sc_dev); - error = 0; - } - break; + sc->sc_ih.ih_arg = sc; + intr_establish(pri, &sc->sc_ih); - default: - error = EINVAL; + /* now initialize DMA */ + if (sc->sc_dma) { + dmaenintr(sc->sc_dma); } - splx(s); - return (error); -} - -void -leerror(sc, stat) - register struct le_softc *sc; - int stat; -{ - if (!ledebug) - return; - - /* - * Not all transceivers implement heartbeat - * so we only log CERR once. - */ - if ((stat & LE_C0_CERR) && sc->sc_cerr) - return; - log(LOG_WARNING, "%s: error: stat=%b\n", - sc->sc_dev.dv_xname, stat, LE_C0_BITS); } -void -lererror(sc, msg) - register struct le_softc *sc; - char *msg; -{ - register volatile struct lermd *rmd; - int len; - - if (!ledebug) - return; - - rmd = &sc->sc_r2->ler2_rmd[sc->sc_rmd]; - len = rmd->rmd3; - log(LOG_WARNING, "%s: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", - sc->sc_dev.dv_xname, msg, len > 11 ? - ether_sprintf((u_char *)&sc->sc_r2->ler2_rbuf[sc->sc_rmd][6]) : - "unknown", - sc->sc_rmd, len, rmd->rmd1_bits, LE_R1_BITS); -} - -void -lexerror(sc) - register struct le_softc *sc; -{ - register volatile struct letmd *tmd; - register int len, tmd3, tdr; - - if (!ledebug) - return; - - tmd = sc->sc_r2->ler2_tmd; - tmd3 = tmd->tmd3; - tdr = tmd3 & LE_T3_TDR_MASK; - len = -(tmd->tmd2 & ~LE_XMD2_ONES); - log(LOG_WARNING, - "%s: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b, tdr=%d (%d nsecs)\n", - sc->sc_dev.dv_xname, len > 5 ? - ether_sprintf((u_char *)&sc->sc_r2->ler2_tbuf[0][0]) : "unknown", - 0, len, - tmd->tmd1_bits, LE_T1_BITS, - tmd3, LE_T3_BITS, tdr, tdr * 100); -} +#include <dev/ic/am7990.c> diff --git a/sys/arch/sparc/dev/if_lereg.h b/sys/arch/sparc/dev/if_lereg.h index ae4f7626fd2..5035566a439 100644 --- a/sys/arch/sparc/dev/if_lereg.h +++ b/sys/arch/sparc/dev/if_lereg.h @@ -1,9 +1,13 @@ -/* $NetBSD: if_lereg.h,v 1.4 1994/11/20 20:52:22 deraadt Exp $ */ +/* $NetBSD: if_lereg.h,v 1.5 1995/12/10 10:15:07 mycroft Exp $ */ /*- - * Copyright (c) 1982, 1992, 1993 + * Copyright (c) 1995 Charles M. Hannum. All rights reserved. + * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -32,136 +36,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)if_lereg.h 8.2 (Berkeley) 10/30/93 + * @(#)if_le.c 8.2 (Berkeley) 11/16/93 */ -#define LEMTU 1518 -#define LEMINSIZE 60 /* should be 64 if mode DTCR is set */ -#define LERBUF 8 -#define LERBUFLOG2 3 -#define LE_RLEN (LERBUFLOG2 << 13) -#define LETBUF 1 -#define LETBUFLOG2 0 -#define LE_TLEN (LETBUFLOG2 << 13) - -/* Local Area Network Controller for Ethernet (LANCE) registers */ -struct lereg1 { - u_short ler1_rdp; /* register data port */ - u_short ler1_rap; /* register address port */ -}; - -/* register addresses */ -#define LE_CSR0 0 /* Control and status register */ -#define LE_CSR1 1 /* low address of init block */ -#define LE_CSR2 2 /* high address of init block */ -#define LE_CSR3 3 /* Bus master and control */ +#define MEMSIZE 0x4000 -/* Control and status register 0 (csr0) */ -#define LE_C0_ERR 0x8000 /* error summary */ -#define LE_C0_BABL 0x4000 /* transmitter timeout error */ -#define LE_C0_CERR 0x2000 /* collision */ -#define LE_C0_MISS 0x1000 /* missed a packet */ -#define LE_C0_MERR 0x0800 /* memory error */ -#define LE_C0_RINT 0x0400 /* receiver interrupt */ -#define LE_C0_TINT 0x0200 /* transmitter interrupt */ -#define LE_C0_IDON 0x0100 /* initalization done */ -#define LE_C0_INTR 0x0080 /* interrupt condition */ -#define LE_C0_INEA 0x0040 /* interrupt enable */ -#define LE_C0_RXON 0x0020 /* receiver on */ -#define LE_C0_TXON 0x0010 /* transmitter on */ -#define LE_C0_TDMD 0x0008 /* transmit demand */ -#define LE_C0_STOP 0x0004 /* disable all external activity */ -#define LE_C0_STRT 0x0002 /* enable external activity */ -#define LE_C0_INIT 0x0001 /* begin initalization */ - -#define LE_C0_BITS \ - "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\ -\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT" - -/* Control and status register 3 (csr3) */ -#define LE_C3_BSWP 0x4 /* byte swap */ -#define LE_C3_ACON 0x2 /* ALE control, eh? */ -#define LE_C3_BCON 0x1 /* byte control */ /* - * Current size is 13,758 bytes with 8 x 1518 receive buffers and - * 1 x 1518 transmit buffer. + * LANCE registers. */ -struct lereg2 { - /* initialization block */ - u_short ler2_mode; /* mode */ - u_char ler2_padr[6]; /* physical address */ - u_short ler2_ladrf[4]; /* logical address filter */ - u_short ler2_rdra; /* receive descriptor addr */ - u_short ler2_rlen; /* rda high and ring size */ - u_short ler2_tdra; /* transmit descriptor addr */ - u_short ler2_tlen; /* tda high and ring size */ - /* receive message descriptors. bits/hadr are byte order dependent. */ - struct lermd { - u_short rmd0; /* low address of packet */ - u_char rmd1_bits; /* descriptor bits */ - u_char rmd1_hadr; /* high address of packet */ - short rmd2; /* buffer byte count */ - u_short rmd3; /* message byte count */ - } ler2_rmd[LERBUF]; - /* transmit message descriptors */ - struct letmd { - u_short tmd0; /* low address of packet */ - u_char tmd1_bits; /* descriptor bits */ - u_char tmd1_hadr; /* high address of packet */ - short tmd2; /* buffer byte count */ - u_short tmd3; /* transmit error bits */ - } ler2_tmd[LETBUF]; - char ler2_rbuf[LERBUF][LEMTU]; - char ler2_tbuf[LETBUF][LEMTU]; +struct lereg1 { + volatile u_int16_t ler1_rdp; /* data port */ + volatile u_int16_t ler1_rap; /* register select port */ }; - -/* Initialzation block (mode) */ -#define LE_MODE_PROM 0x8000 /* promiscuous mode */ -/* 0x7f80 reserved, must be zero */ -#define LE_MODE_INTL 0x0040 /* internal loopback */ -#define LE_MODE_DRTY 0x0020 /* disable retry */ -#define LE_MODE_COLL 0x0010 /* force a collision */ -#define LE_MODE_DTCR 0x0008 /* disable transmit CRC */ -#define LE_MODE_LOOP 0x0004 /* loopback mode */ -#define LE_MODE_DTX 0x0002 /* disable transmitter */ -#define LE_MODE_DRX 0x0001 /* disable receiver */ -#define LE_MODE_NORMAL 0 /* none of the above */ - - -/* Receive message descriptor 1 (rmd1_bits) */ -#define LE_R1_OWN 0x80 /* LANCE owns the packet */ -#define LE_R1_ERR 0x40 /* error summary */ -#define LE_R1_FRAM 0x20 /* framing error */ -#define LE_R1_OFLO 0x10 /* overflow error */ -#define LE_R1_CRC 0x08 /* CRC error */ -#define LE_R1_BUFF 0x04 /* buffer error */ -#define LE_R1_STP 0x02 /* start of packet */ -#define LE_R1_ENP 0x01 /* end of packet */ - -#define LE_R1_BITS \ - "\20\10OWN\7ERR\6FRAM\5OFLO\4CRC\3BUFF\2STP\1ENP" - -/* Transmit message descriptor 1 (tmd1_bits) */ -#define LE_T1_OWN 0x80 /* LANCE owns the packet */ -#define LE_T1_ERR 0x40 /* error summary */ -#define LE_T1_MORE 0x10 /* multiple collisions */ -#define LE_T1_ONE 0x08 /* single collision */ -#define LE_T1_DEF 0x04 /* defferred transmit */ -#define LE_T1_STP 0x02 /* start of packet */ -#define LE_T1_ENP 0x01 /* end of packet */ - -#define LE_T1_BITS \ - "\20\10OWN\7ERR\6RES\5MORE\4ONE\3DEF\2STP\1ENP" - -/* Transmit message descriptor 3 (tmd3) */ -#define LE_T3_BUFF 0x8000 /* buffer error */ -#define LE_T3_UFLO 0x4000 /* underflow error */ -#define LE_T3_LCOL 0x1000 /* late collision */ -#define LE_T3_LCAR 0x0800 /* loss of carrier */ -#define LE_T3_RTRY 0x0400 /* retry error */ -#define LE_T3_TDR_MASK 0x03ff /* time domain reflectometry counter */ - -#define LE_XMD2_ONES 0xf000 - -#define LE_T3_BITS \ - "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY" diff --git a/sys/arch/sparc/dev/if_levar.h b/sys/arch/sparc/dev/if_levar.h new file mode 100644 index 00000000000..7361c4eae7a --- /dev/null +++ b/sys/arch/sparc/dev/if_levar.h @@ -0,0 +1,91 @@ +/* $NetBSD: if_levar.h,v 1.2 1995/12/11 12:43:29 pk Exp $ */ + +/*- + * Copyright (c) 1995 Charles M. Hannum. All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_le.c 8.2 (Berkeley) 11/16/93 + */ + +/* + * Ethernet software status per interface. + * + * Each interface is referenced by a network interface structure, + * arpcom.ac_if, which the routing code uses to locate the interface. + * This structure contains the output queue for the interface, its address, ... + */ +struct le_softc { + struct device sc_dev; /* base structure */ + struct arpcom sc_arpcom; /* Ethernet common part */ + + void (*sc_copytodesc)(); /* Copy to descriptor */ + void (*sc_copyfromdesc)(); /* Copy from descriptor */ + + void (*sc_copytobuf)(); /* Copy to buffer */ + void (*sc_copyfrombuf)(); /* Copy from buffer */ + void (*sc_zerobuf)(); /* and Zero bytes in buffer */ + + u_int16_t sc_conf3; /* CSR3 value */ + + void *sc_mem; /* base address of RAM -- CPU's view */ + u_long sc_addr; /* base address of RAM -- LANCE's view */ + u_long sc_memsize; /* size of RAM */ + + int sc_nrbuf; /* number of receive buffers */ + int sc_ntbuf; /* number of transmit buffers */ + int sc_last_rd; + int sc_first_td, sc_last_td, sc_no_td; + + int sc_initaddr; + int sc_rmdaddr; + int sc_tmdaddr; + int sc_rbufaddr; + int sc_tbufaddr; + +#ifdef LEDEBUG + int sc_debug; +#endif + + struct sbusdev sc_sd; /* sbus device */ + struct intrhand sc_ih; /* interrupt vectoring */ + struct lereg1 *sc_r1; /* LANCE registers */ + struct dma_softc *sc_dma; /* pointer to my dma */ +}; + +/* DMA macros for ledma */ +#define DMA_ENINTR(r) ((r->enintr)(r)) +#define DMA_ISINTR(r) ((r->isintr)(r)) +#define DMA_RESET(r) ((r->reset)(r)) + |