diff options
author | marius <marius@FreeBSD.org> | 2011-07-13 18:52:11 +0000 |
---|---|---|
committer | marius <marius@FreeBSD.org> | 2011-07-13 18:52:11 +0000 |
commit | 6620a4474b278d01edd0ca6fc446c01f9fa8b619 (patch) | |
tree | e3108fe8a18d726fb687b18c187d453a6f836ffc /sys | |
parent | 13b1156fcdf44f68b3cfb1075695f70c4f077339 (diff) | |
download | FreeBSD-src-6620a4474b278d01edd0ca6fc446c01f9fa8b619.zip FreeBSD-src-6620a4474b278d01edd0ca6fc446c01f9fa8b619.tar.gz |
- Expand the scope of the lock in the interrupt routine to close races with
checking IFF_DRV_RUNNING and simplify the code. This also involves holding
the driver lock in the rx_ch callout.
- Just use ifp instead of sc->sc_ifp.
Submitted by: jhb (mostly)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/cas/if_cas.c | 47 |
1 files changed, 25 insertions, 22 deletions
diff --git a/sys/dev/cas/if_cas.c b/sys/dev/cas/if_cas.c index 5d830f8..858c8bc 100644 --- a/sys/dev/cas/if_cas.c +++ b/sys/dev/cas/if_cas.c @@ -203,7 +203,7 @@ cas_attach(struct cas_softc *sc) IFQ_SET_READY(&ifp->if_snd); callout_init_mtx(&sc->sc_tick_ch, &sc->sc_mtx, 0); - callout_init(&sc->sc_rx_ch, 1); + callout_init_mtx(&sc->sc_rx_ch, &sc->sc_mtx, 0); /* Create local taskq. */ TASK_INIT(&sc->sc_intr_task, 0, cas_intr_task, sc); TASK_INIT(&sc->sc_tx_task, 1, cas_tx_task, ifp); @@ -1599,7 +1599,7 @@ cas_rint_timeout(void *arg) { struct cas_softc *sc = arg; - CAS_LOCK_ASSERT(sc, MA_NOTOWNED); + CAS_LOCK_ASSERT(sc, MA_OWNED); cas_rint(sc); } @@ -1614,7 +1614,7 @@ cas_rint(struct cas_softc *sc) uint32_t rxhead; u_int idx, idx2, len, off, skip; - CAS_LOCK_ASSERT(sc, MA_NOTOWNED); + CAS_LOCK_ASSERT(sc, MA_OWNED); callout_stop(&sc->sc_rx_ch); @@ -1742,7 +1742,9 @@ cas_rint(struct cas_softc *sc) cas_rxcksum(m, CAS_GET(word4, CAS_RC4_TCP_CSUM)); /* Pass it on. */ + CAS_UNLOCK(sc); (*ifp->if_input)(ifp, m); + CAS_LOCK(sc); } else ifp->if_iqdrops++; @@ -1838,7 +1840,9 @@ cas_rint(struct cas_softc *sc) cas_rxcksum(m, CAS_GET(word4, CAS_RC4_TCP_CSUM)); /* Pass it on. */ + CAS_UNLOCK(sc); (*ifp->if_input)(ifp, m); + CAS_LOCK(sc); } else ifp->if_iqdrops++; @@ -1876,7 +1880,7 @@ cas_free(void *arg1, void *arg2) { struct cas_rxdsoft *rxds; struct cas_softc *sc; - u_int idx; + u_int idx, locked; #if __FreeBSD_version < 800016 rxds = arg2; @@ -1894,17 +1898,18 @@ cas_free(void *arg1, void *arg2) * NB: this function can be called via m_freem(9) within * this driver! */ - + if ((locked = CAS_LOCK_OWNED(sc)) == 0) + CAS_LOCK(sc); cas_add_rxdesc(sc, idx); + if (locked == 0) + CAS_UNLOCK(sc); } static inline void cas_add_rxdesc(struct cas_softc *sc, u_int idx) { - u_int locked; - if ((locked = CAS_LOCK_OWNED(sc)) == 0) - CAS_LOCK(sc); + CAS_LOCK_ASSERT(sc, MA_OWNED); bus_dmamap_sync(sc->sc_rdmatag, sc->sc_rxdsoft[idx].rxds_dmamap, BUS_DMASYNC_PREREAD); @@ -1922,9 +1927,6 @@ cas_add_rxdesc(struct cas_softc *sc, u_int idx) CAS_WRITE_4(sc, CAS_RX_KICK, (sc->sc_rxdptr + CAS_NRXDESC - 4) & CAS_NRXDESC_MASK); } - - if (locked == 0) - CAS_UNLOCK(sc); } static void @@ -1932,7 +1934,7 @@ cas_eint(struct cas_softc *sc, u_int status) { struct ifnet *ifp = sc->sc_ifp; - CAS_LOCK_ASSERT(sc, MA_NOTOWNED); + CAS_LOCK_ASSERT(sc, MA_OWNED); ifp->if_ierrors++; @@ -1949,7 +1951,7 @@ cas_eint(struct cas_softc *sc, u_int status) printf("\n"); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - cas_init(sc); + cas_init_locked(sc); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) taskqueue_enqueue(sc->sc_tq, &sc->sc_tx_task); } @@ -1986,6 +1988,7 @@ cas_intr_task(void *arg, int pending __unused) if (__predict_false((status & CAS_INTR_SUMMARY) == 0)) goto done; + CAS_LOCK(sc); #ifdef CAS_DEBUG CTR4(KTR_CAS, "%s: %s: cplt %x, status %x", device_get_name(sc->sc_dev), __func__, @@ -2025,6 +2028,7 @@ cas_intr_task(void *arg, int pending __unused) (CAS_INTR_TX_TAG_ERR | CAS_INTR_RX_TAG_ERR | CAS_INTR_RX_LEN_MMATCH | CAS_INTR_PCI_ERROR_INT)) != 0)) { cas_eint(sc, status); + CAS_UNLOCK(sc); return; } @@ -2032,7 +2036,7 @@ cas_intr_task(void *arg, int pending __unused) status2 = CAS_READ_4(sc, CAS_MAC_TX_STATUS); if ((status2 & (CAS_MAC_TX_UNDERRUN | CAS_MAC_TX_MAX_PKT_ERR)) != 0) - sc->sc_ifp->if_oerrors++; + ifp->if_oerrors++; else if ((status2 & ~CAS_MAC_TX_FRAME_XMTD) != 0) device_printf(sc->sc_dev, "MAC TX fault, status %x\n", status2); @@ -2041,7 +2045,7 @@ cas_intr_task(void *arg, int pending __unused) if (__predict_false(status & CAS_INTR_RX_MAC_INT)) { status2 = CAS_READ_4(sc, CAS_MAC_RX_STATUS); if ((status2 & CAS_MAC_RX_OVERFLOW) != 0) - sc->sc_ifp->if_ierrors++; + ifp->if_ierrors++; else if ((status2 & ~CAS_MAC_RX_FRAME_RCVD) != 0) device_printf(sc->sc_dev, "MAC RX fault, status %x\n", status2); @@ -2061,16 +2065,15 @@ cas_intr_task(void *arg, int pending __unused) } if ((status & - (CAS_INTR_TX_INT_ME | CAS_INTR_TX_ALL | CAS_INTR_TX_DONE)) != 0) { - CAS_LOCK(sc); + (CAS_INTR_TX_INT_ME | CAS_INTR_TX_ALL | CAS_INTR_TX_DONE)) != 0) cas_tint(sc); - CAS_UNLOCK(sc); - } - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + CAS_UNLOCK(sc); return; - else if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + } else if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) taskqueue_enqueue(sc->sc_tq, &sc->sc_tx_task); + CAS_UNLOCK(sc); status = CAS_READ_4(sc, CAS_STATUS_ALIAS); if (__predict_false((status & CAS_INTR_SUMMARY) != 0)) { @@ -2403,7 +2406,7 @@ cas_mii_statchg(device_t dev) CAS_WRITE_4(sc, CAS_MAC_XIF_CONF, v); sc->sc_mac_rxcfg = rxcfg; - if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && (sc->sc_flags & CAS_LINK) != 0) { CAS_WRITE_4(sc, CAS_MAC_TX_CONF, txcfg | CAS_MAC_TX_CONF_EN); |