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/32fbdc38c8e6
branches:  trunk
changeset: 371685:32fbdc38c8e6
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 ddb7c253459e -r 32fbdc38c8e6 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 @@
                            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 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 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 @@
        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 @@
        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 @@
        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 @@
                        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_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_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 @@
 #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