svn commit: r343373 - head/sys/dev/iwm
Kyle Evans
kevans at FreeBSD.org
Thu Jan 24 03:41:11 UTC 2019
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 <waddlesplash at 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))
More information about the svn-src-all
mailing list