diff options
author | Jason Downs <downsj@cvs.openbsd.org> | 1997-08-08 08:27:49 +0000 |
---|---|---|
committer | Jason Downs <downsj@cvs.openbsd.org> | 1997-08-08 08:27:49 +0000 |
commit | c6af50ae96c114059441edde31a2879102e32d99 (patch) | |
tree | e77d44cd72b4d881fb3461d76bdd50f77adc0966 /sys/arch/sparc/dev/if_le.c | |
parent | c1492b0f5209b759b0ab6624db56b310c28e48e2 (diff) |
Mostly sync to NetBSD-current 970804.
GENERIC currently compiles and runs; some devices (isp) are not complete and
not yet enabled.
Diffstat (limited to 'sys/arch/sparc/dev/if_le.c')
-rw-r--r-- | sys/arch/sparc/dev/if_le.c | 378 |
1 files changed, 329 insertions, 49 deletions
diff --git a/sys/arch/sparc/dev/if_le.c b/sys/arch/sparc/dev/if_le.c index 4db240f0f62..b0bf63e56e6 100644 --- a/sys/arch/sparc/dev/if_le.c +++ b/sys/arch/sparc/dev/if_le.c @@ -1,6 +1,8 @@ -/* $NetBSD: if_le.c,v 1.35.4.1 1996/07/17 01:46:00 jtc Exp $ */ +/* $OpenBSD: if_le.c,v 1.7 1997/08/08 08:25:12 downsj Exp $ */ +/* $NetBSD: if_le.c,v 1.49 1997/07/07 16:28:44 pk Exp $ */ /*- + * Copyright (c) 1997 Jason R. Thorpe. All rights reserved. * Copyright (c) 1996 * The President and Fellows of Harvard College. All rights reserved. * Copyright (c) 1995 Charles M. Hannum. All rights reserved. @@ -22,6 +24,8 @@ * must display the following acknowledgement: * This product includes software developed by Aaron Brown and * Harvard University. + * This product includes software developed for the NetBSD Project + * by Jason R. Thorpe. * 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 @@ -54,10 +58,18 @@ #include <sys/malloc.h> #include <net/if.h> +#if defined(__NetBSD__) +#include <net/if_ether.h> +#include <net/if_media.h> +#endif /* __NetBSD__ */ #ifdef INET #include <netinet/in.h> +#if defined(__NetBSD__) +#include <netinet/if_inarp.h> +#else #include <netinet/if_ether.h> +#endif /* __NetBSD__ */ #endif #include <machine/autoconf.h> @@ -66,6 +78,7 @@ #include <sparc/dev/sbusvar.h> #include <sparc/dev/dmareg.h> #include <sparc/dev/dmavar.h> +#include <sparc/dev/lebuffervar.h> #include <dev/ic/am7990reg.h> #include <dev/ic/am7990var.h> @@ -73,7 +86,11 @@ #include <sparc/dev/if_lereg.h> #include <sparc/dev/if_levar.h> +#if defined(__NetBSD__) +int lematch __P((struct device *, struct cfdata *, void *)); +#else int lematch __P((struct device *, void *, void *)); +#endif /* __NetBSD__ */ void leattach __P((struct device *, struct device *, void *)); #if defined(SUN4M) /* XXX */ @@ -89,25 +106,41 @@ myleintr(arg) if (lesc->sc_dma->sc_regs->csr & D_ERR_PEND) return ledmaintr(lesc->sc_dma); - /* - * XXX There is a bug somewhere in the interrupt code that causes stray - * ethernet interrupts under high network load. This bug has been - * impossible to locate, so until it is found, we just ignore stray - * interrupts, as they do not in fact correspond to dropped packets. - */ - - /* return */ am7990_intr(arg); - return 1; + return (am7990_intr(arg)); } #endif +#if defined(SUN4M) +#if defined(__NetBSD__) +/* + * Media types supported by the Sun4m. + */ +int lemediasun4m[] = { + IFM_ETHER|IFM_10_T, + IFM_ETHER|IFM_10_5, + IFM_ETHER|IFM_AUTO, +}; +#define NLEMEDIASUN4M (sizeof(lemediasun4m) / sizeof(lemediasun4m[0])) +#endif /* __NetBSD__ */ + +void lesetutp __P((struct am7990_softc *)); +void lesetaui __P((struct am7990_softc *)); + +int lemediachange __P((struct am7990_softc *)); +#if defined(__NetBSD__) +void lemediastatus __P((struct am7990_softc *, struct ifmediareq *)); +#endif /* __NetBSD__ */ +#endif /* SUN4M */ + struct cfattach le_ca = { sizeof(struct le_softc), lematch, leattach }; 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 lehwreset __P((struct am7990_softc *)); hide void lehwinit __P((struct am7990_softc *)); +hide void lenocarrier __P((struct am7990_softc *)); hide void lewrcsr(sc, port, val) @@ -115,9 +148,21 @@ lewrcsr(sc, port, val) u_int16_t port, val; { register struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; +#if defined(SUN4M) + volatile u_int16_t discard; +#endif ler1->ler1_rap = port; ler1->ler1_rdp = val; +#if defined(SUN4M) + /* + * We need to flush the Sbus->Mbus write buffers. This can most + * easily be accomplished by reading back the register that we + * just wrote (thanks to Chris Torek for this solution). + */ + if (CPU_ISSUN4M) + discard = ler1->ler1_rdp; +#endif } hide u_int16_t @@ -133,6 +178,109 @@ lerdcsr(sc, port) return (val); } +#if defined(SUN4M) +void +lesetutp(sc) + struct am7990_softc *sc; +{ + struct le_softc *lesc = (struct le_softc *)sc; + + lesc->sc_dma->sc_regs->csr |= DE_AUI_TP; + delay(20000); /* must not touch le for 20ms */ +} + +void +lesetaui(sc) + struct am7990_softc *sc; +{ + struct le_softc *lesc = (struct le_softc *)sc; + + lesc->sc_dma->sc_regs->csr &= ~DE_AUI_TP; + delay(20000); /* must not touch le for 20ms */ +} + +int +lemediachange(sc) + struct am7990_softc *sc; +{ +#if defined(__NetBSD__) + struct ifmedia *ifm = &sc->sc_media; + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return (EINVAL); + + /* + * Switch to the selected media. If autoselect is + * set, we don't really have to do anything. We'll + * switch to the other media when we detect loss of + * carrier. + */ + switch (IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_10_T: + lesetutp(sc); + break; + + case IFM_10_5: + lesetaui(sc); + break; + + case IFM_AUTO: + break; + + default: + return (EINVAL); + } +#else + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + + if (ifp->if_flags & IFF_LINK0) + lesetutp(sc); + else if (ifp->if_flags & IFF_LINK1) + lesetaui(sc); +#endif /* __NetBSD__ */ + return (0); +} + +#if defined(__NetBSD__) +void +lemediastatus(sc, ifmr) + struct am7990_softc *sc; + struct ifmediareq *ifmr; +{ + struct le_softc *lesc = (struct le_softc *)sc; + + if (lesc->sc_dma == NULL) + return; + + /* + * Notify the world which media we're currently using. + */ + if (lesc->sc_dma->sc_regs->csr & DE_AUI_TP) + ifmr->ifm_active = IFM_ETHER|IFM_10_T; + else + ifmr->ifm_active = IFM_ETHER|IFM_10_5; +} +#endif /* __NetBSD__ */ +#endif /* SUN4M */ + +hide void +lehwreset(sc) + struct am7990_softc *sc; +{ +#if defined(SUN4M) + struct le_softc *lesc = (struct le_softc *)sc; + + /* + * Reset DMA channel. + */ + if (CPU_ISSUN4M && lesc->sc_dma) { + DMA_RESET(lesc->sc_dma); + lesc->sc_dma->sc_regs->en_bar = lesc->sc_laddr & 0xff000000; + DMA_ENINTR(lesc->sc_dma); + } +#endif +} + hide void lehwinit(sc) struct am7990_softc *sc; @@ -140,25 +288,100 @@ lehwinit(sc) #if defined(SUN4M) struct le_softc *lesc = (struct le_softc *)sc; + /* + * Make sure we're using the currently-enabled media type. + * XXX Actually, this is probably unnecessary, now. + */ if (CPU_ISSUN4M && lesc->sc_dma) { +#if defined(__NetBSD__) + switch (IFM_SUBTYPE(sc->sc_media.ifm_cur->ifm_media)) { + case IFM_10_T: + lesetutp(sc); + break; + + case IFM_10_5: + lesetaui(sc); + break; + } +#else struct ifnet *ifp = &sc->sc_arpcom.ac_if; if (ifp->if_flags & IFF_LINK0) - lesc->sc_dma->sc_regs->csr |= DE_AUI_TP; + lesetutp(sc); else if (ifp->if_flags & IFF_LINK1) - lesc->sc_dma->sc_regs->csr &= ~DE_AUI_TP; - - delay(20000); /* must not touch le for 20ms */ + lesetaui(sc); +#endif /* __NetBSD__ */ } #endif } +hide void +lenocarrier(sc) + struct am7990_softc *sc; +{ +#if defined(SUN4M) + struct le_softc *lesc = (struct le_softc *)sc; +#if !defined(__NetBSD__) + struct ifnet *ifp = &sc->sc_arpcom.ac_if; +#endif /* __NetBSD__ */ + + if (CPU_ISSUN4M && lesc->sc_dma) { + /* + * Check if the user has requested a certain cable type, and + * if so, honor that request. + */ + printf("%s: lost carrier on ", sc->sc_dev.dv_xname); + if (lesc->sc_dma->sc_regs->csr & DE_AUI_TP) { + printf("UTP port"); +#if defined(__NetBSD__) + switch (IFM_SUBTYPE(sc->sc_media.ifm_media)) { + case IFM_10_5: + case IFM_AUTO: + printf(", switching to AUI port"); + lesetaui(sc); + } +#else + if (!(ifp->if_flags & IFF_LINK0)) { + printf(", switching to AUI port"); + lesetaui(sc); + } +#endif /* __NetBSD__ */ + } else { + printf("AUI port"); +#if defined(__NetBSD__) + switch (IFM_SUBTYPE(sc->sc_media.ifm_media)) { + case IFM_10_T: + case IFM_AUTO: + printf(", switching to UTP port"); + lesetutp(sc); + } +#else + if (!(ifp->if_flags & IFF_LINK1)) { + printf(", switching to UTP port"); + lesetutp(sc); + } +#endif /* __NetBSD__ */ + } + printf("\n"); + } else +#endif + printf("%s: lost carrier\n", sc->sc_dev.dv_xname); +} + int -lematch(parent, match, aux) +#if defined(__NetBSD__) +lematch(parent, cf, aux) struct device *parent; - void *match, *aux; + struct cfdata *cf; + void *aux; { - struct cfdata *cf = match; +#else +lematch(parent, vcf, aux) + struct device *parent; + void *vcf, *aux; +{ + struct cfdata *cf = vcf; +#endif /* __NetBSD__ */ struct confargs *ca = aux; register struct romaux *ra = &ca->ca_ra; @@ -180,9 +403,11 @@ leattach(parent, self, aux) struct confargs *ca = aux; int pri; struct bootpath *bp; - u_long laddr; #if defined(SUN4C) || defined(SUN4M) int sbuschild = strncmp(parent->dv_xname, "sbus", 4) == 0; + int lebufchild = strncmp(parent->dv_xname, "lebuffer", 8) == 0; + int dmachild = strncmp(parent->dv_xname, "ledma", 5) == 0; + struct lebuf_softc *lebuf; #endif /* XXX the following declarations should be elsewhere */ @@ -195,31 +420,62 @@ leattach(parent, self, aux) pri = ca->ca_ra.ra_intr[0].int_pri; printf(" pri %d", pri); - lesc->sc_r1 = (struct lereg1 *)mapiodev(ca->ca_ra.ra_reg, 0, - sizeof(struct lereg1), - ca->ca_bustype); - sc->sc_conf3 = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON; - laddr = (u_long)dvma_malloc(MEMSIZE, &sc->sc_mem, M_NOWAIT); + lesc->sc_r1 = (struct lereg1 *) + mapiodev(ca->ca_ra.ra_reg, 0, sizeof(struct lereg1)); + +#if defined(SUN4C) || defined(SUN4M) + lebuf = NULL; + if (lebufchild) { + lebuf = (struct lebuf_softc *)parent; + } else if (sbuschild) { + struct sbus_softc *sbus = (struct sbus_softc *)parent; + struct sbusdev *sd; + + /* + * Find last "unallocated" lebuffer and pair it with + * this `le' device on the assumption that we're on + * a pre-historic ROM that doesn't establish le<=>lebuffer + * parent-child relationships. + */ + for (sd = sbus->sc_sbdev; sd != NULL; sd = sd->sd_bchain) { + if (strncmp("lebuffer", sd->sd_dev->dv_xname, 8) != 0) + continue; + if (((struct lebuf_softc *)sd->sd_dev)->attached == 0) { + lebuf = (struct lebuf_softc *)sd->sd_dev; + break; + } + } + } + if (lebuf != NULL) { + sc->sc_mem = lebuf->sc_buffer; + sc->sc_memsize = lebuf->sc_bufsiz; + sc->sc_addr = 0; /* Lance view is offset by buffer location */ + lebuf->attached = 1; + + /* That old black magic... */ + sc->sc_conf3 = getpropint(ca->ca_ra.ra_node, + "busmaster-regval", + LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON); + } else +#endif + { + u_long laddr; + laddr = (u_long)dvma_malloc(MEMSIZE, &sc->sc_mem, M_NOWAIT); #if defined (SUN4M) - if ((laddr & 0xffffff) >= (laddr & 0xffffff) + MEMSIZE) - panic("if_le: Lance buffer crosses 16MB boundary"); + if ((laddr & 0xffffff) >= (laddr & 0xffffff) + MEMSIZE) + panic("if_le: Lance buffer crosses 16MB boundary"); #endif - sc->sc_addr = laddr & 0xffffff; - sc->sc_memsize = MEMSIZE; - - myetheraddr(sc->sc_arpcom.ac_enaddr); - - 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; - - sc->sc_rdcsr = lerdcsr; - sc->sc_wrcsr = lewrcsr; - sc->sc_hwinit = lehwinit; - - am7990_config(sc); + sc->sc_addr = laddr & 0xffffff; + sc->sc_memsize = MEMSIZE; + sc->sc_conf3 = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON; +#if defined(SUN4C) || defined(SUN4M) + if (dmachild) { + lesc->sc_dma = (struct dma_softc *)parent; + lesc->sc_dma->sc_le = lesc; + lesc->sc_laddr = laddr; + } +#endif + } bp = ca->ca_ra.ra_bp; switch (ca->ca_bustype) { @@ -231,12 +487,8 @@ leattach(parent, self, aux) case BUS_SBUS: lesc->sc_sd.sd_reset = (void *)am7990_reset; if (sbuschild) { - lesc->sc_dma = NULL; sbus_establish(&lesc->sc_sd, &sc->sc_dev); } else { - lesc->sc_dma = (struct dma_softc *)parent; - lesc->sc_dma->sc_le = lesc; - lesc->sc_dma->sc_regs->en_bar = laddr & 0xff000000; /* Assume SBus is grandparent */ sbus_establish(&lesc->sc_sd, parent); } @@ -254,16 +506,44 @@ leattach(parent, self, aux) break; } +#if defined(__NetBSD__) + myetheraddr(sc->sc_enaddr); +#else + myetheraddr(sc->sc_arpcom.ac_enaddr); +#endif /* __NetBSD__ */ + + 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; + + sc->sc_rdcsr = lerdcsr; + sc->sc_wrcsr = lewrcsr; + sc->sc_hwinit = lehwinit; + sc->sc_nocarrier = lenocarrier; + sc->sc_hwreset = lehwreset; + +#if defined(SUN4M) && defined(__NetBSD__) + if (CPU_ISSUN4M && lesc->sc_dma) { + sc->sc_mediachange = lemediachange; + sc->sc_mediastatus = lemediastatus; + sc->sc_supmedia = lemediasun4m; + sc->sc_nsupmedia = NLEMEDIASUN4M; + sc->sc_defaultmedia = IFM_ETHER|IFM_AUTO; + } +#endif + + am7990_config(sc); + lesc->sc_ih.ih_fun = am7990_intr; #if defined(SUN4M) /*XXX*/ - if (CPU_ISSUN4M) + if (CPU_ISSUN4M && lesc->sc_dma) lesc->sc_ih.ih_fun = myleintr; #endif lesc->sc_ih.ih_arg = sc; intr_establish(pri, &lesc->sc_ih); /* now initialize DMA */ - if (lesc->sc_dma) { - DMA_ENINTR(lesc->sc_dma); - } + lehwreset(sc); } |