rework iwm(4) Tx rate selection

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

rework iwm(4) Tx rate selection

Stefan Sperling-5
iwm(4) has been using a firmware-based approach to retrying failed
Tx attempts with successively lower data rates. This is suboptimal
for our kernel's Tx rate selection algorithms, which are called
MiRA (for 11n) and AMRR (for 11a/b/g).

I have observed a mismatch between the Tx rate reported by ifconfig iwm0
and the Rx rate reported at the receiving end, and this diff fixes
that issue for me.

Because iwm firmware retries on lower rates, our own rate selection
is fooled into believing that high rates succeed when they in fact
don't succeed. This causes more Tx retries than necessary, which
results in lower throughput than we could achieve otherwise.

With the diff below we instead ask the firmware to always keep retrying
at a constant Tx rate. This provides more accurate feedback to MiRa and
AMRR, which are then able to select an initial Tx rate which is more
likely to succeed.

However, there is another reason why we were using firmware-based retries.
In 11n mode, net80211 only knows about rates which are based on OFDM.
On 2GHz channels, the older CCK modulation provides a larger range and can
thus make the difference between a bad network connection and no network
connection at all. We were relying on the firmware to retry with CCK if
OFDM frames failed so I had to implement a similar strategy in the driver.
This is achived by falling back to CCK rates and running AMRR instead of
MiRA if the lowest OFDM rate is failing, until AMRR decides to start using
OFDM again, and then switch back to OFDM + MiRA. Getting the driver to switch
back to OFDM once it is using CCK wasn't straightforward. I eventually found
out that feeding only actual Tx failures to AMRR makes this work well.

I had to remove 11n support from AMRR which interfered with this fallback.
This is overdue anyway since all drivers are using MiRa in 11n mode now.

When testing this, please compare throughput before and after this diff.
I run tcpbench -s on a host behind the AP and start a tcpbench client on
my iwm laptop. With this diff, and an 11ac AP on channel 149, tcpbench
measures up to 26 Mpbs in my environment, with an average rate above 20 Mbps.

Also pay attention to changes in latency. To test this, on my iwm laptop
I run ping and rain(6) through an SSH connection to a machine behind the AP.

Tested on a 7265 device only so far.

iwn(4) has the same problem and should also be fixed once this change
has made it into the tree.

diff 3cfc9cae129c023be655a6d31902cddd094fdec4 /usr/src
blob - 45e4446d79d2da0f847170e34b9a01e25b71ea62
file + sys/dev/pci/if_iwm.c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -217,6 +217,7 @@ const struct iwm_rate {
 #define IWM_RIDX_MAX (nitems(iwm_rates)-1)
 #define IWM_RIDX_IS_CCK(_i_) ((_i_) < IWM_RIDX_OFDM)
 #define IWM_RIDX_IS_OFDM(_i_) ((_i_) >= IWM_RIDX_OFDM)
+#define IWM_RVAL_IS_OFDM(_i_) ((_i_) >= 12 && (_i_) != 22)
 
 /* Convert an MCS index into an iwm_rates[] index. */
 const int iwm_mcs2ridx[] = {
@@ -368,6 +369,7 @@ void iwm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_
 int iwm_get_noise(const struct iwm_statistics_rx_non_phy *);
 void iwm_rx_rx_mpdu(struct iwm_softc *, struct iwm_rx_packet *,
     struct iwm_rx_data *);
+void iwm_enable_ht_cck_fallback(struct iwm_softc *, struct iwm_node *);
 void iwm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *,
     struct iwm_node *);
 void iwm_rx_tx_cmd(struct iwm_softc *, struct iwm_rx_packet *,
@@ -447,7 +449,6 @@ int iwm_run(struct iwm_softc *);
 int iwm_run_stop(struct iwm_softc *);
 struct ieee80211_node *iwm_node_alloc(struct ieee80211com *);
 void iwm_calib_timeout(void *);
-void iwm_setrates(struct iwm_node *);
 int iwm_media_change(struct ifnet *);
 void iwm_newstate_task(void *);
 int iwm_newstate(struct ieee80211com *, enum ieee80211_state, int);
@@ -3574,6 +3575,37 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_pac
 }
 
 void
+iwm_enable_ht_cck_fallback(struct iwm_softc *sc, struct iwm_node *in)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_node *ni = &in->in_ni;
+ struct ieee80211_rateset *rs = &ni->ni_rates;
+ uint8_t rval = (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL);
+ uint8_t min_rval = ieee80211_min_basic_rate(ic);
+ int i;
+
+ /* Are CCK frames forbidden in our BSS? */
+ if (IWM_RVAL_IS_OFDM(min_rval))
+ return;
+
+ in->ht_force_cck = 1;
+
+ ieee80211_mira_cancel_timeouts(&in->in_mn);
+ ieee80211_mira_node_init(&in->in_mn);
+ ieee80211_amrr_node_init(&sc->sc_amrr, &in->in_amn);
+
+ /* Choose initial CCK Tx rate. */
+ ni->ni_txrate = 0;
+ for (i = 0; i < rs->rs_nrates; i++) {
+ rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL);
+ if (rval == min_rval) {
+ ni->ni_txrate = i;
+ break;
+ }
+ }
+}
+
+void
 iwm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
     struct iwm_node *in)
 {
@@ -3590,12 +3622,18 @@ iwm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_
     status != IWM_TX_STATUS_DIRECT_DONE);
 
  /* Update rate control statistics. */
