From 2f8a91c47cca546e6c101cb27c094e543265ae2b Mon Sep 17 00:00:00 2001 From: Alexander Egorenkov Date: Sun, 14 Mar 2010 14:34:52 +0100 Subject: [PATCH] Improved Tx locking --- rt2860.c | 63 +++++++++++++++++++++++++++++++++++++++++++++------------- rt2860_softc.h | 5 +++++ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/rt2860.c b/rt2860.c index eb626c9..634796a 100644 --- a/rt2860.c +++ b/rt2860.c @@ -1662,21 +1662,20 @@ static void rt2860_start(struct ifnet *ifp) sc = ifp->if_softc; ic = &sc->ic; - RT2860_SOFTC_LOCK(sc); - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) - { - RT2860_SOFTC_UNLOCK(sc); return; - } for (;;) { IF_POLL(&ic->ic_mgtq, m); if (m != NULL) { + RT2860_SOFTC_TX_RING_LOCK(&sc->tx_ring[sc->tx_ring_mgtqid]); + if (sc->tx_ring[sc->tx_ring_mgtqid].data_queued >= RT2860_SOFTC_TX_RING_DATA_COUNT) { + RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[sc->tx_ring_mgtqid]); + RT2860_DPRINTF(sc, RT2860_DEBUG_TX, "%s: if_start: Tx ring with qid=%d is full\n", device_get_nameunit(sc->dev), sc->tx_ring_mgtqid); @@ -1689,15 +1688,26 @@ static void rt2860_start(struct ifnet *ifp) } IF_DEQUEUE(&ic->ic_mgtq, m); + if (m == NULL) + { + RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[sc->tx_ring_mgtqid]); + break; + } ni = (struct ieee80211_node *) m->m_pkthdr.rcvif; + m->m_pkthdr.rcvif = NULL; if (bpf_peers_present(ic->ic_rawbpf)) bpf_mtap(ic->ic_rawbpf, m); if (rt2860_tx_frame(sc, m, ni, sc->tx_ring_mgtqid) != 0) + { + RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[sc->tx_ring_mgtqid]); break; + } + + RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[sc->tx_ring_mgtqid]); rt2860_drain_fifo_stats(sc); } @@ -1706,12 +1716,10 @@ static void rt2860_start(struct ifnet *ifp) if (ic->ic_state != IEEE80211_S_RUN) break; - IF_POLL(&ifp->if_snd, m); + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); if (m == NULL) break; - IFQ_DRV_DEQUEUE(&ifp->if_snd, m); - if (ic->ic_flags & IEEE80211_F_SCAN) ieee80211_cancel_scan(ic); @@ -1729,6 +1737,7 @@ static void rt2860_start(struct ifnet *ifp) device_get_nameunit(sc->dev)); m_freem(m); + continue; } @@ -1736,8 +1745,12 @@ static void rt2860_start(struct ifnet *ifp) qid = M_WME_GETAC(m); + RT2860_SOFTC_TX_RING_LOCK(&sc->tx_ring[qid]); + if (sc->tx_ring[qid].data_queued >= RT2860_SOFTC_TX_RING_DATA_COUNT) { + RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]); + RT2860_DPRINTF(sc, RT2860_DEBUG_TX, "%s: if_start: Tx ring with qid=%d is full\n", device_get_nameunit(sc->dev), qid); @@ -1758,8 +1771,12 @@ static void rt2860_start(struct ifnet *ifp) m = ieee80211_encap(ic, m, ni); if (m == NULL) { + RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]); + ieee80211_free_node(ni); + ifp->if_oerrors++; + continue; } @@ -1768,6 +1785,8 @@ static void rt2860_start(struct ifnet *ifp) if (rt2860_tx_frame(sc, m, ni, qid) != 0) { + RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]); + ieee80211_free_node(ni); ifp->if_oerrors++; @@ -1775,6 +1794,8 @@ static void rt2860_start(struct ifnet *ifp) break; } + RT2860_SOFTC_TX_RING_UNLOCK(&sc->tx_ring[qid]); + rt2860_drain_fifo_stats(sc); } @@ -1784,8 +1805,6 @@ static void rt2860_start(struct ifnet *ifp) callout_reset(&sc->tx_watchdog_ch, hz, rt2860_tx_watchdog, sc); } - - RT2860_SOFTC_UNLOCK(sc); } /* @@ -3726,6 +3745,8 @@ static int rt2860_tx_frame(struct rt2860_softc *sc, ("%s: Tx frame: invalid qid=%d\n", device_get_nameunit(sc->dev), qid)); + RT2860_SOFTC_TX_RING_ASSERT_LOCKED(&sc->tx_ring[qid]); + ic = &sc->ic; rni = (struct rt2860_softc_node *) ni; @@ -4577,11 +4598,13 @@ static void rt2860_tx_done_task(void *context, int pending) { struct rt2860_softc *sc; struct ifnet *ifp; + struct ieee80211com *ic; uint32_t intr_mask; int i; sc = context; ifp = sc->ifp; + ic = &sc->ic; RT2860_DPRINTF(sc, RT2860_DEBUG_TX, "%s: Tx done task\n", @@ -4626,6 +4649,9 @@ static void rt2860_tx_done_task(void *context, int pending) } RT2860_SOFTC_UNLOCK(sc); + + if (!IFQ_IS_EMPTY(&ic->ic_mgtq) || !IFQ_IS_EMPTY(&ifp->if_snd)) + rt2860_start(ifp); } /* @@ -4635,9 +4661,11 @@ static void rt2860_fifo_sta_full_task(void *context, int pending) { struct rt2860_softc *sc; struct ifnet *ifp; + struct ieee80211com *ic; sc = context; ifp = sc->ifp; + ic = &sc->ic; RT2860_DPRINTF(sc, RT2860_DEBUG_STATS, "%s: FIFO statistic full task\n", @@ -4666,6 +4694,9 @@ static void rt2860_fifo_sta_full_task(void *context, int pending) } RT2860_SOFTC_UNLOCK(sc); + + if (!IFQ_IS_EMPTY(&ic->ic_mgtq) || !IFQ_IS_EMPTY(&ifp->if_snd)) + rt2860_start(ifp); } /* @@ -5093,12 +5124,12 @@ static void rt2860_tx_eof(struct rt2860_softc *sc, ifp->if_opackets++; - RT2860_SOFTC_LOCK(sc); + RT2860_SOFTC_TX_RING_LOCK(ring); ring->data_queued--; ring->data_next = (ring->data_next + 1) % RT2860_SOFTC_TX_RING_DATA_COUNT; - RT2860_SOFTC_UNLOCK(sc); + RT2860_SOFTC_TX_RING_UNLOCK(ring); } desc->sdl0 &= ~htole16(RT2860_TXDESC_SDL0_DDONE); @@ -5106,12 +5137,12 @@ static void rt2860_tx_eof(struct rt2860_softc *sc, bus_dmamap_sync(ring->desc_dma_tag, ring->desc_dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - RT2860_SOFTC_LOCK(sc); + RT2860_SOFTC_TX_RING_LOCK(ring); ring->desc_queued--; ring->desc_next = (ring->desc_next + 1) % RT2860_SOFTC_TX_RING_DESC_COUNT; - RT2860_SOFTC_UNLOCK(sc); + RT2860_SOFTC_TX_RING_UNLOCK(ring); } RT2860_DPRINTF(sc, RT2860_DEBUG_TX, @@ -5680,6 +5711,8 @@ static int rt2860_alloc_tx_ring(struct rt2860_softc *sc, struct rt2860_softc_tx_data *data; int error, i; + mtx_init(&ring->lock, device_get_nameunit(sc->dev), NULL, MTX_DEF); + error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, RT2860_SOFTC_TX_RING_DESC_COUNT * sizeof(struct rt2860_txdesc), 1, @@ -5894,6 +5927,8 @@ static void rt2860_free_tx_ring(struct rt2860_softc *sc, if (ring->data_dma_tag != NULL) bus_dma_tag_destroy(ring->data_dma_tag); + + mtx_destroy(&ring->lock); } /* diff --git a/rt2860_softc.h b/rt2860_softc.h index 6917558..bb719ba 100644 --- a/rt2860_softc.h +++ b/rt2860_softc.h @@ -61,6 +61,10 @@ #define RT2860_SOFTC_UNLOCK(sc) mtx_unlock(&(sc)->lock) #define RT2860_SOFTC_ASSERT_LOCKED(sc) mtx_assert(&(sc)->lock, MA_OWNED) +#define RT2860_SOFTC_TX_RING_LOCK(ring) mtx_lock(&(ring)->lock) +#define RT2860_SOFTC_TX_RING_UNLOCK(ring) mtx_unlock(&(ring)->lock) +#define RT2860_SOFTC_TX_RING_ASSERT_LOCKED(ring) mtx_assert(&(ring)->lock, MA_OWNED) + #define RT2860_SOFTC_FLAGS_UCODE_LOADED (1 << 0) #define RT2860_SOFTC_LED_OFF_COUNT 3 @@ -132,6 +136,7 @@ struct rt2860_softc_tx_data struct rt2860_softc_tx_ring { + struct mtx lock; bus_dma_tag_t desc_dma_tag; bus_dmamap_t desc_dma_map; bus_addr_t desc_phys_addr; -- 2.11.4.GIT