diff options
author | Felix Fietkau <nbd@nbd.name> | 2017-01-25 15:32:18 +0100 |
---|---|---|
committer | Felix Fietkau <nbd@nbd.name> | 2017-01-25 16:25:48 +0100 |
commit | b94177e10fc72f9309eae7459c3570e5c080e960 (patch) | |
tree | 26efa9c6172b394c2113926cfa7b6aad6c9ebc1f /package/kernel/mac80211/patches/356-ath9k-check-for-deaf-rx-path-state.patch | |
parent | 4cacc1c5f5e01594d4e9148a7b34946845424e24 (diff) | |
download | upstream-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.patch | 100 |
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) { |