aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2010-05-06 11:54:11 -0400
committerReinette Chatre <reinette.chatre@intel.com>2010-06-06 02:16:09 -0400
commit79d07325502e73508f917475bc1617b60979dd94 (patch)
tree7493c7db482c41b4535690c3a19fb81f3a7b2580 /drivers/net
parenta0ee74cf080389aee4fbf198ffa7e85b3480b661 (diff)
iwlwifi: support channel switch offload in driver
Support channel switch in driver as a separated mac80211 callback function instead of part of mac_config callback; by moving to this approach, uCode can have more control of channel switch timing. Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c52
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c52
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c53
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c95
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c48
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h8
6 files changed, 257 insertions, 51 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index fe7aa73cc0eb..1e4f1bc515db 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -1445,7 +1445,8 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
1445 return ret; 1445 return ret;
1446} 1446}
1447 1447
1448static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) 1448static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
1449 struct ieee80211_channel_switch *ch_switch)
1449{ 1450{
1450 int rc; 1451 int rc;
1451 u8 band = 0; 1452 u8 band = 0;
@@ -1453,11 +1454,14 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
1453 u8 ctrl_chan_high = 0; 1454 u8 ctrl_chan_high = 0;
1454 struct iwl4965_channel_switch_cmd cmd; 1455 struct iwl4965_channel_switch_cmd cmd;
1455 const struct iwl_channel_info *ch_info; 1456 const struct iwl_channel_info *ch_info;
1456 1457 u32 switch_time_in_usec, ucode_switch_time;
1458 u16 ch;
1459 u32 tsf_low;
1460 u8 switch_count;
1461 u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
1462 struct ieee80211_vif *vif = priv->vif;
1457 band = priv->band == IEEE80211_BAND_2GHZ; 1463 band = priv->band == IEEE80211_BAND_2GHZ;
1458 1464
1459 ch_info = iwl_get_channel_info(priv, priv->band, channel);
1460
1461 is_ht40 = is_ht40_channel(priv->staging_rxon.flags); 1465 is_ht40 = is_ht40_channel(priv->staging_rxon.flags);
1462 1466
1463 if (is_ht40 && 1467 if (is_ht40 &&
@@ -1466,26 +1470,56 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
1466 1470
1467 cmd.band = band; 1471 cmd.band = band;
1468 cmd.expect_beacon = 0; 1472 cmd.expect_beacon = 0;
1469 cmd.channel = cpu_to_le16(channel); 1473 ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
1474 cmd.channel = cpu_to_le16(ch);
1470 cmd.rxon_flags = priv->staging_rxon.flags; 1475 cmd.rxon_flags = priv->staging_rxon.flags;
1471 cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; 1476 cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
1472 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); 1477 switch_count = ch_switch->count;
1478 tsf_low = ch_switch->timestamp & 0x0ffffffff;
1479 /*
1480 * calculate the ucode channel switch time
1481 * adding TSF as one of the factor for when to switch
1482 */
1483 if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
1484 if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
1485 beacon_interval)) {
1486 switch_count -= (priv->ucode_beacon_time -
1487 tsf_low) / beacon_interval;
1488 } else
1489 switch_count = 0;
1490 }
1491 if (switch_count <= 1)
1492 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
1493 else {
1494 switch_time_in_usec =
1495 vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
1496 ucode_switch_time = iwl_usecs_to_beacons(priv,
1497 switch_time_in_usec,
1498 beacon_interval);
1499 cmd.switch_time = iwl_add_beacon_time(priv,
1500 priv->ucode_beacon_time,
1501 ucode_switch_time,
1502 beacon_interval);
1503 }
1504 IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
1505 cmd.switch_time);
1506 ch_info = iwl_get_channel_info(priv, priv->band, ch);
1473 if (ch_info) 1507 if (ch_info)
1474 cmd.expect_beacon = is_channel_radar(ch_info); 1508 cmd.expect_beacon = is_channel_radar(ch_info);
1475 else { 1509 else {
1476 IWL_ERR(priv, "invalid channel switch from %u to %u\n", 1510 IWL_ERR(priv, "invalid channel switch from %u to %u\n",
1477 priv->active_rxon.channel, channel); 1511 priv->active_rxon.channel, ch);
1478 return -EFAULT; 1512 return -EFAULT;
1479 } 1513 }
1480 1514
1481 rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40, 1515 rc = iwl4965_fill_txpower_tbl(priv, band, ch, is_ht40,
1482 ctrl_chan_high, &cmd.tx_power); 1516 ctrl_chan_high, &cmd.tx_power);
1483 if (rc) { 1517 if (rc) {
1484 IWL_DEBUG_11H(priv, "error:%d fill txpower_tbl\n", rc); 1518 IWL_DEBUG_11H(priv, "error:%d fill txpower_tbl\n", rc);
1485 return rc; 1519 return rc;
1486 } 1520 }
1487 1521
1488 priv->switch_rxon.channel = cpu_to_le16(channel); 1522 priv->switch_rxon.channel = cmd.channel;
1489 priv->switch_rxon.switch_in_progress = true; 1523 priv->switch_rxon.switch_in_progress = true;
1490 1524
1491 return iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); 1525 return iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index c320d4110fef..19bb5b89b63d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -271,10 +271,17 @@ static void iwl5150_temperature(struct iwl_priv *priv)
271 iwl_tt_handler(priv); 271 iwl_tt_handler(priv);
272} 272}
273 273
274static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel) 274static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
275 struct ieee80211_channel_switch *ch_switch)
275{ 276{
276 struct iwl5000_channel_switch_cmd cmd; 277 struct iwl5000_channel_switch_cmd cmd;
277 const struct iwl_channel_info *ch_info; 278 const struct iwl_channel_info *ch_info;
279 u32 switch_time_in_usec, ucode_switch_time;
280 u16 ch;
281 u32 tsf_low;
282 u8 switch_count;
283 u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
284 struct ieee80211_vif *vif = priv->vif;
278 struct iwl_host_cmd hcmd = { 285 struct iwl_host_cmd hcmd = {
279 .id = REPLY_CHANNEL_SWITCH, 286 .id = REPLY_CHANNEL_SWITCH,
280 .len = sizeof(cmd), 287 .len = sizeof(cmd),
@@ -282,22 +289,51 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
282 .data = &cmd, 289 .data = &cmd,
283 }; 290 };
284 291
285 IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
286 priv->active_rxon.channel, channel);
287 cmd.band = priv->band == IEEE80211_BAND_2GHZ; 292 cmd.band = priv->band == IEEE80211_BAND_2GHZ;
288 cmd.channel = cpu_to_le16(channel); 293 ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
294 IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
295 priv->active_rxon.channel, ch);
296 cmd.channel = cpu_to_le16(ch);
289 cmd.rxon_flags = priv->staging_rxon.flags; 297 cmd.rxon_flags = priv->staging_rxon.flags;
290 cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; 298 cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
291 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); 299 switch_count = ch_switch->count;
292 ch_info = iwl_get_channel_info(priv, priv->band, channel); 300 tsf_low = ch_switch->timestamp & 0x0ffffffff;
301 /*
302 * calculate the ucode channel switch time
303 * adding TSF as one of the factor for when to switch
304 */
305 if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
306 if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
307 beacon_interval)) {
308 switch_count -= (priv->ucode_beacon_time -
309 tsf_low) / beacon_interval;
310 } else
311 switch_count = 0;
312 }
313 if (switch_count <= 1)
314 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
315 else {
316 switch_time_in_usec =
317 vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
318 ucode_switch_time = iwl_usecs_to_beacons(priv,
319 switch_time_in_usec,
320 beacon_interval);
321 cmd.switch_time = iwl_add_beacon_time(priv,
322 priv->ucode_beacon_time,
323 ucode_switch_time,
324 beacon_interval);
325 }
326 IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
327 cmd.switch_time);
328 ch_info = iwl_get_channel_info(priv, priv->band, ch);
293 if (ch_info) 329 if (ch_info)
294 cmd.expect_beacon = is_channel_radar(ch_info); 330 cmd.expect_beacon = is_channel_radar(ch_info);
295 else { 331 else {
296 IWL_ERR(priv, "invalid channel switch from %u to %u\n", 332 IWL_ERR(priv, "invalid channel switch from %u to %u\n",
297 priv->active_rxon.channel, channel); 333 priv->active_rxon.channel, ch);
298 return -EFAULT; 334 return -EFAULT;
299 } 335 }
300 priv->switch_rxon.channel = cpu_to_le16(channel); 336 priv->switch_rxon.channel = cmd.channel;
301 priv->switch_rxon.switch_in_progress = true; 337 priv->switch_rxon.switch_in_progress = true;
302 338
303 return iwl_send_cmd_sync(priv, &hcmd); 339 return iwl_send_cmd_sync(priv, &hcmd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 5f6dbd9561d7..077514546d02 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -239,10 +239,17 @@ static int iwl6050_hw_set_hw_params(struct iwl_priv *priv)
239 return 0; 239 return 0;
240} 240}
241 241
242static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel) 242static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
243 struct ieee80211_channel_switch *ch_switch)
243{ 244{
244 struct iwl6000_channel_switch_cmd cmd; 245 struct iwl6000_channel_switch_cmd cmd;
245 const struct iwl_channel_info *ch_info; 246 const struct iwl_channel_info *ch_info;
247 u32 switch_time_in_usec, ucode_switch_time;
248 u16 ch;
249 u32 tsf_low;
250 u8 switch_count;
251 u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
252 struct ieee80211_vif *vif = priv->vif;
246 struct iwl_host_cmd hcmd = { 253 struct iwl_host_cmd hcmd = {
247 .id = REPLY_CHANNEL_SWITCH, 254 .id = REPLY_CHANNEL_SWITCH,
248 .len = sizeof(cmd), 255 .len = sizeof(cmd),
@@ -250,23 +257,51 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
250 .data = &cmd, 257 .data = &cmd,
251 }; 258 };
252 259
253 IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
254 priv->active_rxon.channel, channel);
255
256 cmd.band = priv->band == IEEE80211_BAND_2GHZ; 260 cmd.band = priv->band == IEEE80211_BAND_2GHZ;
257 cmd.channel = cpu_to_le16(channel); 261 ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
262 IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
263 priv->active_rxon.channel, ch);
264 cmd.channel = cpu_to_le16(ch);
258 cmd.rxon_flags = priv->staging_rxon.flags; 265 cmd.rxon_flags = priv->staging_rxon.flags;
259 cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; 266 cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
260 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); 267 switch_count = ch_switch->count;
261 ch_info = iwl_get_channel_info(priv, priv->band, channel); 268 tsf_low = ch_switch->timestamp & 0x0ffffffff;
269 /*
270 * calculate the ucode channel switch time
271 * adding TSF as one of the factor for when to switch
272 */
273 if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
274 if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
275 beacon_interval)) {
276 switch_count -= (priv->ucode_beacon_time -
277 tsf_low) / beacon_interval;
278 } else
279 switch_count = 0;
280 }
281 if (switch_count <= 1)
282 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
283 else {
284 switch_time_in_usec =
285 vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
286 ucode_switch_time = iwl_usecs_to_beacons(priv,
287 switch_time_in_usec,
288 beacon_interval);
289 cmd.switch_time = iwl_add_beacon_time(priv,
290 priv->ucode_beacon_time,
291 ucode_switch_time,
292 beacon_interval);
293 }
294 IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
295 cmd.switch_time);
296 ch_info = iwl_get_channel_info(priv, priv->band, ch);
262 if (ch_info) 297 if (ch_info)
263 cmd.expect_beacon = is_channel_radar(ch_info); 298 cmd.expect_beacon = is_channel_radar(ch_info);
264 else { 299 else {
265 IWL_ERR(priv, "invalid channel switch from %u to %u\n", 300 IWL_ERR(priv, "invalid channel switch from %u to %u\n",
266 priv->active_rxon.channel, channel); 301 priv->active_rxon.channel, ch);
267 return -EFAULT; 302 return -EFAULT;
268 } 303 }
269 priv->switch_rxon.channel = cpu_to_le16(channel); 304 priv->switch_rxon.channel = cmd.channel;
270 priv->switch_rxon.switch_in_progress = true; 305 priv->switch_rxon.switch_in_progress = true;
271 306
272 return iwl_send_cmd_sync(priv, &hcmd); 307 return iwl_send_cmd_sync(priv, &hcmd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 021b01494a2a..9c85e1bd2971 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -120,7 +120,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
120 (priv->switch_rxon.channel != priv->staging_rxon.channel)) { 120 (priv->switch_rxon.channel != priv->staging_rxon.channel)) {
121 IWL_DEBUG_11H(priv, "abort channel switch on %d\n", 121 IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
122 le16_to_cpu(priv->switch_rxon.channel)); 122 le16_to_cpu(priv->switch_rxon.channel));
123 priv->switch_rxon.switch_in_progress = false; 123 iwl_chswitch_done(priv, false);
124 } 124 }
125 125
126 /* If we don't need to send a full RXON, we can use 126 /* If we don't need to send a full RXON, we can use
@@ -3325,6 +3325,98 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
3325 return 0; 3325 return 0;
3326} 3326}
3327 3327
3328static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
3329 struct ieee80211_channel_switch *ch_switch)
3330{
3331 struct iwl_priv *priv = hw->priv;
3332 const struct iwl_channel_info *ch_info;
3333 struct ieee80211_conf *conf = &hw->conf;
3334 struct iwl_ht_config *ht_conf = &priv->current_ht_config;
3335 u16 ch;
3336 unsigned long flags = 0;
3337
3338 IWL_DEBUG_MAC80211(priv, "enter\n");
3339
3340 if (iwl_is_rfkill(priv))
3341 goto out_exit;
3342
3343 if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
3344 test_bit(STATUS_SCANNING, &priv->status))
3345 goto out_exit;
3346
3347 if (!iwl_is_associated(priv))
3348 goto out_exit;
3349
3350 /* channel switch in progress */
3351 if (priv->switch_rxon.switch_in_progress == true)
3352 goto out_exit;
3353
3354 mutex_lock(&priv->mutex);
3355 if (priv->cfg->ops->lib->set_channel_switch) {
3356
3357 ch = ieee80211_frequency_to_channel(
3358 ch_switch->channel->center_freq);
3359 if (le16_to_cpu(priv->active_rxon.channel) != ch) {
3360 ch_info = iwl_get_channel_info(priv,
3361 conf->channel->band,
3362 ch);
3363 if (!is_channel_valid(ch_info)) {
3364 IWL_DEBUG_MAC80211(priv, "invalid channel\n");
3365 goto out;
3366 }
3367 spin_lock_irqsave(&priv->lock, flags);
3368
3369 priv->current_ht_config.smps = conf->smps_mode;
3370
3371 /* Configure HT40 channels */
3372 ht_conf->is_ht = conf_is_ht(conf);
3373 if (ht_conf->is_ht) {
3374 if (conf_is_ht40_minus(conf)) {
3375 ht_conf->extension_chan_offset =
3376 IEEE80211_HT_PARAM_CHA_SEC_BELOW;
3377 ht_conf->is_40mhz = true;
3378 } else if (conf_is_ht40_plus(conf)) {
3379 ht_conf->extension_chan_offset =
3380 IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
3381 ht_conf->is_40mhz = true;
3382 } else {
3383 ht_conf->extension_chan_offset =
3384 IEEE80211_HT_PARAM_CHA_SEC_NONE;
3385 ht_conf->is_40mhz = false;
3386 }
3387 } else
3388 ht_conf->is_40mhz = false;
3389
3390 /* if we are switching from ht to 2.4 clear flags
3391 * from any ht related info since 2.4 does not
3392 * support ht */
3393 if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
3394 priv->staging_rxon.flags = 0;
3395
3396 iwl_set_rxon_channel(priv, conf->channel);
3397 iwl_set_rxon_ht(priv, ht_conf);
3398 iwl_set_flags_for_band(priv, conf->channel->band,
3399 priv->vif);
3400 spin_unlock_irqrestore(&priv->lock, flags);
3401
3402 iwl_set_rate(priv);
3403 /*
3404 * at this point, staging_rxon has the
3405 * configuration for channel switch
3406 */
3407 if (priv->cfg->ops->lib->set_channel_switch(priv,
3408 ch_switch))
3409 priv->switch_rxon.switch_in_progress = false;
3410 }
3411 }
3412out:
3413 mutex_unlock(&priv->mutex);
3414out_exit:
3415 if (!priv->switch_rxon.switch_in_progress)
3416 ieee80211_chswitch_done(priv->vif, false);
3417 IWL_DEBUG_MAC80211(priv, "leave\n");
3418}
3419
3328/***************************************************************************** 3420/*****************************************************************************
3329 * 3421 *
3330 * sysfs attributes 3422 * sysfs attributes
@@ -3646,6 +3738,7 @@ static struct ieee80211_ops iwl_hw_ops = {
3646 .sta_notify = iwl_mac_sta_notify, 3738 .sta_notify = iwl_mac_sta_notify,
3647 .sta_add = iwlagn_mac_sta_add, 3739 .sta_add = iwlagn_mac_sta_add,
3648 .sta_remove = iwl_mac_sta_remove, 3740 .sta_remove = iwl_mac_sta_remove,
3741 .channel_switch = iwl_mac_channel_switch,
3649}; 3742};
3650 3743
3651static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 3744static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index b05b813413fd..718ffa3d89c1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -893,9 +893,9 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
893} 893}
894EXPORT_SYMBOL(iwl_set_rxon_channel); 894EXPORT_SYMBOL(iwl_set_rxon_channel);
895 895
896static void iwl_set_flags_for_band(struct iwl_priv *priv, 896void iwl_set_flags_for_band(struct iwl_priv *priv,
897 enum ieee80211_band band, 897 enum ieee80211_band band,
898 struct ieee80211_vif *vif) 898 struct ieee80211_vif *vif)
899{ 899{
900 if (band == IEEE80211_BAND_5GHZ) { 900 if (band == IEEE80211_BAND_5GHZ) {
901 priv->staging_rxon.flags &= 901 priv->staging_rxon.flags &=
@@ -914,6 +914,7 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv,
914 priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK; 914 priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
915 } 915 }
916} 916}
917EXPORT_SYMBOL(iwl_set_flags_for_band);
917 918
918/* 919/*
919 * initialize rxon structure with default values from eeprom 920 * initialize rxon structure with default values from eeprom
@@ -989,7 +990,7 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv,
989} 990}
990EXPORT_SYMBOL(iwl_connection_init_rx_config); 991EXPORT_SYMBOL(iwl_connection_init_rx_config);
991 992
992static void iwl_set_rate(struct iwl_priv *priv) 993void iwl_set_rate(struct iwl_priv *priv)
993{ 994{
994 const struct ieee80211_supported_band *hw = NULL; 995 const struct ieee80211_supported_band *hw = NULL;
995 struct ieee80211_rate *rate; 996 struct ieee80211_rate *rate;
@@ -1017,6 +1018,21 @@ static void iwl_set_rate(struct iwl_priv *priv)
1017 priv->staging_rxon.ofdm_basic_rates = 1018 priv->staging_rxon.ofdm_basic_rates =
1018 (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; 1019 (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
1019} 1020}
1021EXPORT_SYMBOL(iwl_set_rate);
1022
1023void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
1024{
1025 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
1026 return;
1027
1028 if (priv->switch_rxon.switch_in_progress) {
1029 ieee80211_chswitch_done(priv->vif, is_success);
1030 mutex_lock(&priv->mutex);
1031 priv->switch_rxon.switch_in_progress = false;
1032 mutex_unlock(&priv->mutex);
1033 }
1034}
1035EXPORT_SYMBOL(iwl_chswitch_done);
1020 1036
1021void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) 1037void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
1022{ 1038{
@@ -1031,11 +1047,12 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
1031 priv->staging_rxon.channel = csa->channel; 1047 priv->staging_rxon.channel = csa->channel;
1032 IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", 1048 IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
1033 le16_to_cpu(csa->channel)); 1049 le16_to_cpu(csa->channel));
1034 } else 1050 iwl_chswitch_done(priv, true);
1051 } else {
1035 IWL_ERR(priv, "CSA notif (fail) : channel %d\n", 1052 IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
1036 le16_to_cpu(csa->channel)); 1053 le16_to_cpu(csa->channel));
1037 1054 iwl_chswitch_done(priv, false);
1038 priv->switch_rxon.switch_in_progress = false; 1055 }
1039 } 1056 }
1040} 1057}
1041EXPORT_SYMBOL(iwl_rx_csa); 1058EXPORT_SYMBOL(iwl_rx_csa);
@@ -2044,22 +2061,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
2044 2061
2045 iwl_set_flags_for_band(priv, conf->channel->band, priv->vif); 2062 iwl_set_flags_for_band(priv, conf->channel->band, priv->vif);
2046 spin_unlock_irqrestore(&priv->lock, flags); 2063 spin_unlock_irqrestore(&priv->lock, flags);
2047 if (iwl_is_associated(priv) && 2064
2048 (le16_to_cpu(priv->active_rxon.channel) != ch) &&
2049 priv->cfg->ops->lib->set_channel_switch) {
2050 iwl_set_rate(priv);
2051 /*
2052 * at this point, staging_rxon has the
2053 * configuration for channel switch
2054 */
2055 ret = priv->cfg->ops->lib->set_channel_switch(priv,
2056 ch);
2057 if (!ret) {
2058 iwl_print_rx_config_cmd(priv);
2059 goto out;
2060 }
2061 priv->switch_rxon.switch_in_progress = false;
2062 }
2063 set_ch_out: 2065 set_ch_out:
2064 /* The list of supported rates and rate mask can be different 2066 /* The list of supported rates and rate mask can be different
2065 * for each band; since the band may have changed, reset 2067 * for each band; since the band may have changed, reset
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 48d96fda431c..9fe08ecdc14b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -175,7 +175,8 @@ struct iwl_lib_ops {
175 void (*dump_nic_error_log)(struct iwl_priv *priv); 175 void (*dump_nic_error_log)(struct iwl_priv *priv);
176 void (*dump_csr)(struct iwl_priv *priv); 176 void (*dump_csr)(struct iwl_priv *priv);
177 int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display); 177 int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display);
178 int (*set_channel_switch)(struct iwl_priv *priv, u16 channel); 178 int (*set_channel_switch)(struct iwl_priv *priv,
179 struct ieee80211_channel_switch *ch_switch);
179 /* power management */ 180 /* power management */
180 struct iwl_apm_ops apm_ops; 181 struct iwl_apm_ops apm_ops;
181 182
@@ -345,11 +346,15 @@ int iwl_check_rxon_cmd(struct iwl_priv *priv);
345int iwl_full_rxon_required(struct iwl_priv *priv); 346int iwl_full_rxon_required(struct iwl_priv *priv);
346void iwl_set_rxon_chain(struct iwl_priv *priv); 347void iwl_set_rxon_chain(struct iwl_priv *priv);
347int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); 348int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
349void iwl_set_flags_for_band(struct iwl_priv *priv,
350 enum ieee80211_band band,
351 struct ieee80211_vif *vif);
348void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf); 352void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
349u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, 353u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
350 struct ieee80211_sta_ht_cap *sta_ht_inf); 354 struct ieee80211_sta_ht_cap *sta_ht_inf);
351void iwl_connection_init_rx_config(struct iwl_priv *priv, 355void iwl_connection_init_rx_config(struct iwl_priv *priv,
352 struct ieee80211_vif *vif); 356 struct ieee80211_vif *vif);
357void iwl_set_rate(struct iwl_priv *priv);
353int iwl_set_decrypted_flag(struct iwl_priv *priv, 358int iwl_set_decrypted_flag(struct iwl_priv *priv,
354 struct ieee80211_hdr *hdr, 359 struct ieee80211_hdr *hdr,
355 u32 decrypt_res, 360 u32 decrypt_res,
@@ -461,6 +466,7 @@ void iwl_rx_statistics(struct iwl_priv *priv,
461 struct iwl_rx_mem_buffer *rxb); 466 struct iwl_rx_mem_buffer *rxb);
462void iwl_reply_statistics(struct iwl_priv *priv, 467void iwl_reply_statistics(struct iwl_priv *priv,
463 struct iwl_rx_mem_buffer *rxb); 468 struct iwl_rx_mem_buffer *rxb);
469void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
464void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); 470void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
465 471
466/* TX helpers */ 472/* TX helpers */