diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2010-05-06 11:54:11 -0400 |
---|---|---|
committer | Reinette Chatre <reinette.chatre@intel.com> | 2010-06-06 02:16:09 -0400 |
commit | 79d07325502e73508f917475bc1617b60979dd94 (patch) | |
tree | 7493c7db482c41b4535690c3a19fb81f3a7b2580 /drivers/net | |
parent | a0ee74cf080389aee4fbf198ffa7e85b3480b661 (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.c | 52 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-5000.c | 52 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-6000.c | 53 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 95 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 48 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 8 |
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 | ||
1448 | static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) | 1448 | static 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 | ||
274 | static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel) | 274 | static 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 | ||
242 | static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel) | 242 | static 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 | ||
3328 | static 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 | } | ||
3412 | out: | ||
3413 | mutex_unlock(&priv->mutex); | ||
3414 | out_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 | ||
3651 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 3744 | static 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 | } |
894 | EXPORT_SYMBOL(iwl_set_rxon_channel); | 894 | EXPORT_SYMBOL(iwl_set_rxon_channel); |
895 | 895 | ||
896 | static void iwl_set_flags_for_band(struct iwl_priv *priv, | 896 | void 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 | } |
917 | EXPORT_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 | } |
990 | EXPORT_SYMBOL(iwl_connection_init_rx_config); | 991 | EXPORT_SYMBOL(iwl_connection_init_rx_config); |
991 | 992 | ||
992 | static void iwl_set_rate(struct iwl_priv *priv) | 993 | void 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 | } |
1021 | EXPORT_SYMBOL(iwl_set_rate); | ||
1022 | |||
1023 | void 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 | } | ||
1035 | EXPORT_SYMBOL(iwl_chswitch_done); | ||
1020 | 1036 | ||
1021 | void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | 1037 | void 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 | } |
1041 | EXPORT_SYMBOL(iwl_rx_csa); | 1058 | EXPORT_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); | |||
345 | int iwl_full_rxon_required(struct iwl_priv *priv); | 346 | int iwl_full_rxon_required(struct iwl_priv *priv); |
346 | void iwl_set_rxon_chain(struct iwl_priv *priv); | 347 | void iwl_set_rxon_chain(struct iwl_priv *priv); |
347 | int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); | 348 | int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); |
349 | void iwl_set_flags_for_band(struct iwl_priv *priv, | ||
350 | enum ieee80211_band band, | ||
351 | struct ieee80211_vif *vif); | ||
348 | void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf); | 352 | void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf); |
349 | u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | 353 | u8 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); |
351 | void iwl_connection_init_rx_config(struct iwl_priv *priv, | 355 | void iwl_connection_init_rx_config(struct iwl_priv *priv, |
352 | struct ieee80211_vif *vif); | 356 | struct ieee80211_vif *vif); |
357 | void iwl_set_rate(struct iwl_priv *priv); | ||
353 | int iwl_set_decrypted_flag(struct iwl_priv *priv, | 358 | int 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); |
462 | void iwl_reply_statistics(struct iwl_priv *priv, | 467 | void iwl_reply_statistics(struct iwl_priv *priv, |
463 | struct iwl_rx_mem_buffer *rxb); | 468 | struct iwl_rx_mem_buffer *rxb); |
469 | void iwl_chswitch_done(struct iwl_priv *priv, bool is_success); | ||
464 | void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); | 470 | void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); |
465 | 471 | ||
466 | /* TX helpers */ | 472 | /* TX helpers */ |