summaryrefslogtreecommitdiff
path: root/sys/arch/sparc/dev/if_le.c
diff options
context:
space:
mode:
authorJason Downs <downsj@cvs.openbsd.org>1997-08-08 08:27:49 +0000
committerJason Downs <downsj@cvs.openbsd.org>1997-08-08 08:27:49 +0000
commitc6af50ae96c114059441edde31a2879102e32d99 (patch)
treee77d44cd72b4d881fb3461d76bdd50f77adc0966 /sys/arch/sparc/dev/if_le.c
parentc1492b0f5209b759b0ab6624db56b310c28e48e2 (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.c378
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);
}