summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/iwn/if_iwn.c149
-rw-r--r--sys/dev/iwn/if_iwnvar.h1
-rw-r--r--sys/dev/ral/rt2560.c2
-rw-r--r--sys/dev/ral/rt2661.c2
-rw-r--r--sys/dev/ral/rt2860.c7
-rw-r--r--sys/net80211/ieee80211_amrr.c101
-rw-r--r--sys/net80211/ieee80211_phy.c193
-rw-r--r--sys/net80211/ieee80211_phy.h51
8 files changed, 431 insertions, 75 deletions
diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c
index cdf7d27..6e0cc1b 100644
--- a/sys/dev/iwn/if_iwn.c
+++ b/sys/dev/iwn/if_iwn.c
@@ -335,6 +335,8 @@ enum {
IWN_DEBUG_NODE = 0x00000400, /* node management */
IWN_DEBUG_LED = 0x00000800, /* led management */
IWN_DEBUG_CMD = 0x00001000, /* cmd submission */
+ IWN_DEBUG_TXRATE = 0x00002000, /* TX rate debugging */
+ IWN_DEBUG_PWRSAVE = 0x00004000, /* Power save operations */
IWN_DEBUG_FATAL = 0x80000000, /* fatal errors */
IWN_DEBUG_ANY = 0xffffffff
};
@@ -2098,56 +2100,106 @@ rate2plcp(int rate)
return 0;
}
-static void
-iwn_newassoc(struct ieee80211_node *ni, int isnew)
+/*
+ * Calculate the required PLCP value from the given rate,
+ * to the given node.
+ *
+ * This will take the node configuration (eg 11n, rate table
+ * setup, etc) into consideration.
+ */
+static uint32_t
+iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni,
+ uint8_t rate)
{
#define RV(v) ((v) & IEEE80211_RATE_VAL)
struct ieee80211com *ic = ni->ni_ic;
- struct iwn_softc *sc = ic->ic_ifp->if_softc;
- struct iwn_node *wn = (void *)ni;
uint8_t txant1, txant2;
- int i, plcp, rate, ridx;
+ uint32_t plcp = 0;
+ int ridx;
/* Use the first valid TX antenna. */
txant1 = IWN_LSB(sc->txchainmask);
txant2 = IWN_LSB(sc->txchainmask & ~txant1);
+ /*
+ * If it's an MCS rate, let's set the plcp correctly
+ * and set the relevant flags based on the node config.
+ */
if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
- ridx = ni->ni_rates.rs_nrates - 1;
- for (i = ni->ni_htrates.rs_nrates - 1; i >= 0; i--) {
- plcp = RV(ni->ni_htrates.rs_rates[i]) | IWN_RFLAG_MCS;
- if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
- plcp |= IWN_RFLAG_HT40;
- if (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40)
- plcp |= IWN_RFLAG_SGI;
- } else if (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)
+ /*
+ * Set the initial PLCP value to be between 0->31 for
+ * MCS 0 -> MCS 31, then set the "I'm an MCS rate!"
+ * flag.
+ */
+ plcp = RV(rate) | IWN_RFLAG_MCS;
+
+ /*
+ * XXX the following should only occur if both
+ * the local configuration _and_ the remote node
+ * advertise these capabilities. Thus this code
+ * may need fixing!
+ */
+
+ /*
+ * Set the channel width and guard interval.
+ */
+ if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
+ plcp |= IWN_RFLAG_HT40;
+ if (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40)
plcp |= IWN_RFLAG_SGI;
- if (RV(ni->ni_htrates.rs_rates[i]) > 7)
- plcp |= IWN_RFLAG_ANT(txant1 | txant2);
- else
- plcp |= IWN_RFLAG_ANT(txant1);
- if (ridx >= 0) {
- rate = RV(ni->ni_rates.rs_rates[ridx]);
- wn->ridx[rate] = plcp;
- }
- wn->ridx[IEEE80211_RATE_MCS | i] = plcp;
- ridx--;
+ } else if (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) {
+ plcp |= IWN_RFLAG_SGI;
}
- } else {
- for (i = 0; i < ni->ni_rates.rs_nrates; i++) {
- rate = RV(ni->ni_rates.rs_rates[i]);
- plcp = rate2plcp(rate);
- ridx = ic->ic_rt->rateCodeToIndex[rate];
- if (ridx < IWN_RIDX_OFDM6 &&
- IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
- plcp |= IWN_RFLAG_CCK;
+
+ /*
+ * If it's a two stream rate, enable TX on both
+ * antennas.
+ *
+ * XXX three stream rates?
+ */
+ if (rate > 0x87)
+ plcp |= IWN_RFLAG_ANT(txant1 | txant2);
+ else
plcp |= IWN_RFLAG_ANT(txant1);
- wn->ridx[rate] = htole32(plcp);
- }
+ } else {
+ /*
+ * Set the initial PLCP - fine for both
+ * OFDM and CCK rates.
+ */
+ plcp = rate2plcp(rate);
+
+ /* Set CCK flag if it's CCK */
+
+ /* XXX It would be nice to have a method
+ * to map the ridx -> phy table entry
+ * so we could just query that, rather than
+ * this hack to check against IWN_RIDX_OFDM6.
+ */
+ ridx = ieee80211_legacy_rate_lookup(ic->ic_rt,
+ rate & IEEE80211_RATE_VAL);
+ if (ridx < IWN_RIDX_OFDM6 &&
+ IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
+ plcp |= IWN_RFLAG_CCK;
+
+ /* Set antenna configuration */
+ plcp |= IWN_RFLAG_ANT(txant1);
}
+
+ DPRINTF(sc, IWN_DEBUG_TXRATE, "%s: rate=0x%02x, plcp=0x%08x\n",
+ __func__,
+ rate,
+ plcp);
+
+ return (htole32(plcp));
#undef RV
}
+static void
+iwn_newassoc(struct ieee80211_node *ni, int isnew)
+{
+ /* Doesn't do anything at the moment */
+}
+
static int
iwn_media_change(struct ifnet *ifp)
{
@@ -3401,7 +3453,8 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
(void) ieee80211_ratectl_rate(ni, NULL, 0);
rate = ni->ni_txrate;
}
- ridx = ic->ic_rt->rateCodeToIndex[rate];
+ ridx = ieee80211_legacy_rate_lookup(ic->ic_rt,
+ rate & IEEE80211_RATE_VAL);
/* Encrypt the frame if need be. */
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
@@ -3507,7 +3560,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
tx->rts_ntries = 60;
tx->data_ntries = 15;
tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
- tx->rate = wn->ridx[rate];
+ tx->rate = iwn_rate_to_plcp(sc, ni, rate);
if (tx->id == sc->broadcast_id) {
/* Group or management frame. */
tx->linkq = 0;
@@ -3638,7 +3691,8 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
/* Choose a TX rate index. */
rate = params->ibp_rate0;
- ridx = ic->ic_rt->rateCodeToIndex[rate];
+ ridx = ieee80211_legacy_rate_lookup(ic->ic_rt,
+ rate & IEEE80211_RATE_VAL);
if (ridx == (uint8_t)-1) {
/* XXX fall back to mcast/mgmt rate? */
m_freem(m);
@@ -3714,14 +3768,18 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
tx->rts_ntries = params->ibp_try1;
tx->data_ntries = params->ibp_try0;
tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
+
+ /* XXX should just use iwn_rate_to_plcp() */
tx->rate = htole32(rate2plcp(rate));
if (ridx < IWN_RIDX_OFDM6 &&
IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
tx->rate |= htole32(IWN_RFLAG_CCK);
+
/* Group or management frame. */
tx->linkq = 0;
txant = IWN_LSB(sc->txchainmask);
tx->rate |= htole32(IWN_RFLAG_ANT(txant));
+
/* Set physical address of "scratch area". */
tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr));
tx->hiaddr = IWN_HIADDR(data->scratch_paddr);
@@ -4077,14 +4135,20 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni)
else
txrate = rs->rs_nrates - 1;
for (i = 0; i < IWN_MAX_TX_RETRIES; i++) {
+ uint32_t plcp;
+
if (IEEE80211_IS_CHAN_HT(ni->ni_chan))
rate = IEEE80211_RATE_MCS | txrate;
else
rate = RV(rs->rs_rates[txrate]);
- linkq.retry[i] = wn->ridx[rate];
- if ((le32toh(wn->ridx[rate]) & IWN_RFLAG_MCS) &&
- RV(le32toh(wn->ridx[rate])) > 7)
+ /* Do rate -> PLCP config mapping */
+ plcp = iwn_rate_to_plcp(sc, ni, rate);
+ linkq.retry[i] = plcp;
+
+ /* Special case for dual-stream rates? */
+ if ((le32toh(plcp) & IWN_RFLAG_MCS) &&
+ RV(le32toh(plcp)) > 7)
linkq.mimo = i + 1;
/* Next retry at immediate lower bit-rate. */
@@ -4940,6 +5004,13 @@ iwn_set_pslevel(struct iwn_softc *sc, int dtim, int level, int async)
uint32_t reg;
int i;
+ DPRINTF(sc, IWN_DEBUG_PWRSAVE,
+ "%s: dtim=%d, level=%d, async=%d\n",
+ __func__,
+ dtim,
+ level,
+ async);
+
/* Select which PS parameters to use. */
if (dtim <= 2)
pmgt = &iwn_pmgt[0][level];
diff --git a/sys/dev/iwn/if_iwnvar.h b/sys/dev/iwn/if_iwnvar.h
index 7326260..0bcc19b 100644
--- a/sys/dev/iwn/if_iwnvar.h
+++ b/sys/dev/iwn/if_iwnvar.h
@@ -102,7 +102,6 @@ struct iwn_node {
struct ieee80211_node ni; /* must be the first */
uint16_t disable_tid;
uint8_t id;
- uint32_t ridx[256];
struct {
uint64_t bitmap;
int startidx;
diff --git a/sys/dev/ral/rt2560.c b/sys/dev/ral/rt2560.c
index c67f1f7..7c1b9de 100644
--- a/sys/dev/ral/rt2560.c
+++ b/sys/dev/ral/rt2560.c
@@ -2370,7 +2370,7 @@ rt2560_set_basicrates(struct rt2560_softc *sc,
if (!(rate & IEEE80211_RATE_BASIC))
continue;
- mask |= 1 << ic->ic_rt->rateCodeToIndex[RV(rate)];
+ mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, RV(rate));
}
RAL_WRITE(sc, RT2560_ARSP_PLCP_1, mask);
diff --git a/sys/dev/ral/rt2661.c b/sys/dev/ral/rt2661.c
index 8ae2515..70c30f1 100644
--- a/sys/dev/ral/rt2661.c
+++ b/sys/dev/ral/rt2661.c
@@ -1923,7 +1923,7 @@ rt2661_set_basicrates(struct rt2661_softc *sc,
if (!(rate & IEEE80211_RATE_BASIC))
continue;
- mask |= 1 << ic->ic_rt->rateCodeToIndex[RV(rate)];
+ mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, RV(rate));
}
RAL_WRITE(sc, RT2661_TXRX_CSR5, mask);
diff --git a/sys/dev/ral/rt2860.c b/sys/dev/ral/rt2860.c
index 4207d75..3bdd01d 100644
--- a/sys/dev/ral/rt2860.c
+++ b/sys/dev/ral/rt2860.c
@@ -1528,7 +1528,7 @@ rt2860_tx(struct rt2860_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
tid = 0;
}
ring = &sc->txq[qid];
- ridx = ic->ic_rt->rateCodeToIndex[rate];
+ ridx = ieee80211_legacy_rate_lookup(ic->ic_rt, rate);
/* get MCS code from rate index */
mcs = rt2860_rates[ridx].mcs;
@@ -1779,7 +1779,8 @@ rt2860_tx_raw(struct rt2860_softc *sc, struct mbuf *m,
/* Choose a TX rate index. */
rate = params->ibp_rate0;
- ridx = ic->ic_rt->rateCodeToIndex[rate];
+ ridx = ieee80211_legacy_rate_lookup(ic->ic_rt,
+ rate & IEEE80211_RATE_VAL);
if (ridx == (uint8_t)-1) {
/* XXX fall back to mcast/mgmt rate? */
m_freem(m);
@@ -2311,7 +2312,7 @@ rt2860_set_basicrates(struct rt2860_softc *sc,
if (!(rate & IEEE80211_RATE_BASIC))
continue;
- mask |= 1 << ic->ic_rt->rateCodeToIndex[RV(rate)];
+ mask |= 1 << ieee80211_legacy_rate_lookup(ic->ic_rt, RV(rate));
}
RAL_WRITE(sc, RT2860_LEGACY_BASIC_RATE, mask);
diff --git a/sys/net80211/ieee80211_amrr.c b/sys/net80211/ieee80211_amrr.c
index 73dd901..874659f 100644
--- a/sys/net80211/ieee80211_amrr.c
+++ b/sys/net80211/ieee80211_amrr.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_ht.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_ratectl.h>
@@ -128,13 +129,25 @@ amrr_deinit(struct ieee80211vap *vap)
free(vap->iv_rs, M_80211_RATECTL);
}
+static int
+amrr_node_is_11n(struct ieee80211_node *ni)
+{
+
+ if (ni->ni_chan == NULL)
+ return (0);
+ if (ni->ni_chan == IEEE80211_CHAN_ANYC)
+ return (0);
+ return (IEEE80211_IS_CHAN_HT(ni->ni_chan));
+}
+
static void
amrr_node_init(struct ieee80211_node *ni)
{
- const struct ieee80211_rateset *rs = &ni->ni_rates;
+ const struct ieee80211_rateset *rs = NULL;
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_amrr *amrr = vap->iv_rs;
struct ieee80211_amrr_node *amn;
+ uint8_t rate;
if (ni->ni_rctls == NULL) {
ni->ni_rctls = amn = malloc(sizeof(struct ieee80211_amrr_node),
@@ -152,16 +165,50 @@ amrr_node_init(struct ieee80211_node *ni)
amn->amn_txcnt = amn->amn_retrycnt = 0;
amn->amn_success_threshold = amrr->amrr_min_success_threshold;
- /* pick initial rate */
- for (amn->amn_rix = rs->rs_nrates - 1;
- amn->amn_rix > 0 && (rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) > 72;
- amn->amn_rix--)
- ;
- ni->ni_txrate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
+ /* 11n or not? Pick the right rateset */
+ if (amrr_node_is_11n(ni)) {
+ /* XXX ew */
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
+ "%s: 11n node", __func__);
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ } else {
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
+ "%s: non-11n node", __func__);
+ rs = &ni->ni_rates;
+ }
+
+ /* Initial rate - lowest */
+ rate = rs->rs_rates[0];
+
+ /* XXX clear the basic rate flag if it's not 11n */
+ if (! amrr_node_is_11n(ni))
+ rate &= IEEE80211_RATE_VAL;
+
+ /* pick initial rate from the rateset - HT or otherwise */
+ for (amn->amn_rix = rs->rs_nrates - 1; amn->amn_rix > 0;
+ amn->amn_rix--) {
+ /* legacy - anything < 36mbit, stop searching */
+ /* 11n - stop at MCS4 / MCS12 / MCS28 */
+ if (amrr_node_is_11n(ni) &&
+ (rs->rs_rates[amn->amn_rix] & 0x7) < 4)
+ break;
+ else if ((rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) <= 72)
+ break;
+ rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL;
+ }
+
+ /* if the rate is an 11n rate, ensure the MCS bit is set */
+ if (amrr_node_is_11n(ni))
+ rate |= IEEE80211_RATE_MCS;
+
+ /* Assign initial rate from the rateset */
+ ni->ni_txrate = rate;
amn->amn_ticks = ticks;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
- "AMRR initial rate %d", ni->ni_txrate);
+ "AMRR: nrates=%d, initial rate %d",
+ rs->rs_nrates,
+ rate);
}
static void
@@ -175,19 +222,34 @@ amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn,
struct ieee80211_node *ni)
{
int rix = amn->amn_rix;
+ const struct ieee80211_rateset *rs = NULL;
KASSERT(is_enough(amn), ("txcnt %d", amn->amn_txcnt));
+ /* 11n or not? Pick the right rateset */
+ if (amrr_node_is_11n(ni)) {
+ /* XXX ew */
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ } else {
+ rs = &ni->ni_rates;
+ }
+
+ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
+ "AMRR: current rate %d, txcnt=%d, retrycnt=%d",
+ rs->rs_rates[rix] & IEEE80211_RATE_VAL,
+ amn->amn_txcnt,
+ amn->amn_retrycnt);
+
if (is_success(amn)) {
amn->amn_success++;
if (amn->amn_success >= amn->amn_success_threshold &&
- rix + 1 < ni->ni_rates.rs_nrates) {
+ rix + 1 < rs->rs_nrates) {
amn->amn_recovery = 1;
amn->amn_success = 0;
rix++;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
"AMRR increasing rate %d (txcnt=%d retrycnt=%d)",
- ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL,
+ rs->rs_rates[rix] & IEEE80211_RATE_VAL,
amn->amn_txcnt, amn->amn_retrycnt);
} else {
amn->amn_recovery = 0;
@@ -208,7 +270,7 @@ amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn,
rix--;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
"AMRR decreasing rate %d (txcnt=%d retrycnt=%d)",
- ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL,
+ rs->rs_rates[rix] & IEEE80211_RATE_VAL,
amn->amn_txcnt, amn->amn_retrycnt);
}
amn->amn_recovery = 0;
@@ -231,14 +293,27 @@ amrr_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused)
{
struct ieee80211_amrr_node *amn = ni->ni_rctls;
struct ieee80211_amrr *amrr = amn->amn_amrr;
+ const struct ieee80211_rateset *rs = NULL;
int rix;
+ /* 11n or not? Pick the right rateset */
+ if (amrr_node_is_11n(ni)) {
+ /* XXX ew */
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ } else {
+ rs = &ni->ni_rates;
+ }
+
if (is_enough(amn) && (ticks - amn->amn_ticks) > amrr->amrr_interval) {
rix = amrr_update(amrr, amn, ni);
if (rix != amn->amn_rix) {
/* update public rate */
- ni->ni_txrate =
- ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL;
+ ni->ni_txrate = rs->rs_rates[rix];
+ /* XXX strip basic rate flag from txrate, if non-11n */
+ if (amrr_node_is_11n(ni))
+ ni->ni_txrate |= IEEE80211_RATE_MCS;
+ else
+ ni->ni_txrate &= IEEE80211_RATE_VAL;
amn->amn_rix = rix;
}
amn->amn_ticks = ticks;
diff --git a/sys/net80211/ieee80211_phy.c b/sys/net80211/ieee80211_phy.c
index d2ad60d..d1924d8 100644
--- a/sys/net80211/ieee80211_phy.c
+++ b/sys/net80211/ieee80211_phy.c
@@ -60,8 +60,11 @@ struct ieee80211_ds_plcp_hdr {
#define TURBO IEEE80211_T_TURBO
#define HALF IEEE80211_T_OFDM_HALF
#define QUART IEEE80211_T_OFDM_QUARTER
+#define HT IEEE80211_T_HT
+/* XXX the 11n and the basic rate flag are unfortunately overlapping. Grr. */
+#define N(r) (IEEE80211_RATE_MCS | r)
#define PBCC (IEEE80211_T_OFDM_QUARTER+1) /* XXX */
-#define B(r) (0x80 | r)
+#define B(r) (IEEE80211_RATE_BASIC | r)
#define Mb(x) (x*1000)
static struct ieee80211_rate_table ieee80211_11b_table = {
@@ -176,6 +179,98 @@ static struct ieee80211_rate_table ieee80211_turboa_table = {
},
};
+static struct ieee80211_rate_table ieee80211_11ng_table = {
+ .rateCount = 36,
+ .info = {
+/* short ctrl */
+/* Preamble dot11Rate Rate */
+ [0] = { .phy = CCK, 1000, 0x00, B(2), 0 },
+ [1] = { .phy = CCK, 2000, 0x04, B(4), 1 },
+ [2] = { .phy = CCK, 5500, 0x04, B(11), 2 },
+ [3] = { .phy = CCK, 11000, 0x04, B(22), 3 },
+ [4] = { .phy = OFDM, 6000, 0x00, 12, 4 },
+ [5] = { .phy = OFDM, 9000, 0x00, 18, 4 },
+ [6] = { .phy = OFDM, 12000, 0x00, 24, 6 },
+ [7] = { .phy = OFDM, 18000, 0x00, 36, 6 },
+ [8] = { .phy = OFDM, 24000, 0x00, 48, 8 },
+ [9] = { .phy = OFDM, 36000, 0x00, 72, 8 },
+ [10] = { .phy = OFDM, 48000, 0x00, 96, 8 },
+ [11] = { .phy = OFDM, 54000, 0x00, 108, 8 },
+
+ [12] = { .phy = HT, 6500, 0x00, N(0), 4 },
+ [13] = { .phy = HT, 13000, 0x00, N(1), 6 },
+ [14] = { .phy = HT, 19500, 0x00, N(2), 6 },
+ [15] = { .phy = HT, 26000, 0x00, N(3), 8 },
+ [16] = { .phy = HT, 39000, 0x00, N(4), 8 },
+ [17] = { .phy = HT, 52000, 0x00, N(5), 8 },
+ [18] = { .phy = HT, 58500, 0x00, N(6), 8 },
+ [19] = { .phy = HT, 65000, 0x00, N(7), 8 },
+
+ [20] = { .phy = HT, 13000, 0x00, N(8), 4 },
+ [21] = { .phy = HT, 26000, 0x00, N(9), 6 },
+ [22] = { .phy = HT, 39000, 0x00, N(10), 6 },
+ [23] = { .phy = HT, 52000, 0x00, N(11), 8 },
+ [24] = { .phy = HT, 78000, 0x00, N(12), 8 },
+ [25] = { .phy = HT, 104000, 0x00, N(13), 8 },
+ [26] = { .phy = HT, 117000, 0x00, N(14), 8 },
+ [27] = { .phy = HT, 130000, 0x00, N(15), 8 },
+
+ [28] = { .phy = HT, 19500, 0x00, N(16), 4 },
+ [29] = { .phy = HT, 39000, 0x00, N(17), 6 },
+ [30] = { .phy = HT, 58500, 0x00, N(18), 6 },
+ [31] = { .phy = HT, 78000, 0x00, N(19), 8 },
+ [32] = { .phy = HT, 117000, 0x00, N(20), 8 },
+ [33] = { .phy = HT, 156000, 0x00, N(21), 8 },
+ [34] = { .phy = HT, 175500, 0x00, N(22), 8 },
+ [35] = { .phy = HT, 195000, 0x00, N(23), 8 },
+
+ },
+};
+
+static struct ieee80211_rate_table ieee80211_11na_table = {
+ .rateCount = 32,
+ .info = {
+/* short ctrl */
+/* Preamble dot11Rate Rate */
+ [0] = { .phy = OFDM, 6000, 0x00, B(12), 0 },
+ [1] = { .phy = OFDM, 9000, 0x00, 18, 0 },
+ [2] = { .phy = OFDM, 12000, 0x00, B(24), 2 },
+ [3] = { .phy = OFDM, 18000, 0x00, 36, 2 },
+ [4] = { .phy = OFDM, 24000, 0x00, B(48), 4 },
+ [5] = { .phy = OFDM, 36000, 0x00, 72, 4 },
+ [6] = { .phy = OFDM, 48000, 0x00, 96, 4 },
+ [7] = { .phy = OFDM, 54000, 0x00, 108, 4 },
+
+ [8] = { .phy = HT, 6500, 0x00, N(0), 0 },
+ [9] = { .phy = HT, 13000, 0x00, N(1), 2 },
+ [10] = { .phy = HT, 19500, 0x00, N(2), 2 },
+ [11] = { .phy = HT, 26000, 0x00, N(3), 4 },
+ [12] = { .phy = HT, 39000, 0x00, N(4), 4 },
+ [13] = { .phy = HT, 52000, 0x00, N(5), 4 },
+ [14] = { .phy = HT, 58500, 0x00, N(6), 4 },
+ [15] = { .phy = HT, 65000, 0x00, N(7), 4 },
+
+ [16] = { .phy = HT, 13000, 0x00, N(8), 0 },
+ [17] = { .phy = HT, 26000, 0x00, N(9), 2 },
+ [18] = { .phy = HT, 39000, 0x00, N(10), 2 },
+ [19] = { .phy = HT, 52000, 0x00, N(11), 4 },
+ [20] = { .phy = HT, 78000, 0x00, N(12), 4 },
+ [21] = { .phy = HT, 104000, 0x00, N(13), 4 },
+ [22] = { .phy = HT, 117000, 0x00, N(14), 4 },
+ [23] = { .phy = HT, 130000, 0x00, N(15), 4 },
+
+ [24] = { .phy = HT, 19500, 0x00, N(16), 0 },
+ [25] = { .phy = HT, 39000, 0x00, N(17), 2 },
+ [26] = { .phy = HT, 58500, 0x00, N(18), 2 },
+ [27] = { .phy = HT, 78000, 0x00, N(19), 4 },
+ [28] = { .phy = HT, 117000, 0x00, N(20), 4 },
+ [29] = { .phy = HT, 156000, 0x00, N(21), 4 },
+ [30] = { .phy = HT, 175500, 0x00, N(22), 4 },
+ [31] = { .phy = HT, 195000, 0x00, N(23), 4 },
+
+ },
+};
+
#undef Mb
#undef B
#undef OFDM
@@ -184,6 +279,8 @@ static struct ieee80211_rate_table ieee80211_turboa_table = {
#undef CCK
#undef TURBO
#undef XR
+#undef HT
+#undef N
/*
* Setup a rate table's reverse lookup table and fill in
@@ -210,15 +307,23 @@ ieee80211_setup_ratetable(struct ieee80211_rate_table *rt)
uint8_t cix = rt->info[i].ctlRateIndex;
uint8_t ctl_rate = rt->info[cix].dot11Rate;
- rt->rateCodeToIndex[code] = i;
- if (code & IEEE80211_RATE_BASIC) {
- /*
- * Map w/o basic rate bit too.
- */
- code &= IEEE80211_RATE_VAL;
- rt->rateCodeToIndex[code] = i;
+ /*
+ * Map without the basic rate bit.
+ *
+ * It's up to the caller to ensure that the basic
+ * rate bit is stripped here.
+ *
+ * For HT, use the MCS rate bit.
+ */
+ code &= IEEE80211_RATE_VAL;
+ if (rt->info[i].phy == IEEE80211_T_HT) {
+ code |= IEEE80211_RATE_MCS;
}
+ /* XXX assume the control rate is non-MCS? */
+ ctl_rate &= IEEE80211_RATE_VAL;
+ rt->rateCodeToIndex[code] = i;
+
/*
* XXX for 11g the control rate to use for 5.5 and 11 Mb/s
* depends on whether they are marked as basic rates;
@@ -247,11 +352,10 @@ ieee80211_phy_init(void)
static struct ieee80211_rate_table * const ratetables[] = {
&ieee80211_half_table,
&ieee80211_quarter_table,
- &ieee80211_11a_table,
- &ieee80211_11g_table,
+ &ieee80211_11na_table,
+ &ieee80211_11ng_table,
&ieee80211_turbog_table,
&ieee80211_turboa_table,
- &ieee80211_turboa_table,
&ieee80211_11a_table,
&ieee80211_11g_table,
&ieee80211_11b_table
@@ -276,9 +380,9 @@ ieee80211_get_ratetable(struct ieee80211_channel *c)
else if (IEEE80211_IS_CHAN_QUARTER(c))
rt = &ieee80211_quarter_table;
else if (IEEE80211_IS_CHAN_HTA(c))
- rt = &ieee80211_11a_table; /* XXX */
+ rt = &ieee80211_11na_table;
else if (IEEE80211_IS_CHAN_HTG(c))
- rt = &ieee80211_11g_table; /* XXX */
+ rt = &ieee80211_11ng_table;
else if (IEEE80211_IS_CHAN_108G(c))
rt = &ieee80211_turbog_table;
else if (IEEE80211_IS_CHAN_ST(c))
@@ -463,3 +567,66 @@ ieee80211_compute_duration(const struct ieee80211_rate_table *rt,
}
return txTime;
}
+
+static const uint16_t ht20_bps[32] = {
+ 26, 52, 78, 104, 156, 208, 234, 260,
+ 52, 104, 156, 208, 312, 416, 468, 520,
+ 78, 156, 234, 312, 468, 624, 702, 780,
+ 104, 208, 312, 416, 624, 832, 936, 1040
+};
+static const uint16_t ht40_bps[32] = {
+ 54, 108, 162, 216, 324, 432, 486, 540,
+ 108, 216, 324, 432, 648, 864, 972, 1080,
+ 162, 324, 486, 648, 972, 1296, 1458, 1620,
+ 216, 432, 648, 864, 1296, 1728, 1944, 2160
+};
+
+
+#define OFDM_PLCP_BITS 22
+#define HT_L_STF 8
+#define HT_L_LTF 8
+#define HT_L_SIG 4
+#define HT_SIG 8
+#define HT_STF 4
+#define HT_LTF(n) ((n) * 4)
+
+#define HT_RC_2_MCS(_rc) ((_rc) & 0xf)
+#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
+#define IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS)
+
+/*
+ * Calculate the transmit duration of an 11n frame.
+ */
+uint32_t
+ieee80211_compute_duration_ht(uint32_t frameLen, uint16_t rate,
+ int streams, int isht40, int isShortGI)
+{
+ uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
+
+ KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
+ KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate));
+
+ if (isht40)
+ bitsPerSymbol = ht40_bps[rate & 0x1f];
+ else
+ bitsPerSymbol = ht20_bps[rate & 0x1f];
+ numBits = OFDM_PLCP_BITS + (frameLen << 3);
+ numSymbols = howmany(numBits, bitsPerSymbol);
+ if (isShortGI)
+ txTime = ((numSymbols * 18) + 4) / 5; /* 3.6us */
+ else
+ txTime = numSymbols * 4; /* 4us */
+ return txTime + HT_L_STF + HT_L_LTF +
+ HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
+}
+
+#undef IS_HT_RATE
+#undef HT_RC_2_STREAMS
+#undef HT_RC_2_MCS
+#undef HT_LTF
+#undef HT_STF
+#undef HT_SIG
+#undef HT_L_SIG
+#undef HT_L_LTF
+#undef HT_L_STF
+#undef OFDM_PLCP_BITS
diff --git a/sys/net80211/ieee80211_phy.h b/sys/net80211/ieee80211_phy.h
index 56b404f7..bf39cdd 100644
--- a/sys/net80211/ieee80211_phy.h
+++ b/sys/net80211/ieee80211_phy.h
@@ -60,6 +60,8 @@
struct ieee80211_channel;
+#define IEEE80211_RATE_TABLE_SIZE 128
+
struct ieee80211_rate_table {
int rateCount; /* NB: for proper padding */
uint8_t rateCodeToIndex[256]; /* back mapping */
@@ -74,7 +76,7 @@ struct ieee80211_rate_table {
* rate; used for dur. calcs */
uint16_t lpAckDuration; /* long preamble ACK dur. */
uint16_t spAckDuration; /* short preamble ACK dur. */
- } info[32];
+ } info[IEEE80211_RATE_TABLE_SIZE];
};
const struct ieee80211_rate_table *ieee80211_get_ratetable(
@@ -83,7 +85,14 @@ const struct ieee80211_rate_table *ieee80211_get_ratetable(
static __inline__ uint8_t
ieee80211_ack_rate(const struct ieee80211_rate_table *rt, uint8_t rate)
{
- uint8_t cix = rt->info[rt->rateCodeToIndex[rate]].ctlRateIndex;
+ /*
+ * XXX Assert this is for a legacy rate; not for an MCS rate.
+ * If the caller wishes to use it for a basic rate, they should
+ * clear the high bit first.
+ */
+ KASSERT(! (rate & 0x80), ("rate %d is basic/mcs?", rate));
+
+ uint8_t cix = rt->info[rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL]].ctlRateIndex;
KASSERT(cix != (uint8_t)-1, ("rate %d has no info", rate));
return rt->info[cix].dot11Rate;
}
@@ -91,7 +100,14 @@ ieee80211_ack_rate(const struct ieee80211_rate_table *rt, uint8_t rate)
static __inline__ uint8_t
ieee80211_ctl_rate(const struct ieee80211_rate_table *rt, uint8_t rate)
{
- uint8_t cix = rt->info[rt->rateCodeToIndex[rate]].ctlRateIndex;
+ /*
+ * XXX Assert this is for a legacy rate; not for an MCS rate.
+ * If the caller wishes to use it for a basic rate, they should
+ * clear the high bit first.
+ */
+ KASSERT(! (rate & 0x80), ("rate %d is basic/mcs?", rate));
+
+ uint8_t cix = rt->info[rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL]].ctlRateIndex;
KASSERT(cix != (uint8_t)-1, ("rate %d has no info", rate));
return rt->info[cix].dot11Rate;
}
@@ -99,7 +115,14 @@ ieee80211_ctl_rate(const struct ieee80211_rate_table *rt, uint8_t rate)
static __inline__ enum ieee80211_phytype
ieee80211_rate2phytype(const struct ieee80211_rate_table *rt, uint8_t rate)
{
- uint8_t rix = rt->rateCodeToIndex[rate];
+ /*
+ * XXX Assert this is for a legacy rate; not for an MCS rate.
+ * If the caller wishes to use it for a basic rate, they should
+ * clear the high bit first.
+ */
+ KASSERT(! (rate & 0x80), ("rate %d is basic/mcs?", rate));
+
+ uint8_t rix = rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL];
KASSERT(rix != (uint8_t)-1, ("rate %d has no info", rate));
return rt->info[rix].phy;
}
@@ -107,6 +130,13 @@ ieee80211_rate2phytype(const struct ieee80211_rate_table *rt, uint8_t rate)
static __inline__ int
ieee80211_isratevalid(const struct ieee80211_rate_table *rt, uint8_t rate)
{
+ /*
+ * XXX Assert this is for a legacy rate; not for an MCS rate.
+ * If the caller wishes to use it for a basic rate, they should
+ * clear the high bit first.
+ */
+ KASSERT(! (rate & 0x80), ("rate %d is basic/mcs?", rate));
+
return rt->rateCodeToIndex[rate] != (uint8_t)-1;
}
@@ -134,6 +164,14 @@ ieee80211_ack_duration(const struct ieee80211_rate_table *rt,
}
}
+static __inline__ uint8_t
+ieee80211_legacy_rate_lookup(const struct ieee80211_rate_table *rt,
+ uint8_t rate)
+{
+
+ return (rt->rateCodeToIndex[rate & IEEE80211_RATE_VAL]);
+}
+
/*
* Compute the time to transmit a frame of length frameLen bytes
* using the specified 802.11 rate code, phy, and short preamble
@@ -151,5 +189,10 @@ uint8_t ieee80211_plcp2rate(uint8_t, enum ieee80211_phytype);
* Convert 802.11 rate code to PLCP signal.
*/
uint8_t ieee80211_rate2plcp(int, enum ieee80211_phytype);
+
+uint32_t ieee80211_compute_duration_ht(uint32_t frameLen,
+ uint16_t rate, int streams, int isht40,
+ int isShortGI);
+
#endif /* _KERNEL */
#endif /* !_NET80211_IEEE80211_PHY_H_ */
OpenPOWER on IntegriCloud