svn commit: r297175 - head/sys/dev/urtwn
Adrian Chadd
adrian at FreeBSD.org
Tue Mar 22 01:09:16 UTC 2016
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));
More information about the svn-src-all
mailing list