diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2017-01-12 16:32:29 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2017-01-12 16:32:29 +0000 |
commit | 19d64615e1d504bcb0ec4f31357b153e753901ec (patch) | |
tree | d31e35d587bd2083e9dc54b819a30efaaf52d29b /sys/dev/ic | |
parent | 18fb7d1e5099a73622a6b1f0444f790c711943ee (diff) |
Finish initial 11n support for athn(4).
The heavy lifting was done by damien@ years ago. I didn't even have
to figure out what the hardware expects, the code was already there.
This driver now supports MCS 0-15 in client and hostap mode.
No Tx aggregation and no 40 MHz channels yet.
tested by vgross@, bmercer@, tb@, jmc@, Vadim Vygonets, Peter Kay
ok bmercer@ tb@ phessler@
Diffstat (limited to 'sys/dev/ic')
-rw-r--r-- | sys/dev/ic/ar5008.c | 92 | ||||
-rw-r--r-- | sys/dev/ic/ar5008reg.h | 5 | ||||
-rw-r--r-- | sys/dev/ic/ar5416.c | 3 | ||||
-rw-r--r-- | sys/dev/ic/ar9003.c | 3 | ||||
-rw-r--r-- | sys/dev/ic/ar9280.c | 3 | ||||
-rw-r--r-- | sys/dev/ic/ar9285.c | 3 | ||||
-rw-r--r-- | sys/dev/ic/ar9287.c | 3 | ||||
-rw-r--r-- | sys/dev/ic/ar9380.c | 3 | ||||
-rw-r--r-- | sys/dev/ic/athn.c | 132 | ||||
-rw-r--r-- | sys/dev/ic/athnvar.h | 51 |
10 files changed, 231 insertions, 67 deletions
diff --git a/sys/dev/ic/ar5008.c b/sys/dev/ic/ar5008.c index 5de3a212ec4..942f6700637 100644 --- a/sys/dev/ic/ar5008.c +++ b/sys/dev/ic/ar5008.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ar5008.c,v 1.37 2016/11/29 10:22:30 jsg Exp $ */ +/* $OpenBSD: ar5008.c,v 1.38 2017/01/12 16:32:28 stsp Exp $ */ /*- * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> @@ -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> @@ -213,12 +214,24 @@ ar5008_attach(struct athn_softc *sc) return (EINVAL); } - if (base->opCapFlags & AR_OPFLAGS_11A) + if (base->opCapFlags & AR_OPFLAGS_11A) { sc->flags |= ATHN_FLAG_11A; - if (base->opCapFlags & AR_OPFLAGS_11G) + if ((base->opCapFlags & AR_OPFLAGS_11N_5G20) == 0) + sc->flags |= ATHN_FLAG_11N; +#ifdef notyet + if ((base->opCapFlags & AR_OPFLAGS_11N_5G40) == 0) + sc->flags |= ATHN_FLAG_11N; +#endif + } + if (base->opCapFlags & AR_OPFLAGS_11G) { sc->flags |= ATHN_FLAG_11G; - if (base->opCapFlags & AR_OPFLAGS_11N) - sc->flags |= ATHN_FLAG_11N; + if ((base->opCapFlags & AR_OPFLAGS_11N_2G20) == 0) + sc->flags |= ATHN_FLAG_11N; +#ifdef notyet + if ((base->opCapFlags & AR_OPFLAGS_11N_2G40) == 0) + sc->flags |= ATHN_FLAG_11N; +#endif + } IEEE80211_ADDR_COPY(ic->ic_myaddr, base->macAddr); @@ -952,9 +965,11 @@ ar5008_tx_process(struct athn_softc *sc, int qid) 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 +985,16 @@ ar5008_tx_process(struct athn_softc *sc, int qid) 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 +1005,26 @@ ar5008_tx_process(struct athn_softc *sc, int qid) 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_state == IEEE80211_S_RUN) { +#ifndef IEEE80211_STA_ONLY + if (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 +1144,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 +1349,25 @@ ar5008_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, 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 +1381,10 @@ ar5008_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, 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 +1502,16 @@ ar5008_tx(struct athn_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)) { + 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) @@ -1525,7 +1577,7 @@ ar5008_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, 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,8 +1594,8 @@ ar5008_tx(struct athn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, ds->ds_ctl5 |= AR_TXC5_RTSCTS_QUAL23; } /* Select protection rate (suboptimal but ok). */ - protridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? - ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK2; + protridx = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? + ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK1; if (ds->ds_ctl0 & AR_TXC0_RTS_ENABLE) { /* Account for CTS duration. */ dur += athn_txtime(sc, IEEE80211_ACK_LEN, diff --git a/sys/dev/ic/ar5008reg.h b/sys/dev/ic/ar5008reg.h index d5845cb0134..7f1f32c7569 100644 --- a/sys/dev/ic/ar5008reg.h +++ b/sys/dev/ic/ar5008reg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ar5008reg.h,v 1.3 2010/12/31 17:50:48 damien Exp $ */ +/* $OpenBSD: ar5008reg.h,v 1.4 2017/01/12 16:32:28 stsp Exp $ */ /*- * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> @@ -950,12 +950,11 @@ 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 uint8_t eepMisc; uint16_t regDmn[2]; diff --git a/sys/dev/ic/ar5416.c b/sys/dev/ic/ar5416.c index de79dd917f5..1cb5d545068 100644 --- a/sys/dev/ic/ar5416.c +++ b/sys/dev/ic/ar5416.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ar5416.c,v 1.19 2016/01/05 18:41:15 stsp Exp $ */ +/* $OpenBSD: ar5416.c,v 1.20 2017/01/12 16:32:28 stsp Exp $ */ /*- * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> @@ -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> diff --git a/sys/dev/ic/ar9003.c b/sys/dev/ic/ar9003.c index 76b06d4ff54..0e299c9adbf 100644 --- a/sys/dev/ic/ar9003.c +++ b/sys/dev/ic/ar9003.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ar9003.c,v 1.41 2016/11/29 10:22:30 jsg Exp $ */ +/* $OpenBSD: ar9003.c,v 1.42 2017/01/12 16:32:28 stsp Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> @@ -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> diff --git a/sys/dev/ic/ar9280.c b/sys/dev/ic/ar9280.c index 55366961bff..4c3c549daf0 100644 --- a/sys/dev/ic/ar9280.c +++ b/sys/dev/ic/ar9280.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ar9280.c,v 1.25 2016/01/05 18:41:15 stsp Exp $ */ +/* $OpenBSD: ar9280.c,v 1.26 2017/01/12 16:32:28 stsp Exp $ */ /*- * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> @@ -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> diff --git a/sys/dev/ic/ar9285.c b/sys/dev/ic/ar9285.c index 9e379236e53..a817b0dcef6 100644 --- a/sys/dev/ic/ar9285.c +++ b/sys/dev/ic/ar9285.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ar9285.c,v 1.26 2016/01/05 18:41:15 stsp Exp $ */ +/* $OpenBSD: ar9285.c,v 1.27 2017/01/12 16:32:28 stsp Exp $ */ /*- * Copyright (c) 2009-2010 Damien Bergamini <damien.bergamini@free.fr> @@ -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> diff --git a/sys/dev/ic/ar9287.c b/sys/dev/ic/ar9287.c index 2bb331501fd..e61f78427c0 100644 --- a/sys/dev/ic/ar9287.c +++ b/sys/dev/ic/ar9287.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ar9287.c,v 1.24 2016/01/05 18:41:15 stsp Exp $ */ +/* $OpenBSD: ar9287.c,v 1.25 2017/01/12 16:32:28 stsp Exp $ */ /*- * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> @@ -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> diff --git a/sys/dev/ic/ar9380.c b/sys/dev/ic/ar9380.c index cb6a115713f..30c687eb74b 100644 --- a/sys/dev/ic/ar9380.c +++ b/sys/dev/ic/ar9380.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ar9380.c,v 1.24 2016/01/05 18:41:15 stsp Exp $ */ +/* $OpenBSD: ar9380.c,v 1.25 2017/01/12 16:32:28 stsp Exp $ */ /*- * Copyright (c) 2011 Damien Bergamini <damien.bergamini@free.fr> @@ -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> diff --git a/sys/dev/ic/athn.c b/sys/dev/ic/athn.c index ad6ccd38170..1b616a5a59d 100644 --- a/sys/dev/ic/athn.c +++ b/sys/dev/ic/athn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: athn.c,v 1.93 2016/04/13 10:49:26 mpi Exp $ */ +/* $OpenBSD: athn.c,v 1.94 2017/01/12 16:32:28 stsp Exp $ */ /*- * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> @@ -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_node *, 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 *); @@ -122,8 +123,11 @@ int athn_hw_reset(struct athn_softc *, struct ieee80211_channel *, struct ieee80211_node *athn_node_alloc(struct ieee80211com *); void athn_newassoc(struct ieee80211com *, struct ieee80211_node *, int); +void athn_node_leave(struct ieee80211com *, struct ieee80211_node *); int athn_media_change(struct ifnet *); void athn_next_scan(void *); +void athn_iter_mira_delete(void *, struct ieee80211_node *); +void athn_delete_mira_nodes(struct athn_softc *); int athn_newstate(struct ieee80211com *, enum ieee80211_state, int); void athn_updateedca(struct ieee80211com *); @@ -289,11 +293,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 +310,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)) { @@ -346,6 +355,9 @@ athn_attach(struct athn_softc *sc) if_attach(ifp); ieee80211_ifattach(ifp); ic->ic_node_alloc = athn_node_alloc; +#ifndef IEEE80211_STA_ONLY + ic->ic_node_leave = athn_node_leave; +#endif ic->ic_newassoc = athn_newassoc; ic->ic_updateslot = athn_updateslot; ic->ic_updateedca = athn_updateedca; @@ -370,10 +382,13 @@ void athn_detach(struct athn_softc *sc) { struct ifnet *ifp = &sc->sc_ic.ic_if; + struct ieee80211com *ic = &sc->sc_ic; int qid; timeout_del(&sc->scan_to); timeout_del(&sc->calib_to); + if (ic->ic_flags & IEEE80211_F_HTON) + athn_delete_mira_nodes(sc); if (!(sc->flags & ATHN_FLAG_USB)) { for (qid = 0; qid < ATHN_QID_COUNT; qid++) @@ -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 *sc) #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_softc *sc) 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_softc *sc) 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 qid) 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; @@ -2306,7 +2334,12 @@ athn_hw_reset(struct athn_softc *sc, struct ieee80211_channel *c, struct ieee80211_node * athn_node_alloc(struct ieee80211com *ic) { - return (malloc(sizeof(struct athn_node), M_DEVBUF, M_NOWAIT | M_ZERO)); + struct athn_node *an; + + an = malloc(sizeof(struct athn_node), M_DEVBUF, M_NOWAIT | M_ZERO); + if (ic->ic_flags & IEEE80211_F_HTON) + ieee80211_mira_node_init(&an->mn); + return (struct ieee80211_node *)an; } void @@ -2318,7 +2351,11 @@ athn_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew) uint8_t rate; int ridx, i, j; - ieee80211_amrr_node_init(&sc->amrr, &an->amn); + if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) + ieee80211_amrr_node_init(&sc->amrr, &an->amn); + else if (ic->ic_opmode == IEEE80211_M_STA) + ieee80211_mira_node_init(&an->mn); + /* Start at lowest available bit-rate, AMRR will raise. */ ni->ni_txrate = 0; @@ -2343,8 +2380,47 @@ athn_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew) } 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])); + } } +#ifndef IEEE80211_STA_ONLY +void +athn_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + struct athn_node *an = (void *)ni; + if (ic->ic_flags & IEEE80211_F_HTON) + ieee80211_mira_node_destroy(&an->mn); +} +#endif + int athn_media_change(struct ifnet *ifp) { @@ -2387,6 +2463,26 @@ athn_next_scan(void *arg) splx(s); } +void +athn_iter_mira_delete(void *arg, struct ieee80211_node *ni) +{ + struct athn_node *an = (struct athn_node *)ni; + ieee80211_mira_node_destroy(&an->mn); +} + +/* Delete pending timeouts managed by MiRA. */ +void +athn_delete_mira_nodes(struct athn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + if (ic->ic_opmode == IEEE80211_M_STA) { + struct athn_node *an = (struct athn_node *)ic->ic_bss; + ieee80211_mira_node_destroy(&an->mn); + } else + ieee80211_iterate_nodes(ic, athn_iter_mira_delete, sc); +} + int athn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) { @@ -2397,6 +2493,10 @@ athn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) timeout_del(&sc->calib_to); + if ((ic->ic_flags & IEEE80211_F_HTON) && + ic->ic_state == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) + athn_delete_mira_nodes(sc); + switch (nstate) { case IEEE80211_S_INIT: athn_set_led(sc, 0); @@ -2497,7 +2597,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 diff --git a/sys/dev/ic/athnvar.h b/sys/dev/ic/athnvar.h index 6073413c8f1..2232d5484d2 100644 --- a/sys/dev/ic/athnvar.h +++ b/sys/dev/ic/athnvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: athnvar.h,v 1.36 2016/01/05 18:41:15 stsp Exp $ */ +/* $OpenBSD: athnvar.h,v 1.37 2017/01/12 16:32:28 stsp Exp $ */ /*- * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> @@ -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; }; |