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