Author: kevans
Date: Thu Jan 24 03:41:09 2019
New Revision: 343373
URL: https://svnweb.freebsd.org/changeset/base/343373

Log:
  if_iwm - Update firmware rs table, instead of indexing the table in tx cmds.
  
  * Rather than providing a non-zero index into the firmware RS table,
  we should always use index 0 and update the firmware RS table whenever
  our chosen tx rate for data-frames changes.
  
  * Send IWM_LQ_CMD updates when the tx rate gets updated by the net80211
  rate control (which is after we tell the tx status to the net80211
  rate-control in iwm_mvm_rx_tx_cmd_single()).
  
  * Disregard frames transferred with a different tx rate than the currently
  selected rate for the rate-control calculations. This way we avoid
  counting management frames (which are sent at a slow, and fixed rate),
  as well as frames we added to the tx queue just before a new IWM_LQ_CMD
  update took effect.
  
  Submitted by: Augustin Cavalier <waddlespl...@gmail.com> (Haiku)
  Obtained from:        DragonFlyBSD (5d6b465e288ac5b52d7115688d4e6516acbbea1c)

Modified:
  head/sys/dev/iwm/if_iwm.c
  head/sys/dev/iwm/if_iwmvar.h

Modified: head/sys/dev/iwm/if_iwm.c
==============================================================================
--- head/sys/dev/iwm/if_iwm.c   Thu Jan 24 01:08:37 2019        (r343372)
+++ head/sys/dev/iwm/if_iwm.c   Thu Jan 24 03:41:09 2019        (r343373)
@@ -353,7 +353,9 @@ static int  iwm_release(struct iwm_softc *, struct iwm_
 static struct ieee80211_node *
                iwm_node_alloc(struct ieee80211vap *,
                               const uint8_t[IEEE80211_ADDR_LEN]);
-static void    iwm_setrates(struct iwm_softc *, struct iwm_node *);
+static uint8_t iwm_rate_from_ucode_rate(uint32_t);
+static int     iwm_rate2ridx(struct iwm_softc *, uint8_t);
+static void    iwm_setrates(struct iwm_softc *, struct iwm_node *, int);
 static int     iwm_media_change(struct ifnet *);
 static int     iwm_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static void    iwm_endscan_cb(void *, int);
@@ -3317,7 +3319,11 @@ iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct 
        struct iwm_mvm_tx_resp *tx_resp = (void *)pkt->data;
        struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
        struct ieee80211_node *ni = &in->in_ni;
+       struct ieee80211vap *vap = ni->ni_vap;
        int status = le16toh(tx_resp->status.status) & IWM_TX_STATUS_MSK;
+       int new_rate, cur_rate = vap->iv_bss->ni_txrate;
+       boolean_t rate_matched;
+       uint8_t tx_resp_rate;
 
        KASSERT(tx_resp->frame_count == 1, ("too many frames"));
 
@@ -3333,6 +3339,17 @@ iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct 
            le32toh(tx_resp->initial_rate),
            (int) le16toh(tx_resp->wireless_media_time));
 
+       tx_resp_rate = iwm_rate_from_ucode_rate(le32toh(tx_resp->initial_rate));
+
+       /* For rate control, ignore frames sent at different initial rate */
+       rate_matched = (tx_resp_rate != 0 && tx_resp_rate == cur_rate);
+
+       if (tx_resp_rate != 0 && cur_rate != 0 && !rate_matched) {
+               IWM_DPRINTF(sc, IWM_DEBUG_TXRATE,
+                   "tx_resp_rate doesn't match ni_txrate (tx_resp_rate=%u "
+                   "ni_txrate=%d)\n", tx_resp_rate, cur_rate);
+       }
+
        txs->flags = IEEE80211_RATECTL_STATUS_SHORT_RETRY |
                     IEEE80211_RATECTL_STATUS_LONG_RETRY;
        txs->short_retries = tx_resp->failure_rts;
@@ -3356,8 +3373,19 @@ iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct 
        } else {
                txs->status = IEEE80211_RATECTL_TX_SUCCESS;
        }
-       ieee80211_ratectl_tx_complete(ni, txs);
 
+       if (rate_matched) {
+               ieee80211_ratectl_tx_complete(ni, txs);
+
+               int rix = ieee80211_ratectl_rate(vap->iv_bss, NULL, 0);
+               new_rate = vap->iv_bss->ni_txrate;
+               if (new_rate != 0 && new_rate != cur_rate) {
+                       struct iwm_node *in = IWM_NODE(vap->iv_bss);
+                       iwm_setrates(sc, in, rix);
+                       iwm_mvm_send_lq_cmd(sc, &in->in_lq, FALSE);
+               }
+       }
+
        return (txs->status != IEEE80211_RATECTL_TX_SUCCESS);
 }
 
