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_ */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to