[run] Add initial 802.11n support.

* Enable self-generated 11n frames
* add MCS rates for 1-stream and 2-stream rates; will do 3-stream
  once the rest of this tests out OK with other people.
* Hard-code 1 stream for now
* Add A-MPDU RX mbuf tagging
* RTS/CTS if doing RTSCTS in HT protmode as well as legacy; they're
  separate configuration flags
* Update the amrr rate index stuff - walk the rates array like others
  to find the right one - this now works for MCS and CCK/OFDM rates
* Add support for atheros fast frames/AMSDU support as we can generate
  those in net80211.

TODO:

* HT40 isn't enabled yet
* No A-MPDU support just yet; that requires some more firmware research
  and maybe porting some ath(4) A-MPDU support/tracking into net80211
* Short preamble flags aren't set yet for MCS; need to check the linux
  driver and see what's going on there
* Add 3x3 rates and set tx/rx stream configuration appropriately
* More 5GHz testing; I have a 3x3 dual band USB NIC coming soon that'll
  let me test this.
* Figure out why the RX path isn't performing as fast as it could -
  there's only a single buffer loaded at a time for the receive path
  in the USB bulk handler and this may not be super useful.

Tested:

* RT5390 usb, 1x1, RF5370 (2GHz radio), STA mode - A-MSDU TX, A-MPDU RX

Submitted by:	Ashish Gupta <ashishgu@andrew.cmu.edu>
Differential Revision:	https://reviews.freebsd.org/D22840
This commit is contained in:
Adrian Chadd 2020-05-29 15:56:44 +00:00
parent dbcf7598b0
commit f520d76129
3 changed files with 123 additions and 41 deletions

View File

