This patch fixes a couple of issues in the VHT rate adaptation code,
and with the data which iwm(4) is feeding into it.
Testing 11ac mode from a distance to my AP, I found that iwm(4) tends
to pick a Tx rate which is too high, resulting in too much of a drop
in throughput.
With this patch, iwm(4) hovers around VHT-MCS4 or VHT-MCS5, instead of
trying to reach the AP on VHT-MCS8 or VHT-MCS9 with heavy retries.
Effective throughput changes from 30Mbit/s to about 100Mbit/s, though
the rate is a bit jumpy and less stable than from a short distance.
A quick test suggests that this patch improves the effective data rate
at a short distance, too.
iwm(4) didn't attribute retries to the correct MCS, resulting in lower
MCS being punished unfairly while a higher MCS keeps failing.
This is what made us pick an Tx that is too high.
Another bug is that we didn't actually set rn->best_nss after deciding
on a new best rate. ieee80211_ra_vht_best_rate() would have to return
two values (mcs, nss), so just make it avoid and let it set rn->best_mcs
and rn->best_nss directly. With this, we are switching between SISO and
MIMO rates as intended.
When switching between ratesets, avoid switching directly to the highest
rate in the new rateset, which might be MCS 9 and not work at all from a
distance. Instead, use the most recently determined best rate in the set.
I plan to make this change in ieee80211_ra.c for 11n mode as well.
A non-obvious fix involves the rn->probed_rates[] array.
The bit which corresponds to the current best MS will not be set in
this array while we are probing an MCS other than the best.
So checking for this bit is simply wrong and prevents us from probing
the next rateset unless we manage to successfully probe up all the way
to MCS 9 in the current set.
This fix might also be needed in ieee80211_ra.c for 11n mode, but I will
deal with this later.
ok?
diff f186611d55a60b95262b00c94ece78add3698ea8
f5d662f7a36c876abaa8b0987deef01a3fa99b0f
blob - ed592c9012b6ed157d2ab3457d6894f0e68a4f50
blob + ad7e788d6aace58e20247e5c522622e84c649667
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -5532,6 +5532,8 @@ iwm_vht_single_rate_control(struct iwm_softc *sc, stru
{
struct ieee80211com *ic = &sc->sc_ic;
struct iwm_node *in = (void *)ni;
+ uint8_t vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_80;
+ uint8_t sco = IEEE80211_HTOP0_SCO_SCN;
/* Ignore Tx reports which don't match our last LQ command. */
if (txmcs != ni->ni_txmcs || nss != ni->ni_vht_ss) {
@@ -5544,13 +5546,34 @@ iwm_vht_single_rate_control(struct iwm_softc *sc, stru
int mcs = txmcs;
unsigned int retries = 0, i;
+ if (in->in_phyctxt) {
+ vht_chan_width = in->in_phyctxt->vht_chan_width;
+ sco = in->in_phyctxt->sco;
+ }
in->lq_rate_mismatch = 0;
for (i = 0; i < failure_frame; i++) {
if (mcs > 0) {
ieee80211_ra_vht_add_stats(&in->in_rn_vht,
ic, ni, mcs, nss, 1, 1);
- mcs--;
+ if (vht_chan_width >=
+ IEEE80211_VHTOP0_CHAN_WIDTH_80) {
+ /*
+ * First 4 Tx attempts used same MCS,
+ * twice at 80MHz and twice at 40MHz.
+ */
+ if (i >= 4)
+ mcs--;
+ } else if (sco == IEEE80211_HTOP0_SCO_SCA ||
+ sco == IEEE80211_HTOP0_SCO_SCB) {
+ /*
+ * First 4 Tx attempts used same MCS,
+ * four times at 40MHz.
+ */
+ if (i >= 4)
+ mcs--;
+ } else
+ mcs--;
} else
retries++;
}
@@ -9234,7 +9257,7 @@ iwm_set_rate_table_vht(struct iwm_node *in, struct iwm
}
/*
- * First two Tx attempts may use 80MHz/SGI.
+ * First two Tx attempts may use 80MHz/40MHz/SGI.
* Next two Tx attempts may use 40MHz/SGI.
* Beyond that use 20 MHz and decrease the rate.
* As a special case, MCS 9 is invalid on 20 Mhz.
@@ -9257,7 +9280,7 @@ iwm_set_rate_table_vht(struct iwm_node *in, struct iwm
tab |= IWM_RATE_MCS_RTS_REQUIRED_MSK;
if (ieee80211_ra_vht_use_sgi(ni))
tab |= IWM_RATE_MCS_SGI_MSK;
- } else if (i >= 2 && i < 4 &&
+ } else if (i < 4 &&
in->in_phyctxt->vht_chan_width >=
IEEE80211_VHTOP0_CHAN_WIDTH_HT &&
(in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCA ||
blob - 643664673d3a82e17235a9545b770c95935db29c
blob + 981538a62e7185c1f05b874f5b0f21a3e35de3b2
--- sys/net80211/ieee80211_ra_vht.c
+++ sys/net80211/ieee80211_ra_vht.c
@@ -48,7 +48,7 @@ void ieee80211_ra_vht_trigger_next_rateset(struct ieee
struct ieee80211_node *);
int ieee80211_ra_vht_inter_mode_ra_finished(
struct ieee80211_ra_vht_node *, struct ieee80211_node *);
-int ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_node *,
+void ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_node *,
struct ieee80211_node *);
void ieee80211_ra_vht_probe_next_rate(struct ieee80211_ra_vht_node *,
struct ieee80211_node *);
@@ -330,9 +330,9 @@ ieee80211_ra_vht_probe_next_rateset(struct ieee80211_r
break;
}
}
- /* If all rates are lower the maximum rate is the closest match. */
+ /* If all rates are lower then the best rate is the closest match. */
if (mcs == rsnext->nrates)
- ni->ni_txmcs = rn->max_mcs[rsnext->num_ss - 1];
+ ni->ni_txmcs = ieee80211_ra_vht_best_mcs_in_rateset(rn, rsnext);
/* Add rates from the next rateset as candidates. */
rn->candidate_rates[rsnext->num_ss - 1] |= (1 << ni->ni_txmcs);
@@ -427,8 +427,7 @@ ieee80211_ra_vht_intra_mode_ra_finished(struct ieee802
/* Check if we had a better measurement at a previously probed MCS. */
best_mcs = ieee80211_ra_vht_best_mcs_in_rateset(rn, rs);
- if (best_mcs != ni->ni_txmcs &&
- (rn->probed_rates[nss - 1] & (1 << best_mcs))) {
+ if (best_mcs != ni->ni_txmcs) {
if ((rn->probing & IEEE80211_RA_PROBING_UP) &&
best_mcs < ni->ni_txmcs) {
ieee80211_ra_vht_trigger_next_rateset(rn, ni);
@@ -473,7 +472,7 @@ ieee80211_ra_vht_inter_mode_ra_finished(struct ieee802
return ((rn->probing & IEEE80211_RA_PROBING_INTER) == 0);
}
-int
+void
ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_node *rn,
struct ieee80211_node *ni)
{
@@ -505,13 +504,16 @@ ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_nod
best_mcs, best_nss));
for (i = 0; i < IEEE80211_VHT_NUM_RATESETS; i++) {
rs = &ieee80211_std_ratesets_11ac[i];
+ if (rs->chan80 == 0 ||
+ rs->sgi != ieee80211_ra_vht_use_sgi(ni))
+ continue;
for (j = 0; j < IEEE80211_VHT_RATESET_MAX_NRATES; j++) {
struct ieee80211_ra_vht_goodput_stats *g;
g = &rn->g[i][j];
if ((rn->valid_rates[rs->num_ss - 1] &
- (1 << i)) == 0)
+ (1 << j)) == 0)
continue;
- DPRINTF((" %d,%d{%s|", i, j,
+ DPRINTF((" %d,%d{%s|", j, rs->num_ss,
ra_vht_fp_sprintf(g->measured)));
DPRINTF(("%s|", ra_vht_fp_sprintf(g->average)));
DPRINTF(("%s%%}", ra_vht_fp_sprintf(g->loss)));
@@ -520,7 +522,8 @@ ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_nod
DPRINTF(("\n"));
}
#endif
- return best_mcs;
+ rn->best_mcs = best_mcs;
+ rn->best_nss = best_nss;
}
void
@@ -671,7 +674,7 @@ ieee80211_ra_vht_choose(struct ieee80211_ra_vht_node *
DPRINTFN(3, ("probing MCS,NSS %d,%d\n",
ni->ni_txmcs, ni->ni_vht_ss));
} else if (ieee80211_ra_vht_inter_mode_ra_finished(rn, ni)) {
- rn->best_mcs = ieee80211_ra_vht_best_rate(rn, ni);
+ ieee80211_ra_vht_best_rate(rn, ni);
ni->ni_txmcs = rn->best_mcs;
ni->ni_vht_ss = rn->best_nss;
ieee80211_ra_vht_probe_done(rn, nss);