iwm adjusts the firmware's Tx rate retry table dynamically such
that the first slot in this table always reflects the current
rate chosen by AMRR.
The table starts off looking like this:
0 1 n-2 n-1 n
MCS 0, MCS 0, ..., MCS 0, CCK 2, CCK 1
(On 5GHz, the lowest rate is OFDM 6 rather than CCK 1.)
As AMRR raises the desired Tx rate to say, MCS 4, we fill in
the higher rates at the front:
0 1 n-2 n-1 n
MCS 4, MCS 3, ..., MCS 1, MCS 0, CCK 2
However, the code calculating the first slot the firmware shall
use when sending a data frame still assumes a static layout and
points the firmware at slot number 'n - 1 - r' for rate r.
So for rates other than MCS 7 and OFDM 54 the firmware starts
transmitting on a fallback rate rather than the rate chosen by AMRR.
Fix this by always pointing the firmware at the first slot:
Index: if_iwm.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
retrieving revision 1.71
diff -u -p -r1.71 if_iwm.c
--- if_iwm.c 14 Dec 2015 08:34:56 -0000 1.71
+++ if_iwm.c 5 Jan 2016 13:32:24 -0000
@@ -3867,13 +3867,7 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, st
ridx = sc->sc_fixed_ridx;
} else {
/* for data frames, use RS table */
-#ifndef IEEE80211_NO_HT
- if (ni->ni_flags & IEEE80211_NODE_HT) {
- tx->initial_rate_index =
- (nitems(iwm_mcs2ridx) - 1) - ni->ni_txmcs;
- } else
-#endif
- tx->initial_rate_index = (nrates - 1) - ni->ni_txrate;
+ tx->initial_rate_index = 0;
tx->tx_flags |= htole32(IWM_TX_CMD_FLG_STA_RATE);
DPRINTFN(12, ("start with txrate %d\n",
tx->initial_rate_index));
#ifndef IEEE80211_NO_HT
iwn still populates this table once after association and doesn't
update it, so the table is static and always looks like this:
0 1 n-2 n-1 n
MCS 7, MCS 6, ..., MCS 0, MCS 0, MCS 0
We select a slot for the firmware to start off from based on AMRR's
current choice. This is fine for now but will have to change once we
support more MCS since the table isn't large enough for all of them
(which is why iwm already uses a dynamic scheme).
The problem I'd like to fix is that in 11n mode iwn's table currently
contains MCS 7 to 0, but no legacy rates. This will cause transmit
problems in case the environment is so noisy that MCS/OFDM won't work.
So make the firmware fall back to the lowest legacy rate if all MCS
have failed.
This means we'll fall back to CCK (11b) rates on 2GHz which may be
the only way to get data through in noisy environments (such as
the CCC congress, for instance -- hint for benno@ and phessler@).
Index: if_iwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
retrieving revision 1.149
diff -u -p -r1.149 if_iwn.c
--- if_iwn.c 4 Jan 2016 13:54:19 -0000 1.149
+++ if_iwn.c 5 Jan 2016 09:46:06 -0000
@@ -3439,9 +3439,21 @@ iwn_set_link_quality(struct iwn_softc *s
}
/* Fill the rest with MCS 0. */
rinfo = &iwn_rates[iwn_mcs2ridx[0]];
- while (i < IWN_MAX_TX_RETRIES) {
+ while (i < IWN_MAX_TX_RETRIES - 1) {
linkq.retry[i].plcp = rinfo->ht_plcp;
linkq.retry[i].rflags = rinfo->ht_flags;
+ linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant);
+ i++;
+ }
+
+ /* Fill the last slot with the lowest legacy rate. */
+ if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
+ rinfo = &iwn_rates[IWN_RIDX_OFDM6];
+ else
+ rinfo = &iwn_rates[IWN_RIDX_CCK1];
+ while (i < IWN_MAX_TX_RETRIES) {
+ linkq.retry[i].plcp = rinfo->plcp;
+ linkq.retry[i].rflags = rinfo->flags;
linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant);
i++;
}