Skip to content

Commit

Permalink
Enable tx mimo, port over link quality table from iwm.
Browse files Browse the repository at this point in the history
  • Loading branch information
pigworlds committed Nov 28, 2020
1 parent f4c9c46 commit 38bbc0c
Show file tree
Hide file tree
Showing 2 changed files with 271 additions and 82 deletions.
199 changes: 139 additions & 60 deletions itlwm/hal_iwn/ItlIwn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,15 +516,24 @@ iwn_attach(struct iwn_softc *sc, struct pci_attach_args *pa)
ieee80211_std_rateset_11a;
}
if (sc->sc_flags & IWN_FLAG_HAS_11N) {
/* TX is supported with the same MCS as RX. */
ic->ic_tx_mcs_set = IEEE80211_TX_MCS_SET_DEFINED;
int ntxstreams = sc->ntxchains;
int nrxstreams = sc->nrxchains;

/* Set supported HT rates. */
if (ic->ic_userflags & IEEE80211_F_NOMIMO)
ntxstreams = nrxstreams = 1;

ic->ic_sup_mcs[0] = 0xff; /* MCS 0-7 */
if (sc->nrxchains > 1)
if (nrxstreams > 1)
ic->ic_sup_mcs[1] = 0xff; /* MCS 8-15 */
if (sc->nrxchains > 2)
if (nrxstreams > 2)
ic->ic_sup_mcs[2] = 0xff; /* MCS 16-23 */

ic->ic_tx_mcs_set = IEEE80211_TX_MCS_SET_DEFINED;
if (ntxstreams != nrxstreams) {
ic->ic_tx_mcs_set |= IEEE80211_TX_RX_MCS_NOT_EQUAL;
ic->ic_tx_mcs_set |= (ntxstreams - 1) << 2;
}
}

/* IBSS channel undefined for now. */
Expand Down Expand Up @@ -1730,7 +1739,7 @@ iwn_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew)
rate = ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL;
/* Map 802.11 rate to HW rate index. */
for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) {
if (iwn_rates[ridx].plcp != IWN_PLCP_INVALID &&
if (iwn_rates[ridx].plcp != IWN_RATE_INVM_PLCP &&
iwn_rates[ridx].rate == rate)
break;
}
Expand All @@ -1757,7 +1766,7 @@ iwn_media_change(struct _ifnet *ifp)
rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
/* Map 802.11 rate to HW rate index. */
for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++)
if (iwn_rates[ridx].plcp != IWN_PLCP_INVALID &&
if (iwn_rates[ridx].plcp != IWN_RATE_INVM_PLCP &&
iwn_rates[ridx].rate == rate)
break;
sc->fixed_ridx = ridx;
Expand Down Expand Up @@ -2712,9 +2721,8 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, struct iwn_tx_ring *txq,
iwn_mira_choose(sc, ni);
}

if (txfail) {
if (txfail)
ieee80211_tx_compressed_bar(ic, ni, tid, ssn);
}
else if (!SEQ_LT(seq, ba->ba_winstart)) {
/*
* Move window forward if SEQ lies beyond end of window,
Expand Down Expand Up @@ -2775,7 +2783,7 @@ iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
stat->nframes * sizeof(stat->stat) > len)
return;

if (desc->qid < sc->first_agg_txq) {
if (desc->qid < sc->first_agg_txq) {
/* XXX 4965 does not report byte count */
struct iwn_tx_data *txdata = &ring->data[desc->idx];
uint16_t framelen = txdata->totlen + IEEE80211_CRC_LEN;
Expand Down Expand Up @@ -3405,6 +3413,21 @@ iwn_rval2ridx(int rval)
return ridx;
}

static int
iwn_is_mimo_ht_plcp(uint8_t ht_plcp)
{
return (ht_plcp != IWN_RATE_HT_SISO_MCS_INV_PLCP &&
(ht_plcp & IWN_RATE_HT_MCS_NSS_MSK));
}

static int
iwn_is_mimo_mcs(int mcs)
{
int ridx = iwn_mcs2ridx[mcs];
return iwn_is_mimo_ht_plcp(iwn_rates[ridx].ht_plcp);

}