- if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) {
+ if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 || in->ht_force_cck) {
  in->in_amn.amn_txcnt++;
- if (tx_resp->failure_frame > 0)
+ if (in->ht_force_cck) {
+ /*
+ * We want to move back to OFDM quickly if possible.
+ * Only show actual Tx failures to AMRR, not retries.
+ */
+ if (txfail)
+ in->in_amn.amn_retrycnt++;
+ } else if (tx_resp->failure_frame > 0)
  in->in_amn.amn_retrycnt++;
  } else if (ic->ic_fixed_mcs == -1) {
- int omcs = ni->ni_txmcs;
  in->in_mn.frames += tx_resp->frame_count;
  in->in_mn.ampdu_size = le16toh(tx_resp->byte_cnt);
  in->in_mn.agglen = tx_resp->frame_count;
@@ -3603,14 +3641,16 @@ iwm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_
  in->in_mn.retries += tx_resp->failure_frame;
  if (txfail)
  in->in_mn.txfail += tx_resp->frame_count;
- if (ic->ic_state == IEEE80211_S_RUN)
+ if (ic->ic_state == IEEE80211_S_RUN && !in->ht_force_cck) {
+ int otxmcs = ni->ni_txmcs;
+
  ieee80211_mira_choose(&in->in_mn, ic, &in->in_ni);
- /*
- * If MiRA has chosen a new TX rate we must update
- * the firwmare's LQ rate table from process context.
- */
- if (omcs != ni->ni_txmcs)
- iwm_add_task(sc, systq, &sc->setrates_task);
+
+ /* Fall back to CCK rates if MCS 0 is failing. */
+ if (txfail && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) &&
+    otxmcs == 0 && ni->ni_txmcs == 0)
+ iwm_enable_ht_cck_fallback(sc, in);
+ }
  }
 
  if (txfail)
@@ -4112,41 +4152,32 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ieee80211_node *ni = &in->in_ni;
+ struct ieee80211_rateset *rs = &ni->ni_rates;
  const struct iwm_rate *rinfo;
  int type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
- int ridx, rate_flags, i;
- int nrates = ni->ni_rates.rs_nrates;
+ int min_ridx = iwm_rval2ridx(ieee80211_min_basic_rate(ic));
+ int ridx, rate_flags;
 
  tx->rts_retry_limit = IWM_RTS_DFAULT_RETRY_LIMIT;
- tx->data_retry_limit = IWM_DEFAULT_TX_RETRY;
+ tx->data_retry_limit = IWM_LOW_RETRY_LIMIT;
 
  if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
     type != IEEE80211_FC0_TYPE_DATA) {
  /* for non-data, use the lowest supported rate */
- ridx = iwm_rval2ridx(ieee80211_min_basic_rate(ic));
+ ridx = min_ridx;
  tx->data_retry_limit = IWM_MGMT_DFAULT_RETRY_LIMIT;
  } else if (ic->ic_fixed_mcs != -1) {
  ridx = sc->sc_fixed_ridx;
  } else if (ic->ic_fixed_rate != -1) {
  ridx = sc->sc_fixed_ridx;
+ } else if ((ni->ni_flags & IEEE80211_NODE_HT) && !in->ht_force_cck) {
+ ridx = iwm_mcs2ridx[ni->ni_txmcs];
  } else {
- /* for data frames, use RS table */
- tx->initial_rate_index = 0;
- tx->tx_flags |= htole32(IWM_TX_CMD_FLG_STA_RATE);
- if (ni->ni_flags & IEEE80211_NODE_HT) {
- ridx = iwm_mcs2ridx[ni->ni_txmcs];
- return &iwm_rates[ridx];
- }
- ridx = (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) ?
-    IWM_RIDX_OFDM : IWM_RIDX_CCK;
- for (i = 0; i < nrates; i++) {
- if (iwm_rates[i].rate == (ni->ni_txrate &
-    IEEE80211_RATE_VAL)) {
- ridx = i;
- break;
- }
- }
- return &iwm_rates[ridx];
+ uint8_t rval;
+ rval = (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL);
+ ridx = iwm_rval2ridx(rval);
+ if (ridx < min_ridx)
+ ridx = min_ridx;
  }
 
  rinfo = &iwm_rates[ridx];
@@ -4228,7 +4259,7 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ie
  if ((ni->ni_flags & IEEE80211_NODE_HT) &&
     !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
     type == IEEE80211_FC0_TYPE_DATA &&
-    rinfo->plcp == IWM_RATE_INVM_PLCP) {
+    rinfo->ht_plcp != IWM_RATE_HT_SISO_MCS_INV_PLCP) {
  tap->wt_rate = (0x80 | rinfo->ht_plcp);
  } else
  tap->wt_rate = rinfo->rate;
@@ -5172,6 +5203,8 @@ iwm_rval2ridx(int rval)
  int ridx;
 
  for (ridx = 0; ridx < nitems(iwm_rates); ridx++) {
+ if (iwm_rates[ridx].plcp == IWM_RATE_INVM_PLCP)
+ continue;
  if (rval == iwm_rates[ridx].rate)
  break;
  }
@@ -5837,7 +5870,6 @@ iwm_run(struct iwm_softc *sc)
  /* Start at lowest available bit-rate, AMRR will raise. */
  in->in_ni.ni_txrate = 0;
  in->in_ni.ni_txmcs = 0;
- iwm_setrates(in);
 
  timeout_add_msec(&sc->sc_calib_to, 500);
  iwm_led_enable(sc);
@@ -5900,159 +5932,27 @@ iwm_calib_timeout(void *arg)
  struct ieee80211com *ic = &sc->sc_ic;
  struct iwm_node *in = (void *)ic->ic_bss;
  struct ieee80211_node *ni = &in->in_ni;
- int s, otxrate;
+ int s;
 
  s = splnet();
  if ((ic->ic_fixed_rate == -1 || ic->ic_fixed_mcs == -1) &&
-    ((ni->ni_flags & IEEE80211_NODE_HT) == 0) &&
+    ((ni->ni_flags & IEEE80211_NODE_HT) == 0 || in->ht_force_cck) &&
     ic->ic_opmode == IEEE80211_M_STA && ic->ic_bss) {
- otxrate = ni->ni_txrate;
  ieee80211_amrr_choose(&sc->sc_amrr, &in->in_ni, &in->in_amn);
- /*
- * If AMRR has chosen a new TX rate we must update
- * the firwmare's LQ rate table from process context.
- */
- if (otxrate != ni->ni_txrate)
- iwm_add_task(sc, systq, &sc->setrates_task);
+ if (in->ht_force_cck) {
+ struct ieee80211_rateset *rs = &ni->ni_rates;
+ uint8_t rv;
+ rv = (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL);
+ if (IWM_RVAL_IS_OFDM(rv))
+ in->ht_force_cck = 0;
+ }
  }
+
  splx(s);
 
  timeout_add_msec(&sc->sc_calib_to, 500);
 }
 
