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(4) can use workqueue as deferred Rx/Tx handle...



details:   https://anonhg.NetBSD.org/src/rev/d3e946264ce9
branches:  trunk
changeset: 848298:d3e946264ce9
user:      knakahara <knakahara%NetBSD.org@localhost>
date:      Fri Jan 24 02:50:41 2020 +0000

description:
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 msaitoh@n.o.

diffstat:

 sys/dev/pci/if_wm.c |  138 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 118 insertions(+), 20 deletions(-)

diffs (290 lines):

diff -r 6803fd84b8de -r d3e946264ce9 sys/dev/pci/if_wm.c
--- a/sys/dev/pci/if_wm.c       Thu Jan 23 23:59:53 2020 +0000
+++ b/sys/dev/pci/if_wm.c       Fri Jan 24 02:50:41 2020 +0000
@@ -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 @@
 #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 @@
 #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_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 @@
        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 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_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 @@
     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 @@
            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 @@
 
        pmf_device_deregister(self);
 
+       sysctl_teardown(&sc->sc_sysctllog);
+
 #ifdef WM_EVENT_COUNTERS
        evcnt_detach(&sc->sc_ev_linkintr);
 
@@ -5393,9 +5413,12 @@
 }
 
 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 @@
            | SOFTINT_MPSAFE
 #endif
            , wm_handle_queue, wmq);
-       if (wmq->wmq_si != NULL)
-               return 0;
-
-       aprint_error_dev(sc->sc_dev, "unable to establish queue[%d] handler\n",
-           wmq->wmq_id);
-
+       if (wmq->wmq_si == NULL) {
+               aprint_error_dev(sc->sc_dev,
+                   "unable to establish queue[%d] softint handler\n",
+                   wmq->wmq_id);
+               goto err;
+       }
+
+       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 @@
        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 @@
                            "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 @@
 #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_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 @@
 
        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 @@
        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 @@
        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:
  *



Home | Main Index | Thread Index | Old Index