Author: adrian
Date: Tue Mar 22 01:09:15 2016
New Revision: 297175
URL: https://svnweb.freebsd.org/changeset/base/297175

Log:
  [urtwn] welcome basic 11n support to urtwn.
  
  This is a pretty good reference for teaching an almost-11n-capable
  driver about 11n.
  
  It enables HT20 operation, A-MPDU/A-MSDU RX, but no aggregate support
  for transmit.  That'll come later.  This means that receive throughput
  should be higher, but transmit throughput won't have changed much.
  
  * Disable bgscan - for now, bgscan will interfere with AMPDU TX/RX,
    so until we correctly handle it in software driven scans, disable.
  * Add null 11n methods for channel width / ampdu_enable.
    the firmware can apparently handle ampdu tx (and hopefully block-ack
    handling and retransmission) so I'll go review the linux code and
    figure it out.
  * Set the number of tx/rx streams.  I /hope/ that nchains == nstreams
    here.
  * Add 11n channels in the call to ieee80211_init_channels().
  * Don't enable HT40 for now - I'll have to verify the channel set command
    and tidy it up a bit first.
  * Teach the RX path about M_AMPDU for 11n nodes.  Kinda wonder why
    we aren't just doing this in net80211 already, this is the fourth
    driver I've had to do this to.
  * Teach rate2ridx() about MCS rates and what hardware rates to use.
  * Teach the urtwn_tx_data() routine about MCS/11ng transmission.
    It doesn't know about short-gi and 40MHz modes yet; that'll come
    later.
  * For 8192CU firmware, teach the rate table code about MCS rates.
  * Ensure that the fixed rate transmit sets the right transmit flag
    so the firmware obeys the driver transmit path.
  * Set the default transmit rate to MCS4 if no rate control is available.
  * Add HT protection (RTS-CTS exchange) support.
  
  * Add appropriate XXX TODO entries.
  
  TODO:
  
  * 40MHz, short-gi, etc - channel tuning, TX, RX;
  * teach urtwn_tx_raw() about (more) 11n stuff;
  * A-MPDU TX would be nice!
  
  Thanks to Andriy (avos@) for reviewing the code and testing it on IRC.
  
  Tested:
  
  * RTL8188EU - STA (me)
  * RTL8192CU - STA (me)
  * RTL8188EU - hostap (avos)
  * RTL8192CU - STA (avos)
  
  Reviewed by:  avos

Modified:
  head/sys/dev/urtwn/if_urtwn.c

Modified: head/sys/dev/urtwn/if_urtwn.c
==============================================================================
--- head/sys/dev/urtwn/if_urtwn.c       Mon Mar 21 23:32:13 2016        
(r297174)
+++ head/sys/dev/urtwn/if_urtwn.c       Tue Mar 22 01:09:15 2016        
(r297175)
@@ -95,6 +95,7 @@ enum {
        URTWN_DEBUG_ROM         = 0x00000200,   /* various ROM info */
        URTWN_DEBUG_KEY         = 0x00000400,   /* crypto keys management */
        URTWN_DEBUG_TXPWR       = 0x00000800,   /* dump Tx power values */
+       URTWN_DEBUG_RSSI        = 0x00001000,   /* dump RSSI lookups */
        URTWN_DEBUG_ANY         = 0xffffffff
 };
 
