| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767 |
- From: Felix Fietkau <[email protected]>
- Date: Fri, 22 Jan 2021 23:57:50 +0100
- Subject: [PATCH] mac80211: minstrel_ht: significantly redesign the rate
- probing strategy
- The biggest flaw in current minstrel_ht is the fact that it needs way too
- many probing packets to be able to quickly find the best rate.
- Depending on the wifi hardware and operating mode, this can significantly
- reduce throughput when not operating at the highest available data rate.
- In order to be able to significantly reduce the amount of rate sampling,
- we need a much smarter selection of probing rates.
- The new approach introduced by this patch maintains a limited set of
- available rates to be tested during a statistics window.
- They are split into distinct categories:
- - MINSTREL_SAMPLE_TYPE_INC - incremental rate upgrade:
- Pick the next rate group and find the first rate that is faster than
- the current max. throughput rate
- - MINSTREL_SAMPLE_TYPE_JUMP - random testing of higher rates:
- Pick a random rate from the next group that is faster than the current
- max throughput rate. This allows faster adaptation when the link changes
- significantly
- - MINSTREL_SAMPLE_TYPE_SLOW - test a rate between max_prob, max_tp2 and
- max_tp in order to reduce the gap between them
- In order to prioritize sampling, every 6 attempts are split into 3x INC,
- 2x JUMP, 1x SLOW.
- Available rates are checked and refilled on every stats window update.
- With this approach, we finally get a very small delta in throughput when
- comparing setting the optimal data rate as a fixed rate vs normal rate
- control operation.
- Signed-off-by: Felix Fietkau <[email protected]>
- ---
- --- a/net/mac80211/rc80211_minstrel_ht.c
- +++ b/net/mac80211/rc80211_minstrel_ht.c
- @@ -266,6 +266,14 @@ const struct mcs_group minstrel_mcs_grou
- const s16 minstrel_cck_bitrates[4] = { 10, 20, 55, 110 };
- const s16 minstrel_ofdm_bitrates[8] = { 60, 90, 120, 180, 240, 360, 480, 540 };
- static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;
- +static const u8 minstrel_sample_seq[] = {
- + MINSTREL_SAMPLE_TYPE_INC,
- + MINSTREL_SAMPLE_TYPE_JUMP,
- + MINSTREL_SAMPLE_TYPE_INC,
- + MINSTREL_SAMPLE_TYPE_JUMP,
- + MINSTREL_SAMPLE_TYPE_INC,
- + MINSTREL_SAMPLE_TYPE_SLOW,
- +};
-
- static void
- minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi);
- @@ -620,77 +628,31 @@ minstrel_ht_prob_rate_reduce_streams(str
- }
- }
-
- -static bool
- -minstrel_ht_probe_group(struct minstrel_ht_sta *mi, const struct mcs_group *tp_group,
- - int tp_idx, const struct mcs_group *group)
- -{
- - if (group->bw < tp_group->bw)
- - return false;
- -
- - if (group->streams == tp_group->streams)
- - return true;
- -
- - if (tp_idx < 4 && group->streams == tp_group->streams - 1)
- - return true;
- -
- - return group->streams == tp_group->streams + 1;
- -}
- -
- -static void
- -minstrel_ht_find_probe_rates(struct minstrel_ht_sta *mi, u16 *rates, int *n_rates,
- - bool faster_rate)
- +static u16
- +__minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi,
- + enum minstrel_sample_type type)
- {
- - const struct mcs_group *group, *tp_group;
- - int i, g, max_dur;
- - int tp_idx;
- -
- - tp_group = &minstrel_mcs_groups[MI_RATE_GROUP(mi->max_tp_rate[0])];
- - tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]);
- -
- - max_dur = minstrel_get_duration(mi->max_tp_rate[0]);
- - if (faster_rate)
- - max_dur -= max_dur / 16;
- -
- - for (g = 0; g < MINSTREL_GROUPS_NB; g++) {
- - u16 supported = mi->supported[g];
- -
- - if (!supported)
- - continue;
- + u16 *rates = mi->sample[type].sample_rates;
- + u16 cur;
- + int i;
-
- - group = &minstrel_mcs_groups[g];
- - if (!minstrel_ht_probe_group(mi, tp_group, tp_idx, group))
- + for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) {
- + if (!rates[i])
- continue;
-
- - for (i = 0; supported; supported >>= 1, i++) {
- - int idx;
- -
- - if (!(supported & 1))
- - continue;
- -
- - if ((group->duration[i] << group->shift) > max_dur)
- - continue;
- -
- - idx = MI_RATE(g, i);
- - if (idx == mi->max_tp_rate[0])
- - continue;
- -
- - rates[(*n_rates)++] = idx;
- - break;
- - }
- + cur = rates[i];
- + rates[i] = 0;
- + return cur;
- }
- +
- + return 0;
- }
-
- static void
- minstrel_ht_rate_sample_switch(struct minstrel_priv *mp,
- struct minstrel_ht_sta *mi)
- {
- - struct minstrel_rate_stats *mrs;
- - u16 rates[MINSTREL_GROUPS_NB];
- - int n_rates = 0;
- - int probe_rate = 0;
- - bool faster_rate;
- - int i;
- - u8 random;
- + u16 rate;
-
- /*
- * Use rate switching instead of probing packets for devices with
- @@ -699,43 +661,11 @@ minstrel_ht_rate_sample_switch(struct mi
- if (mp->hw->max_rates > 1)
- return;
-
- - /*
- - * If the current EWMA prob is >75%, look for a rate that's 6.25%
- - * faster than the max tp rate.
- - * If that fails, look again for a rate that is at least as fast
- - */
- - mrs = minstrel_get_ratestats(mi, mi->max_tp_rate[0]);
- - faster_rate = mrs->prob_avg > MINSTREL_FRAC(75, 100);
- - minstrel_ht_find_probe_rates(mi, rates, &n_rates, faster_rate);
- - if (!n_rates && faster_rate)
- - minstrel_ht_find_probe_rates(mi, rates, &n_rates, false);
- -
- - /* If no suitable rate was found, try to pick the next one in the group */
- - if (!n_rates) {
- - int g_idx = MI_RATE_GROUP(mi->max_tp_rate[0]);
- - u16 supported = mi->supported[g_idx];
- -
- - supported >>= MI_RATE_IDX(mi->max_tp_rate[0]);
- - for (i = 0; supported; supported >>= 1, i++) {
- - if (!(supported & 1))
- - continue;
- -
- - probe_rate = mi->max_tp_rate[0] + i;
- - goto out;
- - }
- -
- + rate = __minstrel_ht_get_sample_rate(mi, MINSTREL_SAMPLE_TYPE_INC);
- + if (!rate)
- return;
- - }
- -
- - i = 0;
- - if (n_rates > 1) {
- - random = prandom_u32();
- - i = random % n_rates;
- - }
- - probe_rate = rates[i];
-
- -out:
- - mi->sample_rate = probe_rate;
- + mi->sample_rate = rate;
- mi->sample_mode = MINSTREL_SAMPLE_ACTIVE;
- }
-
- @@ -804,6 +734,274 @@ minstrel_ht_calc_rate_stats(struct minst
- mrs->attempts = 0;
- }
-
- +static bool
- +minstrel_ht_find_sample_rate(struct minstrel_ht_sta *mi, int type, int idx)
- +{
- + int i;
- +
- + for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) {
- + u16 cur = mi->sample[type].sample_rates[i];
- +
- + if (cur == idx)
- + return true;
- +
- + if (!cur)
- + break;
- + }
- +
- + return false;
- +}
- +
- +static int
- +minstrel_ht_move_sample_rates(struct minstrel_ht_sta *mi, int type,
- + u32 fast_rate_dur, u32 slow_rate_dur)
- +{
- + u16 *rates = mi->sample[type].sample_rates;
- + int i, j;
- +
- + for (i = 0, j = 0; i < MINSTREL_SAMPLE_RATES; i++) {
- + u32 duration;
- + bool valid = false;
- + u16 cur;
- +
- + cur = rates[i];
- + if (!cur)
- + continue;
- +
- + duration = minstrel_get_duration(cur);
- + switch (type) {
- + case MINSTREL_SAMPLE_TYPE_SLOW:
- + valid = duration > fast_rate_dur &&
- + duration < slow_rate_dur;
- + break;
- + case MINSTREL_SAMPLE_TYPE_INC:
- + case MINSTREL_SAMPLE_TYPE_JUMP:
- + valid = duration < fast_rate_dur;
- + break;
- + default:
- + valid = false;
- + break;
- + }
- +
- + if (!valid) {
- + rates[i] = 0;
- + continue;
- + }
- +
- + if (i == j)
- + continue;
- +
- + rates[j++] = cur;
- + rates[i] = 0;
- + }
- +
- + return j;
- +}
- +
- +static int
- +minstrel_ht_group_min_rate_offset(struct minstrel_ht_sta *mi, int group,
- + u32 max_duration)
- +{
- + u16 supported = mi->supported[group];
- + int i;
- +
- + for (i = 0; i < MCS_GROUP_RATES && supported; i++, supported >>= 1) {
- + if (!(supported & BIT(0)))
- + continue;
- +
- + if (minstrel_get_duration(MI_RATE(group, i)) >= max_duration)
- + continue;
- +
- + return i;
- + }
- +
- + return -1;
- +}
- +
- +/*
- + * Incremental update rates:
- + * Flip through groups and pick the first group rate that is faster than the
- + * highest currently selected rate
- + */
- +static u16
- +minstrel_ht_next_inc_rate(struct minstrel_ht_sta *mi, u32 fast_rate_dur)
- +{
- + struct minstrel_mcs_group_data *mg;
- + u8 type = MINSTREL_SAMPLE_TYPE_INC;
- + int i, index = 0;
- + u8 group;
- +
- + group = mi->sample[type].sample_group;
- + for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) {
- + group = (group + 1) % ARRAY_SIZE(minstrel_mcs_groups);
- + mg = &mi->groups[group];
- +
- + index = minstrel_ht_group_min_rate_offset(mi, group,
- + fast_rate_dur);
- + if (index < 0)
- + continue;
- +
- + index = MI_RATE(group, index & 0xf);
- + if (!minstrel_ht_find_sample_rate(mi, type, index))
- + goto out;
- + }
- + index = 0;
- +
- +out:
- + mi->sample[type].sample_group = group;
- +
- + return index;
- +}
- +
- +static int
- +minstrel_ht_next_group_sample_rate(struct minstrel_ht_sta *mi, int group,
- + u16 supported, int offset)
- +{
- + struct minstrel_mcs_group_data *mg = &mi->groups[group];
- + u16 idx;
- + int i;
- +
- + for (i = 0; i < MCS_GROUP_RATES; i++) {
- + idx = sample_table[mg->column][mg->index];
- + if (++mg->index >= MCS_GROUP_RATES) {
- + mg->index = 0;
- + if (++mg->column >= ARRAY_SIZE(sample_table))
- + mg->column = 0;
- + }
- +
- + if (idx < offset)
- + continue;
- +
- + if (!(supported & BIT(idx)))
- + continue;
- +
- + return MI_RATE(group, idx);
- + }
- +
- + return -1;
- +}
- +
- +/*
- + * Jump rates:
- + * Sample random rates, use those that are faster than the highest
- + * currently selected rate. Rates between the fastest and the slowest
- + * get sorted into the slow sample bucket, but only if it has room
- + */
- +static u16
- +minstrel_ht_next_jump_rate(struct minstrel_ht_sta *mi, u32 fast_rate_dur,
- + u32 slow_rate_dur, int *slow_rate_ofs)
- +{
- + struct minstrel_mcs_group_data *mg;
- + struct minstrel_rate_stats *mrs;
- + u32 max_duration = slow_rate_dur;
- + int i, index, offset;
- + u16 *slow_rates;
- + u16 supported;
- + u32 duration;
- + u8 group;
- +
- + if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES)
- + max_duration = fast_rate_dur;
- +
- + slow_rates = mi->sample[MINSTREL_SAMPLE_TYPE_SLOW].sample_rates;
- + group = mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_group;
- + for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) {
- + u8 type;
- +
- + group = (group + 1) % ARRAY_SIZE(minstrel_mcs_groups);
- + mg = &mi->groups[group];
- +
- + supported = mi->supported[group];
- + if (!supported)
- + continue;
- +
- + offset = minstrel_ht_group_min_rate_offset(mi, group,
- + max_duration);
- + if (offset < 0)
- + continue;
- +
- + index = minstrel_ht_next_group_sample_rate(mi, group, supported,
- + offset);
- + if (index < 0)
- + continue;
- +
- + duration = minstrel_get_duration(index);
- + if (duration < fast_rate_dur)
- + type = MINSTREL_SAMPLE_TYPE_JUMP;
- + else
- + type = MINSTREL_SAMPLE_TYPE_SLOW;
- +
- + if (minstrel_ht_find_sample_rate(mi, type, index))
- + continue;
- +
- + if (type == MINSTREL_SAMPLE_TYPE_JUMP)
- + goto found;
- +
- + if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES)
- + continue;
- +
- + if (duration >= slow_rate_dur)
- + continue;
- +
- + /* skip slow rates with high success probability */
- + mrs = minstrel_get_ratestats(mi, index);
- + if (mrs->prob_avg > MINSTREL_FRAC(95, 100))
- + continue;
- +
- + slow_rates[(*slow_rate_ofs)++] = index;
- + if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES)
- + max_duration = fast_rate_dur;
- + }
- + index = 0;
- +
- +found:
- + mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_group = group;
- +
- + return index;
- +}
- +
- +static void
- +minstrel_ht_refill_sample_rates(struct minstrel_ht_sta *mi)
- +{
- + u32 prob_dur = minstrel_get_duration(mi->max_prob_rate);
- + u32 tp_dur = minstrel_get_duration(mi->max_tp_rate[0]);
- + u32 tp2_dur = minstrel_get_duration(mi->max_tp_rate[1]);
- + u32 fast_rate_dur = min(min(tp_dur, tp2_dur), prob_dur);
- + u32 slow_rate_dur = max(max(tp_dur, tp2_dur), prob_dur);
- + u16 *rates;
- + int i, j;
- +
- + rates = mi->sample[MINSTREL_SAMPLE_TYPE_INC].sample_rates;
- + i = minstrel_ht_move_sample_rates(mi, MINSTREL_SAMPLE_TYPE_INC,
- + fast_rate_dur, slow_rate_dur);
- + while (i < MINSTREL_SAMPLE_RATES) {
- + rates[i] = minstrel_ht_next_inc_rate(mi, tp_dur);
- + if (!rates[i])
- + break;
- +
- + i++;
- + }
- +
- + rates = mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_rates;
- + i = minstrel_ht_move_sample_rates(mi, MINSTREL_SAMPLE_TYPE_JUMP,
- + fast_rate_dur, slow_rate_dur);
- + j = minstrel_ht_move_sample_rates(mi, MINSTREL_SAMPLE_TYPE_SLOW,
- + fast_rate_dur, slow_rate_dur);
- + while (i < MINSTREL_SAMPLE_RATES) {
- + rates[i] = minstrel_ht_next_jump_rate(mi, fast_rate_dur,
- + slow_rate_dur, &j);
- + if (!rates[i])
- + break;
- +
- + i++;
- + }
- +
- + for (i = 0; i < ARRAY_SIZE(mi->sample); i++)
- + memcpy(mi->sample[i].cur_sample_rates, mi->sample[i].sample_rates,
- + sizeof(mi->sample[i].cur_sample_rates));
- +}
- +
- +
- /*
- * Update rate statistics and select new primary rates
- *
- @@ -848,8 +1046,6 @@ minstrel_ht_update_stats(struct minstrel
- mi->ampdu_packets = 0;
- }
-
- - mi->sample_count = 0;
- -
- if (mi->supported[MINSTREL_CCK_GROUP])
- group = MINSTREL_CCK_GROUP;
- else if (mi->supported[MINSTREL_OFDM_GROUP])
- @@ -884,8 +1080,6 @@ minstrel_ht_update_stats(struct minstrel
- if (!mi->supported[group])
- continue;
-
- - mi->sample_count++;
- -
- /* (re)Initialize group rate indexes */
- for(j = 0; j < MAX_THR_RATES; j++)
- tmp_group_tp_rate[j] = MI_RATE(group, 0);
- @@ -952,9 +1146,7 @@ minstrel_ht_update_stats(struct minstrel
-
- /* Try to increase robustness of max_prob_rate*/
- minstrel_ht_prob_rate_reduce_streams(mi);
- -
- - /* try to sample half of all available rates during each interval */
- - mi->sample_count *= 4;
- + minstrel_ht_refill_sample_rates(mi);
-
- if (sample)
- minstrel_ht_rate_sample_switch(mp, mi);
- @@ -971,6 +1163,7 @@ minstrel_ht_update_stats(struct minstrel
-
- /* Reset update timer */
- mi->last_stats_update = jiffies;
- + mi->sample_time = jiffies;
- }
-
- static bool
- @@ -1001,28 +1194,6 @@ minstrel_ht_txstat_valid(struct minstrel
- }
-
- static void
- -minstrel_set_next_sample_idx(struct minstrel_ht_sta *mi)
- -{
- - struct minstrel_mcs_group_data *mg;
- -
- - for (;;) {
- - mi->sample_group++;
- - mi->sample_group %= ARRAY_SIZE(minstrel_mcs_groups);
- - mg = &mi->groups[mi->sample_group];
- -
- - if (!mi->supported[mi->sample_group])
- - continue;
- -
- - if (++mg->index >= MCS_GROUP_RATES) {
- - mg->index = 0;
- - if (++mg->column >= ARRAY_SIZE(sample_table))
- - mg->column = 0;
- - }
- - break;
- - }
- -}
- -
- -static void
- minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary)
- {
- int group, orig_group;
- @@ -1107,14 +1278,6 @@ minstrel_ht_tx_status(void *priv, struct
- mi->ampdu_packets++;
- mi->ampdu_len += info->status.ampdu_len;
-
- - if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {
- - int avg_ampdu_len = minstrel_ht_avg_ampdu_len(mi);
- -
- - mi->sample_wait = 16 + 2 * avg_ampdu_len;
- - mi->sample_tries = 1;
- - mi->sample_count--;
- - }
- -
- if (mi->sample_mode != MINSTREL_SAMPLE_IDLE)
- rate_sample = minstrel_get_ratestats(mi, mi->sample_rate);
-
- @@ -1386,97 +1549,20 @@ minstrel_ht_update_rates(struct minstrel
- rate_control_set_rates(mp->hw, mi->sta, rates);
- }
-
- -static int
- -minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
- +static u16
- +minstrel_ht_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
- {
- - struct minstrel_rate_stats *mrs;
- - struct minstrel_mcs_group_data *mg;
- - unsigned int sample_dur, sample_group, cur_max_tp_streams;
- - int tp_rate1, tp_rate2;
- - int sample_idx = 0;
- -
- - if (mp->hw->max_rates == 1 && mp->sample_switch &&
- - (mi->total_packets_cur >= SAMPLE_SWITCH_THR ||
- - mp->sample_switch == 1))
- - return -1;
- -
- - if (mi->sample_wait > 0) {
- - mi->sample_wait--;
- - return -1;
- - }
- -
- - if (!mi->sample_tries)
- - return -1;
- -
- - sample_group = mi->sample_group;
- - mg = &mi->groups[sample_group];
- - sample_idx = sample_table[mg->column][mg->index];
- - minstrel_set_next_sample_idx(mi);
- -
- - if (!(mi->supported[sample_group] & BIT(sample_idx)))
- - return -1;
- + u8 seq;
-
- - mrs = &mg->rates[sample_idx];
- - sample_idx += MI_RATE(sample_group, 0);
- -
- - tp_rate1 = mi->max_tp_rate[0];
- -
- - /* Set tp_rate2 to the second highest max_tp_rate */
- - if (minstrel_get_duration(mi->max_tp_rate[0]) >
- - minstrel_get_duration(mi->max_tp_rate[1])) {
- - tp_rate2 = mi->max_tp_rate[0];
- + if (mp->hw->max_rates > 1) {
- + seq = mi->sample_seq;
- + mi->sample_seq = (seq + 1) % ARRAY_SIZE(minstrel_sample_seq);
- + seq = minstrel_sample_seq[seq];
- } else {
- - tp_rate2 = mi->max_tp_rate[1];
- + seq = MINSTREL_SAMPLE_TYPE_INC;
- }
-
- - /*
- - * Sampling might add some overhead (RTS, no aggregation)
- - * to the frame. Hence, don't use sampling for the highest currently
- - * used highest throughput or probability rate.
- - */
- - if (sample_idx == mi->max_tp_rate[0] || sample_idx == mi->max_prob_rate)
- - return -1;
- -
- - /*
- - * Do not sample if the probability is already higher than 95%,
- - * or if the rate is 3 times slower than the current max probability
- - * rate, to avoid wasting airtime.
- - */
- - sample_dur = minstrel_get_duration(sample_idx);
- - if (mrs->prob_avg > MINSTREL_FRAC(95, 100) ||
- - minstrel_get_duration(mi->max_prob_rate) * 3 < sample_dur)
- - return -1;
- -
- -
- - /*
- - * For devices with no configurable multi-rate retry, skip sampling
- - * below the per-group max throughput rate, and only use one sampling
- - * attempt per rate
- - */
- - if (mp->hw->max_rates == 1 &&
- - (minstrel_get_duration(mg->max_group_tp_rate[0]) < sample_dur ||
- - mrs->attempts))
- - return -1;
- -
- - /* Skip already sampled slow rates */
- - if (sample_dur >= minstrel_get_duration(tp_rate1) && mrs->attempts)
- - return -1;
- -
- - /*
- - * Make sure that lower rates get sampled only occasionally,
- - * if the link is working perfectly.
- - */
- -
- - cur_max_tp_streams = minstrel_mcs_groups[MI_RATE_GROUP(tp_rate1)].streams;
- - if (sample_dur >= minstrel_get_duration(tp_rate2) &&
- - (cur_max_tp_streams - 1 <
- - minstrel_mcs_groups[sample_group].streams ||
- - sample_dur >= minstrel_get_duration(mi->max_prob_rate)))
- - return -1;
- -
- - mi->sample_tries--;
- -
- - return sample_idx;
- + return __minstrel_ht_get_sample_rate(mi, seq);
- }
-
- static void
- @@ -1488,7 +1574,7 @@ minstrel_ht_get_rate(void *priv, struct
- struct ieee80211_tx_rate *rate = &info->status.rates[0];
- struct minstrel_ht_sta *mi = priv_sta;
- struct minstrel_priv *mp = priv;
- - int sample_idx;
- + u16 sample_idx;
-
- if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
- !minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_prob_rate)))
- @@ -1504,11 +1590,19 @@ minstrel_ht_get_rate(void *priv, struct
- /* Don't use EAPOL frames for sampling on non-mrr hw */
- if (mp->hw->max_rates == 1 &&
- (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO))
- - sample_idx = -1;
- - else
- - sample_idx = minstrel_get_sample_rate(mp, mi);
- + return;
- +
- + if (mp->hw->max_rates == 1 && mp->sample_switch &&
- + (mi->total_packets_cur >= SAMPLE_SWITCH_THR ||
- + mp->sample_switch == 1))
- + return;
- +
- + if (time_is_before_jiffies(mi->sample_time))
- + return;
-
- - if (sample_idx < 0)
- + mi->sample_time = jiffies + MINSTREL_SAMPLE_INTERVAL;
- + sample_idx = minstrel_ht_get_sample_rate(mp, mi);
- + if (!sample_idx)
- return;
-
- sample_group = &minstrel_mcs_groups[MI_RATE_GROUP(sample_idx)];
- @@ -1629,16 +1723,6 @@ minstrel_ht_update_caps(void *priv, stru
-
- 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 (!use_vht) {
- stbc = (ht_cap & IEEE80211_HT_CAP_RX_STBC) >>
- IEEE80211_HT_CAP_RX_STBC_SHIFT;
- --- a/net/mac80211/rc80211_minstrel_ht.h
- +++ b/net/mac80211/rc80211_minstrel_ht.h
- @@ -69,6 +69,8 @@
- #define MI_RATE_IDX(_rate) FIELD_GET(MI_RATE_IDX_MASK, _rate)
- #define MI_RATE_GROUP(_rate) FIELD_GET(MI_RATE_GROUP_MASK, _rate)
-
- +#define MINSTREL_SAMPLE_RATES 5 /* rates per sample type */
- +#define MINSTREL_SAMPLE_INTERVAL (HZ / 50)
-
- struct minstrel_priv {
- struct ieee80211_hw *hw;
- @@ -126,6 +128,13 @@ struct minstrel_rate_stats {
- bool retry_updated;
- };
-
- +enum minstrel_sample_type {
- + MINSTREL_SAMPLE_TYPE_INC,
- + MINSTREL_SAMPLE_TYPE_JUMP,
- + MINSTREL_SAMPLE_TYPE_SLOW,
- + __MINSTREL_SAMPLE_TYPE_MAX
- +};
- +
- struct minstrel_mcs_group_data {
- u8 index;
- u8 column;
- @@ -144,6 +153,12 @@ enum minstrel_sample_mode {
- MINSTREL_SAMPLE_PENDING,
- };
-
- +struct minstrel_sample_category {
- + u8 sample_group;
- + u16 sample_rates[MINSTREL_SAMPLE_RATES];
- + u16 cur_sample_rates[MINSTREL_SAMPLE_RATES];
- +};
- +
- struct minstrel_ht_sta {
- struct ieee80211_sta *sta;
-
- @@ -175,16 +190,14 @@ struct minstrel_ht_sta {
- /* tx flags to add for frames for this sta */
- u32 tx_flags;
-
- - u8 sample_wait;
- - u8 sample_tries;
- - u8 sample_count;
- + unsigned long sample_time;
- + struct minstrel_sample_category sample[__MINSTREL_SAMPLE_TYPE_MAX];
- +
- + u8 sample_seq;
-
- enum minstrel_sample_mode sample_mode;
- u16 sample_rate;
-
- - /* current MCS group to be sampled */
- - u8 sample_group;
- -
- u8 band;
-
- /* Bitfield of supported MCS rates of all groups */
|