diff --git a/sys/dev/rtwn/if_rtwn.c b/sys/dev/rtwn/if_rtwn.c index efe6fd168b05..0b313b13b0b0 100644 --- a/sys/dev/rtwn/if_rtwn.c +++ b/sys/dev/rtwn/if_rtwn.c @@ -382,7 +382,8 @@ rtwn_sysctlattach(struct rtwn_softc *sc) if (sc->sc_hwcrypto >= RTWN_CRYPTO_MAX) sc->sc_hwcrypto = RTWN_CRYPTO_FULL; - sc->sc_ratectl_sysctl = RTWN_RATECTL_NET80211; +// sc->sc_ratectl_sysctl = RTWN_RATECTL_NET80211; + sc->sc_ratectl_sysctl = RTWN_RATECTL_FW; SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "ratectl", CTLFLAG_RDTUN, &sc->sc_ratectl_sysctl, sc->sc_ratectl_sysctl, "Select rate control mechanism: " @@ -964,6 +965,7 @@ rtwn_tsf_sync_adhoc_task(void *arg, int pending) sc->sc_flags |= RTWN_RCR_LOCKED; /* Enable synchronization. */ + /* XXX HALify */ rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id), R92C_BCN_CTRL_DIS_TSF_UDT0, 0); @@ -971,6 +973,7 @@ rtwn_tsf_sync_adhoc_task(void *arg, int pending) rtwn_delay(sc, ni->ni_intval * 5 * 1000); /* Disable synchronization. */ + /* XXX HALify */ rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id), 0, R92C_BCN_CTRL_DIS_TSF_UDT0); @@ -997,6 +1000,7 @@ rtwn_tsf_sync_enable(struct rtwn_softc *sc, struct ieee80211vap *vap) switch (vap->iv_opmode) { case IEEE80211_M_STA: /* Enable TSF synchronization. */ + /* XXX HALify */ rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id), R92C_BCN_CTRL_DIS_TSF_UDT0, 0); /* Enable TSF beacon handling, needed for RA */ @@ -1143,6 +1147,7 @@ rtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) /* Disable TSF synchronization / beaconing. */ rtwn_beacon_enable(sc, uvp->id, 0); rtwn_sta_beacon_enable(sc, uvp->id, 0); + /* XXX HALify */ rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id), 0, R92C_BCN_CTRL_DIS_TSF_UDT0); @@ -1844,6 +1849,38 @@ rtwn_node_free(struct ieee80211_node *ni) static void rtwn_init_beacon_reg(struct rtwn_softc *sc) { + + /* + * TODO: R92C_BCN_CTRL_EN_BCN needs to be set in at least + * BCN_CTRL(0) or BCN_CTRL(1) for firmware rate control to + * function. + * + * rtwlwifi initialises R92C_BCN_CTRL(0) and the cached + * beacon register value to 0x18 during _rtl92cu_hw_configure(), + * even though in _rtl92cu_init_beacon_parameters() it initialises + * them both to 0x10, like done here. + * + * _beacon_function_enable() sets bits 4, 3, 1 (0x1a) and + * REG_RD_CTRL to 0x6f and calls that from + * rtl92cu_set_beacon_related_registers(). + * + * Then, in rtl92cu_set_hw_reg(), the HW_VAR_H2C_FW_JOINBSSRPT + * call is tweaking a bunch of stuff, like AID and such, and + * also clearing bit 3 and setting bit 4, doing some recovery/ + * reservedpage stff, then setting bit 3 and clearing bit 4. + * + * It's doing this just before it calls + * rtl92c_set_fw_joinbss_report_cmd() which is doing the actual + * connect or disconnect firmware message. + * + * So, during init it's 0x10, but any further subsequent set/clear + * operations are being done using that mask. + * + * Also, bit 3 (R92C_BCN_CTRL_EN_BCN) needs to be set in either + * BCN_CTRL(0) or BCN_CTRL(1) for firmware rate control to work. + * I need to go see what avos@ changed in this area years ago, + * and see about re-enabling that bit appropriately. + */ rtwn_write_1(sc, R92C_BCN_CTRL(0), R92C_BCN_CTRL_DIS_TSF_UDT0); rtwn_write_1(sc, R92C_BCN_CTRL(1), R92C_BCN_CTRL_DIS_TSF_UDT0); rtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404); diff --git a/sys/dev/rtwn/if_rtwn_rx.c b/sys/dev/rtwn/if_rtwn_rx.c index b1465dd80ee7..cfdc391e9661 100644 --- a/sys/dev/rtwn/if_rtwn_rx.c +++ b/sys/dev/rtwn/if_rtwn_rx.c @@ -132,6 +132,11 @@ rtwn_set_basicrates(struct rtwn_softc *sc, uint32_t rates) RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X\n", __func__, rates); rtwn_setbits_4(sc, R92C_RRSR, R92C_RRSR_RATE_BITMAP_M, rates); + + /* TODO: R92C_INIRTS_RATE_SEL */ + + /* XXX TODO: default to OFDM18? */ + rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, RTWN_RIDX_OFDM18); } static void diff --git a/sys/dev/rtwn/if_rtwn_tx.c b/sys/dev/rtwn/if_rtwn_tx.c index bf45d14f7edc..4336bf64dbff 100644 --- a/sys/dev/rtwn/if_rtwn_tx.c +++ b/sys/dev/rtwn/if_rtwn_tx.c @@ -119,6 +119,7 @@ rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni, uint8_t rate, ridx, type; u_int cipher; int ismcast; + bool force_rate = false; RTWN_ASSERT_LOCKED(sc); @@ -129,13 +130,17 @@ rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni, /* Choose a TX rate index. */ if (type == IEEE80211_FC0_TYPE_MGT || type == IEEE80211_FC0_TYPE_CTL || - (m->m_flags & M_EAPOL) != 0) + (m->m_flags & M_EAPOL) != 0) { rate = tp->mgmtrate; - else if (ismcast) + force_rate = true; + } else if (ismcast) { rate = tp->mcastrate; - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) + force_rate = true; + } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { + /* XXX TODO: fixed rate control should override FW rate control somehow */ rate = tp->ucastrate; - else { + force_rate = true; + } else { if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { /* XXX pass pktlen */ (void) ieee80211_ratectl_rate(ni, NULL, 0); @@ -172,7 +177,7 @@ rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni, memset(txd, 0, sc->txdesc_len); txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher))); - rtwn_fill_tx_desc(sc, ni, m, txd, ridx, tp->maxretry); + rtwn_fill_tx_desc(sc, ni, m, txd, ridx, force_rate, tp->maxretry); if (ieee80211_radiotap_active_vap(vap)) { struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; diff --git a/sys/dev/rtwn/if_rtwnvar.h b/sys/dev/rtwn/if_rtwnvar.h index 6b668a1ba979..56d47cebeb34 100644 --- a/sys/dev/rtwn/if_rtwnvar.h +++ b/sys/dev/rtwn/if_rtwnvar.h @@ -329,7 +329,7 @@ struct rtwn_softc { void (*sc_detach_private)(struct rtwn_softc *); void (*sc_fill_tx_desc)(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, - void *, uint8_t, int); + void *, uint8_t, bool, int); void (*sc_fill_tx_desc_raw)(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, void *, const struct ieee80211_bpf_params *); @@ -535,9 +535,9 @@ void rtwn_suspend(struct rtwn_softc *); #define rtwn_detach_private(_sc) \ (((_sc)->sc_detach_private)((_sc))) #define rtwn_fill_tx_desc(_sc, _ni, _m, \ - _buf, _ridx, _maxretry) \ + _buf, _ridx, _force_rate, _maxretry) \ (((_sc)->sc_fill_tx_desc)((_sc), (_ni), \ - (_m), (_buf), (_ridx), (_maxretry))) + (_m), (_buf), (_ridx), (_force_rate), (_maxretry))) #define rtwn_fill_tx_desc_raw(_sc, _ni, _m, \ _buf, _params) \ (((_sc)->sc_fill_tx_desc_raw)((_sc), (_ni), \ diff --git a/sys/dev/rtwn/rtl8192c/r92c.h b/sys/dev/rtwn/rtl8192c/r92c.h index 47a5da90a3bf..8969fee705f6 100644 --- a/sys/dev/rtwn/rtl8192c/r92c.h +++ b/sys/dev/rtwn/rtl8192c/r92c.h @@ -117,7 +117,7 @@ void r92c_tx_enable_ampdu(void *, int); void r92c_tx_setup_hwseq(void *); void r92c_tx_setup_macid(void *, int); void r92c_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *, - struct mbuf *, void *, uint8_t, int); + struct mbuf *, void *, uint8_t, bool, int); void r92c_fill_tx_desc_raw(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, void *, const struct ieee80211_bpf_params *); void r92c_fill_tx_desc_null(struct rtwn_softc *, void *, int, int, int); diff --git a/sys/dev/rtwn/rtl8192c/r92c_chan.c b/sys/dev/rtwn/rtl8192c/r92c_chan.c index f93159a3c94e..eb6e1ac82b7a 100644 --- a/sys/dev/rtwn/rtl8192c/r92c_chan.c +++ b/sys/dev/rtwn/rtl8192c/r92c_chan.c @@ -316,7 +316,11 @@ r92c_set_bw40(struct rtwn_softc *sc, uint8_t chan, int prichlo) struct r92c_softc *rs = sc->sc_priv; rtwn_setbits_1(sc, R92C_BWOPMODE, R92C_BWOPMODE_20MHZ, 0); - rtwn_setbits_1(sc, R92C_RRSR + 2, 0x6f, (prichlo ? 1 : 2) << 5); + + /* This is specifically for the RTL8192C; different for the RTL8188E */ + /* TODO: triple / quadruple check this */ + rtwn_setbits_4(sc, R92C_RRSR, R92C_RRSR_RSC_SUBCHNL_MASK, + (prichlo ? R92C_RRSR_RSC_UPSUBCHNL : R92C_RRSR_RSC_LOWSUBCHNL)); rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_40MHZ); rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, 0, R92C_RFMOD_40MHZ); diff --git a/sys/dev/rtwn/rtl8192c/r92c_fw.c b/sys/dev/rtwn/rtl8192c/r92c_fw.c index 462c3764aaea..aaf2c6fd6d6f 100644 --- a/sys/dev/rtwn/rtl8192c/r92c_fw.c +++ b/sys/dev/rtwn/rtl8192c/r92c_fw.c @@ -177,10 +177,16 @@ r92c_send_ra_cmd(struct rtwn_softc *sc, int macid, uint32_t rates, mode = R92C_RAID_11BG; else mode = R92C_RAID_11B; + cmd.macid = macid | R92C_CMD_MACID_VALID; if (shortgi) cmd.macid |= R92C_CMD_MACID_SGI; - cmd.mask = htole32(mode << 28 | rates); + cmd.mask = htole32(mode << 28 | rates & 0x0fffffff); + + device_printf(sc->sc_dev, + "%s: macid=0x%02x, mask=0x%08x\n", + __func__, cmd.macid, cmd.mask); + error = r92c_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); if (error != 0) { device_printf(sc->sc_dev, @@ -193,6 +199,59 @@ r92c_send_ra_cmd(struct rtwn_softc *sc, int macid, uint32_t rates, } #endif +/* + * NOTE: setting a fixed ucast rate but having the firmware rate masks + * not enable it leads to some hilarious behaviour. + */ +static void +r92c_filter_rate_mask(struct rtwn_softc *sc, struct ieee80211_node *ni, + uint32_t *rates, uint32_t *htrates) +{ +#if 0 + struct rtwn_node *un = RTWN_NODE(ni); + + switch (un->current_ra_level) { + case RTWN_RA_LEVEL_OFF: + break; + case RTWN_RA_LEVEL_LOW: + /* Filter out everything except low rates */ + *rates &= 0x0f3; + /* Allow MCS0-2, MCS8-10 */ + *htrates &= 0x0707; + break; + case RTWN_RA_LEVEL_MED: + /* Filter out high rates */ + *rates &= 0x1ff; + /* Allow MCS0-4, MCS8-12 */ + *htrates &= 0x1f1f; + break; + case RTWN_RA_LEVEL_HI: + /* Allow everything (filter out low rates to save time) */ + *rates &= 0xfcc; + /* Allow MCS4-7, 12-15 */ + *htrates &= 0xf0f0; + break; + } +#endif +} + +static uint8_t +r92c_recalculate_maxrate(struct rtwn_softc *sc, struct ieee80211_node *ni, + uint32_t rates, uint32_t ht_rates) +{ + int i; + uint8_t rate = 0; + uint32_t fw_rates; + + fw_rates = rates | ((ht_rates & 0xffff) << RTWN_RIDX_HT_MCS_SHIFT); + + for (i = 0; i < 32; i++) { + if ((1 << i) & fw_rates) + rate = i; + } + return rate; +} + static void r92c_init_ra(struct rtwn_softc *sc, int macid) { @@ -225,11 +284,18 @@ r92c_init_ra(struct rtwn_softc *sc, int macid) un->ht_rate_mask = htrates; RTWN_NT_UNLOCK(sc); + device_printf(sc->sc_dev, + "%s: rates=0x%08x, htrates=0x%08x, maxrate=%d\n", + __func__, rates, htrates, maxrate); + #ifndef RTWN_WITHOUT_UCODE if (sc->sc_ratectl == RTWN_RATECTL_FW) { uint32_t fw_rates; bool shortgi; /* Add HT rates after normal rates; limit to MCS0..15 */ + r92c_filter_rate_mask(sc, ni, &rates, &htrates); + /* Re-calculate maxrate */ + maxrate = r92c_recalculate_maxrate(sc, ni, rates, htrates); fw_rates = rates | ((htrates & 0xffff) << RTWN_RIDX_HT_MCS_SHIFT); /* Re-calculate short-gi based on op mode */ @@ -243,7 +309,20 @@ r92c_init_ra(struct rtwn_softc *sc, int macid) } #endif - rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(macid), maxrate); + /* + * Note: vendor driver bit 6 set is "use short gi" + */ +// if (sc->sc_ratectl != RTWN_RATECTL_FW) + //rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(macid), RTWN_RIDX_HT_MCS(5)); + //rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(macid), 0); + + /* + * This needs to be set; the RTS initial rate is something + * not set in the descriptor for some reason? + * + * XXX duplicated in if_rtwn.c when setting basic rates. + */ + //rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, RTWN_RIDX_OFDM18); ieee80211_free_node(ni); } @@ -324,6 +403,49 @@ r92c_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap, return (error); } +static enum rtwn_ra_level +r92c_calculate_new_ra_level(struct rtwn_softc *sc, struct ieee80211_node *ni) +{ + struct rtwn_node *rn = RTWN_NODE(ni); + + /* + * Switch based on current RA level too, so we can apply + * some hysteresis. + */ + switch (rn->current_ra_level) { + case RTWN_RA_LEVEL_OFF: + if (rn->avg_pwdb > 75) + return RTWN_RA_LEVEL_HI; + if (rn->avg_pwdb > 40) + return RTWN_RA_LEVEL_MED; + return RTWN_RA_LEVEL_LOW; + break; + case RTWN_RA_LEVEL_LOW: + if (rn->avg_pwdb > 70) + return RTWN_RA_LEVEL_HI; + else if (rn->avg_pwdb > 50) + return RTWN_RA_LEVEL_MED; + return RTWN_RA_LEVEL_LOW; + break; + case RTWN_RA_LEVEL_MED: + if (rn->avg_pwdb > 80) + return RTWN_RA_LEVEL_HI; + else if (rn->avg_pwdb > 40) + return RTWN_RA_LEVEL_MED; + return RTWN_RA_LEVEL_LOW; + break; + case RTWN_RA_LEVEL_HI: + if (rn->avg_pwdb > 70) + return RTWN_RA_LEVEL_HI; + if (rn->avg_pwdb > 50) + return RTWN_RA_LEVEL_MED; + return RTWN_RA_LEVEL_LOW; + break; + } + + return RTWN_RA_LEVEL_OFF; +} + void r92c_set_rssi(struct rtwn_softc *sc) { @@ -336,6 +458,8 @@ r92c_set_rssi(struct rtwn_softc *sc) RTWN_NT_LOCK(sc); for (i = 0; i < sc->macid_limit; i++) { + enum rtwn_ra_level new_ra_level; + /* XXX optimize? */ ni = sc->node_list[i]; if (ni == NULL) @@ -344,12 +468,70 @@ r92c_set_rssi(struct rtwn_softc *sc) rn = RTWN_NODE(ni); cmd.macid = i; cmd.pwdb = rn->avg_pwdb; - RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, - "%s: sending RSSI command (macid %d, rssi %d)\n", - __func__, i, rn->avg_pwdb); + + new_ra_level = r92c_calculate_new_ra_level(sc, ni); RTWN_NT_UNLOCK(sc); + + RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI | RTWN_DEBUG_RA, + "%s: sending RSSI command (macid %d, rssi %d), inidata ridx=0x%02x\n", + __func__, i, rn->avg_pwdb, + rtwn_read_1(sc, R92C_INIDATA_RATE_SEL(i))); + + /* + * TODO: create a new HAL routine to do the iteration + * and calculating the new RA level, caching + * INIDATA_RATE_SEL(i) & 0x3f, etc. Don't put it here. + */ + + /* + * TODO: that adaptive RA level stuff may not be needed + * for RTL8192CU's firmware rate control, so make it + * a HAL call. + */ + + /* + * Send RSSI command + */ r92c_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd)); + + /* + * If the RA level has changed, send a new maskset. + */ + if (new_ra_level != rn->current_ra_level) { + uint32_t rates, htrates, fw_rates; + uint8_t maxrate, macid; + bool shortgi = false; + + macid = i; + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: changing RA level from %d to %d\n", + __func__, + rn->current_ra_level, + new_ra_level); + rn->current_ra_level = new_ra_level; + + rates = rn->rate_mask; + htrates = rn->ht_rate_mask; + /* Add HT rates after normal rates; limit to MCS0..15 */ + r92c_filter_rate_mask(sc, ni, &rates, &htrates); + /* Re-calculate maxrate */ + maxrate = r92c_recalculate_maxrate(sc, ni, rates, + htrates); + /* Re-calculate short-gi based on op mode */ + if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) + shortgi = ieee80211_ht_check_tx_shortgi_40(ni); + else if (IEEE80211_IS_CHAN_HT20(ni->ni_chan)) + shortgi = ieee80211_ht_check_tx_shortgi_20(ni); + else + shortgi = false; + /* Re-calculate rates bitmap */ + fw_rates = rates | + ((htrates & 0xffff) << RTWN_RIDX_HT_MCS_SHIFT); + r92c_send_ra_cmd(sc, macid, fw_rates, maxrate, + shortgi); + } RTWN_NT_LOCK(sc); } RTWN_NT_UNLOCK(sc); @@ -364,12 +546,14 @@ r92c_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) uint8_t macid; int ntries; +#if 0 if (sc->sc_ratectl != RTWN_RATECTL_NET80211) { /* shouldn't happen */ device_printf(sc->sc_dev, "%s called while ratectl = %d!\n", __func__, sc->sc_ratectl); return; } +#endif rpt = (struct r92c_c2h_tx_rpt *)buf; if (len != sizeof(*rpt)) { @@ -385,6 +569,12 @@ r92c_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) __func__, rpt->rptb0, rpt->rptb1, rpt->queue_time_low, rpt->queue_time_high, rpt->rptb4, rpt->rptb5, rpt->rptb6, rpt->rptb7); + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: ok=%d life_expire=%d retry_over=%d\n", + __func__, + !! (rpt->rptb7 & R92C_RPTB7_PKT_OK), + !! (rpt->rptb6 & R92C_RPTB6_LIFE_EXPIRE), + !! (rpt->rptb6 & R92C_RPTB6_RETRY_OVER)); macid = MS(rpt->rptb5, R92C_RPTB5_MACID); if (macid > sc->macid_limit) { @@ -414,7 +604,8 @@ r92c_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED; else txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED; - ieee80211_ratectl_tx_complete(ni, &txs); + if (sc->sc_ratectl == RTWN_RATECTL_NET80211) + ieee80211_ratectl_tx_complete(ni, &txs); } else { RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: macid %u, ni is NULL\n", __func__, macid); diff --git a/sys/dev/rtwn/rtl8192c/r92c_tx.c b/sys/dev/rtwn/rtl8192c/r92c_tx.c index 313f79e216e6..1543486b9de4 100644 --- a/sys/dev/rtwn/rtl8192c/r92c_tx.c +++ b/sys/dev/rtwn/rtl8192c/r92c_tx.c @@ -61,11 +61,18 @@ r92c_tx_get_sco(struct rtwn_softc *sc, struct ieee80211_channel *c) return (R92C_TXDW4_SCO_SCB); } +/* + * TODO: this is only applicable for 8188EU (no rate control), or + * non-rate control config? + */ static void r92c_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + if (sc->sc_ratectl == RTWN_RATECTL_FW) + return; + if (ieee80211_ht_check_tx_ht40(ni)) { int extc_offset; @@ -77,17 +84,34 @@ r92c_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) static void r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd, - enum ieee80211_protmode mode, uint8_t ridx) + enum ieee80211_protmode mode, uint8_t ridx, bool force_ht) { +#if 0 struct ieee80211com *ic = &sc->sc_ic; uint8_t rate; +#endif + +#if 0 + device_printf(sc->sc_dev, + "%s: called; mode=%d, ridx=%d force_ht=%d\n", + __func__, + mode, ridx, force_ht); +#endif + + /* + * Note: for firmware rate control we don't know what rate is + * being transmitted, so for HT frames it should be bumped + * to something like OFDM24. + */ switch (mode) { case IEEE80211_PROT_CTSONLY: txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF); +// txd->txdw4 |= htole32(R92C_TXDW4_HWRTSEN); break; case IEEE80211_PROT_RTSCTS: txd->txdw4 |= htole32(R92C_TXDW4_RTSEN); +// txd->txdw4 |= htole32(R92C_TXDW4_HWRTSEN); break; default: break; @@ -95,19 +119,16 @@ r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd, if (mode == IEEE80211_PROT_CTSONLY || mode == IEEE80211_PROT_RTSCTS) { - if (RTWN_RATE_IS_HT(ridx)) - rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); - else - rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); - ridx = rate2ridx(IEEE80211_RV(rate)); - + ridx = RTWN_RIDX_OFDM24; txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, ridx)); /* RTS rate fallback limit (max). */ txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FB_LMT, 0xf)); - - if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && +#if 0 + if (force_ht == false && RTWN_RATE_IS_CCK(ridx) + && ridx != RTWN_RIDX_CCK1 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) txd->txdw4 |= htole32(R92C_TXDW4_RTS_SHORT); +#endif } } @@ -236,9 +257,17 @@ r92c_calculate_tx_agg_window(struct rtwn_softc *sc, return (wnd); } +/* + * TODO: this needs quite a bit of cleaning up, and there may be + * enough differences between RTL8192CU, RTL8192EU, and RTL8188EU + * to justify creating three separate ones. + * + * Go look at rtl8xxxu and rtlwifi to figure out what's really + * necessary. + */ void r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, - struct mbuf *m, void *buf, uint8_t ridx, int maxretry) + struct mbuf *m, void *buf, uint8_t ridx, bool force_rate, int maxretry) { #ifndef RTWN_WITHOUT_UCODE struct r92c_softc *rs = sc->sc_priv; @@ -251,11 +280,13 @@ r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, enum ieee80211_protmode prot; uint8_t type, tid, qos, qsel; int hasqos, ismcast, macid; + bool ismgmt; wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; hasqos = IEEE80211_QOS_HAS_SEQ(wh); ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + ismgmt = IEEE80211_IS_MGMT(wh); /* Select TX ring for this frame. */ if (hasqos) { @@ -269,22 +300,51 @@ r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, /* Fill Tx descriptor. */ txd = (struct r92c_tx_desc *)buf; txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; - if (ismcast) + if (ismcast) { txd->flags0 |= R92C_FLAGS0_BMCAST; + } + + (void) ismgmt; + + if (ismgmt) { + txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); + txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, + maxretry)); + } + + /* XXX QOSDATA or DATA? Check the vendor/linux drivers again */ + if (IEEE80211_IS_QOSDATA(wh)) + txd->txdw4 |= htole32(R92C_TXDW4_QOS); if (!ismcast) { /* Unicast frame, check if an ACK is expected. */ if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != IEEE80211_QOS_ACKPOLICY_NOACK) { - txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); - txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, - maxretry)); } struct rtwn_node *un = RTWN_NODE(ni); macid = un->id; if (type == IEEE80211_FC0_TYPE_DATA) { + bool use_shpreamble = false; + bool use_ht = false; + + /* + * Calculate whether to use shared preamble / HT + * based on config if its firmware rate control, or + * rate if any other rate control. + */ + if (sc->sc_ratectl == RTWN_RATECTL_FW && force_rate == false) { + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) + use_shpreamble = true; + } else { + if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + use_shpreamble = true; + if (RTWN_RATE_IS_HT(ridx)) + use_ht = true; + } + qsel = tid % RTWN_MAX_TID; rtwn_r92c_tx_enable_ampdu(sc, buf, @@ -303,17 +363,20 @@ r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, #endif } - if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && - (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + if (use_shpreamble) txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE); prot = IEEE80211_PROT_NONE; - if (RTWN_RATE_IS_HT(ridx)) { + /* XXX better way to know whether to set SGI/HT40? */ + if (use_ht || m->m_flags & M_AMPDU_MPDU) { r92c_tx_set_ht40(sc, txd, ni); r92c_tx_set_sgi(sc, txd, ni); prot = ic->ic_htprotmode; - } else if (ic->ic_flags & IEEE80211_F_USEPROT) + } else if (ic->ic_flags & IEEE80211_F_USEPROT) { prot = ic->ic_protmode; + } else if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { + prot = ic->ic_htprotmode; + } /* XXX fix last comparison for A-MSDU (in net80211) */ /* XXX A-MPDU? */ @@ -324,7 +387,8 @@ r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, /* NB: checks for ht40 / short bits (set above). */ if (prot != IEEE80211_PROT_NONE) - r92c_tx_protection(sc, txd, prot, ridx); + r92c_tx_protection(sc, txd, prot, ridx, + !! (m->m_flags & M_AMPDU_MPDU)); } else /* IEEE80211_FC0_TYPE_MGT */ qsel = R92C_TXDW1_QSEL_MGNT; } else { @@ -335,21 +399,43 @@ r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, qsel)); rtwn_r92c_tx_setup_macid(sc, txd, macid); - txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); + /* + * XXX TODO: this should be maxrate from either the + * last firmware ratemask H2C, or the last value + * read from INIDATA. + * + * Having it set to 0 here is fine for the RTL8192CU + * if rate control is working, but it's not fine + * if it hasn't yet become active (eg R92C_BCN_CTRL + * isn't 0x18) - it'll just transmit at CCK1.) + */ + if (sc->sc_ratectl == RTWN_RATECTL_FW && force_rate == false) { + //txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 27)); /* XXX MCS15 */ + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, 0)); /* XXX MCS15 */ + } else { + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); + } + /* Data rate fallback limit (max). */ txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); r92c_tx_raid(sc, txd, ni, ismcast); /* Force this rate if needed. */ - if (sc->sc_ratectl != RTWN_RATECTL_FW) + if (sc->sc_ratectl != RTWN_RATECTL_FW || force_rate == true) txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); + /* Note: 8188cu/8192cu/8723au doesn't set hardware seq */ + /* Note: TXDW4_SEQ_SEL is not a field? What's going on here */ +#if 0 if (!hasqos) { /* Use HW sequence numbering for non-QoS frames. */ rtwn_r92c_tx_setup_hwseq(sc, txd); txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id)); - } else { + } + else +#endif + { uint16_t seqno; if (m->m_flags & M_AMPDU_MPDU) { @@ -392,9 +478,11 @@ r92c_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, params->ibp_try0)); } if (params->ibp_flags & IEEE80211_BPF_RTS) - r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); + r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx, + false); if (params->ibp_flags & IEEE80211_BPF_CTS) - r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); + r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx, + false); rtwn_r92c_tx_setup_macid(sc, txd, RTWN_MACID_BC); txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); @@ -406,6 +494,9 @@ r92c_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); r92c_tx_raid(sc, txd, ni, ismcast); + /* Get TX feedback */ + txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT); + if (!IEEE80211_QOS_HAS_SEQ(wh)) { /* Use HW sequence numbering for non-QoS frames. */ rtwn_r92c_tx_setup_hwseq(sc, txd); diff --git a/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h b/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h index 6e546c3da236..4ddaea25de71 100644 --- a/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h +++ b/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h @@ -69,8 +69,10 @@ struct r92c_tx_desc { uint32_t txdw4; #define R92C_TXDW4_RTSRATE_M 0x0000001f #define R92C_TXDW4_RTSRATE_S 0 +/* XXX what is this SUPPOSED to be */ #define R92C_TXDW4_SEQ_SEL_M 0x00000040 #define R92C_TXDW4_SEQ_SEL_S 6 +#define R92C_TXDW4_QOS 0x00000040 /* BIT(6) for 8188cu/8192cu/8723au */ #define R92C_TXDW4_HWSEQ_EN 0x00000080 #define R92C_TXDW4_DRVRATE 0x00000100 #define R92C_TXDW4_CTS2SELF 0x00000800 diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c b/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c index 10d812dd7a80..91b1b78edb01 100644 --- a/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c +++ b/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c @@ -373,11 +373,7 @@ r92cu_post_init(struct rtwn_softc *sc) if (sc->sc_flags & RTWN_FW_LOADED) { struct r92c_softc *rs = sc->sc_priv; - if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) { - /* XXX firmware RA does not work yet */ - sc->sc_ratectl = RTWN_RATECTL_NET80211; - } else - sc->sc_ratectl = sc->sc_ratectl_sysctl; + sc->sc_ratectl = sc->sc_ratectl_sysctl; /* Start C2H event handling. */ callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout, diff --git a/sys/dev/rtwn/rtl8812a/r12a.h b/sys/dev/rtwn/rtl8812a/r12a.h index 4338c71c1d29..5f6071d34901 100644 --- a/sys/dev/rtwn/rtl8812a/r12a.h +++ b/sys/dev/rtwn/rtl8812a/r12a.h @@ -1,4 +1,4 @@ -/*- +/* * Copyright (c) 2016 Andriy Voskoboinyk * All rights reserved. * @@ -131,7 +131,7 @@ void r12a_get_rx_stats(struct rtwn_softc *, struct ieee80211_rx_stats *, /* r12a_tx.c */ void r12a_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *, - struct mbuf *, void *, uint8_t, int); + struct mbuf *, void *, uint8_t, bool, int); void r12a_fill_tx_desc_raw(struct rtwn_softc *, struct ieee80211_node *, struct mbuf *, void *, const struct ieee80211_bpf_params *); void r12a_fill_tx_desc_null(struct rtwn_softc *, void *, int, int, int); diff --git a/sys/dev/rtwn/rtl8812a/r12a_tx.c b/sys/dev/rtwn/rtl8812a/r12a_tx.c index 822416a09618..cc686668e4a2 100644 --- a/sys/dev/rtwn/rtl8812a/r12a_tx.c +++ b/sys/dev/rtwn/rtl8812a/r12a_tx.c @@ -261,7 +261,7 @@ r12a_calculate_tx_agg_window(struct rtwn_softc *sc, void r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, - struct mbuf *m, void *buf, uint8_t ridx, int maxretry) + struct mbuf *m, void *buf, uint8_t ridx, bool force_rate, int maxretry) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = ni->ni_vap;