-void
-iwm_setrates_task(void *arg)
-{
- struct iwm_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
- struct iwm_node *in = (struct iwm_node *)ic->ic_bss;
- int s = splnet();
-
- if (sc->sc_flags & IWM_FLAG_SHUTDOWN) {
- refcnt_rele_wake(&sc->task_refs);
- splx(s);
- return;
- }
-
- /* Update rates table based on new TX rate determined by AMRR. */
- iwm_setrates(in);
- refcnt_rele_wake(&sc->task_refs);
- splx(s);
-}
-
-void
-iwm_setrates(struct iwm_node *in)
-{
- struct ieee80211_node *ni = &in->in_ni;
- struct ieee80211com *ic = ni->ni_ic;
- struct iwm_softc *sc = IC2IFP(ic)->if_softc;
- struct iwm_lq_cmd *lq = &in->in_lq;
- struct ieee80211_rateset *rs = &ni->ni_rates;
- int i, ridx, ridx_min, ridx_max, j, sgi_ok = 0, mimo, tab = 0;
- struct iwm_host_cmd cmd = {
- .id = IWM_LQ_CMD,
- .len = { sizeof(in->in_lq), },
- };
-
- memset(lq, 0, sizeof(*lq));
- lq->sta_id = IWM_STATION_ID;
-
- if (ic->ic_flags & IEEE80211_F_USEPROT)
- lq->flags |= IWM_LQ_FLAG_USE_RTS_MSK;
-
- if ((ni->ni_flags & IEEE80211_NODE_HT) &&
-    ieee80211_node_supports_ht_sgi20(ni)) {
- ni->ni_flags |= IEEE80211_NODE_HT_SGI20;
- sgi_ok = 1;
- }
-
- /*
- * Fill the LQ rate selection table with legacy and/or HT rates
- * in descending order, i.e. with the node's current TX rate first.
- * In cases where throughput of an HT rate corresponds to a legacy
- * rate it makes no sense to add both. We rely on the fact that
- * iwm_rates is laid out such that equivalent HT/legacy rates share
- * the same IWM_RATE_*_INDEX value. Also, rates not applicable to
- * legacy/HT are assumed to be marked with an 'invalid' PLCP value.
- */
- j = 0;
- ridx_min = iwm_rval2ridx(ieee80211_min_basic_rate(ic));
- mimo = iwm_is_mimo_mcs(ni->ni_txmcs);
- ridx_max = (mimo ? IWM_RIDX_MAX : IWM_LAST_HT_SISO_RATE);
- for (ridx = ridx_max; ridx >= ridx_min; ridx--) {
- uint8_t plcp = iwm_rates[ridx].plcp;
- uint8_t ht_plcp = iwm_rates[ridx].ht_plcp;
-
- if (j >= nitems(lq->rs_table))
- break;
- tab = 0;
- if (ni->ni_flags & IEEE80211_NODE_HT) {
-     if (ht_plcp == IWM_RATE_HT_SISO_MCS_INV_PLCP)
- continue;
- /* Do not mix SISO and MIMO HT rates. */
- if ((mimo && !iwm_is_mimo_ht_plcp(ht_plcp)) ||
-    (!mimo && iwm_is_mimo_ht_plcp(ht_plcp)))
- continue;
- for (i = ni->ni_txmcs; i >= 0; i--) {
- if (isclr(ni->ni_rxmcs, i))
- continue;
- if (ridx == iwm_mcs2ridx[i]) {
- tab = ht_plcp;
- tab |= IWM_RATE_MCS_HT_MSK;
- if (sgi_ok)
- tab |= IWM_RATE_MCS_SGI_MSK;
- break;
- }
- }
- } else if (plcp != IWM_RATE_INVM_PLCP) {
- for (i = ni->ni_txrate; i >= 0; i--) {
- if (iwm_rates[ridx].rate == (rs->rs_rates[i] &
-    IEEE80211_RATE_VAL)) {
- tab = plcp;
- break;
- }
- }
- }
-
- if (tab == 0)
- continue;
-
- if (iwm_is_mimo_ht_plcp(ht_plcp))
- tab |= IWM_RATE_MCS_ANT_AB_MSK;
- else
- tab |= IWM_RATE_MCS_ANT_A_MSK;
-
- if (IWM_RIDX_IS_CCK(ridx))
- tab |= IWM_RATE_MCS_CCK_MSK;
- lq->rs_table[j++] = htole32(tab);
- }
-
- lq->mimo_delim = (mimo ? j : 0);
-
- /* Fill the rest with the lowest possible rate */
- while (j < nitems(lq->rs_table)) {
- tab = iwm_rates[ridx_min].plcp;
- if (IWM_RIDX_IS_CCK(ridx_min))
- tab |= IWM_RATE_MCS_CCK_MSK;
- tab |= IWM_RATE_MCS_ANT_A_MSK;
- lq->rs_table[j++] = htole32(tab);
- }
-
- lq->single_stream_ant_msk = IWM_ANT_A;
- lq->dual_stream_ant_msk = IWM_ANT_AB;
-
- lq->agg_time_limit = htole16(4000); /* 4ms */
- lq->agg_disable_start_th = 3;
-#ifdef notyet
- lq->agg_frame_cnt_limit = 0x3f;
-#else
- lq->agg_frame_cnt_limit = 1; /* tx agg disabled */
-#endif
-
- cmd.data[0] = &in->in_lq;
- iwm_send_cmd(sc, &cmd);
-}
-
 int
 iwm_media_change(struct ifnet *ifp)
 {
@@ -6196,7 +6096,6 @@ iwm_newstate(struct ieee80211com *ic, enum ieee80211_s
  if (ic->ic_state == IEEE80211_S_RUN) {
  timeout_del(&sc->sc_calib_to);
  ieee80211_mira_cancel_timeouts(&in->in_mn);
- iwm_del_task(sc, systq, &sc->setrates_task);
  iwm_del_task(sc, systq, &sc->ba_task);
  iwm_del_task(sc, systq, &sc->htprot_task);
  }
@@ -6705,7 +6604,6 @@ iwm_stop(struct ifnet *ifp)
  /* Cancel scheduled tasks and let any stale tasks finish up. */
  task_del(systq, &sc->init_task);
  iwm_del_task(sc, sc->sc_nswq, &sc->newstate_task);
- iwm_del_task(sc, systq, &sc->setrates_task);
  iwm_del_task(sc, systq, &sc->ba_task);
  iwm_del_task(sc, systq, &sc->htprot_task);
  KASSERT(sc->task_refs.refs >= 1);
@@ -7895,7 +7793,6 @@ iwm_attach(struct device *parent, struct device *self,
  timeout_set(&sc->sc_led_blink_to, iwm_led_blink_timeout, sc);
  task_set(&sc->init_task, iwm_init_task, sc);
  task_set(&sc->newstate_task, iwm_newstate_task, sc);
- task_set(&sc->setrates_task, iwm_setrates_task, sc);
  task_set(&sc->ba_task, iwm_ba_task, sc);
  task_set(&sc->htprot_task, iwm_htprot_task, sc);
 
blob - 7e35820c7ceb997683c3c0c0e1da1112290c38cd
file + sys/dev/pci/if_iwmvar.h
--- sys/dev/pci/if_iwmvar.h
+++ sys/dev/pci/if_iwmvar.h
@@ -509,9 +509,12 @@ struct iwm_node {
  uint16_t in_id;
  uint16_t in_color;
 
- struct iwm_lq_cmd in_lq;
  struct ieee80211_amrr_node in_amn;
  struct ieee80211_mira_node in_mn;
+
+ /* Set in 11n mode if we don't receive ACKs for OFDM frames. */
+ int ht_force_cck;
+
 };
 #define IWM_STATION_ID 0
 #define IWM_AUX_STA_ID 1
blob - 2daf18ca6aed42bfded73d204690736ca6a4ae5e
file + sys/net80211/ieee80211_amrr.c
--- sys/net80211/ieee80211_amrr.c
+++ sys/net80211/ieee80211_amrr.c
@@ -41,45 +41,28 @@
 #define reset_cnt(amn) \
  do { (amn)->amn_txcnt = (amn)->amn_retrycnt = 0; } while (0)
 
-/*
- * XXX In HT mode we only support MCS 0-7, for now.
- * Beyond MCS 7, incrementing the MCS index does not imply a
- * higher data rate, so this simple implementation will need
- * to be enhanced.
- */
-
 static inline int
 is_min_rate(struct ieee80211_node *ni)
 {
- if (ni->ni_flags & IEEE80211_NODE_HT)
- return (ni->ni_txmcs == 0);
  return (ni->ni_txrate == 0);
 }
 
 static inline int
 is_max_rate(struct ieee80211_node *ni)
 {
- if (ni->ni_flags & IEEE80211_NODE_HT)
- return (ni->ni_txmcs == 7); /* XXX up to MCS 7 only */
  return (ni->ni_txrate == ni->ni_rates.rs_nrates - 1);
 }
 
 static inline void
 increase_rate(struct ieee80211_node *ni)
 {
- if (ni->ni_flags & IEEE80211_NODE_HT)
- ni->ni_txmcs++;
- else
- ni->ni_txrate++;
+ ni->ni_txrate++;
 }
 
 static inline void
 decrease_rate(struct ieee80211_node *ni)
 {
- if (ni->ni_flags & IEEE80211_NODE_HT)
- ni->ni_txmcs--;
- else
- ni->ni_txrate--;
+ ni->ni_txrate--;
 }
 
 void
@@ -110,7 +93,6 @@ ieee80211_amrr_choose(struct ieee80211_amrr *amrr, str
  amn->amn_success = 0;
  increase_rate(ni);
  DPRINTF(("increase rate=%d,#tx=%d,#retries=%d\n",
-    (ni->ni_flags & IEEE80211_NODE_HT) ? ni->ni_txmcs :
     RV(ni->ni_rates.rs_rates[ni->ni_txrate]),
     amn->amn_txcnt, amn->amn_retrycnt));
  need_change = 1;
@@ -132,7 +114,6 @@ ieee80211_amrr_choose(struct ieee80211_amrr *amrr, str
  }
  decrease_rate(ni);
  DPRINTF(("decrease rate=%d,#tx=%d,#retries=%d\n",
-    (ni->ni_flags & IEEE80211_NODE_HT) ? ni->ni_txmcs :
     RV(ni->ni_rates.rs_rates[ni->ni_txrate]),
     amn->amn_txcnt, amn->amn_retrycnt));
  need_change = 1;




Reply | Threaded
Open this post in threaded view
|

Re: rework iwm(4) Tx rate selection

Solene Rapenne
On Wed, Feb 20, 2019 at 04:04:13PM +0100, Stefan Sperling wrote:

> iwm(4) has been using a firmware-based approach to retrying failed
> Tx attempts with successively lower data rates. This is suboptimal
> for our kernel's Tx rate selection algorithms, which are called
> MiRA (for 11n) and AMRR (for 11a/b/g).
>
> I have observed a mismatch between the Tx rate reported by ifconfig iwm0
> and the Rx rate reported at the receiving end, and this diff fixes
> that issue for me.
>
> Because iwm firmware retries on lower rates, our own rate selection
> is fooled into believing that high rates succeed when they in fact
> don't succeed. This causes more Tx retries than necessary, which
> results in lower throughput than we could achieve otherwise.
>
> With the diff below we instead ask the firmware to always keep retrying
> at a constant Tx rate. This provides more accurate feedback to MiRa and
> AMRR, which are then able to select an initial Tx rate which is more
> likely to succeed.
>
> However, there is another reason why we were using firmware-based retries.
> In 11n mode, net80211 only knows about rates which are based on OFDM.
> On 2GHz channels, the older CCK modulation provides a larger range and can
> thus make the difference between a bad network connection and no network
> connection at all. We were relying on the firmware to retry with CCK if
> OFDM frames failed so I had to implement a similar strategy in the driver.
> This is achived by falling back to CCK rates and running AMRR instead of
> MiRA if the lowest OFDM rate is failing, until AMRR decides to start using
> OFDM again, and then switch back to OFDM + MiRA. Getting the driver to switch
> back to OFDM once it is using CCK wasn't straightforward. I eventually found
> out that feeding only actual Tx failures to AMRR makes this work well.
>
> I had to remove 11n support from AMRR which interfered with this fallback.
> This is overdue anyway since all drivers are using MiRa in 11n mode now.
>
> When testing this, please compare throughput before and after this diff.
> I run tcpbench -s on a host behind the AP and start a tcpbench client on
> my iwm laptop. With this diff, and an 11ac AP on channel 149, tcpbench
> measures up to 26 Mpbs in my environment, with an average rate above 20 Mbps.
>
> Also pay attention to changes in latency. To test this, on my iwm laptop
> I run ping and rain(6) through an SSH connection to a machine behind the AP.
>
> Tested on a 7265 device only so far.
>
> iwn(4) has the same problem and should also be fixed once this change
> has made it into the tree.
>
> diff 3cfc9cae129c023be655a6d31902cddd094fdec4 /usr/src
> blob - 45e4446d79d2da0f847170e34b9a01e25b71ea62
> file + sys/dev/pci/if_iwm.c
> --- sys/dev/pci/if_iwm.c
> +++ sys/dev/pci/if_iwm.c
> @@ -217,6 +217,7 @@ const struct iwm_rate {
>  #define IWM_RIDX_MAX (nitems(iwm_rates)-1)
>  #define IWM_RIDX_IS_CCK(_i_) ((_i_) < IWM_RIDX_OFDM)
>  #define IWM_RIDX_IS_OFDM(_i_) ((_i_) >= IWM_RIDX_OFDM)
> +#define IWM_RVAL_IS_OFDM(_i_) ((_i_) >= 12 && (_i_) != 22)
>  
>  /* Convert an MCS index into an iwm_rates[] index. */
>  const int iwm_mcs2ridx[] = {
> @@ -368,6 +369,7 @@ void iwm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_
>  int iwm_get_noise(const struct iwm_statistics_rx_non_phy *);
>  void iwm_rx_rx_mpdu(struct iwm_softc *, struct iwm_rx_packet *,
>      struct iwm_rx_data *);
> +void iwm_enable_ht_cck_fallback(struct iwm_softc *, struct iwm_node *);
>  void iwm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *,
>      struct iwm_node *);
>  void iwm_rx_tx_cmd(struct iwm_softc *, struct iwm_rx_packet *,
> @@ -447,7 +449,6 @@ int iwm_run(struct iwm_softc *);
>  int iwm_run_stop(struct iwm_softc *);
>  struct ieee80211_node *iwm_node_alloc(struct ieee80211com *);
>  void iwm_calib_timeout(void *);
> -void iwm_setrates(struct iwm_node *);
>  int iwm_media_change(struct ifnet *);
>  void iwm_newstate_task(void *);
>  int iwm_newstate(struct ieee80211com *, enum ieee80211_state, int);
> @@ -3574,6 +3575,37 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_pac
>  }
>  
>  void
> +iwm_enable_ht_cck_fallback(struct iwm_softc *sc, struct iwm_node *in)
> +{
> + struct ieee80211com *ic = &sc->sc_ic;
> + struct ieee80211_node *ni = &in->in_ni;
> + struct ieee80211_rateset *rs = &ni->ni_rates;
> + uint8_t rval = (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL);
> + uint8_t min_rval = ieee80211_min_basic_rate(ic);
> + int i;
> +
> + /* Are CCK frames forbidden in our BSS? */
> + if (IWM_RVAL_IS_OFDM(min_rval))
> + return;
> +
> + in->ht_force_cck = 1;
> +
> + ieee80211_mira_cancel_timeouts(&in->in_mn);
> + ieee80211_mira_node_init(&in->in_mn);
> + ieee80211_amrr_node_init(&sc->sc_amrr, &in->in_amn);
> +
> + /* Choose initial CCK Tx rate. */
> + ni->ni_txrate = 0;
> + for (i = 0; i < rs->rs_nrates; i++) {
> + rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL);
> + if (rval == min_rval) {
> + ni->ni_txrate = i;
> + break;
> + }
> + }
> +}
> +
> +void
>  iwm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
>      struct iwm_node *in)
>  {
> @@ -3590,12 +3622,18 @@ iwm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_
>      status != IWM_TX_STATUS_DIRECT_DONE);
>  
>   /* Update rate control statistics. */
> - if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) {
> + if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 || in->ht_force_cck) {
>   in->in_amn.amn_txcnt++;
> - if (tx_resp->failure_frame > 0)
> + if (in->ht_force_cck) {
> + /*
> + * We want to move back to OFDM quickly if possible.
> + * Only show actual Tx failures to AMRR, not retries.
> + */
> + if (txfail)
> + in->in_amn.amn_retrycnt++;
> + } else if (tx_resp->failure_frame > 0)
>   in->in_amn.amn_retrycnt++;
>   } else if (ic->ic_fixed_mcs == -1) {
> - int omcs = ni->ni_txmcs;
>   in->in_mn.frames += tx_resp->frame_count;
>   in->in_mn.ampdu_size = le16toh(tx_resp->byte_cnt);
>   in->in_mn.agglen = tx_resp->frame_count;
> @@ -3603,14 +3641,16 @@ iwm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_
>   in->in_mn.retries += tx_resp->failure_frame;
>   if (txfail)
>   in->in_mn.txfail += tx_resp->frame_count;
> - if (ic->ic_state == IEEE80211_S_RUN)
> + if (ic->ic_state == IEEE80211_S_RUN && !in->ht_force_cck) {
> + int otxmcs = ni->ni_txmcs;
> +
>   ieee80211_mira_choose(&in->in_mn, ic, &in->in_ni);
> - /*
> - * If MiRA has chosen a new TX rate we must update
> - * the firwmare's LQ rate table from process context.
> - */
> - if (omcs != ni->ni_txmcs)
> - iwm_add_task(sc, systq, &sc->setrates_task);
> +
> + /* Fall back to CCK rates if MCS 0 is failing. */
> + if (txfail && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) &&
> +    otxmcs == 0 && ni->ni_txmcs == 0)
> + iwm_enable_ht_cck_fallback(sc, in);
> + }
>   }
>  
>   if (txfail)
> @@ -4112,41 +4152,32 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node
>  {
>   struct ieee80211com *ic = &sc->sc_ic;
>   struct ieee80211_node *ni = &in->in_ni;
> + struct ieee80211_rateset *rs = &ni->ni_rates;
>   const struct iwm_rate *rinfo;
>   int type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
> - int ridx, rate_flags, i;
> - int nrates = ni->ni_rates.rs_nrates;
> + int min_ridx = iwm_rval2ridx(ieee80211_min_basic_rate(ic));
> + int ridx, rate_flags;
>  
>   tx->rts_retry_limit = IWM_RTS_DFAULT_RETRY_LIMIT;
> - tx->data_retry_limit = IWM_DEFAULT_TX_RETRY;
> + tx->data_retry_limit = IWM_LOW_RETRY_LIMIT;
>  
>   if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
>      type != IEEE80211_FC0_TYPE_DATA) {
>   /* for non-data, use the lowest supported rate */
> - ridx = iwm_rval2ridx(ieee80211_min_basic_rate(ic));
> + ridx = min_ridx;
>   tx->data_retry_limit = IWM_MGMT_DFAULT_RETRY_LIMIT;
>   } else if (ic->ic_fixed_mcs != -1) {
>   ridx = sc->sc_fixed_ridx;
>   } else if (ic->ic_fixed_rate != -1) {
>   ridx = sc->sc_fixed_ridx;
> + } else if ((ni->ni_flags & IEEE80211_NODE_HT) && !in->ht_force_cck) {
> + ridx = iwm_mcs2ridx[ni->ni_txmcs];
>   } else {
> - /* for data frames, use RS table */
> - tx->initial_rate_index = 0;
> - tx->tx_flags |= htole32(IWM_TX_CMD_FLG_STA_RATE);
> - if (ni->ni_flags & IEEE80211_NODE_HT) {
> - ridx = iwm_mcs2ridx[ni->ni_txmcs];
> - return &iwm_rates[ridx];
> - }
> - ridx = (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) ?
> -    IWM_RIDX_OFDM : IWM_RIDX_CCK;
> - for (i = 0; i < nrates; i++) {
> - if (iwm_rates[i].rate == (ni->ni_txrate &
> -    IEEE80211_RATE_VAL)) {
> - ridx = i;
> - break;
> - }
> - }
> - return &iwm_rates[ridx];
> + uint8_t rval;
> + rval = (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL);
> + ridx = iwm_rval2ridx(rval);
> + if (ridx < min_ridx)
> + ridx = min_ridx;
>   }
>  
>   rinfo = &iwm_rates[ridx];
> @@ -4228,7 +4259,7 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ie
>   if ((ni->ni_flags & IEEE80211_NODE_HT) &&
>      !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
>      type == IEEE80211_FC0_TYPE_DATA &&
> -    rinfo->plcp == IWM_RATE_INVM_PLCP) {
> +    rinfo->ht_plcp != IWM_RATE_HT_SISO_MCS_INV_PLCP) {
>   tap->wt_rate = (0x80 | rinfo->ht_plcp);
>   } else
>   tap->wt_rate = rinfo->rate;
> @@ -5172,6 +5203,8 @@ iwm_rval2ridx(int rval)
>   int ridx;
>  
>   for (ridx = 0; ridx < nitems(iwm_rates); ridx++) {
> + if (iwm_rates[ridx].plcp == IWM_RATE_INVM_PLCP)
> + continue;
>   if (rval == iwm_rates[ridx].rate)
>   break;
>   }
> @@ -5837,7 +5870,6 @@ iwm_run(struct iwm_softc *sc)
>   /* Start at lowest available bit-rate, AMRR will raise. */
>   in->in_ni.ni_txrate = 0;
>   in->in_ni.ni_txmcs = 0;
> - iwm_setrates(in);
>  
>   timeout_add_msec(&sc->sc_calib_to, 500);
>   iwm_led_enable(sc);
> @@ -5900,159 +5932,27 @@ iwm_calib_timeout(void *arg)
>   struct ieee80211com *ic = &sc->sc_ic;
>   struct iwm_node *in = (void *)ic->ic_bss;
>   struct ieee80211_node *ni = &in->in_ni;
> - int s, otxrate;
> + int s;
>  
>   s = splnet();
>   if ((ic->ic_fixed_rate == -1 || ic->ic_fixed_mcs == -1) &&
> -    ((ni->ni_flags & IEEE80211_NODE_HT) == 0) &&
> +    ((ni->ni_flags & IEEE80211_NODE_HT) == 0 || in->ht_force_cck) &&
>      ic->ic_opmode == IEEE80211_M_STA && ic->ic_bss) {
> - otxrate = ni->ni_txrate;
>   ieee80211_amrr_choose(&sc->sc_amrr, &in->in_ni, &in->in_amn);
> - /*
> - * If AMRR has chosen a new TX rate we must update
> - * the firwmare's LQ rate table from process context.
> - */
> - if (otxrate != ni->ni_txrate)
> - iwm_add_task(sc, systq, &sc->setrates_task);
> + if (in->ht_force_cck) {
> + struct ieee80211_rateset *rs = &ni->ni_rates;
> + uint8_t rv;
> + rv = (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL);
> + if (IWM_RVAL_IS_OFDM(rv))
> + in->ht_force_cck = 0;
> + }
>   }
> +
>   splx(s);
>  
>   timeout_add_msec(&sc->sc_calib_to, 500);
>  }
>  
> -void
> -iwm_setrates_task(void *arg)
> -{
> - struct iwm_softc *sc = arg;
> - struct ieee80211com *ic = &sc->sc_ic;
> - struct iwm_node *in = (struct iwm_node *)ic->ic_bss;
> - int s = splnet();
> -
> - if (sc->sc_flags & IWM_FLAG_SHUTDOWN) {
> - refcnt_rele_wake(&sc->task_refs);
> - splx(s);
> - return;
> - }
> -
> - /* Update rates table based on new TX rate determined by AMRR. */
> - iwm_setrates(in);
> - refcnt_rele_wake(&sc->task_refs);
> - splx(s);
> -}
> -
> -void
> -iwm_setrates(struct iwm_node *in)
> -{
> - struct ieee80211_node *ni = &in->in_ni;
> - struct ieee80211com *ic = ni->ni_ic;
> - struct iwm_softc *sc = IC2IFP(ic)->if_softc;
> - struct iwm_lq_cmd *lq = &in->in_lq;
> - struct ieee80211_rateset *rs = &ni->ni_rates;
> - int i, ridx, ridx_min, ridx_max, j, sgi_ok = 0, mimo, tab = 0;
> - struct iwm_host_cmd cmd = {
> - .id = IWM_LQ_CMD,
> - .len = { sizeof(in->in_lq), },
> - };
> -
> - memset(lq, 0, sizeof(*lq));
> - lq->sta_id = IWM_STATION_ID;
> -
> - if (ic->ic_flags & IEEE80211_F_USEPROT)
> - lq->flags |= IWM_LQ_FLAG_USE_RTS_MSK;
> -
> - if ((ni->ni_flags & IEEE80211_NODE_HT) &&
> -    ieee80211_node_supports_ht_sgi20(ni)) {
> - ni->ni_flags |= IEEE80211_NODE_HT_SGI20;
> - sgi_ok = 1;
> - }
> -
> - /*
> - * Fill the LQ rate selection table with legacy and/or HT rates
> - * in descending order, i.e. with the node's current TX rate first.
> - * In cases where throughput of an HT rate corresponds to a legacy
> - * rate it makes no sense to add both. We rely on the fact that
> - * iwm_rates is laid out such that equivalent HT/legacy rates share
> - * the same IWM_RATE_*_INDEX value. Also, rates not applicable to
> - * legacy/HT are assumed to be marked with an 'invalid' PLCP value.
> - */
> - j = 0;
> - ridx_min = iwm_rval2ridx(ieee80211_min_basic_rate(ic));
> - mimo = iwm_is_mimo_mcs(ni->ni_txmcs);
> - ridx_max = (mimo ? IWM_RIDX_MAX : IWM_LAST_HT_SISO_RATE);
> - for (ridx = ridx_max; ridx >= ridx_min; ridx--) {
> - uint8_t plcp = iwm_rates[ridx].plcp;
> - uint8_t ht_plcp = iwm_rates[ridx].ht_plcp;
> -
> - if (j >= nitems(lq->rs_table))
> - break;
> - tab = 0;
> - if (ni->ni_flags & IEEE80211_NODE_HT) {
> -     if (ht_plcp == IWM_RATE_HT_SISO_MCS_INV_PLCP)
> - continue;
> - /* Do not mix SISO and MIMO HT rates. */
> - if ((mimo && !iwm_is_mimo_ht_plcp(ht_plcp)) ||
> -    (!mimo && iwm_is_mimo_ht_plcp(ht_plcp)))
> - continue;
> - for (i = ni->ni_txmcs; i >= 0; i--) {
> - if (isclr(ni->ni_rxmcs, i))
> - continue;
> - if (ridx == iwm_mcs2ridx[i]) {
> - tab = ht_plcp;
> - tab |= IWM_RATE_MCS_HT_MSK;
> - if (sgi_ok)
> - tab |= IWM_RATE_MCS_SGI_MSK;
> - break;
> - }
> - }
> - } else if (plcp != IWM_RATE_INVM_PLCP) {
> - for (i = ni->ni_txrate; i >= 0; i--) {
> - if (iwm_rates[ridx].rate == (rs->rs_rates[i] &
> -    IEEE80211_RATE_VAL)) {
> - tab = plcp;
> - break;
> - }
> - }
> - }
> -
> - if (tab == 0)
> - continue;
> -
> - if (iwm_is_mimo_ht_plcp(ht_plcp))
> - tab |= IWM_RATE_MCS_ANT_AB_MSK;
> - else
> - tab |= IWM_RATE_MCS_ANT_A_MSK;
> -
> - if (IWM_RIDX_IS_CCK(ridx))
> - tab |= IWM_RATE_MCS_CCK_MSK;
> - lq->rs_table[j++] = htole32(tab);
> - }
> -
> - lq->mimo_delim = (mimo ? j : 0);
> -
> - /* Fill the rest with the lowest possible rate */
> - while (j < nitems(lq->rs_table)) {
> - tab = iwm_rates[ridx_min].plcp;
> - if (IWM_RIDX_IS_CCK(ridx_min))
> - tab |= IWM_RATE_MCS_CCK_MSK;
> - tab |= IWM_RATE_MCS_ANT_A_MSK;
> - lq->rs_table[j++] = htole32(tab);
> - }
> -
> - lq->single_stream_ant_msk = IWM_ANT_A;
> - lq->dual_stream_ant_msk = IWM_ANT_AB;
> -
> - lq->agg_time_limit = htole16(4000); /* 4ms */
> - lq->agg_disable_start_th = 3;
> -#ifdef notyet
> - lq->agg_frame_cnt_limit = 0x3f;
> -#else
> - lq->agg_frame_cnt_limit = 1; /* tx agg disabled */
> -#endif
> -
> - cmd.data[0] = &in->in_lq;
> - iwm_send_cmd(sc, &cmd);
> -}
> -
>  int
>  iwm_media_change(struct ifnet *ifp)
>  {
> @@ -6196,7 +6096,6 @@ iwm_newstate(struct ieee80211com *ic, enum ieee80211_s
>   if (ic->ic_state == IEEE80211_S_RUN) {
>   timeout_del(&sc->sc_calib_to);
>   ieee80211_mira_cancel_timeouts(&in->in_mn);
> - iwm_del_task(sc, systq, &sc->setrates_task);
>   iwm_del_task(sc, systq, &sc->ba_task);
>   iwm_del_task(sc, systq, &sc->htprot_task);
>   }
> @@ -6705,7 +6604,6 @@ iwm_stop(struct ifnet *ifp)
>   /* Cancel scheduled tasks and let any stale tasks finish up. */
>   task_del(systq, &sc->init_task);
>   iwm_del_task(sc, sc->sc_nswq, &sc->newstate_task);
> - iwm_del_task(sc, systq, &sc->setrates_task);
>   iwm_del_task(sc, systq, &sc->ba_task);
>   iwm_del_task(sc, systq, &sc->htprot_task);
>   KASSERT(sc->task_refs.refs >= 1);
> @@ -7895,7 +7793,6 @@ iwm_attach(struct device *parent, struct device *self,
>   timeout_set(&sc->sc_led_blink_to, iwm_led_blink_timeout, sc);
>   task_set(&sc->init_task, iwm_init_task, sc);
>   task_set(&sc->newstate_task, iwm_newstate_task, sc);
> - task_set(&sc->setrates_task, iwm_setrates_task, sc);
>   task_set(&sc->ba_task, iwm_ba_task, sc);
>   task_set(&sc->htprot_task, iwm_htprot_task, sc);
>  
> blob - 7e35820c7ceb997683c3c0c0e1da1112290c38cd
> file + sys/dev/pci/if_iwmvar.h
> --- sys/dev/pci/if_iwmvar.h
> +++ sys/dev/pci/if_iwmvar.h
> @@ -509,9 +509,12 @@ struct iwm_node {
>   uint16_t in_id;
>   uint16_t in_color;
>  
> - struct iwm_lq_cmd in_lq;
>   struct ieee80211_amrr_node in_amn;
>   struct ieee80211_mira_node in_mn;
> +
> + /* Set in 11n mode if we don't receive ACKs for OFDM frames. */
> + int ht_force_cck;
> +
>  };
>  #define IWM_STATION_ID 0
>  #define IWM_AUX_STA_ID 1
> blob - 2daf18ca6aed42bfded73d204690736ca6a4ae5e
> file + sys/net80211/ieee80211_amrr.c
> --- sys/net80211/ieee80211_amrr.c
> +++ sys/net80211/ieee80211_amrr.c
> @@ -41,45 +41,28 @@
>  #define reset_cnt(amn) \
>   do { (amn)->amn_txcnt = (amn)->amn_retrycnt = 0; } while (0)
>  
> -/*
> - * XXX In HT mode we only support MCS 0-7, for now.
> - * Beyond MCS 7, incrementing the MCS index does not imply a
> - * higher data rate, so this simple implementation will need
> - * to be enhanced.
> - */
> -
>  static inline int
>  is_min_rate(struct ieee80211_node *ni)
>  {
> - if (ni->ni_flags & IEEE80211_NODE_HT)
> - return (ni->ni_txmcs == 0);
>   return (ni->ni_txrate == 0);
>  }
>  
>  static inline int
>  is_max_rate(struct ieee80211_node *ni)
>  {
> - if (ni->ni_flags & IEEE80211_NODE_HT)
> - return (ni->ni_txmcs == 7); /* XXX up to MCS 7 only */
>   return (ni->ni_txrate == ni->ni_rates.rs_nrates - 1);
>  }
>  
>  static inline void
>  increase_rate(struct ieee80211_node *ni)
>  {
> - if (ni->ni_flags & IEEE80211_NODE_HT)
> - ni->ni_txmcs++;
> - else
> - ni->ni_txrate++;
> + ni->ni_txrate++;
>  }
>  
>  static inline void
>  decrease_rate(struct ieee80211_node *ni)
>  {
> - if (ni->ni_flags & IEEE80211_NODE_HT)
> - ni->ni_txmcs--;
> - else
> - ni->ni_txrate--;
> + ni->ni_txrate--;
>  }
>  
>  void
> @@ -110,7 +93,6 @@ ieee80211_amrr_choose(struct ieee80211_amrr *amrr, str
>   amn->amn_success = 0;
>   increase_rate(ni);
>   DPRINTF(("increase rate=%d,#tx=%d,#retries=%d\n",
> -    (ni->ni_flags & IEEE80211_NODE_HT) ? ni->ni_txmcs :
>      RV(ni->ni_rates.rs_rates[ni->ni_txrate]),
>      amn->amn_txcnt, amn->amn_retrycnt));
>   need_change = 1;
> @@ -132,7 +114,6 @@ ieee80211_amrr_choose(struct ieee80211_amrr *amrr, str
>   }
>   decrease_rate(ni);
>   DPRINTF(("decrease rate=%d,#tx=%d,#retries=%d\n",
> -    (ni->ni_flags & IEEE80211_NODE_HT) ? ni->ni_txmcs :
>      RV(ni->ni_rates.rs_rates[ni->ni_txrate]),
>      amn->amn_txcnt, amn->amn_retrycnt));
>   need_change = 1;
>
>
>
>
Hi

# hardware

iwm0 at pci2 dev 0 function 0 "Intel Dual Band Wireless-AC 8265" rev 0x78, msi
iwm0: hw rev 0x230, fw ver 22.361476.0, address b4:6b:fc:f3:e4:13

# local ping before
round-trip min/avg/max/std-dev = 2.148/2.695/4.014/0.491 ms

# local ping after
round-trip min/avg/max/std-dev = 1.888/3.236/9.751/1.356 ms

I'll report any changes if I see some.

Reply | Threaded
Open this post in threaded view
|

Re: rework iwm(4) Tx rate selection

Matthias Schmidt
In reply to this post by Stefan Sperling-5
Hi Stefan,

* Stefan Sperling wrote:
>
> When testing this, please compare throughput before and after this diff.
> I run tcpbench -s on a host behind the AP and start a tcpbench client on
> my iwm laptop. With this diff, and an 11ac AP on channel 149, tcpbench
> measures up to 26 Mpbs in my environment, with an average rate above 20 Mbps.
>
> Also pay attention to changes in latency. To test this, on my iwm laptop
> I run ping and rain(6) through an SSH connection to a machine behind the AP.

I tested your diff with the following setup:

iwm0 at pci2 dev 0 function 0 "Intel Dual Band Wireless-AC 8265" rev 0x78, msi
iwm0: hw rev 0x230, fw ver 22.361476.0

iwm0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
        index 2 priority 4 llprio 3
        trunk: trunkdev trunk0
        groups: wlan
        media: IEEE802.11 autoselect (OFDM54 mode 11g)
        status: active
        ieee80211: join karlsruhe chan 3 bssid cc:ce:1e:8b:cf:d2 68% wpakey wpaprotos wpa2 wpaakms psk wpaciphers ccmp wpagroupcipher ccmp

Laptop with iwm connect to AP, both targets connected to the AP via LAN.

Without the patch:

Ping a local host: Average RTT 12.8ms
Copy large files from a local host via NFS over TCP: 2.59MB/s
Ping a local host: Average RTT 13.6ms
Copy large files from a local host via NFS over TCP: 2.56MB/s

With the patch:

Ping a local host: Average RTT 12.2ms
Copy large files from a local host via NFS over TCP: 2.49MB/s
2nd run:
Ping a local host: Average RTT 13.0ms
Copy large files from a local host via NFS over TCP: 2.61MB/s

Cheers and HTH

        Matthias