aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Chadd <adrian@FreeBSD.org>2024-12-15 04:38:18 +0000
committerAdrian Chadd <adrian@FreeBSD.org>2024-12-31 19:11:33 +0000
commitaf2e102c40652156c89029177da7961165ffe4cc (patch)
treeacdad9cb3468278ecd14ab3defbc4c470fe75814
parent7ddf19492cd930e8b3df970b2cab0909d227dc6a (diff)
rtwn: enable periodic TX reporting support on RTL8188EU NICs.
The RTL8188E firmware doesn't have the "full" offload firmware rate control. Instead, the vendor driver has a bunch of logic in the driver for rate probing and selection. Part of this is the periodic TX report - which uploads a summary of multi-rate retries and drops per MAC. Using it drastically cuts down on the TX notifications - it's fired from a timer (defaulting to ~ 1.6 seconds) and is a single receive frame in the normal bulk RX path. I've not ported / reimplemented the whole vendor driver rate adaption code - instead, I'm just using the normal net80211 rate control APIs. It seems to behave OK - I get 25-30mbit down and 20mbit up using TCP/ speedtest. Locally tested: * RTL8188EU, STA mode Differential Revision: https://reviews.freebsd.org/D48088 Reviewed by: fuz, bz Obtained from: https://github.com/lwfinger/rtl8188eu/blob/master/hal/Hal8188ERateAdaptive.c
-rw-r--r--sys/dev/rtwn/if_rtwnvar.h1
-rw-r--r--sys/dev/rtwn/rtl8188e/r88e.h1
-rw-r--r--sys/dev/rtwn/rtl8188e/r88e_rx.c86
-rw-r--r--sys/dev/rtwn/rtl8188e/r88e_rx_desc.h14
-rw-r--r--sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c4
-rw-r--r--sys/dev/rtwn/rtl8188e/usb/r88eu_init.c15
-rw-r--r--sys/dev/rtwn/rtl8192c/r92c_tx.c23
7 files changed, 141 insertions, 3 deletions
diff --git a/sys/dev/rtwn/if_rtwnvar.h b/sys/dev/rtwn/if_rtwnvar.h
index 570403747392..3913526f8c3c 100644
--- a/sys/dev/rtwn/if_rtwnvar.h
+++ b/sys/dev/rtwn/if_rtwnvar.h
@@ -401,6 +401,7 @@ struct rtwn_softc {
uint16_t rx_dma_size;
int macid_limit;
+ int macid_rpt2_max_num;
int cam_entry_limit;
int fwsize_limit;
int temp_delta;
diff --git a/sys/dev/rtwn/rtl8188e/r88e.h b/sys/dev/rtwn/rtl8188e/r88e.h
index 488e6ea79d3f..6569b014a5c6 100644
--- a/sys/dev/rtwn/rtl8188e/r88e.h
+++ b/sys/dev/rtwn/rtl8188e/r88e.h
@@ -86,6 +86,7 @@ int8_t r88e_get_rssi_cck(struct rtwn_softc *, void *);
int8_t r88e_get_rssi_ofdm(struct rtwn_softc *, void *);
void r88e_get_rx_stats(struct rtwn_softc *, struct ieee80211_rx_stats *,
const void *, const void *);
+void r88e_ratectl_tx_complete_periodic(struct rtwn_softc *, uint8_t *, int);
/* r88e_tx.c */
void r88e_tx_enable_ampdu(void *, int);
diff --git a/sys/dev/rtwn/rtl8188e/r88e_rx.c b/sys/dev/rtwn/rtl8188e/r88e_rx.c
index 287869885b86..2ff0ee4dae00 100644
--- a/sys/dev/rtwn/rtl8188e/r88e_rx.c
+++ b/sys/dev/rtwn/rtl8188e/r88e_rx.c
@@ -232,3 +232,89 @@ r88e_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs,
rxs->c_band = IEEE80211_CHAN_2GHZ;
}
}
+
+void
+r88e_ratectl_tx_complete_periodic(struct rtwn_softc *sc, uint8_t *buf,
+ int len)
+{
+ const struct r92c_rx_stat *rxs;
+ uint64_t mac_bitmap;
+ int macid;
+
+ if (len < sizeof(struct r92c_rx_stat))
+ return;
+
+ rxs = (const struct r92c_rx_stat *) buf;
+
+ /* Skip Rx descriptor. */
+ buf += sizeof(struct r92c_rx_stat);
+ len -= sizeof(struct r92c_rx_stat);
+
+ /*
+ * Note: the valid macid bitmap is rx_desc[5] << 32 | rx_desc[4];
+ * Note: rx_desc[5] is the TSF, which isn't valid for this report!
+ */
+ mac_bitmap = ((uint64_t) le32toh(rxs->tsf_low) << 32)
+ | le32toh(rxs->rxdw4);
+
+ RTWN_DPRINTF(sc, RTWN_DEBUG_RA,
+ "%s: mac bitmap: 0x%lx\n", __func__, mac_bitmap);
+
+ /*
+ * Note: the RX reports aren't sparse - invalid entries (ie,
+ * the bitmap has the macid set to 0) are just populated
+ * with random data.
+ */
+ for (macid = 0; (macid < 64) && (macid < sc->macid_rpt2_max_num) &&
+ (len >= sizeof(struct r88e_fw_c2h_txreport2_entry)); macid++) {
+ struct ieee80211_ratectl_tx_stats txs = { 0 };
+ const struct r88e_fw_c2h_txreport2_entry *rpt;
+ uint32_t ntotal, nsuccess, ndrop, nretry, nframes;
+
+ rpt = (const struct r88e_fw_c2h_txreport2_entry *) buf;
+ buf += sizeof(struct r88e_fw_c2h_txreport2_entry);
+ len -= sizeof(struct r88e_fw_c2h_txreport2_entry);
+
+ if ((mac_bitmap & (1UL << macid)) == 0)
+ continue;
+
+ txs.flags = IEEE80211_RATECTL_TX_STATS_NODE |
+ IEEE80211_RATECTL_TX_STATS_RETRIES;
+
+ /* calculate all the various combinations of things */
+ nframes = le16toh(rpt->retry0);
+ ntotal = nframes + rpt->retry1 + rpt->retry2
+ + rpt->retry3 + rpt->retry4 + rpt->drop;
+ /*
+ * Note: sometimes this is zero or 1, but the retries
+ * are all capped out at 255! That means the frame
+ * transmits are all failing.
+ */
+ nsuccess = ntotal - rpt->drop;
+ ndrop = rpt->drop;
+ nretry = rpt->retry1 + rpt->retry2 + rpt->retry3
+ + rpt->retry4;
+
+ txs.nretries = nretry + ndrop;
+ txs.nsuccess = nsuccess;
+ txs.nframes = ntotal;
+
+ RTWN_DPRINTF(sc, RTWN_DEBUG_RA,
+ "%s: MAC %d rpt retries %d %d %d %d %d, "
+ "drop %d\n",
+ __func__,
+ macid,
+ le16toh(rpt->retry0),
+ rpt->retry1,
+ rpt->retry2,
+ rpt->retry3,
+ rpt->retry4,
+ rpt->drop);
+ if (sc->node_list[macid] != NULL) {
+ struct ieee80211_node *ni;
+ ni = sc->node_list[macid];
+ txs.ni = ni;
+ ieee80211_ratectl_tx_update(ni->ni_vap, &txs);
+ }
+ }
+}
diff --git a/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h b/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h
index f3e1a3c1b9bc..59e885eb4821 100644
--- a/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h
+++ b/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h
@@ -81,6 +81,20 @@ struct r88e_tx_rpt_ccx {
uint8_t rptb7;
} __packed;
+/*
+ * The 8188E periodic TX report entries
+ * (type 2 report.)
+ */
+struct r88e_fw_c2h_txreport2_entry {
+ uint16_t retry0;
+ uint8_t retry1;
+ uint8_t retry2;
+ uint8_t retry3;
+ uint8_t retry4;
+ uint8_t drop;
+ uint8_t reserved;
+} __packed;
+
/* Interrupt message format. */
/* XXX recheck */
struct r88e_intr_msg {
diff --git a/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c b/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
index 2d4713e92bd2..9ace2396d712 100644
--- a/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
+++ b/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
@@ -138,7 +138,7 @@ r88eu_attach(struct rtwn_usb_softc *uc)
sc->sc_get_rssi_ofdm = r88e_get_rssi_ofdm;
sc->sc_classify_intr = r88e_classify_intr;
sc->sc_handle_tx_report = r88e_ratectl_tx_complete;
- sc->sc_handle_tx_report2 = rtwn_nop_softc_uint8_int;
+ sc->sc_handle_tx_report2 = r88e_ratectl_tx_complete_periodic;
sc->sc_handle_c2h_report = r88e_handle_c2h_report;
sc->sc_check_frame = rtwn_nop_int_softc_mbuf;
sc->sc_rf_read = r92c_rf_read;
@@ -212,6 +212,8 @@ r88eu_attach(struct rtwn_usb_softc *uc)
sc->rx_dma_size = R88E_RX_DMA_BUFFER_SIZE;
sc->macid_limit = R88E_MACID_MAX + 1;
+ /* XXX this limit may be expanded to R88E_MACID_MAX */
+ sc->macid_rpt2_max_num = 2;
sc->cam_entry_limit = R92C_CAM_ENTRY_COUNT;
sc->fwsize_limit = R92C_MAX_FW_SIZE;
sc->temp_delta = R88E_CALIB_THRESHOLD;
diff --git a/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c b/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c
index f4f936493cda..312e437958ec 100644
--- a/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c
+++ b/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c
@@ -279,9 +279,22 @@ void
r88eu_post_init(struct rtwn_softc *sc)
{
- /* Enable per-packet TX report. */
+ /* Enable per-packet TX report (RPT1) */
rtwn_setbits_1(sc, R88E_TX_RPT_CTRL, 0, R88E_TX_RPT1_ENA);
+#ifndef RTWN_WITHOUT_UCODE
+ /* Enable timer report (RPT2) if requested */
+ if (sc->macid_rpt2_max_num > 0) {
+ rtwn_setbits_1(sc, R88E_TX_RPT_CTRL, 0,
+ R88E_TX_RPT2_ENA);
+
+ /* Configure how many TX RPT2 entries to populate */
+ rtwn_write_1(sc, R88E_TX_RPT_MACID_MAX,
+ sc->macid_rpt2_max_num);
+ /* Enable periodic TX report; 32uS units */
+ rtwn_write_2(sc, R88E_TX_RPT_TIME, 0xcdf0);
+ }
+#endif
/* Disable Tx if MACID is not associated. */
rtwn_write_4(sc, R88E_MACID_NO_LINK, 0xffffffff);
rtwn_write_4(sc, R88E_MACID_NO_LINK + 4, 0xffffffff);
diff --git a/sys/dev/rtwn/rtl8192c/r92c_tx.c b/sys/dev/rtwn/rtl8192c/r92c_tx.c
index c60081fc675c..07a6a184e924 100644
--- a/sys/dev/rtwn/rtl8192c/r92c_tx.c
+++ b/sys/dev/rtwn/rtl8192c/r92c_tx.c
@@ -236,6 +236,27 @@ r92c_calculate_tx_agg_window(struct rtwn_softc *sc,
return (wnd);
}
+/*
+ * Check whether to enable the per-packet TX CCX report.
+ *
+ * For chipsets that do the RPT2 reports, enabling the TX
+ * CCX report results in the packet not being counted in
+ * the RPT2 counts.
+ */
+static bool
+r92c_check_enable_ccx_report(struct rtwn_softc *sc, int macid)
+{
+ if (sc->sc_ratectl != RTWN_RATECTL_NET80211)
+ return false;
+
+#ifndef RTWN_WITHOUT_UCODE
+ if ((sc->macid_rpt2_max_num != 0) &&
+ (macid < sc->macid_rpt2_max_num))
+ return false;
+#endif
+ return true;
+}
+
void
r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni,
struct mbuf *m, void *buf, uint8_t ridx, int maxretry)
@@ -298,7 +319,7 @@ r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni,
txd->txdw6 |= htole32(SM(R92C_TXDW6_MAX_AGG,
r92c_calculate_tx_agg_window(sc, ni, tid)));
}
- if (sc->sc_ratectl == RTWN_RATECTL_NET80211) {
+ if (r92c_check_enable_ccx_report(sc, macid)) {
txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT);
sc->sc_tx_n_active++;
#ifndef RTWN_WITHOUT_UCODE