diff options
Diffstat (limited to 'package/mac80211')
7 files changed, 428 insertions, 1 deletions
diff --git a/package/mac80211/Makefile b/package/mac80211/Makefile index 9b268be77..f6229a5ef 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 000000000..61ed2b30e --- /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 000000000..f4937f763 --- /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 000000000..b46e20ae7 --- /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 000000000..45ddf81e5 --- /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 000000000..c97d94a9a --- /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 000000000..01318fb2f --- /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); + } +  + /*  | 
