-@@ -2162,12 +2174,13 @@
- * Insert the frame on the outbound list and
- * pass it on to the hardware.
- */
-- ATH_TXQ_LOCK(txq);
-+ ATH_TXQ_LOCK_IRQ(txq);
- if (ni && ni->ni_vap && txq == &ATH_VAP(ni->ni_vap)->av_mcastq) {
- /*
- * The CAB queue is started from the SWBA handler since
- * frames only go out on DTIM and to avoid possible races.
- */
-+ sc->sc_imask &= ~HAL_INT_SWBA;
- ath_hal_intrset(ah, sc->sc_imask & ~HAL_INT_SWBA);
- ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
- DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: txq depth = %d\n", __func__, txq->axq_depth);
-@@ -2183,6 +2196,7 @@
- ito64(bf->bf_daddr), bf->bf_desc);
- }
- txq->axq_link = &lastds->ds_link;
-+ sc->sc_imask |= HAL_INT_SWBA;
- ath_hal_intrset(ah, sc->sc_imask);
- } else {
- ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
-@@ -2218,7 +2232,7 @@
- }
- }
- }
-- ATH_TXQ_UNLOCK(txq);
-+ ATH_TXQ_UNLOCK_IRQ(txq);
-
- sc->sc_devstats.tx_packets++;
- sc->sc_devstats.tx_bytes += framelen;
-@@ -2369,8 +2383,14 @@
- unsigned int pktlen;
- int framecnt;
-
-+ /*
-+ * NB: using _BH style locking even though this function may be called
-+ * at interrupt time (within tasklet or bh). This should be harmless
-+ * and this function calls others (i.e., ath_tx_start()) which do
-+ * the same.
-+ */
- for (;;) {
-- ATH_TXQ_LOCK(txq);
-+ ATH_TXQ_LOCK_BH(txq);
-
- bf_ff = TAILQ_LAST(&txq->axq_stageq, axq_headtype);
- if ((!bf_ff) || ath_ff_flushdonetest(txq, bf_ff)) {
-@@ -2384,7 +2404,7 @@
- ATH_NODE(ni)->an_tx_ffbuf[bf_ff->bf_skb->priority] = NULL;
- TAILQ_REMOVE(&txq->axq_stageq, bf_ff, bf_stagelist);
-
-- ATH_TXQ_UNLOCK(txq);
-+ ATH_TXQ_UNLOCK_BH(txq);
-
- /* encap and xmit */
- bf_ff->bf_skb = ieee80211_encap(ni, bf_ff->bf_skb, &framecnt);
-@@ -2405,15 +2425,16 @@
- }
- bf_ff->bf_node = NULL;
-
-- ATH_TXBUF_LOCK_IRQ(sc);
-+ ATH_TXBUF_LOCK_BH(sc);
- STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf_ff, bf_list);
-- ATH_TXBUF_UNLOCK_IRQ(sc);
-+ ATH_TXBUF_UNLOCK_BH(sc);
- }
-+ ATH_TXQ_UNLOCK_BH(txq);
- }
- #endif
-
- #define ATH_HARDSTART_GET_TX_BUF_WITH_LOCK \
-- ATH_TXBUF_LOCK_IRQ(sc); \
-+ ATH_TXBUF_LOCK_BH(sc); \
- bf = STAILQ_FIRST(&sc->sc_txbuf); \
- if (bf != NULL) { \
- STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list); \
-@@ -2428,11 +2449,23 @@
- sc->sc_devstopped = 1; \
- ATH_SCHEDULE_TQUEUE(&sc->sc_txtq, NULL); \
- } \
-- ATH_TXBUF_UNLOCK_IRQ(sc); \
-+
-+#define ATH_HARDSTART_REL_TX_BUF_WITH_TXQLOCK_OFF \
-+ ATH_TXBUF_UNLOCK_BH(sc); \
-+ if (bf == NULL) { /* NB: should not happen */ \
-+ DPRINTF(sc,ATH_DEBUG_XMIT,"%s: discard, no xmit buf\n", __func__); \
-+ sc->sc_stats.ast_tx_nobuf++; \
-+ goto hardstart_fail; \
-+ }
-+
-+#define ATH_HARDSTART_REL_TX_BUF_WITH_TXQLOCK_ON \
-+ ATH_TXBUF_UNLOCK_BH(sc); \
- if (bf == NULL) { /* NB: should not happen */ \
- DPRINTF(sc,ATH_DEBUG_XMIT, \
- "%s: discard, no xmit buf\n", __func__); \
-+ ATH_TXQ_UNLOCK_BH(txq); \
- sc->sc_stats.ast_tx_nobuf++; \
-+ goto hardstart_fail; \
- }
-
- /*
-@@ -2494,6 +2527,7 @@
- if (M_FLAG_GET(skb, M_UAPSD)) {
- /* bypass FF handling */
- ATH_HARDSTART_GET_TX_BUF_WITH_LOCK;
-+ ATH_HARDSTART_REL_TX_BUF_WITH_TXQLOCK_OFF;
- if (bf == NULL)
- goto hardstart_fail;
- goto ff_bypass;
-@@ -2515,7 +2549,7 @@
- /* NB: use this lock to protect an->an_ff_txbuf in athff_can_aggregate()
- * call too.
- */
-- ATH_TXQ_LOCK(txq);
-+ ATH_TXQ_LOCK_BH(txq);
- if (athff_can_aggregate(sc, eh, an, skb, vap->iv_fragthreshold, &ff_flush)) {
-
- if (an->an_tx_ffbuf[skb->priority]) { /* i.e., frame on the staging queue */
-@@ -2525,7 +2559,7 @@
- TAILQ_REMOVE(&txq->axq_stageq, bf, bf_stagelist);
- an->an_tx_ffbuf[skb->priority] = NULL;
-
-- ATH_TXQ_UNLOCK(txq);
-+ ATH_TXQ_UNLOCK_BH(txq);
-
- /*
- * chain skbs and add FF magic
-@@ -2552,6 +2586,7 @@
- * to give the buffer back.
- */
- ATH_HARDSTART_GET_TX_BUF_WITH_LOCK;
-+ ATH_HARDSTART_REL_TX_BUF_WITH_TXQLOCK_ON;
- if (bf == NULL) {
- ATH_TXQ_UNLOCK(txq);
- goto hardstart_fail;
-@@ -2566,7 +2601,7 @@
-
- TAILQ_INSERT_HEAD(&txq->axq_stageq, bf, bf_stagelist);
-
-- ATH_TXQ_UNLOCK(txq);
-+ ATH_TXQ_UNLOCK_BH(txq);
-
- return 0;
- }
-@@ -2577,7 +2612,7 @@
- TAILQ_REMOVE(&txq->axq_stageq, bf_ff, bf_stagelist);
- an->an_tx_ffbuf[skb->priority] = NULL;
-
-- ATH_TXQ_UNLOCK(txq);
-+ ATH_TXQ_UNLOCK_BH(txq);
-
- /* encap and xmit */
- bf_ff->bf_skb = ieee80211_encap(ni, bf_ff->bf_skb, &framecnt);
-@@ -2607,9 +2642,9 @@
- }
- bf_ff->bf_node = NULL;
-
-- ATH_TXBUF_LOCK(sc);
-+ ATH_TXBUF_LOCK_BH(sc);
- STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf_ff, bf_list);
-- ATH_TXBUF_UNLOCK(sc);
-+ ATH_TXBUF_UNLOCK_BH(sc);
- goto ff_flushdone;
- }
- /*
-@@ -2619,14 +2654,13 @@
- else if (an->an_tx_ffbuf[skb->priority]) {
- DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
- "%s: Out-Of-Order fast-frame\n", __func__);
-- ATH_TXQ_UNLOCK(txq);
-+ ATH_TXQ_UNLOCK_BH(txq);
- } else
-- ATH_TXQ_UNLOCK(txq);
-+ ATH_TXQ_UNLOCK_BH(txq);
-
- ff_flushdone:
- ATH_HARDSTART_GET_TX_BUF_WITH_LOCK;
-- if (bf == NULL)
-- goto hardstart_fail;
-+ ATH_HARDSTART_REL_TX_BUF_WITH_TXQLOCK_OFF;
- }
-
- ff_bypass:
-@@ -2634,6 +2668,7 @@
- #else /* ATH_SUPERG_FF */
-
- ATH_HARDSTART_GET_TX_BUF_WITH_LOCK;
-+ ATH_HARDSTART_REL_TX_BUF_WITH_TXQLOCK_OFF;
-
- #endif /* ATH_SUPERG_FF */
-
-@@ -2655,7 +2690,7 @@
- * Allocate 1 ath_buf for each frame given 1 was
- * already alloc'd
- */
-- ATH_TXBUF_LOCK(sc);
-+ ATH_TXBUF_LOCK_BH(sc);
- for (bfcnt = 1; bfcnt < framecnt; ++bfcnt) {
- if ((tbf = STAILQ_FIRST(&sc->sc_txbuf)) != NULL) {
- STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list);
-@@ -2676,11 +2711,11 @@
- STAILQ_INSERT_TAIL(&sc->sc_txbuf, tbf, bf_list);
- }
- }
-- ATH_TXBUF_UNLOCK(sc);
-+ ATH_TXBUF_UNLOCK_BH(sc);
- STAILQ_INIT(&bf_head);
- goto hardstart_fail;
- }
-- ATH_TXBUF_UNLOCK(sc);
-+ ATH_TXBUF_UNLOCK_BH(sc);
-
- while ((bf = STAILQ_FIRST(&bf_head)) != NULL && skb != NULL) {
- unsigned int nextfraglen = 0;
-@@ -2716,7 +2751,7 @@
-
- hardstart_fail:
- if (!STAILQ_EMPTY(&bf_head)) {
-- ATH_TXBUF_LOCK(sc);
-+ ATH_TXBUF_LOCK_BH(sc);
- STAILQ_FOREACH_SAFE(tbf, &bf_head, bf_list, tempbf) {
- tbf->bf_skb = NULL;
- tbf->bf_node = NULL;
-@@ -2726,7 +2761,7 @@
-
- STAILQ_INSERT_TAIL(&sc->sc_txbuf, tbf, bf_list);
- }
-- ATH_TXBUF_UNLOCK(sc);
-+ ATH_TXBUF_UNLOCK_BH(sc);
- }
-
- /* free sk_buffs */
-@@ -2769,7 +2804,7 @@
- /*
- * Grab a TX buffer and associated resources.
- */
-- ATH_TXBUF_LOCK_IRQ(sc);
-+ ATH_TXBUF_LOCK_BH(sc);
- bf = STAILQ_FIRST(&sc->sc_txbuf);
- if (bf != NULL)
- STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list);
-@@ -2780,7 +2815,7 @@
- sc->sc_devstopped=1;
- ATH_SCHEDULE_TQUEUE(&sc->sc_txtq, NULL);
- }
-- ATH_TXBUF_UNLOCK_IRQ(sc);
-+ ATH_TXBUF_UNLOCK_BH(sc);
- if (bf == NULL) {
- printk("ath_mgtstart: discard, no xmit buf\n");
- sc->sc_stats.ast_tx_nobufmgt++;
-@@ -2809,9 +2844,9 @@
- bf->bf_skb = NULL;
- bf->bf_node = NULL;
-
-- ATH_TXBUF_LOCK_IRQ(sc);
-+ ATH_TXBUF_LOCK_BH(sc);
- STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
-- ATH_TXBUF_UNLOCK_IRQ(sc);
-+ ATH_TXBUF_UNLOCK_BH(sc);
- }
- dev_kfree_skb_any(skb);
- skb = NULL;
-@@ -3279,10 +3314,10 @@