diff options
-rw-r--r-- | sys/dev/ath/if_ath.c | 59 | ||||
-rw-r--r-- | sys/dev/ath/if_athvar.h | 4 |
2 files changed, 55 insertions, 8 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index a71b3f8..6f5fb45 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -3896,6 +3896,7 @@ ath_tx_process_buf_completion(struct ath_softc *sc, struct ath_txq *txq, struct ath_node *an = NULL; ATH_TX_UNLOCK_ASSERT(sc); + ATH_TXQ_UNLOCK_ASSERT(txq); /* If unicast frame, update general statistics */ if (ni != NULL) { @@ -4000,6 +4001,28 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq, int dosched) break; } ATH_TXQ_REMOVE(txq, bf, bf_list); + + /* + * Sanity check. + */ + if (txq->axq_qnum != bf->bf_state.bfs_tx_queue) { + device_printf(sc->sc_dev, + "%s: TXQ=%d: bf=%p, bfs_tx_queue=%d\n", + __func__, + txq->axq_qnum, + bf, + bf->bf_state.bfs_tx_queue); + } + if (txq->axq_qnum != bf->bf_last->bf_state.bfs_tx_queue) { + device_printf(sc->sc_dev, + "%s: TXQ=%d: bf_last=%p, bfs_tx_queue=%d\n", + __func__, + txq->axq_qnum, + bf->bf_last, + bf->bf_last->bf_state.bfs_tx_queue); + } + +#if 0 if (txq->axq_depth > 0) { /* * More frames follow. Mark the buffer busy @@ -4013,6 +4036,9 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq, int dosched) bf->bf_last->bf_flags |= ATH_BUF_BUSY; } else txq->axq_link = NULL; +#else + bf->bf_last->bf_flags |= ATH_BUF_BUSY; +#endif if (bf->bf_state.bfs_aggr) txq->axq_aggr_depth--; @@ -4288,13 +4314,18 @@ ath_returnbuf_head(struct ath_softc *sc, struct ath_buf *bf) void ath_txq_freeholdingbuf(struct ath_softc *sc, struct ath_txq *txq) { - ATH_TXBUF_LOCK_ASSERT(sc); + ATH_TXBUF_UNLOCK_ASSERT(sc); + ATH_TXQ_LOCK_ASSERT(txq); if (txq->axq_holdingbf == NULL) return; txq->axq_holdingbf->bf_flags &= ~ATH_BUF_BUSY; + + ATH_TXBUF_LOCK(sc); ath_returnbuf_tail(sc, txq->axq_holdingbf); + ATH_TXBUF_UNLOCK(sc); + txq->axq_holdingbf = NULL; } @@ -4307,7 +4338,10 @@ ath_txq_addholdingbuf(struct ath_softc *sc, struct ath_buf *bf) { struct ath_txq *txq; - ATH_TXBUF_LOCK_ASSERT(sc); + txq = &sc->sc_txq[bf->bf_state.bfs_tx_queue]; + + ATH_TXBUF_UNLOCK_ASSERT(sc); + ATH_TXQ_LOCK_ASSERT(txq); /* XXX assert ATH_BUF_BUSY is set */ @@ -4321,7 +4355,6 @@ ath_txq_addholdingbuf(struct ath_softc *sc, struct ath_buf *bf) ath_returnbuf_tail(sc, bf); return; } - txq = &sc->sc_txq[bf->bf_state.bfs_tx_queue]; ath_txq_freeholdingbuf(sc, txq); txq->axq_holdingbf = bf; } @@ -4336,20 +4369,30 @@ ath_txq_addholdingbuf(struct ath_softc *sc, struct ath_buf *bf) * for restart (eg for TDMA.) * * The caller must free the mbuf and recycle the node reference. + * + * XXX This method of handling busy / holding buffers is insanely stupid. + * It requires bf_state.bfs_tx_queue to be correctly assigned. It would + * be much nicer if buffers in the processq() methods would instead be + * always completed there (pushed onto a txq or ath_bufhead) so we knew + * exactly what hardware queue they came from in the first place. */ void ath_freebuf(struct ath_softc *sc, struct ath_buf *bf) { + struct ath_txq *txq; + + txq = &sc->sc_txq[bf->bf_state.bfs_tx_queue]; + KASSERT((bf->bf_node == NULL), ("%s: bf->bf_node != NULL\n", __func__)); KASSERT((bf->bf_m == NULL), ("%s: bf->bf_m != NULL\n", __func__)); /* - * If this buffer is busy, push it onto the holding queue + * If this buffer is busy, push it onto the holding queue. */ if (bf->bf_flags & ATH_BUF_BUSY) { - ATH_TXBUF_LOCK(sc); + ATH_TXQ_LOCK(txq); ath_txq_addholdingbuf(sc, bf); - ATH_TXBUF_UNLOCK(sc); + ATH_TXQ_UNLOCK(txq); return; } @@ -4521,9 +4564,9 @@ ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq) /* * Free the holding buffer if it exists */ - ATH_TXBUF_LOCK(sc); + ATH_TXQ_LOCK(txq); ath_txq_freeholdingbuf(sc, txq); - ATH_TXBUF_UNLOCK(sc); + ATH_TXQ_UNLOCK(txq); /* * Drain software queued frames which are on diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index f2b9230..662382f 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -381,6 +381,8 @@ struct ath_txq { #define ATH_TXQ_LOCK(_tq) mtx_lock(&(_tq)->axq_lock) #define ATH_TXQ_UNLOCK(_tq) mtx_unlock(&(_tq)->axq_lock) #define ATH_TXQ_LOCK_ASSERT(_tq) mtx_assert(&(_tq)->axq_lock, MA_OWNED) +#define ATH_TXQ_UNLOCK_ASSERT(_tq) mtx_assert(&(_tq)->axq_lock, \ + MA_NOTOWNED) #define ATH_NODE_LOCK(_an) mtx_lock(&(_an)->an_mtx) @@ -964,6 +966,8 @@ struct ath_softc { #define ATH_TXBUF_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_txbuflock) #define ATH_TXBUF_LOCK_ASSERT(_sc) \ mtx_assert(&(_sc)->sc_txbuflock, MA_OWNED) +#define ATH_TXBUF_UNLOCK_ASSERT(_sc) \ + mtx_assert(&(_sc)->sc_txbuflock, MA_NOTOWNED) #define ATH_TXSTATUS_LOCK_INIT(_sc) do { \ snprintf((_sc)->sc_txcompname, sizeof((_sc)->sc_txcompname), \ |