diff options
author | delphij <delphij@FreeBSD.org> | 2008-05-26 07:40:14 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2008-05-26 07:40:14 +0000 |
commit | 642c6dfdab53b79ea3b3e494e6a93a4d7bb5b216 (patch) | |
tree | ad38dee03daf1fb0babf363cd7be955d615b0452 /sys/dev/iwn | |
parent | d546148e70c16bd8528c88bc8ac0e806668f7ab4 (diff) | |
download | FreeBSD-src-642c6dfdab53b79ea3b3e494e6a93a4d7bb5b216.zip FreeBSD-src-642c6dfdab53b79ea3b3e494e6a93a4d7bb5b216.tar.gz |
We can not call iwn_start directly in the interrupt
context, where the iwn mutex is being held, and
iwn_start assumes that we do not have that mutex held.
Resolve this issue with what we do for other NICs by
splitting the iwn_start procedure into two parts,
iwn_start() do the locking, and iwn_start_locked()
assumes that the mutex is being held. This resolves
panic when WITNESS is enabled.
Diffstat (limited to 'sys/dev/iwn')
-rw-r--r-- | sys/dev/iwn/if_iwn.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c index 8a1ed68..ee7bda5 100644 --- a/sys/dev/iwn/if_iwn.c +++ b/sys/dev/iwn/if_iwn.c @@ -138,6 +138,7 @@ uint8_t iwn_plcp_signal(int); int iwn_tx_data(struct iwn_softc *, struct mbuf *, struct ieee80211_node *, struct iwn_tx_ring *); void iwn_start(struct ifnet *); +void iwn_start_locked(struct ifnet *); static int iwn_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static void iwn_watchdog(struct iwn_softc *); @@ -1627,7 +1628,7 @@ iwn_tx_intr(struct iwn_softc *sc, struct iwn_rx_desc *desc) sc->sc_tx_timer = 0; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - iwn_start(ifp); + iwn_start_locked(ifp); } void @@ -2092,11 +2093,23 @@ void iwn_start(struct ifnet *ifp) { struct iwn_softc *sc = ifp->if_softc; + + IWN_LOCK(sc); + iwn_start_locked(ifp); + IWN_UNLOCK(sc); +} + +void +iwn_start_locked(struct ifnet *ifp) +{ + struct iwn_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct iwn_tx_ring *txq; struct mbuf *m; int pri; + IWN_LOCK_ASSERT(sc); + for (;;) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m); if (m == NULL) @@ -2110,7 +2123,6 @@ iwn_start(struct ifnet *ifp) ieee80211_free_node(ni); continue; } - IWN_LOCK(sc); if (txq->queued >= IWN_TX_RING_COUNT - 8) { /* XXX not right */ /* ring is nearly full, stop flow */ @@ -2122,7 +2134,6 @@ iwn_start(struct ifnet *ifp) IWN_UNLOCK(sc); break; } - IWN_UNLOCK(sc); } } |