summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorChristopher Pascoe <pascoe@cvs.openbsd.org>2004-12-08 22:35:14 +0000
committerChristopher Pascoe <pascoe@cvs.openbsd.org>2004-12-08 22:35:14 +0000
commit602e638f065a9d058ebd35b51e57a36b20f119b3 (patch)
tree60833030591f26b58a054d6cabd3dd3febdd455e /sys/dev/ic
parent15417e484b91dd936867aae40ae3f02d2bbef2a1 (diff)
Defer reinitialisation of the RU until after the interrupt handler has had
a chance to process all pending packets, otherwise the chip may overwrite their mbuf clusters after we have freed them. Eliminates a race that can cause random pool corruption when reconfiguring an interface under heavy network load. ok brad@ mcbride@ beck@ deraadt@ dlg@
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/fxp.c27
-rw-r--r--sys/dev/ic/fxpreg.h4
2 files changed, 20 insertions, 11 deletions
diff --git a/sys/dev/ic/fxp.c b/sys/dev/ic/fxp.c
index c457557ba53..0d738c053fb 100644
--- a/sys/dev/ic/fxp.c
+++ b/sys/dev/ic/fxp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fxp.c,v 1.60 2004/11/07 01:13:48 dhartmei Exp $ */
+/* $OpenBSD: fxp.c,v 1.61 2004/12/08 22:35:13 pascoe Exp $ */
/* $NetBSD: if_fxp.c,v 1.2 1997/06/05 02:01:55 thorpej Exp $ */
/*
@@ -873,7 +873,8 @@ fxp_intr(arg)
while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
claimed = 1;
- rnr = (statack & FXP_SCB_STATACK_RNR) ? 1 : 0;
+ rnr = (statack & (FXP_SCB_STATACK_RNR |
+ FXP_SCB_STATACK_SWI)) ? 1 : 0;
/*
* First ACK all the interrupts in this pass.
*/
@@ -922,7 +923,8 @@ fxp_intr(arg)
* not ready (RNR) condition exists, get whatever
* packets we can and re-start the receiver.
*/
- if (statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR)) {
+ if (statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR |
+ FXP_SCB_STATACK_SWI)) {
struct mbuf *m;
u_int8_t *rfap;
rcvloop:
@@ -1206,7 +1208,6 @@ fxp_init(xsc)
struct fxp_cb_config *cbp;
struct fxp_cb_ias *cb_ias;
struct fxp_cb_tx *txp;
- struct mbuf *m;
bus_dmamap_t rxmap;
int i, prm, allm, s, bufs;
@@ -1407,10 +1408,10 @@ fxp_init(xsc)
bufs = FXP_NRFABUFS_MIN;
if (sc->rx_bufs > bufs) {
while (sc->rfa_headm != NULL && sc->rx_bufs-- > bufs) {
- rxmap = *((bus_dmamap_t *)m->m_ext.ext_buf);
+ rxmap = *((bus_dmamap_t *)sc->rfa_headm->m_ext.ext_buf);
bus_dmamap_unload(sc->sc_dmat, rxmap);
FXP_RXMAP_PUT(sc, rxmap);
- sc->rfa_headm = m_free(m);
+ sc->rfa_headm = m_free(sc->rfa_headm);
}
} else if (sc->rx_bufs < bufs) {
int err, tmp_rx_bufs = sc->rx_bufs;
@@ -1428,10 +1429,6 @@ fxp_init(xsc)
break;
}
fxp_scb_wait(sc);
- rxmap = *((bus_dmamap_t *)sc->rfa_headm->m_ext.ext_buf);
- CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
- rxmap->dm_segs[0].ds_addr + RFA_ALIGNMENT_FUDGE);
- fxp_scb_cmd(sc, FXP_SCB_COMMAND_RU_START);
/*
* Set current media.
@@ -1440,6 +1437,16 @@ fxp_init(xsc)
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * Request a software generated interrupt that will be used to
+ * (re)start the RU processing. If we direct the chip to start
+ * receiving from the start of queue now, instead of letting the
+ * interrupt handler first process all received packets, we run
+ * the risk of having it overwrite mbuf clusters while they are
+ * being processed or after they have been returned to the pool.
+ */
+ CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTRCNTL_REQUEST_SWI);
splx(s);
/*
diff --git a/sys/dev/ic/fxpreg.h b/sys/dev/ic/fxpreg.h
index 6d0657a62dc..99f1cd81a0a 100644
--- a/sys/dev/ic/fxpreg.h
+++ b/sys/dev/ic/fxpreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: fxpreg.h,v 1.6 2004/08/04 19:42:30 mickey Exp $ */
+/* $OpenBSD: fxpreg.h,v 1.7 2004/12/08 22:35:13 pascoe Exp $ */
/*
* Copyright (c) 1995, David Greenman
@@ -96,6 +96,8 @@
#define FXP_SCB_COMMAND_RU_BASE 6
#define FXP_SCB_COMMAND_RU_RBDRESUME 7
+#define FXP_SCB_INTRCNTL_REQUEST_SWI 0x02
+
/*
* Command block definitions
*/