ath9k: fix false positives in the baseband hang check by repeating the test a few...
authorFelix Fietkau <nbd@openwrt.org>
Thu, 1 Jul 2010 21:41:40 +0000 (21:41 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Thu, 1 Jul 2010 21:41:40 +0000 (21:41 +0000)
SVN-Revision: 22038

package/mac80211/patches/540-ath9k_hang_check.patch [new file with mode: 0644]

diff --git a/package/mac80211/patches/540-ath9k_hang_check.patch b/package/mac80211/patches/540-ath9k_hang_check.patch
new file mode 100644 (file)
index 0000000..85e03bc
--- /dev/null
@@ -0,0 +1,90 @@
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -428,6 +428,7 @@ int ath_beaconq_config(struct ath_softc 
+ #define ATH_PAPRD_TIMEOUT     100 /* msecs */
++void ath_hw_check(struct work_struct *work);
+ void ath_paprd_calibrate(struct work_struct *work);
+ void ath_ani_calibrate(unsigned long data);
+@@ -563,6 +564,7 @@ struct ath_softc {
+       spinlock_t sc_pm_lock;
+       struct mutex mutex;
+       struct work_struct paprd_work;
++      struct work_struct hw_check_work;
+       struct completion paprd_complete;
+       u32 intrstatus;
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -516,6 +516,25 @@ static void ath_node_detach(struct ath_s
+               ath_tx_node_cleanup(sc, an);
+ }
++void ath_hw_check(struct work_struct *work)
++{
++      struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
++      int i;
++
++      ath9k_ps_wakeup(sc);
++
++      for (i = 0; i < 3; i++) {
++              if (ath9k_hw_check_alive(sc->sc_ah))
++                      goto out;
++
++              msleep(1);
++      }
++      ath_reset(sc, false);
++
++out:
++      ath9k_ps_restore(sc);
++}
++
+ void ath9k_tasklet(unsigned long data)
+ {
+       struct ath_softc *sc = (struct ath_softc *)data;
+@@ -527,13 +546,15 @@ void ath9k_tasklet(unsigned long data)
+       ath9k_ps_wakeup(sc);
+-      if ((status & ATH9K_INT_FATAL) ||
+-          !ath9k_hw_check_alive(ah)) {
++      if (status & ATH9K_INT_FATAL) {
+               ath_reset(sc, false);
+               ath9k_ps_restore(sc);
+               return;
+       }
++      if (!ath9k_hw_check_alive(ah))
++              ieee80211_queue_work(sc->hw, &sc->hw_check_work);
++
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+               rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
+                         ATH9K_INT_RXORN);
+@@ -1254,6 +1275,7 @@ static void ath9k_stop(struct ieee80211_
+       cancel_delayed_work_sync(&sc->tx_complete_work);
+       cancel_work_sync(&sc->paprd_work);
++      cancel_work_sync(&sc->hw_check_work);
+       if (!sc->num_sec_wiphy) {
+               cancel_delayed_work_sync(&sc->wiphy_work);
+@@ -1977,6 +1999,7 @@ static void ath9k_sw_scan_start(struct i
+       sc->sc_flags |= SC_OP_SCANNING;
+       del_timer_sync(&common->ani.timer);
+       cancel_work_sync(&sc->paprd_work);
++      cancel_work_sync(&sc->hw_check_work);
+       cancel_delayed_work_sync(&sc->tx_complete_work);
+       mutex_unlock(&sc->mutex);
+ }
+--- a/drivers/net/wireless/ath/ath9k/init.c
++++ b/drivers/net/wireless/ath/ath9k/init.c
+@@ -751,6 +751,7 @@ int ath9k_init_device(u16 devid, struct 
+                       goto error_world;
+       }
++      INIT_WORK(&sc->hw_check_work, ath_hw_check);
+       INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
+       INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
+       INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);