Module Name:    src
Committed By:   knakahara
Date:           Fri Jan 24 02:50:41 UTC 2020

Modified Files:
        src/sys/dev/pci: if_wm.c

Log Message:
wm(4) can use workqueue as deferred Rx/Tx handler like ixg(4).

Set hw.wm*.txrx_workqueue=1 to use workqueue instead of softint.
The default value of hw.wm*.txrx_workqueue is 0, that is, use softint
as before.

ok by [email protected].


To generate a diff of this commit:
cvs rdiff -u -r1.661 -r1.662 src/sys/dev/pci/if_wm.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.661 src/sys/dev/pci/if_wm.c:1.662
--- src/sys/dev/pci/if_wm.c:1.661	Thu Jan 23 07:49:57 2020
+++ src/sys/dev/pci/if_wm.c	Fri Jan 24 02:50:41 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.661 2020/01/23 07:49:57 knakahara Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.662 2020/01/24 02:50:41 knakahara 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.661 2020/01/23 07:49:57 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.662 2020/01/24 02:50:41 knakahara Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -105,6 +105,8 @@ __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.
 #include <sys/interrupt.h>
 #include <sys/cpu.h>
 #include <sys/pcq.h>
+#include <sys/sysctl.h>
+#include <sys/workqueue.h>
 
 #include <sys/rndsource.h>
 
@@ -164,10 +166,14 @@ int	wm_debug = WM_DEBUG_TX | WM_DEBUG_RX
 #ifdef NET_MPSAFE
 #define WM_MPSAFE	1
 #define CALLOUT_FLAGS	CALLOUT_MPSAFE
+#define WM_WORKQUEUE_FLAGS	WQ_PERCPU | WQ_MPSAFE
 #else
 #define CALLOUT_FLAGS	0
+#define WM_WORKQUEUE_FLAGS	WQ_PERCPU
 #endif
 
+#define WM_WORKQUEUE_PRI PRI_SOFTNET
+
 /*
  * This device driver's max interrupt numbers.
  */
@@ -456,6 +462,8 @@ struct wm_queue {
 	struct wm_txqueue wmq_txq;
 	struct wm_rxqueue wmq_rxq;
 
+	bool wmq_txrx_use_workqueue;
+	struct work wmq_cookie;
 	void *wmq_si;
 	krndsource_t rnd_source;	/* random source */
 };