@ -64,6 +64,9 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_regdomain.h>
#include <net80211/ieee80211_radiotap.h>
#include <net80211/ieee80211_ratectl.h>
#ifdef IEEE80211_SUPPORT_SUPERG
#include <net80211/ieee80211_superg.h>
#endif
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@ -495,6 +498,9 @@ static void run_adjust_freq_offset(struct run_softc *);
static void run_init_locked(struct run_softc *);
static void run_stop(void *);
static void run_delay(struct run_softc *, u_int);
static void run_update_chw(struct ieee80211com *ic);
static int run_ampdu_enable(struct ieee80211_node *ni,
struct ieee80211_tx_ampdu *tap);
static eventhandler_tag run_etag;
@ -506,10 +512,13 @@ static const struct rt2860_rate {
uint16_t sp_ack_dur;
uint16_t lp_ack_dur;
} rt2860_rates[] = {
/* CCK rates (11b) */
{ 2, 0, IEEE80211_T_DS, 0, 314, 314 },
{ 4, 1, IEEE80211_T_DS, 1, 258, 162 },
{ 11, 2, IEEE80211_T_DS, 2, 223, 127 },
{ 22, 3, IEEE80211_T_DS, 3, 213, 117 },
/* OFDM rates (11a / 11g) */
{ 12, 0, IEEE80211_T_OFDM, 4, 60, 60 },
{ 18, 1, IEEE80211_T_OFDM, 4, 52, 52 },
{ 24, 2, IEEE80211_T_OFDM, 6, 48, 48 },
@ -517,9 +526,35 @@ static const struct rt2860_rate {
{ 48, 4, IEEE80211_T_OFDM, 8, 44, 44 },
{ 72, 5, IEEE80211_T_OFDM, 8, 40, 40 },
{ 96, 6, IEEE80211_T_OFDM, 8, 40, 40 },
{ 108, 7, IEEE80211_T_OFDM, 8, 40, 40 }
{ 108, 7, IEEE80211_T_OFDM, 8, 40, 40 },
/* MCS - single stream */
{ 0x80, 0, IEEE80211_T_HT, 4, 60, 60 },
{ 0x81, 1, IEEE80211_T_HT, 4, 60, 60 },
{ 0x82, 2, IEEE80211_T_HT, 4, 60, 60 },
{ 0x83, 3, IEEE80211_T_HT, 4, 60, 60 },
{ 0x84, 4, IEEE80211_T_HT, 4, 60, 60 },
{ 0x85, 5, IEEE80211_T_HT, 4, 60, 60 },
{ 0x86, 6, IEEE80211_T_HT, 4, 60, 60 },
{ 0x87, 7, IEEE80211_T_HT, 4, 60, 60 },
/* MCS - 2 streams */
{ 0x88, 8, IEEE80211_T_HT, 4, 60, 60 },
{ 0x89, 9, IEEE80211_T_HT, 4, 60, 60 },
{ 0x8a, 10, IEEE80211_T_HT, 4, 60, 60 },
{ 0x8b, 11, IEEE80211_T_HT, 4, 60, 60 },
{ 0x8c, 12, IEEE80211_T_HT, 4, 60, 60 },
{ 0x8d, 13, IEEE80211_T_HT, 4, 60, 60 },
{ 0x8e, 14, IEEE80211_T_HT, 4, 60, 60 },
{ 0x8f, 15, IEEE80211_T_HT, 4, 60, 60 },
};
/* These are indexes into the above rt2860_rates[] array */
#define RT2860_RIDX_CCK1 0
#define RT2860_RIDX_CCK11 3
#define RT2860_RIDX_OFDM6 4
#define RT2860_RIDX_MCS0 12
#define RT2860_RIDX_MAX 28
static const struct {
uint16_t reg;
uint32_t val;
@ -807,9 +842,25 @@ run_attach(device_t self)
IEEE80211_C_MBSS |
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
IEEE80211_C_SWAMSDUTX | /* Do software A-MSDU TX */
IEEE80211_C_FF | /* Atheros fast-frames */
IEEE80211_C_WME | /* WME */
IEEE80211_C_WPA; /* WPA1|WPA2(RSN) */
ic->ic_htcaps =
IEEE80211_HTC_HT |
IEEE80211_HTC_AMPDU |
IEEE80211_HTC_AMSDU |
IEEE80211_HTCAP_MAXAMSDU_3839 |
IEEE80211_HTCAP_SMPS_OFF;
/*
* For now, just do 1 stream. Later on we'll figure out
* how many tx/rx streams a particular NIC supports.
*/
ic->ic_rxstream = 1;
ic->ic_txstream = 1;
ic->ic_cryptocaps =
IEEE80211_CRYPTO_WEP |
IEEE80211_CRYPTO_AES_CCM |
@ -839,6 +890,8 @@ run_attach(device_t self)
ic->ic_vap_delete = run_vap_delete;
ic->ic_transmit = run_transmit;
ic->ic_parent = run_parent;
ic->ic_update_chw = run_update_chw;
ic->ic_ampdu_enable = run_ampdu_enable;
ieee80211_radiotap_attach(ic,
&sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap),
@ -974,6 +1027,10 @@ run_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
vap->iv_update_beacon = run_update_beacon;
vap->iv_max_aid = RT2870_WCID_MAX;
vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K;
vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_2;
/*
* To delete the right key from h/w, we need wcid.
* Luckily, there is unused space in ieee80211_key{}, wk_pad,
@ -2059,11 +2116,13 @@ run_media_change(struct ifnet *ifp)
struct ieee80211_node *ni;
struct run_node *rn;
/* XXX TODO: methodize with MCS rates */
rate = ic->ic_sup_rates[ic->ic_curmode].
rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL;
for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
if (rt2860_rates[ridx].rate == rate)
break;
ni = ieee80211_ref_node(vap->iv_bss);
rn = RUN_NODE(ni);
rn->fix_ridx = ridx;
@ -2605,7 +2664,7 @@ run_iter_func(void *arg, struct ieee80211_node *ni)
struct run_node *rn = RUN_NODE(ni);
union run_stats sta[2];
uint16_t (*wstat)[3];
int error;
int error, ridx;
RUN_LOCK(sc);
@ -2656,12 +2715,17 @@ run_iter_func(void *arg, struct ieee80211_node *ni)
}
ieee80211_ratectl_tx_update(vap, txs);
rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0);
ieee80211_ratectl_rate(ni, NULL, 0);
/* XXX TODO: methodize with MCS rates */
for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
if (rt2860_rates[ridx].rate == ni->ni_txrate)
break;
rn->amrr_ridx = ridx;
fail:
RUN_UNLOCK(sc);
RUN_DPRINTF(sc, RUN_DEBUG_RATE, "ridx=%d\n", rn->amrr_ridx);
RUN_DPRINTF(sc, RUN_DEBUG_RATE, "rate=%d, ridx=%d\n", ni->ni_txrate, rn->amrr_ridx);
}
static void
@ -2684,14 +2748,12 @@ static void
run_newassoc(struct ieee80211_node *ni, int isnew)
{
struct run_node *rn = RUN_NODE(ni);
struct ieee80211_rateset *rs = &ni->ni_rates;
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = vap->iv_ic;
struct run_softc *sc = ic->ic_softc;
uint8_t rate;
uint8_t ridx;
uint8_t wcid;
int i, j;
wcid = (vap->iv_opmode == IEEE80211_M_STA) ?
1 : RUN_AID2WCID(ni->ni_associd);
@ -2721,31 +2783,8 @@ run_newassoc(struct ieee80211_node *ni, int isnew)
"new assoc isnew=%d associd=%x addr=%s\n",
isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr));
for (i = 0; i < rs->rs_nrates; i++) {
rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
/* convert 802.11 rate to hardware rate index */
for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
if (rt2860_rates[ridx].rate == rate)
break;
rn->ridx[i] = ridx;
/* determine rate of control response frames */
for (j = i; j >= 0; j--) {
if ((rs->rs_rates[j] & IEEE80211_RATE_BASIC) &&
rt2860_rates[rn->ridx[i]].phy ==
rt2860_rates[rn->ridx[j]].phy)
break;
}
if (j >= 0) {
rn->ctl_ridx[i] = rn->ridx[j];
} else {
/* no basic rate found, use mandatory one */
rn->ctl_ridx[i] = rt2860_rates[ridx].ctl_ridx;
}
RUN_DPRINTF(sc, RUN_DEBUG_STATE | RUN_DEBUG_RATE,
"rate=0x%02x ridx=%d ctl_ridx=%d\n",
rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]);
}
rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate;
/* XXX TODO: methodize with MCS rates */
for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
if (rt2860_rates[ridx].rate == rate)
break;
@ -2876,6 +2915,10 @@ run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
} else
ni = NULL;
if(ni && ni->ni_flags & IEEE80211_NODE_HT) {
m->m_flags |= M_AMPDU;
}
if (__predict_false(flags & RT2860_RX_MICERR)) {
/* report MIC failures to net80211 for TKIP */
if (ni != NULL)
@ -3089,6 +3132,9 @@ tr_setup:
/* make sure we free the source buffer, if any */
m_freem(m);
#ifdef IEEE80211_SUPPORT_SUPERG
ieee80211_ff_age_all(ic, 100);
#endif
RUN_LOCK(sc);
}
@ -3234,6 +3280,15 @@ tr_setup:
}
break;
}
#ifdef IEEE80211_SUPPORT_SUPERG
/* XXX TODO: make this deferred rather than unlock/relock */
/* XXX TODO: should only do the QoS AC this belongs to */
if (pq->tx_nfree >= RUN_TX_RING_COUNT) {
RUN_UNLOCK(sc);
ieee80211_ff_flush_all(ic);
RUN_LOCK(sc);
}
#endif
}
static void
@ -3318,15 +3373,21 @@ run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data)
if (ridx != RT2860_RIDX_CCK1 &&
(ic->ic_flags & IEEE80211_F_SHPREAMBLE))
mcs |= RT2860_PHY_SHPRE;
} else
} else if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM) {
mcs |= RT2860_PHY_OFDM;
} else if (rt2860_rates[ridx].phy == IEEE80211_T_HT) {
/* XXX TODO: [adrian] set short preamble for MCS? */
mcs |= RT2860_PHY_HT; /* Mixed, not greenfield */
}
txwi->phy = htole16(mcs);
/* check if RTS/CTS or CTS-to-self protection is required */
if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
(m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold ||
((m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) ||
((ic->ic_flags & IEEE80211_F_USEPROT) &&
rt2860_rates[ridx].phy == IEEE80211_T_OFDM)))
rt2860_rates[ridx].phy == IEEE80211_T_OFDM) ||
((ic->ic_htprotmode == IEEE80211_PROT_RTSCTS) &&
rt2860_rates[ridx].phy == IEEE80211_T_HT)))
txwi->txop |= RT2860_TX_TXOP_HT;
else
txwi->txop |= RT2860_TX_TXOP_BACKOFF;
@ -3390,7 +3451,8 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
/* pickup a rate index */
if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
type != IEEE80211_FC0_TYPE_DATA || m->m_flags & M_EAPOL) {
ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
/* XXX TODO: methodize for 11n; use MCS0 for 11NA/11NG */
ridx = (ic->ic_curmode == IEEE80211_MODE_11A || ic->ic_curmode == IEEE80211_MODE_11NA) ?
RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1;
ctl_ridx = rt2860_rates[ridx].ctl_ridx;
} else {
@ -3609,6 +3671,7 @@ run_sendprot(struct run_softc *sc,
data->m = mprot;
data->ni = ieee80211_ref_node(ni);
/* XXX TODO: methodize with MCS rates */
for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
if (rt2860_rates[ridx].rate == protrate)
break;
@ -3684,6 +3747,7 @@ run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
data->m = m;
data->ni = ni;
/* XXX TODO: methodize with MCS rates */
for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++)
if (rt2860_rates[ridx].rate == rate)
break;
@ -4856,12 +4920,17 @@ run_getradiocaps(struct ieee80211com *ic,
memset(bands, 0, sizeof(bands));
setbit(bands, IEEE80211_MODE_11B);
setbit(bands, IEEE80211_MODE_11G);
setbit(bands, IEEE80211_MODE_11NG);
/* Note: for now, only support HT20 channels */
ieee80211_add_channels_default_2ghz(chans, maxchans, nchans, bands, 0);
if (sc->rf_rev == RT2860_RF_2750 || sc->rf_rev == RT2860_RF_2850 ||
sc->rf_rev == RT3070_RF_3052 || sc->rf_rev == RT3593_RF_3053 ||
sc->rf_rev == RT5592_RF_5592) {
setbit(bands, IEEE80211_MODE_11A);
setbit(bands, IEEE80211_MODE_11NA);
/* Note: for now, only support HT20 channels */
ieee80211_add_channel_list_5ghz(chans, maxchans, nchans,
run_chan_5ghz, nitems(run_chan_5ghz), bands, 0);
}
@ -6205,6 +6274,10 @@ run_init_locked(struct run_softc *sc)
/* turn radio LED on */
run_set_leds(sc, RT2860_LED_RADIO);
/* Set up AUTO_RSP_CFG register for auto response */
run_write(sc, RT2860_AUTO_RSP_CFG, RT2860_AUTO_RSP_EN |
RT2860_BAC_ACKPOLICY_EN | RT2860_CTS_40M_MODE_EN);
sc->sc_flags |= RUN_RUNNING;
sc->cmdq_run = RUN_CMDQ_GO;
@ -6311,6 +6384,22 @@ run_delay(struct run_softc *sc, u_int ms)
&sc->sc_mtx : NULL, USB_MS_TO_TICKS(ms));
}
static void
run_update_chw(struct ieee80211com *ic)
{
printf("%s: TODO\n", __func__);
}
static int
run_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
{
/* For now, no A-MPDU TX support in the driver */
return (0);
}
static device_method_t run_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, run_match),

View File

@ -955,11 +955,6 @@ struct rt2860_rxwi {
#define RT5390_EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5GHZ 0x14e
#define RT5390_EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5GHZ 0x14f
#define RT2860_RIDX_CCK1 0
#define RT2860_RIDX_CCK11 3
#define RT2860_RIDX_OFDM6 4
#define RT2860_RIDX_MAX 12
/*
* EEPROM access macro.
*/

View File

@ -97,8 +97,6 @@ STAILQ_HEAD(run_tx_data_head, run_tx_data);
struct run_node {
struct ieee80211_node ni;
uint8_t ridx[IEEE80211_RATE_MAXSIZE];
uint8_t ctl_ridx[IEEE80211_RATE_MAXSIZE];
uint8_t amrr_ridx;
uint8_t mgt_ridx;
uint8_t fix_ridx;