Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci Some MP improvements



details:   https://anonhg.NetBSD.org/src/rev/527ec044c03c
branches:  trunk
changeset: 370080:527ec044c03c
user:      skrll <skrll%NetBSD.org@localhost>
date:      Fri Sep 16 03:55:53 2022 +0000

description:
Some MP improvements

- Remove use of IFF_OACTIVE

- Remove use of if_timer and provide an MP safe multiqueue watchdog

- Sprinkle some lock assertions.

Tested by ryo@. Thanks.

diffstat:

 sys/dev/pci/if_aq.c |  318 ++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 247 insertions(+), 71 deletions(-)

diffs (truncated from 591 to 300 lines):

diff -r 1a5a336379fd -r 527ec044c03c sys/dev/pci/if_aq.c
--- a/sys/dev/pci/if_aq.c       Fri Sep 16 03:12:03 2022 +0000
+++ b/sys/dev/pci/if_aq.c       Fri Sep 16 03:55:53 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_aq.c,v 1.32 2022/09/08 07:05:42 skrll Exp $ */
+/*     $NetBSD: if_aq.c,v 1.33 2022/09/16 03:55:53 skrll Exp $ */
 
 /**
  * aQuantia Corporation Network Driver
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_aq.c,v 1.32 2022/09/08 07:05:42 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_aq.c,v 1.33 2022/09/16 03:55:53 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_if_aq.h"
@@ -854,6 +854,9 @@
        int txr_index;
        kmutex_t txr_mutex;
        bool txr_active;
+       bool txr_stopping;
+       bool txr_sending;
+       time_t txr_lastsent;
 
        pcq_t *txr_pcq;
        void *txr_softint;
@@ -878,6 +881,7 @@
        kmutex_t rxr_mutex;
        bool rxr_active;
        bool rxr_discarding;
+       bool rxr_stopping;
        struct mbuf *rxr_receiving_m;           /* receiving jumboframe */
        struct mbuf *rxr_receiving_m_last;      /* last mbuf of jumboframe */
 
@@ -934,10 +938,12 @@
 
 #define AQ_LOCK(sc)            mutex_enter(&(sc)->sc_mutex);
 #define AQ_UNLOCK(sc)          mutex_exit(&(sc)->sc_mutex);
+#define AQ_LOCKED(sc)          KASSERT(mutex_owned(&(sc)->sc_mutex));
 
 /* lock for FW2X_MPI_{CONTROL,STATE]_REG read-modify-write */
 #define AQ_MPI_LOCK(sc)                mutex_enter(&(sc)->sc_mpi_mutex);
 #define AQ_MPI_UNLOCK(sc)      mutex_exit(&(sc)->sc_mpi_mutex);