@@ -552,6 +560,8 @@ struct wm_softc {
 	u_int sc_tx_intr_process_limit;	/* Tx proc. repeat limit in H/W intr */
 	u_int sc_rx_process_limit;	/* Rx proc. repeat limit in softint */
 	u_int sc_rx_intr_process_limit;	/* Rx proc. repeat limit in H/W intr */
+	struct workqueue *sc_queue_wq;
+	bool sc_txrx_use_workqueue;
 
 	int sc_affinity_offset;
 
@@ -567,6 +577,8 @@ struct wm_softc {
 	struct evcnt sc_ev_rx_macctl;	/* Rx Unsupported */
 #endif /* WM_EVENT_COUNTERS */
 
+	struct sysctllog *sc_sysctllog;
+
 	/* This variable are used only on the 82547. */
 	callout_t sc_txfifo_ch;		/* Tx FIFO stall work-around timer */
 
@@ -738,11 +750,12 @@ static void	wm_init_rss(struct wm_softc 
 static void	wm_adjust_qnum(struct wm_softc *, int);
 static inline bool	wm_is_using_msix(struct wm_softc *);
 static inline bool	wm_is_using_multiqueue(struct wm_softc *);
-static int	wm_softint_establish(struct wm_softc *, int, int);
+static int	wm_softhandler_establish(struct wm_softc *, int, int);
 static int	wm_setup_legacy(struct wm_softc *);
 static int	wm_setup_msix(struct wm_softc *);
 static int	wm_init(struct ifnet *);
 static int	wm_init_locked(struct ifnet *);
+static void	wm_init_sysctls(struct wm_softc *);
 static void	wm_unset_stopping_flags(struct wm_softc *);
 static void	wm_set_stopping_flags(struct wm_softc *);
 static void	wm_stop(struct ifnet *, int);
@@ -794,6 +807,7 @@ static void	wm_nq_send_common_locked(str
     bool);
 static void	wm_deferred_start_locked(struct wm_txqueue *);
 static void	wm_handle_queue(void *);
+static void	wm_handle_queue_work(struct work *, void *);
 /* Interrupt */
 static bool	wm_txeof(struct wm_txqueue *, u_int);
 static bool	wm_rxeof(struct wm_rxqueue *, u_int);
@@ -3026,6 +3040,10 @@ alloc_retry:
 	    NULL, xname, "rx_macctl");
 #endif /* WM_EVENT_COUNTERS */
 
+	sc->sc_txrx_use_workqueue = false;
+
+	wm_init_sysctls(sc);
+
 	if (pmf_device_register(self, wm_suspend, wm_resume))
 		pmf_class_network_register(self, ifp);
 	else
@@ -3052,6 +3070,8 @@ wm_detach(device_t self, int flags __unu
 
 	pmf_device_deregister(self);
 
+	sysctl_teardown(&sc->sc_sysctllog);
+
 #ifdef WM_EVENT_COUNTERS
 	evcnt_detach(&sc->sc_ev_linkintr);
 
@@ -5393,9 +5413,12 @@ wm_is_using_multiqueue(struct wm_softc *
 }
 
 static int
-wm_softint_establish(struct wm_softc *sc, int qidx, int intr_idx)
+wm_softhandler_establish(struct wm_softc *sc, int qidx, int intr_idx)
 {
+	char wqname[MAXCOMLEN];
 	struct wm_queue *wmq = &sc->sc_queue[qidx];
+	int error;
+
 	wmq->wmq_id = qidx;
 	wmq->wmq_intr_idx = intr_idx;
 	wmq->wmq_si = softint_establish(SOFTINT_NET
@@ -5403,12 +5426,28 @@ wm_softint_establish(struct wm_softc *sc
 	    | SOFTINT_MPSAFE
 #endif
 	    , wm_handle_queue, wmq);
-	if (wmq->wmq_si != NULL)
-		return 0;
+	if (wmq->wmq_si == NULL) {
+		aprint_error_dev(sc->sc_dev,
+		    "unable to establish queue[%d] softint handler\n",
+		    wmq->wmq_id);
+		goto err;
+	}
 
-	aprint_error_dev(sc->sc_dev, "unable to establish queue[%d] handler\n",
-	    wmq->wmq_id);
+	snprintf(wqname, sizeof(wqname), "%sTxRx", device_xname(sc->sc_dev));
+	error = workqueue_create(&sc->sc_queue_wq, wqname,
+	    wm_handle_queue_work, sc, WM_WORKQUEUE_PRI, IPL_NET,
+	    WM_WORKQUEUE_FLAGS);
+	if (error) {
+		softint_disestablish(wmq->wmq_si);
+		aprint_error_dev(sc->sc_dev,
+		    "unable to create queue[%d] workqueue\n",
+		    wmq->wmq_id);
+		goto err;
+	}
 
+	return 0;
+
+err:
 	pci_intr_disestablish(sc->sc_pc, sc->sc_ihs[wmq->wmq_intr_idx]);
 	sc->sc_ihs[wmq->wmq_intr_idx] = NULL;
 	return ENOMEM;
@@ -5448,7 +5487,7 @@ wm_setup_legacy(struct wm_softc *sc)
 	aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
 	sc->sc_nintrs = 1;
 
-	return wm_softint_establish(sc, 0, 0);
+	return wm_softhandler_establish(sc, 0, 0);
 }
 
 static int
@@ -5526,7 +5565,7 @@ wm_setup_msix(struct wm_softc *sc)
 			    "for TX and RX interrupting at %s\n", intrstr);
 		}
 		sc->sc_ihs[intr_idx] = vih;
-		if (wm_softint_establish(sc, qidx, intr_idx) != 0)
+		if (wm_softhandler_establish(sc, qidx, intr_idx) != 0)
 			goto fail;
 		txrx_established++;
 		intr_idx++;
@@ -5720,6 +5759,40 @@ out:
 #endif
 }
 
+static void
+wm_init_sysctls(struct wm_softc *sc)
+{
+	struct sysctllog **log;
+	const struct sysctlnode *rnode, *cnode;
+	int rv;
+	const char *dvname;
+
+	log = &sc->sc_sysctllog;
+	dvname = device_xname(sc->sc_dev);
+
+	rv = sysctl_createv(log, 0, NULL, &rnode,
+	    0, CTLTYPE_NODE, dvname,
+	    SYSCTL_DESCR("wm information and settings"),
+	    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
+	if (rv != 0)
+		goto err;
+
+	rv = sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_READWRITE,
+	    CTLTYPE_BOOL, "txrx_workqueue", SYSCTL_DESCR("Use workqueue for packet processing"),
+	    NULL, 0, &sc->sc_txrx_use_workqueue, 0, CTL_CREATE, CTL_EOL);
+	if (rv != 0)
+		goto teardown;
+
+	return;
+
+teardown:
+	sysctl_teardown(log);
+err:
+	sc->sc_sysctllog = NULL;
+	device_printf(sc->sc_dev, "%s: sysctl_createv failed, rv = %d\n",
+	    __func__, rv);
+}
+
 /*
  * wm_init:		[ifnet interface function]
  *
@@ -9435,6 +9508,17 @@ wm_linkintr(struct wm_softc *sc, uint32_
 		wm_linkintr_tbi(sc, icr);
 }
 
+
+static inline void
+wm_sched_handle_queue(struct wm_softc *sc, struct wm_queue *wmq)
+{
+
+	if (wmq->wmq_txrx_use_workqueue)
+		workqueue_enqueue(sc->sc_queue_wq, &wmq->wmq_cookie, curcpu());
+	else
+		softint_schedule(wmq->wmq_si);
+}
+
 /*
  * wm_intr_legacy:
  *
@@ -9536,7 +9620,8 @@ wm_intr_legacy(void *arg)
 
 	if (handled) {
 		/* Try to get more packets going. */
-		softint_schedule(wmq->wmq_si);
+		wmq->wmq_txrx_use_workqueue = sc->sc_txrx_use_workqueue;
+		wm_sched_handle_queue(sc, wmq);
 	}
 
 	return handled;
