summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2017-01-12 16:32:29 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2017-01-12 16:32:29 +0000
commit19d64615e1d504bcb0ec4f31357b153e753901ec (patch)
treed31e35d587bd2083e9dc54b819a30efaaf52d29b /sys/dev/ic
parent18fb7d1e5099a73622a6b1f0444f790c711943ee (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.c92
-rw-r--r--sys/dev/ic/ar5008reg.h5
-rw-r--r--sys/dev/ic/ar5416.c3
-rw-r--r--sys/dev/ic/ar9003.c3
-rw-r--r--sys/dev/ic/ar9280.c3
-rw-r--r--sys/dev/ic/ar9285.c3
-rw-r--r--sys/dev/ic/ar9287.c3
-rw-r--r--sys/dev/ic/ar9380.c3
-rw-r--r--sys/dev/ic/athn.c132
-rw-r--r--sys/dev/ic/athnvar.h51
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;
};