diff options
Diffstat (limited to 'net/mac80211/rc80211_minstrel_ht.c')
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.c | 177 |
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 | |||
100 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES]; | 129 | static 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 | ||
151 | static struct minstrel_rate_stats * | ||
152 | minstrel_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 | |||
122 | static inline struct minstrel_rate_stats * | 174 | static inline struct minstrel_rate_stats * |
123 | minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) | 175 | minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) |
124 | { | 176 | { |
@@ -159,7 +211,7 @@ static void | |||
159 | minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | 211 | minstrel_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 | ||
295 | static bool | 349 | static bool |
296 | minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate) | 350 | minstrel_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 | ||
307 | static void | 367 | static 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 | ||
594 | static void | 666 | static void |
667 | minstrel_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 | |||
682 | static void | ||
595 | minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | 683 | minstrel_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 | ||
685 | static void | 774 | static void |
775 | minstrel_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 | |||
798 | static void | ||
686 | minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | 799 | minstrel_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 | ||