summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2013-06-04 19:10:53 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2013-06-04 19:10:53 +0000
commit90d6b0cf3afb714c27b88d247910182eadc2f01a (patch)
tree3f2666bd37285a5d2cf4a9cd5404fee771995461 /sys/dev
parentcfc344e2f6251c9ba4a4d9ae67687414c1925c78 (diff)
Prevent panic'ing on alpha after ifconfig'ing up an unplugged de interface,
by making tulip_txput() aware of whether or not the mbuf it is processing is in if_snq or not, rather than abusing the TULIP_TXPROBE_ACTIVE flag. Found the hard way by kurt@, tested on AlphaServer 1000A, I've been sleeping on this diff for about 3 years.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/if_de.c51
1 files changed, 28 insertions, 23 deletions
diff --git a/sys/dev/pci/if_de.c b/sys/dev/pci/if_de.c
index e2ce3371cd8..ccd36a16d5b 100644
--- a/sys/dev/pci/if_de.c
+++ b/sys/dev/pci/if_de.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_de.c,v 1.109 2011/07/07 20:42:56 henning Exp $ */
+/* $OpenBSD: if_de.c,v 1.110 2013/06/04 19:10:52 miod Exp $ */
/* $NetBSD: if_de.c,v 1.58 1998/01/12 09:39:58 thorpej Exp $ */
/*-
@@ -212,7 +212,7 @@ void tulip_intr_handler(tulip_softc_t * const sc, int *progress_p);
int tulip_intr_shared(void *arg);
int tulip_intr_normal(void *arg);
struct mbuf *tulip_mbuf_compress(struct mbuf *m);
-struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m);
+struct mbuf *tulip_txput(tulip_softc_t * const sc, struct mbuf *m, int);
void tulip_txput_setup(tulip_softc_t * const sc);
int tulip_ifioctl(struct ifnet * ifp, u_long cmd, caddr_t data);
void tulip_ifstart(struct ifnet *ifp);
@@ -292,7 +292,7 @@ tulip_txprobe(tulip_softc_t * const sc)
sc->tulip_flags |= TULIP_TXPROBE_ACTIVE;
TULIP_CSR_WRITE(sc, csr_command, sc->tulip_cmdmode);
TULIP_CSR_WRITE(sc, csr_intr, sc->tulip_intrmask);
- if ((m = tulip_txput(sc, m)) != NULL)
+ if ((m = tulip_txput(sc, m, 1)) != NULL)
m_freem(m);
sc->tulip_probe.probe_txprobes++;
return (1);
@@ -3225,6 +3225,10 @@ tulip_rx_intr(tulip_softc_t * const sc)
*/
TULIP_RXDESC_POSTSYNC(sc, eop, sizeof(*eop));
if ((((volatile tulip_desc_t *) eop)->d_status & (TULIP_DSTS_OWNER|TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) == (TULIP_DSTS_RxFIRSTDESC|TULIP_DSTS_RxLASTDESC)) {
+#ifdef DIAGNOSTIC
+ if (IF_IS_EMPTY(&sc->tulip_rxq))
+ panic("%s: tulip_rxq empty", sc->tulip_if.if_xname);
+#endif
IF_DEQUEUE(&sc->tulip_rxq, ms);
me = ms;
} else {
@@ -3814,7 +3818,7 @@ tulip_mbuf_compress(struct mbuf *m)
}
struct mbuf *
-tulip_txput(tulip_softc_t * const sc, struct mbuf *m)
+tulip_txput(tulip_softc_t * const sc, struct mbuf *m, int notonqueue)
{
TULIP_PERFSTART(txput)
tulip_ringinfo_t * const ri = &sc->tulip_txinfo;
@@ -3824,7 +3828,9 @@ tulip_txput(tulip_softc_t * const sc, struct mbuf *m)
bus_dmamap_t map;
int error;
struct ifnet *ifp = &sc->tulip_if;
+#ifdef DIAGNOSTIC
struct mbuf *ombuf = m;
+#endif
int compressed = 0;
#if defined(TULIP_DEBUG)
@@ -3887,24 +3893,17 @@ tulip_txput(tulip_softc_t * const sc, struct mbuf *m)
* to recopy it into one mbuf and then try again.
*/
struct mbuf *tmp;
- /*
- * tulip_mbuf_compress() frees the original mbuf.
- * thus, we have to remove the mbuf from the queue
- * before calling it.
- * we don't have to worry about space shortage
- * after compressing the mbuf since the compressed
- * mbuf will take only two segs.
- */
- if (compressed) {
- /* should not happen */
-#ifdef TULIP_DEBUG
- printf("tulip_txput: compress called twice!\n");
+ if (!notonqueue) {
+#ifdef DIAGNOSTIC
+ if (IF_IS_EMPTY(&ifp->if_snd))
+ panic("%s: if_snd queue empty", ifp->if_xname);
+#endif
+ IFQ_DEQUEUE(&ifp->if_snd, tmp);
+#ifdef DIAGNOSTIC
+ if (tmp != ombuf)
+ panic("tulip_txput: different mbuf dequeued!");
#endif
- goto finish;
}
- IFQ_DEQUEUE(&ifp->if_snd, tmp);
- if (tmp != ombuf)
- panic("tulip_txput: different mbuf dequeued!");
compressed = 1;
m = tulip_mbuf_compress(m);
if (m == NULL) {
@@ -3976,12 +3975,18 @@ tulip_txput(tulip_softc_t * const sc, struct mbuf *m)
* The descriptors have been filled in. Now get ready
* to transmit.
*/
- if (!compressed && (sc->tulip_flags & TULIP_TXPROBE_ACTIVE) == 0) {
+ if (!compressed && !notonqueue) {
/* remove the mbuf from the queue */
struct mbuf *tmp;
+#ifdef DIAGNOSTIC
+ if (IF_IS_EMPTY(&ifp->if_snd))
+ panic("%s: if_snd queue empty", ifp->if_xname);
+#endif
IFQ_DEQUEUE(&ifp->if_snd, tmp);
+#ifdef DIAGNOSTIC
if (tmp != ombuf)
panic("tulip_txput: different mbuf dequeued!");
+#endif
}
IF_ENQUEUE(&sc->tulip_txq, m);
@@ -4246,7 +4251,7 @@ tulip_ifstart(struct ifnet * const ifp)
IFQ_POLL(&sc->tulip_if.if_snd, m);
if (m == NULL)
break;
- if ((m0 = tulip_txput(sc, m)) != NULL) {
+ if ((m0 = tulip_txput(sc, m, 0)) != NULL) {
if (m0 != m)
/* should not happen */
printf("tulip_if_start: txput failed!\n");
@@ -4274,7 +4279,7 @@ tulip_ifstart_one(struct ifnet * const ifp)
&& !IFQ_IS_EMPTY(&sc->tulip_if.if_snd)) {
struct mbuf *m, *m0;
IFQ_POLL(&sc->tulip_if.if_snd, m);
- if (m != NULL && (m0 = tulip_txput(sc, m)) != NULL)
+ if (m != NULL && (m0 = tulip_txput(sc, m, 0)) != NULL)
if (m0 != m)
/* should not happen */
printf("tulip_if_start_one: txput failed!\n");