Browse Source

ath9k: fix crashes when using shared IRQs

Signed-off-by: Felix Fietkau <[email protected]>

SVN-Revision: 43239
Felix Fietkau 11 years ago
parent
commit
5a05cb40ce

+ 38 - 0
package/kernel/mac80211/patches/309-ath9k-prevent-early-IRQs-from-accessing-hardware.patch

@@ -0,0 +1,38 @@
+From: Felix Fietkau <[email protected]>
+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 <[email protected]>
+---
+
+--- 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);

+ 29 - 0
package/kernel/mac80211/patches/310-ath9k-set-ATH_OP_INVALID-before-disabling-hardware.patch

@@ -0,0 +1,29 @@
+From: Felix Fietkau <[email protected]>
+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 <[email protected]>
+---
+
+--- 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);

+ 51 - 0
package/kernel/mac80211/patches/311-ath9k-do-not-access-hardware-on-IRQs-during-reset.patch

@@ -0,0 +1,51 @@
+From: Felix Fietkau <[email protected]>
+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: [email protected]
+Signed-off-by: Felix Fietkau <[email protected]>
+---
+
+--- 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);
+ }

+ 1 - 1
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) },

+ 1 - 1
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;
  

+ 1 - 1
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 */

+ 1 - 1
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 */
  

+ 3 - 3
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