mac80211: add new minstrel_ht patches to improve probing on mt76x2
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
98b654de2e
commit
9861050b85
@ -0,0 +1,22 @@
|
|||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Fri, 14 Jun 2019 21:12:04 +0200
|
||||||
|
Subject: [PATCH] mac80211: minstrel_ht: fix per-group max throughput rate
|
||||||
|
initialization
|
||||||
|
|
||||||
|
The group number needs to be multiplied by the number of rates per group
|
||||||
|
to get the full rate index
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||||
|
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||||
|
@@ -576,7 +576,7 @@ minstrel_ht_update_stats(struct minstrel
|
||||||
|
|
||||||
|
/* (re)Initialize group rate indexes */
|
||||||
|
for(j = 0; j < MAX_THR_RATES; j++)
|
||||||
|
- tmp_group_tp_rate[j] = group;
|
||||||
|
+ tmp_group_tp_rate[j] = MCS_GROUP_RATES * group;
|
||||||
|
|
||||||
|
for (i = 0; i < MCS_GROUP_RATES; i++) {
|
||||||
|
if (!(mi->supported[group] & BIT(i)))
|
@ -0,0 +1,42 @@
|
|||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Wed, 5 Jun 2019 20:42:49 +0200
|
||||||
|
Subject: [PATCH] mac80211: minstrel_ht: reduce unnecessary rate probing
|
||||||
|
attempts
|
||||||
|
|
||||||
|
On hardware with static fallback tables (e.g. mt76x2), rate probing attempts
|
||||||
|
can be very expensive.
|
||||||
|
On such devices, avoid sampling rates slower than the per-group max throughput
|
||||||
|
rate, based on the assumption that the fallback table will take care of probing
|
||||||
|
lower rates within that group if the higher rates fail.
|
||||||
|
To make this work, this also fixes a wrong initialization in the previously
|
||||||
|
unused per-group sorted rate array.
|
||||||
|
To further reduce unnecessary probing attempts, skip duplicate attempts on
|
||||||
|
rates slower than the max throughput rate.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||||
|
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||||
|
@@ -1062,6 +1062,21 @@ minstrel_get_sample_rate(struct minstrel
|
||||||
|
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.
|
@ -0,0 +1,46 @@
|
|||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Fri, 14 Jun 2019 21:14:22 +0200
|
||||||
|
Subject: [PATCH] mac80211: minstrel_ht: fix default max throughput rate
|
||||||
|
indexes
|
||||||
|
|
||||||
|
Use the first supported rate instead of 0 (which can be invalid)
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||||
|
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||||
|
@@ -487,7 +487,7 @@ minstrel_ht_assign_best_tp_rates(struct
|
||||||
|
tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
|
||||||
|
tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
|
||||||
|
|
||||||
|
- if (tmp_cck_tp > tmp_mcs_tp) {
|
||||||
|
+ if (tmp_cck_tp_rate && tmp_cck_tp > tmp_mcs_tp) {
|
||||||
|
for(i = 0; i < MAX_THR_RATES; i++) {
|
||||||
|
minstrel_ht_sort_best_tp_rates(mi, tmp_cck_tp_rate[i],
|
||||||
|
tmp_mcs_tp_rate);
|
||||||
|
@@ -559,11 +559,19 @@ minstrel_ht_update_stats(struct minstrel
|
||||||
|
mi->sample_slow = 0;
|
||||||
|
mi->sample_count = 0;
|
||||||
|
|
||||||
|
- /* Initialize global rate indexes */
|
||||||
|
- for(j = 0; j < MAX_THR_RATES; j++){
|
||||||
|
- tmp_mcs_tp_rate[j] = 0;
|
||||||
|
- tmp_cck_tp_rate[j] = 0;
|
||||||
|
- }
|
||||||
|
+ memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate));
|
||||||
|
+ memset(tmp_cck_tp_rate, 0, sizeof(tmp_cck_tp_rate));
|
||||||
|
+ if (mi->supported[MINSTREL_CCK_GROUP])
|
||||||
|
+ for (j = 0; j < ARRAY_SIZE(tmp_cck_tp_rate); j++)
|
||||||
|
+ tmp_cck_tp_rate[j] = MINSTREL_CCK_GROUP * MCS_GROUP_RATES;
|
||||||
|
+
|
||||||
|
+ if (mi->supported[MINSTREL_VHT_GROUP_0])
|
||||||
|
+ index = MINSTREL_VHT_GROUP_0 * MCS_GROUP_RATES;
|
||||||
|
+ else
|
||||||
|
+ index = MINSTREL_HT_GROUP_0 * MCS_GROUP_RATES;
|
||||||
|
+
|
||||||
|
+ for (j = 0; j < ARRAY_SIZE(tmp_mcs_tp_rate); j++)
|
||||||
|
+ tmp_mcs_tp_rate[j] = index;
|
||||||
|
|
||||||
|
/* Find best rate sets within all MCS groups*/
|
||||||
|
for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
|
@ -0,0 +1,481 @@
|
|||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Fri, 14 Jun 2019 21:15:47 +0200
|
||||||
|
Subject: [PATCH] mac80211: minstrel_ht: improve rate probing for devices
|
||||||
|
with static fallback
|
||||||
|
|
||||||
|
On some devices that only support static rate fallback tables sending rate
|
||||||
|
control probing packets can be really expensive.
|
||||||
|
Probing lower rates can already hurt throughput quite a bit. What hurts even
|
||||||
|
more is the fact that on mt76x0/mt76x2, single probing packets can only be
|
||||||
|
forced by directing packets at a different internal hardware queue, which
|
||||||
|
causes some heavy reordering and extra latency.
|
||||||
|
The reordering issue is mainly problematic while pushing lots of packets to
|
||||||
|
a particular station. If there is little activity, the overhead of probing is
|
||||||
|
neglegible.
|
||||||
|
|
||||||
|
The static fallback behavior is designed to pretty much only handle rate
|
||||||
|
control algorithms that use only a very limited set of rates on which the
|
||||||
|
algorithm switches up/down based on packet error rate.
|
||||||
|
|
||||||
|
In order to better support that kind of hardware, this patch implements a
|
||||||
|
different approach to rate probing where it switches to a slightly higher rate,
|
||||||
|
waits for tx status feedback, then updates the stats and switches back to
|
||||||
|
the new max throughput rate. This only triggers above a packet rate of 100
|
||||||
|
per stats interval (~50ms).
|
||||||
|
For that kind of probing, the code has to reduce the set of probing rates
|
||||||
|
a lot more compared to single packet probing, so it uses only one packet
|
||||||
|
per MCS group which is either slightly faster, or as close as possible to
|
||||||
|
the max throughput rate.
|
||||||
|
This allows switching between similar rates with different numbers of
|
||||||
|
streams. The algorithm assumes that the hardware will work its way lower
|
||||||
|
within an MCS group in case of retransmissions, so that lower rates don't
|
||||||
|
have to be probed by the high packets per second rate probing code.
|
||||||
|
|
||||||
|
To further reduce the search space, it also does not probe rates with lower
|
||||||
|
channel bandwidth than the max throughput rate.
|
||||||
|
|
||||||
|
At the moment, these changes will only affect mt76x0/mt76x2.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/net/mac80211/rc80211_minstrel.h
|
||||||
|
+++ b/net/mac80211/rc80211_minstrel.h
|
||||||
|
@@ -114,6 +114,7 @@ struct minstrel_sta_info {
|
||||||
|
struct minstrel_priv {
|
||||||
|
struct ieee80211_hw *hw;
|
||||||
|
bool has_mrr;
|
||||||
|
+ u32 sample_switch;
|
||||||
|
unsigned int cw_min;
|
||||||
|
unsigned int cw_max;
|
||||||
|
unsigned int max_retry;
|
||||||
|
--- a/net/mac80211/rc80211_minstrel_ht.c
|
||||||
|
+++ b/net/mac80211/rc80211_minstrel_ht.c
|
||||||
|
@@ -21,6 +21,8 @@
|
||||||
|
#define AVG_AMPDU_SIZE 16
|
||||||
|
#define AVG_PKT_SIZE 1200
|
||||||
|
|
||||||
|
+#define SAMPLE_SWITCH_THR 100
|
||||||
|
+
|
||||||
|
/* Number of bits for an average sized packet */
|
||||||
|
#define MCS_NBITS ((AVG_PKT_SIZE * AVG_AMPDU_SIZE) << 3)
|
||||||
|
|
||||||
|
@@ -59,6 +61,7 @@
|
||||||
|
[GROUP_IDX(_streams, _sgi, _ht40)] = { \
|
||||||
|
.streams = _streams, \
|
||||||
|
.shift = _s, \
|
||||||
|
+ .bw = _ht40, \
|
||||||
|
.flags = \
|
||||||
|
IEEE80211_TX_RC_MCS | \
|
||||||
|
(_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \
|
||||||
|
@@ -95,6 +98,7 @@
|
||||||
|
[VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \
|
||||||
|
.streams = _streams, \
|
||||||
|
.shift = _s, \
|
||||||
|
+ .bw = _bw, \
|
||||||
|
.flags = \
|
||||||
|
IEEE80211_TX_RC_VHT_MCS | \
|
||||||
|
(_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \
|
||||||
|
@@ -527,6 +531,133 @@ minstrel_ht_prob_rate_reduce_streams(str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline int
|
||||||
|
+minstrel_get_duration(int index)
|
||||||
|
+{
|
||||||
|
+ const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
|
||||||
|
+ unsigned int duration = group->duration[index % MCS_GROUP_RATES];
|
||||||
|
+ return duration << group->shift;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+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)
|
||||||
|
+{
|
||||||
|
+ const struct mcs_group *group, *tp_group;
|
||||||
|
+ int i, g, max_dur;
|
||||||
|
+ int tp_idx;
|
||||||
|
+
|
||||||
|
+ tp_group = &minstrel_mcs_groups[mi->max_tp_rate[0] / MCS_GROUP_RATES];
|
||||||
|
+ tp_idx = mi->max_tp_rate[0] % MCS_GROUP_RATES;
|
||||||
|
+
|
||||||
|
+ 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;
|
||||||
|
+
|
||||||
|
+ group = &minstrel_mcs_groups[g];
|
||||||
|
+ if (!minstrel_ht_probe_group(mi, tp_group, tp_idx, group))
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ for (i = 0; supported; supported >>= 1, i++) {
|
||||||
|
+ int idx;
|
||||||
|
+
|
||||||
|
+ if (!(supported & 1))
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ if ((group->duration[i] << group->shift) > max_dur)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ idx = g * MCS_GROUP_RATES + i;
|
||||||
|
+ if (idx == mi->max_tp_rate[0])
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ rates[(*n_rates)++] = idx;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+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;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Use rate switching instead of probing packets for devices with
|
||||||
|
+ * little control over retry fallback behavior
|
||||||
|
+ */
|
||||||
|
+ 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_ewma > 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->max_tp_rate[0] / MCS_GROUP_RATES;
|
||||||
|
+ u16 supported = mi->supported[g_idx];
|
||||||
|
+
|
||||||
|
+ supported >>= mi->max_tp_rate[0] % MCS_GROUP_RATES;
|
||||||
|
+ for (i = 0; supported; i++) {
|
||||||
|
+ if (!(supported & 1))
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ probe_rate = mi->max_tp_rate[0] + i;
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ 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_mode = MINSTREL_SAMPLE_ACTIVE;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Update rate statistics and select new primary rates
|
||||||
|
*
|
||||||
|
@@ -537,7 +668,8 @@ minstrel_ht_prob_rate_reduce_streams(str
|
||||||
|
* higher throughput rates, even if the probablity is a bit lower
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
-minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
||||||
|
+minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
|
||||||
|
+ bool sample)
|
||||||
|
{
|
||||||
|
struct minstrel_mcs_group_data *mg;
|
||||||
|
struct minstrel_rate_stats *mrs;
|
||||||
|
@@ -545,6 +677,18 @@ minstrel_ht_update_stats(struct minstrel
|
||||||
|
u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES];
|
||||||
|
u16 tmp_cck_tp_rate[MAX_THR_RATES], index;
|
||||||
|
|
||||||
|
+ mi->sample_mode = MINSTREL_SAMPLE_IDLE;
|
||||||
|
+
|
||||||
|
+ if (sample) {
|
||||||
|
+ mi->total_packets_cur = mi->total_packets -
|
||||||
|
+ mi->total_packets_last;
|
||||||
|
+ mi->total_packets_last = mi->total_packets;
|
||||||
|
+ }
|
||||||
|
+ if (!mp->sample_switch)
|
||||||
|
+ sample = false;
|
||||||
|
+ if (mi->total_packets_cur < SAMPLE_SWITCH_THR && mp->sample_switch != 1)
|
||||||
|
+ sample = false;
|
||||||
|
+
|
||||||
|
if (mi->ampdu_packets > 0) {
|
||||||
|
if (!ieee80211_hw_check(mp->hw, TX_STATUS_NO_AMPDU_LEN))
|
||||||
|
mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len,
|
||||||
|
@@ -631,12 +775,16 @@ minstrel_ht_update_stats(struct minstrel
|
||||||
|
/* try to sample all available rates during each interval */
|
||||||
|
mi->sample_count *= 8;
|
||||||
|
|
||||||
|
+ if (sample)
|
||||||
|
+ minstrel_ht_rate_sample_switch(mp, mi);
|
||||||
|
+
|
||||||
|
#ifdef CPTCFG_MAC80211_DEBUGFS
|
||||||
|
/* use fixed index if set */
|
||||||
|
if (mp->fixed_rate_idx != -1) {
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
mi->max_tp_rate[i] = mp->fixed_rate_idx;
|
||||||
|
mi->max_prob_rate = mp->fixed_rate_idx;
|
||||||
|
+ mi->sample_mode = MINSTREL_SAMPLE_IDLE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -740,15 +888,17 @@ minstrel_ht_tx_status(void *priv, struct
|
||||||
|
struct minstrel_ht_sta_priv *msp = priv_sta;
|
||||||
|
struct minstrel_ht_sta *mi = &msp->ht;
|
||||||
|
struct ieee80211_tx_rate *ar = info->status.rates;
|
||||||
|
- struct minstrel_rate_stats *rate, *rate2;
|
||||||
|
+ struct minstrel_rate_stats *rate, *rate2, *rate_sample = NULL;
|
||||||
|
struct minstrel_priv *mp = priv;
|
||||||
|
bool last, update = false;
|
||||||
|
+ bool sample_status = false;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!msp->is_ht)
|
||||||
|
return mac80211_minstrel.tx_status_ext(priv, sband,
|
||||||
|
&msp->legacy, st);
|
||||||
|
|
||||||
|
+
|
||||||
|
/* This packet was aggregated but doesn't carry status info */
|
||||||
|
if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
|
||||||
|
!(info->flags & IEEE80211_TX_STAT_AMPDU))
|
||||||
|
@@ -774,12 +924,17 @@ minstrel_ht_tx_status(void *priv, struct
|
||||||
|
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
|
||||||
|
mi->sample_packets += info->status.ampdu_len;
|
||||||
|
|
||||||
|
+ if (mi->sample_mode != MINSTREL_SAMPLE_IDLE)
|
||||||
|
+ rate_sample = minstrel_get_ratestats(mi, mi->sample_rate);
|
||||||
|
+
|
||||||
|
last = !minstrel_ht_txstat_valid(mp, &ar[0]);
|
||||||
|
for (i = 0; !last; i++) {
|
||||||
|
last = (i == IEEE80211_TX_MAX_RATES - 1) ||
|
||||||
|
!minstrel_ht_txstat_valid(mp, &ar[i + 1]);
|
||||||
|
|
||||||
|
rate = minstrel_ht_get_stats(mp, mi, &ar[i]);
|
||||||
|
+ if (rate == rate_sample)
|
||||||
|
+ sample_status = true;
|
||||||
|
|
||||||
|
if (last)
|
||||||
|
rate->success += info->status.ampdu_ack_len;
|
||||||
|
@@ -787,44 +942,60 @@ minstrel_ht_tx_status(void *priv, struct
|
||||||
|
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[0]);
|
||||||
|
- if (rate->attempts > 30 &&
|
||||||
|
- MINSTREL_FRAC(rate->success, rate->attempts) <
|
||||||
|
- MINSTREL_FRAC(20, 100)) {
|
||||||
|
- minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true);
|
||||||
|
+ switch (mi->sample_mode) {
|
||||||
|
+ case MINSTREL_SAMPLE_IDLE:
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case MINSTREL_SAMPLE_ACTIVE:
|
||||||
|
+ if (!sample_status)
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ mi->sample_mode = MINSTREL_SAMPLE_PENDING;
|
||||||
|
update = true;
|
||||||
|
- }
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case MINSTREL_SAMPLE_PENDING:
|
||||||
|
+ if (sample_status)
|
||||||
|
+ break;
|
||||||
|
|
||||||
|
- rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]);
|
||||||
|
- if (rate2->attempts > 30 &&
|
||||||
|
- MINSTREL_FRAC(rate2->success, rate2->attempts) <
|
||||||
|
- MINSTREL_FRAC(20, 100)) {
|
||||||
|
- minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false);
|
||||||
|
update = true;
|
||||||
|
+ minstrel_ht_update_stats(mp, mi, false);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ if (mp->hw->max_rates > 1) {
|
||||||
|
+ /*
|
||||||
|
+ * 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[0]);
|
||||||
|
+ if (rate->attempts > 30 &&
|
||||||
|
+ MINSTREL_FRAC(rate->success, rate->attempts) <
|
||||||
|
+ MINSTREL_FRAC(20, 100)) {
|
||||||
|
+ minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true);
|
||||||
|
+ update = true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]);
|
||||||
|
+ if (rate2->attempts > 30 &&
|
||||||
|
+ MINSTREL_FRAC(rate2->success, rate2->attempts) <
|
||||||
|
+ MINSTREL_FRAC(20, 100)) {
|
||||||
|
+ minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false);
|
||||||
|
+ update = true;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_after(jiffies, mi->last_stats_update +
|
||||||
|
(mp->update_interval / 2 * HZ) / 1000)) {
|
||||||
|
update = true;
|
||||||
|
- minstrel_ht_update_stats(mp, mi);
|
||||||
|
+ minstrel_ht_update_stats(mp, mi, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update)
|
||||||
|
minstrel_ht_update_rates(mp, mi);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static inline int
|
||||||
|
-minstrel_get_duration(int index)
|
||||||
|
-{
|
||||||
|
- const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
|
||||||
|
- unsigned int duration = group->duration[index % MCS_GROUP_RATES];
|
||||||
|
- return duration << group->shift;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static void
|
||||||
|
minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
|
||||||
|
int index)
|
||||||
|
@@ -989,14 +1160,18 @@ static void
|
||||||
|
minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
|
||||||
|
{
|
||||||
|
struct ieee80211_sta_rates *rates;
|
||||||
|
+ u16 first_rate = mi->max_tp_rate[0];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
+ if (mi->sample_mode == MINSTREL_SAMPLE_ACTIVE)
|
||||||
|
+ first_rate = mi->sample_rate;
|
||||||
|
+
|
||||||
|
rates = kzalloc(sizeof(*rates), GFP_ATOMIC);
|
||||||
|
if (!rates)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Start with max_tp_rate[0] */
|
||||||
|
- minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate[0]);
|
||||||
|
+ minstrel_ht_set_rate(mp, mi, rates, i++, first_rate);
|
||||||
|
|
||||||
|
if (mp->hw->max_rates >= 3) {
|
||||||
|
/* At least 3 tx rates supported, use max_tp_rate[1] next */
|
||||||
|
@@ -1023,6 +1198,11 @@ minstrel_get_sample_rate(struct minstrel
|
||||||
|
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;
|
||||||
|
@@ -1349,7 +1529,7 @@ minstrel_ht_update_caps(void *priv, stru
|
||||||
|
mi->supported[MINSTREL_CCK_GROUP] |= mi->cck_supported_short << 4;
|
||||||
|
|
||||||
|
/* create an initial rate table with the lowest supported rates */
|
||||||
|
- minstrel_ht_update_stats(mp, mi);
|
||||||
|
+ minstrel_ht_update_stats(mp, mi, true);
|
||||||
|
minstrel_ht_update_rates(mp, mi);
|
||||||
|
|
||||||
|
return;
|
||||||
|
@@ -1467,6 +1647,8 @@ minstrel_ht_alloc(struct ieee80211_hw *h
|
||||||
|
if (!mp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
+ mp->sample_switch = -1;
|
||||||
|
+
|
||||||
|
/* contention window settings
|
||||||
|
* Just an approximation. Using the per-queue values would complicate
|
||||||
|
* the calculations and is probably unnecessary */
|
||||||
|
@@ -1498,6 +1680,8 @@ minstrel_ht_alloc(struct ieee80211_hw *h
|
||||||
|
mp->fixed_rate_idx = (u32) -1;
|
||||||
|
debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir,
|
||||||
|
&mp->fixed_rate_idx);
|
||||||
|
+ debugfs_create_u32("sample_switch", S_IRUGO | S_IWUSR, debugfsdir,
|
||||||
|
+ &mp->sample_switch);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
minstrel_ht_init_cck_rates(mp);
|
||||||
|
--- a/net/mac80211/rc80211_minstrel_ht.h
|
||||||
|
+++ b/net/mac80211/rc80211_minstrel_ht.h
|
||||||
|
@@ -36,6 +36,7 @@ struct mcs_group {
|
||||||
|
u16 flags;
|
||||||
|
u8 streams;
|
||||||
|
u8 shift;
|
||||||
|
+ u8 bw;
|
||||||
|
u16 duration[MCS_GROUP_RATES];
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -53,6 +54,12 @@ struct minstrel_mcs_group_data {
|
||||||
|
struct minstrel_rate_stats rates[MCS_GROUP_RATES];
|
||||||
|
};
|
||||||
|
|
||||||
|
+enum minstrel_sample_mode {
|
||||||
|
+ MINSTREL_SAMPLE_IDLE,
|
||||||
|
+ MINSTREL_SAMPLE_ACTIVE,
|
||||||
|
+ MINSTREL_SAMPLE_PENDING,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
struct minstrel_ht_sta {
|
||||||
|
struct ieee80211_sta *sta;
|
||||||
|
|
||||||
|
@@ -74,6 +81,8 @@ struct minstrel_ht_sta {
|
||||||
|
unsigned int overhead;
|
||||||
|
unsigned int overhead_rtscts;
|
||||||
|
|
||||||
|
+ unsigned int total_packets_last;
|
||||||
|
+ unsigned int total_packets_cur;
|
||||||
|
unsigned int total_packets;
|
||||||
|
unsigned int sample_packets;
|
||||||
|
|
||||||
|
@@ -85,6 +94,9 @@ struct minstrel_ht_sta {
|
||||||
|
u8 sample_count;
|
||||||
|
u8 sample_slow;
|
||||||
|
|
||||||
|
+ enum minstrel_sample_mode sample_mode;
|
||||||
|
+ u16 sample_rate;
|
||||||
|
+
|
||||||
|
/* current MCS group to be sampled */
|
||||||
|
u8 sample_group;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user