int ItlIwn::
iwn_tx(struct iwn_softc *sc, mbuf_t m, struct ieee80211_node *ni)
{
Expand Down Expand Up @@ -3577,7 +3600,7 @@ iwn_tx(struct iwn_softc *sc, mbuf_t m, struct ieee80211_node *ni)
if (totlen + IEEE80211_CRC_LEN > rtsthres) {
flags |= IWN_TX_NEED_RTS;
} else if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
ridx >= IWN_RIDX_OFDM6) {
IWN_RIDX_IS_OFDM(ridx)) {
if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
flags |= IWN_TX_NEED_CTS;
else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
Expand Down Expand Up @@ -3628,19 +3651,24 @@ iwn_tx(struct iwn_softc *sc, mbuf_t m, struct ieee80211_node *ni)
tx->lifetime = htole32(IWN_LIFETIME_INFINITE);

if ((ni->ni_flags & IEEE80211_NODE_HT) &&
tx->id != sc->broadcast_id)
tx->id != sc->broadcast_id &&
rinfo->ht_plcp != IWN_RATE_HT_SISO_MCS_INV_PLCP) {
tx->plcp = rinfo->ht_plcp;
else
tx->plcp = rinfo->plcp;

if ((ni->ni_flags & IEEE80211_NODE_HT) &&
tx->id != sc->broadcast_id) {
tx->rflags = rinfo->ht_flags;
tx->rflags = IWN_RFLAG_MCS;
if (ni->ni_htcaps & IEEE80211_HTCAP_SGI20)
tx->rflags |= IWN_RFLAG_SGI;
}
else {
tx->plcp = rinfo->plcp;
if (IWN_RIDX_IS_CCK(ridx))
tx->rflags = IWN_RFLAG_CCK;
}

if (iwn_is_mimo_ht_plcp(rinfo->ht_plcp))
tx->rflags |= IWN_RFLAG_ANT(sc->txchainmask);
else
tx->rflags = rinfo->flags;
tx->rflags |= IWN_RFLAG_ANT(IWN_LSB(sc->txchainmask));

/*
* 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
Expand Down Expand Up @@ -4034,9 +4062,9 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni)
struct ieee80211com *ic = &sc->sc_ic;
struct iwn_node *wn = (struct iwn_node *)ni;
struct iwn_cmd_link_quality linkq;
const struct iwn_rate *rinfo;
struct ieee80211_rateset *rs = &ni->ni_rates;
uint8_t txant;
int i;
int i, ridx, ridx_min, ridx_max, j, sgi_ok = 0, mimo, tab = 0, rflags = 0;

/* Use the first valid TX antenna. */
txant = IWN_LSB(sc->txchainmask);
Expand All @@ -4049,42 +4077,92 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni)
linkq.ampdu_threshold = 3;
linkq.ampdu_limit = htole16(4000); /* 4ms */

i = 0;
if (ni->ni_flags & IEEE80211_NODE_HT) {
int txmcs;
for (txmcs = ni->ni_txmcs; txmcs >= 0; txmcs--) {
rinfo = &iwn_rates[iwn_mcs2ridx[txmcs]];
linkq.retry[i].plcp = rinfo->ht_plcp;
linkq.retry[i].rflags = rinfo->ht_flags;

if (ni->ni_htcaps & IEEE80211_HTCAP_SGI20)
linkq.retry[i].rflags |= IWN_RFLAG_SGI;

/* XXX set correct ant mask for MIMO rates here */
linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant);

if (++i >= IWN_MAX_TX_RETRIES)
break;
}
} else {
int txrate;
for (txrate = ni->ni_txrate; txrate >= 0; txrate--) {
rinfo = &iwn_rates[wn->ridx[txrate]];
linkq.retry[i].plcp = rinfo->plcp;
linkq.retry[i].rflags = rinfo->flags;
linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant);
if (++i >= IWN_MAX_TX_RETRIES)
break;
}
if (ic->ic_flags & IEEE80211_F_USEPROT)
linkq.flags |= IWN_TX_NEED_RTS;

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 = iwn_rval2ridx(ieee80211_min_basic_rate(ic));
mimo = iwn_is_mimo_mcs(ni->ni_txmcs);
ridx_max = (mimo ? IWN_LAST_HT_RATE : IWN_LAST_HT_SISO_RATE);
for (ridx = ridx_max; ridx >= ridx_min; ridx--) {
uint8_t plcp = iwn_rates[ridx].plcp;
uint8_t ht_plcp = iwn_rates[ridx].ht_plcp;

if (j >= IWN_MAX_TX_RETRIES)
break;
tab = 0;
rflags = 0;
if (ni->ni_flags & IEEE80211_NODE_HT) {
if (ht_plcp == IWN_RATE_HT_SISO_MCS_INV_PLCP)
continue;
/* Do not mix SISO and MIMO HT rates. */
if ((mimo && !iwn_is_mimo_ht_plcp(ht_plcp)) ||
(!mimo && iwn_is_mimo_ht_plcp(ht_plcp)))
continue;
for (i = ni->ni_txmcs; i >= 0; i--) {
if (isclr(ni->ni_rxmcs, i))
continue;
if (ridx == iwn_mcs2ridx[i]) {
tab = ht_plcp;
rflags |= IWN_RFLAG_MCS;
if (sgi_ok)
rflags |= IWN_RFLAG_SGI;
break;
}
}
} else if (plcp != IWN_RATE_INVM_PLCP) {
for (i = ni->ni_txrate; i >= 0; i--) {
if (iwn_rates[ridx].rate == (rs->rs_rates[i] &
IEEE80211_RATE_VAL)) {
tab = plcp;
break;
}
}
}

if (tab == 0)
continue;

if (iwn_is_mimo_ht_plcp(ht_plcp))
rflags |= IWN_RFLAG_ANT(sc->txchainmask);
else
rflags |= IWN_RFLAG_ANT(txant);

if (IWN_RIDX_IS_CCK(ridx))
rflags |= IWN_RFLAG_CCK;

/* Fill the rest with the lowest basic rate. */
rinfo = &iwn_rates[iwn_rval2ridx(ieee80211_min_basic_rate(ic))];
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++;
linkq.retry[j].plcp = tab;
linkq.retry[j].rflags = rflags;
j++;
}

