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
This commit is contained in:
benoit 2008-04-20 21:06:15 +00:00
parent 4cb21704e2
commit ae11ec5e49

View File

@ -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; i<HAL_NUM_TX_QUEUES; i++) {
ath_txq_check(sc, &sc->sc_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 */