@@ -9639,9 +9724,10 @@ wm_txrxintr_msix(void *arg)
 	if (rndval != 0)
 		rnd_add_uint32(&sc->sc_queue[wmq->wmq_id].rnd_source, rndval);
 
-	if (txmore || rxmore)
-		softint_schedule(wmq->wmq_si);
-	else
+	if (txmore || rxmore) {
+		wmq->wmq_txrx_use_workqueue = sc->sc_txrx_use_workqueue;
+		wm_sched_handle_queue(sc, wmq);
+	} else
 		wm_txrxintr_enable(wmq);
 
 	return 1;
@@ -9677,12 +9763,24 @@ wm_handle_queue(void *arg)
 	rxmore = wm_rxeof(rxq, rxlimit);
 	mutex_exit(rxq->rxq_lock);
 
-	if (txmore || rxmore)
-		softint_schedule(wmq->wmq_si);
-	else
+	if (txmore || rxmore) {
+		wmq->wmq_txrx_use_workqueue = sc->sc_txrx_use_workqueue;
+		wm_sched_handle_queue(sc, wmq);
+	} else
 		wm_txrxintr_enable(wmq);
 }
 
+static void
+wm_handle_queue_work(struct work *wk, void *context)
+{
+	struct wm_queue *wmq = container_of(wk, struct wm_queue, wmq_cookie);
+
+	/*
+	 * "enqueued flag" is not required here.
+	 */
+	wm_handle_queue(wmq);
+}
+
 /*
  * wm_linkintr_msix:
  *

Reply via email to