diff options
author | Christopher Pascoe <pascoe@cvs.openbsd.org> | 2004-12-08 22:35:14 +0000 |
---|---|---|
committer | Christopher Pascoe <pascoe@cvs.openbsd.org> | 2004-12-08 22:35:14 +0000 |
commit | 602e638f065a9d058ebd35b51e57a36b20f119b3 (patch) | |
tree | 60833030591f26b58a054d6cabd3dd3febdd455e /sys/dev/ic | |
parent | 15417e484b91dd936867aae40ae3f02d2bbef2a1 (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.c | 27 | ||||
-rw-r--r-- | sys/dev/ic/fxpreg.h | 4 |
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 */ |