1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Wed, 25 Jan 2017 13:00:58 +0100
3 Subject: [PATCH] ath9k: check for deaf rx path state
5 Various chips occasionally run into a state where the tx path still
6 appears to be working normally, but the rx path is deaf.
8 There is no known register signature to check for this state explicitly,
9 so use the lack of rx interrupts as an indicator.
11 This detection is prone to false positives, since a device could also
12 simply be in an environment where there are no frames on the air.
13 However, in this case doing a reset should be harmless since it's
14 obviously not interrupting any real activity. To avoid confusion, call
15 the reset counters in this case "Rx path inactive" instead of something
16 like "Rx path deaf", since it may not be an indication of a real
19 Signed-off-by: Felix Fietkau <nbd@nbd.name>
22 --- a/drivers/net/wireless/ath/ath9k/ath9k.h
23 +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
24 @@ -1027,6 +1027,7 @@ struct ath_softc {
29 u16 ps_flags; /* PS_* */
32 --- a/drivers/net/wireless/ath/ath9k/debug.c
33 +++ b/drivers/net/wireless/ath/ath9k/debug.c
34 @@ -763,6 +763,7 @@ static int read_file_reset(struct seq_fi
35 [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
36 [RESET_TYPE_MCI] = "MCI Reset",
37 [RESET_TYPE_CALIBRATION] = "Calibration error",
38 + [RESET_TYPE_RX_INACTIVE] = "Rx path inactive",
39 [RESET_TX_DMA_ERROR] = "Tx DMA stop error",
40 [RESET_RX_DMA_ERROR] = "Rx DMA stop error",
42 --- a/drivers/net/wireless/ath/ath9k/debug.h
43 +++ b/drivers/net/wireless/ath/ath9k/debug.h
44 @@ -50,6 +50,7 @@ enum ath_reset_type {
45 RESET_TYPE_BEACON_STUCK,
47 RESET_TYPE_CALIBRATION,
48 + RESET_TYPE_RX_INACTIVE,
52 --- a/drivers/net/wireless/ath/ath9k/link.c
53 +++ b/drivers/net/wireless/ath/ath9k/link.c
54 @@ -53,13 +53,27 @@ reset:
58 +static bool ath_rx_active_check(struct ath_softc *sc)
60 + if (sc->rx_active) {
65 + ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
66 + "rx path inactive, resetting the chip\n");
67 + ath9k_queue_reset(sc, RESET_TYPE_RX_INACTIVE);
71 void ath_hw_check_work(struct work_struct *work)
73 struct ath_softc *sc = container_of(work, struct ath_softc,
76 if (!ath_hw_check(sc) ||
77 - !ath_tx_complete_check(sc))
78 + !ath_tx_complete_check(sc) ||
79 + !ath_rx_active_check(sc))
82 ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work,
83 --- a/drivers/net/wireless/ath/ath9k/main.c
84 +++ b/drivers/net/wireless/ath/ath9k/main.c
85 @@ -269,6 +269,7 @@ static bool ath_complete_reset(struct at
91 ath9k_hw_set_interrupts(ah);
92 ath9k_hw_enable_interrupts(ah);
93 @@ -452,6 +453,7 @@ void ath9k_tasklet(unsigned long data)
94 ath_rx_tasklet(sc, 0, true);
96 ath_rx_tasklet(sc, 0, false);
100 if (status & ATH9K_INT_TX) {