linkq.mimo = (mimo ? j : 0);

/* Fill the rest with the lowest possible rate */
while (j < IWN_MAX_TX_RETRIES) {
tab = iwn_rates[ridx_min].plcp;
rflags = 0;
if (IWN_RIDX_IS_CCK(ridx_min))
rflags |= IWN_RFLAG_CCK;
rflags |= IWN_RFLAG_ANT(txant);
linkq.retry[j].plcp = tab;
linkq.retry[j].rflags = rflags;
j++;
}

return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, 1);
Expand Down Expand Up @@ -4124,7 +4202,8 @@ iwn_add_broadcast_node(struct iwn_softc *sc, int async, int ridx)
/* Use lowest mandatory bit-rate. */
rinfo = &iwn_rates[ridx];
linkq.retry[0].plcp = rinfo->plcp;
linkq.retry[0].rflags = rinfo->flags;
if (IWN_RIDX_IS_CCK(ridx))
linkq.retry[0].rflags = IWN_RFLAG_CCK;
linkq.retry[0].rflags |= IWN_RFLAG_ANT(txant);
/* Use same bit-rate for all TX retries. */
for (i = 1; i < IWN_MAX_TX_RETRIES; i++) {
Expand Down Expand Up @@ -5181,7 +5260,7 @@ iwn_config(struct iwn_softc *sc)
}

ridx = (sc->sc_ic.ic_curmode == IEEE80211_MODE_11A) ?
IWN_RIDX_OFDM6 : IWN_RIDX_CCK1;
IWN_RIDX_OFDM : IWN_RIDX_CCK;
if ((error = iwn_add_broadcast_node(sc, 0, ridx)) != 0) {
XYLog("%s: could not add broadcast node\n",
sc->sc_dev.dv_xname);
Expand Down Expand Up @@ -5335,7 +5414,7 @@ iwn_scan(struct iwn_softc *sc, uint16_t flags, int bgscan)

if (flags & IEEE80211_CHAN_5GHZ) {
/* Send probe requests at 6Mbps. */
tx->plcp = iwn_rates[IWN_RIDX_OFDM6].plcp;
tx->plcp = iwn_rates[IWN_RATE_6M_INDEX].plcp;
rs = &ic->ic_sup_rates[IEEE80211_MODE_11A];
} else {
hdr->flags = htole32(IWN_RXON_24GHZ | IWN_RXON_AUTO);
Expand All @@ -5346,10 +5425,10 @@ iwn_scan(struct iwn_softc *sc, uint16_t flags, int bgscan)
* with CCK rates while associated to a 5GHz AP.
* Send probe requests at 6Mbps OFDM as a workaround.
*/
tx->plcp = iwn_rates[IWN_RIDX_OFDM6].plcp;
tx->plcp = iwn_rates[IWN_RATE_6M_INDEX].plcp;
} else {
/* Send probe requests at 1Mbps. */
tx->plcp = iwn_rates[IWN_RIDX_CCK1].plcp;
tx->plcp = iwn_rates[IWN_RATE_1M_INDEX].plcp;
tx->rflags = IWN_RFLAG_CCK;
}
rs = &ic->ic_sup_rates[IEEE80211_MODE_11G];
Expand Down Expand Up @@ -5590,7 +5669,7 @@ iwn_auth(struct iwn_softc *sc, int arg)
* add the broadcast node again.
*/
ridx = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ?
IWN_RIDX_OFDM6 : IWN_RIDX_CCK1;
IWN_RIDX_OFDM : IWN_RIDX_CCK;
if ((error = iwn_add_broadcast_node(sc, 1, ridx)) != 0) {
XYLog("%s: could not add broadcast node\n",
sc->sc_dev.dv_xname);
Expand Down
Loading

0 comments on commit 38bbc0c

Please sign in to comment.