mirror of
https://github.com/proski/madwifi
synced 2024-11-22 06:21:47 +03:00
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:
parent
4cb21704e2
commit
ae11ec5e49
65
ath/if_ath.c
65
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; 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 */
|
||||
|
Loading…
Reference in New Issue
Block a user