Index: sys/net80211/ieee80211_phy.c =================================================================== --- sys/net80211/ieee80211_phy.c (revision 252381) +++ sys/net80211/ieee80211_phy.c (working copy) @@ -60,8 +60,11 @@ #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_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 @@ #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 @@ 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 @@ 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 @@ 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 @@ } 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 Index: sys/net80211/ieee80211_phy.h =================================================================== --- sys/net80211/ieee80211_phy.h (revision 252381) +++ sys/net80211/ieee80211_phy.h (working copy) @@ -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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } +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 @@ * 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_ */ Index: sys/net80211/ieee80211_amrr.c =================================================================== --- sys/net80211/ieee80211_amrr.c (revision 252381) +++ sys/net80211/ieee80211_amrr.c (working copy) @@ -46,6 +46,7 @@ #endif #include +#include #include #include @@ -128,13 +129,25 @@ 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 @@ 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 @@ 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 @@ 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 @@ { 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; Index: sys/dev/iwn/if_iwnvar.h =================================================================== --- sys/dev/iwn/if_iwnvar.h (revision 252381) +++ sys/dev/iwn/if_iwnvar.h (working copy) @@ -102,7 +102,9 @@ struct ieee80211_node ni; /* must be the first */ uint16_t disable_tid; uint8_t id; +#if 0 uint32_t ridx[256]; +#endif struct { uint64_t bitmap; int startidx; Index: sys/dev/iwn/if_iwn.c =================================================================== --- sys/dev/iwn/if_iwn.c (revision 252381) +++ sys/dev/iwn/if_iwn.c (working copy) @@ -335,6 +335,7 @@ 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_FATAL = 0x80000000, /* fatal errors */ IWN_DEBUG_ANY = 0xffffffff }; @@ -585,6 +586,7 @@ | IEEE80211_C_IBSS /* ibss/adhoc mode */ #endif | IEEE80211_C_WME /* WME */ + | IEEE80211_C_PMGT /* Station-side power mgmt */ ; /* Read MAC address, channels, etc from EEPROM. */ @@ -2097,10 +2099,105 @@ return 0; } +/* + * 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; + uint8_t txant1, txant2; + 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)) { + /* + * 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; + } else if (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) { + plcp |= IWN_RFLAG_SGI; + } + + /* + * 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); + } 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) { #define RV(v) ((v) & IEEE80211_RATE_VAL) +#if 0 struct ieee80211com *ic = ni->ni_ic; struct iwn_softc *sc = ic->ic_ifp->if_softc; struct iwn_node *wn = (void *)ni; @@ -2136,7 +2233,8 @@ 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]; + 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; @@ -2144,6 +2242,7 @@ wn->ridx[rate] = htole32(plcp); } } +#endif #undef RV } @@ -3400,7 +3499,8 @@ (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) { @@ -3506,7 +3606,7 @@ 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; @@ -3637,7 +3737,8 @@ /* 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); @@ -3713,14 +3814,18 @@ 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); @@ -4076,14 +4181,20 @@ 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. */ @@ -4585,6 +4696,8 @@ { struct iwn_ops *ops = &sc->ops; struct iwn_calib_state *calib = &sc->calib; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; uint32_t val; int i; @@ -4623,11 +4736,12 @@ (void)iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1); #endif -#if 0 +#if 1 /* XXX: not yet */ /* Enable power-saving mode if requested by user. */ - if (sc->sc_ic.ic_flags & IEEE80211_F_PMGTON) + if (ic->ic_flags & IEEE80211_F_PMGTON) { (void)iwn_set_pslevel(sc, 0, 3, 1); + } #endif } @@ -4940,6 +5054,12 @@ uint32_t reg; int i; + device_printf(sc->sc_dev, "%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]; Index: sys/dev/ral/rt2560.c =================================================================== --- sys/dev/ral/rt2560.c (revision 252381) +++ sys/dev/ral/rt2560.c (working copy) @@ -2370,7 +2370,7 @@ 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); Index: sys/dev/ral/rt2661.c =================================================================== --- sys/dev/ral/rt2661.c (revision 252381) +++ sys/dev/ral/rt2661.c (working copy) @@ -1923,7 +1923,7 @@ 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); Index: sys/dev/ral/rt2860.c =================================================================== --- sys/dev/ral/rt2860.c (revision 252381) +++ sys/dev/ral/rt2860.c (working copy) @@ -1528,7 +1528,7 @@ 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 @@ /* 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 @@ 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);