+#define AQ_MPI_LOCKED(sc)      KASSERT(mutex_owned(&(sc)->sc_mpi_mutex));
 
 
 struct aq_softc {
@@ -1018,6 +1024,15 @@
        int sc_ec_capenable;            /* last ec_capenable */
        unsigned short sc_if_flags;     /* last if_flags */
 
+       bool sc_tx_sending;
+       bool sc_stopping;
+
+       struct workqueue *sc_reset_wq;
+       struct work sc_reset_work;
+       volatile unsigned sc_reset_pending;
+
+       bool sc_trigger_reset;
+
 #ifdef AQ_EVENT_COUNTERS
        aq_hw_stats_s_t sc_statistics[2];
        int sc_statistics_idx;
@@ -1059,13 +1074,14 @@
 static int aq_vlan_cb(struct ethercom *ec, uint16_t vid, bool set);
 static int aq_ifflags_cb(struct ethercom *);
 static int aq_init(struct ifnet *);
+static int aq_init_locked(struct ifnet *);
 static void aq_send_common_locked(struct ifnet *, struct aq_softc *,
     struct aq_txring *, bool);
 static int aq_transmit(struct ifnet *, struct mbuf *);
 static void aq_deferred_transmit(void *);
 static void aq_start(struct ifnet *);
 static void aq_stop(struct ifnet *, int);
-static void aq_watchdog(struct ifnet *);
+static void aq_stop_locked(struct ifnet *, bool);
 static int aq_ioctl(struct ifnet *, unsigned long, void *);
 
 static int aq_txrx_rings_alloc(struct aq_softc *);
@@ -1076,6 +1092,10 @@
 static void aq_initmedia(struct aq_softc *);
 static void aq_enable_intr(struct aq_softc *, bool, bool);
 
+static void aq_handle_reset_work(struct work *, void *);
+static void aq_unset_stopping_flags(struct aq_softc *);
+static void aq_set_stopping_flags(struct aq_softc *);
+
 #if NSYSMON_ENVSYS > 0
 static void aq_temp_refresh(struct sysmon_envsys *, envsys_data_t *);
 #endif
@@ -1119,6 +1139,12 @@
 static int fw2x_get_temperature(struct aq_softc *, uint32_t *);
 #endif
 
+#ifndef AQ_WATCHDOG_TIMEOUT
+#define AQ_WATCHDOG_TIMEOUT 5
+#endif
+static int aq_watchdog_timeout = AQ_WATCHDOG_TIMEOUT;
+
+
 static const struct aq_firmware_ops aq_fw1x_ops = {
        .reset = fw1x_reset,
        .set_mode = fw1x_set_mode,
@@ -1370,9 +1396,20 @@
        if (error != 0)
                goto attach_failure;
 
-       callout_init(&sc->sc_tick_ch, 0);
+       callout_init(&sc->sc_tick_ch, CALLOUT_MPSAFE);
        callout_setfunc(&sc->sc_tick_ch, aq_tick, sc);
 
+       char wqname[MAXCOMLEN];
+       snprintf(wqname, sizeof(wqname), "%sReset", device_xname(sc->sc_dev));
+       error = workqueue_create(&sc->sc_reset_wq, wqname,
+           aq_handle_reset_work, sc, PRI_SOFTNET, IPL_SOFTCLOCK,
+           WQ_MPSAFE);
+       if (error) {
+               aprint_error_dev(sc->sc_dev,
+                   "unable to create reset workqueue\n");
+               goto attach_failure;
+       }
+
        sc->sc_intr_moderation_enable = CONFIG_INTR_MODERATION_ENABLE;
 
        if (sc->sc_msix && (sc->sc_nqueues > 1))
@@ -1423,7 +1460,7 @@
                ifp->if_transmit = aq_transmit;
        ifp->if_start = aq_start;
        ifp->if_stop = aq_stop;
-       ifp->if_watchdog = aq_watchdog;
+       ifp->if_watchdog = NULL;
        IFQ_SET_READY(&ifp->if_snd);
 
        /* initialize capabilities */
@@ -1551,9 +1588,7 @@
 
        if (sc->sc_iosize != 0) {
                if (ifp->if_softc != NULL) {
-                       const int s = splnet();
                        aq_stop(ifp, 0);
-                       splx(s);
                }
 
                for (i = 0; i < AQ_NINTR_MAX; i++) {
@@ -2753,6 +2788,7 @@
 aq_ifmedia_change(struct ifnet * const ifp)
 {
        struct aq_softc * const sc = ifp->if_softc;
+
        aq_link_speed_t rate = AQ_LINK_NONE;
        aq_link_fc_t fc = AQ_FC_NONE;
        aq_link_eee_t eee = AQ_EEE_DISABLE;
@@ -3828,10 +3864,67 @@
 }
 #endif
 
+
+
+static bool
+aq_watchdog_check(struct aq_softc * const sc)
+{
+
+       AQ_LOCKED(sc);
+
+       bool ok = true;
+       for (u_int n = 0; n < sc->sc_nqueues; n++) {
+               struct aq_txring *txring = &sc->sc_queue[n].txring;
+
+               mutex_enter(&txring->txr_mutex);
+               if (txring->txr_sending &&
+                   time_uptime - txring->txr_lastsent > aq_watchdog_timeout)
+                       ok = false;
+
+               mutex_exit(&txring->txr_mutex);
+
+               if (!ok)
+                       return false;
+       }
+
+       if (sc->sc_trigger_reset) {
+               /* debug operation, no need for atomicity or reliability */
+               sc->sc_trigger_reset = 0;
+               return false;
+       }
+
+       return true;
+}
+
+
+
+static bool
+aq_watchdog_tick(struct ifnet *ifp)
+{
+       struct aq_softc * const sc = ifp->if_softc;
+
+       AQ_LOCKED(sc);
+
+       if (!sc->sc_trigger_reset && aq_watchdog_check(sc))
+               return true;
+
+       if (atomic_swap_uint(&sc->sc_reset_pending, 1) == 0) {
+               workqueue_enqueue(sc->sc_reset_wq, &sc->sc_reset_work, NULL);
+       }
+
+       return false;
+}
+
 static void
 aq_tick(void *arg)
 {
-       struct aq_softc *sc = arg;
+       struct aq_softc * const sc = arg;
+
+       AQ_LOCK(sc);
+       if (sc->sc_stopping) {
+               AQ_UNLOCK(sc);
+               return;
+       }
 
        if (sc->sc_poll_linkstat || sc->sc_detect_linkstat) {
                sc->sc_detect_linkstat = false;
@@ -3843,13 +3936,12 @@
                aq_update_statistics(sc);
 #endif
 
-       if (sc->sc_poll_linkstat
-#ifdef AQ_EVENT_COUNTERS
-           || sc->sc_poll_statistics
-#endif
-           ) {
+       struct ifnet * const ifp = &sc->sc_ethercom.ec_if;
+       const bool ok = aq_watchdog_tick(ifp);
+       if (ok)
                callout_schedule(&sc->sc_tick_ch, hz);
-       }
+
+       AQ_UNLOCK(sc);
 }
 
 /* interrupt enable/disable */
@@ -3931,7 +4023,7 @@
 static int
 aq_link_intr(void *arg)
 {
-       struct aq_softc *sc = arg;
+       struct aq_softc * const sc = arg;
        uint32_t status;
        int nintr = 0;
 
@@ -4229,6 +4321,7 @@
        hw_head = AQ_READ_REG_BIT(sc, TX_DMA_DESC_HEAD_PTR_REG(ringidx),
            TX_DMA_DESC_HEAD_PTR);
        if (hw_head == txring->txr_considx) {
+               txring->txr_sending = false;
                goto tx_intr_done;
        }
 
@@ -4256,12 +4349,9 @@
 
        IF_STAT_PUTREF(ifp);
 
-       if (ringidx == 0 && txring->txr_nfree >= AQ_TXD_MIN)
-               ifp->if_flags &= ~IFF_OACTIVE;
-
        /* no more pending TX packet, cancel watchdog */
        if (txring->txr_nfree >= AQ_TXD_NUM)
-               ifp->if_timer = 0;
+               txring->txr_sending = false;
 
  tx_intr_done:
        mutex_exit(&txring->txr_mutex);
@@ -4536,16 +4626,32 @@
        return error;
 }
 
+
 static int
 aq_init(struct ifnet *ifp)
 {
        struct aq_softc * const sc = ifp->if_softc;
-       int i, error = 0;
-
-       aq_stop(ifp, false);
 
        AQ_LOCK(sc);
 
+       int ret = aq_init_locked(ifp);
+
+       AQ_UNLOCK(sc);
+
+       return ret;
+}
+
+static int
+aq_init_locked(struct ifnet *ifp)
+{
+       struct aq_softc * const sc = ifp->if_softc;
+       int i, error = 0;



Home | Main Index | Thread Index | Old Index