summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/iwlwifi/mvm/rs.c
diff options
context:
space:
mode:
authorEyal Shapira <eyal@wizery.com>2014-08-13 00:31:13 +0300
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-09-21 13:25:44 +0300
commit361dbec8acffe0201486f1750353a26d21cfff32 (patch)
tree29150fbb04ea971fc6409aef97fa589450ef6d41 /drivers/net/wireless/iwlwifi/mvm/rs.c
parent59ecb1283fde3da7b40803067ee9ef91cd8eadc2 (diff)
iwlwifi: mvm: choose an initial tx rate based on rssi conditions
Improve the initial tx rate and antenna selection to be based on the rssi of the last rx. This avoids starting at the lowest legacy rate always and requiring more tx traffic to "climb" up the rates. Since this option might cause trouble in certain setups, allow to disable it by default. Signed-off-by: Eyal Shapira <eyalx.shapira@intel.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/rs.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c131
1 files changed, 108 insertions, 23 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index f77dfe4df074..d179a8eb50df 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -2288,6 +2288,110 @@ out:
lq_sta->last_txrate_idx = index;
}
+struct rs_init_rate_info {
+ s8 rssi;
+ u8 rate_idx;
+};
+
+static const struct rs_init_rate_info rs_init_rates_24ghz[] = {
+ { -60, IWL_RATE_54M_INDEX },
+ { -64, IWL_RATE_48M_INDEX },
+ { -68, IWL_RATE_36M_INDEX },
+ { -80, IWL_RATE_24M_INDEX },
+ { -84, IWL_RATE_18M_INDEX },
+ { -85, IWL_RATE_12M_INDEX },
+ { -86, IWL_RATE_11M_INDEX },
+ { -88, IWL_RATE_5M_INDEX },
+ { -90, IWL_RATE_2M_INDEX },
+ { S8_MIN, IWL_RATE_1M_INDEX },
+};
+
+static const struct rs_init_rate_info rs_init_rates_5ghz[] = {
+ { -60, IWL_RATE_54M_INDEX },
+ { -64, IWL_RATE_48M_INDEX },
+ { -72, IWL_RATE_36M_INDEX },
+ { -80, IWL_RATE_24M_INDEX },
+ { -84, IWL_RATE_18M_INDEX },
+ { -85, IWL_RATE_12M_INDEX },
+ { -87, IWL_RATE_9M_INDEX },
+ { S8_MIN, IWL_RATE_6M_INDEX },
+};
+
+/* Choose an initial legacy rate and antenna to use based on the RSSI
+ * of last Rx
+ */
+static void rs_get_initial_rate(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ enum ieee80211_band band,
+ struct rs_rate *rate)
+{
+ int i, nentries;
+ s8 best_rssi = S8_MIN;
+ u8 best_ant = ANT_NONE;
+ u8 valid_tx_ant = mvm->fw->valid_tx_ant;
+ const struct rs_init_rate_info *initial_rates;
+
+ for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) {
+ if (!(lq_sta->pers.chains & BIT(i)))
+ continue;
+
+ if (lq_sta->pers.chain_signal[i] > best_rssi) {
+ best_rssi = lq_sta->pers.chain_signal[i];
+ best_ant = BIT(i);
+ }
+ }
+
+ IWL_DEBUG_RATE(mvm, "Best ANT: %s Best RSSI: %d\n",
+ rs_pretty_ant(best_ant), best_rssi);
+
+ if (best_ant != ANT_A && best_ant != ANT_B)
+ rate->ant = first_antenna(valid_tx_ant);
+ else
+ rate->ant = best_ant;
+
+ rate->sgi = false;
+ rate->ldpc = false;
+ rate->bw = RATE_MCS_CHAN_WIDTH_20;
+
+ rate->index = find_first_bit(&lq_sta->active_legacy_rate,
+ BITS_PER_LONG);
+
+ if (band == IEEE80211_BAND_5GHZ) {
+ rate->type = LQ_LEGACY_A;
+ initial_rates = rs_init_rates_5ghz;
+ nentries = ARRAY_SIZE(rs_init_rates_5ghz);
+ } else {
+ rate->type = LQ_LEGACY_G;
+ initial_rates = rs_init_rates_24ghz;
+ nentries = ARRAY_SIZE(rs_init_rates_24ghz);
+ }
+
+ if (IWL_MVM_RS_RSSI_BASED_INIT_RATE) {
+ for (i = 0; i < nentries; i++) {
+ int rate_idx = initial_rates[i].rate_idx;
+ if ((best_rssi >= initial_rates[i].rssi) &&
+ (BIT(rate_idx) & lq_sta->active_legacy_rate)) {
+ rate->index = rate_idx;
+ break;
+ }
+ }
+ }
+
+ IWL_DEBUG_RATE(mvm, "rate_idx %d ANT %s\n", rate->index,
+ rs_pretty_ant(rate->ant));
+}
+
+/* Save info about RSSI of last Rx */
+void rs_update_last_rssi(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_rx_status *rx_status)
+{
+ lq_sta->pers.chains = rx_status->chains;
+ lq_sta->pers.chain_signal[0] = rx_status->chain_signal[0];
+ lq_sta->pers.chain_signal[1] = rx_status->chain_signal[1];
+ lq_sta->pers.chain_signal[2] = rx_status->chain_signal[2];
+}
+
/**
* rs_initialize_lq - Initialize a station's hardware rate table
*
@@ -2310,17 +2414,11 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
{
struct iwl_scale_tbl_info *tbl;
struct rs_rate *rate;
- int i;
u8 active_tbl = 0;
- u8 valid_tx_ant;
if (!sta || !lq_sta)
return;
- i = lq_sta->last_txrate_idx;
-
- valid_tx_ant = mvm->fw->valid_tx_ant;
-
if (!lq_sta->search_better_tbl)
active_tbl = lq_sta->active_tbl;
else
@@ -2329,18 +2427,8 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
tbl = &(lq_sta->lq_info[active_tbl]);
rate = &tbl->rate;
- if ((i < 0) || (i >= IWL_RATE_COUNT))
- i = 0;
-
- rate->index = i;
- rate->ant = first_antenna(valid_tx_ant);
- rate->sgi = false;
- rate->ldpc = false;
- rate->bw = RATE_MCS_CHAN_WIDTH_20;
- if (band == IEEE80211_BAND_5GHZ)
- rate->type = LQ_LEGACY_A;
- else
- rate->type = LQ_LEGACY_G;
+ rs_get_initial_rate(mvm, lq_sta, band, rate);
+ lq_sta->last_txrate_idx = rate->index;
WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B);
if (rate->ant == ANT_A)
@@ -2397,6 +2485,8 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,
lq_sta->pers.dbg_fixed_rate = 0;
lq_sta->pers.dbg_fixed_txp_reduction = TPC_INVALID;
#endif
+ lq_sta->pers.chains = 0;
+ memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal));
return &sta_priv->lq_sta;
}
@@ -2630,11 +2720,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
/* as default allow aggregation for all tids */
lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
-
- /* Set last_txrate_idx to lowest rate */
- lq_sta->last_txrate_idx = rate_lowest_index(sband, sta);
- if (sband->band == IEEE80211_BAND_5GHZ)
- lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
lq_sta->is_agg = 0;
#ifdef CONFIG_IWLWIFI_DEBUGFS
iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats);