Stefan Sperling <s...@stsp.name> writes: > This diff adds 11n support to the athn(4) driver. > Requires -current net80211 code from today. > > Tested in hostap mode and client mode with: > athn0 at pci1 dev 0 function 0 "Atheros AR9281" rev 0x01: apic 2 int 16 > athn0: AR9280 rev 2 (2T2R), ROM rev 22, adddress xx:xx:xx:xx:xx:xx > > And in client mode with: > athn0 at uhub1 port 2 configuration 1 interface 0 "ATHEROS USB2.0 WLAN" rev > 2.00/1.08 addr 2 > athn0: AR9271 rev 1 (1T1R), ROM rev 13, address xx:xx:xx:xx:xx:xx > > Hostap performance is not perfect yet but should be no worse than > 11a/b/g modes in the same environment. > > For Linux clients a fix for WME params is needed which I also posted to tech@. > > This diff does not modify the known-broken and disabled ar9003 code, > apart from making sure it still builds. > > I'm looking for both tests and OKs. > > Index: dev/cardbus/if_athn_cardbus.c > =================================================================== > RCS file: /cvs/src/sys/dev/cardbus/if_athn_cardbus.c,v > retrieving revision 1.14 > diff -u -p -r1.14 if_athn_cardbus.c > --- dev/cardbus/if_athn_cardbus.c 24 Nov 2015 17:11:39 -0000 1.14 > +++ dev/cardbus/if_athn_cardbus.c 8 Jan 2017 09:31:28 -0000 > @@ -43,6 +43,7 @@ > > #include <net80211/ieee80211_var.h> > #include <net80211/ieee80211_amrr.h> > +#include <net80211/ieee80211_mira.h> > #include <net80211/ieee80211_radiotap.h> > > #include <dev/ic/athnreg.h> > Index: dev/ic/ar5008.c > =================================================================== > RCS file: /cvs/src/sys/dev/ic/ar5008.c,v > retrieving revision 1.37 > diff -u -p -r1.37 ar5008.c > --- dev/ic/ar5008.c 29 Nov 2016 10:22:30 -0000 1.37 > +++ dev/ic/ar5008.c 9 Jan 2017 10:14:41 -0000 > @@ -51,6 +51,7 @@ > > #include <net80211/ieee80211_var.h> > #include <net80211/ieee80211_amrr.h> > +#include <net80211/ieee80211_mira.h> > #include <net80211/ieee80211_radiotap.h> > > #include <dev/ic/athnreg.h> > @@ -217,7 +218,7 @@ ar5008_attach(struct athn_softc *sc) > sc->flags |= ATHN_FLAG_11A; > if (base->opCapFlags & AR_OPFLAGS_11G) > sc->flags |= ATHN_FLAG_11G; > - if (base->opCapFlags & AR_OPFLAGS_11N) > + if ((base->opCapFlags & AR_OPFLAGS_11N_DISABLED) == 0) > sc->flags |= ATHN_FLAG_11N; > > IEEE80211_ADDR_COPY(ic->ic_myaddr, base->macAddr); > @@ -952,9 +953,11 @@ ar5008_tx_process(struct athn_softc *sc, > struct ifnet *ifp = &ic->ic_if; > struct athn_txq *txq = &sc->txq[qid]; > struct athn_node *an; > + struct ieee80211_node *ni; > struct athn_tx_buf *bf; > struct ar_tx_desc *ds; > uint8_t failcnt; > + int txfail; > > bf = SIMPLEQ_FIRST(&txq->head); > if (bf == NULL) > @@ -970,13 +973,16 @@ ar5008_tx_process(struct athn_softc *sc, > > sc->sc_tx_timer = 0; > > - if (ds->ds_status1 & AR_TXS1_EXCESSIVE_RETRIES) > + txfail = (ds->ds_status1 & AR_TXS1_EXCESSIVE_RETRIES); > + if (txfail) > ifp->if_oerrors++; > > if (ds->ds_status1 & AR_TXS1_UNDERRUN) > athn_inc_tx_trigger_level(sc); > > an = (struct athn_node *)bf->bf_ni; > + ni = (struct ieee80211_node *)bf->bf_ni; > + > /* > * NB: the data fail count contains the number of un-acked tries > * for the final series used. We must add the number of tries for > @@ -987,10 +993,27 @@ ar5008_tx_process(struct athn_softc *sc, > failcnt += MS(ds->ds_status9, AR_TXS9_FINAL_IDX) * 2; > > /* Update rate control statistics. */ > - an->amn.amn_txcnt++; > - if (failcnt > 0) > - an->amn.amn_retrycnt++; > - > + if (ni->ni_flags & IEEE80211_NODE_HT) { > + an->mn.frames++; > + an->mn.ampdu_size = bf->bf_m->m_pkthdr.len + IEEE80211_CRC_LEN; > + an->mn.agglen = 1; /* XXX We do not yet support Tx agg. */ > + if (failcnt > 0) > + an->mn.retries++; > + if (txfail) > + an->mn.txfail++; > + if ((ic->ic_opmode == IEEE80211_M_STA && > + ic->ic_state == IEEE80211_S_RUN) > +#ifndef IEEE80211_STA_ONLY > + || (ic->ic_opmode == IEEE80211_M_HOSTAP && > + ni->ni_state == IEEE80211_STA_ASSOC) > +#endif > + ) > + ieee80211_mira_choose(&an->mn, ic, ni); > + } else { > + an->amn.amn_txcnt++; > + if (failcnt > 0) > + an->amn.amn_retrycnt++; > + } > DPRINTFN(5, ("Tx done qid=%d status1=%d fail count=%d\n", > qid, ds->ds_status1, failcnt)); > > @@ -1110,7 +1133,7 @@ ar5008_swba_intr(struct athn_softc *sc) > ds->ds_ctl2 = SM(AR_TXC2_XMIT_DATA_TRIES0, 1); > > /* Write Tx rate. */ > - ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? > + ridx = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? > ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK1; > hwrate = athn_rates[ridx].hwrate; > ds->ds_ctl3 = SM(AR_TXC3_XMIT_RATE0, hwrate); > @@ -1315,15 +1338,25 @@ ar5008_tx(struct athn_softc *sc, struct > IEEE80211_FC0_TYPE_DATA) { > /* Use lowest rate for all tries. */ > ridx[0] = ridx[1] = ridx[2] = ridx[3] = > - (ic->ic_curmode == IEEE80211_MODE_11A) ? > - ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK1; > + (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? > + ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK1); > + } else if ((ni->ni_flags & IEEE80211_NODE_HT) && > + ic->ic_fixed_mcs != -1) { > + /* Use same fixed rate for all tries. */ > + ridx[0] = ridx[1] = ridx[2] = ridx[3] = > + ATHN_RIDX_MCS0 + ic->ic_fixed_mcs; > } else if (ic->ic_fixed_rate != -1) { > /* Use same fixed rate for all tries. */ > ridx[0] = ridx[1] = ridx[2] = ridx[3] = > sc->fixed_ridx; > } else { > - int txrate = ni->ni_txrate; > /* Use fallback table of the node. */ > + int txrate; > + > + if (ni->ni_flags & IEEE80211_NODE_HT) > + txrate = ATHN_NUM_LEGACY_RATES + ni->ni_txmcs; > + else > + txrate = ni->ni_txrate; > for (i = 0; i < 4; i++) { > ridx[i] = an->ridx[txrate]; > txrate = an->fallback[txrate]; > @@ -1337,7 +1370,10 @@ ar5008_tx(struct athn_softc *sc, struct > > tap->wt_flags = 0; > /* Use initial transmit rate. */ > - tap->wt_rate = athn_rates[ridx[0]].rate; > + if (athn_rates[ridx[0]].hwrate & 0x80) /* MCS */ > + tap->wt_rate = athn_rates[ridx[0]].hwrate; > + else > + tap->wt_rate = athn_rates[ridx[0]].rate; > tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq); > tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags); > tap->wt_hwqueue = qid; > @@ -1455,11 +1491,16 @@ ar5008_tx(struct athn_softc *sc, struct > > /* Check if frame must be protected using RTS/CTS or CTS-to-self. */ > if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { > + enum ieee80211_htprot htprot; > + > + htprot = (ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK); > /* NB: Group frames are sent using CCK in 802.11b/g. */ > if (totlen > ic->ic_rtsthreshold) { > ds->ds_ctl0 |= AR_TXC0_RTS_ENABLE; > - } else if ((ic->ic_flags & IEEE80211_F_USEPROT) && > - athn_rates[ridx[0]].phy == IEEE80211_T_OFDM) { > + } else if (((ic->ic_flags & IEEE80211_F_USEPROT) && > + athn_rates[ridx[0]].phy == IEEE80211_T_OFDM) || > + ((ic->ic_flags & IEEE80211_F_HTON) && > + htprot != IEEE80211_HTPROT_NONE)) { > if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) > ds->ds_ctl0 |= AR_TXC0_RTS_ENABLE; > else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) > @@ -1523,9 +1564,10 @@ ar5008_tx(struct athn_softc *sc, struct > SM(AR_TXC7_CHAIN_SEL1, sc->txchainmask) | > SM(AR_TXC7_CHAIN_SEL2, sc->txchainmask) | > SM(AR_TXC7_CHAIN_SEL3, sc->txchainmask); > + > #ifdef notyet > /* Use the same short GI setting for all tries. */ > - if (ic->ic_flags & IEEE80211_F_SHGI) > + if (ni->ni_htcaps & IEEE80211_HTCAP_SGI20) > ds->ds_ctl7 |= AR_TXC7_GI0123; > /* Use the same channel width for all tries. */ > if (ic->ic_flags & IEEE80211_F_CBW40) > @@ -1542,7 +1584,7 @@ ar5008_tx(struct athn_softc *sc, struct > ds->ds_ctl5 |= AR_TXC5_RTSCTS_QUAL23; > } > /* Select protection rate (suboptimal but ok). */ > - protridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? > + protridx = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? > ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK2; > if (ds->ds_ctl0 & AR_TXC0_RTS_ENABLE) { > /* Account for CTS duration. */ > Index: dev/ic/ar5008reg.h > =================================================================== > RCS file: /cvs/src/sys/dev/ic/ar5008reg.h,v > retrieving revision 1.3 > diff -u -p -r1.3 ar5008reg.h > --- dev/ic/ar5008reg.h 31 Dec 2010 17:50:48 -0000 1.3 > +++ dev/ic/ar5008reg.h 8 Jan 2017 15:08:19 -0000 > @@ -950,12 +950,13 @@ struct ar_base_eep_header { > uint8_t opCapFlags; > #define AR_OPFLAGS_11A 0x01 > #define AR_OPFLAGS_11G 0x02 > +/* NB: If set, 11n is _disabled_ in the corresponding mode: */ > #define AR_OPFLAGS_11N_5G40 0x04 > #define AR_OPFLAGS_11N_2G40 0x08 > #define AR_OPFLAGS_11N_5G20 0x10 > #define AR_OPFLAGS_11N_2G20 0x20 > -/* Shortcut. */ > -#define AR_OPFLAGS_11N 0x3c > +/* Shortcut for "all of 11n is disabled". */ > +#define AR_OPFLAGS_11N_DISABLED 0x3c > > uint8_t eepMisc; > uint16_t regDmn[2]; > Index: dev/ic/ar5416.c > =================================================================== > RCS file: /cvs/src/sys/dev/ic/ar5416.c,v > retrieving revision 1.19 > diff -u -p -r1.19 ar5416.c > --- dev/ic/ar5416.c 5 Jan 2016 18:41:15 -0000 1.19 > +++ dev/ic/ar5416.c 8 Jan 2017 09:29:59 -0000 > @@ -51,6 +51,7 @@ > > #include <net80211/ieee80211_var.h> > #include <net80211/ieee80211_amrr.h> > +#include <net80211/ieee80211_mira.h> > #include <net80211/ieee80211_radiotap.h> > > #include <dev/ic/athnreg.h> > Index: dev/ic/ar9003.c > =================================================================== > RCS file: /cvs/src/sys/dev/ic/ar9003.c,v > retrieving revision 1.41 > diff -u -p -r1.41 ar9003.c > --- dev/ic/ar9003.c 29 Nov 2016 10:22:30 -0000 1.41 > +++ dev/ic/ar9003.c 8 Jan 2017 09:30:50 -0000 > @@ -51,6 +51,7 @@ > > #include <net80211/ieee80211_var.h> > #include <net80211/ieee80211_amrr.h> > +#include <net80211/ieee80211_mira.h> > #include <net80211/ieee80211_radiotap.h> > > #include <dev/ic/athnreg.h> > Index: dev/ic/ar9280.c > =================================================================== > RCS file: /cvs/src/sys/dev/ic/ar9280.c,v > retrieving revision 1.25 > diff -u -p -r1.25 ar9280.c > --- dev/ic/ar9280.c 5 Jan 2016 18:41:15 -0000 1.25 > +++ dev/ic/ar9280.c 8 Jan 2017 09:30:11 -0000 > @@ -51,6 +51,7 @@ > > #include <net80211/ieee80211_var.h> > #include <net80211/ieee80211_amrr.h> > +#include <net80211/ieee80211_mira.h> > #include <net80211/ieee80211_radiotap.h> > > #include <dev/ic/athnreg.h> > Index: dev/ic/ar9285.c > =================================================================== > RCS file: /cvs/src/sys/dev/ic/ar9285.c,v > retrieving revision 1.26 > diff -u -p -r1.26 ar9285.c > --- dev/ic/ar9285.c 5 Jan 2016 18:41:15 -0000 1.26 > +++ dev/ic/ar9285.c 8 Jan 2017 09:30:24 -0000 > @@ -52,6 +52,7 @@ > > #include <net80211/ieee80211_var.h> > #include <net80211/ieee80211_amrr.h> > +#include <net80211/ieee80211_mira.h> > #include <net80211/ieee80211_radiotap.h> > > #include <dev/ic/athnreg.h> > Index: dev/ic/ar9287.c > =================================================================== > RCS file: /cvs/src/sys/dev/ic/ar9287.c,v > retrieving revision 1.24 > diff -u -p -r1.24 ar9287.c > --- dev/ic/ar9287.c 5 Jan 2016 18:41:15 -0000 1.24 > +++ dev/ic/ar9287.c 8 Jan 2017 09:30:37 -0000 > @@ -51,6 +51,7 @@ > > #include <net80211/ieee80211_var.h> > #include <net80211/ieee80211_amrr.h> > +#include <net80211/ieee80211_mira.h> > #include <net80211/ieee80211_radiotap.h> > > #include <dev/ic/athnreg.h> > Index: dev/ic/ar9380.c > =================================================================== > RCS file: /cvs/src/sys/dev/ic/ar9380.c,v > retrieving revision 1.24 > diff -u -p -r1.24 ar9380.c > --- dev/ic/ar9380.c 5 Jan 2016 18:41:15 -0000 1.24 > +++ dev/ic/ar9380.c 8 Jan 2017 15:10:10 -0000 > @@ -49,6 +49,7 @@ > > #include <net80211/ieee80211_var.h> > #include <net80211/ieee80211_amrr.h> > +#include <net80211/ieee80211_mira.h> > #include <net80211/ieee80211_radiotap.h> > > #include <dev/ic/athnreg.h> > Index: dev/ic/athn.c > =================================================================== > RCS file: /cvs/src/sys/dev/ic/athn.c,v > retrieving revision 1.93 > diff -u -p -r1.93 athn.c > --- dev/ic/athn.c 13 Apr 2016 10:49:26 -0000 1.93 > +++ dev/ic/athn.c 9 Jan 2017 10:01:20 -0000 > @@ -53,6 +53,7 @@ > > #include <net80211/ieee80211_var.h> > #include <net80211/ieee80211_amrr.h> > +#include <net80211/ieee80211_mira.h> > #include <net80211/ieee80211_radiotap.h> > > #include <dev/ic/athnreg.h> > @@ -93,7 +94,7 @@ int athn_set_key(struct ieee80211com *, > struct ieee80211_key *); > void athn_delete_key(struct ieee80211com *, struct ieee80211_node *, > struct ieee80211_key *); > -void athn_iter_func(void *, struct ieee80211_node *); > +void athn_iter_calib(void *, struct ieee80211_node *); > void athn_calib_to(void *); > int athn_init_calib(struct athn_softc *, > struct ieee80211_channel *, struct ieee80211_channel *); > @@ -120,10 +121,12 @@ void athn_init_qos(struct athn_softc *) > int athn_hw_reset(struct athn_softc *, struct ieee80211_channel *, > struct ieee80211_channel *, int); > struct ieee80211_node *athn_node_alloc(struct ieee80211com *); > +void athn_node_free(struct ieee80211com *, struct ieee80211_node *); > void athn_newassoc(struct ieee80211com *, struct ieee80211_node *, > int); > int athn_media_change(struct ifnet *); > void athn_next_scan(void *); > +void athn_iter_newstate(void *, struct ieee80211_node *); > int athn_newstate(struct ieee80211com *, enum ieee80211_state, > int); > void athn_updateedca(struct ieee80211com *); > @@ -289,11 +292,15 @@ athn_attach(struct athn_softc *sc) > int i, ntxstreams, nrxstreams; > > /* Set HT capabilities. */ > - ic->ic_htcaps = > - IEEE80211_HTCAP_SMPS_DIS | > - IEEE80211_HTCAP_CBW20_40 | > + ic->ic_htcaps = (IEEE80211_HTCAP_SMPS_DIS << > + IEEE80211_HTCAP_SMPS_SHIFT); > +#ifdef notyet > + ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40 | > IEEE80211_HTCAP_SGI40 | > IEEE80211_HTCAP_DSSSCCK40; > +#endif > + ic->ic_htxcaps = 0; > +#ifdef notyet > if (AR_SREV_9271(sc) || AR_SREV_9287_10_OR_LATER(sc)) > ic->ic_htcaps |= IEEE80211_HTCAP_SGI20; > if (AR_SREV_9380_10_OR_LATER(sc)) > @@ -302,6 +309,7 @@ athn_attach(struct athn_softc *sc) > ic->ic_htcaps |= IEEE80211_HTCAP_TXSTBC; > ic->ic_htcaps |= 1 << IEEE80211_HTCAP_RXSTBC_SHIFT; > } > +#endif > ntxstreams = sc->ntxchains; > nrxstreams = sc->nrxchains; > if (!AR_SREV_9380_10_OR_LATER(sc)) { > @@ -316,6 +324,11 @@ athn_attach(struct athn_softc *sc) > ic->ic_tx_mcs_set |= IEEE80211_TX_RX_MCS_NOT_EQUAL; > ic->ic_tx_mcs_set |= (ntxstreams - 1) << 2; > } > + > + DPRINTF(("%s: htcaps=0x%x, MCS 0x%x%x%x%x\n", > + sc->sc_dev.dv_xname, ic->ic_htcaps, > + ic->ic_sup_mcs[0], ic->ic_sup_mcs[1], > + ic->ic_sup_mcs[2], ic->ic_sup_mcs[3])); > } > > /* Set supported rates. */ > @@ -346,6 +359,8 @@ athn_attach(struct athn_softc *sc) > if_attach(ifp); > ieee80211_ifattach(ifp); > ic->ic_node_alloc = athn_node_alloc; > + sc->sc_node_free = ic->ic_node_free; > + ic->ic_node_free = athn_node_free; > ic->ic_newassoc = athn_newassoc; > ic->ic_updateslot = athn_updateslot; > ic->ic_updateedca = athn_updateedca; > @@ -425,6 +440,9 @@ athn_get_chanlist(struct athn_softc *sc) > ic->ic_channels[chan].ic_flags = > IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | > IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; > + if (sc->flags & ATHN_FLAG_11N) > + ic->ic_channels[chan].ic_flags |= > + IEEE80211_CHAN_HT; > } > } > if (sc->flags & ATHN_FLAG_11A) { > @@ -433,6 +451,9 @@ athn_get_chanlist(struct athn_softc *sc) > ic->ic_channels[chan].ic_freq = > ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); > ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A; > + if (sc->flags & ATHN_FLAG_11N) > + ic->ic_channels[chan].ic_flags |= > + IEEE80211_CHAN_HT; > } > } > } > @@ -1206,12 +1227,13 @@ athn_btcoex_disable(struct athn_softc *s > #endif > > void > -athn_iter_func(void *arg, struct ieee80211_node *ni) > +athn_iter_calib(void *arg, struct ieee80211_node *ni) > { > struct athn_softc *sc = arg; > struct athn_node *an = (struct athn_node *)ni; > > - ieee80211_amrr_choose(&sc->amrr, ni, &an->amn); > + if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) > + ieee80211_amrr_choose(&sc->amrr, ni, &an->amn); > } > > void > @@ -1251,9 +1273,9 @@ athn_calib_to(void *arg) > #endif > if (ic->ic_fixed_rate == -1) { > if (ic->ic_opmode == IEEE80211_M_STA) > - athn_iter_func(sc, ic->ic_bss); > + athn_iter_calib(sc, ic->ic_bss); > else > - ieee80211_iterate_nodes(ic, athn_iter_func, sc); > + ieee80211_iterate_nodes(ic, athn_iter_calib, sc); > } > timeout_add_msec(&sc->calib_to, 500); > splx(s); > @@ -1377,7 +1399,7 @@ athn_ani_ofdm_err_trigger(struct athn_so > ani->firstep_level++; > ops->set_firstep_level(sc, ani->firstep_level); > } > - } else if (sc->sc_ic.ic_curmode != IEEE80211_MODE_11A) { > + } else if (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_bss->ni_chan)) { > /* > * Beacon RSSI is low, if in b/g mode, turn off OFDM weak > * signal detection and zero first step level to maximize > @@ -1427,7 +1449,7 @@ athn_ani_cck_err_trigger(struct athn_sof > ani->firstep_level++; > ops->set_firstep_level(sc, ani->firstep_level); > } > - } else if (sc->sc_ic.ic_curmode != IEEE80211_MODE_11A) { > + } else if (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_bss->ni_chan)) { > /* > * Beacon RSSI is low, zero first step level to maximize > * CCK sensitivity. > @@ -1790,11 +1812,17 @@ athn_stop_tx_dma(struct athn_softc *sc, > int > athn_txtime(struct athn_softc *sc, int len, int ridx, u_int flags) > { > + struct ieee80211com *ic = &sc->sc_ic; > #define divround(a, b) (((a) + (b) - 1) / (b)) > int txtime; > > - /* XXX HT. */ > - if (athn_rates[ridx].phy == IEEE80211_T_OFDM) { > + if (athn_rates[ridx].hwrate & 0x80) { /* MCS */ > + /* Assumes a 20MHz channel, HT-mixed frame format, no STBC. */ > + txtime = 8 + 8 + 4 + 4 + 4 * 4 + 8 /* HT PLCP */ > + + 4 * ((8 * len + 16 + 6) / (athn_rates[ridx].rate * 2)); > + if (IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan)) > + txtime += 6; /* aSignalExtension */ > + } else if (athn_rates[ridx].phy == IEEE80211_T_OFDM) { > txtime = divround(8 + 4 * len + 3, athn_rates[ridx].rate); > /* SIFS is 10us for 11g but Signal Extension adds 6us. */ > txtime = 16 + 4 + 4 * txtime + 16; > @@ -2310,6 +2338,19 @@ athn_node_alloc(struct ieee80211com *ic) > } > > void > +athn_node_free(struct ieee80211com *ic, struct ieee80211_node *ni) > +{ > + struct athn_softc *sc = ic->ic_softc; > + struct athn_node *an = (void *)ni; > + > + if ((ni->ni_flags & IEEE80211_NODE_HT) && > + ic->ic_state == IEEE80211_S_RUN) > + ieee80211_mira_node_destroy(&an->mn); > + > + sc->sc_node_free(ic, ni); > +} > + > +void > athn_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew) > { > struct athn_softc *sc = ic->ic_softc; > @@ -2318,7 +2359,11 @@ athn_newassoc(struct ieee80211com *ic, s > uint8_t rate; > int ridx, i, j; > > - ieee80211_amrr_node_init(&sc->amrr, &an->amn); > + if (ni->ni_flags & IEEE80211_NODE_HT) > + ieee80211_mira_node_init(&an->mn); > + else > + ieee80211_amrr_node_init(&sc->amrr, &an->amn); > + > /* Start at lowest available bit-rate, AMRR will raise. */ > ni->ni_txrate = 0; > > @@ -2343,6 +2388,35 @@ athn_newassoc(struct ieee80211com *ic, s > } > DPRINTFN(2, ("%d fallbacks to %d\n", i, an->fallback[i])); > } > + > + /* In 11n mode, start at lowest available bit-rate, MiRA will raise. */ > + ni->ni_txmcs = 0; > + > + for (i = 0; i <= ATHN_MCS_MAX; i++) { > + /* Map MCS index to HW rate index. */ > + ridx = ATHN_NUM_LEGACY_RATES + i; > + an->ridx[ridx] = ATHN_RIDX_MCS0 + i; > + > + DPRINTFN(2, ("mcs %d index %d ", i, ridx)); > + /* Compute fallback rate for retries. */ > + if (i == 0 || i == 8) { > + /* MCS 0 and 8 fall back to the lowest legacy rate. */ > + if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) > + an->fallback[ridx] = ATHN_RIDX_OFDM6; > + else > + an->fallback[ridx] = ATHN_RIDX_CCK1; > + } else { > + /* Other MCS fall back to next supported lower MCS. */ > + an->fallback[ridx] = ATHN_NUM_LEGACY_RATES + i; > + for (j = i - 1; j >= 0; j--) { > + if (!isset(ni->ni_rxmcs, j)) > + continue; > + an->fallback[ridx] = ATHN_NUM_LEGACY_RATES + j; > + break; > + } > + } > + DPRINTFN(2, (" fallback to %d\n", an->fallback[ridx])); > + } > } > > int > @@ -2387,6 +2461,19 @@ athn_next_scan(void *arg) > splx(s); > } > > +void > +athn_iter_newstate(void *arg, struct ieee80211_node *ni) > +{ > + struct athn_softc *sc = arg; > + struct ieee80211com *ic = &sc->sc_ic; > + struct athn_node *an = (struct athn_node *)ni; > + > + /* Destroy MiRA node when hopping out of RUN state. */ > + if ((ni->ni_flags & IEEE80211_NODE_HT) && > + ic->ic_state == IEEE80211_S_RUN) > + ieee80211_mira_node_destroy(&an->mn); > +} > + > int > athn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) > { > @@ -2397,6 +2484,11 @@ athn_newstate(struct ieee80211com *ic, e > > timeout_del(&sc->calib_to); > > + if (ic->ic_opmode == IEEE80211_M_STA) > + athn_iter_newstate(sc, ic->ic_bss); > + else > + ieee80211_iterate_nodes(ic, athn_iter_newstate, sc); > + > switch (nstate) { > case IEEE80211_S_INIT: > athn_set_led(sc, 0); > @@ -2497,7 +2589,7 @@ athn_clock_rate(struct athn_softc *sc) > struct ieee80211com *ic = &sc->sc_ic; > int clockrate; /* MHz. */ > > - if (ic->ic_curmode == IEEE80211_MODE_11A) { > + if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->ni_chan)) { > if (sc->flags & ATHN_FLAG_FAST_PLL_CLOCK) > clockrate = AR_CLOCK_RATE_FAST_5GHZ_OFDM; > else > Index: dev/ic/athnvar.h > =================================================================== > RCS file: /cvs/src/sys/dev/ic/athnvar.h,v > retrieving revision 1.36 > diff -u -p -r1.36 athnvar.h > --- dev/ic/athnvar.h 5 Jan 2016 18:41:15 -0000 1.36 > +++ dev/ic/athnvar.h 8 Jan 2017 22:41:47 -0000 > @@ -120,14 +120,18 @@ struct athn_rxq { > #define ATHN_RIDX_CCK2 1 > #define ATHN_RIDX_OFDM6 4 > #define ATHN_RIDX_MCS0 12 > +#define ATHN_RIDX_MCS8 (ATHN_RIDX_MCS0 + 8) > #define ATHN_RIDX_MCS15 27 > #define ATHN_RIDX_MAX 27 > +#define ATHN_MCS_MAX 15 > +#define ATHN_NUM_MCS (ATHN_MCS_MAX + 1) > #define ATHN_IS_HT_RIDX(ridx) ((ridx) >= ATHN_RIDX_MCS0) > +#define ATHN_IS_MIMO_RIDX(ridx) ((ridx) >= ATHN_RIDX_MCS8) > > static const struct athn_rate { > - uint8_t rate; /* Rate in 500Kbps unit or MCS if 0x80. */ > - uint8_t hwrate; /* HW representation. */ > - uint8_t rspridx; /* Control Response Frame rate index. */ > + uint16_t rate; /* Rate in 500Kbps unit. */ > + uint8_t hwrate; /* HW representation. */ > + uint8_t rspridx; /* Control Response Frame rate index. */ > enum ieee80211_phytype phy; > } athn_rates[] = { > { 2, 0x1b, 0, IEEE80211_T_DS }, > @@ -142,22 +146,22 @@ static const struct athn_rate { > { 72, 0x0d, 8, IEEE80211_T_OFDM }, > { 96, 0x08, 8, IEEE80211_T_OFDM }, > { 108, 0x0c, 8, IEEE80211_T_OFDM }, > - { 0x80, 0x80, 8, IEEE80211_T_OFDM }, > - { 0x81, 0x81, 8, IEEE80211_T_OFDM }, > - { 0x82, 0x82, 8, IEEE80211_T_OFDM }, > - { 0x83, 0x83, 8, IEEE80211_T_OFDM }, > - { 0x84, 0x84, 8, IEEE80211_T_OFDM }, > - { 0x85, 0x85, 8, IEEE80211_T_OFDM }, > - { 0x86, 0x86, 8, IEEE80211_T_OFDM }, > - { 0x87, 0x87, 8, IEEE80211_T_OFDM }, > - { 0x88, 0x88, 8, IEEE80211_T_OFDM }, > - { 0x89, 0x89, 8, IEEE80211_T_OFDM }, > - { 0x8a, 0x8a, 8, IEEE80211_T_OFDM }, > - { 0x8b, 0x8b, 8, IEEE80211_T_OFDM }, > - { 0x8c, 0x8c, 8, IEEE80211_T_OFDM }, > - { 0x8d, 0x8d, 8, IEEE80211_T_OFDM }, > - { 0x8e, 0x8e, 8, IEEE80211_T_OFDM }, > - { 0x8f, 0x8f, 8, IEEE80211_T_OFDM } > + { 13, 0x80, 4, IEEE80211_T_OFDM }, > + { 26, 0x81, 6, IEEE80211_T_OFDM }, > + { 39, 0x82, 6, IEEE80211_T_OFDM }, > + { 52, 0x83, 8, IEEE80211_T_OFDM }, > + { 78, 0x84, 8, IEEE80211_T_OFDM }, > + { 104, 0x85, 8, IEEE80211_T_OFDM }, > + { 117, 0x86, 8, IEEE80211_T_OFDM }, > + { 130, 0x87, 8, IEEE80211_T_OFDM }, > + { 26, 0x88, 4, IEEE80211_T_OFDM }, > + { 52, 0x89, 6, IEEE80211_T_OFDM }, > + { 78, 0x8a, 8, IEEE80211_T_OFDM }, > + { 104, 0x8b, 8, IEEE80211_T_OFDM }, > + { 156, 0x8c, 8, IEEE80211_T_OFDM }, > + { 208, 0x8d, 8, IEEE80211_T_OFDM }, > + { 234, 0x8e, 8, IEEE80211_T_OFDM }, > + { 260, 0x8f, 8, IEEE80211_T_OFDM } > }; > > struct athn_series { > @@ -288,11 +292,14 @@ static const uint16_t ar_mcs_ndbps[][2] > #define ATHN_POWER_OFDM_EXT 67 > #define ATHN_POWER_COUNT 68 > > +#define ATHN_NUM_LEGACY_RATES IEEE80211_RATE_MAXSIZE > +#define ATHN_NUM_RATES (ATHN_NUM_LEGACY_RATES + ATHN_NUM_MCS) > struct athn_node { > struct ieee80211_node ni; > struct ieee80211_amrr_node amn; > - uint8_t ridx[IEEE80211_RATE_MAXSIZE]; > - uint8_t fallback[IEEE80211_RATE_MAXSIZE]; > + struct ieee80211_mira_node mn; > + uint8_t ridx[ATHN_NUM_RATES]; > + uint8_t fallback[ATHN_NUM_RATES]; > uint8_t sta_index; > }; > > @@ -429,6 +436,8 @@ struct athn_softc { > > int (*sc_newstate)(struct ieee80211com *, > enum ieee80211_state, int); > + void (*sc_node_free)(struct ieee80211com *, > + struct ieee80211_node *); > > bus_dma_tag_t sc_dmat; > > Index: dev/pci/if_athn_pci.c > =================================================================== > RCS file: /cvs/src/sys/dev/pci/if_athn_pci.c,v > retrieving revision 1.18 > diff -u -p -r1.18 if_athn_pci.c > --- dev/pci/if_athn_pci.c 24 Nov 2015 17:11:39 -0000 1.18 > +++ dev/pci/if_athn_pci.c 8 Jan 2017 09:31:15 -0000 > @@ -43,6 +43,7 @@ > > #include <net80211/ieee80211_var.h> > #include <net80211/ieee80211_amrr.h> > +#include <net80211/ieee80211_mira.h> > #include <net80211/ieee80211_radiotap.h> > > #include <dev/ic/athnreg.h> > Index: dev/usb/if_athn_usb.c > =================================================================== > RCS file: /cvs/src/sys/dev/usb/if_athn_usb.c,v > retrieving revision 1.43 > diff -u -p -r1.43 if_athn_usb.c > --- dev/usb/if_athn_usb.c 29 Nov 2016 10:22:30 -0000 1.43 > +++ dev/usb/if_athn_usb.c 9 Jan 2017 10:57:15 -0000 > @@ -48,6 +48,7 @@ > > #include <net80211/ieee80211_var.h> > #include <net80211/ieee80211_amrr.h> > +#include <net80211/ieee80211_mira.h> > #include <net80211/ieee80211_radiotap.h> > > #include <dev/ic/athnreg.h> > @@ -1132,7 +1133,7 @@ athn_usb_newassoc_cb(struct athn_usb_sof > > s = splnet(); > /* NB: Node may have left before we got scheduled. */ > - if (ni->ni_associd != 0) > + if (ni->ni_associd != 0 && ni->ni_state == IEEE80211_STA_ASSOC) > (void)athn_usb_create_node(usc, ni); > ieee80211_release_node(ic, ni); > splx(s); > @@ -1224,7 +1225,7 @@ athn_usb_create_node(struct athn_usb_sof > struct athn_node *an = (struct athn_node *)ni; > struct ar_htc_target_sta sta; > struct ar_htc_target_rate rate; > - int error; > + int error, i, j; > > /* Firmware cannot handle more than 8 STAs. */ > if (usc->nnodes > AR_USB_MAX_STA) > @@ -1257,8 +1258,16 @@ athn_usb_create_node(struct athn_usb_sof > ni->ni_rates.rs_nrates); > if (ni->ni_flags & IEEE80211_NODE_HT) { > rate.capflags |= htobe32(AR_RC_HT_FLAG); > + /* Setup HT rates. */ > + for (i = 0, j = 0; i < IEEE80211_HT_NUM_MCS; i++) { > + if (!isset(ni->ni_rxmcs, i)) > + continue; > + if (j >= AR_HTC_RATE_MAX) > + break; > + rate.ht_rates.rs_rates[j++] = i; > + } > + rate.ht_rates.rs_nrates = j; > #ifdef notyet > - /* XXX setup HT rates */ > if (ni->ni_htcaps & IEEE80211_HTCAP_CBW20_40) > rate.capflags |= htobe32(AR_RC_40_FLAG); > if (ni->ni_htcaps & IEEE80211_HTCAP_SGI40) >
Hmm, I've been running the 11n for a while and it seems to be a lot slower than 11g for me. Just did quick benchmark using tcpbench between OpenBSD hostAP (athn) and laptop (iwn). It looks when my athn is in 11n mode I get around ~3 Mbps: ... Conn: 1 Mbps: 3.321 Peak Mbps: 5.763 Avg Mbps: 3.321 16044 406888 3.249 100.00% Conn: 1 Mbps: 3.249 Peak Mbps: 5.763 Avg Mbps: 3.249 17045 350416 2.803 100.00% Conn: 1 Mbps: 2.803 Peak Mbps: 5.763 Avg Mbps: 2.803 18047 408336 3.260 100.00% Conn: 1 Mbps: 3.260 Peak Mbps: 5.763 Avg Mbps: 3.260 19050 414128 3.303 100.00% Conn: 1 Mbps: 3.303 Peak Mbps: 5.763 Avg Mbps: 3.303 20054 402544 3.211 100.00% Conn: 1 Mbps: 3.211 Peak Mbps: 5.763 Avg Mbps: 3.211 21055 444536 3.553 100.00% Conn: 1 Mbps: 3.553 Peak Mbps: 5.763 Avg Mbps: 3.553 22056 363448 2.908 100.00% Conn: 1 Mbps: 2.908 Peak Mbps: 5.763 Avg Mbps: 2.908 23058 427160 3.414 100.00% ... Switching the AP to 11g mode seems to provide a lot better throughput: ... Conn: 1 Mbps: 13.449 Peak Mbps: 14.373 Avg Mbps: 13.449 4003 1765112 14.121 100.00% Conn: 1 Mbps: 14.121 Peak Mbps: 14.373 Avg Mbps: 14.121 5003 1579768 12.638 100.00% Conn: 1 Mbps: 12.638 Peak Mbps: 14.373 Avg Mbps: 12.638 6004 1374152 10.993 100.00% Conn: 1 Mbps: 10.993 Peak Mbps: 14.373 Avg Mbps: 10.993 7017 1268448 10.027 100.00% Conn: 1 Mbps: 10.027 Peak Mbps: 14.373 Avg Mbps: 10.027 8017 1165640 9.325 100.00% Conn: 1 Mbps: 9.325 Peak Mbps: 14.373 Avg Mbps: 9.325 9018 1081656 8.653 100.00% Conn: 1 Mbps: 8.653 Peak Mbps: 14.373 Avg Mbps: 8.653 10019 1113512 8.908 100.00% Conn: 1 Mbps: 8.908 Peak Mbps: 14.373 Avg Mbps: 8.908 11020 1155504 9.235 100.00% Conn: 1 Mbps: 9.235 Peak Mbps: 14.373 Avg Mbps: 9.235 ... Quickly looking it seems the 11g is 3x faster than 11n which seems a bit odd. I'd assume they should be roughly the same. Any idea what could explain the difference? There are 8 other wireless networks in range but all of those are on different channels. running with: athn0 at pci4 dev 0 function 0 "Atheros AR9281" rev 0x01: apic 5 int 16 athn0: AR9280 rev 2 (2T2R), ROM rev 22, address 04:f0:21:16:93:cc and iwn0 at pci2 dev 0 function 0 "Intel Centrino Advanced-N 6205" rev 0x34: msi, MIMO 2T2R, MoW, address 60:67:20:f8:17:f4 Timo