diff --git a/sys/arch/sun3/dev/if_le.c b/sys/arch/sun3/dev/if_le.c index 6ca05d095fe7..7ce0b32d43a3 100644 --- a/sys/arch/sun3/dev/if_le.c +++ b/sys/arch/sun3/dev/if_le.c @@ -1,1031 +1,154 @@ -/* $NetBSD: if_le.c,v 1.23 1995/10/27 15:53:39 gwr Exp $ */ +/* $NetBSD: if_le.c,v 1.24 1995/12/10 08:46:05 mycroft Exp $ */ -/* - * LANCE Ethernet driver +/*- + * Copyright (c) 1995 Charles M. Hannum. All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. * - * Copyright (c) 1995 Gordon W. Ross - * Copyright (c) 1994 Charles Hannum. + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. * - * Copyright (C) 1993, Paul Richards. This software may be used, modified, - * copied, distributed, and sold, in both source and binary form provided - * that the above copyright and these terms are retained. Under no - * circumstances is the author responsible for the proper functioning - * of this software, nor does the author assume any responsibility - * for damages incurred with its use. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_le.c 8.2 (Berkeley) 11/16/93 */ #include "bpfilter.h" #include #include -#include -#include #include -#include #include +#include #include #include -#include -#include -#include #ifdef INET #include -#include -#include -#include #include #endif -#ifdef NS -#include -#include -#endif - -#if NBPFILTER > 0 -#include -#include -#endif - #include #include +#include +#include +#include +#include -/* - * XXX - Be warned: Most Sun3/50 and many Sun3/60 machines have - * the LANCE Rev. C bug, which we MUST avoid or suffer likely - * NFS file corruption and worse! That said, if you are SURE - * your LANCE is OK, you can remove this work-around using: - * options LANCE_REVC_BUG=0 - * in your kernel config file. - */ -#ifndef LANCE_REVC_BUG -#define LANCE_REVC_BUG 1 -#endif +#include +#include +#include +#define LE_NEED_BUF_CONTIG +#include -/* #define LEDEBUG 1 */ +#define LE_SOFTC(unit) lecd.cd_devs[unit] +#define LE_DELAY(x) DELAY(x) -#include "if_lereg.h" -#include "if_le.h" -#include "if_le_subr.h" - -#define RMD_BITS "\20\20own\17err\16fram\15oflo\14crc\13rbuf\12stp\11enp" - -#define ETHER_MIN_LEN 64 -#define ETHER_MAX_LEN 1518 - -/* - * The lance has only 24 address lines. When it accesses memory, - * the high address lines are hard-wired to 0xFF, so we must: - * (1) put what we want the LANCE to see above 0xFF000000, and - * (2) mask our CPU addresses down to 24 bits for the LANCE. - */ -#define LANCE_ADDR(sc,x) ((u_int)(x) & 0xFFffff) - -#ifdef PACKETSTATS -long lexpacketsizes[LEMTU+1]; -long lerpacketsizes[LEMTU+1]; -#endif - -/* autoconfiguration driver */ -void le_attach(struct device *, struct device *, void *); +int lematch __P((struct device *, void *, void *)); +void leattach __P((struct device *, struct device *, void *)); +int leintr __P((void *)); struct cfdriver lecd = { - NULL, "le", le_md_match, le_attach, - DV_IFNET, sizeof(struct le_softc), + NULL, "le", lematch, leattach, DV_IFNET, sizeof(struct le_softc) }; -int leioctl __P((struct ifnet *, u_long, caddr_t)); -void lestart __P((struct ifnet *)); -void 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((struct le_softc *)); -void lerint __P((struct le_softc *)); -void leread __P((struct le_softc *, u_char *, int)); -struct mbuf *leget __P((u_char *, int, struct ifnet *)); -void lesetladrf __P((struct arpcom *, u_long *)); -#ifdef LEDEBUG -void recv_print __P((struct le_softc *, int)); -void xmit_print __P((struct le_softc *, int)); -#endif - -/* - * Inline routines to read and write the LANCE registers. - */ - -static inline void -lewrcsr(sc, regnum, value) +integrate void +lewrcsr(sc, port, val) struct le_softc *sc; - u_short regnum; - u_short value; + u_int16_t port, val; { - volatile struct le_regs *regs = sc->sc_regs; + register struct lereg1 *ler1 = sc->sc_r1; - regs->lereg_addr = regnum; - regs->lereg_data = value; + ler1->ler1_rap = port; + ler1->ler1_rdp = val; } -static inline u_short -lerdcsr(sc, regnum) +integrate u_int16_t +lerdcsr(sc, port) struct le_softc *sc; - u_short regnum; + u_int16_t port; { - volatile struct le_regs *regs = sc->sc_regs; - u_short value; + register struct lereg1 *ler1 = sc->sc_r1; + u_int16_t val; - regs->lereg_addr = regnum; - value = regs->lereg_data; - - return (value); + ler1->ler1_rap = port; + val = ler1->ler1_rdp; + return (val); } -/* - * The probe is done in if_le_subr.c:if_md_match() - */ +int +lematch(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct confargs *ca = aux; + int x; + + if (ca->ca_paddr == -1) + ca->ca_paddr = OBIO_AMD_ETHER; + if (ca->ca_intpri == -1) + ca->ca_intpri = 3; + + /* The peek returns -1 on bus error. */ + x = bus_peek(ca->ca_bustype, ca->ca_paddr, 1); + return (x != -1); +} -/* - * Interface exists: make available by filling in network interface - * record. System will initialize the interface when it is ready - * to accept packets. We get the ethernet address here. - */ void -le_attach(parent, self, aux) +leattach(parent, self, aux) struct device *parent, *self; void *aux; { struct le_softc *sc = (void *)self; struct confargs *ca = aux; - struct ifnet *ifp = &sc->sc_if; - int pri; - u_int a; - le_md_attach(parent, self, aux); - printf(" hwaddr %s\n", ether_sprintf(sc->sc_enaddr)); + sc->sc_r1 = (struct lereg1 *) + obio_alloc(ca->ca_paddr, OBIO_AMD_ETHER_SIZE); + sc->sc_mem = dvma_malloc(MEMSIZE); + sc->sc_conf3 = LE_C3_BSWP; + sc->sc_addr = (u_long)sc->sc_mem & 0xffffff; + sc->sc_memsize = MEMSIZE; - /* - * Initialize and attach S/W interface - */ - ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = lecd.cd_name; - ifp->if_start = lestart; - ifp->if_ioctl = leioctl; - ifp->if_watchdog = lewatchdog; - ifp->if_flags = - IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; + idprom_etheraddr(sc->sc_arpcom.ac_enaddr); -#if LANCE_REVC_BUG == 0 - /* The work-around precludes multicast... */ - ifp->if_flags |= IFF_MULTICAST; -#endif + 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; - /* Attach the interface. */ - if_attach(ifp); - ether_ifattach(ifp); + sc->sc_arpcom.ac_if.if_name = lecd.cd_name; + leconfig(sc); -#if NBPFILTER > 0 - bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); -#endif + /* Install interrupt handler. */ + isr_add_autovect(leintr, (void *)sc, ca->ca_intpri); } -void -lereset(sc) - struct le_softc *sc; -{ - - leinit(sc); -} - -void -lewatchdog(unit) - short unit; -{ - struct le_softc *sc = lecd.cd_devs[unit]; - - log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); - ++sc->sc_if.if_oerrors; - lereset(sc); -} - -/* LANCE initialization block set up. */ -void -lememinit(sc) - register struct le_softc *sc; -{ - struct ifnet *ifp = &sc->sc_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; - - /* Set the Ethernet address (have to byte-swap) */ - for (i = 0; i < 6; i += 2) { - sc->sc_init->padr[i] = sc->sc_enaddr[i+1]; - sc->sc_init->padr[i+1] = sc->sc_enaddr[i]; - } - lesetladrf(&sc->sc_ac, 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; - } - -#ifdef DIAGNOSTIC - if (mem > (sc->sc_mem + MEMSIZE)) - panic("lememinit: used 0x%x\n", mem - sc->sc_mem); -#endif -} - -void -lestop(sc) - struct le_softc *sc; -{ - - lewrcsr(sc, 0, LE_STOP); -} - -/* - * 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_if; - int s; - register int timo; - u_long a; - - 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); - - /* Set byte swapping etc. */ - lewrcsr(sc, 3, LE_CONF3); - - /* 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 = 1000; 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("%s: card failed to initialize\n", sc->sc_dev.dv_xname); - - (void) splx(s); -} - -/* - * Controller interrupt. - */ -int -leintr(vsc) - void *vsc; -{ - register struct le_softc *sc = vsc; - register u_short isr; - - isr = lerdcsr(sc, 0); -#ifdef LEDEBUG - if (sc->sc_debug) - printf("%s: leintr entering with isr=%04x\n", - sc->sc_dev.dv_xname, 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("%s: babble\n", sc->sc_dev.dv_xname); - sc->sc_if.if_oerrors++; - } -#if 0 - if (isr & LE_CERR) { - printf("%s: collision error\n", sc->sc_dev.dv_xname); - sc->sc_if.if_collisions++; - } -#endif - if (isr & LE_MISS) { -#if 0 - printf("%s: missed packet\n", sc->sc_dev.dv_xname); -#endif - sc->sc_if.if_ierrors++; - } - if (isr & LE_MERR) { - printf("%s: memory error\n", sc->sc_dev.dv_xname); - lereset(sc); - goto out; - } - } - - if ((isr & LE_RXON) == 0) { - printf("%s: receiver disabled\n", sc->sc_dev.dv_xname); - sc->sc_if.if_ierrors++; - lereset(sc); - goto out; - } - if ((isr & LE_TXON) == 0) { - printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname); - sc->sc_if.if_oerrors++; - lereset(sc); - goto out; - } - - if (isr & LE_RINT) { - /* Reset watchdog timer. */ - sc->sc_if.if_timer = 0; - lerint(sc); - } - if (isr & LE_TINT) { - /* Reset watchdog timer. */ - sc->sc_if.if_timer = 0; - letint(sc); - } - - isr = lerdcsr(sc, 0); - } while ((isr & LE_INTR) != 0); - -#ifdef LEDEBUG - if (sc->sc_debug) - printf("%s: leintr returning with isr=%04x\n", - sc->sc_dev.dv_xname, isr); -#endif - -out: - return 1; -} - -#define NEXTTDS \ - if (++tmd == NTBUF) tmd=0, cdm=sc->sc_td; else ++cdm - -/* - * 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. - */ -void -lestart(ifp) - struct ifnet *ifp; -{ - register struct le_softc *sc = lecd.cd_devs[ifp->if_unit]; - register int tmd; - volatile struct mds *cdm; - struct mbuf *m0, *m; - u_char *buffer; - int len; - - if ((sc->sc_if.if_flags & (IFF_RUNNING | IFF_OACTIVE)) != - IFF_RUNNING) - return; - - tmd = sc->sc_last_td; - cdm = &sc->sc_td[tmd]; - - for (;;) { - if (sc->sc_no_td >= NTBUF) { - sc->sc_if.if_flags |= IFF_OACTIVE; -#ifdef LEDEBUG - if (sc->sc_debug) - printf("no_td = %d, last_td = %d\n", sc->sc_no_td, - sc->sc_last_td); -#endif - break; - } - -#ifdef LEDEBUG - if (cdm->flags & LE_OWN) { - sc->sc_if.if_flags |= IFF_OACTIVE; - printf("missing buffer, no_td = %d, last_td = %d\n", - sc->sc_no_td, sc->sc_last_td); - } -#endif - - IF_DEQUEUE(&sc->sc_if.if_snd, m); - if (!m) - break; - - ++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; - } - -#ifdef LEDEBUG - if (len > ETHER_MAX_LEN) - printf("packet length %d\n", len); -#endif - -#if NBPFILTER > 0 - if (sc->sc_if.if_bpf) - bpf_mtap(sc->sc_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); - - NEXTTDS; - } - - sc->sc_last_td = tmd; -} - -void -letint(sc) - struct le_softc *sc; -{ - register int tmd = (sc->sc_last_td - sc->sc_no_td + NTBUF) % NTBUF; - volatile struct mds *cdm; - - cdm = &sc->sc_td[tmd]; - if (cdm->flags & LE_OWN) { - /* Race condition with loop below. */ -#ifdef LEDEBUG - if (sc->sc_debug) - printf("%s: extra tint\n", sc->sc_dev.dv_xname); -#endif - return; - } - - sc->sc_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_if.if_opackets++; - --sc->sc_no_td; - if (cdm->mcnt & (LE_TBUFF | LE_UFLO | LE_LCOL | LE_LCAR | LE_RTRY)) { - if (cdm->mcnt & LE_TBUFF) - printf("%s: transmit buffer error\n", sc->sc_dev.dv_xname); - if ((cdm->mcnt & (LE_TBUFF | LE_UFLO)) == LE_UFLO) - printf("%s: underflow\n", sc->sc_dev.dv_xname); - if (cdm->mcnt & LE_UFLO) { - lereset(sc); - return; - } -#if 0 - if (cdm->mcnt & LE_LCOL) { - printf("%s: late collision\n", sc->sc_dev.dv_xname); - sc->sc_if.if_collisions++; - } - if (cdm->mcnt & LE_LCAR) - printf("%s: lost carrier\n", sc->sc_dev.dv_xname); - if (cdm->mcnt & LE_RTRY) { - printf("%s: excessive collisions, tdr %d\n", - sc->sc_dev.dv_xname, cdm->flags & 0x1ff); - sc->sc_if.if_collisions += 16; - } -#endif - } else if (cdm->flags & LE_ONE) - sc->sc_if.if_collisions++; - else if (cdm->flags & LE_MORE) - /* Real number is unknown. */ - sc->sc_if.if_collisions += 2; - NEXTTDS; - } while ((cdm->flags & LE_OWN) == 0); - - lestart(&sc->sc_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(sc) - struct le_softc *sc; -{ - register int rmd = sc->sc_last_rd; - volatile struct mds *cdm; - - cdm = &sc->sc_rd[rmd]; - if (cdm->flags & LE_OWN) { - /* Race condition with loop below. */ -#ifdef LEDEBUG - if (sc->sc_debug) - printf("%s: extra rint\n", sc->sc_dev.dv_xname); -#endif - return; - } - - /* Process all buffers with valid data. */ - do { - if (cdm->flags & LE_ERR) { -#ifdef LEDEBUG - /* - * XXX - These happen a LOT on the Sun3/50 so - * it is really NOT appropriate to print them. - */ - printf("%s: error, cdm->flags=%b\n", - sc->sc_dev.dv_xname, cdm->flags, RMD_BITS); -#endif - sc->sc_if.if_ierrors++; - } 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("%s: chained buffer\n", sc->sc_dev.dv_xname); - 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); - } - - cdm->bcnt = -BUFSIZE; - 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 ifnet *ifp; - struct mbuf *m; - struct ether_header *eh; - - ifp = &sc->sc_if; - - if ((len < ETHERMIN) || (len > ETHER_MAX_LEN)) { - log(LOG_ERR, "%s: invalid packet size %d; dropping\n", - sc->sc_dev.dv_xname, len); - ifp->if_ierrors++; - return; - } - - /* Pull packet off interface. */ - m = leget(buf, len, ifp); - if (m == 0) { - ifp->if_ierrors++; - return; - } - - ifp->if_ipackets++; - - /* We assume that the header fit entirely in one mbuf. */ - eh = mtod(m, struct ether_header *); - -#if NBPFILTER > 0 - /* - * Check if there's a BPF listener on this interface. - * If so, hand off the raw packet to BPF. - */ - if (ifp->if_bpf) { - /* Note that BPF may see garbage! (if LANCE_REVC_BUG) */ - bpf_mtap(ifp->if_bpf, m); - } -#endif /* NBPFILTER */ - -#if LANCE_REVC_BUG - /* - * Check for unreported packet errors. Rev C of the LANCE chip - * has a bug which can cause "random" bytes to be prepended to - * the start of the packet. The work-around is to make sure that - * the Ethernet destination address in the packet matches our - * address (or the broadcast address). Must ALWAYS check! - */ - if (bcmp(eh->ether_dhost, sc->sc_enaddr, 6) && - bcmp(eh->ether_dhost, etherbroadcastaddr, 6)) - { - /* Not for us. */ - m_freem(m); - return; - } -#else /* LANCE_REVC_BUG */ -#if NBPFILTER > 0 - if (ifp->if_bpf) { - /* - * 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 ((ifp->if_flags & IFF_PROMISC) && - (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ - bcmp(eh->ether_dhost, sc->sc_enaddr, 6) != 0) - { - m_freem(m); - return; - } - } -#endif /* NBPFILTER */ -#endif /* LANCE_REVC_BUG */ - - /* Pass the packet up, with the ether header sort-of removed. */ - m_adj(m, sizeof(struct ether_header)); - ether_input(ifp, 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; - int len; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == 0) - return 0; - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = totlen; - len = MHLEN; - top = 0; - mp = ⊤ - - while (totlen > 0) { - if (top) { - MGET(m, M_DONTWAIT, MT_DATA); - if (m == 0) { - m_freem(top); - return 0; - } - len = MLEN; - } - if (totlen >= MINCLSIZE) { - MCLGET(m, M_DONTWAIT); - if (m->m_flags & M_EXT) - len = MCLBYTES; - } - m->m_len = len = min(totlen, len); - bcopy((caddr_t)buf, mtod(m, caddr_t), len); - buf += len; - totlen -= len; - *mp = m; - mp = &m->m_next; - } - - return top; -} - -/* - * Process an ioctl request. - */ -int -leioctl(ifp, cmd, data) - register struct ifnet *ifp; - u_long cmd; - caddr_t data; -{ - struct le_softc *sc = lecd.cd_devs[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); - arp_ifinit(&sc->sc_ac, ifa); - 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_enaddr); - else - bcopy(ina->x_host.c_host, - sc->sc_enaddr, - sizeof(sc->sc_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_ac): - ether_delmulti(ifr, &sc->sc_ac); - - 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) - struct arpcom *ac; - u_long *af; -{ - struct ifnet *ifp = &ac->ac_if; - 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 an - * index into the 64 bit logical address filter. The high order bit - * selects the word, while the rest of the bits select the bit within - * the word. - */ - - if (ifp->if_flags & IFF_PROMISC) { - ifp->if_flags |= IFF_ALLMULTI; - af[0] = af[1] = 0xffffffff; - return; - } - - af[0] = af[1] = 0; - ETHER_FIRST_MULTI(step, ac, enm); - while (enm != NULL) { - if (bcmp(enm->enm_addrlo, 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.) - */ - ifp->if_flags |= IFF_ALLMULTI; - af[0] = af[1] = 0xffffffff; - return; - } - - cp = enm->enm_addrlo; - crc = 0xffffffff; - for (len = sizeof(enm->enm_addrlo); --len >= 0;) { - c = *cp++; - for (i = 8; --i >= 0;) { - if ((crc & 0x01) ^ (c & 0x01)) { - crc >>= 1; - crc ^= 0x6db88320 | 0x80000000; - } else - crc >>= 1; - c >>= 1; - } - } - /* Just want the 6 most significant bits. */ - crc >>= 26; - - /* Turn on the corresponding bit in the filter. */ - af[crc >> 5] |= 1 << ((crc & 0x1f) ^ 0); - - ETHER_NEXT_MULTI(step, enm); - } - ifp->if_flags &= ~IFF_ALLMULTI; -} +#include diff --git a/sys/arch/sun3/dev/if_lereg.h b/sys/arch/sun3/dev/if_lereg.h index 5d51af3098c6..07580beed4c6 100644 --- a/sys/arch/sun3/dev/if_lereg.h +++ b/sys/arch/sun3/dev/if_lereg.h @@ -1,127 +1,46 @@ -/* $NetBSD: if_lereg.h,v 1.10 1995/01/24 05:50:52 gwr Exp $ */ +/* $NetBSD: if_lereg.h,v 1.11 1995/12/10 08:46:07 mycroft Exp $ */ /* - * LANCE Ethernet driver header file + * Copyright (c) 1982, 1990 The Regents of the University of California. + * All rights reserved. * - * Copyright (c) 1995 Gordon W. Ross - * Copyright (c) 1994 Charles Hannum. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * - * Copyright (C) 1993, Paul Richards. This software may be used, modified, - * copied, distributed, and sold, in both source and binary form provided - * that the above copyright and these terms are retained. Under no - * circumstances is the author responsible for the proper functioning - * of this software, nor does the author assume any responsibility - * for damages incurred with its use. + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_lereg.h 7.1 (Berkeley) 5/8/90 */ -/* Declarations specific to this driver */ -#define NTBUF 2 -#define TLEN 1 -#define NRBUF 8 -#define RLEN 3 -#define BUFSIZE 1536 - #define MEMSIZE 0x4000 -/* Local Area Network Controller for Ethernet (LANCE) registers */ -struct le_regs { - u_short lereg_data; /* data port */ - u_short lereg_addr; /* address port */ +/* + * LANCE registers. + */ +struct lereg1 { + volatile u_int16_t ler1_rdp; /* data port */ + volatile u_int16_t ler1_rap; /* register select port */ }; - -/* - * Control and status bits - */ -#define LE_SERR 0x8000 -#define LE_BABL 0x4000 -#define LE_CERR 0x2000 -#define LE_MISS 0x1000 -#define LE_MERR 0x0800 -#define LE_RINT 0x0400 -#define LE_TINT 0x0200 -#define LE_IDON 0x0100 -#define LE_INTR 0x0080 -#define LE_INEA 0x0040 -#define LE_RXON 0x0020 -#define LE_TXON 0x0010 -#define LE_TDMD 0x0008 -#define LE_STOP 0x0004 -#define LE_STRT 0x0002 -#define LE_INIT 0x0001 - -#define LE_BSWP 0x0004 -#define LE_ACON 0x0002 -#define LE_BCON 0x0001 - -/* - * 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 */ - - -/* DEPCA-specific definitions */ -#define DEPCA_CSR 0x0 -#define DEPCA_CSR_SHE 0x80 /* Shared memory enabled */ -#define DEPCA_CSR_SWAP32 0x40 /* Byte swapped */ -#define DEPCA_CSR_DUM 0x08 /* rev E compatibility */ -#define DEPCA_CSR_IM 0x04 /* Interrupt masked */ -#define DEPCA_CSR_IEN 0x02 /* Interrupt enabled */ -#define DEPCA_CSR_NORMAL \ - (DEPCA_CSR_SHE | DEPCA_CSR_DUM | DEPCA_CSR_IEN) - -#define DEPCA_ADP 0xc diff --git a/sys/arch/sun3/dev/if_levar.h b/sys/arch/sun3/dev/if_levar.h new file mode 100644 index 000000000000..17fea04312ea --- /dev/null +++ b/sys/arch/sun3/dev/if_levar.h @@ -0,0 +1,82 @@ +/* $NetBSD: if_levar.h,v 1.1 1995/12/10 08:46:08 mycroft Exp $ */ + +/*- + * Copyright (c) 1995 Charles M. Hannum. All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_le.c 8.2 (Berkeley) 11/16/93 + */ + +/* + * Ethernet software status per interface. + * + * Each interface is referenced by a network interface structure, + * arpcom.ac_if, which the routing code uses to locate the interface. + * This structure contains the output queue for the interface, its address, ... + */ +struct le_softc { + struct device sc_dev; /* base structure */ + struct arpcom sc_arpcom; /* Ethernet common part */ + + void (*sc_copytodesc)(); /* Copy to descriptor */ + void (*sc_copyfromdesc)(); /* Copy from descriptor */ + + void (*sc_copytobuf)(); /* Copy to buffer */ + void (*sc_copyfrombuf)(); /* Copy from buffer */ + void (*sc_zerobuf)(); /* and Zero bytes in buffer */ + + u_int16_t sc_conf3; /* CSR3 value */ + + void *sc_mem; /* base address of RAM -- CPU's view */ + u_long sc_addr; /* base address of RAM -- LANCE's view */ + u_long sc_memsize; /* size of RAM */ + + int sc_nrbuf; /* number of receive buffers */ + int sc_ntbuf; /* number of transmit buffers */ + int sc_last_rd; + int sc_first_td, sc_last_td, sc_no_td; + + int sc_initaddr; + int sc_rmdaddr; + int sc_tmdaddr; + int sc_rbufaddr; + int sc_tbufaddr; + +#ifdef LEDEBUG + int sc_debug; +#endif + + struct lereg1 *sc_r1; /* LANCE registers */ +};