aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@nbd.name>2017-01-25 15:32:18 +0100
committerFelix Fietkau <nbd@nbd.name>2017-01-25 16:25:48 +0100
commitb94177e10fc72f9309eae7459c3570e5c080e960 (patch)
tree26efa9c6172b394c2113926cfa7b6aad6c9ebc1f /package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch
parent4cacc1c5f5e01594d4e9148a7b34946845424e24 (diff)
downloadupstream-b94177e10fc72f9309eae7459c3570e5c080e960.tar.gz
upstream-b94177e10fc72f9309eae7459c3570e5c080e960.tar.bz2
upstream-b94177e10fc72f9309eae7459c3570e5c080e960.zip
ath9k: add stability fixes for long standing hang issues (FS#13, #34, #373, #383)
The radio would stop communicating completely. This issue was easiest to trigger on AR913x devices, e.g. the TP-Link TL-WR1043ND, but other hardware was occasionally affected as well. The most critical issue was a race condition in disabling/enabling IRQs between the IRQ handler and the IRQ processing tasklet Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch')
-rw-r--r--package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch100
1 files changed, 100 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch b/package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch
new file mode 100644
index 0000000000..347d06ec88
--- /dev/null
+++ b/package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch
@@ -0,0 +1,100 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 25 Jan 2017 13:00:58 +0100
+Subject: [PATCH] ath9k: check for deaf rx path state
+
+Various chips occasionally run into a state where the tx path still
+appears to be working normally, but the rx path is deaf.
+
+There is no known register signature to check for this state explicitly,
+so use the lack of rx interrupts as an indicator.
+
+This detection is prone to false positives, since a device could also
+simply be in an environment where there are no frames on the air.
+However, in this case doing a reset should be harmless since it's
+obviously not interrupting any real activity. To avoid confusion, call
+the reset counters in this case "Rx path inactive" instead of something
+like "Rx path deaf", since it may not be an indication of a real
+hardware failure.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -1027,6 +1027,7 @@ struct ath_softc {
+
+ u8 gtt_cnt;
+ u32 intrstatus;
++ u32 rx_active;
+ u16 ps_flags; /* PS_* */
+ bool ps_enabled;
+ bool ps_idle;
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -763,6 +763,7 @@ static int read_file_reset(struct seq_fi
+ [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
+ [RESET_TYPE_MCI] = "MCI Reset",
+ [RESET_TYPE_CALIBRATION] = "Calibration error",
++ [RESET_TYPE_RX_INACTIVE] = "Rx path inactive",
+ [RESET_TX_DMA_ERROR] = "Tx DMA stop error",
+ [RESET_RX_DMA_ERROR] = "Rx DMA stop error",
+ };
+--- a/drivers/net/wireless/ath/ath9k/debug.h
++++ b/drivers/net/wireless/ath/ath9k/debug.h
+@@ -50,6 +50,7 @@ enum ath_reset_type {
+ RESET_TYPE_BEACON_STUCK,
+ RESET_TYPE_MCI,
+ RESET_TYPE_CALIBRATION,
++ RESET_TYPE_RX_INACTIVE,
+ RESET_TX_DMA_ERROR,
+ RESET_RX_DMA_ERROR,
+ __RESET_TYPE_MAX
+--- a/drivers/net/wireless/ath/ath9k/link.c
++++ b/drivers/net/wireless/ath/ath9k/link.c
+@@ -53,13 +53,27 @@ reset:
+
+ }
+
++static bool ath_rx_active_check(struct ath_softc *sc)
++{
++ if (sc->rx_active) {
++ sc->rx_active = 0;
++ return true;
++ }
++
++ ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
++ "rx path inactive, resetting the chip\n");
++ ath9k_queue_reset(sc, RESET_TYPE_RX_INACTIVE);
++ return false;
++}
++
+ void ath_hw_check_work(struct work_struct *work)
+ {
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ hw_check_work.work);
+
+ if (!ath_hw_check(sc) ||
+- !ath_tx_complete_check(sc))
++ !ath_tx_complete_check(sc) ||
++ !ath_rx_active_check(sc))
+ return;
+
+ ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work,
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -269,6 +269,7 @@ static bool ath_complete_reset(struct at
+ }
+
+ sc->gtt_cnt = 0;
++ sc->rx_active = 1;
+
+ ath9k_hw_set_interrupts(ah);
+ ath9k_hw_enable_interrupts(ah);
+@@ -452,6 +453,7 @@ void ath9k_tasklet(unsigned long data)
+ ath_rx_tasklet(sc, 0, true);
+
+ ath_rx_tasklet(sc, 0, false);
++ sc->rx_active = 1;
+ }
+
+ if (status & ATH9K_INT_TX) {