svn commit: r224880 - user/adrian/if_ath_tx/sys/dev/ath
Adrian Chadd
adrian at FreeBSD.org
Mon Aug 15 13:25:56 UTC 2011
Author: adrian
Date: Mon Aug 15 13:25:55 2011
New Revision: 224880
URL: http://svn.freebsd.org/changeset/base/224880
Log:
Fix some of the locking to correctly protect things.
Specifically, ath_tx_tid_unsched() wasn't correctly locking things,
so there was a race condition between the upper half that were
unscheduling things (eg a node flush) and the lower half (tx sched
and completion task.) Fixing it required re-doing some of the
locking.
This seems to now cope with TX failures -> BAR -> BAR failure ->
DELBA. Normal TX then continues fine. Before, the code would
get wedged whilst doing packet TX whilst doing BAR re-transmission,
and things would stop progressing until a scan or some other flush
would occur.
Modified:
user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c
user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h
Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Mon Aug 15 12:08:41 2011 (r224879)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Mon Aug 15 13:25:55 2011 (r224880)
@@ -1662,7 +1662,7 @@ ath_tx_tid_sched(struct ath_softc *sc, s
* Mark the current node as no longer needing to be polled for
* TX packets.
*
- * The TXQ lock must NOT be held, it'll be grabbed as needed.
+ * The TXQ lock must be held.
*/
static void
ath_tx_tid_unsched(struct ath_softc *sc, struct ath_node *an, int tid)
@@ -1670,13 +1670,13 @@ ath_tx_tid_unsched(struct ath_softc *sc,
struct ath_tid *atid = &an->an_tid[tid];
struct ath_txq *txq = sc->sc_ac2q[atid->ac];
+ ATH_TXQ_LOCK_ASSERT(txq);
+
if (atid->sched == 0)
return;
atid->sched = 0;
- ATH_TXQ_LOCK(txq);
STAILQ_REMOVE(&txq->axq_tidq, atid, ath_tid, axq_qelem);
- ATH_TXQ_UNLOCK(txq);
}
/*
@@ -1922,29 +1922,18 @@ void
ath_tx_node_flush(struct ath_softc *sc, struct ath_node *an)
{
int tid;
- int is_owned;
for (tid = 0; tid < IEEE80211_TID_SIZE; tid++) {
struct ath_tid *atid = &an->an_tid[tid];
struct ath_txq *txq = sc->sc_ac2q[atid->ac];
- /*
- * Only lock if we don't have it locked.
- * It may be locked already if this is being called
- * when the last buffer for an ieee80211_node is
- * being freed.
- */
- is_owned = ATH_TXQ_IS_LOCKED(txq);
- if (! is_owned)
- ATH_TXQ_LOCK(txq);
/* Remove this tid from the list of active tids */
+ ATH_TXQ_LOCK(txq);
ath_tx_tid_unsched(sc, an, tid);
+ ATH_TXQ_UNLOCK(txq);
/* Free packets */
ath_tx_tid_free_pkts(sc, an, tid);
- if (! is_owned)
- ATH_TXQ_UNLOCK(txq);
-
}
}
@@ -1971,27 +1960,16 @@ ath_tx_tid_cleanup(struct ath_softc *sc,
}
}
-#ifdef notyet
/*
* Handle completion of non-aggregate session frames.
*/
-static void
+void
ath_tx_normal_comp(struct ath_softc *sc, struct ath_buf *bf, int fail)
{
- struct ieee80211_node *ni = bf->bf_node;
- struct ath_node *an;
- struct ath_tid *atid;
- int tid;
-
- if (ni != NULL) {
- tid = bf->bf_state.bfs_tid;
- an = ATH_NODE(ni);
- atid = &an->an_tid[tid];
-
- ath_tx_default_comp(sc, bf, fail);
- }
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: bf=%p: fail=%d\n", __func__,
+ bf, fail);
+ ath_tx_default_comp(sc, bf, fail);
}
-#endif
/*
* Handle cleanup of aggregate session packets that aren't
@@ -2064,7 +2042,7 @@ ath_tx_cleanup(struct ath_softc *sc, str
continue;
}
/* Give these the default completion handler */
- bf->bf_comp = NULL;
+ bf->bf_comp = ath_tx_normal_comp;
bf = STAILQ_NEXT(bf, bf_list);
}
ATH_TXQ_UNLOCK(atid);
@@ -2350,6 +2328,9 @@ ath_tx_tid_hw_queue_norm(struct ath_soft
struct ath_txq *txq;
struct ath_tid *atid = &an->an_tid[tid];
+ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: node %p: TID %d: called\n",
+ __func__, an, tid);
+
/* Check - is AMPDU pending or running? then print out something */
if (ath_tx_ampdu_pending(sc, an, tid))
device_printf(sc->sc_dev, "%s: tid=%d, ampdu pending?\n",
@@ -2376,7 +2357,8 @@ ath_tx_tid_hw_queue_norm(struct ath_soft
" tid %d\n",
__func__, bf->bf_state.bfs_tid, tid);
}
- bf->bf_comp = NULL; /* XXX default handler */
+ /* Normal completion handler */
+ bf->bf_comp = ath_tx_normal_comp;
/* Punt to hardware or software txq */
ATH_TXQ_LOCK(txq);
@@ -2410,7 +2392,9 @@ ath_txq_sched(struct ath_softc *sc, stru
DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: tid=%d, paused=%d\n",
__func__, atid->tid, atid->paused);
if (atid->paused) {
+ ATH_TXQ_LOCK(txq);
ath_tx_tid_unsched(sc, atid->an, atid->tid);
+ ATH_TXQ_UNLOCK(txq);
continue;
}
if (ath_tx_ampdu_running(sc, atid->an, atid->tid))
@@ -2419,8 +2403,10 @@ ath_txq_sched(struct ath_softc *sc, stru
ath_tx_tid_hw_queue_norm(sc, atid->an, atid->tid);
/* Empty? Remove */
+ ATH_TXQ_LOCK(txq);
if (atid->axq_depth == 0)
ath_tx_tid_unsched(sc, atid->an, atid->tid);
+ ATH_TXQ_UNLOCK(txq);
}
}
Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h Mon Aug 15 12:08:41 2011 (r224879)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h Mon Aug 15 13:25:55 2011 (r224880)
@@ -52,6 +52,8 @@ extern void ath_tx_tid_hw_queue_aggr(str
extern void ath_tx_tid_hw_queue_norm(struct ath_softc *sc, struct ath_node *an,
int tid);
extern void ath_txq_sched(struct ath_softc *sc, struct ath_txq *txq);
+extern void ath_tx_normal_comp(struct ath_softc *sc, struct ath_buf *bf,
+ int fail);
/* TX addba handling */
extern int ath_addba_request(struct ieee80211_node *ni,
More information about the svn-src-user
mailing list