Skip to content

Commit

Permalink
ath5k: Add watchdog for stuck TX queues
Browse files Browse the repository at this point in the history
Since we do not know any better solution to the problem that TX queues can get
stuck, this adds a timer-based watchdog, which will check for stuck queues and
reset the hardware if necessary.

Ported from ath9k commit 164ace3.

Signed-off-by: Bruno Randolf <br1@einfach.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Bruno Randolf authored and John W. Linville committed Sep 21, 2010
1 parent 1440401 commit 4edd761
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 0 deletions.
2 changes: 2 additions & 0 deletions drivers/net/wireless/ath/ath5k/ath5k.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@
#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */
#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF 60000 /* 60 sec */

#define ATH5K_TX_COMPLETE_POLL_INT 3000 /* 3 sec */

#define AR5K_INIT_CARR_SENSE_EN 1

/*Swap RX/TX Descriptor for big endian archs*/
Expand Down
51 changes: 51 additions & 0 deletions drivers/net/wireless/ath/ath5k/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,7 @@ ath5k_txq_setup(struct ath5k_softc *sc,
spin_lock_init(&txq->lock);
txq->setup = true;
txq->txq_len = 0;
txq->txq_poll_mark = false;
}
return &sc->txqs[qnum];
}
Expand Down Expand Up @@ -989,6 +990,7 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
spin_unlock_bh(&sc->txbuflock);
}
txq->link = NULL;
txq->txq_poll_mark = false;
spin_unlock_bh(&txq->lock);
}

Expand Down Expand Up @@ -1616,6 +1618,8 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
sc->txbuf_len++;
txq->txq_len--;
spin_unlock(&sc->txbuflock);

txq->txq_poll_mark = false;
}
if (likely(list_empty(&txq->q)))
txq->link = NULL;
Expand Down Expand Up @@ -2170,6 +2174,46 @@ ath5k_tasklet_ani(unsigned long data)
}


static void
ath5k_tx_complete_poll_work(struct work_struct *work)
{
struct ath5k_softc *sc = container_of(work, struct ath5k_softc,
tx_complete_work.work);
struct ath5k_txq *txq;
int i;
bool needreset = false;

for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) {
if (sc->txqs[i].setup) {
txq = &sc->txqs[i];
spin_lock_bh(&txq->lock);
if (txq->txq_len > 0) {
if (txq->txq_poll_mark) {
ATH5K_DBG(sc, ATH5K_DEBUG_XMIT,
"TX queue stuck %d\n",
txq->qnum);
needreset = true;
spin_unlock_bh(&txq->lock);
break;
} else {
txq->txq_poll_mark = true;
}
}
spin_unlock_bh(&txq->lock);
}
}

if (needreset) {
ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
"TX queues stuck, resetting\n");
ath5k_reset(sc, sc->curchan);
}

ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT));
}


/*************************\
* Initialization routines *
\*************************/
Expand Down Expand Up @@ -2261,6 +2305,10 @@ ath5k_init(struct ath5k_softc *sc)
done:
mmiowb();
mutex_unlock(&sc->lock);

ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT));

return ret;
}

Expand Down Expand Up @@ -2319,6 +2367,8 @@ ath5k_stop_hw(struct ath5k_softc *sc)

stop_tasklets(sc);

cancel_delayed_work_sync(&sc->tx_complete_work);

ath5k_rfkill_hw_stop(sc->ah);

return ret;
Expand Down Expand Up @@ -2505,6 +2555,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc);

INIT_WORK(&sc->reset_work, ath5k_reset_work);
INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work);

ret = ath5k_eeprom_read_mac(ah, mac);
if (ret) {
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/ath/ath5k/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ struct ath5k_txq {
spinlock_t lock; /* lock on q and link */
bool setup;
int txq_len; /* number of queued buffers */
bool txq_poll_mark;
};

#define ATH5K_LED_MAX_NAME_LEN 31
Expand Down Expand Up @@ -233,6 +234,8 @@ struct ath5k_softc {

struct ath5k_ani_state ani_state;
struct tasklet_struct ani_tasklet; /* ANI calibration */

struct delayed_work tx_complete_work;
};

#define ath5k_hw_hasbssidmask(_ah) \
Expand Down

0 comments on commit 4edd761

Please sign in to comment.