Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src-draft/trunk]: src/sys/dev/usb Convert rate adaption from hardcoded AMRR ...
details: https://anonhg.NetBSD.org/src-all/rev/90098a455514
branches: trunk
changeset: 375801:90098a455514
user: Martin Husemann <martin%NetBSD.org@localhost>
date: Mon Aug 15 17:29:12 2022 +0200
description:
Convert rate adaption from hardcoded AMRR to the new generic ratectl interface.
This is a bit tricky as the chip only does "easy" TX statistics globaly,
and if we have multiple peers we need to poll the TX stats fifo regularily
to be able to associate the statistics with still alive nodes.
diffstat:
sys/dev/usb/if_run.c | 376 +++++++++++++++++++++++++++++++++++++++--------
sys/dev/usb/if_runvar.h | 56 ++----
2 files changed, 327 insertions(+), 105 deletions(-)
diffs (truncated from 718 to 300 lines):
diff -r c9b82d526fcb -r 90098a455514 sys/dev/usb/if_run.c
--- a/sys/dev/usb/if_run.c Mon Aug 15 17:21:30 2022 +0200
+++ b/sys/dev/usb/if_run.c Mon Aug 15 17:29:12 2022 +0200
@@ -56,8 +56,8 @@
#include <net80211/ieee80211_netbsd.h>
#include <net80211/ieee80211_var.h>
-#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_ratectl.h>
#include <net80211/ieee80211_regdomain.h>
#include <dev/firmload.h>
@@ -386,8 +386,9 @@ static int run_delete_key(struct ieee80
const struct ieee80211_key *);
static void run_delete_key_cb(struct run_softc *, void *);
#endif
-static void run_calibrate_to(void *);
-static void run_calibrate_cb(struct run_softc *, void *);
+static void run_ratectl_to(void *);
+static void run_ratectl_cb(struct run_softc *, void *);
+static void run_ratectl_node(void *arg, struct ieee80211_node *ni);
static void run_newassoc(struct ieee80211_node *, int);
static void run_rx_frame(struct run_softc *, uint8_t *, int);
static void run_rx_loop(struct usbwifi *, struct usbwifi_chain *,
@@ -397,7 +398,7 @@ static void run_rx_loop(struct usbwifi
static unsigned run_tx_prepare(struct usbwifi *, struct usbwifi_chain *,
uint8_t);
/* static void run_start(struct ifnet *); */
-static void run_watchdog(void *);
+// static void run_watchdog(void *);
/* static int run_ioctl(struct ifnet *, u_long, void *); */
static void run_select_chan_group(struct run_softc *, int);
static void run_iq_calib(struct run_softc *, u_int);
@@ -543,6 +544,7 @@ struct run_vap {
struct ieee80211vap vap;
int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int);
struct mbuf *beacon_mbuf;
+ int rvp_id;
};
static const struct usbwifi_ops run_ops = {
@@ -671,13 +673,8 @@ run_attach(device_t parent, device_t sel
callout_init(&sc->scan_to, 0);
callout_setfunc(&sc->scan_to, run_next_scan, sc);
*/
- callout_init(&sc->calib_to, 0);
- callout_setfunc(&sc->calib_to, run_calibrate_to, sc);
- callout_init(&sc->sc_watchdog_to, CALLOUT_MPSAFE);
- callout_setfunc(&sc->sc_watchdog_to, run_watchdog, sc);
-
- sc->amrr.amrr_min_success_threshold = 1;
- sc->amrr.amrr_max_success_threshold = 10;
+ callout_init(&sc->ratectl_to, CALLOUT_MPSAFE);
+ callout_setfunc(&sc->ratectl_to, run_ratectl_to, sc);
/* wait for the chip to settle */
for (ntries = 0; ntries < 100; ntries++) {
@@ -787,12 +784,13 @@ run_detach(device_t self, int flags)
struct run_softc *sc = device_private(self);
int err;
+ sc->ratectl_run = RUN_RATECTL_OFF;
err = usbwifi_detach(self, flags);
if (err)
return err;
- callout_stop(&sc->calib_to);
- callout_destroy(&sc->calib_to);
+ callout_stop(&sc->ratectl_to);
+ callout_destroy(&sc->ratectl_to);
return 0;
}
@@ -1743,7 +1741,7 @@ run_newstate(struct ieee80211vap *vap, e
uint32_t tmp, sta[3];
uint8_t wcid;
- callout_stop(&sc->calib_to);
+ callout_stop(&sc->ratectl_to);
ostate = vap->iv_state;
@@ -1797,6 +1795,8 @@ run_newstate(struct ieee80211vap *vap, e
wcid = RUN_AID2WCID(ni->ni_associd);
run_write_region_1(sc, RT2860_WCID_ENTRY(wcid),
ni->ni_macaddr, IEEE80211_ADDR_LEN);
+ memset(&(sc->wcid_stats[wcid]), 0,
+ sizeof(sc->wcid_stats[wcid]));
/* fake a join to init the tx rate */
run_newassoc(ni, 1);
@@ -1808,7 +1808,7 @@ run_newstate(struct ieee80211vap *vap, e
run_read_region_1(sc, RT2860_TX_STA_CNT0,
(uint8_t *)sta, sizeof(sta));
/* start calibration timer */
- callout_schedule(&sc->calib_to, hz);
+ callout_schedule(&sc->ratectl_to, hz);
}
/* turn link LED on */
@@ -1902,7 +1902,7 @@ run_newstate(struct ieee80211vap *vap, e
// run_read_region_1(sc, RT2860_TX_STA_CNT0,
// (uint8_t *)sta, sizeof(sta));
// /* start calibration timer */
-// callout_schedule(&sc->calib_to, hz);
+// callout_schedule(&sc->ratctl_to, hz);
// }
// /* turn link LED on */
@@ -2122,55 +2122,206 @@ run_delete_key_cb(struct run_softc *sc,
#endif
static void
-run_calibrate_to(void *arg)
+run_reset_livelock(struct run_softc *sc)
+{
+ uint32_t tmp;
+
+ usbwifi_isowned_ic(&sc->sc_uw);
+
+ /*
+ * In IBSS or HostAP modes (when the hardware sends beacons), the MAC
+ * can run into a livelock and start sending CTS-to-self frames like
+ * crazy if protection is enabled. Reset MAC/BBP for a while
+ */
+ run_read(sc, RT2860_DEBUG, &tmp);
+ DPRINTFN(4, ("debug reg %08x\n", tmp));
+ if ((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))) {
+ DPRINTFN(4,
+ ("CTS-to-self livelock detected\n"));
+ run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST);
+ usbd_delay_ms(sc->sc_uw.uw_udev, 1);
+ run_write(sc, RT2860_MAC_SYS_CTRL,
+ RT2860_MAC_RX_EN | RT2860_MAC_TX_EN);
+ }
+}
+
+static void
+run_drain_fifo(struct run_softc *sc, void *arg)
+{
+ uint32_t stat;
+ uint16_t (*wstat)[3];
+ uint8_t wcid, mcs, pid;
+ int8_t retry;
+
+ usbwifi_isowned_ic(&sc->sc_uw);
+
+ for (;;) {
+ /* drain Tx status FIFO (maxsize = 16) */
+ run_read(sc, RT2860_TX_STAT_FIFO, &stat);
+ DPRINTFN(6, ("tx stat 0x%08x\n", stat));
+ if (!(stat & RT2860_TXQ_VLD))
+ break;
+
+ wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff;
+
+ /* if no ACK was requested, no feedback is available */
+ if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX ||
+ wcid == 0)
+ continue;
+
+ /*
+ * Even though each stat is Tx-complete-status like format,
+ * the device can poll stats. Because there is no guarantee
+ * that the referring node is still around when read the stats.
+ * So that, if we use ieee80211_ratectl_tx_update(), we will
+ * have hard time not to refer already freed node.
+ *
+ * To eliminate such page faults, we poll stats in softc.
+ * Then, update the rates later with ieee80211_ratectl_tx_updat$
+ */
+ wstat = &(sc->wcid_stats[wcid]);
+ (*wstat)[RUN_TXCNT]++;
+ if (stat & RT2860_TXQ_OK)
+ (*wstat)[RUN_SUCCESS]++;
+ else
+ ieee80211_stat_add(&sc->sc_uw.uw_ic.ic_oerrors, 1);
+ /*
+ * Check if there were retries, ie if the Tx success rate is
+ * different from the requested rate. Note that it works only
+ * because we do not allow rate fallback from OFDM to CCK.
+ */
+ mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f;
+ pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf;
+ if ((retry = pid -1 - mcs) > 0) {
+ (*wstat)[RUN_TXCNT] += retry;
+ (*wstat)[RUN_RETRY] += retry;
+ }
+ }
+
+ DPRINTFN(5, ("clearing tx stat fifo count=%d\n", sc->fifo_cnt));
+ sc->fifo_cnt = 0;
+}
+
+
+static void
+run_ratectl_to(void *arg)
{
/* do it in a process context */
- run_do_async(arg, run_calibrate_cb, NULL, 0);
+ run_do_async(arg, run_ratectl_cb, NULL, 0);
/* next timeout will be rescheduled in the calibration task */
}
/* ARGSUSED */
static void
-run_calibrate_cb(struct run_softc *sc, void *arg)
+run_ratectl_cb(struct run_softc *sc, void *arg)
{
+ struct ieee80211com *ic = usbwifi_ic(&sc->sc_uw);
+ struct ieee80211vap *vap;
+ bool has_non_sta_vaps;
+
+ if (sc->rvp_cnt == 0)
+ return;
+
+ if (sc->rvp_cnt > 1) {
+ /*
+ * run_reset_livelock() doesn't do anything with AMRR,
+ * but Ralink wants us to call it every 1 sec. So, we
+ * piggyback here rather than creating another callout.
+ * Livelock may occur only in HOSTAP or IBSS mode
+ * (when h/w is sending beacons).
+ */
+ usbwifi_lock_ic(&sc->sc_uw);
+ has_non_sta_vaps = false;
+ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+ if (vap->iv_opmode != IEEE80211_M_STA) {
+ has_non_sta_vaps = true;
+ break;
+ }
+ }
+ if (has_non_sta_vaps)
+ run_reset_livelock(sc);
+ /* drain stats if needed */
+ if (sc->fifo_cnt > 0)
+ run_drain_fifo(sc, NULL);
+ usbwifi_unlock_ic(&sc->sc_uw);
+ }
+
+ ieee80211_iterate_nodes(&ic->ic_sta, run_ratectl_node, sc);
+
+ usbwifi_lock_ic(&sc->sc_uw);
+ if (sc->ratectl_run != RUN_RATECTL_OFF)
+ callout_schedule(&sc->ratectl_to, hz);
+ usbwifi_unlock_ic(&sc->sc_uw);
+}
+
+static void
+run_ratectl_node(void *arg, struct ieee80211_node *ni)
+{
+ struct run_softc *sc = arg;
+ struct ieee80211_ratectl_tx_stats *txs = &sc->sc_txs;
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct run_node *rn = (void*)ni;
uint32_t sta[3];
- int s, error;
- struct ieee80211com *ic = usbwifi_ic(&sc->sc_uw);
+ uint16_t (*wstat)[3];
+ int error, ridx;
usbwifi_lock_ic(&sc->sc_uw);
- /* read statistic counters (clear on read) and update AMRR state */
- error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta,
- sizeof(sta));
- if (error != 0)
+ /* Check for special case */
+ if (sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA &&
+ ni != vap->iv_bss)
goto skip;
- DPRINTF(("retrycnt=%d txcnt=%d failcnt=%d\n",
- le32toh(sta[1]) >> 16, le32toh(sta[1]) & 0xffff,
- le32toh(sta[0]) & 0xffff));
-
- s = splnet();
- /* count failed TX as errors */
- ieee80211_stat_add(&ic->ic_oerrors, le32toh(sta[0]) & 0xffff);
-
- sc->amn.amn_retrycnt =
- (le32toh(sta[0]) & 0xffff) + /* failed TX count */
- (le32toh(sta[1]) >> 16); /* TX retransmission count */
-
- sc->amn.amn_txcnt =
- sc->amn.amn_retrycnt +
- (le32toh(sta[1]) & 0xffff); /* successful TX count */
-
- /* XXX amrr not implemented yet? */
- /*
- ieee80211_amrr_choose(&sc->amrr, usbwifi_ic(&sc->sc_uw)->ic_bss,
- &sc->amn);
- */
- splx(s);
-
-skip: usbwifi_unlock_ic(&sc->sc_uw);
- callout_schedule(&sc->calib_to, hz);
+ txs->flags = IEEE80211_RATECTL_TX_STATS_NODE |
Home |
Main Index |
Thread Index |
Old Index