@@ -3482,38 +3510,7 @@ iwm_update_sched(struct iwm_softc *sc, int qid, int id
 }
 #endif
 
-/*
- * Take an 802.11 (non-n) rate, find the relevant rate
- * table entry.  return the index into in_ridx[].
- *
- * The caller then uses that index back into in_ridx
- * to figure out the rate index programmed /into/
- * the firmware for this given node.
- */
 static int
-iwm_tx_rateidx_lookup(struct iwm_softc *sc, struct iwm_node *in,
-    uint8_t rate)
-{
-       int i;
-       uint8_t r;
-
-       for (i = 0; i < nitems(in->in_ridx); i++) {
-               r = iwm_rates[in->in_ridx[i]].rate;
-               if (rate == r)
-                       return (i);
-       }
-
-       IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE,
-           "%s: couldn't find an entry for rate=%d\n",
-           __func__,
-           rate);
-
-       /* XXX Return the first */
-       /* XXX TODO: have it return the /lowest/ */
-       return (0);
-}
-
-static int
 iwm_tx_rateidx_global_lookup(struct iwm_softc *sc, uint8_t rate)
 {
        int i;
@@ -3565,22 +3562,15 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node 
                IWM_DPRINTF(sc, IWM_DEBUG_TXRATE,
                    "%s: FIXED_RATE (%d)\n", __func__, tp->ucastrate);
        } else {
-               int i;
-
                /* for data frames, use RS table */
                IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: DATA\n", __func__);
-               /* XXX pass pktlen */
-               (void) ieee80211_ratectl_rate(ni, NULL, 0);
-               i = iwm_tx_rateidx_lookup(sc, in, ni->ni_txrate);
-               ridx = in->in_ridx[i];
+               ridx = iwm_rate2ridx(sc, ni->ni_txrate);
+               if (ridx == -1)
+                       ridx = 0;
 
                /* This is the index into the programmed table */
-               tx->initial_rate_index = i;
+               tx->initial_rate_index = 0;
                tx->tx_flags |= htole32(IWM_TX_CMD_FLG_STA_RATE);
-
-               IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE,
-                   "%s: start with i=%d, txrate %d\n",
-                   __func__, i, iwm_rates[ridx].rate);
        }
 
        IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE,
@@ -4165,6 +4155,19 @@ iwm_node_alloc(struct ieee80211vap *vap, const uint8_t
            M_NOWAIT | M_ZERO);
 }
 
+static uint8_t
+iwm_rate_from_ucode_rate(uint32_t rate_n_flags)
+{
+       uint8_t plcp = rate_n_flags & 0xff;
+       int i;
+
+       for (i = 0; i <= IWM_RIDX_MAX; i++) {
+               if (iwm_rates[i].plcp == plcp)
+                       return iwm_rates[i].rate;
+       }
+       return 0;
+}
+
 uint8_t
 iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx)
 {
@@ -4180,15 +4183,36 @@ iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx)
        return 0;
 }
 
+static int
+iwm_rate2ridx(struct iwm_softc *sc, uint8_t rate)
+{
+       int i;
+
+       for (i = 0; i <= IWM_RIDX_MAX; i++) {
+               if (iwm_rates[i].rate == rate)
+                       return i;
+       }
+
+       device_printf(sc->sc_dev,
+           "%s: WARNING: device rate for %u not found!\n",
+           __func__, rate);
+
+       return -1;
+}
+
+
 static void
