aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEyal Shapira <eyal@wizery.com>2014-08-12 17:31:13 -0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-09-21 06:25:44 -0400
commit361dbec8acffe0201486f1750353a26d21cfff32 (patch)
tree29150fbb04ea971fc6409aef97fa589450ef6d41
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>
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/constants.h1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c131
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c41
4 files changed, 136 insertions, 40 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h
index a355788b1166..f47f4586422c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/iwlwifi/mvm/constants.h
@@ -94,5 +94,6 @@
94#define IWL_MVM_BT_COEX_MPLUT 1 94#define IWL_MVM_BT_COEX_MPLUT 1
95#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 95#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0
96#define IWL_MVM_QUOTA_THRESHOLD 8 96#define IWL_MVM_QUOTA_THRESHOLD 8
97#define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0
97 98
98#endif /* __MVM_CONSTANTS_H */ 99#endif /* __MVM_CONSTANTS_H */
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index c913d5e80c9d..7d0194bccdd6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -989,6 +989,9 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm,
989 struct iwl_mvm_frame_stats *stats, 989 struct iwl_mvm_frame_stats *stats,
990 u32 rate, bool agg); 990 u32 rate, bool agg);
991int rs_pretty_print_rate(char *buf, const u32 rate); 991int rs_pretty_print_rate(char *buf, const u32 rate);
992void rs_update_last_rssi(struct iwl_mvm *mvm,
993 struct iwl_lq_sta *lq_sta,
994 struct ieee80211_rx_status *rx_status);
992 995
993/* power management */ 996/* power management */
994int iwl_mvm_power_update_device(struct iwl_mvm *mvm); 997int iwl_mvm_power_update_device(struct iwl_mvm *mvm);
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:
2288 lq_sta->last_txrate_idx = index; 2288 lq_sta->last_txrate_idx = index;
2289} 2289}
2290 2290
2291struct rs_init_rate_info {
2292 s8 rssi;
2293 u8 rate_idx;
2294};
2295
2296static const struct rs_init_rate_info rs_init_rates_24ghz[] = {
2297 { -60, IWL_RATE_54M_INDEX },
2298 { -64, IWL_RATE_48M_INDEX },
2299 { -68, IWL_RATE_36M_INDEX },
2300 { -80, IWL_RATE_24M_INDEX },
2301 { -84, IWL_RATE_18M_INDEX },
2302 { -85, IWL_RATE_12M_INDEX },
2303 { -86, IWL_RATE_11M_INDEX },
2304 { -88, IWL_RATE_5M_INDEX },
2305 { -90, IWL_RATE_2M_INDEX },
2306 { S8_MIN, IWL_RATE_1M_INDEX },
2307};
2308
2309static const struct rs_init_rate_info rs_init_rates_5ghz[] = {
2310 { -60, IWL_RATE_54M_INDEX },
2311 { -64, IWL_RATE_48M_INDEX },
2312 { -72, IWL_RATE_36M_INDEX },
2313 { -80, IWL_RATE_24M_INDEX },
2314 { -84, IWL_RATE_18M_INDEX },
2315 { -85, IWL_RATE_12M_INDEX },
2316 { -87, IWL_RATE_9M_INDEX },
2317 { S8_MIN, IWL_RATE_6M_INDEX },
2318};
2319
2320/* Choose an initial legacy rate and antenna to use based on the RSSI
2321 * of last Rx
2322 */
2323static void rs_get_initial_rate(struct iwl_mvm *mvm,
2324 struct iwl_lq_sta *lq_sta,
2325 enum ieee80211_band band,
2326 struct rs_rate *rate)
2327{
2328 int i, nentries;
2329 s8 best_rssi = S8_MIN;
2330 u8 best_ant = ANT_NONE;
2331 u8 valid_tx_ant = mvm->fw->valid_tx_ant;
2332 const struct rs_init_rate_info *initial_rates;
2333
2334 for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) {
2335 if (!(lq_sta->pers.chains & BIT(i)))
2336 continue;
2337
2338 if (lq_sta->pers.chain_signal[i] > best_rssi) {
2339 best_rssi = lq_sta->pers.chain_signal[i];
2340 best_ant = BIT(i);
2341 }
2342 }
2343
2344 IWL_DEBUG_RATE(mvm, "Best ANT: %s Best RSSI: %d\n",
2345 rs_pretty_ant(best_ant), best_rssi);
2346
2347 if (best_ant != ANT_A && best_ant != ANT_B)
2348 rate->ant = first_antenna(valid_tx_ant);
2349 else
2350 rate->ant = best_ant;
2351
2352 rate->sgi = false;
2353 rate->ldpc = false;
2354 rate->bw = RATE_MCS_CHAN_WIDTH_20;
2355
2356 rate->index = find_first_bit(&lq_sta->active_legacy_rate,
2357 BITS_PER_LONG);
2358
2359 if (band == IEEE80211_BAND_5GHZ) {
2360 rate->type = LQ_LEGACY_A;
2361 initial_rates = rs_init_rates_5ghz;
2362 nentries = ARRAY_SIZE(rs_init_rates_5ghz);
2363 } else {
2364 rate->type = LQ_LEGACY_G;
2365 initial_rates = rs_init_rates_24ghz;
2366 nentries = ARRAY_SIZE(rs_init_rates_24ghz);
2367 }
2368
2369 if (IWL_MVM_RS_RSSI_BASED_INIT_RATE) {
2370 for (i = 0; i < nentries; i++) {
2371 int rate_idx = initial_rates[i].rate_idx;
2372 if ((best_rssi >= initial_rates[i].rssi) &&
2373 (BIT(rate_idx) & lq_sta->active_legacy_rate)) {
2374 rate->index = rate_idx;
2375 break;
2376 }
2377 }
2378 }
2379
2380 IWL_DEBUG_RATE(mvm, "rate_idx %d ANT %s\n", rate->index,
2381 rs_pretty_ant(rate->ant));
2382}
2383
2384/* Save info about RSSI of last Rx */
2385void rs_update_last_rssi(struct iwl_mvm *mvm,
2386 struct iwl_lq_sta *lq_sta,
2387 struct ieee80211_rx_status *rx_status)
2388{
2389 lq_sta->pers.chains = rx_status->chains;
2390 lq_sta->pers.chain_signal[0] = rx_status->chain_signal[0];
2391 lq_sta->pers.chain_signal[1] = rx_status->chain_signal[1];
2392 lq_sta->pers.chain_signal[2] = rx_status->chain_signal[2];
2393}
2394
2291/** 2395/**
2292 * rs_initialize_lq - Initialize a station's hardware rate table 2396 * rs_initialize_lq - Initialize a station's hardware rate table
2293 * 2397 *
@@ -2310,17 +2414,11 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
2310{ 2414{
2311 struct iwl_scale_tbl_info *tbl; 2415 struct iwl_scale_tbl_info *tbl;
2312 struct rs_rate *rate; 2416 struct rs_rate *rate;
2313 int i;
2314 u8 active_tbl = 0; 2417 u8 active_tbl = 0;
2315 u8 valid_tx_ant;
2316 2418
2317 if (!sta || !lq_sta) 2419 if (!sta || !lq_sta)
2318 return; 2420 return;
2319 2421
2320 i = lq_sta->last_txrate_idx;
2321
2322 valid_tx_ant = mvm->fw->valid_tx_ant;
2323
2324 if (!lq_sta->search_better_tbl) 2422 if (!lq_sta->search_better_tbl)
2325 active_tbl = lq_sta->active_tbl; 2423 active_tbl = lq_sta->active_tbl;
2326 else 2424 else
@@ -2329,18 +2427,8 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
2329 tbl = &(lq_sta->lq_info[active_tbl]); 2427 tbl = &(lq_sta->lq_info[active_tbl]);
2330 rate = &tbl->rate; 2428 rate = &tbl->rate;
2331 2429
2332 if ((i < 0) || (i >= IWL_RATE_COUNT)) 2430 rs_get_initial_rate(mvm, lq_sta, band, rate);
2333 i = 0; 2431 lq_sta->last_txrate_idx = rate->index;
2334
2335 rate->index = i;
2336 rate->ant = first_antenna(valid_tx_ant);
2337 rate->sgi = false;
2338 rate->ldpc = false;
2339 rate->bw = RATE_MCS_CHAN_WIDTH_20;
2340 if (band == IEEE80211_BAND_5GHZ)
2341 rate->type = LQ_LEGACY_A;
2342 else
2343 rate->type = LQ_LEGACY_G;
2344 2432
2345 WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B); 2433 WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B);
2346 if (rate->ant == ANT_A) 2434 if (rate->ant == ANT_A)
@@ -2397,6 +2485,8 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,
2397 lq_sta->pers.dbg_fixed_rate = 0; 2485 lq_sta->pers.dbg_fixed_rate = 0;
2398 lq_sta->pers.dbg_fixed_txp_reduction = TPC_INVALID; 2486 lq_sta->pers.dbg_fixed_txp_reduction = TPC_INVALID;
2399#endif 2487#endif
2488 lq_sta->pers.chains = 0;
2489 memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal));
2400 2490
2401 return &sta_priv->lq_sta; 2491 return &sta_priv->lq_sta;
2402} 2492}
@@ -2630,11 +2720,6 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
2630 2720
2631 /* as default allow aggregation for all tids */ 2721 /* as default allow aggregation for all tids */
2632 lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; 2722 lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
2633
2634 /* Set last_txrate_idx to lowest rate */
2635 lq_sta->last_txrate_idx = rate_lowest_index(sband, sta);
2636 if (sband->band == IEEE80211_BAND_5GHZ)
2637 lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
2638 lq_sta->is_agg = 0; 2723 lq_sta->is_agg = 0;
2639#ifdef CONFIG_IWLWIFI_DEBUGFS 2724#ifdef CONFIG_IWLWIFI_DEBUGFS
2640 iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats); 2725 iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats);
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index a6cb84ed653f..3cf40f3f58ec 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -246,6 +246,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
246 struct iwl_rx_packet *pkt = rxb_addr(rxb); 246 struct iwl_rx_packet *pkt = rxb_addr(rxb);
247 struct iwl_rx_phy_info *phy_info; 247 struct iwl_rx_phy_info *phy_info;
248 struct iwl_rx_mpdu_res_start *rx_res; 248 struct iwl_rx_mpdu_res_start *rx_res;
249 struct ieee80211_sta *sta;
249 u32 len; 250 u32 len;
250 u32 ampdu_status; 251 u32 ampdu_status;
251 u32 rate_n_flags; 252 u32 rate_n_flags;
@@ -261,23 +262,6 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
261 memset(&rx_status, 0, sizeof(rx_status)); 262 memset(&rx_status, 0, sizeof(rx_status));
262 263
263 /* 264 /*
264 * We have tx blocked stations (with CS bit). If we heard frames from
265 * a blocked station on a new channel we can TX to it again.
266 */
267 if (unlikely(mvm->csa_tx_block_bcn_timeout)) {
268 struct ieee80211_sta *sta;
269
270 rcu_read_lock();
271
272 sta = ieee80211_find_sta(
273 rcu_dereference(mvm->csa_tx_blocked_vif), hdr->addr2);
274 if (sta)
275 iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
276
277 rcu_read_unlock();
278 }
279
280 /*
281 * drop the packet if it has failed being decrypted by HW 265 * drop the packet if it has failed being decrypted by HW
282 */ 266 */
283 if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, &rx_status, rx_pkt_status)) { 267 if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, &rx_status, rx_pkt_status)) {
@@ -325,6 +309,29 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
325 IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal, 309 IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status.signal,
326 (unsigned long long)rx_status.mactime); 310 (unsigned long long)rx_status.mactime);
327 311
312 rcu_read_lock();
313 /*
314 * We have tx blocked stations (with CS bit). If we heard frames from
315 * a blocked station on a new channel we can TX to it again.
316 */
317 if (unlikely(mvm->csa_tx_block_bcn_timeout)) {
318 sta = ieee80211_find_sta(
319 rcu_dereference(mvm->csa_tx_blocked_vif), hdr->addr2);
320 if (sta)
321 iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
322 }
323
324 /* This is fine since we don't support multiple AP interfaces */
325 sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL);
326 if (sta) {
327 struct iwl_mvm_sta *mvmsta;
328 mvmsta = iwl_mvm_sta_from_mac80211(sta);
329 rs_update_last_rssi(mvm, &mvmsta->lq_sta,
330 &rx_status);
331 }
332
333 rcu_read_unlock();
334
328 /* set the preamble flag if appropriate */ 335 /* set the preamble flag if appropriate */
329 if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE)) 336 if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE))
330 rx_status.flag |= RX_FLAG_SHORTPRE; 337 rx_status.flag |= RX_FLAG_SHORTPRE;