diff options
author | Reinette Chatre <reinette.chatre@intel.com> | 2010-04-23 13:33:33 -0400 |
---|---|---|
committer | Reinette Chatre <reinette.chatre@intel.com> | 2010-05-10 18:08:51 -0400 |
commit | d2e210aef3a8e7472f91d10a50ecbc91c0a53d62 (patch) | |
tree | 072dceeed6ab669ed0619d4c195d11a01df6b93d /drivers/net/wireless/iwlwifi/iwl-sta.c | |
parent | 459bc732abad5e461da9a06d82dfc0cb1119ef5a (diff) |
iwlwifi: make bcast LQ command available for later restore actions
When adding the broadcast station the link quality command is
generated on demand, sent to device, and disappears. It is thus not
available for later cases when we need to restore stations and need
to send the link quality command afterwards. Now, when first adding the
broadcast station, also generate its link quality command to always be
available for later restoring.
Also fix an issue when adding local stations where the "in progress" state
is never cleared.
Reported-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 91 |
1 files changed, 66 insertions, 25 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index db934476b5e9..5c6b3262baf9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -418,15 +418,19 @@ int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr, | |||
418 | } | 418 | } |
419 | EXPORT_SYMBOL(iwl_add_station_common); | 419 | EXPORT_SYMBOL(iwl_add_station_common); |
420 | 420 | ||
421 | static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap) | 421 | static struct iwl_link_quality_cmd *iwl_sta_init_lq(struct iwl_priv *priv, |
422 | const u8 *addr, bool is_ap) | ||
422 | { | 423 | { |
423 | int i, r; | 424 | int i, r; |
424 | struct iwl_link_quality_cmd link_cmd = { | 425 | struct iwl_link_quality_cmd *link_cmd; |
425 | .reserved1 = 0, | ||
426 | }; | ||
427 | u32 rate_flags; | 426 | u32 rate_flags; |
428 | int ret = 0; | 427 | int ret = 0; |
429 | 428 | ||
429 | link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL); | ||
430 | if (!link_cmd) { | ||
431 | IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n"); | ||
432 | return NULL; | ||
433 | } | ||
430 | /* Set up the rate scaling to start at selected rate, fall back | 434 | /* Set up the rate scaling to start at selected rate, fall back |
431 | * all the way down to 1M in IEEE order, and then spin on 1M */ | 435 | * all the way down to 1M in IEEE order, and then spin on 1M */ |
432 | if (is_ap) | 436 | if (is_ap) |
@@ -444,35 +448,36 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap) | |||
444 | rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << | 448 | rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << |
445 | RATE_MCS_ANT_POS; | 449 | RATE_MCS_ANT_POS; |
446 | 450 | ||
447 | link_cmd.rs_table[i].rate_n_flags = | 451 | link_cmd->rs_table[i].rate_n_flags = |
448 | iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); | 452 | iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); |
449 | r = iwl_get_prev_ieee_rate(r); | 453 | r = iwl_get_prev_ieee_rate(r); |
450 | } | 454 | } |
451 | 455 | ||
452 | link_cmd.general_params.single_stream_ant_msk = | 456 | link_cmd->general_params.single_stream_ant_msk = |
453 | first_antenna(priv->hw_params.valid_tx_ant); | 457 | first_antenna(priv->hw_params.valid_tx_ant); |
454 | 458 | ||
455 | link_cmd.general_params.dual_stream_ant_msk = | 459 | link_cmd->general_params.dual_stream_ant_msk = |
456 | priv->hw_params.valid_tx_ant & | 460 | priv->hw_params.valid_tx_ant & |
457 | ~first_antenna(priv->hw_params.valid_tx_ant); | 461 | ~first_antenna(priv->hw_params.valid_tx_ant); |
458 | if (!link_cmd.general_params.dual_stream_ant_msk) { | 462 | if (!link_cmd->general_params.dual_stream_ant_msk) { |
459 | link_cmd.general_params.dual_stream_ant_msk = ANT_AB; | 463 | link_cmd->general_params.dual_stream_ant_msk = ANT_AB; |
460 | } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) { | 464 | } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) { |
461 | link_cmd.general_params.dual_stream_ant_msk = | 465 | link_cmd->general_params.dual_stream_ant_msk = |
462 | priv->hw_params.valid_tx_ant; | 466 | priv->hw_params.valid_tx_ant; |
463 | } | 467 | } |
464 | 468 | ||
465 | link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; | 469 | link_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; |
466 | link_cmd.agg_params.agg_time_limit = | 470 | link_cmd->agg_params.agg_time_limit = |
467 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | 471 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); |
468 | 472 | ||
469 | /* Update the rate scaling for control frame Tx to AP */ | 473 | /* Update the rate scaling for control frame Tx to AP */ |
470 | link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; | 474 | link_cmd->sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; |
471 | 475 | ||
472 | ret = iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, | 476 | ret = iwl_send_lq_cmd(priv, link_cmd, CMD_SYNC, true); |
473 | sizeof(link_cmd), &link_cmd); | ||
474 | if (ret) | 477 | if (ret) |
475 | IWL_ERR(priv, "REPLY_TX_LINK_QUALITY_CMD failed (%d)\n", ret); | 478 | IWL_ERR(priv, "Link quality command failed (%d)\n", ret); |
479 | |||
480 | return link_cmd; | ||
476 | } | 481 | } |
477 | 482 | ||
478 | /* | 483 | /* |
@@ -487,6 +492,8 @@ int iwl_add_local_station(struct iwl_priv *priv, const u8 *addr, bool init_rs) | |||
487 | { | 492 | { |
488 | int ret; | 493 | int ret; |
489 | u8 sta_id; | 494 | u8 sta_id; |
495 | struct iwl_link_quality_cmd *link_cmd; | ||
496 | unsigned long flags; | ||
490 | 497 | ||
491 | ret = iwl_add_station_common(priv, addr, 0, NULL, &sta_id); | 498 | ret = iwl_add_station_common(priv, addr, 0, NULL, &sta_id); |
492 | if (ret) { | 499 | if (ret) { |
@@ -494,9 +501,23 @@ int iwl_add_local_station(struct iwl_priv *priv, const u8 *addr, bool init_rs) | |||
494 | return ret; | 501 | return ret; |
495 | } | 502 | } |
496 | 503 | ||
497 | if (init_rs) | 504 | spin_lock_irqsave(&priv->sta_lock, flags); |
505 | priv->stations[sta_id].used |= IWL_STA_LOCAL; | ||
506 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
507 | |||
508 | if (init_rs) { | ||
498 | /* Set up default rate scaling table in device's station table */ | 509 | /* Set up default rate scaling table in device's station table */ |
499 | iwl_sta_init_lq(priv, addr, false); | 510 | link_cmd = iwl_sta_init_lq(priv, addr, false); |
511 | if (!link_cmd) { | ||
512 | IWL_ERR(priv, "Unable to initialize rate scaling for station %pM.\n", | ||
513 | addr); | ||
514 | return -ENOMEM; | ||
515 | } | ||
516 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
517 | priv->stations[sta_id].lq = link_cmd; | ||
518 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
519 | } | ||
520 | |||
500 | return 0; | 521 | return 0; |
501 | } | 522 | } |
502 | EXPORT_SYMBOL(iwl_add_local_station); | 523 | EXPORT_SYMBOL(iwl_add_local_station); |
@@ -509,7 +530,8 @@ EXPORT_SYMBOL(iwl_add_local_station); | |||
509 | static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id) | 530 | static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id) |
510 | { | 531 | { |
511 | /* Ucode must be active and driver must be non active */ | 532 | /* Ucode must be active and driver must be non active */ |
512 | if (priv->stations[sta_id].used != IWL_STA_UCODE_ACTIVE) | 533 | if ((priv->stations[sta_id].used & |
534 | (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) != IWL_STA_UCODE_ACTIVE) | ||
513 | IWL_ERR(priv, "removed non active STA %u\n", sta_id); | 535 | IWL_ERR(priv, "removed non active STA %u\n", sta_id); |
514 | 536 | ||
515 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; | 537 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; |
@@ -676,8 +698,23 @@ void iwl_clear_ucode_stations(struct iwl_priv *priv, bool force) | |||
676 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | 698 | spin_lock_irqsave(&priv->sta_lock, flags_spin); |
677 | if (force) { | 699 | if (force) { |
678 | IWL_DEBUG_INFO(priv, "Clearing all station information in driver\n"); | 700 | IWL_DEBUG_INFO(priv, "Clearing all station information in driver\n"); |
701 | /* | ||
702 | * The station entry contains a link to the LQ command. For | ||
703 | * all stations managed by mac80211 this memory will be | ||
704 | * managed by it also. For local stations (broadcast and | ||
705 | * bssid station when in adhoc mode) we need to maintain | ||
706 | * this lq command separately. This memory is created when | ||
707 | * these stations are added. | ||
708 | */ | ||
709 | for (i = 0; i < priv->hw_params.max_stations; i++) { | ||
710 | if (priv->stations[i].used & IWL_STA_LOCAL) { | ||
711 | kfree(priv->stations[i].lq); | ||
712 | priv->stations[i].lq = NULL; | ||
713 | } | ||
714 | } | ||
679 | priv->num_stations = 0; | 715 | priv->num_stations = 0; |
680 | memset(priv->stations, 0, sizeof(priv->stations)); | 716 | memset(priv->stations, 0, sizeof(priv->stations)); |
717 | cleared = true; | ||
681 | } else { | 718 | } else { |
682 | for (i = 0; i < priv->hw_params.max_stations; i++) { | 719 | for (i = 0; i < priv->hw_params.max_stations; i++) { |
683 | if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) { | 720 | if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) { |
@@ -1207,7 +1244,8 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, | |||
1207 | BUG_ON(init && (cmd.flags & CMD_ASYNC)); | 1244 | BUG_ON(init && (cmd.flags & CMD_ASYNC)); |
1208 | 1245 | ||
1209 | ret = iwl_send_cmd(priv, &cmd); | 1246 | ret = iwl_send_cmd(priv, &cmd); |
1210 | if (ret || (cmd.flags & CMD_ASYNC)) | 1247 | |
1248 | if (cmd.flags & CMD_ASYNC) | ||
1211 | return ret; | 1249 | return ret; |
1212 | 1250 | ||
1213 | if (init) { | 1251 | if (init) { |
@@ -1217,33 +1255,36 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, | |||
1217 | priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; | 1255 | priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; |
1218 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | 1256 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); |
1219 | } | 1257 | } |
1220 | return 0; | 1258 | return ret; |
1221 | } | 1259 | } |
1222 | EXPORT_SYMBOL(iwl_send_lq_cmd); | 1260 | EXPORT_SYMBOL(iwl_send_lq_cmd); |
1223 | 1261 | ||
1224 | /** | 1262 | /** |
1225 | * iwl_add_bcast_station - add broadcast station into station table. | 1263 | * iwl_add_bcast_station - add broadcast station into station table. |
1226 | */ | 1264 | */ |
1227 | void iwl_add_bcast_station(struct iwl_priv *priv) | 1265 | int iwl_add_bcast_station(struct iwl_priv *priv) |
1228 | { | 1266 | { |
1229 | IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); | 1267 | IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); |
1230 | iwl_add_local_station(priv, iwl_bcast_addr, true); | 1268 | return iwl_add_local_station(priv, iwl_bcast_addr, true); |
1231 | } | 1269 | } |
1232 | EXPORT_SYMBOL(iwl_add_bcast_station); | 1270 | EXPORT_SYMBOL(iwl_add_bcast_station); |
1233 | 1271 | ||
1234 | /** | 1272 | /** |
1235 | * iwl3945_add_bcast_station - add broadcast station into station table. | 1273 | * iwl3945_add_bcast_station - add broadcast station into station table. |
1236 | */ | 1274 | */ |
1237 | void iwl3945_add_bcast_station(struct iwl_priv *priv) | 1275 | int iwl3945_add_bcast_station(struct iwl_priv *priv) |
1238 | { | 1276 | { |
1277 | int ret; | ||
1278 | |||
1239 | IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); | 1279 | IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); |
1240 | iwl_add_local_station(priv, iwl_bcast_addr, false); | 1280 | ret = iwl_add_local_station(priv, iwl_bcast_addr, false); |
1241 | /* | 1281 | /* |
1242 | * It is assumed that when station is added more initialization | 1282 | * It is assumed that when station is added more initialization |
1243 | * needs to be done, but for 3945 it is not the case and we can | 1283 | * needs to be done, but for 3945 it is not the case and we can |
1244 | * just release station table access right here. | 1284 | * just release station table access right here. |
1245 | */ | 1285 | */ |
1246 | priv->stations[priv->hw_params.bcast_sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; | 1286 | priv->stations[priv->hw_params.bcast_sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; |
1287 | return ret; | ||
1247 | 1288 | ||
1248 | } | 1289 | } |
1249 | EXPORT_SYMBOL(iwl3945_add_bcast_station); | 1290 | EXPORT_SYMBOL(iwl3945_add_bcast_station); |