X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/fa28364d938334a52cd54d4c4599dc3e1cf8247e..1b8ec058f81b3778ab74492f0b8773286880a338:/package/mac80211/patches/560-minstrel_ht.patch diff --git a/package/mac80211/patches/560-minstrel_ht.patch b/package/mac80211/patches/560-minstrel_ht.patch index 15ff3e6d7..c51d541fb 100644 --- a/package/mac80211/patches/560-minstrel_ht.patch +++ b/package/mac80211/patches/560-minstrel_ht.patch @@ -68,7 +68,7 @@ --- /dev/null +++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -0,0 +1,824 @@ +@@ -0,0 +1,815 @@ +/* + * Copyright (C) 2010 Felix Fietkau + * @@ -125,9 +125,6 @@ + } \ +} + -+#define MINSTREL_INTFL_SAMPLE_SLOT0 BIT(30) -+#define MINSTREL_INTFL_SAMPLE_SLOT1 BIT(31) -+ +/* + * To enable sufficiently targeted rate sampling, MCS rates are divided into + * groups, based on the number of streams and flags (HT40, SGI) that they @@ -206,7 +203,8 @@ +static void +minstrel_calc_rate_ewma(struct minstrel_priv *mp, struct minstrel_rate_stats *mr) +{ -+ if (mr->attempts) { ++ if (unlikely(mr->attempts > 0)) { ++ mr->sample_skipped = 0; + mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts); + if (!mr->att_hist) + mr->probability = mr->cur_prob; @@ -215,6 +213,8 @@ + mr->cur_prob, EWMA_LEVEL); + mr->att_hist += mr->attempts; + mr->succ_hist += mr->success; ++ } else { ++ mr->sample_skipped++; + } + mr->last_success = mr->success; + mr->last_attempts = mr->attempts; @@ -262,6 +262,15 @@ + int cur_prob, cur_prob_tp, cur_tp, cur_tp2; + int group, i, index; + ++ if (mi->ampdu_packets > 0) { ++ mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, ++ MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), EWMA_LEVEL); ++ mi->ampdu_len = 0; ++ mi->ampdu_packets = 0; ++ } ++ ++ mi->sample_slow = 0; ++ mi->sample_count = 0; + mi->max_tp_rate = 0; + mi->max_tp_rate2 = 0; + mi->max_prob_rate = 0; @@ -279,6 +288,7 @@ + mg->max_tp_rate = 0; + mg->max_tp_rate2 = 0; + mg->max_prob_rate = 0; ++ mi->sample_count++; + + for (i = 0; i < MCS_GROUP_RATES; i++) { + if (!(mg->supported & BIT(i))) @@ -309,7 +319,7 @@ + mr = minstrel_get_ratestats(mi, index); + } + -+ if (index == mg->max_tp_rate) ++ if (index >= mg->max_tp_rate) + continue; + + if (mr->cur_tp > cur_tp2) { @@ -319,6 +329,9 @@ + } + } + ++ /* try to sample up to half of the availble rates during each interval */ ++ mi->sample_count *= 4; ++ + cur_prob = 0; + cur_prob_tp = 0; + cur_tp = 0; @@ -386,7 +399,7 @@ +} + +static void -+minstrel_downgrade_rate(struct minstrel_ht_sta *mi, int *idx, int type) ++minstrel_downgrade_rate(struct minstrel_ht_sta *mi, int *idx, bool primary) +{ + int group, orig_group; + @@ -397,22 +410,37 @@ + if (!mi->groups[group].supported) + continue; + -+ if (minstrel_mcs_groups[group].streams >= ++ if (minstrel_mcs_groups[group].streams > + minstrel_mcs_groups[orig_group].streams) + continue; + -+ switch(type) { -+ case 0: ++ if (primary) + *idx = mi->groups[group].max_tp_rate; -+ break; -+ case 1: ++ else + *idx = mi->groups[group].max_tp_rate2; -+ break; -+ } + break; + } +} + ++static void ++minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, struct sk_buff *skb) ++{ ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; ++ struct sta_info *sta = container_of(pubsta, struct sta_info, sta); ++ u16 tid; ++ ++ if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) ++ return; ++ ++ if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) ++ return; ++ ++ tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; ++ if (likely(sta->ampdu_mlme.tid_state_tx[tid] != HT_AGG_STATE_IDLE)) ++ return; ++ ++ ieee80211_start_tx_ba_session(pubsta, tid); ++} + +static void +minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, @@ -442,8 +470,19 @@ + info->status.ampdu_len = 1; + } + -+ mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, -+ MINSTREL_FRAC(info->status.ampdu_len, 1), 90); ++ mi->ampdu_packets++; ++ mi->ampdu_len += info->status.ampdu_len; ++ ++ if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { ++ mi->sample_wait = 4 + MINSTREL_TRUNC(mi->avg_ampdu_len); ++ mi->sample_tries = 3; ++ mi->sample_count--; ++ } ++ ++ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { ++ mi->sample_packets += info->status.ampdu_len; ++ minstrel_next_sample_idx(mi); ++ } + + for (i = 0; !last; i++) { + last = (i == IEEE80211_TX_MAX_RATES - 1) || @@ -452,14 +491,6 @@ + if (!minstrel_ht_txstat_valid(&ar[i])) + break; + -+ if ((i == 0 && (info->flags & MINSTREL_INTFL_SAMPLE_SLOT0)) || -+ (i == 1 && (info->flags & MINSTREL_INTFL_SAMPLE_SLOT1))) { -+ if (mi->sample_pending > 0) -+ mi->sample_pending--; -+ mi->sample_packets++; -+ minstrel_next_sample_idx(mi); -+ } -+ + group = minstrel_ht_get_group_idx(&ar[i]); + rate = &mi->groups[group].rates[ar[i].idx % 8]; + @@ -469,23 +500,26 @@ + rate->attempts += ar[i].count * info->status.ampdu_len; + } + -+ + /* + * check for sudden death of spatial multiplexing, + * downgrade to a lower number of streams if necessary. + */ + rate = minstrel_get_ratestats(mi, mi->max_tp_rate); -+ if (MINSTREL_FRAC(rate->success, rate->attempts) < -+ MINSTREL_FRAC(20, 100) && rate->attempts > 15) -+ minstrel_downgrade_rate(mi, &mi->max_tp_rate, 0); ++ if (rate->attempts > 30 && ++ MINSTREL_FRAC(rate->success, rate->attempts) < ++ MINSTREL_FRAC(20, 100)) ++ minstrel_downgrade_rate(mi, &mi->max_tp_rate, true); + + rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2); -+ if (MINSTREL_FRAC(rate->success, rate->attempts) < -+ MINSTREL_FRAC(20, 100) && rate->attempts > 15) -+ minstrel_downgrade_rate(mi, &mi->max_tp_rate2, 1); ++ if (rate->attempts > 30 && ++ MINSTREL_FRAC(rate->success, rate->attempts) < ++ MINSTREL_FRAC(20, 100)) ++ minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false); + -+ if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) ++ if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { + minstrel_ht_update_stats(mp, mi); ++ minstrel_aggr_check(mp, sta, skb); ++ } +} + +static void @@ -539,7 +573,9 @@ + if (!mr->retry_updated) + minstrel_calc_retransmit(mp, mi, index); + -+ if (rtscts) ++ if (mr->probability < MINSTREL_FRAC(20, 100)) ++ rate->count = 2; ++ else if (rtscts) + rate->count = mr->retry_count_rtscts; + else + rate->count = mr->retry_count; @@ -560,41 +596,21 @@ +} + +static int -+minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, -+ bool *defer) ++minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) +{ + struct minstrel_rate_stats *mr; + struct minstrel_mcs_group_data *mg; + int sample_idx = 0; -+ int sample_rate; -+ int delta; -+ -+ if (mp->has_mrr) -+ sample_rate = mp->lookaround_rate_mrr; -+ else -+ sample_rate = mp->lookaround_rate; -+ -+ delta = (mi->total_packets * sample_rate) / 100 - mi->sample_packets; -+ delta -= mi->sample_pending / 2; + -+ if (delta <= 0) ++ if (mi->sample_wait > 0) { ++ mi->sample_wait--; + return -1; -+ -+ delta -= 16; -+ if (delta > 1) { -+ /* With multi-rate retry, not every planned sample -+ * attempt actually gets used, due to the way the retry -+ * chain is set up - [max_tp,sample,prob,lowest] for -+ * sample_rate < max_tp. -+ * -+ * If there's too much sampling backlog and the link -+ * starts getting worse, minstrel would start bursting -+ * out lots of sampling frames, which would result -+ * in a large throughput loss. -+ */ -+ mi->sample_packets += delta - 1; + } + ++ if (!mi->sample_tries) ++ return -1; ++ ++ mi->sample_tries--; + mg = &mi->groups[mi->sample_group]; + sample_idx = sample_table[mg->column][mg->index]; + mr = &mg->rates[sample_idx]; @@ -605,47 +621,26 @@ + * higher than 95% to avoid wasting airtime + */ + if (!mp->has_mrr && (mr->probability > MINSTREL_FRAC(95, 100))) -+ return -1; ++ goto next; + ++ /* ++ * Make sure that lower rates get sampled only occasionally, ++ * if the link is working perfectly. ++ */ + if (minstrel_get_duration(sample_idx) > + minstrel_get_duration(mi->max_tp_rate)) { -+ /* -+ * Make sure that lower rates get sampled occasionally, even -+ * if the link is working perfectly. Some drivers such as ath9k -+ * severely limit aggregation size if the MRR chain contains low -+ * rates -+ * -+ * If the lower rate has already been tried a few times, there's -+ * no point in forcing it to be sampled again, so skip to the -+ * next sampling index after applying this one in the tx control -+ */ -+ if (mr->att_hist > 15) { -+ *defer = true; -+ minstrel_next_sample_idx(mi); -+ } ++ if (mr->sample_skipped < 10) ++ goto next; ++ ++ if (mi->sample_slow++ > 2) ++ goto next; + } + + return sample_idx; -+} + -+static void -+minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, struct sk_buff *skb) -+{ -+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; -+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta); -+ u16 tid; -+ -+ if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) -+ return; -+ -+ if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) -+ return; -+ -+ tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; -+ if (likely(sta->ampdu_mlme.tid_state_tx[tid] != HT_AGG_STATE_IDLE)) -+ return; -+ -+ ieee80211_start_tx_ba_session(pubsta, tid); ++next: ++ minstrel_next_sample_idx(mi); ++ return -1; +} + +static void @@ -657,7 +652,6 @@ + struct minstrel_ht_sta_priv *msp = priv_sta; + struct minstrel_ht_sta *mi = &msp->ht; + struct minstrel_priv *mp = priv; -+ bool sample_defer = false; + int sample_idx; + + if (rate_control_send_low(sta, priv_sta, txrc)) @@ -666,24 +660,13 @@ + if (!msp->is_ht) + return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); + -+ minstrel_aggr_check(mp, sta, txrc->skb); -+ -+ sample_idx = minstrel_get_sample_rate(mp, mi, &sample_defer); ++ sample_idx = minstrel_get_sample_rate(mp, mi); + if (sample_idx >= 0) { -+ if (sample_defer) { -+ minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, -+ txrc, false, false); -+ minstrel_ht_set_rate(mp, mi, &ar[1], sample_idx, -+ txrc, true, true); -+ info->flags |= MINSTREL_INTFL_SAMPLE_SLOT1; -+ } else { -+ minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, -+ txrc, true, false); -+ minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate, -+ txrc, false, true); -+ info->flags |= MINSTREL_INTFL_SAMPLE_SLOT0; -+ } -+ mi->sample_pending++; ++ minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, ++ txrc, true, false); ++ minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate, ++ txrc, false, true); ++ info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; + } else { + minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, + txrc, false, false); @@ -698,21 +681,58 @@ + mi->total_packets++; + + /* wraparound */ -+ if (mi->total_packets >= 100000) { ++ if (mi->total_packets == ~0) { + mi->total_packets = 0; + mi->sample_packets = 0; -+ mi->sample_pending = 0; + } +} + +static void -+minstrel_ht_update_cap(struct minstrel_ht_sta *mi, struct ieee80211_sta *sta, -+ enum nl80211_channel_type oper_chan_type) ++minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, ++ struct ieee80211_sta *sta, void *priv_sta, ++ enum nl80211_channel_type oper_chan_type) +{ ++ struct minstrel_priv *mp = priv; ++ struct minstrel_ht_sta_priv *msp = priv_sta; ++ struct minstrel_ht_sta *mi = &msp->ht; + struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; ++ struct ieee80211_local *local = hw_to_local(mp->hw); + u16 sta_cap = sta->ht_cap.cap; ++ int ack_dur; + int i; + ++ /* fall back to the old minstrel for legacy stations */ ++ if (sta && !sta->ht_cap.ht_supported) { ++ msp->is_ht = false; ++ memset(&msp->legacy, 0, sizeof(msp->legacy)); ++ msp->legacy.r = msp->ratelist; ++ msp->legacy.sample_table = msp->sample_table; ++ return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy); ++ } ++ ++ BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != ++ MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS); ++ ++ msp->is_ht = true; ++ memset(mi, 0, sizeof(*mi)); ++ mi->stats_update = jiffies; ++ ++ ack_dur = ieee80211_frame_duration(local, 10, 60, 1, 1); ++ mi->overhead = ieee80211_frame_duration(local, 0, 60, 1, 1) + ack_dur; ++ mi->overhead_rtscts = mi->overhead + 2 * ack_dur; ++ ++ mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); ++ ++ /* When using MRR, sample more on the first attempt, without delay */ ++ if (mp->has_mrr) { ++ mi->sample_count = 16; ++ mi->sample_wait = 0; ++ } else { ++ mi->sample_count = 8; ++ mi->sample_wait = 8; ++ } ++ mi->sample_tries = 4; ++ + if (oper_chan_type != NL80211_CHAN_HT40MINUS && + oper_chan_type != NL80211_CHAN_HT40PLUS) + sta_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; @@ -744,34 +764,8 @@ + struct ieee80211_sta *sta, void *priv_sta) +{ + struct minstrel_priv *mp = priv; -+ struct minstrel_ht_sta_priv *msp = priv_sta; -+ struct minstrel_ht_sta *mi = &msp->ht; -+ struct ieee80211_local *local = hw_to_local(mp->hw); -+ int ack_dur; + -+ /* fall back to the old minstrel for legacy stations */ -+ if (sta && !sta->ht_cap.ht_supported) { -+ msp->is_ht = false; -+ memset(&msp->legacy, 0, sizeof(msp->legacy)); -+ msp->legacy.r = msp->ratelist; -+ msp->legacy.sample_table = msp->sample_table; -+ return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy); -+ } -+ -+ BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != -+ MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS); -+ -+ msp->is_ht = true; -+ memset(mi, 0, sizeof(*mi)); -+ mi->stats_update = jiffies; -+ -+ ack_dur = ieee80211_frame_duration(local, 10, 60, 1, 1); -+ mi->overhead = ieee80211_frame_duration(local, 0, 60, 1, 1) + ack_dur; -+ mi->overhead_rtscts = mi->overhead + 2 * ack_dur; -+ -+ mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); -+ -+ minstrel_ht_update_cap(mi, sta, mp->hw->conf.channel_type); ++ minstrel_ht_update_caps(priv, sband, sta, priv_sta, mp->hw->conf.channel_type); +} + +static void @@ -779,10 +773,7 @@ + struct ieee80211_sta *sta, void *priv_sta, + u32 changed, enum nl80211_channel_type oper_chan_type) +{ -+ struct minstrel_ht_sta_priv *msp = priv_sta; -+ struct minstrel_ht_sta *mi = &msp->ht; -+ -+ minstrel_ht_update_cap(mi, sta, oper_chan_type); ++ minstrel_ht_update_caps(priv, sband, sta, priv_sta, oper_chan_type); +} + +static void * @@ -895,7 +886,7 @@ +} --- /dev/null +++ b/net/mac80211/rc80211_minstrel_ht.h -@@ -0,0 +1,115 @@ +@@ -0,0 +1,125 @@ +/* + * Copyright (C) 2010 Felix Fietkau + * @@ -942,9 +933,11 @@ + unsigned int cur_prob, probability; + + /* maximum retry counts */ -+ bool retry_updated; + unsigned int retry_count; + unsigned int retry_count_rtscts; ++ ++ bool retry_updated; ++ u8 sample_skipped; +}; + +struct minstrel_mcs_group_data { @@ -964,7 +957,11 @@ +}; + +struct minstrel_ht_sta { -+ /* ampdu length average (EWMA) */ ++ /* ampdu length (average, per sampling interval) */ ++ unsigned int ampdu_len; ++ unsigned int ampdu_packets; ++ ++ /* ampdu length (EWMA) */ + unsigned int avg_ampdu_len; + + /* best throughput rate */ @@ -985,10 +982,14 @@ + + unsigned int total_packets; + unsigned int sample_packets; -+ unsigned int sample_pending; ++ ++ u8 sample_wait; ++ u8 sample_tries; ++ u8 sample_count; ++ u8 sample_slow; + + /* current MCS group to be sampled */ -+ unsigned int sample_group; ++ u8 sample_group; + + /* MCS rate group info and statistics */ + struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS]; @@ -1073,7 +1074,7 @@ + struct minstrel_rate_stats *mr = &mi->groups[i].rates[j]; + int idx = i * MCS_GROUP_RATES + j; + -+ if (!mi->groups[i].supported & BIT(j)) ++ if (!(mi->groups[i].supported & BIT(j))) + continue; + + p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);