From ae11ec5e4985e0ad2c2dc4fcf359aaece2ea4c76 Mon Sep 17 00:00:00 2001 From: benoit Date: Sun, 20 Apr 2008 21:06:15 +0000 Subject: [PATCH] Added debug in case the TX queue locked up (You need to do athdebug +watchdog to see those debug message). Fixed a bug where we removed TX descriptors too early. This should fix NETDEV WATCHDOG error messages. Apparently, TX descriptor status is updated by the hardware before TXDP. git-svn-id: http://madwifi-project.org/svn/madwifi/trunk@3552 0192ed92-7a03-0410-a25b-9323aeb14dbd --- ath/if_ath.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/ath/if_ath.c b/ath/if_ath.c index 6ff61d5..de6ef9f 100644 --- a/ath/if_ath.c +++ b/ath/if_ath.c @@ -2855,6 +2855,54 @@ ath_desc_swap(struct ath_desc *ds) #endif } +static void +ath_txq_dump(struct ath_softc *sc, struct ath_txq *txq) +{ + int j; + struct ath_buf *bf; + + DPRINTF(sc, ATH_DEBUG_WATCHDOG, + "txq:%p : axq_qnum:%u axq_depth:%d axq_link:%p TXDP:%08x\n", + txq, txq->axq_qnum, txq->axq_depth, txq->axq_link, + ath_hal_gettxbuf(sc->sc_ah, txq->axq_qnum)); + + j = 0; + STAILQ_FOREACH(bf, &txq->axq_q, bf_list) { + DPRINTF(sc, ATH_DEBUG_WATCHDOG, + " [%3u] bf_daddr:%08x ds_link:%08x ds_hw3:%08x\n", + j++, + bf->bf_daddr, bf->bf_desc->ds_link, + bf->bf_desc->ds_hw[3]); + } +} + +/* Check TXDP (HW queue head) and SW queue head */ + +static void +ath_txq_check(struct ath_softc *sc, struct ath_txq *txq) +{ + struct ath_hal * ah = sc->sc_ah; + struct ath_buf *bf; + u_int32_t txdp; + int sw_head_printed = 0; + int hw_head_printed = 0; + + txdp = ath_hal_gettxbuf(ah, txq->axq_qnum); + + STAILQ_FOREACH(bf, &txq->axq_q, bf_list) { + if (!sw_head_printed) + sw_head_printed = 1; + if (!hw_head_printed && txdp == bf->bf_daddr) + hw_head_printed = 1; + } + + if (sw_head_printed && !hw_head_printed) { + DPRINTF(sc, ATH_DEBUG_WATCHDOG, + "Q:%u BUG TXDP:%08x not in queue (%d elements)\n", + txq->axq_qnum, txdp, txq->axq_depth); + } +} + /* * Insert a buffer on a txq */ @@ -8260,6 +8308,17 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) goto bf_fail; } + /* We make sure we don't remove the TX descriptor on + * which the HW is pointing since it contains the + * ds_link field, except if this is the last TX + * descriptor in the queue */ + + if ((txq->axq_depth > 1) && + (bf->bf_daddr == ath_hal_gettxbuf(ah, txq->axq_qnum))) { + ATH_TXQ_UNLOCK_IRQ_EARLY(txq); + goto bf_fail; + } + ATH_TXQ_REMOVE_HEAD(txq, bf_list); if (txq->axq_depth <= 0) txq->axq_link = NULL; @@ -8545,6 +8604,7 @@ static void ath_tx_timeout(struct net_device *dev) { struct ath_softc *sc = dev->priv; + int i; if (ath_chan_unavail(sc)) return; @@ -8553,6 +8613,11 @@ ath_tx_timeout(struct net_device *dev) (dev->flags & IFF_RUNNING) ? "" : "NOT ", sc->sc_invalid ? "in" : ""); + for (i=0; isc_txq[i]); + ath_txq_dump(sc, &sc->sc_txq[i]); + } + if ((dev->flags & IFF_RUNNING) && !sc->sc_invalid) { sc->sc_stats.ast_watchdog++; ath_reset(dev); /* Avoid taking a semaphore in ath_init */ -- 2.35.1