iwlagn: fix channel switch locking
PATCH 1/2 iwlagn: fix channel switch locking
We use priv->mutex to avoid race condtions between iwl_chswitch_done() and iwlagn_mac_channel_switch(), when marking channel switch in progress. But iwl_chswitch_dane() 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 <[email protected]> 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.
--- drivers/net/wireless/iwlwifi/iwl-2000.c | 2 -- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 -- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 -- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-agn.c | 19 ++++++++++--------- drivers/net/wireless/iwlwifi/iwl-core.c | 6 +----- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-dev.h | 13 +------------ drivers/net/wireless/iwlwifi/iwl-rx.c | 24 ++++++++++++------------ 9 files changed, 28 insertions(+), 47 deletions(-)
drivers/net/wireless/iwlwifi/iwl-2000.c +0 -2
@@ -244,8 +244,6 @@ static int iwl2030_hw_channel_switch(struct iwl_priv *priv, ctx->active.channel, ch);return -EFAULT ; } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true;return iwl_send_cmd_sync (priv, &hcmd); }
drivers/net/wireless/iwlwifi/iwl-5000.c +0 -2
@@ -331,8 +331,6 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, ctx->active.channel, ch);return -EFAULT ; } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true;return iwl_send_cmd_sync (priv, &hcmd); }
drivers/net/wireless/iwlwifi/iwl-6000.c +0 -2
@@ -270,8 +270,6 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, ctx->active.channel, ch);return -EFAULT ; } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true;return iwl_send_cmd_sync (priv, &hcmd); }
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +3 -3
@@ -370,10 +370,10 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)* receive commit_rxon request * abort any previous channel switch if still in process */ -if (priv->switch_rxon.switch_in_progress && - (priv->switch_rxon.channel != ctx->staging.channel)) { +if (test_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status) && + (priv->switch_channel != ctx->staging.channel)) {IWL_DEBUG_11H (priv,"abort channel switch on %d\n" , -le16_to_cpu (priv->switch_rxon.channel)); +le16_to_cpu (priv->switch_channel));iwl_chswitch_done (priv, false); }
drivers/net/wireless/iwlwifi/iwl-agn.c +10 -9
@@ -2843,16 +2843,13 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, goto out;if (test_bit (STATUS_EXIT_PENDING , &priv->status) || -test_bit (STATUS_SCANNING , &priv->status)) +test_bit (STATUS_SCANNING , &priv->status) || +test_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status)) goto out;if (!iwl_is_associated_ctx (ctx)) goto out; -/* channel switch in progress */ -if (priv->switch_rxon.switch_in_progress == true) - goto out; -if (priv->cfg->ops->lib->set_channel_switch) { ch = channel->hw_value;
@@ -2901,15 +2898,19 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,* at this point, staging_rxon has the * configuration for channel switch */ +set_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status); + priv->switch_channel =cpu_to_le16 (ch);if (priv->cfg->ops->lib->set_channel_switch (priv, - ch_switch)) - priv->switch_rxon.switch_in_progress = false; + ch_switch)) { +clear_bit (STATUS_CHANNEL_SWITCH_PENDING , + &priv->status); + priv->switch_channel =0 ; +ieee80211_chswitch_done (ctx->vif, false); + } } } out:mutex_unlock (&priv->mutex); -if (!priv->switch_rxon.switch_in_progress) -ieee80211_chswitch_done (ctx->vif, false);IWL_DEBUG_MAC80211 (priv,"leave\n" ); }
drivers/net/wireless/iwlwifi/iwl-core.c +1 -5
@@ -843,12 +843,8 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)if (test_bit (STATUS_EXIT_PENDING , &priv->status))return ; -if (priv->switch_rxon.switch_in_progress) { +if (test_and_clear_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status))ieee80211_chswitch_done (ctx->vif, is_success); -mutex_lock (&priv->mutex); - priv->switch_rxon.switch_in_progress = false; -mutex_unlock (&priv->mutex); - } }#ifdef CONFIG_IWLWIFI_DEBUG
drivers/net/wireless/iwlwifi/iwl-core.h +1 -0
@@ -559,6 +559,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);#define STATUS_POWER_PMI 16#define STATUS_FW_ERROR 17#define STATUS_DEVICE_ENABLED 18 +#define STATUS_CHANNEL_SWITCH_PENDING 19static inline int iwl_is_ready (struct iwl_priv *priv)
drivers/net/wireless/iwlwifi/iwl-dev.h +1 -12
@@ -982,17 +982,6 @@ struct traffic_stats { };/* -* iwl_switch_rxon: "channel switch" structure -* -* @ switch_in_progress: channel switch in progress -* @ channel: new channel -*/ -struct iwl_switch_rxon { -bool switch_in_progress; -__le16 channel; -}; - -/* * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds * to perform continuous uCode event logging operation if enabled */
@@ -1287,7 +1276,7 @@ struct iwl_priv {struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX ]; -struct iwl_switch_rxon switch_rxon; +__le16 switch_channel;struct {u32 error_event_table;
drivers/net/wireless/iwlwifi/iwl-rx.c +12 -12
@@ -250,19 +250,19 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS ];struct iwl_rxon_cmd *rxon = (void *)&ctx->active; -if (priv->switch_rxon.switch_in_progress) { -if (!le32_to_cpu (csa->status) && - (csa->channel == priv->switch_rxon.channel)) { - rxon->channel = csa->channel; - ctx->staging.channel = csa->channel; -IWL_DEBUG_11H (priv,"CSA notif: channel %d\n" , -le16_to_cpu (csa->channel)); -iwl_chswitch_done (priv, true); - }else { -IWL_ERR (priv,"CSA notif (fail) : channel %d\n" , +if (!test_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status)) +return ; + +if (!le32_to_cpu (csa->status) && csa->channel == priv->switch_channel) { + rxon->channel = csa->channel; + ctx->staging.channel = csa->channel; +IWL_DEBUG_11H (priv,"CSA notif: channel %d\n" ,le16_to_cpu (csa->channel)); -iwl_chswitch_done (priv, false); - } +iwl_chswitch_done (priv, true); + }else { +IWL_ERR (priv,"CSA notif (fail) : channel %d\n" , +le16_to_cpu (csa->channel)); +iwl_chswitch_done (priv, false); } }
Signature · 1 line
1.7.1
PATCH 2/2 iwlagn: refactor iwlagn_mac_channel_switch
Use less indentions and remove uneeded irq-save flags.
--- drivers/net/wireless/iwlwifi/iwl-agn.c | 106 ++++++++++++++++---------------- 1 files changed, 52 insertions(+), 54 deletions(-)
drivers/net/wireless/iwlwifi/iwl-agn.c +52 -54
@@ -2833,7 +2833,6 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,*/ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS ];u16 ch; -unsigned long flags =0 ;IWL_DEBUG_MAC80211 (priv,"enter\n" );
@@ -2850,65 +2849,64 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,if (!iwl_is_associated_ctx (ctx)) goto out; -if (priv->cfg->ops->lib->set_channel_switch) { +if (!priv->cfg->ops->lib->set_channel_switch) + goto out; - ch = channel->hw_value; -if (le16_to_cpu (ctx->active.channel) != ch) { - ch_info =iwl_get_channel_info (priv, - channel->band, - ch); -if (!is_channel_valid (ch_info)) { -IWL_DEBUG_MAC80211 (priv,"invalid channel\n" ); - goto out; - } -spin_lock_irqsave (&priv->lock, flags); - - priv->current_ht_config.smps = conf->smps_mode; - -/* Configure HT40 channels */ - ctx->ht.enabled =conf_is_ht (conf); -if (ctx->ht.enabled) { -if (conf_is_ht40_minus (conf)) { - ctx->ht.extension_chan_offset = -IEEE80211_HT_PARAM_CHA_SEC_BELOW ; - ctx->ht.is_40mhz = true; - }else if (conf_is_ht40_plus (conf)) { - ctx->ht.extension_chan_offset = -IEEE80211_HT_PARAM_CHA_SEC_ABOVE ; - ctx->ht.is_40mhz = true; - }else { - ctx->ht.extension_chan_offset = -IEEE80211_HT_PARAM_CHA_SEC_NONE ; - ctx->ht.is_40mhz = false; - } - }else - ctx->ht.is_40mhz = false; + ch = channel->hw_value; +if (le16_to_cpu (ctx->active.channel) == ch) + goto out; + + ch_info =iwl_get_channel_info (priv, channel->band, ch); +if (!is_channel_valid (ch_info)) { +IWL_DEBUG_MAC80211 (priv,"invalid channel\n" ); + goto out; + } -if ((le16_to_cpu (ctx->staging.channel) != ch)) - ctx->staging.flags =0 ; +spin_lock_irq (&priv->lock); -iwl_set_rxon_channel (priv, channel, ctx); -iwl_set_rxon_ht (priv, ht_conf); -iwl_set_flags_for_band (priv, ctx, channel->band, - ctx->vif); -spin_unlock_irqrestore (&priv->lock, flags); + priv->current_ht_config.smps = conf->smps_mode; -iwl_set_rate (priv); -/* -* at this point, staging_rxon has the -* configuration for channel switch -*/ -set_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status); - priv->switch_channel =cpu_to_le16 (ch); -if (priv->cfg->ops->lib->set_channel_switch (priv, - ch_switch)) { -clear_bit (STATUS_CHANNEL_SWITCH_PENDING , - &priv->status); - priv->switch_channel =0 ; -ieee80211_chswitch_done (ctx->vif, false); - } +/* Configure HT40 channels */ + ctx->ht.enabled =conf_is_ht (conf); +if (ctx->ht.enabled) { +if (conf_is_ht40_minus (conf)) { + ctx->ht.extension_chan_offset = +IEEE80211_HT_PARAM_CHA_SEC_BELOW ; + ctx->ht.is_40mhz = true; + }else if (conf_is_ht40_plus (conf)) { + ctx->ht.extension_chan_offset = +IEEE80211_HT_PARAM_CHA_SEC_ABOVE ; + ctx->ht.is_40mhz = true; + }else { + ctx->ht.extension_chan_offset = +IEEE80211_HT_PARAM_CHA_SEC_NONE ; + ctx->ht.is_40mhz = false; } + }else + ctx->ht.is_40mhz = false; + +if ((le16_to_cpu (ctx->staging.channel) != ch)) + ctx->staging.flags =0 ; + +iwl_set_rxon_channel (priv, channel, ctx); +iwl_set_rxon_ht (priv, ht_conf); +iwl_set_flags_for_band (priv, ctx, channel->band, ctx->vif); + +spin_unlock_irq (&priv->lock); + +iwl_set_rate (priv); +/* +* at this point, staging_rxon has the +* configuration for channel switch +*/ +set_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status); + priv->switch_channel =cpu_to_le16 (ch); +if (priv->cfg->ops->lib->set_channel_switch (priv, ch_switch)) { +clear_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status); + priv->switch_channel =0 ; +ieee80211_chswitch_done (ctx->vif, false); } + out:mutex_unlock (&priv->mutex);IWL_DEBUG_MAC80211 (priv,"leave\n" );
Signature · 1 line
1.7.1
Re: [PATCH 2/2] iwlagn: refactor iwlagn_mac_channel_switch
Quoted 3 lines · Stanislaw Gruszka
Use less indentions and remove uneeded irq-save flags.
Signed-off-by Stanislaw Gruszka <[email protected]>
Quoted 4 lines
--- drivers/net/wireless/iwlwifi/iwl-agn.c | 106 ++++++++++++++++---------------- 1 files changed, 52 insertions(+), 54 deletions(-)
Hi Stanislaw,
Quoted 35 lines · Stanislaw Gruszka
We use
priv->mutexto avoid race condtions betweeniwl_chswitch_done()andiwlagn_mac_channel_switch(), when marking channel switch in progress. Butiwl_chswitch_dane()can be called in atomic context fromiwl_rx_csa()or with mutex already taken fromiwlagn_commit_rxon().These bugs were introduced by:
commit
79d07325502e73508f917475bc1617b60979dd94Author: Wey-Yi Guy <[email protected]> Date: Thu May 6 08:54:11 2010 -0700iwlwifi: support channel switch offload in driver
To fix remove mutex from
iwl_chswitch_done()and use atomic bitops for marking channel switch pending.Cc [email protected] # 2.6.36+Signed-off-by Stanislaw Gruszka <[email protected]>--- drivers/net/wireless/iwlwifi/iwl-2000.c | 2 -- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 -- drivers/net/wireless/iwlwifi/iwl-6000.c | 2 -- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-agn.c | 19 ++++++++++--------- drivers/net/wireless/iwlwifi/iwl-core.c | 6 +----- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-dev.h | 13 +------------ drivers/net/wireless/iwlwifi/iwl-rx.c | 24 ++++++++++++------------ 9 files changed, 28 insertions(+), 47 deletions(-)drivers/net/wireless/iwlwifi/iwl-2000.c +0
-0
drivers/net/wireless/iwlwifi/iwl-2000.c static int iwl2030_hw_channel_switch(struct iwl_priv *priv, · line 249
Quoted 8 lines
drivers/net/wireless/iwlwifi/iwl-2000.c +0
-2@@ -244,8 +244,6 @@ static int iwl2030_hw_channel_switch(struct iwl_priv *priv, ctx->active.channel, ch);return -EFAULT ; } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true;return iwl_send_cmd_sync (priv, &hcmd); }
Thank you for fix my mistake.
Could you please remove the channel switch from iwl-2000.c all together. 2000 series are 2.4 GHz only
Thanks
Wey
PATCH v2 1/2 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 <[email protected]> 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.
--- drivers/net/wireless/iwlwifi/iwl-2000.c | 74 --------------------------- drivers/net/wireless/iwlwifi/iwl-5000.c | 2 - drivers/net/wireless/iwlwifi/iwl-6000.c | 2 - drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 6 +- drivers/net/wireless/iwlwifi/iwl-agn.c | 19 ++++--- drivers/net/wireless/iwlwifi/iwl-core.c | 6 +-- drivers/net/wireless/iwlwifi/iwl-core.h | 1 + drivers/net/wireless/iwlwifi/iwl-dev.h | 13 +---- drivers/net/wireless/iwlwifi/iwl-rx.c | 24 ++++---- 9 files changed, 28 insertions(+), 119 deletions(-)
drivers/net/wireless/iwlwifi/iwl-2000.c +0 -74
@@ -177,79 +177,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)return 0 ; } -static int iwl2030_hw_channel_switch (struct iwl_priv *priv, -struct ieee80211_channel_switch *ch_switch) -{ -/* -* MULTI-FIXME -* See iwl_mac_channel_switch. -*/ -struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS ]; -struct iwl6000_channel_switch_cmd cmd; -const struct iwl_channel_info *ch_info; -u32 switch_time_in_usec, ucode_switch_time; -u16 ch; -u32 tsf_low; -u8 switch_count; -u16 beacon_interval =le16_to_cpu (ctx->timing.beacon_interval); -struct ieee80211_vif *vif = ctx->vif; -struct iwl_host_cmd hcmd = { - .id =REPLY_CHANNEL_SWITCH , - .len = {sizeof (cmd), }, - .flags =CMD_SYNC , - .data = { &cmd, }, - }; - - cmd.band = priv->band ==IEEE80211_BAND_2GHZ ; - ch = ch_switch->channel->hw_value; -IWL_DEBUG_11H (priv,"channel switch from %u to %u\n" , - ctx->active.channel, ch); - cmd.channel =cpu_to_le16 (ch); - cmd.rxon_flags = ctx->staging.flags; - cmd.rxon_filter_flags = ctx->staging.filter_flags; - switch_count = ch_switch->count; - tsf_low = ch_switch->timestamp &0x0ffffffff ; -/* -* calculate the ucode channel switch time -* adding TSF as one of the factor for when to switch -*/ -if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { -if (switch_count > ((priv->ucode_beacon_time - tsf_low) / - beacon_interval)) { - switch_count -= (priv->ucode_beacon_time - - tsf_low) / beacon_interval; - }else - switch_count =0 ; - } -if (switch_count <=1 ) - cmd.switch_time =cpu_to_le32 (priv->ucode_beacon_time); -else { - switch_time_in_usec = - vif->bss_conf.beacon_int * switch_count *TIME_UNIT ; - ucode_switch_time =iwl_usecs_to_beacons (priv, - switch_time_in_usec, - beacon_interval); - cmd.switch_time =iwl_add_beacon_time (priv, - priv->ucode_beacon_time, - ucode_switch_time, - beacon_interval); - } -IWL_DEBUG_11H (priv,"uCode time for the switch is 0x%x\n" , - cmd.switch_time); - ch_info =iwl_get_channel_info (priv, priv->band, ch); -if (ch_info) - cmd.expect_beacon =is_channel_radar (ch_info); -else { -IWL_ERR (priv,"invalid channel switch from %u to %u\n" , - ctx->active.channel, ch); -return -EFAULT ; - } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true; - -return iwl_send_cmd_sync (priv, &hcmd); -} -static struct iwl_lib_ops iwl2000_lib = { .set_hw_params = iwl2000_hw_set_hw_params, .rx_handler_setup = iwlagn_rx_handler_setup,
@@ -257,7 +184,6 @@ static struct iwl_lib_ops iwl2000_lib = { .cancel_deferred_work = iwlagn_bt_cancel_deferred_work, .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr, .update_chain_flags = iwl_update_chain_flags, - .set_channel_switch = iwl2030_hw_channel_switch, .apm_ops = { .init = iwl_apm_init, .config = iwl2000_nic_config,
drivers/net/wireless/iwlwifi/iwl-5000.c +0 -2
@@ -331,8 +331,6 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, ctx->active.channel, ch);return -EFAULT ; } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true;return iwl_send_cmd_sync (priv, &hcmd); }
drivers/net/wireless/iwlwifi/iwl-6000.c +0 -2
@@ -270,8 +270,6 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, ctx->active.channel, ch);return -EFAULT ; } - priv->switch_rxon.channel = cmd.channel; - priv->switch_rxon.switch_in_progress = true;return iwl_send_cmd_sync (priv, &hcmd); }
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +3 -3
@@ -370,10 +370,10 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)* receive commit_rxon request * abort any previous channel switch if still in process */ -if (priv->switch_rxon.switch_in_progress && - (priv->switch_rxon.channel != ctx->staging.channel)) { +if (test_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status) && + (priv->switch_channel != ctx->staging.channel)) {IWL_DEBUG_11H (priv,"abort channel switch on %d\n" , -le16_to_cpu (priv->switch_rxon.channel)); +le16_to_cpu (priv->switch_channel));iwl_chswitch_done (priv, false); }
drivers/net/wireless/iwlwifi/iwl-agn.c +10 -9
@@ -2926,16 +2926,13 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, goto out;if (test_bit (STATUS_EXIT_PENDING , &priv->status) || -test_bit (STATUS_SCANNING , &priv->status)) +test_bit (STATUS_SCANNING , &priv->status) || +test_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status)) goto out;if (!iwl_is_associated_ctx (ctx)) goto out; -/* channel switch in progress */ -if (priv->switch_rxon.switch_in_progress == true) - goto out; -if (priv->cfg->ops->lib->set_channel_switch) { ch = channel->hw_value;
@@ -2984,15 +2981,19 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,* at this point, staging_rxon has the * configuration for channel switch */ +set_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status); + priv->switch_channel =cpu_to_le16 (ch);if (priv->cfg->ops->lib->set_channel_switch (priv, - ch_switch)) - priv->switch_rxon.switch_in_progress = false; + ch_switch)) { +clear_bit (STATUS_CHANNEL_SWITCH_PENDING , + &priv->status); + priv->switch_channel =0 ; +ieee80211_chswitch_done (ctx->vif, false); + } } } out:mutex_unlock (&priv->mutex); -if (!priv->switch_rxon.switch_in_progress) -ieee80211_chswitch_done (ctx->vif, false);IWL_DEBUG_MAC80211 (priv,"leave\n" ); }
drivers/net/wireless/iwlwifi/iwl-core.c +1 -5
@@ -843,12 +843,8 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)if (test_bit (STATUS_EXIT_PENDING , &priv->status))return ; -if (priv->switch_rxon.switch_in_progress) { +if (test_and_clear_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status))ieee80211_chswitch_done (ctx->vif, is_success); -mutex_lock (&priv->mutex); - priv->switch_rxon.switch_in_progress = false; -mutex_unlock (&priv->mutex); - } }#ifdef CONFIG_IWLWIFI_DEBUG
drivers/net/wireless/iwlwifi/iwl-core.h +1 -0
@@ -559,6 +559,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);#define STATUS_POWER_PMI 16#define STATUS_FW_ERROR 17#define STATUS_DEVICE_ENABLED 18 +#define STATUS_CHANNEL_SWITCH_PENDING 19static inline int iwl_is_ready (struct iwl_priv *priv)
drivers/net/wireless/iwlwifi/iwl-dev.h +1 -12
@@ -982,17 +982,6 @@ struct traffic_stats { };/* -* iwl_switch_rxon: "channel switch" structure -* -* @ switch_in_progress: channel switch in progress -* @ channel: new channel -*/ -struct iwl_switch_rxon { -bool switch_in_progress; -__le16 channel; -}; - -/* * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds * to perform continuous uCode event logging operation if enabled */
@@ -1287,7 +1276,7 @@ struct iwl_priv {struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX ]; -struct iwl_switch_rxon switch_rxon; +__le16 switch_channel;struct {u32 error_event_table;
drivers/net/wireless/iwlwifi/iwl-rx.c +12 -12
@@ -250,19 +250,19 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS ];struct iwl_rxon_cmd *rxon = (void *)&ctx->active; -if (priv->switch_rxon.switch_in_progress) { -if (!le32_to_cpu (csa->status) && - (csa->channel == priv->switch_rxon.channel)) { - rxon->channel = csa->channel; - ctx->staging.channel = csa->channel; -IWL_DEBUG_11H (priv,"CSA notif: channel %d\n" , -le16_to_cpu (csa->channel)); -iwl_chswitch_done (priv, true); - }else { -IWL_ERR (priv,"CSA notif (fail) : channel %d\n" , +if (!test_bit (STATUS_CHANNEL_SWITCH_PENDING , &priv->status)) +return ; + +if (!le32_to_cpu (csa->status) && csa->channel == priv->switch_channel) { + rxon->channel = csa->channel; + ctx->staging.channel = csa->channel; +IWL_DEBUG_11H (priv,"CSA notif: channel %d\n" ,le16_to_cpu (csa->channel)); -iwl_chswitch_done (priv, false); - } +iwl_chswitch_done (priv, true); + }else { +IWL_ERR (priv,"CSA notif (fail) : channel %d\n" , +le16_to_cpu (csa->channel)); +iwl_chswitch_done (priv, false); } }
Signature · 1 line
1.7.1
Quoted 13 lines · Stanislaw Gruszka
We use
priv->mutexto avoid race conditions betweeniwl_chswitch_done()andiwlagn_mac_channel_switch(), when marking channel switch in progress. Butiwl_chswitch_done()can be called in atomic context fromiwl_rx_csa()or with mutex already taken fromiwlagn_commit_rxon().These bugs were introduced by:
commit
79d07325502e73508f917475bc1617b60979dd94Author: Wey-Yi Guy <[email protected]> Date: Thu May 6 08:54:11 2010 -0700iwlwifi: support channel switch offload in driver
Quoted 8 lines
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 [email protected] # 2.6.36+Signed-off-by Stanislaw Gruszka <[email protected]>
Quoted 1 line
---