ath9k: reorganize patches, reset hardware after full sleep (fixes #10349)
authorFelix Fietkau <nbd@openwrt.org>
Tue, 15 Nov 2011 14:53:21 +0000 (14:53 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Tue, 15 Nov 2011 14:53:21 +0000 (14:53 +0000)
SVN-Revision: 29155

package/mac80211/patches/560-ath9k_fix_radio_stop.patch [deleted file]
package/mac80211/patches/560-ath9k_reset_after_full_sleep.patch [new file with mode: 0644]
package/mac80211/patches/561-ath9k_fix_flush.patch [deleted file]
package/mac80211/patches/561-ath9k_fix_ps_idle_handling.patch [new file with mode: 0644]
package/mac80211/patches/562-ath9k_fix_flush.patch [new file with mode: 0644]
package/mac80211/patches/562-ath9k_fix_led.patch [deleted file]
package/mac80211/patches/563-ath9k_fix_full_sleep_tx.patch [deleted file]

diff --git a/package/mac80211/patches/560-ath9k_fix_radio_stop.patch b/package/mac80211/patches/560-ath9k_fix_radio_stop.patch
deleted file mode 100644 (file)
index 2367ffa..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -880,82 +880,6 @@ chip_reset:
- #undef SCHED_INTR
- }
--static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
--{
--      struct ath_hw *ah = sc->sc_ah;
--      struct ath_common *common = ath9k_hw_common(ah);
--      struct ieee80211_channel *channel = hw->conf.channel;
--      int r;
--
--      ath9k_ps_wakeup(sc);
--      spin_lock_bh(&sc->sc_pcu_lock);
--      atomic_set(&ah->intr_ref_cnt, -1);
--
--      ath9k_hw_configpcipowersave(ah, false);
--
--      if (!ah->curchan)
--              ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah);
--
--      r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
--      if (r) {
--              ath_err(common,
--                      "Unable to reset channel (%u MHz), reset status %d\n",
--                      channel->center_freq, r);
--      }
--
--      ath_complete_reset(sc, true);
--
--      /* Enable LED */
--      ath9k_hw_cfg_output(ah, ah->led_pin,
--                          AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
--      ath9k_hw_set_gpio(ah, ah->led_pin, 0);
--
--      spin_unlock_bh(&sc->sc_pcu_lock);
--
--      ath9k_ps_restore(sc);
--}
--
--void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
--{
--      struct ath_hw *ah = sc->sc_ah;
--      struct ieee80211_channel *channel = hw->conf.channel;
--      int r;
--
--      ath9k_ps_wakeup(sc);
--
--      ath_cancel_work(sc);
--
--      spin_lock_bh(&sc->sc_pcu_lock);
--
--      /*
--       * Keep the LED on when the radio is disabled
--       * during idle unassociated state.
--       */
--      if (!sc->ps_idle) {
--              ath9k_hw_set_gpio(ah, ah->led_pin, 1);
--              ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
--      }
--
--      ath_prepare_reset(sc, false, true);
--
--      if (!ah->curchan)
--              ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
--
--      r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
--      if (r) {
--              ath_err(ath9k_hw_common(sc->sc_ah),
--                      "Unable to reset channel (%u MHz), reset status %d\n",
--                      channel->center_freq, r);
--      }
--
--      ath9k_hw_phy_disable(ah);
--
--      ath9k_hw_configpcipowersave(ah, true);
--
--      spin_unlock_bh(&sc->sc_pcu_lock);
--      ath9k_ps_restore(sc);
--}
--
- static int ath_reset(struct ath_softc *sc, bool retry_tx)
- {
-       int r;
-@@ -1091,6 +1015,9 @@ static int ath9k_start(struct ieee80211_
-        * and then setup of the interrupt mask.
-        */
-       spin_lock_bh(&sc->sc_pcu_lock);
-+
-+      atomic_set(&ah->intr_ref_cnt, -1);
-+
-       r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
-       if (r) {
-               ath_err(common,
-@@ -1129,6 +1056,16 @@ static int ath9k_start(struct ieee80211_
-               goto mutex_unlock;
-       }
-+      ath9k_hw_cfg_output(ah, ah->led_pin,
-+                          AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-+      ath9k_hw_set_gpio(ah, ah->led_pin, 0);
-+
-+      /*
-+       * Reset key cache to sane defaults (all entries cleared) instead of
-+       * semi-random values after suspend/resume.
-+       */
-+      ath9k_cmn_init_crypto(sc->sc_ah);
-+
-       spin_unlock_bh(&sc->sc_pcu_lock);
-       if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
-@@ -1248,33 +1185,39 @@ static void ath9k_stop(struct ieee80211_
-        * before setting the invalid flag. */
-       ath9k_hw_disable_interrupts(ah);
--      if (!(sc->sc_flags & SC_OP_INVALID)) {
--              ath_drain_all_txq(sc, false);
--              ath_stoprecv(sc);
--              ath9k_hw_phy_disable(ah);
--      } else
--              sc->rx.rxlink = NULL;
-+      spin_unlock_bh(&sc->sc_pcu_lock);
-+
-+      /* we can now sync irq and kill any running tasklets, since we already
-+       * disabled interrupts and not holding a spin lock */
-+      synchronize_irq(sc->irq);
-+      tasklet_kill(&sc->intr_tq);
-+      tasklet_kill(&sc->bcon_tasklet);
-+
-+      sc->ps_idle = true;
-+
-+      spin_lock_bh(&sc->sc_pcu_lock);
-+
-+      ath9k_hw_set_gpio(ah, ah->led_pin, 1);
-+      ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
-+
-+      ath_prepare_reset(sc, false, true);
-       if (sc->rx.frag) {
-               dev_kfree_skb_any(sc->rx.frag);
-               sc->rx.frag = NULL;
-       }
--      /* disable HAL and put h/w to sleep */
--      ath9k_hw_disable(ah);
-+      if (!ah->curchan)
-+              ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
--      spin_unlock_bh(&sc->sc_pcu_lock);
-+      ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
-+      ath9k_hw_phy_disable(ah);
--      /* we can now sync irq and kill any running tasklets, since we already
--       * disabled interrupts and not holding a spin lock */
--      synchronize_irq(sc->irq);
--      tasklet_kill(&sc->intr_tq);
--      tasklet_kill(&sc->bcon_tasklet);
-+      ath9k_hw_configpcipowersave(ah, true);
--      ath9k_ps_restore(sc);
-+      spin_unlock_bh(&sc->sc_pcu_lock);
--      sc->ps_idle = true;
--      ath_radio_disable(sc, hw);
-+      ath9k_ps_restore(sc);
-       sc->sc_flags |= SC_OP_INVALID;
-@@ -1598,8 +1541,8 @@ static int ath9k_config(struct ieee80211
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ieee80211_conf *conf = &hw->conf;
--      bool disable_radio = false;
-+      ath9k_ps_wakeup(sc);
-       mutex_lock(&sc->mutex);
-       /*
-@@ -1608,16 +1551,8 @@ static int ath9k_config(struct ieee80211
-        * of the changes. Likewise we must only disable the radio towards
-        * the end.
-        */
--      if (changed & IEEE80211_CONF_CHANGE_IDLE) {
-+      if (changed & IEEE80211_CONF_CHANGE_IDLE)
-               sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
--              if (!sc->ps_idle) {
--                      ath_radio_enable(sc, hw);
--                      ath_dbg(common, ATH_DBG_CONFIG,
--                              "not-idle: enabling radio\n");
--              } else {
--                      disable_radio = true;
--              }
--      }
-       /*
-        * We just prepare to enable PS. We have to wait until our AP has
-@@ -1742,19 +1677,13 @@ static int ath9k_config(struct ieee80211
-               ath_dbg(common, ATH_DBG_CONFIG,
-                       "Set power: %d\n", conf->power_level);
-               sc->config.txpowlimit = 2 * conf->power_level;
--              ath9k_ps_wakeup(sc);
-               ath9k_cmn_update_txpow(ah, sc->curtxpow,
-                                      sc->config.txpowlimit, &sc->curtxpow);
--              ath9k_ps_restore(sc);
-               conf->cur_power_level = sc->curtxpow / 2;
-       }
--      if (disable_radio) {
--              ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
--              ath_radio_disable(sc, hw);
--      }
--
-       mutex_unlock(&sc->mutex);
-+      ath9k_ps_restore(sc);
-       return 0;
- }
---- a/drivers/net/wireless/ath/ath9k/pci.c
-+++ b/drivers/net/wireless/ath/ath9k/pci.c
-@@ -306,12 +306,11 @@ static int ath_pci_suspend(struct device
-       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
-       struct ath_softc *sc = hw->priv;
--      ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
--
-       /* The device has to be moved to FULLSLEEP forcibly.
-        * Otherwise the chip never moved to full sleep,
-        * when no interface is up.
-        */
-+      ath9k_hw_disable(sc->sc_ah);
-       ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
-       return 0;
-@@ -333,22 +332,6 @@ static int ath_pci_resume(struct device 
-       if ((val & 0x0000ff00) != 0)
-               pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
--      ath9k_ps_wakeup(sc);
--      /* Enable LED */
--      ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
--                          AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
--      ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
--
--        /*
--         * Reset key cache to sane defaults (all entries cleared) instead of
--         * semi-random values after suspend/resume.
--         */
--      ath9k_cmn_init_crypto(sc->sc_ah);
--      ath9k_ps_restore(sc);
--
--      sc->ps_idle = true;
--      ath_radio_disable(sc, hw);
--
-       return 0;
- }
diff --git a/package/mac80211/patches/560-ath9k_reset_after_full_sleep.patch b/package/mac80211/patches/560-ath9k_reset_after_full_sleep.patch
new file mode 100644 (file)
index 0000000..9a5b580
--- /dev/null
@@ -0,0 +1,68 @@
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -619,6 +619,7 @@ struct ath_softc {
+       u16 curtxpow;
+       bool ps_enabled;
+       bool ps_idle;
++      bool ps_fullsleep;
+       short nbcnvifs;
+       short nvifs;
+       unsigned long ps_usecount;
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -118,9 +118,10 @@ void ath9k_ps_restore(struct ath_softc *
+       if (--sc->ps_usecount != 0)
+               goto unlock;
+-      if (sc->ps_idle)
++      if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK)) {
+               mode = ATH9K_PM_FULL_SLEEP;
+-      else if (sc->ps_enabled &&
++              sc->ps_fullsleep = true;
++      } else if (sc->ps_enabled &&
+                !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
+                             PS_WAIT_FOR_CAB |
+                             PS_WAIT_FOR_PSPOLL_DATA |
+@@ -275,6 +276,7 @@ static bool ath_complete_reset(struct at
+                              sc->config.txpowlimit, &sc->curtxpow);
+       ath9k_hw_set_interrupts(ah);
+       ath9k_hw_enable_interrupts(ah);
++      sc->ps_fullsleep = false;
+       if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) {
+               if (sc->sc_flags & SC_OP_BEACONS)
+@@ -332,7 +334,8 @@ static int ath_reset_internal(struct ath
+               hchan = ah->curchan;
+       }
+-      if (fastcc && !ath9k_hw_check_alive(ah))
++      if (fastcc && (sc->ps_fullsleep ||
++          !ath9k_hw_check_alive(ah)))
+               fastcc = false;
+       if (!ath_prepare_reset(sc, retry_tx, flush))
+@@ -1173,6 +1176,13 @@ static void ath9k_tx(struct ieee80211_hw
+               }
+       }
++      /*
++       * Cannot tx while the hardware is in full sleep, it first needs a full
++       * chip reset to recover from that
++       */
++      if (unlikely(sc->sc_ah->power_mode == ATH9K_PM_FULL_SLEEP))
++              goto exit;
++
+       if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) {
+               /*
+                * We are using PS-Poll and mac80211 can request TX while in
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -1983,7 +1983,7 @@ static void ath_tx_complete(struct ath_s
+               skb_pull(skb, padsize);
+       }
+-      if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
++      if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
+               sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
+               ath_dbg(common, ATH_DBG_PS,
+                       "Going back to sleep after having received TX status (0x%lx)\n",
diff --git a/package/mac80211/patches/561-ath9k_fix_flush.patch b/package/mac80211/patches/561-ath9k_fix_flush.patch
deleted file mode 100644 (file)
index df20890..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -2251,9 +2251,6 @@ static void ath9k_flush(struct ieee80211
-               return;
-       }
--      if (drop)
--              timeout = 1;
--
-       for (j = 0; j < timeout; j++) {
-               bool npend = false;
-@@ -2271,21 +2268,22 @@ static void ath9k_flush(struct ieee80211
-               }
-               if (!npend)
--                  goto out;
-+                  break;
-       }
--      ath9k_ps_wakeup(sc);
--      spin_lock_bh(&sc->sc_pcu_lock);
--      drain_txq = ath_drain_all_txq(sc, false);
--      spin_unlock_bh(&sc->sc_pcu_lock);
-+      if (drop) {
-+              ath9k_ps_wakeup(sc);
-+              spin_lock_bh(&sc->sc_pcu_lock);
-+              drain_txq = ath_drain_all_txq(sc, false);
-+              spin_unlock_bh(&sc->sc_pcu_lock);
--      if (!drain_txq)
--              ath_reset(sc, false);
-+              if (!drain_txq)
-+                      ath_reset(sc, false);
--      ath9k_ps_restore(sc);
--      ieee80211_wake_queues(hw);
-+              ath9k_ps_restore(sc);
-+              ieee80211_wake_queues(hw);
-+      }
--out:
-       ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
-       mutex_unlock(&sc->mutex);
- }
diff --git a/package/mac80211/patches/561-ath9k_fix_ps_idle_handling.patch b/package/mac80211/patches/561-ath9k_fix_ps_idle_handling.patch
new file mode 100644 (file)
index 0000000..40f24e1
--- /dev/null
@@ -0,0 +1,273 @@
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -883,82 +883,6 @@ chip_reset:
+ #undef SCHED_INTR
+ }
+-static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
+-{
+-      struct ath_hw *ah = sc->sc_ah;
+-      struct ath_common *common = ath9k_hw_common(ah);
+-      struct ieee80211_channel *channel = hw->conf.channel;
+-      int r;
+-
+-      ath9k_ps_wakeup(sc);
+-      spin_lock_bh(&sc->sc_pcu_lock);
+-      atomic_set(&ah->intr_ref_cnt, -1);
+-
+-      ath9k_hw_configpcipowersave(ah, false);
+-
+-      if (!ah->curchan)
+-              ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah);
+-
+-      r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
+-      if (r) {
+-              ath_err(common,
+-                      "Unable to reset channel (%u MHz), reset status %d\n",
+-                      channel->center_freq, r);
+-      }
+-
+-      ath_complete_reset(sc, true);
+-
+-      /* Enable LED */
+-      ath9k_hw_cfg_output(ah, ah->led_pin,
+-                          AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+-      ath9k_hw_set_gpio(ah, ah->led_pin, 0);
+-
+-      spin_unlock_bh(&sc->sc_pcu_lock);
+-
+-      ath9k_ps_restore(sc);
+-}
+-
+-void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
+-{
+-      struct ath_hw *ah = sc->sc_ah;
+-      struct ieee80211_channel *channel = hw->conf.channel;
+-      int r;
+-
+-      ath9k_ps_wakeup(sc);
+-
+-      ath_cancel_work(sc);
+-
+-      spin_lock_bh(&sc->sc_pcu_lock);
+-
+-      /*
+-       * Keep the LED on when the radio is disabled
+-       * during idle unassociated state.
+-       */
+-      if (!sc->ps_idle) {
+-              ath9k_hw_set_gpio(ah, ah->led_pin, 1);
+-              ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
+-      }
+-
+-      ath_prepare_reset(sc, false, true);
+-
+-      if (!ah->curchan)
+-              ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
+-
+-      r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
+-      if (r) {
+-              ath_err(ath9k_hw_common(sc->sc_ah),
+-                      "Unable to reset channel (%u MHz), reset status %d\n",
+-                      channel->center_freq, r);
+-      }
+-
+-      ath9k_hw_phy_disable(ah);
+-
+-      ath9k_hw_configpcipowersave(ah, true);
+-
+-      spin_unlock_bh(&sc->sc_pcu_lock);
+-      ath9k_ps_restore(sc);
+-}
+-
+ static int ath_reset(struct ath_softc *sc, bool retry_tx)
+ {
+       int r;
+@@ -1094,6 +1018,9 @@ static int ath9k_start(struct ieee80211_
+        * and then setup of the interrupt mask.
+        */
+       spin_lock_bh(&sc->sc_pcu_lock);
++
++      atomic_set(&ah->intr_ref_cnt, -1);
++
+       r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
+       if (r) {
+               ath_err(common,
+@@ -1132,6 +1059,18 @@ static int ath9k_start(struct ieee80211_
+               goto mutex_unlock;
+       }
++      if (ah->led_pin >= 0) {
++              ath9k_hw_cfg_output(ah, ah->led_pin,
++                                  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
++              ath9k_hw_set_gpio(ah, ah->led_pin, 0);
++      }
++
++      /*
++       * Reset key cache to sane defaults (all entries cleared) instead of
++       * semi-random values after suspend/resume.
++       */
++      ath9k_cmn_init_crypto(sc->sc_ah);
++
+       spin_unlock_bh(&sc->sc_pcu_lock);
+       if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
+@@ -1229,6 +1168,7 @@ static void ath9k_stop(struct ieee80211_
+       struct ath_softc *sc = hw->priv;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
++      bool prev_idle;
+       mutex_lock(&sc->mutex);
+@@ -1258,35 +1198,45 @@ static void ath9k_stop(struct ieee80211_
+        * before setting the invalid flag. */
+       ath9k_hw_disable_interrupts(ah);
+-      if (!(sc->sc_flags & SC_OP_INVALID)) {
+-              ath_drain_all_txq(sc, false);
+-              ath_stoprecv(sc);
+-              ath9k_hw_phy_disable(ah);
+-      } else
+-              sc->rx.rxlink = NULL;
++      spin_unlock_bh(&sc->sc_pcu_lock);
++
++      /* we can now sync irq and kill any running tasklets, since we already
++       * disabled interrupts and not holding a spin lock */
++      synchronize_irq(sc->irq);
++      tasklet_kill(&sc->intr_tq);
++      tasklet_kill(&sc->bcon_tasklet);
++
++      prev_idle = sc->ps_idle;
++      sc->ps_idle = true;
++
++      spin_lock_bh(&sc->sc_pcu_lock);
++
++      if (ah->led_pin >= 0) {
++              ath9k_hw_set_gpio(ah, ah->led_pin, 1);
++              ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
++      }
++
++      ath_prepare_reset(sc, false, true);
+       if (sc->rx.frag) {
+               dev_kfree_skb_any(sc->rx.frag);
+               sc->rx.frag = NULL;
+       }
+-      /* disable HAL and put h/w to sleep */
+-      ath9k_hw_disable(ah);
++      if (!ah->curchan)
++              ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
+-      spin_unlock_bh(&sc->sc_pcu_lock);
++      ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
++      ath9k_hw_phy_disable(ah);
+-      /* we can now sync irq and kill any running tasklets, since we already
+-       * disabled interrupts and not holding a spin lock */
+-      synchronize_irq(sc->irq);
+-      tasklet_kill(&sc->intr_tq);
+-      tasklet_kill(&sc->bcon_tasklet);
++      ath9k_hw_configpcipowersave(ah, true);
+-      ath9k_ps_restore(sc);
++      spin_unlock_bh(&sc->sc_pcu_lock);
+-      sc->ps_idle = true;
+-      ath_radio_disable(sc, hw);
++      ath9k_ps_restore(sc);
+       sc->sc_flags |= SC_OP_INVALID;
++      sc->ps_idle = prev_idle;
+       mutex_unlock(&sc->mutex);
+@@ -1608,8 +1558,8 @@ static int ath9k_config(struct ieee80211
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ieee80211_conf *conf = &hw->conf;
+-      bool disable_radio = false;
++      ath9k_ps_wakeup(sc);
+       mutex_lock(&sc->mutex);
+       /*
+@@ -1618,16 +1568,8 @@ static int ath9k_config(struct ieee80211
+        * of the changes. Likewise we must only disable the radio towards
+        * the end.
+        */
+-      if (changed & IEEE80211_CONF_CHANGE_IDLE) {
++      if (changed & IEEE80211_CONF_CHANGE_IDLE)
+               sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE);
+-              if (!sc->ps_idle) {
+-                      ath_radio_enable(sc, hw);
+-                      ath_dbg(common, ATH_DBG_CONFIG,
+-                              "not-idle: enabling radio\n");
+-              } else {
+-                      disable_radio = true;
+-              }
+-      }
+       /*
+        * We just prepare to enable PS. We have to wait until our AP has
+@@ -1752,19 +1694,13 @@ static int ath9k_config(struct ieee80211
+               ath_dbg(common, ATH_DBG_CONFIG,
+                       "Set power: %d\n", conf->power_level);
+               sc->config.txpowlimit = 2 * conf->power_level;
+-              ath9k_ps_wakeup(sc);
+               ath9k_cmn_update_txpow(ah, sc->curtxpow,
+                                      sc->config.txpowlimit, &sc->curtxpow);
+-              ath9k_ps_restore(sc);
+               conf->cur_power_level = sc->curtxpow / 2;
+       }
+-      if (disable_radio) {
+-              ath_dbg(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
+-              ath_radio_disable(sc, hw);
+-      }
+-
+       mutex_unlock(&sc->mutex);
++      ath9k_ps_restore(sc);
+       return 0;
+ }
+--- a/drivers/net/wireless/ath/ath9k/pci.c
++++ b/drivers/net/wireless/ath/ath9k/pci.c
+@@ -306,12 +306,11 @@ static int ath_pci_suspend(struct device
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct ath_softc *sc = hw->priv;
+-      ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1);
+-
+       /* The device has to be moved to FULLSLEEP forcibly.
+        * Otherwise the chip never moved to full sleep,
+        * when no interface is up.
+        */
++      ath9k_hw_disable(sc->sc_ah);
+       ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
+       return 0;
+@@ -333,22 +332,6 @@ static int ath_pci_resume(struct device 
+       if ((val & 0x0000ff00) != 0)
+               pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+-      ath9k_ps_wakeup(sc);
+-      /* Enable LED */
+-      ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
+-                          AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+-      ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0);
+-
+-        /*
+-         * Reset key cache to sane defaults (all entries cleared) instead of
+-         * semi-random values after suspend/resume.
+-         */
+-      ath9k_cmn_init_crypto(sc->sc_ah);
+-      ath9k_ps_restore(sc);
+-
+-      sc->ps_idle = true;
+-      ath_radio_disable(sc, hw);
+-
+       return 0;
+ }
diff --git a/package/mac80211/patches/562-ath9k_fix_flush.patch b/package/mac80211/patches/562-ath9k_fix_flush.patch
new file mode 100644 (file)
index 0000000..a5329ad
--- /dev/null
@@ -0,0 +1,45 @@
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -2268,9 +2268,6 @@ static void ath9k_flush(struct ieee80211
+               return;
+       }
+-      if (drop)
+-              timeout = 1;
+-
+       for (j = 0; j < timeout; j++) {
+               bool npend = false;
+@@ -2288,21 +2285,22 @@ static void ath9k_flush(struct ieee80211
+               }
+               if (!npend)
+-                  goto out;
++                  break;
+       }
+-      ath9k_ps_wakeup(sc);
+-      spin_lock_bh(&sc->sc_pcu_lock);
+-      drain_txq = ath_drain_all_txq(sc, false);
+-      spin_unlock_bh(&sc->sc_pcu_lock);
++      if (drop) {
++              ath9k_ps_wakeup(sc);
++              spin_lock_bh(&sc->sc_pcu_lock);
++              drain_txq = ath_drain_all_txq(sc, false);
++              spin_unlock_bh(&sc->sc_pcu_lock);
+-      if (!drain_txq)
+-              ath_reset(sc, false);
++              if (!drain_txq)
++                      ath_reset(sc, false);
+-      ath9k_ps_restore(sc);
+-      ieee80211_wake_queues(hw);
++              ath9k_ps_restore(sc);
++              ieee80211_wake_queues(hw);
++      }
+-out:
+       ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
+       mutex_unlock(&sc->mutex);
+ }
diff --git a/package/mac80211/patches/562-ath9k_fix_led.patch b/package/mac80211/patches/562-ath9k_fix_led.patch
deleted file mode 100644 (file)
index 0ef1668..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1056,9 +1056,11 @@ static int ath9k_start(struct ieee80211_
-               goto mutex_unlock;
-       }
--      ath9k_hw_cfg_output(ah, ah->led_pin,
--                          AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
--      ath9k_hw_set_gpio(ah, ah->led_pin, 0);
-+      if (ah->led_pin >= 0) {
-+              ath9k_hw_cfg_output(ah, ah->led_pin,
-+                                  AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-+              ath9k_hw_set_gpio(ah, ah->led_pin, 0);
-+      }
-       /*
-        * Reset key cache to sane defaults (all entries cleared) instead of
-@@ -1197,8 +1199,10 @@ static void ath9k_stop(struct ieee80211_
-       spin_lock_bh(&sc->sc_pcu_lock);
--      ath9k_hw_set_gpio(ah, ah->led_pin, 1);
--      ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
-+      if (ah->led_pin >= 0) {
-+              ath9k_hw_set_gpio(ah, ah->led_pin, 1);
-+              ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
-+      }
-       ath_prepare_reset(sc, false, true);
diff --git a/package/mac80211/patches/563-ath9k_fix_full_sleep_tx.patch b/package/mac80211/patches/563-ath9k_fix_full_sleep_tx.patch
deleted file mode 100644 (file)
index 17575b9..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -118,7 +118,7 @@ void ath9k_ps_restore(struct ath_softc *
-       if (--sc->ps_usecount != 0)
-               goto unlock;
--      if (sc->ps_idle)
-+      if (sc->ps_idle && !(sc->ps_flags & PS_WAIT_FOR_TX_ACK))
-               mode = ATH9K_PM_FULL_SLEEP;
-       else if (sc->ps_enabled &&
-                !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -1983,7 +1983,7 @@ static void ath_tx_complete(struct ath_s
-               skb_pull(skb, padsize);
-       }
--      if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
-+      if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
-               sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
-               ath_dbg(common, ATH_DBG_PS,
-                       "Going back to sleep after having received TX status (0x%lx)\n",