Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/pci wm: use a workqueue to reset the interface when ...



details:   https://anonhg.NetBSD.org/src/rev/f131b6ec9358
branches:  trunk
changeset: 368898:f131b6ec9358
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Fri Aug 12 10:58:21 2022 +0000

description:
wm: use a workqueue to reset the interface when wm_watchdog determines it needs a reset.


Author: Nick Hudson <skrll%netbsd.org@localhost>
Committer: Taylor R Campbell <riastradh%NetBSD.org@localhost>

diffstat:

 sys/dev/pci/if_wm.c |  103 +++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 79 insertions(+), 24 deletions(-)

diffs (192 lines):

diff -r 669839504e4b -r f131b6ec9358 sys/dev/pci/if_wm.c
--- a/sys/dev/pci/if_wm.c       Fri Aug 12 10:57:06 2022 +0000
+++ b/sys/dev/pci/if_wm.c       Fri Aug 12 10:58:21 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_wm.c,v 1.760 2022/08/12 10:57:06 riastradh Exp $    */
+/*     $NetBSD: if_wm.c,v 1.761 2022/08/12 10:58:21 riastradh Exp $    */
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -82,7 +82,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.760 2022/08/12 10:57:06 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.761 2022/08/12 10:58:21 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -706,10 +706,15 @@
        struct wm_phyop phy;
        struct wm_nvmop nvm;
 
+       struct workqueue *sc_reset_wq;
+       struct work sc_reset_work;
+       volatile unsigned sc_reset_pending;
+
        bool sc_dying;
 
 #ifdef WM_DEBUG
        uint32_t sc_debug;
+       bool sc_trigger_reset;
 #endif
 };
 
@@ -823,7 +828,7 @@
 static int     wm_detach(device_t, int);
 static bool    wm_suspend(device_t, const pmf_qual_t *);
 static bool    wm_resume(device_t, const pmf_qual_t *);
-static void    wm_watchdog(struct ifnet *);
+static bool    wm_watchdog(struct ifnet *);
 static void    wm_watchdog_txq(struct ifnet *, struct wm_txqueue *,
     uint16_t *);
 static void    wm_watchdog_txq_locked(struct ifnet *, struct wm_txqueue *,
@@ -917,6 +922,7 @@
 static void    wm_deferred_start_locked(struct wm_txqueue *);
 static void    wm_handle_queue(void *);
 static void    wm_handle_queue_work(struct work *, void *);
+static void    wm_handle_reset_work(struct work *, void *);
 /* Interrupt */
 static bool    wm_txeof(struct wm_txqueue *, u_int);
 static bool    wm_rxeof(struct wm_rxqueue *, u_int);
@@ -2222,7 +2228,18 @@
            WM_WORKQUEUE_FLAGS);
        if (error) {
                aprint_error_dev(sc->sc_dev,
-                   "unable to create workqueue\n");
+                   "unable to create TxRx workqueue\n");
+               goto out;
+       }
+
+       snprintf(wqname, sizeof(wqname), "%sReset", device_xname(sc->sc_dev));
+       error = workqueue_create(&sc->sc_reset_wq, wqname,
+           wm_handle_reset_work, sc, WM_WORKQUEUE_PRI, IPL_SOFTCLOCK,
+           WQ_MPSAFE);
+       if (error) {
+               workqueue_destroy(sc->sc_queue_wq);
+               aprint_error_dev(sc->sc_dev,
+                   "unable to create reset workqueue\n");
                goto out;
        }
 
@@ -3517,8 +3534,9 @@
        }
        pci_intr_release(sc->sc_pc, sc->sc_intrs, sc->sc_nintrs);
 
-       /* wm_stop() ensured that the workqueue is stopped. */
+       /* wm_stop() ensured that the workqueues are stopped. */
        workqueue_destroy(sc->sc_queue_wq);
+       workqueue_destroy(sc->sc_reset_wq);
 
        for (i = 0; i < sc->sc_nqueues; i++)
                softint_disestablish(sc->sc_queue[i].wmq_si);
@@ -3603,11 +3621,11 @@
 }
 
 /*
- * wm_watchdog:                [ifnet interface function]
- *
- *     Watchdog timer handler.
- */
-static void
+ * wm_watchdog:
+ *
+ *     Watchdog checker.
+ */
+static bool
 wm_watchdog(struct ifnet *ifp)
 {
        int qid;
@@ -3620,17 +3638,48 @@
                wm_watchdog_txq(ifp, txq, &hang_queue);
        }
 
-       /* IF any of queues hanged up, reset the interface. */
-       if (hang_queue != 0) {
-               (void)wm_init(ifp);
-
-               /*
-                * There are still some upper layer processing which call
-                * ifp->if_start(). e.g. ALTQ or one CPU system
-                */
-               /* Try to get more packets going. */
-               ifp->if_start(ifp);
-       }
+#ifdef WM_DEBUG
+       if (sc->sc_trigger_reset) {
+               /* debug operation, no need for atomicity or reliability */
+               sc->sc_trigger_reset = 0;
+               hang_queue++;
+       }
+#endif
+
+       if (hang_queue == 0)
+               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;
+}
+
+/*
+ * Perform an interface watchdog reset.
+ */
+static void
+wm_handle_reset_work(struct work *work, void *arg)
+{
+       struct wm_softc * const sc = arg;
+       struct ifnet * const ifp = &sc->sc_ethercom.ec_if;
+
+       /* Don't want ioctl operations to happen */
+       IFNET_LOCK(ifp);
+
+       /* reset the interface. */
+       wm_init(ifp);
+
+       IFNET_UNLOCK(ifp);
+
+       /*
+        * There are still some upper layer processing which call
+        * ifp->if_start(). e.g. ALTQ or one CPU system
+        */
+       /* Try to get more packets going. */
+       ifp->if_start(ifp);
+
+       atomic_store_relaxed(&sc->sc_reset_pending, 0);
 }
 
 
@@ -3863,9 +3912,8 @@
        splx(s);
 #endif
 
-       wm_watchdog(ifp);
-
-       callout_schedule(&sc->sc_tick_ch, hz);
+       if (wm_watchdog(ifp))
+               callout_schedule(&sc->sc_tick_ch, hz);
 }
 
 static int
@@ -6468,6 +6516,12 @@
            wm_sysctl_debug, 0, (void *)sc, 0, CTL_CREATE, CTL_EOL);
        if (rv != 0)
                goto teardown;
+       rv = sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE,
+           CTLTYPE_BOOL, "trigger_reset",
+           SYSCTL_DESCR("Trigger an interface reset"),
+           NULL, 0, &sc->sc_trigger_reset, 0, CTL_CREATE, CTL_EOL);
+       if (rv != 0)
+               goto teardown;
 #endif
 
        return;
@@ -7110,6 +7164,7 @@
         */
        for (int i = 0; i < sc->sc_nqueues; i++)
                workqueue_wait(sc->sc_queue_wq, &sc->sc_queue[i].wmq_cookie);
+       workqueue_wait(sc->sc_reset_wq, &sc->sc_reset_work);
 }
 
 static void



Home | Main Index | Thread Index | Old Index