[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
This commit is contained in:
parent
c6fa17beae
commit
cf9be7c92a
@ -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, struct mbuf *m, int8_t *rssi_p)
|
||||
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, int rate, int8_t rssi)
|
||||
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 *sc, int rate, void *physt)
|
||||
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, struct ieee80211_node *ni,
|
||||
(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, struct ieee80211_node *ni,
|
||||
} 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, struct ieee80211_node *ni,
|
||||
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, struct ieee80211_node *ni,
|
||||
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, struct ieee80211_node *ni,
|
||||
}
|
||||
}
|
||||
|
||||
/* 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, struct ieee80211_node *ni,
|
||||
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));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user