aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-11-06 17:52:54 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-11-11 15:23:44 -0500
commit0924e519a3a18ffbfaa043f4a2c369140c5a235c (patch)
tree85bab606d81ae1959fec12d246ba19f1097eeacc /drivers/net/wireless/iwlwifi
parent681988653ed46a14032ac5fe2ee84eaae314b72e (diff)
iwlwifi: fix for channel switch
Different channel has different configuration, need to pass correct configuration to uCode when send "channel switch" command to uCode. Invalid configuration will cause sysassert in uCode and produce un-expected result. Even it is a very small windows, but we also need to consider and handle the case if commit_rxon occurred before the "channel switch announcement" notification received from uCode. Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c45
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h13
6 files changed, 68 insertions, 25 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index faa4c4e2d43c..1d22ea390c00 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -1449,14 +1449,14 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
1449 is_ht40 = is_ht40_channel(priv->staging_rxon.flags); 1449 is_ht40 = is_ht40_channel(priv->staging_rxon.flags);
1450 1450
1451 if (is_ht40 && 1451 if (is_ht40 &&
1452 (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK)) 1452 (priv->staging_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
1453 ctrl_chan_high = 1; 1453 ctrl_chan_high = 1;
1454 1454
1455 cmd.band = band; 1455 cmd.band = band;
1456 cmd.expect_beacon = 0; 1456 cmd.expect_beacon = 0;
1457 cmd.channel = cpu_to_le16(channel); 1457 cmd.channel = cpu_to_le16(channel);
1458 cmd.rxon_flags = priv->active_rxon.flags; 1458 cmd.rxon_flags = priv->staging_rxon.flags;
1459 cmd.rxon_filter_flags = priv->active_rxon.filter_flags; 1459 cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
1460 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); 1460 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
1461 if (ch_info) 1461 if (ch_info)
1462 cmd.expect_beacon = is_channel_radar(ch_info); 1462 cmd.expect_beacon = is_channel_radar(ch_info);
@@ -1473,8 +1473,10 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
1473 return rc; 1473 return rc;
1474 } 1474 }
1475 1475
1476 rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); 1476 priv->switch_rxon.channel = cpu_to_le16(channel);
1477 return rc; 1477 priv->switch_rxon.switch_in_progress = true;
1478
1479 return iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
1478} 1480}
1479 1481
1480/** 1482/**
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 6ea5e2dc273c..6eaf26b07636 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1391,8 +1391,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
1391 priv->active_rxon.channel, channel); 1391 priv->active_rxon.channel, channel);
1392 cmd.band = priv->band == IEEE80211_BAND_2GHZ; 1392 cmd.band = priv->band == IEEE80211_BAND_2GHZ;
1393 cmd.channel = cpu_to_le16(channel); 1393 cmd.channel = cpu_to_le16(channel);
1394 cmd.rxon_flags = priv->active_rxon.flags; 1394 cmd.rxon_flags = priv->staging_rxon.flags;
1395 cmd.rxon_filter_flags = priv->active_rxon.filter_flags; 1395 cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
1396 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); 1396 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
1397 ch_info = iwl_get_channel_info(priv, priv->band, channel); 1397 ch_info = iwl_get_channel_info(priv, priv->band, channel);
1398 if (ch_info) 1398 if (ch_info)
@@ -1402,6 +1402,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
1402 priv->active_rxon.channel, channel); 1402 priv->active_rxon.channel, channel);
1403 return -EFAULT; 1403 return -EFAULT;
1404 } 1404 }
1405 priv->switch_rxon.channel = cpu_to_le16(channel);
1406 priv->switch_rxon.switch_in_progress = true;
1405 1407
1406 return iwl_send_cmd_sync(priv, &hcmd); 1408 return iwl_send_cmd_sync(priv, &hcmd);
1407} 1409}
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 9ab79546b8a4..1f769ea23636 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -186,8 +186,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
186 186
187 cmd.band = priv->band == IEEE80211_BAND_2GHZ; 187 cmd.band = priv->band == IEEE80211_BAND_2GHZ;
188 cmd.channel = cpu_to_le16(channel); 188 cmd.channel = cpu_to_le16(channel);
189 cmd.rxon_flags = priv->active_rxon.flags; 189 cmd.rxon_flags = priv->staging_rxon.flags;
190 cmd.rxon_filter_flags = priv->active_rxon.filter_flags; 190 cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
191 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); 191 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
192 ch_info = iwl_get_channel_info(priv, priv->band, channel); 192 ch_info = iwl_get_channel_info(priv, priv->band, channel);
193 if (ch_info) 193 if (ch_info)
@@ -197,6 +197,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
197 priv->active_rxon.channel, channel); 197 priv->active_rxon.channel, channel);
198 return -EFAULT; 198 return -EFAULT;
199 } 199 }
200 priv->switch_rxon.channel = cpu_to_le16(channel);
201 priv->switch_rxon.switch_in_progress = true;
200 202
201 return iwl_send_cmd_sync(priv, &hcmd); 203 return iwl_send_cmd_sync(priv, &hcmd);
202} 204}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 1710815691d5..7bdedf61dd36 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -122,6 +122,17 @@ int iwl_commit_rxon(struct iwl_priv *priv)
122 return -EINVAL; 122 return -EINVAL;
123 } 123 }
124 124
125 /*
126 * receive commit_rxon request
127 * abort any previous channel switch if still in process
128 */
129 if (priv->switch_rxon.switch_in_progress &&
130 (priv->switch_rxon.channel != priv->staging_rxon.channel)) {
131 IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
132 le16_to_cpu(priv->switch_rxon.channel));
133 priv->switch_rxon.switch_in_progress = false;
134 }
135
125 /* If we don't need to send a full RXON, we can use 136 /* If we don't need to send a full RXON, we can use
126 * iwl_rxon_assoc_cmd which is used to reconfigure filter 137 * iwl_rxon_assoc_cmd which is used to reconfigure filter
127 * and other flags for the current radio configuration. */ 138 * and other flags for the current radio configuration. */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index f88a1cb7a12b..e0edc607e33f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -1316,14 +1316,19 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
1316 struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; 1316 struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
1317 struct iwl_csa_notification *csa = &(pkt->u.csa_notif); 1317 struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
1318 1318
1319 if (!le32_to_cpu(csa->status)) { 1319 if (priv->switch_rxon.switch_in_progress) {
1320 rxon->channel = csa->channel; 1320 if (!le32_to_cpu(csa->status) &&
1321 priv->staging_rxon.channel = csa->channel; 1321 (csa->channel == priv->switch_rxon.channel)) {
1322 IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", 1322 rxon->channel = csa->channel;
1323 le16_to_cpu(csa->channel)); 1323 priv->staging_rxon.channel = csa->channel;
1324 } else 1324 IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
1325 IWL_ERR(priv, "CSA notif (fail) : channel %d\n", 1325 le16_to_cpu(csa->channel));
1326 le16_to_cpu(csa->channel)); 1326 } else
1327 IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
1328 le16_to_cpu(csa->channel));
1329
1330 priv->switch_rxon.switch_in_progress = false;
1331 }
1327} 1332}
1328EXPORT_SYMBOL(iwl_rx_csa); 1333EXPORT_SYMBOL(iwl_rx_csa);
1329 1334
@@ -2690,14 +2695,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
2690 goto set_ch_out; 2695 goto set_ch_out;
2691 } 2696 }
2692 2697
2693 if (iwl_is_associated(priv) &&
2694 (le16_to_cpu(priv->active_rxon.channel) != ch) &&
2695 priv->cfg->ops->lib->set_channel_switch) {
2696 ret = priv->cfg->ops->lib->set_channel_switch(priv,
2697 ch);
2698 goto out;
2699 }
2700
2701 spin_lock_irqsave(&priv->lock, flags); 2698 spin_lock_irqsave(&priv->lock, flags);
2702 2699
2703 /* Configure HT40 channels */ 2700 /* Configure HT40 channels */
@@ -2732,6 +2729,22 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
2732 2729
2733 iwl_set_flags_for_band(priv, conf->channel->band); 2730 iwl_set_flags_for_band(priv, conf->channel->band);
2734 spin_unlock_irqrestore(&priv->lock, flags); 2731 spin_unlock_irqrestore(&priv->lock, flags);
2732 if (iwl_is_associated(priv) &&
2733 (le16_to_cpu(priv->active_rxon.channel) != ch) &&
2734 priv->cfg->ops->lib->set_channel_switch) {
2735 iwl_set_rate(priv);
2736 /*
2737 * at this point, staging_rxon has the
2738 * configuration for channel switch
2739 */
2740 ret = priv->cfg->ops->lib->set_channel_switch(priv,
2741 ch);
2742 if (!ret) {
2743 iwl_print_rx_config_cmd(priv);
2744 goto out;
2745 }
2746 priv->switch_rxon.switch_in_progress = false;
2747 }
2735 set_ch_out: 2748 set_ch_out:
2736 /* The list of supported rates and rate mask can be different 2749 /* The list of supported rates and rate mask can be different
2737 * for each band; since the band may have changed, reset 2750 * for each band; since the band may have changed, reset
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 997564584c71..9a19a3d1f704 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -994,6 +994,17 @@ struct traffic_stats {
994}; 994};
995#endif 995#endif
996 996
997/*
998 * iwl_switch_rxon: "channel switch" structure
999 *
1000 * @ switch_in_progress: channel switch in progress
1001 * @ channel: new channel
1002 */
1003struct iwl_switch_rxon {
1004 bool switch_in_progress;
1005 __le16 channel;
1006};
1007
997struct iwl_priv { 1008struct iwl_priv {
998 1009
999 /* ieee device used by generic ieee processing code */ 1010 /* ieee device used by generic ieee processing code */
@@ -1087,6 +1098,8 @@ struct iwl_priv {
1087 const struct iwl_rxon_cmd active_rxon; 1098 const struct iwl_rxon_cmd active_rxon;
1088 struct iwl_rxon_cmd staging_rxon; 1099 struct iwl_rxon_cmd staging_rxon;
1089 1100
1101 struct iwl_switch_rxon switch_rxon;
1102
1090 /* 1st responses from initialize and runtime uCode images. 1103 /* 1st responses from initialize and runtime uCode images.
1091 * 4965's initialize alive response contains some calibration data. */ 1104 * 4965's initialize alive response contains some calibration data. */
1092 struct iwl_init_alive_resp card_alive_init; 1105 struct iwl_init_alive_resp card_alive_init;