aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-sta.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sta.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c91
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 db934476b5e..5c6b3262baf 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}
419EXPORT_SYMBOL(iwl_add_station_common); 419EXPORT_SYMBOL(iwl_add_station_common);
420 420
421static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap) 421static 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}
502EXPORT_SYMBOL(iwl_add_local_station); 523EXPORT_SYMBOL(iwl_add_local_station);
@@ -509,7 +530,8 @@ EXPORT_SYMBOL(iwl_add_local_station);
509static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id) 530static 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}
1222EXPORT_SYMBOL(iwl_send_lq_cmd); 1260EXPORT_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 */
1227void iwl_add_bcast_station(struct iwl_priv *priv) 1265int 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}
1232EXPORT_SYMBOL(iwl_add_bcast_station); 1270EXPORT_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 */
1237void iwl3945_add_bcast_station(struct iwl_priv *priv) 1275int 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}
1249EXPORT_SYMBOL(iwl3945_add_bcast_station); 1290EXPORT_SYMBOL(iwl3945_add_bcast_station);