@@ -109,6 +110,9 @@ enum {
 
 #define        IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh)
 
+static int urtwn_enable_11n = 1;
+TUNABLE_INT("hw.usb.urtwn.enable_11n", &urtwn_enable_11n);
+
 /* various supported device vendors/products */
 static const STRUCT_USB_HOST_ID urtwn_devs[] = {
 #define URTWN_DEV(v,p)  { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
@@ -465,6 +469,19 @@ urtwn_match(device_t self)
        return (usbd_lookup_id_by_uaa(urtwn_devs, sizeof(urtwn_devs), uaa));
 }
 
+static void
+urtwn_update_chw(struct ieee80211com *ic)
+{
+}
+
+static int
+urtwn_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
+{
+
+       /* We're driving this ourselves (eventually); don't involve net80211 */
+       return (0);
+}
+
 static int
 urtwn_attach(device_t self)
 {
@@ -555,7 +572,9 @@ urtwn_attach(device_t self)
                | IEEE80211_C_HOSTAP            /* hostap mode */
                | IEEE80211_C_SHPREAMBLE        /* short preamble supported */
                | IEEE80211_C_SHSLOT            /* short slot time supported */
+#if 0
                | IEEE80211_C_BGSCAN            /* capable of bg scanning */
+#endif
                | IEEE80211_C_WPA               /* 802.11i */
                | IEEE80211_C_WME               /* 802.11e */
                ;
@@ -565,9 +584,27 @@ urtwn_attach(device_t self)
            IEEE80211_CRYPTO_TKIP |
            IEEE80211_CRYPTO_AES_CCM;
 
+       /* Assume they're all 11n capable for now */
+       if (urtwn_enable_11n) {
+               device_printf(self, "enabling 11n\n");
+               ic->ic_htcaps = IEEE80211_HTC_HT |
+                   IEEE80211_HTC_AMPDU |
+                   IEEE80211_HTC_AMSDU |
+                   IEEE80211_HTCAP_MAXAMSDU_3839 |
+                   IEEE80211_HTCAP_SMPS_OFF;
+               /* no HT40 just yet */
+               // ic->ic_htcaps |= IEEE80211_HTCAP_CHWIDTH40;
+
+               /* XXX TODO: verify chains versus streams for urtwn */
+               ic->ic_txstream = sc->ntxchains;
+               ic->ic_rxstream = sc->nrxchains;
+       }
+
        memset(bands, 0, sizeof(bands));
        setbit(bands, IEEE80211_MODE_11B);
        setbit(bands, IEEE80211_MODE_11G);
+       if (urtwn_enable_11n)
+               setbit(bands, IEEE80211_MODE_11NG);
        ieee80211_init_channels(ic, NULL, bands);
 
        ieee80211_ifattach(ic);
@@ -589,6 +626,8 @@ urtwn_attach(device_t self)
                sc->sc_node_free = ic->ic_node_free;
                ic->ic_node_free = urtwn_r88e_node_free;
        }
+       ic->ic_update_chw = urtwn_update_chw;
+       ic->ic_ampdu_enable = urtwn_ampdu_enable;
 
        ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr,
            sizeof(sc->sc_txtap), URTWN_TX_RADIOTAP_PRESENT,
@@ -1005,6 +1044,9 @@ urtwn_rx_frame(struct urtwn_softc *sc, s
                        tap->wr_tsft &= 0xffffffff00000000;
                tap->wr_tsft += stat->rxdw5;
 
+               /* XXX 20/40? */
+               /* XXX shortgi? */
+
                /* Map HW rate index to 802.11 rate. */
                if (!(rxdw3 & R92C_RXDW3_HT)) {
                        tap->wr_rate = ridx2rate[rate];
@@ -1081,6 +1123,8 @@ tr_setup:
 
                        nf = URTWN_NOISE_FLOOR;
                        if (ni != NULL) {
+                               if (ni->ni_flags & IEEE80211_NODE_HT)
+                                       m->m_flags |= M_AMPDU;
                                (void)ieee80211_input(ni, m, rssi - nf, nf);
                                ieee80211_free_node(ni);
                        } else {
@@ -1827,7 +1871,7 @@ urtwn_ra_init(struct urtwn_softc *sc)
        struct ieee80211com *ic = &sc->sc_ic;
        struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
        struct ieee80211_node *ni;
-       struct ieee80211_rateset *rs;
+       struct ieee80211_rateset *rs, *rs_ht;
        struct r92c_fw_cmd_macid_cfg cmd;
        uint32_t rates, basicrates;
        uint8_t mode;
@@ -1835,10 +1879,13 @@ urtwn_ra_init(struct urtwn_softc *sc)
 
        ni = ieee80211_ref_node(vap->iv_bss);
        rs = &ni->ni_rates;
+       rs_ht = (struct ieee80211_rateset *) &ni->ni_htrates;
 
        /* Get normal and basic rates mask. */
        rates = basicrates = 0;
        maxrate = maxbasicrate = 0;
+
+       /* This is for 11bg */
        for (i = 0; i < rs->rs_nrates; i++) {
                /* Convert 802.11 rate to HW rate index. */
                for (j = 0; j < nitems(ridx2rate); j++)
@@ -1856,10 +1903,32 @@ urtwn_ra_init(struct urtwn_softc *sc)
                                maxbasicrate = j;
                }
        }
+
+       /* If we're doing 11n, enable 11n rates */
+       if (ni->ni_flags & IEEE80211_NODE_HT) {
+               for (i = 0; i < rs_ht->rs_nrates; i++) {
+                       if ((rs_ht->rs_rates[i] & 0x7f) > 0xf)
+                               continue;
+                       /* 11n rates start at index 12 */
+                       j = ((rs_ht->rs_rates[i]) & 0xf) + 12;
+                       rates |= (1 << j);
+
+                       /* Guard against the rate table being oddly ordered */
+                       if (j > maxrate)
+                               maxrate = j;
+               }
+       }
+
+#if 0
+       if (ic->ic_curmode == IEEE80211_MODE_11NG)
+               raid = R92C_RAID_11GN;
+#endif
+       /* NB: group addressed frames are done at 11bg rates for now */
        if (ic->ic_curmode == IEEE80211_MODE_11B)
                mode = R92C_RAID_11B;
        else
                mode = R92C_RAID_11BG;
+       /* XXX misleading 'mode' value here for unicast frames */
        URTWN_DPRINTF(sc, URTWN_DEBUG_RA,
            "%s: mode 0x%x, rates 0x%08x, basicrates 0x%08x\n", __func__,
            mode, rates, basicrates);
@@ -1874,6 +1943,7 @@ urtwn_ra_init(struct urtwn_softc *sc)
                    "could not add broadcast station\n");
                return (error);
        }
+
        /* Set initial MRR rate. */
        URTWN_DPRINTF(sc, URTWN_DEBUG_RA, "%s: maxbasicrate %d\n", __func__,
            maxbasicrate);
@@ -1881,6 +1951,12 @@ urtwn_ra_init(struct urtwn_softc *sc)
            maxbasicrate);
 
        /* Set rates mask for unicast frames. */
