aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/rc80211_minstrel_ht.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/rc80211_minstrel_ht.c')
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c177
1 files changed, 145 insertions, 32 deletions
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 5bb316aff21a..3af141c69712 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org> 2 * Copyright (C) 2010-2013 Felix Fietkau <nbd@openwrt.org>
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -63,6 +63,30 @@
63 } \ 63 } \
64} 64}
65 65
66#define CCK_DURATION(_bitrate, _short, _len) \
67 (10 /* SIFS */ + \
68 (_short ? 72 + 24 : 144 + 48 ) + \
69 (8 * (_len + 4) * 10) / (_bitrate))
70
71#define CCK_ACK_DURATION(_bitrate, _short) \
72 (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \
73 CCK_DURATION(_bitrate, _short, AVG_PKT_SIZE))
74
75#define CCK_DURATION_LIST(_short) \
76 CCK_ACK_DURATION(10, _short), \
77 CCK_ACK_DURATION(20, _short), \
78 CCK_ACK_DURATION(55, _short), \
79 CCK_ACK_DURATION(110, _short)
80
81#define CCK_GROUP \
82 [MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS] = { \
83 .streams = 0, \
84 .duration = { \
85 CCK_DURATION_LIST(false), \
86 CCK_DURATION_LIST(true) \
87 } \
88 }
89
66/* 90/*
67 * To enable sufficiently targeted rate sampling, MCS rates are divided into 91 * To enable sufficiently targeted rate sampling, MCS rates are divided into
68 * groups, based on the number of streams and flags (HT40, SGI) that they 92 * groups, based on the number of streams and flags (HT40, SGI) that they
@@ -95,8 +119,13 @@ const struct mcs_group minstrel_mcs_groups[] = {
95#if MINSTREL_MAX_STREAMS >= 3 119#if MINSTREL_MAX_STREAMS >= 3
96 MCS_GROUP(3, 1, 1), 120 MCS_GROUP(3, 1, 1),
97#endif 121#endif
122
123 /* must be last */
124 CCK_GROUP
98}; 125};
99 126
127#define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1)
128
100static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; 129static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
101 130
102/* 131/*
@@ -119,6 +148,29 @@ minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
119 !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); 148 !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
120} 149}
121 150
151static struct minstrel_rate_stats *
152minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
153 struct ieee80211_tx_rate *rate)
154{
155 int group, idx;
156
157 if (rate->flags & IEEE80211_TX_RC_MCS) {
158 group = minstrel_ht_get_group_idx(rate);
159 idx = rate->idx % MCS_GROUP_RATES;
160 } else {
161 group = MINSTREL_CCK_GROUP;
162
163 for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++)
164 if (rate->idx == mp->cck_rates[idx])
165 break;
166
167 /* short preamble */
168 if (!(mi->groups[group].supported & BIT(idx)))
169 idx += 4;
170 }
171 return &mi->groups[group].rates[idx];
172}
173
122static inline struct minstrel_rate_stats * 174static inline struct minstrel_rate_stats *
123minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) 175minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
124{ 176{
@@ -159,7 +211,7 @@ static void
159minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) 211minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
160{ 212{
161 struct minstrel_rate_stats *mr; 213 struct minstrel_rate_stats *mr;
162 unsigned int usecs; 214 unsigned int usecs = 0;
163 215
164 mr = &mi->groups[group].rates[rate]; 216 mr = &mi->groups[group].rates[rate];
165 217
@@ -168,7 +220,9 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
168 return; 220 return;
169 } 221 }
170 222
171 usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); 223 if (group != MINSTREL_CCK_GROUP)
224 usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
225
172 usecs += minstrel_mcs_groups[group].duration[rate]; 226 usecs += minstrel_mcs_groups[group].duration[rate];
173 mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability); 227 mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability);
174} 228}
@@ -293,7 +347,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
293} 347}
294 348
295static bool 349static bool
296minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) 350minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rate)
297{ 351{
298 if (rate->idx < 0) 352 if (rate->idx < 0)
299 return false; 353 return false;
@@ -301,7 +355,13 @@ minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate)
301 if (!rate->count) 355 if (!rate->count)
302 return false; 356 return false;
303 357
304 return !!(rate->flags & IEEE80211_TX_RC_MCS); 358 if (rate->flags & IEEE80211_TX_RC_MCS)
359 return true;
360
361 return rate->idx == mp->cck_rates[0] ||
362 rate->idx == mp->cck_rates[1] ||
363 rate->idx == mp->cck_rates[2] ||
364 rate->idx == mp->cck_rates[3];
305} 365}
306 366
307static void 367static void
@@ -386,7 +446,6 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
386 struct minstrel_rate_stats *rate, *rate2; 446 struct minstrel_rate_stats *rate, *rate2;
387 struct minstrel_priv *mp = priv; 447 struct minstrel_priv *mp = priv;
388 bool last; 448 bool last;
389 int group;
390 int i; 449 int i;
391 450
392 if (!msp->is_ht) 451 if (!msp->is_ht)
@@ -415,13 +474,12 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
415 if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) 474 if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
416 mi->sample_packets += info->status.ampdu_len; 475 mi->sample_packets += info->status.ampdu_len;
417 476
418 last = !minstrel_ht_txstat_valid(&ar[0]); 477 last = !minstrel_ht_txstat_valid(mp, &ar[0]);
419 for (i = 0; !last; i++) { 478 for (i = 0; !last; i++) {
420 last = (i == IEEE80211_TX_MAX_RATES - 1) || 479 last = (i == IEEE80211_TX_MAX_RATES - 1) ||
421 !minstrel_ht_txstat_valid(&ar[i + 1]); 480 !minstrel_ht_txstat_valid(mp, &ar[i + 1]);
422 481
423 group = minstrel_ht_get_group_idx(&ar[i]); 482 rate = minstrel_ht_get_stats(mp, mi, &ar[i]);
424 rate = &mi->groups[group].rates[ar[i].idx % 8];
425 483
426 if (last) 484 if (last)
427 rate->success += info->status.ampdu_ack_len; 485 rate->success += info->status.ampdu_ack_len;
@@ -447,7 +505,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
447 505
448 if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { 506 if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
449 minstrel_ht_update_stats(mp, mi); 507 minstrel_ht_update_stats(mp, mi);
450 if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) 508 if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
509 mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
451 minstrel_aggr_check(sta, skb); 510 minstrel_aggr_check(sta, skb);
452 } 511 }
453} 512}
@@ -463,6 +522,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
463 unsigned int ctime = 0; 522 unsigned int ctime = 0;
464 unsigned int t_slot = 9; /* FIXME */ 523 unsigned int t_slot = 9; /* FIXME */
465 unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); 524 unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len);
525 unsigned int overhead = 0, overhead_rtscts = 0;
466 526
467 mr = minstrel_get_ratestats(mi, index); 527 mr = minstrel_get_ratestats(mi, index);
468 if (mr->probability < MINSTREL_FRAC(1, 10)) { 528 if (mr->probability < MINSTREL_FRAC(1, 10)) {
@@ -484,9 +544,14 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
484 ctime += (t_slot * cw) >> 1; 544 ctime += (t_slot * cw) >> 1;
485 cw = min((cw << 1) | 1, mp->cw_max); 545 cw = min((cw << 1) | 1, mp->cw_max);
486 546
547 if (index / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) {
548 overhead = mi->overhead;
549 overhead_rtscts = mi->overhead_rtscts;
550 }
551
487 /* Total TX time for data and Contention after first 2 tries */ 552 /* Total TX time for data and Contention after first 2 tries */
488 tx_time = ctime + 2 * (mi->overhead + tx_time_data); 553 tx_time = ctime + 2 * (overhead + tx_time_data);
489 tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data); 554 tx_time_rtscts = ctime + 2 * (overhead_rtscts + tx_time_data);
490 555
491 /* See how many more tries we can fit inside segment size */ 556 /* See how many more tries we can fit inside segment size */
492 do { 557 do {
@@ -495,8 +560,8 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
495 cw = min((cw << 1) | 1, mp->cw_max); 560 cw = min((cw << 1) | 1, mp->cw_max);
496 561
497 /* Total TX time after this try */ 562 /* Total TX time after this try */
498 tx_time += ctime + mi->overhead + tx_time_data; 563 tx_time += ctime + overhead + tx_time_data;
499 tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data; 564 tx_time_rtscts += ctime + overhead_rtscts + tx_time_data;
500 565
501 if (tx_time_rtscts < mp->segment_size) 566 if (tx_time_rtscts < mp->segment_size)
502 mr->retry_count_rtscts++; 567 mr->retry_count_rtscts++;
@@ -526,9 +591,16 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
526 else 591 else
527 rate->count = mr->retry_count; 592 rate->count = mr->retry_count;
528 593
529 rate->flags = IEEE80211_TX_RC_MCS | group->flags; 594 rate->flags = 0;
530 if (rtscts) 595 if (rtscts)
531 rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; 596 rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
597
598 if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
599 rate->idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
600 return;
601 }
602
603 rate->flags |= IEEE80211_TX_RC_MCS | group->flags;
532 rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES; 604 rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES;
533} 605}
534 606
@@ -592,6 +664,22 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
592} 664}
593 665
594static void 666static void
667minstrel_ht_check_cck_shortpreamble(struct minstrel_priv *mp,
668 struct minstrel_ht_sta *mi, bool val)
669{
670 u8 supported = mi->groups[MINSTREL_CCK_GROUP].supported;
671
672 if (!supported || !mi->cck_supported_short)
673 return;
674
675 if (supported & (mi->cck_supported_short << (val * 4)))
676 return;
677
678 supported ^= mi->cck_supported_short | (mi->cck_supported_short << 4);
679 mi->groups[MINSTREL_CCK_GROUP].supported = supported;
680}
681
682static void
595minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, 683minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
596 struct ieee80211_tx_rate_control *txrc) 684 struct ieee80211_tx_rate_control *txrc)
597{ 685{
@@ -610,6 +698,7 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
610 return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); 698 return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
611 699
612 info->flags |= mi->tx_flags; 700 info->flags |= mi->tx_flags;
701 minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
613 702
614 /* Don't use EAPOL frames for sampling on non-mrr hw */ 703 /* Don't use EAPOL frames for sampling on non-mrr hw */
615 if (mp->hw->max_rates == 1 && 704 if (mp->hw->max_rates == 1 &&
@@ -683,6 +772,30 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
683} 772}
684 773
685static void 774static void
775minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
776 struct ieee80211_supported_band *sband,
777 struct ieee80211_sta *sta)
778{
779 int i;
780
781 if (sband->band != IEEE80211_BAND_2GHZ)
782 return;
783
784 mi->cck_supported = 0;
785 mi->cck_supported_short = 0;
786 for (i = 0; i < 4; i++) {
787 if (!rate_supported(sta, sband->band, mp->cck_rates[i]))
788 continue;
789
790 mi->cck_supported |= BIT(i);
791 if (sband->bitrates[i].flags & IEEE80211_RATE_SHORT_PREAMBLE)
792 mi->cck_supported_short |= BIT(i);
793 }
794
795 mi->groups[MINSTREL_CCK_GROUP].supported = mi->cck_supported;
796}
797
798static void
686minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, 799minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
687 struct ieee80211_sta *sta, void *priv_sta) 800 struct ieee80211_sta *sta, void *priv_sta)
688{ 801{
@@ -695,14 +808,13 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
695 int ack_dur; 808 int ack_dur;
696 int stbc; 809 int stbc;
697 int i; 810 int i;
698 unsigned int smps;
699 811
700 /* fall back to the old minstrel for legacy stations */ 812 /* fall back to the old minstrel for legacy stations */
701 if (!sta->ht_cap.ht_supported) 813 if (!sta->ht_cap.ht_supported)
702 goto use_legacy; 814 goto use_legacy;
703 815
704 BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != 816 BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) !=
705 MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS); 817 MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1);
706 818
707 msp->is_ht = true; 819 msp->is_ht = true;
708 memset(mi, 0, sizeof(*mi)); 820 memset(mi, 0, sizeof(*mi));
@@ -731,28 +843,29 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
731 if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) 843 if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
732 mi->tx_flags |= IEEE80211_TX_CTL_LDPC; 844 mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
733 845
734 smps = (sta_cap & IEEE80211_HT_CAP_SM_PS) >>
735 IEEE80211_HT_CAP_SM_PS_SHIFT;
736
737 for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { 846 for (i = 0; i < ARRAY_SIZE(mi->groups); i++) {
738 u16 req = 0;
739
740 mi->groups[i].supported = 0; 847 mi->groups[i].supported = 0;
741 if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { 848 if (i == MINSTREL_CCK_GROUP) {
742 if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 849 minstrel_ht_update_cck(mp, mi, sband, sta);
743 req |= IEEE80211_HT_CAP_SGI_40; 850 continue;
744 else
745 req |= IEEE80211_HT_CAP_SGI_20;
746 } 851 }
747 852
748 if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) 853 if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) {
749 req |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; 854 if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
855 if (!(sta_cap & IEEE80211_HT_CAP_SGI_40))
856 continue;
857 } else {
858 if (!(sta_cap & IEEE80211_HT_CAP_SGI_20))
859 continue;
860 }
861 }
750 862
751 if ((sta_cap & req) != req) 863 if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH &&
864 sta->bandwidth < IEEE80211_STA_RX_BW_40)
752 continue; 865 continue;
753 866
754 /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ 867 /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */
755 if (smps == WLAN_HT_CAP_SM_PS_STATIC && 868 if (sta->smps_mode == IEEE80211_SMPS_STATIC &&
756 minstrel_mcs_groups[i].streams > 1) 869 minstrel_mcs_groups[i].streams > 1)
757 continue; 870 continue;
758 871