Date: Thu, 4 Jul 2013 21:16:49 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r252727 - in head/sys: dev/iwn dev/ral net80211 Message-ID: <201307042116.r64LGnZ5047347@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Thu Jul 4 21:16:49 2013 New Revision: 252727 URL: http://svnweb.freebsd.org/changeset/base/252727 Log: Implement basic 802.11n awareness in the PHY and AMRR rate control code. * Add 802.11n 2ghz and 5ghz tables, including legacy rates and up to MCS23 rates (3x3.) * Populate the rate code -> rate index lookup table with MCS _and_ normal rates, but _not_ the basic rate flag. Since the basic rate flag is the same as the MCS flag, we can only use one. * Introduce some accessor inlines that do PLCP and rate table lookup/access and enforce that it doesn't set the basic rate bit. They're not designed for MCS rates, so it will panic. * Start converting drivers that use the rate table stuff to use the accessor inlines and strip the basic flag. * Teach AMRR about basic 11n - it's still as crap for MCS as it is being used by iwn, so it's not a step _backwardS_. * Convert iwn over to accept 11n MCS rates rather than 'translate' legacy to MCS rates. It doesn't use a lookup table any longer; instead it's a function which takes the current node (for HT parameters) and the rate code, and returns the hardware PLCP code to use. Tested: * ath - it's a no-op, and it works that way * iwn - both 11n and non-11n Modified: head/sys/dev/iwn/if_iwn.c head/sys/dev/iwn/if_iwnvar.h head/sys/dev/ral/rt2560.c head/sys/dev/ral/rt2661.c head/sys/dev/ral/rt2860.c head/sys/net80211/ieee80211_amrr.c head/sys/net80211/ieee80211_phy.c head/sys/net80211/ieee80211_phy.h Modified: head/sys/dev/iwn/if_iwn.c ============================================================================== --- head/sys/dev/iwn/if_iwn.c Thu Jul 4 21:12:58 2013 (r252726) +++ head/sys/dev/iwn/if_iwn.c Thu Jul 4 21:16:49 2013 (r252727) @@ -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 (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 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, st /* 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, st 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 *s 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, in 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]; Modified: head/sys/dev/iwn/if_iwnvar.h ============================================================================== --- head/sys/dev/iwn/if_iwnvar.h Thu Jul 4 21:12:58 2013 (r252726) +++ head/sys/dev/iwn/if_iwnvar.h Thu Jul 4 21:16:49 2013 (r252727) @@ -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; Modified: head/sys/dev/ral/rt2560.c ============================================================================== --- head/sys/dev/ral/rt2560.c Thu Jul 4 21:12:58 2013 (r252726) +++ head/sys/dev/ral/rt2560.c Thu Jul 4 21:16:49 2013 (r252727) @@ -2370,7 +2370,7 @@ rt2560_set_basicrates(struct rt2560_soft 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); Modified: head/sys/dev/ral/rt2661.c ============================================================================== --- head/sys/dev/ral/rt2661.c Thu Jul 4 21:12:58 2013 (r252726) +++ head/sys/dev/ral/rt2661.c Thu Jul 4 21:16:49 2013 (r252727) @@ -1923,7 +1923,7 @@ rt2661_set_basicrates(struct rt2661_soft 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); Modified: head/sys/dev/ral/rt2860.c ============================================================================== --- head/sys/dev/ral/rt2860.c Thu Jul 4 21:12:58 2013 (r252726) +++ head/sys/dev/ral/rt2860.c Thu Jul 4 21:16:49 2013 (r252727) @@ -1528,7 +1528,7 @@ rt2860_tx(struct rt2860_softc *sc, struc 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, s /* 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_soft 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); Modified: head/sys/net80211/ieee80211_amrr.c ============================================================================== --- head/sys/net80211/ieee80211_amrr.c Thu Jul 4 21:12:58 2013 (r252726) +++ head/sys/net80211/ieee80211_amrr.c Thu Jul 4 21:16:49 2013 (r252727) @@ -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_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, 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, voi { 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; Modified: head/sys/net80211/ieee80211_phy.c ============================================================================== --- head/sys/net80211/ieee80211_phy.c Thu Jul 4 21:12:58 2013 (r252726) +++ head/sys/net80211/ieee80211_phy.c Thu Jul 4 21:16:49 2013 (r252727) @@ -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 ieee8 }, }; +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 ieee8 #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 ieee802 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 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 } 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 Modified: head/sys/net80211/ieee80211_phy.h ============================================================================== --- head/sys/net80211/ieee80211_phy.h Thu Jul 4 21:12:58 2013 (r252726) +++ head/sys/net80211/ieee80211_phy.h Thu Jul 4 21:16:49 2013 (r252727) @@ -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 *ieee8 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 ieee8021 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 ieee8021 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 ieee 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 ieee } } +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, en * 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_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201307042116.r64LGnZ5047347>