diff options
author | Stanislaw Gruszka <sgruszka@redhat.com> | 2011-06-02 12:17:15 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-06-03 14:22:06 -0400 |
commit | 6f213ff1919fab6f8244ceae55631b5d6ef750a7 (patch) | |
tree | ed2f6312721b9391c85dfcdc6f44a0a5dd208cfb /drivers/net/wireless/iwlwifi/iwl-agn.c | |
parent | a99168eece601d2a79ecfcb968ce226f2f30cf98 (diff) |
iwlagn: fix channel switch locking
We use priv->mutex to avoid race conditions between iwl_chswitch_done()
and iwlagn_mac_channel_switch(), when marking channel switch in
progress. But iwl_chswitch_done() can be called in atomic context
from iwl_rx_csa() or with mutex already taken from iwlagn_commit_rxon().
These bugs were introduced by:
commit 79d07325502e73508f917475bc1617b60979dd94
Author: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Date: Thu May 6 08:54:11 2010 -0700
iwlwifi: support channel switch offload in driver
To fix remove mutex from iwl_chswitch_done() and use atomic bitops for
marking channel switch pending.
Also remove iwl2030_hw_channel_switch() since 2000 series adapters are
2.4GHz only devices.
Cc: stable@kernel.org # 2.6.36+
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Acked-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 19 |
1 files changed, 10 insertions, 9 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a662adcb2ad..8e1942ebd9a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -2843,16 +2843,13 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, | |||
2843 | goto out; | 2843 | goto out; |
2844 | 2844 | ||
2845 | if (test_bit(STATUS_EXIT_PENDING, &priv->status) || | 2845 | if (test_bit(STATUS_EXIT_PENDING, &priv->status) || |
2846 | test_bit(STATUS_SCANNING, &priv->status)) | 2846 | test_bit(STATUS_SCANNING, &priv->status) || |
2847 | test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) | ||
2847 | goto out; | 2848 | goto out; |
2848 | 2849 | ||
2849 | if (!iwl_is_associated_ctx(ctx)) | 2850 | if (!iwl_is_associated_ctx(ctx)) |
2850 | goto out; | 2851 | goto out; |
2851 | 2852 | ||
2852 | /* channel switch in progress */ | ||
2853 | if (priv->switch_rxon.switch_in_progress == true) | ||
2854 | goto out; | ||
2855 | |||
2856 | if (priv->cfg->ops->lib->set_channel_switch) { | 2853 | if (priv->cfg->ops->lib->set_channel_switch) { |
2857 | 2854 | ||
2858 | ch = channel->hw_value; | 2855 | ch = channel->hw_value; |
@@ -2901,15 +2898,19 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, | |||
2901 | * at this point, staging_rxon has the | 2898 | * at this point, staging_rxon has the |
2902 | * configuration for channel switch | 2899 | * configuration for channel switch |
2903 | */ | 2900 | */ |
2901 | set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status); | ||
2902 | priv->switch_channel = cpu_to_le16(ch); | ||
2904 | if (priv->cfg->ops->lib->set_channel_switch(priv, | 2903 | if (priv->cfg->ops->lib->set_channel_switch(priv, |
2905 | ch_switch)) | 2904 | ch_switch)) { |
2906 | priv->switch_rxon.switch_in_progress = false; | 2905 | clear_bit(STATUS_CHANNEL_SWITCH_PENDING, |
2906 | &priv->status); | ||
2907 | priv->switch_channel = 0; | ||
2908 | ieee80211_chswitch_done(ctx->vif, false); | ||
2909 | } | ||
2907 | } | 2910 | } |
2908 | } | 2911 | } |
2909 | out: | 2912 | out: |
2910 | mutex_unlock(&priv->mutex); | 2913 | mutex_unlock(&priv->mutex); |
2911 | if (!priv->switch_rxon.switch_in_progress) | ||
2912 | ieee80211_chswitch_done(ctx->vif, false); | ||
2913 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 2914 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
2914 | } | 2915 | } |
2915 | 2916 | ||