mac80211: add more ath9k patches
authorGabor Juhos <juhosg@openwrt.org>
Thu, 25 Jun 2009 19:45:51 +0000 (19:45 +0000)
committerGabor Juhos <juhosg@openwrt.org>
Thu, 25 Jun 2009 19:45:51 +0000 (19:45 +0000)
SVN-Revision: 16562

package/mac80211/Makefile
package/mac80211/patches/008-mac80211-fix-todo-lock.patch [new file with mode: 0644]
package/mac80211/patches/404-ath9k-wake-up-the-chip-for-TSF-reset.patch [new file with mode: 0644]
package/mac80211/patches/405-ath9k-make-use-ath9k_hw_wait-int-ath9k_hw_reset_tsf.patch [new file with mode: 0644]
package/mac80211/patches/406-ath9k-serialize-ath9k_hw_setpower-calls.patch [new file with mode: 0644]
package/mac80211/patches/407-ath9k-uninline-ath9k_ps_-wakeup-restore-functions.patch [new file with mode: 0644]
package/mac80211/patches/408-ath9k-serialize-ath9k_ps_-wakeup-restore-calls.patch [new file with mode: 0644]

index 9b268be771585bfe2ccbc9efde4b9628e3b0861e..f6229a5ef35757665edf550cb4cdd1ecaf5d7280 100644 (file)
@@ -18,7 +18,7 @@ ifneq ($(CONFIG_LINUX_2_6_21)$(CONFIG_LINUX_2_6_23)$(CONFIG_LINUX_2_6_24)$(CONFI
   PATCH_DIR:=./patches-old
 else
   PKG_VERSION:=2009-06-25
-  PKG_RELEASE:=1
+  PKG_RELEASE:=2
   PKG_SOURCE_URL:= \
        http://www.orbit-lab.org/kernel/compat-wireless-2.6/2009/06 \
        http://wireless.kernel.org/download/compat-wireless-2.6
diff --git a/package/mac80211/patches/008-mac80211-fix-todo-lock.patch b/package/mac80211/patches/008-mac80211-fix-todo-lock.patch
new file mode 100644 (file)
index 0000000..61ed2b3
--- /dev/null
@@ -0,0 +1,117 @@
+From: Johannes Berg <johannes@sipsolutions.net>
+Subject: mac80211: fix todo lock
+
+The key todo lock can be taken from different locks
+that require it to be _bh to avoid lock inversion
+due to (soft)irqs.
+
+This should fix the two problems reported by Bob and
+Gabor:
+http://mid.gmane.org/20090619113049.GB18956@hash.localnet
+http://mid.gmane.org/4A3FA376.8020307@openwrt.org
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
+Cc: Bob Copeland <me@bobcopeland.com>
+Cc: Gabor Juhos <juhosg@openwrt.org>
+---
+ net/mac80211/key.c |   28 +++++++++++++++-------------
+ 1 file changed, 15 insertions(+), 13 deletions(-)
+
+--- a/net/mac80211/key.c
++++ b/net/mac80211/key.c
+@@ -70,6 +70,8 @@ static DECLARE_WORK(todo_work, key_todo)
+  *
+  * @key: key to add to do item for
+  * @flag: todo flag(s)
++ *
++ * Must be called with IRQs or softirqs disabled.
+  */
+ static void add_todo(struct ieee80211_key *key, u32 flag)
+ {
+@@ -143,9 +145,9 @@ static void ieee80211_key_enable_hw_acce
+       ret = drv_set_key(key->local, SET_KEY, &sdata->vif, sta, &key->conf);
+       if (!ret) {
+-              spin_lock(&todo_lock);
++              spin_lock_bh(&todo_lock);
+               key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
+-              spin_unlock(&todo_lock);
++              spin_unlock_bh(&todo_lock);
+       }
+       if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
+@@ -167,12 +169,12 @@ static void ieee80211_key_disable_hw_acc
+       if (!key || !key->local->ops->set_key)
+               return;
+-      spin_lock(&todo_lock);
++      spin_lock_bh(&todo_lock);
+       if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
+-              spin_unlock(&todo_lock);
++              spin_unlock_bh(&todo_lock);
+               return;
+       }
+-      spin_unlock(&todo_lock);
++      spin_unlock_bh(&todo_lock);
+       sta = get_sta_for_key(key);
+       sdata = key->sdata;
+@@ -191,9 +193,9 @@ static void ieee80211_key_disable_hw_acc
+                      wiphy_name(key->local->hw.wiphy),
+                      key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+-      spin_lock(&todo_lock);
++      spin_lock_bh(&todo_lock);
+       key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+-      spin_unlock(&todo_lock);
++      spin_unlock_bh(&todo_lock);
+ }
+ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
+@@ -440,14 +442,14 @@ void ieee80211_key_link(struct ieee80211
+       __ieee80211_key_replace(sdata, sta, old_key, key);
+-      spin_unlock_irqrestore(&sdata->local->key_lock, flags);
+-
+       /* free old key later */
+       add_todo(old_key, KEY_FLAG_TODO_DELETE);
+       add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
+       if (netif_running(sdata->dev))
+               add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
++
++      spin_unlock_irqrestore(&sdata->local->key_lock, flags);
+ }
+ static void __ieee80211_key_free(struct ieee80211_key *key)
+@@ -550,7 +552,7 @@ static void __ieee80211_key_todo(void)
+        */
+       synchronize_rcu();
+-      spin_lock(&todo_lock);
++      spin_lock_bh(&todo_lock);
+       while (!list_empty(&todo_list)) {
+               key = list_first_entry(&todo_list, struct ieee80211_key, todo);
+               list_del_init(&key->todo);
+@@ -561,7 +563,7 @@ static void __ieee80211_key_todo(void)
+                                         KEY_FLAG_TODO_HWACCEL_REMOVE |
+                                         KEY_FLAG_TODO_DELETE);
+               key->flags &= ~todoflags;
+-              spin_unlock(&todo_lock);
++              spin_unlock_bh(&todo_lock);
+               work_done = false;
+@@ -594,9 +596,9 @@ static void __ieee80211_key_todo(void)
+               WARN_ON(!work_done);
+-              spin_lock(&todo_lock);
++              spin_lock_bh(&todo_lock);
+       }
+-      spin_unlock(&todo_lock);
++      spin_unlock_bh(&todo_lock);
+ }
+ void ieee80211_key_todo(void)
diff --git a/package/mac80211/patches/404-ath9k-wake-up-the-chip-for-TSF-reset.patch b/package/mac80211/patches/404-ath9k-wake-up-the-chip-for-TSF-reset.patch
new file mode 100644 (file)
index 0000000..f4937f7
--- /dev/null
@@ -0,0 +1,33 @@
+From d2fa21debb4ea8c022b0fbed165eea821d19da9e Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Sat, 20 Jun 2009 23:57:22 +0200
+Subject: [PATCH] ath9k: wake up the chip for TSF reset
+
+If we are in NETWORK SLEEP state, AR_SLP32_TSF_WRITE_STATUS limit
+always exceeds in 'ath9k_hw_reset_tsf', because reading of the
+AR_SLP3 register always return with the magic 0xdeadbeef value.
+
+Changes-licensed-under: ISC
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/net/wireless/ath/ath9k/hw.c |    2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -3803,6 +3803,7 @@ void ath9k_hw_reset_tsf(struct ath_hw *a
+ {
+       int count;
++      ath9k_ps_wakeup(ah->ah_sc);
+       count = 0;
+       while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
+               count++;
+@@ -3814,6 +3815,7 @@ void ath9k_hw_reset_tsf(struct ath_hw *a
+               udelay(10);
+       }
+       REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
++      ath9k_ps_restore(ah->ah_sc);
+ }
+ bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
diff --git a/package/mac80211/patches/405-ath9k-make-use-ath9k_hw_wait-int-ath9k_hw_reset_tsf.patch b/package/mac80211/patches/405-ath9k-make-use-ath9k_hw_wait-int-ath9k_hw_reset_tsf.patch
new file mode 100644 (file)
index 0000000..b46e20a
--- /dev/null
@@ -0,0 +1,52 @@
+From 9a0a0221024ddb4ddf0e33bb6fdbb3b02eaaf292 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Sat, 20 Jun 2009 23:57:23 +0200
+Subject: [PATCH] ath9k: make use ath9k_hw_wait int ath9k_hw_reset_tsf
+
+We have a dedicated function for this kind of checks, use that
+instead of duplicating the code.
+
+Changes-licensed-under: ISC
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/net/wireless/ath/ath9k/hw.c |   17 +++++------------
+ drivers/net/wireless/ath/ath9k/hw.h |    1 +
+ 2 files changed, 6 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -3801,19 +3801,12 @@ void ath9k_hw_settsf64(struct ath_hw *ah
+ void ath9k_hw_reset_tsf(struct ath_hw *ah)
+ {
+-      int count;
+-
+       ath9k_ps_wakeup(ah->ah_sc);
+-      count = 0;
+-      while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
+-              count++;
+-              if (count > 10) {
+-                      DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+-                              "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
+-                      break;
+-              }
+-              udelay(10);
+-      }
++      if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0,
++                         AH_TSF_WRITE_TIMEOUT))
++              DPRINTF(ah->ah_sc, ATH_DBG_RESET,
++                      "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
++
+       REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
+       ath9k_ps_restore(ah->ah_sc);
+ }
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -95,6 +95,7 @@
+ #define MAX_RATE_POWER              63
+ #define AH_WAIT_TIMEOUT             100000 /* (us) */
++#define AH_TSF_WRITE_TIMEOUT        100    /* (us) */
+ #define AH_TIME_QUANTUM             10
+ #define AR_KEYTABLE_SIZE            128
+ #define POWER_UP_TIME               200000
diff --git a/package/mac80211/patches/406-ath9k-serialize-ath9k_hw_setpower-calls.patch b/package/mac80211/patches/406-ath9k-serialize-ath9k_hw_setpower-calls.patch
new file mode 100644 (file)
index 0000000..45ddf81
--- /dev/null
@@ -0,0 +1,67 @@
+From 841c7e339c4775f4cc614c92aaea82f70fcafbdb Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Sun, 21 Jun 2009 16:59:53 +0200
+Subject: [PATCH 1/3] ath9k: serialize ath9k_hw_setpower calls
+
+Because ath9k_setpower is called from various contexts, we have to
+protect it against concurrent calls.
+
+Changes-licensed-under: ISC
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/net/wireless/ath/ath9k/ath9k.h |    1 +
+ drivers/net/wireless/ath/ath9k/hw.c    |   15 ++++++++++++++-
+ drivers/net/wireless/ath/ath9k/main.c  |    1 +
+ 3 files changed, 16 insertions(+), 1 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -544,6 +544,7 @@ struct ath_softc {
+       int irq;
+       spinlock_t sc_resetlock;
+       spinlock_t sc_serial_rw;
++      spinlock_t sc_pm_lock;
+       struct mutex mutex;
+       u8 curbssid[ETH_ALEN];
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -2738,7 +2738,8 @@ static bool ath9k_hw_set_power_awake(str
+       return true;
+ }
+-bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
++static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
++                                   enum ath9k_power_mode mode)
+ {
+       int status = true, setChip = true;
+       static const char *modes[] = {
+@@ -2772,6 +2773,18 @@ bool ath9k_hw_setpower(struct ath_hw *ah
+       return status;
+ }
++bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
++{
++      unsigned long flags;
++      bool ret;
++
++      spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags);
++      ret = ath9k_hw_setpower_nolock(ah, mode);
++      spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags);
++
++      return ret;
++}
++
+ /*
+  * Helper for ASPM support.
+  *
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -1317,6 +1317,7 @@ static int ath_init(u16 devid, struct at
+       spin_lock_init(&sc->wiphy_lock);
+       spin_lock_init(&sc->sc_resetlock);
+       spin_lock_init(&sc->sc_serial_rw);
++      spin_lock_init(&sc->sc_pm_lock);
+       mutex_init(&sc->mutex);
+       tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
+       tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
diff --git a/package/mac80211/patches/407-ath9k-uninline-ath9k_ps_-wakeup-restore-functions.patch b/package/mac80211/patches/407-ath9k-uninline-ath9k_ps_-wakeup-restore-functions.patch
new file mode 100644 (file)
index 0000000..c97d94a
--- /dev/null
@@ -0,0 +1,76 @@
+From 900d70802f15e835b3dbbe8750313824aa30a118 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Sun, 21 Jun 2009 16:59:53 +0200
+Subject: [PATCH 2/3] ath9k: uninline ath9k_ps_{wakeup,restore} functions
+
+Uninline these functions before we add functional changes to them.
+
+Changes-licensed-under: ISC
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/net/wireless/ath/ath9k/ath9k.h |   23 ++---------------------
+ drivers/net/wireless/ath/ath9k/hw.c    |   21 +++++++++++++++++++++
+ 2 files changed, 23 insertions(+), 21 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -658,27 +658,8 @@ static inline int ath_ahb_init(void) { r
+ static inline void ath_ahb_exit(void) {};
+ #endif
+-static inline void ath9k_ps_wakeup(struct ath_softc *sc)
+-{
+-      if (atomic_inc_return(&sc->ps_usecount) == 1)
+-              if (sc->sc_ah->power_mode !=  ATH9K_PM_AWAKE) {
+-                      sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
+-                      ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+-              }
+-}
+-
+-static inline void ath9k_ps_restore(struct ath_softc *sc)
+-{
+-      if (atomic_dec_and_test(&sc->ps_usecount))
+-              if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
+-                  !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+-                                    SC_OP_WAIT_FOR_CAB |
+-                                    SC_OP_WAIT_FOR_PSPOLL_DATA |
+-                                    SC_OP_WAIT_FOR_TX_ACK)))
+-                      ath9k_hw_setpower(sc->sc_ah,
+-                                        sc->sc_ah->restore_mode);
+-}
+-
++void ath9k_ps_wakeup(struct ath_softc *sc);
++void ath9k_ps_restore(struct ath_softc *sc);
+ void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
+ int ath9k_wiphy_add(struct ath_softc *sc);
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -2785,6 +2785,27 @@ bool ath9k_hw_setpower(struct ath_hw *ah
+       return ret;
+ }
++void ath9k_ps_wakeup(struct ath_softc *sc)
++{
++      if (atomic_inc_return(&sc->ps_usecount) == 1)
++              if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
++                      sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
++                      ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
++              }
++}
++
++void ath9k_ps_restore(struct ath_softc *sc)
++{
++      if (atomic_dec_and_test(&sc->ps_usecount))
++              if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
++                  !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
++                                    SC_OP_WAIT_FOR_CAB |
++                                    SC_OP_WAIT_FOR_PSPOLL_DATA |
++                                    SC_OP_WAIT_FOR_TX_ACK)))
++                      ath9k_hw_setpower(sc->sc_ah,
++                                        sc->sc_ah->restore_mode);
++}
++
+ /*
+  * Helper for ASPM support.
+  *
diff --git a/package/mac80211/patches/408-ath9k-serialize-ath9k_ps_-wakeup-restore-calls.patch b/package/mac80211/patches/408-ath9k-serialize-ath9k_ps_-wakeup-restore-calls.patch
new file mode 100644 (file)
index 0000000..01318fb
--- /dev/null
@@ -0,0 +1,82 @@
+From 7446da6910f1368273a55ca99acba18828306a6e Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Sun, 21 Jun 2009 16:59:53 +0200
+Subject: [PATCH 3/3] ath9k: serialize ath9k_ps_{wakeup,restore} calls
+
+These functions are changing the power mode of the chip, but this may
+have unpredictable effects, if another code are trying to set the power
+mode via 'ath9k_hw_setpower' in the same time from another context.
+
+Changes-licensed-under: ISC
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+---
+ drivers/net/wireless/ath/ath9k/ath9k.h |    2 +-
+ drivers/net/wireless/ath/ath9k/hw.c    |   42 ++++++++++++++++++++++----------
+ 2 files changed, 30 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -561,7 +561,7 @@ struct ath_softc {
+       u32 keymax;
+       DECLARE_BITMAP(keymap, ATH_KEYMAX);
+       u8 splitmic;
+-      atomic_t ps_usecount;
++      unsigned long ps_usecount;
+       enum ath9k_int imask;
+       enum ath9k_ht_extprotspacing ht_extprotspacing;
+       enum ath9k_ht_macmode tx_chan_width;
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -2787,23 +2787,39 @@ bool ath9k_hw_setpower(struct ath_hw *ah
+ void ath9k_ps_wakeup(struct ath_softc *sc)
+ {
+-      if (atomic_inc_return(&sc->ps_usecount) == 1)
+-              if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
+-                      sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
+-                      ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+-              }
++      unsigned long flags;
++
++      spin_lock_irqsave(&sc->sc_pm_lock, flags);
++      if (++sc->ps_usecount != 1)
++              goto unlock;
++
++      if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
++              sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
++              ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
++      }
++
++ unlock:
++      spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+ }
+ void ath9k_ps_restore(struct ath_softc *sc)
+ {
+-      if (atomic_dec_and_test(&sc->ps_usecount))
+-              if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
+-                  !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+-                                    SC_OP_WAIT_FOR_CAB |
+-                                    SC_OP_WAIT_FOR_PSPOLL_DATA |
+-                                    SC_OP_WAIT_FOR_TX_ACK)))
+-                      ath9k_hw_setpower(sc->sc_ah,
+-                                        sc->sc_ah->restore_mode);
++      unsigned long flags;
++
++      spin_lock_irqsave(&sc->sc_pm_lock, flags);
++      if (--sc->ps_usecount != 0)
++              goto unlock;
++
++      if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
++              !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
++                              SC_OP_WAIT_FOR_CAB |
++                              SC_OP_WAIT_FOR_PSPOLL_DATA |
++                              SC_OP_WAIT_FOR_TX_ACK)))
++              ath9k_hw_setpower_nolock(sc->sc_ah,
++                                    sc->sc_ah->restore_mode);
++
++ unlock:
++      spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+ }
+ /*