diff --git a/sys/arch/hp300/dev/if_le.c b/sys/arch/hp300/dev/if_le.c index 9843870a5616..18c5a84c9d6c 100644 --- a/sys/arch/hp300/dev/if_le.c +++ b/sys/arch/hp300/dev/if_le.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)if_le.c 7.6 (Berkeley) 5/8/91 - * $Id: if_le.c,v 1.12 1994/05/13 08:36:17 mycroft Exp $ + * $Id: if_le.c,v 1.13 1994/07/06 01:36:23 mycroft Exp $ */ #include "le.h" @@ -81,76 +81,100 @@ #include #include + +#define ETHER_MIN_LEN 64 +#define ETHER_MAX_LEN 1518 +#define ETHER_ADDR_LEN 6 + + /* offsets for: ID, REGS, MEM, NVRAM */ int lestd[] = { 0, 0x4000, 0x8000, 0xC008 }; struct isr le_isr[NLE]; -int ledebug = 0; /* console error messages */ /* * 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. + * 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 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 lereg0 *sc_r0; /* DIO registers */ - struct lereg1 *sc_r1; /* LANCE registers */ - struct lereg2 *sc_r2; /* dual-port RAM */ - int sc_rmd; /* predicted next rmd to process */ - int sc_tmd; /* next available tmd */ - int sc_txcnt; /* # of transmit buffers in use */ - /* stats */ - int sc_runt; - int sc_jab; - int sc_merr; - int sc_babl; - int sc_cerr; - int sc_miss; - int sc_rown; - int sc_xint; - int sc_xown; - int sc_xown2; - int sc_uflo; - int sc_rxlen; - int sc_rxoff; - int sc_txoff; - int sc_busy; - short sc_iflags; + struct arpcom sc_arpcom; /* common Ethernet structures */ + struct lereg0 *sc_r0; /* DIO registers */ + struct lereg1 *sc_r1; /* LANCE registers */ + void *sc_mem; + struct init_block *sc_init; + struct mds *sc_rd, *sc_td; + u_char *sc_rbuf, *sc_tbuf; + int sc_last_rd, sc_last_td; + int sc_no_td; +#ifdef LEDEBUG + int sc_debug; +#endif } le_softc[NLE]; -/* access LANCE registers */ -#define LERDWR(cntl, src, dst) \ - do { \ - (dst) = (src); \ - } while (((cntl)->ler0_status & LE_ACK) == 0); +int leintr __P((int)); +int leioctl __P((struct ifnet *, int, caddr_t)); +int lestart __P((struct ifnet *)); +int lewatchdog __P((/* short */)); +static inline void lewrcsr __P((/* struct le_softc *, u_short, u_short */)); +static inline u_short lerdcsr __P((/* struct le_softc *, u_short */)); +void leinit __P((struct le_softc *)); +void lememinit __P((struct le_softc *)); +void lereset __P((struct le_softc *)); +void lestop __P((struct le_softc *)); +void letint __P((int)); +void lerint __P((int)); +void leread __P((struct le_softc *, u_char *, int)); +struct mbuf *leget __P((u_char *, int, struct ifnet *)); +#ifdef LEDEBUG +void recv_print __P((struct le_softc *, int)); +void xmit_print __P((struct le_softc *, int)); +#endif +void lesetladrf __P((struct arpcom *, u_long *)); int leattach __P((struct hp_device *)); -void lesetladrf __P((struct arpcom *, u_long *)); -void ledrinit __P((struct lereg2 *)); -void lereset __P((struct le_softc *)); -void leinit __P((int)); -int lestart __P((struct ifnet *)); -int leintr __P((int)); -void lexint __P((struct le_softc *)); -void lerint __P((struct le_softc *)); -void leread __P((struct le_softc *, char *, int)); -int leput __P((char *, struct mbuf *)); -struct mbuf *leget __P((char *, int, int, struct ifnet *)); -int leioctl __P((struct ifnet *, int, caddr_t)); -void leerror __P((struct le_softc *, int)); -void lererror __P((struct le_softc *, char *)); -void lexerror __P((struct le_softc *)); -int ether_output(); struct driver ledriver = { leattach, "le", }; +static inline void +lewrcsr(sc, port, val) + struct le_softc *sc; + register u_short port; + register u_short val; +{ + register struct lereg0 *ler0 = sc->sc_r0; + register struct lereg1 *ler1 = sc->sc_r1; + + do { + ler1->ler1_rap = port; + } while ((ler0->ler0_status & LE_ACK) == 0); + do { + ler1->ler1_rdp = val; + } while ((ler0->ler0_status & LE_ACK) == 0); +} + +static inline u_short +lerdcsr(sc, port) + struct le_softc *sc; + register u_short port; +{ + register struct lereg0 *ler0 = sc->sc_r0; + register struct lereg1 *ler1 = sc->sc_r1; + register u_short val; + + do { + ler1->ler1_rap = port; + } while ((ler0->ler0_status & LE_ACK) == 0); + do { + val = ler1->ler1_rdp; + } while ((ler0->ler0_status & LE_ACK) == 0); + return (val); +} + /* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready @@ -161,18 +185,16 @@ leattach(hd) struct hp_device *hd; { register struct lereg0 *ler0; - register struct lereg2 *ler2; - struct lereg2 *lemem = 0; struct le_softc *sc = &le_softc[hd->hp_unit]; - struct ifnet *ifp = &sc->sc_if; + struct ifnet *ifp = &sc->sc_arpcom.ac_if; char *cp; int i; ler0 = sc->sc_r0 = (struct lereg0 *)(lestd[0] + (int)hd->hp_addr); - sc->sc_r1 = (struct lereg1 *)(lestd[1] + (int)hd->hp_addr); - ler2 = sc->sc_r2 = (struct lereg2 *)(lestd[2] + (int)hd->hp_addr); if (ler0->ler0_id != LEID) return(0); + sc->sc_r1 = (struct lereg1 *)(lestd[1] + (int)hd->hp_addr); + sc->sc_mem = (void *)(lestd[2] + (int)hd->hp_addr); le_isr[hd->hp_unit].isr_intr = leintr; hd->hp_ipl = le_isr[hd->hp_unit].isr_ipl = LE_IPL(ler0->ler0_status); le_isr[hd->hp_unit].isr_arg = hd->hp_unit; @@ -183,43 +205,777 @@ leattach(hd) * Read the ethernet address off the board, one nibble at a time. */ cp = (char *)(lestd[3] + (int)hd->hp_addr); - for (i = 0; i < sizeof(sc->sc_addr); i++) { - sc->sc_addr[i] = (*++cp & 0xF) << 4; + for (i = 0; i < sizeof(sc->sc_arpcom.ac_enaddr); i++) { + sc->sc_arpcom.ac_enaddr[i] = (*++cp & 0xF) << 4; cp++; - sc->sc_addr[i] |= *++cp & 0xF; + sc->sc_arpcom.ac_enaddr[i] |= *++cp & 0xF; cp++; } printf("le%d: hardware address %s\n", hd->hp_unit, - ether_sprintf(sc->sc_addr)); + ether_sprintf(sc->sc_arpcom.ac_enaddr)); - /* - * Setup for transmit/receive - */ - ler2->ler2_mode = LE_MODE; - ler2->ler2_rlen = LE_RLEN; - ler2->ler2_rdra = (int)lemem->ler2_rmd; - ler2->ler2_tlen = LE_TLEN; - ler2->ler2_tdra = (int)lemem->ler2_tmd; isrlink(&le_isr[hd->hp_unit]); ler0->ler0_status = LE_IE; ifp->if_unit = hd->hp_unit; ifp->if_name = "le"; - ifp->if_ioctl = leioctl; ifp->if_output = ether_output; ifp->if_start = lestart; + ifp->if_ioctl = leioctl; + ifp->if_watchdog = lewatchdog; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; + if_attach(ifp); ether_ifattach(ifp); + #if NBPFILTER > 0 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif return (1); } +void +lereset(sc) + struct le_softc *sc; +{ + + leinit(sc); +} + +int +lewatchdog(unit) + short unit; +{ + struct le_softc *sc = &le_softc[unit]; + + log(LOG_ERR, "le%d: device timeout\n", unit); + ++sc->sc_arpcom.ac_if.if_oerrors; + lereset(sc); +} + +#define LANCE_ADDR(sc, a) \ + ((u_long)(a) - (u_long)sc->sc_mem) + +/* LANCE initialization block set up. */ +void +lememinit(sc) + register struct le_softc *sc; +{ + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + int i; + void *mem; + u_long a; + + /* + * At this point we assume that the memory allocated to the Lance is + * quadword aligned. If it isn't then the initialisation is going + * fail later on. + */ + mem = sc->sc_mem; + + sc->sc_init = mem; +#if NBPFILTER > 0 + if (ifp->if_flags & IFF_PROMISC) + sc->sc_init->mode = LE_NORMAL | LE_PROM; + else +#endif + sc->sc_init->mode = LE_NORMAL; + for (i = 0; i < ETHER_ADDR_LEN; i++) + sc->sc_init->padr[i] = sc->sc_arpcom.ac_enaddr[i^1]; + lesetladrf(&sc->sc_arpcom, sc->sc_init->ladrf); + mem += sizeof(struct init_block); + + sc->sc_rd = mem; + a = LANCE_ADDR(sc, mem); + sc->sc_init->rdra = a; + sc->sc_init->rlen = ((a >> 16) & 0xff) | (RLEN << 13); + mem += NRBUF * sizeof(struct mds); + + sc->sc_td = mem; + a = LANCE_ADDR(sc, mem); + sc->sc_init->tdra = a; + sc->sc_init->tlen = ((a >> 16) & 0xff) | (TLEN << 13); + mem += NTBUF * sizeof(struct mds); + + /* + * Set up receive ring descriptors. + */ + sc->sc_rbuf = mem; + for (i = 0; i < NRBUF; i++) { + a = LANCE_ADDR(sc, mem); + sc->sc_rd[i].addr = a; + sc->sc_rd[i].flags = ((a >> 16) & 0xff) | LE_OWN; + sc->sc_rd[i].bcnt = -BUFSIZE; + sc->sc_rd[i].mcnt = 0; + mem += BUFSIZE; + } + + /* + * Set up transmit ring descriptors. + */ + sc->sc_tbuf = mem; + for (i = 0; i < NTBUF; i++) { + a = LANCE_ADDR(sc, mem); + sc->sc_td[i].addr = a; + sc->sc_td[i].flags= ((a >> 16) & 0xff); + sc->sc_td[i].bcnt = 0xf000; + sc->sc_td[i].mcnt = 0; + mem += BUFSIZE; + } +} + +void +lestop(sc) + struct le_softc *sc; +{ + + lewrcsr(sc, 0, LE_STOP); +} + /* - * Set up the logical address filter + * Initialization of interface; set up initialization block + * and transmit/receive descriptor rings. + */ +void +leinit(sc) + register struct le_softc *sc; +{ + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + int s; + register int timo; + u_long a; + + /* Address not known. */ + if (!ifp->if_addrlist) + return; + + s = splimp(); + + /* Don't want to get in a weird state. */ + lewrcsr(sc, 0, LE_STOP); + DELAY(100); + + sc->sc_last_rd = sc->sc_last_td = sc->sc_no_td = 0; + + /* Set up LANCE init block. */ + lememinit(sc); + + /* Turn on byte swapping. */ + lewrcsr(sc, 3, LE_BSWP); + + /* Give LANCE the physical address of its init block. */ + a = LANCE_ADDR(sc, sc->sc_init); + lewrcsr(sc, 1, a); + lewrcsr(sc, 2, (a >> 16) & 0xff); + + /* Try to initialize the LANCE. */ + DELAY(100); + lewrcsr(sc, 0, LE_INIT); + + /* Wait for initialization to finish. */ + for (timo = 100000; timo; timo--) + if (lerdcsr(sc, 0) & LE_IDON) + break; + + if (lerdcsr(sc, 0) & LE_IDON) { + /* Start the LANCE. */ + lewrcsr(sc, 0, LE_INEA | LE_STRT | LE_IDON); + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + lestart(ifp); + } else + printf("le%d: card failed to initialize\n", ifp->if_unit); + + (void) splx(s); +} + +/* + * Setup output on interface. + * Get another datagram to send off of the interface queue, and map it to the + * interface before starting the output. + * Called only at splimp or interrupt level. + */ +int +lestart(ifp) + struct ifnet *ifp; +{ + register struct le_softc *sc = &le_softc[ifp->if_unit]; + struct mbuf *m0, *m; + u_char *buffer; + int len; + int i; + struct mds *cdm; + + if ((sc->sc_arpcom.ac_if.if_flags ^ IFF_RUNNING) & + (IFF_RUNNING | IFF_OACTIVE)) + return; + +outloop: + if (sc->sc_no_td >= NTBUF) { + sc->sc_arpcom.ac_if.if_flags |= IFF_OACTIVE; +#ifdef LEDEBUG + if (sc->sc_debug) + printf("no_td = %x, last_td = %x\n", sc->sc_no_td, + sc->sc_last_td); +#endif + return; + } + + cdm = &sc->sc_td[sc->sc_last_td]; +#if 0 /* XXX redundant */ + if (cdm->flags & LE_OWN) + return; +#endif + + IF_DEQUEUE(&sc->sc_arpcom.ac_if.if_snd, m); + if (!m) + return; + + ++sc->sc_no_td; + + /* + * Copy the mbuf chain into the transmit buffer. + */ + buffer = sc->sc_tbuf + (BUFSIZE * sc->sc_last_td); + len = 0; + for (m0 = m; m; m = m->m_next) { + bcopy(mtod(m, caddr_t), buffer, m->m_len); + buffer += m->m_len; + len += m->m_len; + } + +#if NBPFILTER > 0 + if (sc->sc_arpcom.ac_if.if_bpf) + bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m0); +#endif + + m_freem(m0); + len = max(len, ETHER_MIN_LEN); + + /* + * Init transmit registers, and set transmit start flag. + */ + cdm->bcnt = -len; + cdm->mcnt = 0; + cdm->flags |= LE_OWN | LE_STP | LE_ENP; + +#ifdef LEDEBUG + if (sc->sc_debug) + xmit_print(sc, sc->sc_last_td); +#endif + + lewrcsr(sc, 0, LE_INEA | LE_TDMD); + + /* possible more packets */ + if (++sc->sc_last_td >= NTBUF) + sc->sc_last_td = 0; + goto outloop; +} + +/* + * Controller interrupt. + */ +int +leintr(unit) + int unit; +{ + register struct le_softc *sc = &le_softc[unit]; + register u_short isr; + + isr = lerdcsr(sc, 0); +#ifdef LEDEBUG + if (sc->sc_debug) + printf("le%d: leintr entering with isr=%04x\n", + unit, isr); +#endif + if ((isr & LE_INTR) == 0) + return 0; + + do { + lewrcsr(sc, 0, + isr & (LE_INEA | LE_BABL | LE_MISS | LE_MERR | + LE_RINT | LE_TINT | LE_IDON)); + if (isr & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) { + if (isr & LE_BABL) { + printf("le%d: BABL\n", unit); + sc->sc_arpcom.ac_if.if_oerrors++; + } +#if 0 + if (isr & LE_CERR) { + printf("le%d: CERR\n", unit); + sc->sc_arpcom.ac_if.if_collisions++; + } +#endif + if (isr & LE_MISS) { + printf("le%d: MISS\n", unit); + sc->sc_arpcom.ac_if.if_ierrors++; + } + if (isr & LE_MERR) { + printf("le%d: MERR\n", unit); + lereset(sc); + goto out; + } + } + + if ((isr & LE_RXON) == 0) { + printf("le%d: receiver disabled\n", unit); + sc->sc_arpcom.ac_if.if_ierrors++; + lereset(sc); + goto out; + } + if ((isr & LE_TXON) == 0) { + printf("le%d: transmitter disabled\n", unit); + sc->sc_arpcom.ac_if.if_oerrors++; + lereset(sc); + goto out; + } + + if (isr & LE_RINT) { + /* Reset watchdog timer. */ + sc->sc_arpcom.ac_if.if_timer = 0; + lerint(unit); + } + if (isr & LE_TINT) { + /* Reset watchdog timer. */ + sc->sc_arpcom.ac_if.if_timer = 0; + letint(unit); + } + + isr = lerdcsr(sc, 0); + } while ((isr & LE_INTR) != 0); + +#ifdef LEDEBUG + if (sc->sc_debug) + printf("le%d: leintr returning with isr=%04x\n", + unit, isr); +#endif + +out: + return 1; +} + +#define NEXTTDS \ + if (++tmd == NTBUF) tmd=0, cdm=sc->sc_td; else ++cdm + +void +letint(unit) + int unit; +{ + register struct le_softc *sc = &le_softc[unit]; + register int tmd = (sc->sc_last_td - sc->sc_no_td + NTBUF) % NTBUF; + struct mds *cdm = &sc->sc_td[tmd]; + + if (cdm->flags & LE_OWN) { + /* Race condition with loop below. */ +#ifdef LEDEBUG + if (sc->sc_debug) + printf("le%d: extra tint\n", unit); +#endif + return; + } + + sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE; + + do { + if (sc->sc_no_td <= 0) + break; +#ifdef LEDEBUG + if (sc->sc_debug) + printf("trans cdm = %x\n", cdm); +#endif + sc->sc_arpcom.ac_if.if_opackets++; + --sc->sc_no_td; + if (cdm->flags & (LE_TBUFF | LE_UFLO | LE_LCOL | LE_LCAR | LE_RTRY)) { + if (cdm->flags & LE_TBUFF) + printf("le%d: TBUFF\n", unit); + if ((cdm->flags & (LE_TBUFF | LE_UFLO)) == LE_UFLO) + printf("le%d: UFLO\n", unit); + if (cdm->flags & LE_UFLO) { + lereset(sc); + return; + } +#if 0 + if (cdm->flags & LE_LCOL) { + printf("le%d: late collision\n", unit); + sc->sc_arpcom.ac_if.if_collisions++; + } + if (cdm->flags & LE_LCAR) + printf("le%d: lost carrier\n", unit); + if (cdm->flags & LE_RTRY) { + printf("le%d: excessive collisions, tdr %d\n", + unit, cdm->flags & 0x1ff); + sc->sc_arpcom.ac_if.if_collisions++; + } +#endif + } + NEXTTDS; + } while ((cdm->flags & LE_OWN) == 0); + + lestart(&sc->sc_arpcom.ac_if); +} + +#define NEXTRDS \ + if (++rmd == NRBUF) rmd=0, cdm=sc->sc_rd; else ++cdm + +/* only called from one place, so may as well integrate */ +void +lerint(unit) + int unit; +{ + register struct le_softc *sc = &le_softc[unit]; + register int rmd = sc->sc_last_rd; + struct mds *cdm = &sc->sc_rd[rmd]; + + if (cdm->flags & LE_OWN) { + /* Race condition with loop below. */ +#ifdef LEDEBUG + if (sc->sc_debug) + printf("le%d: extra rint\n", unit); +#endif + return; + } + + /* Process all buffers with valid data. */ + do { + if (cdm->flags & (LE_FRAM | LE_OFLO | LE_CRC | LE_RBUFF)) { + if ((cdm->flags & (LE_FRAM | LE_OFLO | LE_ENP)) == (LE_FRAM | LE_ENP)) + printf("le%d: FRAM\n", unit); + if ((cdm->flags & (LE_OFLO | LE_ENP)) == LE_OFLO) + printf("le%d: OFLO\n", unit); + if ((cdm->flags & (LE_CRC | LE_OFLO | LE_ENP)) == (LE_CRC | LE_ENP)) + printf("le%d: CRC\n", unit); + if (cdm->flags & LE_RBUFF) + printf("le%d: RBUFF\n", unit); + } else if (cdm->flags & (LE_STP | LE_ENP) != (LE_STP | LE_ENP)) { + do { + cdm->mcnt = 0; + cdm->flags |= LE_OWN; + NEXTRDS; + } while ((cdm->flags & (LE_OWN | LE_ERR | LE_STP | LE_ENP)) == 0); + sc->sc_last_rd = rmd; + printf("le%d: chained buffer\n", unit); + if ((cdm->flags & (LE_OWN | LE_ERR | LE_STP | LE_ENP)) != LE_ENP) { + lereset(sc); + return; + } + } else { +#ifdef LEDEBUG + if (sc->sc_debug) + recv_print(sc, sc->sc_last_rd); +#endif + leread(sc, sc->sc_rbuf + (BUFSIZE * rmd), + (int)cdm->mcnt); + sc->sc_arpcom.ac_if.if_ipackets++; + } + + cdm->mcnt = 0; + cdm->flags |= LE_OWN; + NEXTRDS; +#ifdef LEDEBUG + if (sc->sc_debug) + printf("sc->sc_last_rd = %x, cdm = %x\n", + sc->sc_last_rd, cdm); +#endif + } while ((cdm->flags & LE_OWN) == 0); + + sc->sc_last_rd = rmd; +} + +/* + * Pass a packet to the higher levels. + */ +void +leread(sc, buf, len) + register struct le_softc *sc; + u_char *buf; + int len; +{ + struct ether_header *eh; + struct mbuf *m; + + eh = (struct ether_header *)buf; + len -= sizeof(struct ether_header) + 4; + if (len <= 0) + return; + + /* Pull packet off interface. */ + m = leget(buf, len, &sc->sc_arpcom.ac_if); + if (m == 0) + return; + +#if NBPFILTER > 0 + /* + * Check if there's a BPF listener on this interface. + * If so, hand off the raw packet to BPF. + */ + if (sc->sc_arpcom.ac_if.if_bpf) { + bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m); + + /* + * Note that the interface cannot be in promiscuous mode if + * there are no BPF listeners. And if we are in promiscuous + * mode, we have to check if this packet is really ours. + */ + if ((sc->sc_arpcom.ac_if.if_flags & IFF_PROMISC) && + (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ + bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr, + sizeof(eh->ether_dhost)) != 0) { + m_freem(m); + return; + } + } +#endif + + ether_input(&sc->sc_arpcom.ac_if, eh, m); +} + +/* + * Supporting routines + */ + +/* + * Pull data off an interface. + * Len is length of data, with local net header stripped. + * We copy the data into mbufs. When full cluster sized units are present + * we copy into clusters. + */ +struct mbuf * +leget(buf, totlen, ifp) + u_char *buf; + int totlen; + struct ifnet *ifp; +{ + struct mbuf *top, **mp, *m, *p; + int len; + register caddr_t cp = buf; + char *epkt; + + buf += sizeof(struct ether_header); + cp = buf; + epkt = cp + totlen; + + 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; + top = 0; + mp = ⊤ + + 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 = buf; + } + + return top; +} + +/* + * Process an ioctl request. + */ +int +leioctl(ifp, cmd, data) + register struct ifnet *ifp; + int cmd; + caddr_t data; +{ + struct le_softc *sc = &le_softc[ifp->if_unit]; + struct ifaddr *ifa = (struct ifaddr *)data; + struct ifreq *ifr = (struct ifreq *)data; + int s, error = 0; + + s = splimp(); + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + leinit(sc); /* before arpwhohas */ + /* + * See if another station has *our* IP address. + * i.e.: There is an address conflict! If a + * conflict exists, a message is sent to the + * console. + */ + sc->sc_arpcom.ac_ipaddr = IA_SIN(ifa)->sin_addr; + arpwhohas(&sc->sc_arpcom, &IA_SIN(ifa)->sin_addr); + break; +#endif +#ifdef NS + /* XXX - This code is probably wrong. */ + 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_arpcom.ac_enaddr); + else + bcopy(ina->x_host.c_host, + sc->sc_arpcom.ac_enaddr, + sizeof(sc->sc_arpcom.ac_enaddr)); + /* Set new address. */ + leinit(sc); + break; + } +#endif + default: + leinit(sc); + break; + } + break; + + case SIOCSIFFLAGS: + /* + * If interface is marked down and it is running, then stop it + */ + if ((ifp->if_flags & IFF_UP) == 0 && + (ifp->if_flags & IFF_RUNNING) != 0) { + /* + * If interface is marked down and it is running, then + * stop it. + */ + lestop(sc); + ifp->if_flags &= ~IFF_RUNNING; + } else if ((ifp->if_flags & IFF_UP) != 0 && + (ifp->if_flags & IFF_RUNNING) == 0) { + /* + * If interface is marked up and it is stopped, then + * start it. + */ + leinit(sc); + } else { + /* + * Reset the interface to pick up changes in any other + * flags that affect hardware registers. + */ + /*lestop(sc);*/ + leinit(sc); + } +#ifdef LEDEBUG + if (ifp->if_flags & IFF_DEBUG) + sc->sc_debug = 1; + else + sc->sc_debug = 0; +#endif + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + error = (cmd == SIOCADDMULTI) ? + ether_addmulti(ifr, &sc->sc_arpcom): + ether_delmulti(ifr, &sc->sc_arpcom); + + if (error == ENETRESET) { + /* + * Multicast list has changed; set the hardware filter + * accordingly. + */ + leinit(sc); + error = 0; + } + break; + + default: + error = EINVAL; + } + (void) splx(s); + return error; +} + +#ifdef LEDEBUG +void +recv_print(sc, no) + struct le_softc *sc; + int no; +{ + struct mds *rmd; + int i, printed = 0; + u_short len; + + rmd = &sc->sc_rd[no]; + len = rmd->mcnt; + printf("%s: receive buffer %d, len = %d\n", sc->sc_dev.dv_xname, no, + len); + printf("%s: status %x\n", sc->sc_dev.dv_xname, lerdcsr(sc, 0)); + for (i = 0; i < len; i++) { + if (!printed) { + printed = 1; + printf("%s: data: ", sc->sc_dev.dv_xname); + } + printf("%x ", *(sc->sc_rbuf + (BUFSIZE*no) + i)); + } + if (printed) + printf("\n"); +} + +void +xmit_print(sc, no) + struct le_softc *sc; + int no; +{ + struct mds *rmd; + int i, printed=0; + u_short len; + + rmd = &sc->sc_td[no]; + len = -rmd->bcnt; + printf("%s: transmit buffer %d, len = %d\n", sc->sc_dev.dv_xname, no, + len); + printf("%s: status %x\n", sc->sc_dev.dv_xname, lerdcsr(sc, 0)); + printf("%s: addr %x, flags %x, bcnt %x, mcnt %x\n", + sc->sc_dev.dv_xname, rmd->addr, rmd->flags, rmd->bcnt, rmd->mcnt); + for (i = 0; i < len; i++) { + if (!printed) { + printed = 1; + printf("%s: data: ", sc->sc_dev.dv_xname); + } + printf("%x ", *(sc->sc_tbuf + (BUFSIZE*no) + i)); + } + if (printed) + printf("\n"); +} +#endif /* LEDEBUG */ + +/* + * Set up the logical address filter. */ void lesetladrf(ac, af) @@ -270,7 +1026,7 @@ lesetladrf(ac, af) for (len = sizeof(enm->enm_addrlo); --len >= 0;) { c = *cp++; for (i = 8; --i >= 0;) { - if ((c & 0x01) ^ (crc & 0x01)) { + if ((crc & 0x01) ^ (c & 0x01)) { crc >>= 1; crc ^= 0x6db88320 | 0x80000000; } else @@ -288,651 +1044,3 @@ lesetladrf(ac, af) } ifp->if_flags &= ~IFF_ALLMULTI; } - -void -ledrinit(ler2) - register struct lereg2 *ler2; -{ - register struct lereg2 *lemem = 0; - register int i; - - for (i = 0; i < LERBUF; i++) { - ler2->ler2_rmd[i].rmd0 = (int)lemem->ler2_rbuf[i]; - ler2->ler2_rmd[i].rmd1 = LE_OWN; - ler2->ler2_rmd[i].rmd2 = -LEMTU; - ler2->ler2_rmd[i].rmd3 = 0; - } - for (i = 0; i < LETBUF; i++) { - ler2->ler2_tmd[i].tmd0 = (int)lemem->ler2_tbuf[i]; - ler2->ler2_tmd[i].tmd1 = 0; - ler2->ler2_tmd[i].tmd2 = 0; - ler2->ler2_tmd[i].tmd3 = 0; - } -} - -void -lereset(sc) - register struct le_softc *sc; -{ - register struct lereg0 *ler0 = sc->sc_r0; - register struct lereg1 *ler1 = sc->sc_r1; - register struct lereg2 *ler2 = sc->sc_r2; - struct lereg2 *lemem = 0; - register int timo, stat; - -#if NBPFILTER > 0 - if (sc->sc_if.if_flags & IFF_PROMISC) - /* set the promiscuous bit */ - ler2->ler2_mode = LE_MODE|0x8000; - else -#endif - ler2->ler2_mode = LE_MODE; - LERDWR(ler0, LE_CSR0, ler1->ler1_rap); - LERDWR(ler0, LE_STOP, ler1->ler1_rdp); - - 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]; - lesetladrf(&sc->sc_ac, ler2->ler2_ladrf); - ledrinit(ler2); - sc->sc_rmd = sc->sc_tmd = sc->sc_txcnt = 0; - - LERDWR(ler0, LE_CSR1, ler1->ler1_rap); - LERDWR(ler0, (int)&lemem->ler2_mode, ler1->ler1_rdp); - LERDWR(ler0, LE_CSR2, ler1->ler1_rap); - LERDWR(ler0, 0, ler1->ler1_rdp); - LERDWR(ler0, LE_CSR3, ler1->ler1_rap); - LERDWR(ler0, LE_BSWP, ler1->ler1_rdp); - LERDWR(ler0, LE_CSR0, ler1->ler1_rap); - LERDWR(ler0, LE_INIT, ler1->ler1_rdp); - timo = 100000; - do { - if (--timo == 0) { - printf("le%d: init timeout, stat=0x%x\n", - sc->sc_if.if_unit, stat); - break; - } - LERDWR(ler0, ler1->ler1_rdp, stat); - } while ((stat & (LE_IDON | LE_ERR)) == 0); - if (stat & LE_ERR) - printf("le%d: init failed, stat=0x%x\n", - sc->sc_if.if_unit, stat); - else - LERDWR(ler0, LE_IDON, ler1->ler1_rdp); - sc->sc_if.if_flags &= ~IFF_OACTIVE; - LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp); -} - -/* - * Initialization of interface - */ -void -leinit(unit) - int unit; -{ - struct le_softc *sc = &le_softc[unit]; - register struct ifnet *ifp = &sc->sc_if; - int s; - - /* not yet, if address still unknown */ - if (ifp->if_addrlist == (struct ifaddr *)0) - return; - if ((ifp->if_flags & IFF_RUNNING) == 0) { - s = splimp(); - ifp->if_flags |= IFF_RUNNING; - lereset(sc); - (void) lestart(ifp); - splx(s); - } -} - -#define LENEXTTMP \ - if (++bix == LETBUF) bix = 0, tmd = sc->sc_r2->ler2_tmd; else ++tmd - -/* - * Start output on interface. Get another datagram to send - * off of the interface queue, and copy it to the interface - * before starting the output. - */ -int -lestart(ifp) - struct ifnet *ifp; -{ - register struct le_softc *sc = &le_softc[ifp->if_unit]; - register int bix; - register struct letmd *tmd; - register struct mbuf *m; - int len, gotone = 0; - - if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) - return (0); - bix = sc->sc_tmd; - tmd = &sc->sc_r2->ler2_tmd[bix]; - do { - if (tmd->tmd1 & LE_OWN) { - if (gotone) - break; - sc->sc_xown2++; - return (0); - } - IF_DEQUEUE(&sc->sc_if.if_snd, m); - if (m == 0) { - if (gotone) - break; - return (0); - } - len = leput(sc->sc_r2->ler2_tbuf[bix], m); -#if NBPFILTER > 0 - /* - * If bpf is listening on this interface, let it - * see the packet before we commit it to the wire. - */ - if (ifp->if_bpf) - bpf_tap(ifp->if_bpf, sc->sc_r2->ler2_tbuf[bix], len); -#endif - tmd->tmd3 = 0; - tmd->tmd2 = -len; - tmd->tmd1 = LE_OWN | LE_STP | LE_ENP; - LENEXTTMP; - gotone++; - } while (++sc->sc_txcnt < LETBUF); - sc->sc_tmd = bix; - sc->sc_if.if_flags |= IFF_OACTIVE; - /* transmit as soon as possible */ - LERDWR(sc->sc_r0, LE_INEA|LE_TDMD, sc->sc_r1->ler1_rdp); - return (0); -} - -int -leintr(unit) - register int unit; -{ - register struct le_softc *sc = &le_softc[unit]; - register struct lereg0 *ler0 = sc->sc_r0; - register struct lereg1 *ler1; - register int stat; - - if ((ler0->ler0_status & LE_IR) == 0) - return(0); - if (ler0->ler0_status & LE_JAB) { - sc->sc_jab++; - lereset(sc); - return(1); - } - ler1 = sc->sc_r1; - LERDWR(ler0, ler1->ler1_rdp, stat); - if (stat & LE_SERR) { - leerror(sc, stat); - if (stat & LE_MERR) { - sc->sc_merr++; - lereset(sc); - return(1); - } - if (stat & LE_BABL) - sc->sc_babl++; - if (stat & LE_CERR) - sc->sc_cerr++; - if (stat & LE_MISS) - sc->sc_miss++; - LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp); - } - if ((stat & LE_RXON) == 0) { - sc->sc_rxoff++; - lereset(sc); - return(1); - } - if ((stat & LE_TXON) == 0) { - sc->sc_txoff++; - lereset(sc); - return(1); - } - if (stat & LE_RINT) - lerint(sc); - if (stat & LE_TINT) - 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; - int bix, gotone = 0; - - if ((sc->sc_if.if_flags & IFF_OACTIVE) == 0) { - sc->sc_xint++; - return; - } - if ((bix = sc->sc_tmd - sc->sc_txcnt) < 0) - bix += LETBUF; - tmd = &sc->sc_r2->ler2_tmd[bix]; - do { - if (tmd->tmd1 & LE_OWN) { - if (gotone) - break; - sc->sc_xown++; - return; - } - - /* clear interrupt */ - LERDWR(sc->sc_r0, LE_TINT|LE_INEA, sc->sc_r1->ler1_rdp); - - /* XXX documentation says BUFF not included in ERR */ - if ((tmd->tmd1 & LE_ERR) || (tmd->tmd3 & LE_TBUFF)) { - lexerror(sc); - sc->sc_if.if_oerrors++; - if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) { - sc->sc_uflo++; - lereset(sc); - } else if (tmd->tmd3 & LE_LCOL) - sc->sc_if.if_collisions++; - else if (tmd->tmd3 & LE_RTRY) - sc->sc_if.if_collisions += 16; - } - else if (tmd->tmd1 & LE_ONE) - sc->sc_if.if_collisions++; - else if (tmd->tmd1 & LE_MORE) - /* what is the real number? */ - sc->sc_if.if_collisions += 2; - else - sc->sc_if.if_opackets++; - LENEXTTMP; - gotone++; - } while (--sc->sc_txcnt > 0); - sc->sc_if.if_flags &= ~IFF_OACTIVE; - (void) 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]; - - /* - * Out of sync with hardware, should never happen? - */ - if (rmd->rmd1 & LE_OWN) { - sc->sc_rown++; - do { - LENEXTRMP; - } while ((rmd->rmd1 & LE_OWN) && bix != sc->sc_rmd); - if (bix == sc->sc_rmd) { - printf("le%d: rint with no buffer\n", - sc->sc_if.if_unit); - LERDWR(sc->sc_r0, LE_RINT|LE_INEA, sc->sc_r1->ler1_rdp); - return; - } - } - - /* - * Process all buffers with valid data - */ - while ((rmd->rmd1 & LE_OWN) == 0) { - int len = rmd->rmd3; - - /* Clear interrupt to avoid race condition */ - LERDWR(sc->sc_r0, LE_RINT|LE_INEA, sc->sc_r1->ler1_rdp); - - if (rmd->rmd1 & LE_ERR) { - sc->sc_rmd = bix; - lererror(sc, "bad packet"); - sc->sc_if.if_ierrors++; - } else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { - /* - * Find the end of the packet so we can see how long - * it was. We still throw it away. - */ - do { - LERDWR(sc->sc_r0, LE_RINT|LE_INEA, - sc->sc_r1->ler1_rdp); - rmd->rmd3 = 0; - rmd->rmd1 = LE_OWN; - LENEXTRMP; - } while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_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 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != - LE_ENP) { - lereset(sc); - return; - } - } else - leread(sc, sc->sc_r2->ler2_rbuf[bix], len); - rmd->rmd3 = 0; - rmd->rmd1 = LE_OWN; - LENEXTRMP; - } - sc->sc_rmd = bix; -} - -void -leread(sc, buf, len) - register struct le_softc *sc; - char *buf; - int len; -{ - register struct ether_header *et; - register struct ifnet *ifp = &sc->sc_if; - struct mbuf *m; - - ifp->if_ipackets++; - et = (struct ether_header *)buf; - /* adjust input length to account for header and CRC */ - len -= sizeof(struct ether_header) + 4; - - if (len <= 0) { - if (ledebug) - log(LOG_WARNING, - "le%d: ierror(runt packet): from %s: len=%d\n", - sc->sc_if.if_unit, ether_sprintf(et->ether_shost), - len); - sc->sc_runt++; - ifp->if_ierrors++; - return; - } - -#if NBPFILTER > 0 - /* - * Check if there's a bpf filter listening on this interface. - * If so, hand off the raw packet to bpf, then discard things - * not destined for us (but be sure to keep broadcast/multicast). - */ - if (ifp->if_bpf) { - bpf_tap(ifp->if_bpf, buf, len + sizeof(struct ether_header)); - if ((ifp->if_flags & IFF_PROMISC) && - (et->ether_dhost[0] & 1) == 0 && - bcmp(et->ether_dhost, sc->sc_addr, - sizeof(et->ether_dhost)) != 0) - return; - } -#endif - - m = leget(buf, 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. - */ -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; - int cmd; - caddr_t data; -{ - register struct ifaddr *ifa; - struct le_softc *sc = &le_softc[ifp->if_unit]; - 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: - leinit(ifp->if_unit); /* before arpwhohas */ - ((struct arpcom *)ifp)->ac_ipaddr = - IA_SIN(ifa)->sin_addr; - arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); - 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; - LERDWR(sc->sc_r0, LE_STOP, sc->sc_r1->ler1_rdp); - bcopy((caddr_t)ina->x_host.c_host, - (caddr_t)sc->sc_addr, sizeof(sc->sc_addr)); - } - leinit(ifp->if_unit); /* does le_setaddr() */ - break; - } -#endif - default: - leinit(ifp->if_unit); - break; - } - break; - - case SIOCSIFFLAGS: - if ((ifp->if_flags & IFF_UP) == 0 && - ifp->if_flags & IFF_RUNNING) { - ifp->if_flags &= ~IFF_RUNNING; - LERDWR(sc->sc_r0, LE_STOP, sc->sc_r1->ler1_rdp); - } else if (ifp->if_flags & IFF_UP && - (ifp->if_flags & IFF_RUNNING) == 0) - 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); - 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); - 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_CERR) && sc->sc_cerr) - return; - log(LOG_WARNING, - "le%d: error: stat=%b\n", sc->sc_if.if_unit, stat, - "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"); -} - -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, - "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", - sc->sc_if.if_unit, msg, - len > 11 ? ether_sprintf(&sc->sc_r2->ler2_rbuf[sc->sc_rmd][6]) : "unknown", - sc->sc_rmd, len, rmd->rmd1, - "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP"); -} - -void -lexerror(sc) - register struct le_softc *sc; -{ - register struct letmd *tmd; - register int len; - - if (!ledebug) - return; - - tmd = sc->sc_r2->ler2_tmd; - len = -tmd->tmd2; - log(LOG_WARNING, - "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", - sc->sc_if.if_unit, - len > 5 ? ether_sprintf(&sc->sc_r2->ler2_tbuf[0][0]) : "unknown", - 0, len, tmd->tmd1, - "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", - tmd->tmd3, - "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); -} -#endif diff --git a/sys/arch/hp300/dev/if_lereg.h b/sys/arch/hp300/dev/if_lereg.h index fc5f3d9168fd..bf161661ca53 100644 --- a/sys/arch/hp300/dev/if_lereg.h +++ b/sys/arch/hp300/dev/if_lereg.h @@ -31,21 +31,19 @@ * SUCH DAMAGE. * * from: @(#)if_lereg.h 7.1 (Berkeley) 5/8/90 - * $Id: if_lereg.h,v 1.5 1994/02/06 00:46:03 mycroft Exp $ + * $Id: if_lereg.h,v 1.6 1994/07/06 01:36:25 mycroft Exp $ */ #define LEID 21 -#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 NTBUF 2 +#define TLEN 1 +#define NRBUF 8 +#define RLEN 3 +#define BUFSIZE 1518 #define vu_char volatile u_char +#define vu_short volatile u_short /* * LANCE registers. @@ -57,43 +55,6 @@ struct lereg0 { vu_char ler0_status; /* interrupt enable/status */ }; -struct lereg1 { - u_short ler1_rdp; /* data port */ - u_short ler1_rap; /* register select port */ -}; - -/* - * Overlayed on 16K dual-port RAM. - * Current size is 15,284 bytes with 8 x 1518 receive buffers and - * 2 x 1518 transmit buffers. - */ -struct lereg2 { - /* init block */ - u_short ler2_mode; /* +0x0000 */ - u_char ler2_padr[6]; /* +0x0002 */ - u_long ler2_ladrf[2]; /* +0x0008 */ - u_short ler2_rdra; /* +0x0010 */ - u_short ler2_rlen; /* +0x0012 */ - u_short ler2_tdra; /* +0x0014 */ - u_short ler2_tlen; /* +0x0016 */ - /* receive message descriptors */ - struct lermd { /* +0x0018 */ - u_short rmd0; - u_short rmd1; - short rmd2; - u_short rmd3; - } ler2_rmd[LERBUF]; - /* transmit message descriptors */ - struct letmd { /* +0x0058 */ - u_short tmd0; - u_short tmd1; - short tmd2; - u_short tmd3; - } ler2_tmd[LETBUF]; - char ler2_rbuf[LERBUF][LEMTU]; /* +0x0068 */ - char ler2_tbuf[LETBUF][LEMTU]; /* +0x2FD8 */ -}; - /* * Control and status bits -- lereg0 */ @@ -104,14 +65,14 @@ struct lereg2 { #define LE_JAB 0x02 /* loss of tx clock (???) */ #define LE_IPL(x) ((((x) >> 4) & 0x3) + 3) +struct lereg1 { + vu_short ler1_rdp; /* data port */ + vu_short ler1_rap; /* register select port */ +}; + /* * Control and status bits -- lereg1 */ -#define LE_CSR0 0 -#define LE_CSR1 1 -#define LE_CSR2 2 -#define LE_CSR3 3 - #define LE_SERR 0x8000 #define LE_BABL 0x4000 #define LE_CERR 0x2000 @@ -129,26 +90,72 @@ struct lereg2 { #define LE_STRT 0x0002 #define LE_INIT 0x0001 -#define LE_BSWP 0x4 -#define LE_MODE 0x0 +#define LE_BSWP 0x0004 +#define LE_ACON 0x0002 +#define LE_BCON 0x0001 /* - * Control and status bits -- lereg2 + * Overlayed on 16K dual-port RAM. + * Current size is 15,284 bytes with 8 x 1518 receive buffers and + * 2 x 1518 transmit buffers. */ -#define LE_OWN 0x8000 -#define LE_ERR 0x4000 -#define LE_STP 0x0200 -#define LE_ENP 0x0100 -#define LE_FRAM 0x2000 -#define LE_OFLO 0x1000 -#define LE_CRC 0x0800 -#define LE_RBUFF 0x0400 -#define LE_MORE 0x1000 -#define LE_ONE 0x0800 -#define LE_DEF 0x0400 -#define LE_TBUFF 0x8000 -#define LE_UFLO 0x4000 -#define LE_LCOL 0x1000 -#define LE_LCAR 0x0800 -#define LE_RTRY 0x0400 +/* + * LANCE initialization block + */ +struct init_block { + u_short mode; /* mode register */ + u_char padr[6]; /* ethernet address */ + u_long ladrf[2]; /* logical address filter (multicast) */ + u_short rdra; /* low order pointer to receive ring */ + u_short rlen; /* high order pointer and no. rings */ + u_short tdra; /* low order pointer to transmit ring */ + u_short tlen; /* high order pointer and no rings */ +}; + +/* + * Mode bits -- init_block + */ +#define LE_PROM 0x8000 /* promiscuous */ +#define LE_INTL 0x0040 /* internal loopback */ +#define LE_DRTY 0x0020 /* disable retry */ +#define LE_COLL 0x0010 /* force collision */ +#define LE_DTCR 0x0008 /* disable transmit crc */ +#define LE_LOOP 0x0004 /* loopback */ +#define LE_DTX 0x0002 /* disable transmitter */ +#define LE_DRX 0x0001 /* disable receiver */ +#define LE_NORMAL 0x0000 + +/* + * Message descriptor + */ +struct mds { + u_short addr; + u_short flags; + u_short bcnt; + u_short mcnt; +}; + +/* Message descriptor flags */ +#define LE_OWN 0x8000 /* owner bit, 0=host, 1=LANCE */ +#define LE_ERR 0x4000 /* error */ +#define LE_STP 0x0200 /* start of packet */ +#define LE_ENP 0x0100 /* end of packet */ + +/* Receive ring status flags */ +#define LE_FRAM 0x2000 /* framing error error */ +#define LE_OFLO 0x1000 /* silo overflow */ +#define LE_CRC 0x0800 /* CRC error */ +#define LE_RBUFF 0x0400 /* buffer error */ + +/* Transmit ring status flags */ +#define LE_MORE 0x1000 /* more than 1 retry */ +#define LE_ONE 0x0800 /* one retry */ +#define LE_DEF 0x0400 /* deferred transmit */ + +/* Transmit errors */ +#define LE_TBUFF 0x8000 /* buffer error */ +#define LE_UFLO 0x4000 /* silo underflow */ +#define LE_LCOL 0x1000 /* late collision */ +#define LE_LCAR 0x0800 /* loss of carrier */ +#define LE_RTRY 0x0400 /* tried 16 times */