summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/if_iwn.c309
-rw-r--r--sys/dev/pci/if_iwnvar.h11
2 files changed, 129 insertions, 191 deletions
diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c
index a7b7249d46e..afeb963ef62 100644
--- a/sys/dev/pci/if_iwn.c
+++ b/sys/dev/pci/if_iwn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwn.c,v 1.244 2020/12/12 11:48:53 jan Exp $ */
+/* $OpenBSD: if_iwn.c,v 1.245 2021/03/12 16:27:27 stsp Exp $ */
/*-
* Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -55,7 +55,7 @@
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_amrr.h>
-#include <net80211/ieee80211_mira.h>
+#include <net80211/ieee80211_ra.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_priv.h> /* for SEQ_LT */
#undef DPRINTF /* defined in ieee80211_priv.h */
@@ -157,9 +157,11 @@ void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *, struct mbuf_list *);
-void iwn_mira_choose(struct iwn_softc *, struct ieee80211_node *);
+void iwn_ra_choose(struct iwn_softc *, struct ieee80211_node *);
void iwn_ampdu_rate_control(struct iwn_softc *, struct ieee80211_node *,
- struct iwn_tx_ring *, int, uint16_t, uint16_t);
+ struct iwn_tx_ring *, uint16_t, uint16_t);
+void iwn_ht_single_rate_control(struct iwn_softc *,
+ struct ieee80211_node *, uint8_t, uint8_t, uint8_t, int);
void iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
void iwn5000_rx_calib_results(struct iwn_softc *,
@@ -179,7 +181,7 @@ void iwn_tx_done_free_txdata(struct iwn_softc *,
struct iwn_tx_data *);
void iwn_clear_oactive(struct iwn_softc *, struct iwn_tx_ring *);
void iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
- uint8_t, uint8_t, int, int, uint16_t);
+ uint8_t, uint8_t, uint8_t, int, int, uint16_t);
void iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
void iwn_notif_intr(struct iwn_softc *);
void iwn_wakeup_intr(struct iwn_softc *);
@@ -1771,7 +1773,6 @@ iwn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
struct ifnet *ifp = &ic->ic_if;
struct iwn_softc *sc = ifp->if_softc;
struct ieee80211_node *ni = ic->ic_bss;
- struct iwn_node *wn = (void *)ni;
int error;
if (ic->ic_state == IEEE80211_S_RUN) {
@@ -1783,7 +1784,6 @@ iwn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
ieee80211_stop_ampdu_tx(ic, ni, -1);
ieee80211_ba_del(ni);
}
- ieee80211_mira_cancel_timeouts(&wn->mn);
timeout_del(&sc->calib_to);
sc->calib.state = IWN_CALIB_STATE_INIT;
if (sc->sc_flags & IWN_FLAG_BGSCAN)
@@ -2229,104 +2229,98 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
}
void
-iwn_mira_choose(struct iwn_softc *sc, struct ieee80211_node *ni)
+iwn_ra_choose(struct iwn_softc *sc, struct ieee80211_node *ni)
{
struct ieee80211com *ic = &sc->sc_ic;
struct iwn_node *wn = (void *)ni;
- int best_mcs = ieee80211_mira_get_best_mcs(&wn->mn);
+ int old_txmcs = ni->ni_txmcs;
- ieee80211_mira_choose(&wn->mn, ic, ni);
+ ieee80211_ra_choose(&wn->rn, ic, ni);
- /*
- * Update firmware's LQ retry table if MiRA has chosen a new MCS.
- *
- * We only need to do this if the best MCS has changed because
- * we ask firmware to use a fixed MCS while MiRA is probing a
- * candidate MCS.
- * While not probing we ask firmware to retry at lower rates in case
- * Tx at the newly chosen best MCS ends up failing, and then report
- * any resulting Tx retries to MiRA in order to trigger probing.
- */
- if (best_mcs != ieee80211_mira_get_best_mcs(&wn->mn))
+ /* Update firmware's LQ retry table if RA has chosen a new MCS. */
+ if (ni->ni_txmcs != old_txmcs)
iwn_set_link_quality(sc, ni);
}
void
iwn_ampdu_rate_control(struct iwn_softc *sc, struct ieee80211_node *ni,
- struct iwn_tx_ring *txq, int tid, uint16_t seq, uint16_t ssn)
+ struct iwn_tx_ring *txq, uint16_t seq, uint16_t ssn)
{
struct ieee80211com *ic = &sc->sc_ic;
struct iwn_node *wn = (void *)ni;
- struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid];
- int min_ampdu_id, max_ampdu_id, id;
int idx, end_idx;
- /* Determine the min/max IDs we assigned to AMPDUs in this range. */
+ /*
+ * Update Tx rate statistics for A-MPDUs before firmware's BA window.
+ */
idx = IWN_AGG_SSN_TO_TXQ_IDX(seq);
end_idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn);
- min_ampdu_id = txq->data[idx].ampdu_id;
- max_ampdu_id = min_ampdu_id;
while (idx != end_idx) {
struct iwn_tx_data *txdata = &txq->data[idx];
-
- if (txdata->m != NULL) {
- if (min_ampdu_id > txdata->ampdu_id)
- min_ampdu_id = txdata->ampdu_id;
- if (max_ampdu_id < txdata->ampdu_id)
- max_ampdu_id = txdata->ampdu_id;
- }
-
- idx = (idx + 1) % IWN_TX_RING_COUNT;
- }
-
- /*
- * Update Tx rate statistics for A-MPDUs before firmware's BA window.
- */
- for (id = min_ampdu_id; id <= max_ampdu_id; id++) {
- int have_ack = 0, bit = 0;
- idx = IWN_AGG_SSN_TO_TXQ_IDX(seq);
- end_idx = IWN_AGG_SSN_TO_TXQ_IDX(ssn);
- wn->mn.agglen = 0;
- wn->mn.ampdu_size = 0;
- while (idx != end_idx) {
- struct iwn_tx_data *txdata = &txq->data[idx];
- uint16_t s = (seq + bit) & 0xfff;
+ if (txdata->m != NULL && txdata->ampdu_nframes > 1) {
/*
* We can assume that this subframe has been ACKed
* because ACK failures come as single frames and
* before failing an A-MPDU subframe the firmware
* sends it as a single frame at least once.
- *
- * However, when this A-MPDU was transmitted we
- * learned how many subframes it contained.
- * So if firmware isn't reporting all subframes now
- * we can deduce an ACK failure for missing frames.
*/
- if (txdata->m != NULL && txdata->ampdu_id == id &&
- txdata->ampdu_txmcs == ni->ni_txmcs &&
- txdata->ampdu_nframes > 0 &&
- (SEQ_LT(ba->ba_winend, s) ||
- (ba->ba_bitmap & (1 << bit)) == 0)) {
- have_ack++;
- wn->mn.frames = txdata->ampdu_nframes;
- wn->mn.agglen = txdata->ampdu_nframes;
- wn->mn.ampdu_size = txdata->ampdu_size;
- if (txdata->retries > 1)
- wn->mn.retries++;
- if (!SEQ_LT(ba->ba_winend, s))
- ieee80211_output_ba_record_ack(ic, ni,
- tid, s);
- }
+ ieee80211_ra_add_stats_ht(&wn->rn, ic, ni,
+ txdata->ampdu_txmcs, 1, 0);
- idx = (idx + 1) % IWN_TX_RING_COUNT;
- bit++;
+ /* Report this frame only once. */
+ txdata->ampdu_nframes = 0;
}
- if (have_ack > 0) {
- wn->mn.txfail = wn->mn.frames - have_ack;
- iwn_mira_choose(sc, ni);
+ idx = (idx + 1) % IWN_TX_RING_COUNT;
+ }
+
+ iwn_ra_choose(sc, ni);
+}
+
+void
+iwn_ht_single_rate_control(struct iwn_softc *sc, struct ieee80211_node *ni,
+ uint8_t rate, uint8_t rflags, uint8_t ackfailcnt, int txfail)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct iwn_node *wn = (void *)ni;
+ int mcs = rate;
+ const struct ieee80211_ht_rateset *rs =
+ ieee80211_ra_get_ht_rateset(rate,
+ ieee80211_node_supports_ht_sgi20(ni));
+ unsigned int retries = 0, i;
+
+ /*
+ * Ignore Tx reports which don't match our last LQ command.
+ */
+ if (rate != ni->ni_txmcs) {
+ if (++wn->lq_rate_mismatch > 15) {
+ /* Try to sync firmware with driver. */
+ iwn_set_link_quality(sc, ni);
+ wn->lq_rate_mismatch = 0;
}
+ return;
+ }
+
+ wn->lq_rate_mismatch = 0;
+
+ /*
+ * Firmware has attempted rates in this rate set in sequence.
+ * Retries at a basic rate are counted against the minimum MCS.
+ */
+ for (i = 0; i < ackfailcnt; i++) {
+ if (mcs > rs->min_mcs) {
+ ieee80211_ra_add_stats_ht(&wn->rn, ic, ni, mcs, 1, 1);
+ mcs--;
+ } else
+ retries++;
}
+
+ if (txfail && ackfailcnt == 0)
+ ieee80211_ra_add_stats_ht(&wn->rn, ic, ni, mcs, 1, 1);
+ else
+ ieee80211_ra_add_stats_ht(&wn->rn, ic, ni, mcs, retries + 1, retries);
+
+ iwn_ra_choose(sc, ni);
}
/*
@@ -2391,8 +2385,7 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
/* Skip rate control if our Tx rate is fixed. */
if (ic->ic_fixed_mcs == -1)
- iwn_ampdu_rate_control(sc, ni, txq, cba->tid, ba->ba_winstart,
- ssn);
+ iwn_ampdu_rate_control(sc, ni, txq, ba->ba_winstart, ssn);
/*
* SSN corresponds to the first (perhaps not yet transmitted) frame
@@ -2555,9 +2548,9 @@ iwn_ampdu_txq_advance(struct iwn_softc *sc, struct iwn_tx_ring *txq, int qid,
/*
* Handle A-MPDU Tx queue status report.
* Tx failures come as single frames (perhaps out of order), and before failing
- * an A-MPDU subframe the firmware transmits it as a single frame at least once
- * and reports Tx success/failure here. Frames successfully transmitted in an
- * A-MPDU are completed when a compressed block ack notification is received.
+ * an A-MPDU subframe the firmware transmits it as a single frame at least once.
+ * Frames successfully transmitted in an A-MPDU are completed when a compressed
+ * block ack notification is received.
*/
void
iwn_ampdu_tx_done(struct iwn_softc *sc, struct iwn_tx_ring *txq,
@@ -2569,7 +2562,6 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, struct iwn_tx_ring *txq,
int tid = desc->qid - sc->first_agg_txq;
struct iwn_tx_data *txdata = &txq->data[desc->idx];
struct ieee80211_node *ni = txdata->ni;
- struct iwn_node *wn = (void *)ni;
int txfail = (status != IWN_TX_STATUS_SUCCESS &&
status != IWN_TX_STATUS_DIRECT_DONE);
struct ieee80211_tx_ba *ba;
@@ -2581,35 +2573,19 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, struct iwn_tx_ring *txq,
return;
if (nframes > 1) {
- int ampdu_id, have_ampdu_id = 0, ampdu_size = 0;
int i;
- /* Compute the size of this A-MPDU. */
- for (i = 0; i < nframes; i++) {
- uint8_t qid = agg_status[i].qid;
- uint8_t idx = agg_status[i].idx;
-
- if (qid != desc->qid)
- continue;
-
- txdata = &txq->data[idx];
- if (txdata->ni == NULL)
- continue;
-
- ampdu_size += txdata->totlen + IEEE80211_CRC_LEN;
- }
-
- /*
- * For each subframe collect Tx status, retries, and Tx rate.
- * (The Tx rate is the same for all subframes in this batch.)
+ /*
+ * Collect information about this A-MPDU.
*/
for (i = 0; i < nframes; i++) {
uint8_t qid = agg_status[i].qid;
uint8_t idx = agg_status[i].idx;
uint16_t txstatus = (le16toh(agg_status[i].status) &
IWN_AGG_TX_STATUS_MASK);
- uint16_t trycnt = (le16toh(agg_status[i].status) &
- IWN_AGG_TX_TRY) >> IWN_AGG_TX_TRY_SHIFT;
+
+ if (txstatus != IWN_AGG_TX_STATE_TRANSMITTED)
+ continue;
if (qid != desc->qid)
continue;
@@ -2618,36 +2594,9 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, struct iwn_tx_ring *txq,
if (txdata->ni == NULL)
continue;
- if (rflags & IWN_RFLAG_MCS)
- txdata->ampdu_txmcs = rate;
- if (txstatus != IWN_AGG_TX_STATE_TRANSMITTED)
- txdata->txfail++;
- if (trycnt > 1)
- txdata->retries++;
-
- /*
- * Assign a common ID to all subframes of this A-MPDU.
- * This ID will be used during Tx rate control to
- * infer the ACK status of individual subframes.
- */
- if (!have_ampdu_id) {
- wn = (void *)txdata->ni;
- ampdu_id = wn->next_ampdu_id++;
- have_ampdu_id = 1;
- }
- txdata->ampdu_id = ampdu_id;
-
- /*
- * We will also need to know the total number of
- * subframes and the size of this A-MPDU. We store
- * this redundantly on each subframe because firmware
- * only reports acknowledged subframes via compressed
- * block-ack notification. This way we will know what
- * the total number of subframes and size were even if
- * just one of these subframes gets acknowledged.
- */
+ /* The Tx rate was the same for all subframes. */
+ txdata->ampdu_txmcs = rate;
txdata->ampdu_nframes = nframes;
- txdata->ampdu_size = ampdu_size;
}
return;
}
@@ -2664,18 +2613,24 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, struct iwn_tx_ring *txq,
/*
* Skip rate control if our Tx rate is fixed.
- * Don't report frames to MiRA which were sent at a different
- * Tx rate than ni->ni_txmcs.
*/
- if (ic->ic_fixed_mcs == -1 && txdata->txmcs == ni->ni_txmcs) {
- wn->mn.frames++;
- wn->mn.agglen = 1;
- wn->mn.ampdu_size = txdata->totlen + IEEE80211_CRC_LEN;
- if (ackfailcnt > 0)
- wn->mn.retries++;
- if (txfail)
- wn->mn.txfail++;
- iwn_mira_choose(sc, ni);
+ if (ic->ic_fixed_mcs == -1) {
+ if (txdata->ampdu_nframes > 1) {
+ struct iwn_node *wn = (void *)ni;
+ /*
+ * This frame was once part of an A-MPDU.
+ * Report one failed A-MPDU Tx attempt.
+ * The firmware might have made several such
+ * attempts but we don't keep track of this.
+ */
+ ieee80211_ra_add_stats_ht(&wn->rn, ic, ni,
+ txdata->ampdu_txmcs, 1, 1);
+ }
+
+ /* Report the final single-frame Tx attempt. */
+ if (rflags & IWN_RFLAG_MCS)
+ iwn_ht_single_rate_control(sc, ni, rate, rflags,
+ ackfailcnt, txfail);
}
if (txfail)
@@ -2746,8 +2701,8 @@ iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
int txfail = (status != IWN_TX_STATUS_SUCCESS &&
status != IWN_TX_STATUS_DIRECT_DONE);
- iwn_tx_done(sc, desc, stat->ackfailcnt, stat->rate, txfail,
- desc->qid, framelen);
+ iwn_tx_done(sc, desc, stat->ackfailcnt, stat->rate,
+ stat->rflags, txfail, desc->qid, framelen);
} else {
memcpy(&ssn, &stat->stat.status + stat->nframes, sizeof(ssn));
ssn = le32toh(ssn) & 0xfff;
@@ -2794,8 +2749,8 @@ iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
/* Reset TX scheduler slot. */
iwn5000_reset_sched(sc, desc->qid, desc->idx);
- iwn_tx_done(sc, desc, stat->ackfailcnt, stat->rate, txfail,
- desc->qid, letoh16(stat->len));
+ iwn_tx_done(sc, desc, stat->ackfailcnt, stat->rate,
+ stat->rflags, txfail, desc->qid, letoh16(stat->len));
} else {
memcpy(&ssn, &stat->stat.status + stat->nframes, sizeof(ssn));
ssn = le32toh(ssn) & 0xfff;
@@ -2818,11 +2773,8 @@ iwn_tx_done_free_txdata(struct iwn_softc *sc, struct iwn_tx_data *data)
ieee80211_release_node(ic, data->ni);
data->ni = NULL;
data->totlen = 0;
- data->retries = 0;
- data->txfail = 0;
- data->txmcs = 0;
+ data->ampdu_nframes = 0;
data->ampdu_txmcs = 0;
- data->txrate = 0;
}
void
@@ -2846,7 +2798,8 @@ iwn_clear_oactive(struct iwn_softc *sc, struct iwn_tx_ring *ring)
*/
void
iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
- uint8_t ackfailcnt, uint8_t rate, int txfail, int qid, uint16_t len)
+ uint8_t ackfailcnt, uint8_t rate, uint8_t rflags, int txfail,
+ int qid, uint16_t len)
{
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
@@ -2859,23 +2812,26 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
if (data->ni->ni_flags & IEEE80211_NODE_HT) {
if (ic->ic_state == IEEE80211_S_RUN &&
- ic->ic_fixed_mcs == -1 &&
- data->txmcs == data->ni->ni_txmcs) {
- wn->mn.frames++;
- wn->mn.ampdu_size = len;
- wn->mn.agglen = 1;
+ ic->ic_fixed_mcs == -1 && (rflags & IWN_RFLAG_MCS)) {
+ iwn_ht_single_rate_control(sc, data->ni, rate, rflags,
+ ackfailcnt, txfail);
+ }
+ } else {
+ if (rate != data->ni->ni_txrate) {
+ if (++wn->lq_rate_mismatch > 15) {
+ /* Try to sync firmware with driver. */
+ iwn_set_link_quality(sc, data->ni);
+ wn->lq_rate_mismatch = 0;
+ }
+ } else {
+ wn->lq_rate_mismatch = 0;
+
+ wn->amn.amn_txcnt++;
if (ackfailcnt > 0)
- wn->mn.retries++;
+ wn->amn.amn_retrycnt++;
if (txfail)
- wn->mn.txfail++;
- iwn_mira_choose(sc, data->ni);
+ wn->amn.amn_retrycnt++;
}
- } else if (data->txrate == data->ni->ni_txrate) {
- wn->amn.amn_txcnt++;
- if (ackfailcnt > 0)
- wn->amn.amn_retrycnt++;
- if (txfail)
- wn->amn.amn_retrycnt++;
}
if (txfail)
ifp->if_oerrors++;
@@ -3528,13 +3484,8 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
/* Check if frame must be protected using RTS/CTS or CTS-to-self. */
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
- int rtsthres = ic->ic_rtsthreshold;
- if (ni->ni_flags & IEEE80211_NODE_HT)
- rtsthres = ieee80211_mira_get_rts_threshold(&wn->mn,
- ic, ni, totlen + IEEE80211_CRC_LEN);
-
/* NB: Group frames are sent using CCK in 802.11b/g/n (2GHz). */
- if (totlen + IEEE80211_CRC_LEN > rtsthres) {
+ if (totlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) {
flags |= IWN_TX_NEED_RTS;
} else if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
ridx >= IWN_RIDX_OFDM6) {
@@ -3601,15 +3552,9 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
}
else
tx->rflags = rinfo->flags;
- /*
- * Keep the Tx rate constant while mira is probing, or if this is
- * an aggregation queue in which case a fixed Tx rate works around
- * FIFO_UNDERRUN Tx errors.
- */
- if (tx->id == sc->broadcast_id || ieee80211_mira_is_probing(&wn->mn) ||
- qid >= sc->first_agg_txq ||
- ic->ic_fixed_mcs != -1 || ic->ic_fixed_rate != -1) {
- /* Group or management frame, or probing, or fixed Tx rate. */
+ if (tx->id == sc->broadcast_id || ic->ic_fixed_mcs != -1 ||
+ ic->ic_fixed_rate != -1) {
+ /* Group or management frame, or fixed Tx rate. */
tx->linkq = 0;
/* XXX Alternate between antenna A and B? */
txant = IWN_LSB(sc->txchainmask);
@@ -3680,8 +3625,6 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
data->m = m;
data->ni = ni;
- data->txmcs = ni->ni_txmcs;
- data->txrate = ni->ni_txrate;
data->ampdu_txmcs = ni->ni_txmcs; /* updated upon Tx interrupt */
DPRINTFN(4, ("sending data: qid=%d idx=%d len=%d nsegs=%d\n",
@@ -5649,7 +5592,7 @@ iwn_run(struct iwn_softc *sc)
sc->calib_cnt = 0;
timeout_add_msec(&sc->calib_to, 500);
- ieee80211_mira_node_init(&wn->mn);
+ ieee80211_ra_node_init(&wn->rn);
/* Link LED always on while associated. */
iwn_set_led(sc, IWN_LED_LINK, 0, 1);
diff --git a/sys/dev/pci/if_iwnvar.h b/sys/dev/pci/if_iwnvar.h
index 3af35055a6e..e1c3e196d28 100644
--- a/sys/dev/pci/if_iwnvar.h
+++ b/sys/dev/pci/if_iwnvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_iwnvar.h,v 1.39 2020/10/11 07:05:28 mpi Exp $ */
+/* $OpenBSD: if_iwnvar.h,v 1.40 2021/03/12 16:27:28 stsp Exp $ */
/*-
* Copyright (c) 2007, 2008
@@ -65,16 +65,10 @@ struct iwn_tx_data {
struct mbuf *m;
struct ieee80211_node *ni;
int totlen;
- int retries;
- int txfail;
- int txmcs;
- int txrate;
/* A-MPDU subframes */
- int ampdu_id;
int ampdu_txmcs;
int ampdu_nframes;
- int ampdu_size;
};
struct iwn_tx_ring {
@@ -108,11 +102,12 @@ struct iwn_rx_ring {
struct iwn_node {
struct ieee80211_node ni; /* must be the first */
struct ieee80211_amrr_node amn;
- struct ieee80211_mira_node mn;
+ struct ieee80211_ra_node rn;
uint16_t disable_tid;
uint8_t id;
uint8_t ridx[IEEE80211_RATE_MAXSIZE];
uint32_t next_ampdu_id;
+ int lq_rate_mismatch;
};
struct iwn_calib_state {