Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/dev/pci/if_wm.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/dev/pci/if_wm.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.661 retrieving revision 1.662 diff -u -p -r1.661 -r1.662 --- src/sys/dev/pci/if_wm.c 2020/01/23 07:49:57 1.661 +++ src/sys/dev/pci/if_wm.c 2020/01/24 02:50:41 1.662 @@ -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 -__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 #include #include +#include +#include #include @@ -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: *