From 5a05cb40ce04154772ab333bc1587beaad68717d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 13 Nov 2014 17:38:22 +0000 Subject: [PATCH] ath9k: fix crashes when using shared IRQs Signed-off-by: Felix Fietkau SVN-Revision: 43239 --- ...t-early-IRQs-from-accessing-hardware.patch | 38 ++++++++++++++ ...OP_INVALID-before-disabling-hardware.patch | 29 +++++++++++ ...access-hardware-on-IRQs-during-reset.patch | 51 +++++++++++++++++++ .../410-ath9k_allow_adhoc_and_ap.patch | 2 +- .../mac80211/patches/501-ath9k_ahb_init.patch | 2 +- .../patches/530-ath9k_extra_leds.patch | 2 +- .../patches/542-ath9k_debugfs_diag.patch | 2 +- .../patches/543-ath9k_entropy_from_adc.patch | 6 +-- 8 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 package/kernel/mac80211/patches/309-ath9k-prevent-early-IRQs-from-accessing-hardware.patch create mode 100644 package/kernel/mac80211/patches/310-ath9k-set-ATH_OP_INVALID-before-disabling-hardware.patch create mode 100644 package/kernel/mac80211/patches/311-ath9k-do-not-access-hardware-on-IRQs-during-reset.patch diff --git a/package/kernel/mac80211/patches/309-ath9k-prevent-early-IRQs-from-accessing-hardware.patch b/package/kernel/mac80211/patches/309-ath9k-prevent-early-IRQs-from-accessing-hardware.patch new file mode 100644 index 0000000000..6af94c8ea6 --- /dev/null +++ b/package/kernel/mac80211/patches/309-ath9k-prevent-early-IRQs-from-accessing-hardware.patch @@ -0,0 +1,38 @@ +From: Felix Fietkau +Date: Thu, 13 Nov 2014 18:27:47 +0100 +Subject: [PATCH] ath9k: prevent early IRQs from accessing hardware + +IRQs are suppressed if ah == NULL and ATH_OP_INVALID being set in +common->op_flags. Close a short time window between those two. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -513,10 +513,14 @@ static int ath9k_init_softc(u16 devid, s + ah->reg_ops.read = ath9k_ioread32; + ah->reg_ops.write = ath9k_iowrite32; + ah->reg_ops.rmw = ath9k_reg_rmw; +- sc->sc_ah = ah; + pCap = &ah->caps; + + common = ath9k_hw_common(ah); ++ ++ /* Will be cleared in ath9k_start() */ ++ set_bit(ATH_OP_INVALID, &common->op_flags); ++ ++ sc->sc_ah = ah; + sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET); + sc->tx99_power = MAX_RATE_POWER + 1; + init_waitqueue_head(&sc->tx_wait); +@@ -876,9 +880,6 @@ int ath9k_init_device(u16 devid, struct + common = ath9k_hw_common(ah); + ath9k_set_hw_capab(sc, hw); + +- /* Will be cleared in ath9k_start() */ +- set_bit(ATH_OP_INVALID, &common->op_flags); +- + /* Initialize regulatory */ + error = ath_regd_init(&common->regulatory, sc->hw->wiphy, + ath9k_reg_notifier); diff --git a/package/kernel/mac80211/patches/310-ath9k-set-ATH_OP_INVALID-before-disabling-hardware.patch b/package/kernel/mac80211/patches/310-ath9k-set-ATH_OP_INVALID-before-disabling-hardware.patch new file mode 100644 index 0000000000..c382e5d103 --- /dev/null +++ b/package/kernel/mac80211/patches/310-ath9k-set-ATH_OP_INVALID-before-disabling-hardware.patch @@ -0,0 +1,29 @@ +From: Felix Fietkau +Date: Thu, 13 Nov 2014 18:29:00 +0100 +Subject: [PATCH] ath9k: set ATH_OP_INVALID before disabling hardware + +Closes another small IRQ handler race + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -885,6 +885,9 @@ static void ath9k_stop(struct ieee80211_ + &sc->cur_chan->chandef); + + ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); ++ ++ set_bit(ATH_OP_INVALID, &common->op_flags); ++ + ath9k_hw_phy_disable(ah); + + ath9k_hw_configpcipowersave(ah, true); +@@ -893,7 +896,6 @@ static void ath9k_stop(struct ieee80211_ + + ath9k_ps_restore(sc); + +- set_bit(ATH_OP_INVALID, &common->op_flags); + sc->ps_idle = prev_idle; + + mutex_unlock(&sc->mutex); diff --git a/package/kernel/mac80211/patches/311-ath9k-do-not-access-hardware-on-IRQs-during-reset.patch b/package/kernel/mac80211/patches/311-ath9k-do-not-access-hardware-on-IRQs-during-reset.patch new file mode 100644 index 0000000000..7996725025 --- /dev/null +++ b/package/kernel/mac80211/patches/311-ath9k-do-not-access-hardware-on-IRQs-during-reset.patch @@ -0,0 +1,51 @@ +From: Felix Fietkau +Date: Thu, 13 Nov 2014 18:29:26 +0100 +Subject: [PATCH] ath9k: do not access hardware on IRQs during reset + +Instead of killing interrupts during reset when the first one happens, +kill them before issuing the reset. +This fixes an easy to reproduce crash with multiple cards sharing the +same IRQ. + +Cc: stable@vger.kernel.org +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -512,16 +512,13 @@ irqreturn_t ath_isr(int irq, void *dev) + if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags)) + return IRQ_NONE; + +- /* shared irq, not for us */ ++ if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) ++ return IRQ_NONE; + ++ /* shared irq, not for us */ + if (!ath9k_hw_intrpend(ah)) + return IRQ_NONE; + +- if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { +- ath9k_hw_kill_interrupts(ah); +- return IRQ_HANDLED; +- } +- + /* + * Figure out the reason(s) for the interrupt. Note + * that the hal returns a pseudo-ISR that may include +@@ -613,6 +610,7 @@ int ath_reset(struct ath_softc *sc, stru + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + int r; + ++ ath9k_hw_kill_interrupts(sc->sc_ah); + set_bit(ATH_OP_HW_RESET, &common->op_flags); + + ath9k_ps_wakeup(sc); +@@ -633,6 +631,7 @@ void ath9k_queue_reset(struct ath_softc + #ifdef CPTCFG_ATH9K_DEBUGFS + RESET_STAT_INC(sc, type); + #endif ++ ath9k_hw_kill_interrupts(sc->sc_ah); + set_bit(ATH_OP_HW_RESET, &common->op_flags); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + } diff --git a/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch b/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch index ebcb34c381..16bf144ecf 100644 --- a/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch +++ b/package/kernel/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -680,6 +680,7 @@ static const struct ieee80211_iface_limi +@@ -684,6 +684,7 @@ static const struct ieee80211_iface_limi BIT(NL80211_IFTYPE_AP) }, { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) }, diff --git a/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch b/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch index eaae68d40b..965cb6b088 100644 --- a/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch +++ b/package/kernel/mac80211/patches/501-ath9k_ahb_init.patch @@ -1,6 +1,6 @@ --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -989,23 +989,23 @@ static int __init ath9k_init(void) +@@ -990,23 +990,23 @@ static int __init ath9k_init(void) { int error; diff --git a/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch index d7dd4314fd..cb6c477f3e 100644 --- a/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch +++ b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch @@ -162,7 +162,7 @@ void ath_fill_led_pin(struct ath_softc *sc) --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -902,7 +902,7 @@ int ath9k_init_device(u16 devid, struct +@@ -903,7 +903,7 @@ int ath9k_init_device(u16 devid, struct #ifdef CPTCFG_MAC80211_LEDS /* must be initialized before ieee80211_register_hw */ diff --git a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch index 38c0c63529..e135970451 100644 --- a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch +++ b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch @@ -125,7 +125,7 @@ REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c -@@ -532,6 +532,11 @@ irqreturn_t ath_isr(int irq, void *dev) +@@ -529,6 +529,11 @@ irqreturn_t ath_isr(int irq, void *dev) ath9k_debug_sync_cause(sc, sync_cause); status &= ah->imask; /* discard unasked-for bits */ diff --git a/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch b/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch index 9d789b40a7..89f89ece0e 100644 --- a/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch +++ b/package/kernel/mac80211/patches/543-ath9k_entropy_from_adc.patch @@ -55,7 +55,7 @@ ops->spectral_scan_config = ar9003_hw_spectral_scan_config; --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c -@@ -668,7 +668,8 @@ static void ath9k_init_txpower_limits(st +@@ -672,7 +672,8 @@ static void ath9k_init_txpower_limits(st if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ); @@ -65,7 +65,7 @@ } static const struct ieee80211_iface_limit if_limits[] = { -@@ -859,6 +860,18 @@ static void ath9k_set_hw_capab(struct at +@@ -863,6 +864,18 @@ static void ath9k_set_hw_capab(struct at SET_IEEE80211_PERM_ADDR(hw, common->macaddr); } @@ -84,7 +84,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops) { -@@ -907,6 +920,8 @@ int ath9k_init_device(u16 devid, struct +@@ -908,6 +921,8 @@ int ath9k_init_device(u16 devid, struct ARRAY_SIZE(ath9k_tpt_blink)); #endif -- 2.34.1