+       if (ni->ni_flags & IEEE80211_NODE_HT)
+               mode = R92C_RAID_11GN;
+       else if (ic->ic_curmode == IEEE80211_MODE_11B)
+               mode = R92C_RAID_11B;
+       else
+               mode = R92C_RAID_11BG;
        cmd.macid = URTWN_MACID_BSS | URTWN_MACID_VALID;
        cmd.mask = htole32(mode << 28 | rates);
        error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
@@ -1896,7 +1972,11 @@ urtwn_ra_init(struct urtwn_softc *sc)
            maxrate);
 
        /* Indicate highest supported rate. */
-       ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1];
+       if (ni->ni_flags & IEEE80211_NODE_HT)
+               ni->ni_txrate = rs_ht->rs_rates[rs_ht->rs_nrates - 1]
+                   | IEEE80211_RATE_MCS;
+       else
+               ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1];
        ieee80211_free_node(ni);
 
        return (0);
@@ -2559,7 +2639,7 @@ urtwn_update_avgrssi(struct urtwn_softc 
                sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1;
        else
                sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20);
-       URTWN_DPRINTF(sc, URTWN_DEBUG_RA, "%s: PWDB %d, EMA %d\n", __func__,
+       URTWN_DPRINTF(sc, URTWN_DEBUG_RSSI, "%s: PWDB %d, EMA %d\n", __func__,
            pwdb, sc->avg_pwdb);
 }
 
