diff options
7 files changed, 428 insertions, 1 deletions
diff --git a/package/mac80211/Makefile b/package/mac80211/Makefile index 9b268be771..f6229a5ef3 100644 --- a/package/mac80211/Makefile +++ b/package/mac80211/Makefile @@ -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 index 0000000000..61ed2b30e9 --- /dev/null +++ b/package/mac80211/patches/008-mac80211-fix-todo-lock.patch @@ -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 index 0000000000..f4937f763c --- /dev/null +++ b/package/mac80211/patches/404-ath9k-wake-up-the-chip-for-TSF-reset.patch @@ -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 index 0000000000..b46e20ae72 --- /dev/null +++ b/package/mac80211/patches/405-ath9k-make-use-ath9k_hw_wait-int-ath9k_hw_reset_tsf.patch @@ -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 index 0000000000..45ddf81e5b --- /dev/null +++ b/package/mac80211/patches/406-ath9k-serialize-ath9k_hw_setpower-calls.patch @@ -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 index 0000000000..c97d94a9a3 --- /dev/null +++ b/package/mac80211/patches/407-ath9k-uninline-ath9k_ps_-wakeup-restore-functions.patch @@ -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 index 0000000000..01318fb2f7 --- /dev/null +++ b/package/mac80211/patches/408-ath9k-serialize-ath9k_ps_-wakeup-restore-calls.patch @@ -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); + } + + /* |