Current-Users archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Testers wanted - MPSAFE watchdog for rge(4)
For those of you who have any of the various rge(4) hardware (for
RealTek 8125/8126/8127) it would be great if you could test with
the attached changes. This provides an MPSAFE watchdog mechanism
rather trhan using BIG-LOCK or spl() tactics. It should improve
overall system performance.
A big "Thanks!" goes out to skrll@ for doing all the heavy lifting
on this. (I'm just doing the "easy" part of coordinating testing
and the actual commit.)
Thanks in advance for all your efforts.
+---------------------+--------------------------+----------------------+
| Paul Goyette (.sig) | PGP Key fingerprint: | E-mail addresses: |
| (Retired) | 1B11 1849 721C 56C8 F63A | paul%whooppee.com@localhost |
| Software Developer | 6E2E 05FD 15CE 9F2D 5102 | pgoyette%netbsd.org@localhost |
| & Network Engineer | | pgoyette99%gmail.com@localhost |
+---------------------+--------------------------+----------------------+
Index: if_rge.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_rge.c,v
retrieving revision 1.47
diff -u -p -r1.47 if_rge.c
--- if_rge.c 28 Jan 2026 06:15:37 -0000 1.47
+++ if_rge.c 1 Feb 2026 01:04:32 -0000
@@ -94,6 +94,11 @@ MCLGETL(struct rge_softc *sc __unused, i
#endif
#endif
+#ifndef RGE_WATCHDOG_TIMEOUT
+#define RGE_WATCHDOG_TIMEOUT 5
+#endif
+static int rge_watchdog_timeout = RGE_WATCHDOG_TIMEOUT;
+
#ifdef RGE_DEBUG
#define DPRINTF(x) do { if (rge_debug > 0) printf x; } while (0)
int rge_debug = 0;
@@ -109,7 +114,6 @@ static int rge_encap(struct rge_softc *,
struct mbuf *, int);
static int rge_ioctl(struct ifnet *, u_long, void *);
static void rge_start(struct ifnet *);
-static void rge_watchdog(struct ifnet *);
static int rge_init(struct ifnet *);
static void rge_stop(struct ifnet *, int);
static int rge_ifmedia_upd(struct ifnet *);
@@ -120,6 +124,7 @@ static int rge_newbuf(struct rge_queues
static int rge_rx_list_init(struct rge_queues *);
static void rge_rx_list_fini(struct rge_queues *);
static void rge_tx_list_init(struct rge_queues *);
+/* static void rge_tx_list_fini(struct rge_queues *); */
static int rge_rxeof(struct rge_softc *);
static int rge_txeof(struct rge_softc *);
static int rge_reset(struct rge_softc *);
@@ -171,9 +176,11 @@ static uint16_t rge_read_phy(struct rge_
static void rge_write_phy_ocp(struct rge_softc *, uint16_t, uint16_t);
static uint16_t rge_read_phy_ocp(struct rge_softc *, uint16_t);
static int rge_get_link_status(struct rge_softc *);
-static void rge_txstart(void *);
+static void rge_txstart(struct rge_softc *);
static void rge_tick(void *);
static void rge_link_state(struct rge_softc *);
+static bool rge_watchdog_tick(struct ifnet *);
+static void rge_handle_reset_work(struct work *, void *);
static const struct {
uint16_t reg;
@@ -367,6 +374,16 @@ rge_attach(device_t parent, device_t sel
if (rge_allocmem(sc))
return;
+ char wqname[MAXCOMLEN];
+ snprintf(wqname, sizeof(wqname), "%sReset", device_xname(sc->sc_dev));
+ int error = workqueue_create(&sc->sc_reset_wq, wqname,
+ rge_handle_reset_work, sc, PRI_NONE, IPL_SOFTCLOCK,WQ_MPSAFE);
+ if (error) {
+ aprint_error_dev(sc->sc_dev,
+ "unable to create reset workqueue\n");
+ return;
+ }
+
ifp = &sc->sc_ec.ec_if;
ifp->if_softc = sc;
strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
@@ -378,7 +395,7 @@ rge_attach(device_t parent, device_t sel
ifp->if_stop = rge_stop;
ifp->if_start = rge_start;
ifp->if_init = rge_init;
- ifp->if_watchdog = rge_watchdog;
+ ifp->if_watchdog = NULL;
IFQ_SET_MAXLEN(&ifp->if_snd, RGE_TX_LIST_CNT - 1);
ifp->if_capabilities = IFCAP_CSUM_IPv4_Rx |
@@ -388,7 +405,7 @@ rge_attach(device_t parent, device_t sel
sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_HWTAGGING;
- callout_init(&sc->sc_timeout, CALLOUT_FLAGS);
+ callout_init(&sc->sc_timeout, CALLOUT_MPSAFE);
callout_setfunc(&sc->sc_timeout, rge_tick, sc);
command = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
@@ -735,15 +752,67 @@ rge_start(struct ifnet *ifp)
rge_txstart(sc);
}
-static void
-rge_watchdog(struct ifnet *ifp)
+static bool
+rge_watchdog_check(struct rge_softc * const sc)
{
- struct rge_softc *sc = ifp->if_softc;
- device_printf(sc->sc_dev, "watchdog timeout\n");
+ KASSERT(mutex_owned(sc->sc_core_lock));
+
+ if (!sc->sc_tx_sending)
+ return true;
+
+ if (time_uptime - sc->sc_tx_lastsent <= rge_watchdog_timeout)
+ return true;
+
+ return false;
+}
+
+static bool
+rge_watchdog_tick(struct ifnet *ifp)
+{
+ struct rge_softc * const sc = ifp->if_softc;
+
+ KASSERT(mutex_owned(sc->sc_core_lock));
+
+ if (!sc->sc_trigger_reset && rge_watchdog_check(sc))
+ return true;
+
if_statinc(ifp, if_oerrors);
+ 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
+rge_handle_reset_work(struct work *work, void *arg)
+{
+ struct rge_softc * const sc = arg;
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
+
+ printf("%s: watchdog timeout -- resetting\n", ifp->if_xname);
+
+ /* Don't want ioctl operations to happen */
+ IFNET_LOCK(ifp);
+
+ /* reset the interface. */
rge_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);
+
}
static int
@@ -3804,9 +3873,8 @@ rge_get_link_status(struct rge_softc *sc
}
static void
-rge_txstart(void *arg)
+rge_txstart(struct rge_softc *sc)
{
- struct rge_softc *sc = arg;
RGE_WRITE_2(sc, RGE_TXSTART, RGE_TXSTART_START);
}
@@ -3815,13 +3883,21 @@ static void
rge_tick(void *arg)
{
struct rge_softc *sc = arg;
- int s;
- s = splnet();
+ mutex_enter(sc->sc_core_lock);
+ if (sc->sc_stopping) {
+ mutex_exit(sc->sc_core_lock);
+ return;
+ }
+
rge_link_state(sc);
- splx(s);
- callout_schedule(&sc->sc_timeout, hz);
+ struct ifnet * const ifp = &sc->sc_ec.ec_if;
+ const bool ok = rge_watchdog_tick(ifp);
+ if (ok)
+ callout_schedule(&sc->sc_timeout, hz);
+
+ mutex_exit(sc->sc_core_lock);
}
static void
Index: if_rgereg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_rgereg.h,v
retrieving revision 1.18
diff -u -p -r1.18 if_rgereg.h
--- if_rgereg.h 28 Jan 2026 06:15:37 -0000 1.18
+++ if_rgereg.h 1 Feb 2026 01:04:34 -0000
@@ -424,6 +424,18 @@ struct rge_softc {
int rge_timerintr;
#define RGE_IMTYPE_NONE 0
#define RGE_IMTYPE_SIM 1
+
+ kmutex_t *sc_core_lock;
+ time_t sc_tx_lastsent;
+ bool sc_tx_sending;
+
+ struct workqueue *sc_reset_wq;
+ struct work sc_reset_work;
+ volatile unsigned sc_reset_pending;
+ bool sc_stopping;
+
+ bool sc_trigger_reset;
+
};
/*
Home |
Main Index |
Thread Index |
Old Index