summaryrefslogtreecommitdiff
path: root/sys/arch/sparc
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2000-11-16 15:47:58 +0000
committerJason Wright <jason@cvs.openbsd.org>2000-11-16 15:47:58 +0000
commit169456fc9063b6245205cd1cbe827606bd9a9095 (patch)
treeaf4dc804cc5a2fc9df4360954b22df0cbdc186ee /sys/arch/sparc
parent1af37a2897479a00d4af76d1f2cded525f845cc9 (diff)
- Fix the NMI problem: it seems the qec channel reset also resets the MACE, and
a race condition existed where after a qec channel reset, accesses to the MACE would cause an NMI: so wait for the MACE to come out of reset before accessing. - add ifmedia support (mainly so I can get at the link status from other code) - move some of the spl handling around (more correct) - rewrite qe_mcreset() again so that all it does is set the multicast filter - use bzero to initialize the buffers and descriptors - rearrange the MACE setup to conform to the suggestions in the datasheet
Diffstat (limited to 'sys/arch/sparc')
-rw-r--r--sys/arch/sparc/conf/files.sparc4
-rw-r--r--sys/arch/sparc/dev/qe.c194
-rw-r--r--sys/arch/sparc/dev/qereg.h5
-rw-r--r--sys/arch/sparc/dev/qevar.h5
4 files changed, 149 insertions, 59 deletions
diff --git a/sys/arch/sparc/conf/files.sparc b/sys/arch/sparc/conf/files.sparc
index 3d241ea30a5..47cf56c9d40 100644
--- a/sys/arch/sparc/conf/files.sparc
+++ b/sys/arch/sparc/conf/files.sparc
@@ -1,4 +1,4 @@
-# $OpenBSD: files.sparc,v 1.37 2000/06/28 20:20:14 mjacob Exp $
+# $OpenBSD: files.sparc,v 1.38 2000/11/16 15:47:56 jason Exp $
# $NetBSD: files.sparc,v 1.44 1997/08/31 21:29:16 pk Exp $
# @(#)files.sparc 8.1 (Berkeley) 7/19/93
@@ -112,7 +112,7 @@ device be: ifnet, ether, ifmedia
attach be at qec
file arch/sparc/dev/be.c be
-device qe: ifnet, ether
+device qe: ifnet, ether, ifmedia
attach qe at qec
file arch/sparc/dev/qe.c qe
diff --git a/sys/arch/sparc/dev/qe.c b/sys/arch/sparc/dev/qe.c
index aae3fdf200f..4962b51f6d6 100644
--- a/sys/arch/sparc/dev/qe.c
+++ b/sys/arch/sparc/dev/qe.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: qe.c,v 1.9 2000/06/18 17:36:59 jason Exp $ */
+/* $OpenBSD: qe.c,v 1.10 2000/11/16 15:47:57 jason Exp $ */
/*
- * Copyright (c) 1998 Jason L. Wright.
+ * Copyright (c) 1998, 2000 Jason L. Wright.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -50,6 +50,7 @@
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
+#include <net/if_media.h>
#include <net/netisr.h>
#ifdef INET
@@ -96,6 +97,8 @@ int qe_put __P((struct qesoftc *, int, struct mbuf *));
void qe_read __P((struct qesoftc *, int, int));
struct mbuf * qe_get __P((struct qesoftc *, int, int));
void qe_mcreset __P((struct qesoftc *));
+void qe_ifmedia_sts __P((struct ifnet *, struct ifmediareq *));
+int qe_ifmedia_upd __P((struct ifnet *));
struct cfdriver qe_cd = {
NULL, "qe", DV_IFNET
@@ -163,6 +166,16 @@ qeattach(parent, self, aux)
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS |
IFF_MULTICAST;
+ ifmedia_init(&sc->sc_ifmedia, IFM_IMASK,
+ qe_ifmedia_upd, qe_ifmedia_sts);
+ ifmedia_add(&sc->sc_ifmedia,
+ IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0), 0, NULL);
+ ifmedia_add(&sc->sc_ifmedia,
+ IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, 0), 0, NULL);
+ ifmedia_add(&sc->sc_ifmedia,
+ IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 0, NULL);
+ ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO);
+
/* Attach the interface. */
if_attach(ifp);
ether_ifattach(ifp);
@@ -248,17 +261,21 @@ qestop(sc)
{
struct qe_cregs *cr = sc->sc_cr;
struct qe_mregs *mr = sc->sc_mr;
- int tries;
+ int n;
- tries = 200;
mr->biucc = QE_MR_BIUCC_SWRST;
- while ((mr->biucc & QE_MR_BIUCC_SWRST) && --tries)
+ for (n = 200; n > 0; n--) {
+ if ((mr->biucc & QE_MR_BIUCC_SWRST) == 0)
+ break;
DELAY(20);
+ }
- tries = 200;
cr->ctrl = QE_CR_CTRL_RESET;
- while ((cr->ctrl & QE_CR_CTRL_RESET) && --tries)
+ for (n = 200; n > 0; n--) {
+ if ((cr->ctrl & QE_CR_CTRL_RESET) == 0)
+ break;
DELAY(20);
+ }
}
/*
@@ -268,12 +285,8 @@ void
qereset(sc)
struct qesoftc *sc;
{
- int s;
-
- s = splnet();
qestop(sc);
qeinit(sc);
- splx(s);
}
void
@@ -281,11 +294,14 @@ qewatchdog(ifp)
struct ifnet *ifp;
{
struct qesoftc *sc = ifp->if_softc;
+ int s;
log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
++sc->sc_arpcom.ac_if.if_oerrors;
+ s = splnet();
qereset(sc);
+ splx(s);
}
/*
@@ -422,7 +438,6 @@ qe_eint(sc, why)
rst = 1;
}
-
if (why & QE_CR_STAT_LCOLL) {
printf("%s: late tx transmission\n", sc->sc_dev.dv_xname);
ifp->if_oerrors++;
@@ -650,10 +665,15 @@ qeioctl(ifp, cmd, data)
* Multicast list has changed; set the hardware filter
* accordingly.
*/
- qe_mcreset(sc);
+ if (ifp->if_flags & IFF_UP)
+ qeinit(sc);
error = 0;
}
break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
+ break;
default:
if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
splx(s);
@@ -677,29 +697,30 @@ qeinit(sc)
int s = splimp();
int i;
+ qestop(sc);
+
/*
* Allocate descriptor ring and buffers, if not already done
*/
if (sc->sc_desc == NULL)
sc->sc_desc_dva = (struct qe_desc *) dvma_malloc(
sizeof(struct qe_desc), &sc->sc_desc, M_NOWAIT);
+ bzero(sc->sc_desc, sizeof(struct qe_desc));
+
if (sc->sc_bufs == NULL)
sc->sc_bufs_dva = (struct qe_bufs *) dvma_malloc(
sizeof(struct qe_bufs), &sc->sc_bufs, M_NOWAIT);
-
- for (i = 0; i < QE_TX_RING_MAXSIZE; i++) {
+ bzero(sc->sc_bufs, sizeof(struct qe_bufs));
+
+ for (i = 0; i < QE_TX_RING_MAXSIZE; i++)
sc->sc_desc->qe_txd[i].tx_addr =
(u_int32_t) &sc->sc_bufs_dva->tx_buf[i % QE_TX_RING_SIZE][0];
- sc->sc_desc->qe_txd[i].tx_flags = 0;
- }
for (i = 0; i < QE_RX_RING_MAXSIZE; i++) {
sc->sc_desc->qe_rxd[i].rx_addr =
(u_int32_t) &sc->sc_bufs_dva->rx_buf[i % QE_RX_RING_SIZE][0];
if ((i / QE_RX_RING_SIZE) == 0)
sc->sc_desc->qe_rxd[i].rx_flags =
QE_RXD_OWN | QE_RXD_LENGTH;
- else
- sc->sc_desc->qe_rxd[i].rx_flags = 0;
}
cr->rxds = (u_int32_t) &sc->sc_desc_dva->qe_rxd[0];
@@ -708,49 +729,52 @@ qeinit(sc)
sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
sc->sc_last_rd = 0;
- qestop(sc);
-
cr->rimask = 0;
cr->timask = 0;
cr->qmask = 0;
cr->mmask = QE_CR_MMASK_RXCOLL;
- cr->rxwbufptr = cr->rxrbufptr = sc->sc_channel * qec->sc_msize;
- cr->txwbufptr = cr->txrbufptr = cr->rxrbufptr + qec->sc_rsize;
cr->ccnt = 0;
cr->pipg = 0;
+ cr->rxwbufptr = cr->rxrbufptr = sc->sc_channel * qec->sc_msize;
+ cr->txwbufptr = cr->txrbufptr = cr->rxrbufptr + qec->sc_rsize;
+
+ for (i = 500; i > 0; i--) {
+ if ((mr->biucc & QE_MR_BIUCC_SWRST) == 0)
+ break;
+ DELAY(10);
+ }
- mr->phycc = QE_MR_PHYCC_ASEL;
- mr->xmtfc = QE_MR_XMTFC_APADXMT;
- mr->rcvfc = 0;
- mr->imr = QE_MR_IMR_CERRM | QE_MR_IMR_RCVINTM;
mr->biucc = QE_MR_BIUCC_BSWAP | QE_MR_BIUCC_64TS;
mr->fifofc = QE_MR_FIFOCC_TXF16 | QE_MR_FIFOCC_RXF32 |
QE_MR_FIFOCC_RFWU | QE_MR_FIFOCC_TFWU;
- mr->plscc = QE_MR_PLSCC_TP;
+ mr->xmtfc = QE_MR_XMTFC_APADXMT;
+ mr->rcvfc = 0;
+ mr->imr = QE_MR_IMR_CERRM | QE_MR_IMR_RCVINTM;
+
+ qe_ifmedia_upd(ifp);
mr->iac = QE_MR_IAC_ADDRCHG | QE_MR_IAC_PHYADDR;
+ for (i = 100; i > 0; i--) {
+ if ((mr->iac & QE_MR_IAC_ADDRCHG) == 0)
+ break;
+ DELAY(2);
+ }
mr->padr = sc->sc_arpcom.ac_enaddr[0];
mr->padr = sc->sc_arpcom.ac_enaddr[1];
mr->padr = sc->sc_arpcom.ac_enaddr[2];
mr->padr = sc->sc_arpcom.ac_enaddr[3];
mr->padr = sc->sc_arpcom.ac_enaddr[4];
mr->padr = sc->sc_arpcom.ac_enaddr[5];
-
- mr->iac = QE_MR_IAC_ADDRCHG | QE_MR_IAC_LOGADDR;
- for (i = 0; i < 8; i++)
- mr->ladrf = 0;
+ qe_mcreset(sc);
mr->iac = 0;
- delay(50000);
- if ((mr->phycc & QE_MR_PHYCC_LNKFL) == QE_MR_PHYCC_LNKFL)
- printf("%s: no carrier\n", sc->sc_dev.dv_xname);
-
i = mr->mpc; /* cleared on read */
- qe_mcreset(sc);
-
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
+
+ mr->maccc = QE_MR_MACCC_ENXMT | QE_MR_MACCC_ENRCV |
+ ((ifp->if_flags & IFF_PROMISC) ? QE_MR_MACCC_PROM : 0);
splx(s);
}
@@ -906,18 +930,16 @@ qe_mcreset(sc)
u_int8_t octet, *ladrp = (u_int8_t *)&hash[0];
int i, j;
- if (ifp->if_flags & IFF_PROMISC) {
- mr->maccc = QE_MR_MACCC_PROM | QE_MR_MACCC_ENXMT |
- QE_MR_MACCC_ENRCV;
- return;
- }
-
+allmulti:
if (ifp->if_flags & IFF_ALLMULTI) {
mr->iac = QE_MR_IAC_ADDRCHG | QE_MR_IAC_LOGADDR;
+ for (i = 100; i > 0; i--) {
+ if ((mr->iac & QE_MR_IAC_ADDRCHG) == 0)
+ break;
+ DELAY(2);
+ }
for (i = 0; i < 8; i++)
mr->ladrf = 0xff;
- mr->iac = 0;
- mr->maccc = QE_MR_MACCC_ENXMT | QE_MR_MACCC_ENRCV;
return;
}
@@ -937,12 +959,8 @@ qe_mcreset(sc)
* which the range is big enough to require
* all bits set.)
*/
- mr->iac = QE_MR_IAC_ADDRCHG | QE_MR_IAC_LOGADDR;
- for (i = 0; i < 8; i++)
- mr->ladrf = 0xff;
- mr->iac = 0;
ifp->if_flags |= IFF_ALLMULTI;
- break;
+ goto allmulti;
}
crc = 0xffffffff;
@@ -967,9 +985,79 @@ qe_mcreset(sc)
}
mr->iac = QE_MR_IAC_ADDRCHG | QE_MR_IAC_LOGADDR;
+ for (i = 100; i > 0; i--) {
+ if ((mr->iac & QE_MR_IAC_ADDRCHG) == 0)
+ break;
+ DELAY(2);
+ }
for (i = 0; i < 8; i++)
mr->ladrf = ladrp[i];
- mr->iac = 0;
+}
+
+void
+qe_ifmedia_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct qesoftc *sc = (struct qesoftc *)ifp->if_softc;
+ struct qe_mregs *mr = sc->sc_mr;
+ u_int8_t plscc, phycc;
+
+ plscc = mr->plscc;
+ phycc = mr->phycc;
+
+ if (phycc & QE_MR_PHYCC_ASEL)
+ ifmr->ifm_active = IFM_ETHER | IFM_AUTO;
+ else {
+ switch (plscc & QE_MR_PLSCC_PORTMASK) {
+ case QE_MR_PLSCC_TP:
+ ifmr->ifm_active = IFM_ETHER | IFM_10_T;
+ break;
+ case QE_MR_PLSCC_AUI:
+ ifmr->ifm_active = IFM_ETHER | IFM_10_5;
+ break;
+ case QE_MR_PLSCC_DAI:
+ case QE_MR_PLSCC_GPSI:
+ /* ... */
+ break;
+ }
+ }
+
+ if ((phycc & QE_MR_PHYCC_DLNKTST) == 0) {
+ ifmr->ifm_status |= IFM_AVALID;
+ if (phycc & QE_MR_PHYCC_LNKFL)
+ ifmr->ifm_status &= ~IFM_ACTIVE;
+ else
+ ifmr->ifm_status |= IFM_ACTIVE;
+ }
+}
+
+int
+qe_ifmedia_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct qesoftc *sc = (struct qesoftc *)ifp->if_softc;
+ struct qe_mregs *mr = sc->sc_mr;
+ int media = sc->sc_ifmedia.ifm_media;
+ u_int8_t plscc, phycc;
+
+ if (IFM_TYPE(media) != IFM_ETHER)
+ return (EINVAL);
+
+ plscc = mr->plscc & (~QE_MR_PLSCC_PORTMASK);
+ phycc = mr->phycc & (~QE_MR_PHYCC_ASEL);
+
+ if (IFM_SUBTYPE(media) == IFM_AUTO)
+ phycc |= QE_MR_PHYCC_ASEL;
+ else if (IFM_SUBTYPE(media) == IFM_10_T)
+ plscc |= QE_MR_PLSCC_TP;
+ else if (IFM_SUBTYPE(media) == IFM_10_5)
+ plscc |= QE_MR_PLSCC_AUI;
+ else
+ return (EINVAL);
+
+ mr->plscc = plscc;
+ mr->phycc = phycc;
- mr->maccc = QE_MR_MACCC_ENXMT | QE_MR_MACCC_ENRCV;
+ return (0);
}
diff --git a/sys/arch/sparc/dev/qereg.h b/sys/arch/sparc/dev/qereg.h
index f70e363ba63..d43c594e58d 100644
--- a/sys/arch/sparc/dev/qereg.h
+++ b/sys/arch/sparc/dev/qereg.h
@@ -1,7 +1,7 @@
-/* $OpenBSD: qereg.h,v 1.4 1999/03/12 18:56:18 jason Exp $ */
+/* $OpenBSD: qereg.h,v 1.5 2000/11/16 15:47:57 jason Exp $ */
/*
- * Copyright (c) 1998 Jason L. Wright.
+ * Copyright (c) 1998, 2000 Jason L. Wright.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -255,6 +255,7 @@ struct qe_mregs {
/* qe_mregs.plscc: pls config control. */
#define QE_MR_PLSCC_XMTSEL 0x08 /* tx mode select */
+#define QE_MR_PLSCC_PORTMASK 0x06 /* media mask */
#define QE_MR_PLSCC_GPSI 0x06 /* use gpsi connector */
#define QE_MR_PLSCC_DAI 0x04 /* use dai connector */
#define QE_MR_PLSCC_TP 0x02 /* use twistedpair connector */
diff --git a/sys/arch/sparc/dev/qevar.h b/sys/arch/sparc/dev/qevar.h
index e5dd63681d3..de3da606964 100644
--- a/sys/arch/sparc/dev/qevar.h
+++ b/sys/arch/sparc/dev/qevar.h
@@ -1,7 +1,7 @@
-/* $OpenBSD: qevar.h,v 1.3 1999/02/24 06:57:45 jason Exp $ */
+/* $OpenBSD: qevar.h,v 1.4 2000/11/16 15:47:57 jason Exp $ */
/*
- * Copyright (c) 1998 Jason L. Wright.
+ * Copyright (c) 1998, 2000 Jason L. Wright.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,4 +48,5 @@ struct qesoftc {
int sc_no_td, sc_first_td, sc_last_td;
int sc_last_rd;
+ struct ifmedia sc_ifmedia;
};