-/* $OpenBSD: if_le.c,v 1.6 1996/05/06 21:53:39 deraadt Exp $ */
+/* $OpenBSD: if_le.c,v 1.7 1996/05/10 12:42:24 deraadt Exp $ */
/*-
* Copyright (c) 1982, 1992, 1993
#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
-#include <machine/cpu.h>
#include <machine/autoconf.h>
-#include <machine/pmap.h>
+#include <machine/cpu.h>
+
+#include <dev/ic/am7990reg.h>
+#include <dev/ic/am7990var.h>
#include <mvme68k/dev/if_lereg.h>
+#include <mvme68k/dev/if_levar.h>
#include <mvme68k/dev/pccreg.h>
-/* DVMA address to LANCE address -- the Sbus/MMU will resupply the 0xff */
-#define LANCE_ADDR(x) ((int)x)
-
-int ledebug = 0; /* console error messages */
-
-#ifdef PACKETSTATS
-long lexpacketsizes[LEMTU+1];
-long lerpacketsizes[LEMTU+1];
-#endif
-
-/* 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 */
-};
-
-/*
- * 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 evcnt sc_intrcnt; /* # of interrupts, per le */
- struct evcnt sc_errcnt; /* # of errors, per le */
- struct intrhand sc_ih;
-
- 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 */
- struct lereg1 *sc_r1; /* LANCE registers */
- 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 */
-};
-
-
/* autoconfiguration driver */
void leattach(struct device *, struct device *, void *);
int lematch(struct device *, void *, void *);
-struct cfattach le_ca = {
+struct cfattach le_ca = {
sizeof(struct le_softc), lematch, leattach
};
-struct cfdriver le_cd = {
- NULL, "le", DV_IFNET, 0
-};
+hide void lewrcsr __P((struct am7990_softc *, u_int16_t, u_int16_t));
+hide u_int16_t lerdcsr __P((struct am7990_softc *, u_int16_t));
+hide void lehwinit __P((struct am7990_softc *));
-/* 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 *);
+hide void
+lewrcsr(sc, port, val)
+ struct am7990_softc *sc;
+ u_int16_t port, val;
+{
+ register struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
+
+ ler1->ler1_rap = port;
+ ler1->ler1_rdp = val;
+}
+
+hide u_int16_t
+lerdcsr(sc, port)
+ struct am7990_softc *sc;
+ u_int16_t port;
+{
+ register struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
+ u_int16_t val;
-extern void *etherbuf;
+ ler1->ler1_rap = port;
+ val = ler1->ler1_rdp;
+ return (val);
+}
+
+hide void
+lehwinit(sc)
+ struct am7990_softc *sc;
+{
+}
int
lematch(parent, vcf, args)
* to accept packets.
*/
void
-leattach(parent, self, args)
+leattach(parent, self, aux)
struct device *parent;
struct device *self;
- void *args;
+ void *aux;
{
- register struct le_softc *sc = (struct le_softc *)self;
- register struct lereg2 *ler2;
- struct ifnet *ifp = &sc->sc_if;
- struct confargs *ca = args;
+ register struct le_softc *lesc = (struct le_softc *)self;
+ struct am7990_softc *sc = &lesc->sc_am7990;
+ struct confargs *ca = aux;
register int a;
int pri = ca->ca_ipl;
+ extern void *etherbuf;
/* XXX the following declarations should be elsewhere */
extern void myetheraddr(u_char *);
+ printf(" pri %d", pri);
+
/* connect the interrupt */
- sc->sc_ih.ih_fn = leintr;
- sc->sc_ih.ih_arg = sc;
- sc->sc_ih.ih_ipl = pri;
- pccintr_establish(PCCV_LE, &sc->sc_ih);
+ lesc->sc_ih.ih_fn = am7990_intr;
+ lesc->sc_ih.ih_arg = sc;
+ lesc->sc_ih.ih_ipl = pri;
+ pccintr_establish(PCCV_LE, &lesc->sc_ih);
- sc->sc_r1 = (struct lereg1 *)ca->ca_vaddr;
+ lesc->sc_r1 = (struct lereg1 *)ca->ca_vaddr;
+ sc->sc_conf3 = LE_C3_BSWP /*| LE_C3_ACON | LE_C3_BCON*/;
+ sc->sc_addr = (u_long)etherbuf;
+ sc->sc_memsize = MEMSIZE;
- ler2 = sc->sc_r2 = (struct lereg2 *) etherbuf;
+ myetheraddr(sc->sc_arpcom.ac_enaddr);
- myetheraddr(sc->sc_addr);
- printf(": address %s\n", ether_sprintf(sc->sc_addr));
+ evcnt_attach(&sc->sc_dev, "intr", &lesc->sc_intrcnt);
+ evcnt_attach(&sc->sc_dev, "errs", &lesc->sc_errcnt);
- /*
- * 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_copytodesc = am7990_copytobuf_contig;
+ sc->sc_copyfromdesc = am7990_copyfrombuf_contig;
+ sc->sc_copytobuf = am7990_copytobuf_contig;
+ sc->sc_copyfrombuf = am7990_copyfrombuf_contig;
+ sc->sc_zerobuf = am7990_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_rdcsr = lerdcsr;
+ sc->sc_wrcsr = lewrcsr;
+ sc->sc_hwinit = lehwinit;
((struct pccreg *)ca->ca_master)->pcc_leirq = pri | PCC_IRQ_IEN;
}
-
-/*
- * Setup the logical address filter
- */
-void
-lesetladrf(sc)
- register struct le_softc *sc;
-{
- register 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 struct lereg1 *ler1 = sc->sc_r1;
- register 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, ler1=0x%x, stat=%b\n",
- sc->sc_dev.dv_xname, ler1, 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 = le_cd.cd_devs[unit];
- register struct ifnet *ifp = &sc->sc_if;
- register int s;
-
- if ((ifp->if_flags & IFF_RUNNING) == 0) {
- s = splnet();
- 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 = le_cd.cd_devs[ifp->if_unit];
- register 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, (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 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 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 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 = le_cd.cd_devs[ifp->if_unit];
- register struct lereg1 *ler1;
- int s = splnet(), error = 0;
-
- if ((error = ether_ioctl(ifp, &sc->sc_ac, cmd, data)) > 0) {
- splx(s);
- return error;
- }
-
- 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
- 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;
-
- default:
- error = EINVAL;
- }
- 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 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 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);
-}
-/* $OpenBSD: if_lereg.h,v 1.3 1996/04/28 11:03:22 deraadt Exp $ */
+/* $OpenBSD: if_lereg.h,v 1.4 1996/05/10 12:42:24 deraadt Exp $ */
/*-
* Copyright (c) 1982, 1992, 1993
* @(#)if_lereg.h 8.2 (Berkeley) 10/30/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)
+#define MEMSIZE 0x4000
-/* Local Area Network Controller for Ethernet (LANCE) registers */
-struct lereg1 {
- volatile u_short ler1_rdp; /* register data port */
- volatile 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 */
-
-/* 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 */
- volatile u_short ler2_mode; /* mode */
- volatile u_char ler2_padr[6]; /* physical address */
- volatile u_short ler2_ladrf[4]; /* logical address filter */
- volatile u_short ler2_rdra; /* receive descriptor addr */
- volatile u_short ler2_rlen; /* rda high and ring size */
- volatile u_short ler2_tdra; /* transmit descriptor addr */
- volatile u_short ler2_tlen; /* tda high and ring size */
- /* receive message descriptors. bits/hadr are byte order dependent. */
- struct lermd {
- volatile u_short rmd0; /* low address of packet */
- volatile u_char rmd1_bits; /* descriptor bits */
- volatile u_char rmd1_hadr; /* high address of packet */
- volatile short rmd2; /* buffer byte count */
- volatile u_short rmd3; /* message byte count */
- } ler2_rmd[LERBUF];
- /* transmit message descriptors */
- struct letmd {
- volatile u_short tmd0; /* low address of packet */
- volatile u_char tmd1_bits; /* descriptor bits */
- volatile u_char tmd1_hadr; /* high address of packet */
- volatile short tmd2; /* buffer byte count */
- volatile u_short tmd3; /* transmit error bits */
- } ler2_tmd[LETBUF];
- volatile char ler2_rbuf[LERBUF][LEMTU];
- volatile 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"