-/* $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:
* 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);
}
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>
-/* $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:
* 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"