@@ -2643,7 +2723,12 @@ urtwn_r88e_get_rssi(struct urtwn_softc *
 static __inline uint8_t
 rate2ridx(uint8_t rate)
 {
+       if (rate & IEEE80211_RATE_MCS) {
+               /* 11n rates start at idx 12 */
+               return ((rate & 0xf) + 12);
+       }
        switch (rate) {
+       /* 11g */
        case 12:        return 4;
        case 18:        return 5;
        case 24:        return 6;
@@ -2652,6 +2737,7 @@ rate2ridx(uint8_t rate)
        case 72:        return 9;
        case 96:        return 10;
        case 108:       return 11;
+       /* 11b */
        case 2:         return 0;
        case 4:         return 1;
        case 11:        return 2;
@@ -2711,15 +2797,24 @@ urtwn_tx_data(struct urtwn_softc *sc, st
                        (void) ieee80211_ratectl_rate(ni, NULL, 0);
                        rate = ni->ni_txrate;
                } else {
-                       if (ic->ic_curmode != IEEE80211_MODE_11B)
+                       /* XXX TODO: drop the default rate for 11b/11g? */
+                       if (ni->ni_flags & IEEE80211_NODE_HT)
+                               rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */
+                       else if (ic->ic_curmode != IEEE80211_MODE_11B)
                                rate = 108;
                        else
                                rate = 22;
                }
        }
 
+       /*
+        * XXX TODO: this should be per-node, for 11b versus 11bg
+        * nodes in hostap mode
+        */
        ridx = rate2ridx(rate);
-       if (ic->ic_curmode != IEEE80211_MODE_11B)
+       if (ni->ni_flags & IEEE80211_NODE_HT)
+               raid = R92C_RAID_11GN;
+       else if (ic->ic_curmode != IEEE80211_MODE_11B)
                raid = R92C_RAID_11BG;
        else
                raid = R92C_RAID_11B;
@@ -2763,7 +2858,10 @@ urtwn_tx_data(struct urtwn_softc *sc, st
                        } else
                                txd->txdw1 |= htole32(R92C_TXDW1_AGGBK);
 
-                       if (ic->ic_flags & IEEE80211_F_USEPROT) {
+                       /* protmode, non-HT */
+                       /* XXX TODO: noack frames? */
+                       if ((rate & 0x80) == 0 &&
+                           (ic->ic_flags & IEEE80211_F_USEPROT)) {
                                switch (ic->ic_protmode) {
                                case IEEE80211_PROT_CTSONLY:
                                        txd->txdw4 |= htole32(
@@ -2779,8 +2877,21 @@ urtwn_tx_data(struct urtwn_softc *sc, st
                                        break;
                                }
                        }
+
+                       /* protmode, HT */
+                       /* XXX TODO: noack frames? */
+                       if ((rate & 0x80) &&
+                           (ic->ic_htprotmode == IEEE80211_PROT_RTSCTS)) {
+                               txd->txdw4 |= htole32(
+                                   R92C_TXDW4_RTSEN |
+                                   R92C_TXDW4_HWRTSEN);
+                       }
+
+                       /* XXX TODO: rtsrate is configurable? 24mbit may
+                        * be a bit high for RTS rate? */
                        txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE,
                            URTWN_RIDX_OFDM24));
+
                        txd->txdw5 |= htole32(0x0001ff00);
                } else  /* IEEE80211_FC0_TYPE_MGT */
                        qsel = R92C_TXDW1_QSEL_MGNT;
@@ -2793,14 +2904,21 @@ urtwn_tx_data(struct urtwn_softc *sc, st
            SM(R92C_TXDW1_QSEL, qsel) |
            SM(R92C_TXDW1_RAID, raid));
 
+       /* XXX TODO: 40MHZ flag? */
+       /* XXX TODO: AMPDU flag? (AGG_ENABLE or AGG_BREAK?) Density shift? */
+       /* XXX Short preamble? */
+       /* XXX Short-GI? */
+
        if (sc->chip & URTWN_CHIP_88E)
                txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, macid));
        else
                txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, macid));
 
        txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx));
+
        /* Force this rate if needed. */
        if (URTWN_CHIP_HAS_RATECTL(sc) || ismcast ||
+           (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) ||
            (m->m_flags & M_EAPOL) || type != IEEE80211_FC0_TYPE_DATA)
                txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
 
@@ -2888,6 +3006,8 @@ urtwn_tx_raw(struct urtwn_softc *sc, str
                }
        }
 
+       /* XXX TODO: 11n checks, matching urtwn_tx_data() */
+
        wh = mtod(m, struct ieee80211_frame *);
        type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
 
@@ -2916,6 +3036,7 @@ urtwn_tx_raw(struct urtwn_softc *sc, str
        else
                txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, URTWN_MACID_BC));
 
+       /* XXX TODO: rate index/config (RAID) for 11n? */
        txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT));
        txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER, cipher));
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to