-iwm_setrates(struct iwm_softc *sc, struct iwm_node *in)
+iwm_setrates(struct iwm_softc *sc, struct iwm_node *in, int rix)
 {
        struct ieee80211_node *ni = &in->in_ni;
        struct iwm_lq_cmd *lq = &in->in_lq;
-       int nrates = ni->ni_rates.rs_nrates;
+       struct ieee80211_rateset *rs = &ni->ni_rates;
+       int nrates = rs->rs_nrates;
        int i, ridx, tab = 0;
 //     int txant = 0;
 
+       KASSERT(rix >= 0 && rix < nrates, ("invalid rix"));
+
        if (nrates > nitems(lq->rs_table)) {
                device_printf(sc->sc_dev,
                    "%s: node supports %d rates, driver handles "
@@ -4200,45 +4224,11 @@ iwm_setrates(struct iwm_softc *sc, struct iwm_node *in
                    "%s: node supports 0 rates, odd!\n", __func__);
                return;
        }
+       nrates = imin(rix + 1, nrates);
 
-       /*
-        * XXX .. and most of iwm_node is not initialised explicitly;
-        * it's all just 0x0 passed to the firmware.
-        */
-
-       /* first figure out which rates we should support */
-       /* XXX TODO: this isn't 11n aware /at all/ */
-       memset(&in->in_ridx, -1, sizeof(in->in_ridx));
        IWM_DPRINTF(sc, IWM_DEBUG_TXRATE,
            "%s: nrates=%d\n", __func__, nrates);
 
-       /*
-        * Loop over nrates and populate in_ridx from the highest
-        * rate to the lowest rate.  Remember, in_ridx[] has
-        * IEEE80211_RATE_MAXSIZE entries!
-        */
-       for (i = 0; i < min(nrates, IEEE80211_RATE_MAXSIZE); i++) {
-               int rate = ni->ni_rates.rs_rates[(nrates - 1) - i] & 
IEEE80211_RATE_VAL;
-
-               /* Map 802.11 rate to HW rate index. */
-               for (ridx = 0; ridx <= IWM_RIDX_MAX; ridx++)
-                       if (iwm_rates[ridx].rate == rate)
-                               break;
-               if (ridx > IWM_RIDX_MAX) {
-                       device_printf(sc->sc_dev,
-                           "%s: WARNING: device rate for %d not found!\n",
-                           __func__, rate);
-               } else {
-                       IWM_DPRINTF(sc, IWM_DEBUG_TXRATE,
-                           "%s: rate: i: %d, rate=%d, ridx=%d\n",
-                           __func__,
-                           i,
-                           rate,
-                           ridx);
-                       in->in_ridx[i] = ridx;
-               }
-       }
-
        /* then construct a lq_cmd based on those */
        memset(lq, 0, sizeof(*lq));
        lq->sta_id = IWM_STATION_ID;
@@ -4262,13 +4252,15 @@ iwm_setrates(struct iwm_softc *sc, struct iwm_node *in
         * Note that we add the rates in the highest rate first
         * (opposite of ni_rates).
         */
-       /*
-        * XXX TODO: this should be looping over the min of nrates
-        * and LQ_MAX_RETRY_NUM.  Sigh.
-        */
        for (i = 0; i < nrates; i++) {
+               int rate = rs->rs_rates[rix - i] & IEEE80211_RATE_VAL;
                int nextant;
 
+               /* Map 802.11 rate to HW rate index. */
+               ridx = iwm_rate2ridx(sc, rate);
+               if (ridx == -1)
+                       continue;
+
 #if 0
                if (txant == 0)
                        txant = iwm_mvm_get_valid_tx_ant(sc);
@@ -4277,12 +4269,6 @@ iwm_setrates(struct iwm_softc *sc, struct iwm_node *in
 #else
                nextant = iwm_mvm_get_valid_tx_ant(sc);
 #endif
-               /*
-                * Map the rate id into a rate index into
-                * our hardware table containing the
-                * configuration to use for this rate.
-                */
-               ridx = in->in_ridx[i];
                tab = iwm_rates[ridx].plcp;
                tab |= nextant << IWM_RATE_MCS_ANT_POS;
                if (IWM_RIDX_IS_CCK(ridx))
@@ -4474,7 +4460,8 @@ iwm_newstate(struct ieee80211vap *vap, enum ieee80211_
                iwm_mvm_enable_beacon_filter(sc, ivp);
                iwm_mvm_power_update_mac(sc);
                iwm_mvm_update_quotas(sc, ivp);
-               iwm_setrates(sc, in);
+               int rix = ieee80211_ratectl_rate(&in->in_ni, NULL, 0);
+               iwm_setrates(sc, in, rix);
 
                if ((error = iwm_mvm_send_lq_cmd(sc, &in->in_lq, TRUE)) != 0) {
                        device_printf(sc->sc_dev,

Modified: head/sys/dev/iwm/if_iwmvar.h
==============================================================================
--- head/sys/dev/iwm/if_iwmvar.h        Thu Jan 24 01:08:37 2019        
(r343372)
+++ head/sys/dev/iwm/if_iwmvar.h        Thu Jan 24 03:41:09 2019        
(r343373)
@@ -404,8 +404,6 @@ struct iwm_node {
        int                     in_assoc;
 
        struct iwm_lq_cmd       in_lq;
-
-       uint8_t                 in_ridx[IEEE80211_RATE_MAXSIZE];
 };
 #define IWM_NODE(_ni)          ((struct iwm_node *)(_ni))
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to