Module Name: src Committed By: knakahara Date: Mon Jul 29 10:24:18 UTC 2019
Modified Files: src/sys/arch/x86/pci: if_vmx.c Log Message: vmx(4) uses deferred interrupt handlering like ixg(4). To generate a diff of this commit: cvs rdiff -u -r1.42 -r1.43 src/sys/arch/x86/pci/if_vmx.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/arch/x86/pci/if_vmx.c diff -u src/sys/arch/x86/pci/if_vmx.c:1.42 src/sys/arch/x86/pci/if_vmx.c:1.43 --- src/sys/arch/x86/pci/if_vmx.c:1.42 Mon Jul 29 09:45:16 2019 +++ src/sys/arch/x86/pci/if_vmx.c Mon Jul 29 10:24:18 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_vmx.c,v 1.42 2019/07/29 09:45:16 knakahara Exp $ */ +/* $NetBSD: if_vmx.c,v 1.43 2019/07/29 10:24:18 knakahara Exp $ */ /* $OpenBSD: if_vmx.c,v 1.16 2014/01/22 06:04:17 brad Exp $ */ /* @@ -19,7 +19,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_vmx.c,v 1.42 2019/07/29 09:45:16 knakahara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_vmx.c,v 1.43 2019/07/29 10:24:18 knakahara Exp $"); #include <sys/param.h> #include <sys/cpu.h> @@ -83,6 +83,20 @@ __KERNEL_RCSID(0, "$NetBSD: if_vmx.c,v 1 #define VMXNET3_WATCHDOG_TIMEOUT 5 /* + * Default value for vmx_intr_{rx,tx}_process_limit which is used for + * max number of packets to process for interrupt handler + */ +#define VMXNET3_RX_INTR_PROCESS_LIMIT 0U +#define VMXNET3_TX_INTR_PROCESS_LIMIT 256 + +/* + * Default value for vmx_{rx,tx}_process_limit which is used for + * max number of packets to process for deferred processing + */ +#define VMXNET3_RX_PROCESS_LIMIT 256 +#define VMXNET3_TX_PROCESS_LIMIT 256 + +/* * IP protocols that we can perform Tx checksum offloading of. */ #define VMXNET3_CSUM_OFFLOAD \ @@ -209,6 +223,8 @@ struct vmxnet3_queue { struct vmxnet3_txqueue vxq_txqueue; struct vmxnet3_rxqueue vxq_rxqueue; + + void *vxq_si; }; struct vmxnet3_statistics { @@ -270,6 +286,11 @@ struct vmxnet3_softc { int vmx_max_ntxqueues; int vmx_max_nrxqueues; uint8_t vmx_lladdr[ETHER_ADDR_LEN]; + + u_int vmx_rx_intr_process_limit; + u_int vmx_tx_intr_process_limit; + u_int vmx_rx_process_limit; + u_int vmx_tx_process_limit; }; #define VMXNET3_STAT @@ -342,7 +363,7 @@ void vmxnet3_free_data(struct vmxnet3_so int vmxnet3_setup_interface(struct vmxnet3_softc *); void vmxnet3_evintr(struct vmxnet3_softc *); -void vmxnet3_txq_eof(struct vmxnet3_txqueue *); +bool vmxnet3_txq_eof(struct vmxnet3_txqueue *, u_int); int vmxnet3_newbuf(struct vmxnet3_softc *, struct vmxnet3_rxring *); void vmxnet3_rxq_eof_discard(struct vmxnet3_rxqueue *, struct vmxnet3_rxring *, int); @@ -350,9 +371,10 @@ void vmxnet3_rxq_discard_chain(struct vm void vmxnet3_rx_csum(struct vmxnet3_rxcompdesc *, struct mbuf *); void vmxnet3_rxq_input(struct vmxnet3_rxqueue *, struct vmxnet3_rxcompdesc *, struct mbuf *); -void vmxnet3_rxq_eof(struct vmxnet3_rxqueue *); +bool vmxnet3_rxq_eof(struct vmxnet3_rxqueue *, u_int); int vmxnet3_legacy_intr(void *); int vmxnet3_txrxq_intr(void *); +void vmxnet3_handle_queue(void *); int vmxnet3_event_intr(void *); void vmxnet3_txstop(struct vmxnet3_softc *, struct vmxnet3_txqueue *); @@ -819,6 +841,10 @@ vmxnet3_free_interrupts(struct vmxnet3_s int i; for (i = 0; i < sc->vmx_nintrs; i++) { + struct vmxnet3_queue *vmxq = &sc->vmx_queue[i]; + + softint_disestablish(vmxq->vxq_si); + vmxq->vxq_si = NULL; pci_intr_disestablish(pc, sc->vmx_ihs[i]); } pci_intr_release(pc, sc->vmx_intrs, sc->vmx_nintrs); @@ -859,6 +885,14 @@ vmxnet3_setup_msix_interrupts(struct vmx } aprint_normal_dev(sc->vmx_dev, "txrx interrupting at %s\n", intrstr); + vmxq->vxq_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, + vmxnet3_handle_queue, vmxq); + if (vmxq->vxq_si == NULL) { + aprint_error_dev(sc->vmx_dev, + "softint_establish for vxq_si failed\n"); + return (-1); + } + vmxq->vxq_intr_idx = intr_idx; } @@ -886,6 +920,7 @@ vmxnet3_setup_msi_interrupt(struct vmxne pci_chipset_tag_t pc = sc->vmx_pa->pa_pc; pci_intr_handle_t *intr; void **ihs; + struct vmxnet3_queue *vmxq; int i; const char *intrstr; char intrbuf[PCI_INTRSTR_LEN]; @@ -893,6 +928,7 @@ vmxnet3_setup_msi_interrupt(struct vmxne intr = &sc->vmx_intrs[0]; ihs = sc->vmx_ihs; + vmxq = &sc->vmx_queue[0]; intrstr = pci_intr_string(pc, *intr, intrbuf, sizeof(intrbuf)); @@ -907,6 +943,14 @@ vmxnet3_setup_msi_interrupt(struct vmxne } aprint_normal_dev(sc->vmx_dev, "interrupting at %s\n", intrstr); + vmxq->vxq_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, + vmxnet3_handle_queue, vmxq); + if (vmxq->vxq_si == NULL) { + aprint_error_dev(sc->vmx_dev, + "softint_establish for vxq_si failed\n"); + return (-1); + } + for (i = 0; i < MIN(sc->vmx_nrxqueues, sc->vmx_nrxqueues); i++) sc->vmx_queue[i].vxq_intr_idx = 0; sc->vmx_event_intr_idx = 0; @@ -920,6 +964,7 @@ vmxnet3_setup_legacy_interrupt(struct vm pci_chipset_tag_t pc = sc->vmx_pa->pa_pc; pci_intr_handle_t *intr; void **ihs; + struct vmxnet3_queue *vmxq; int i; const char *intrstr; char intrbuf[PCI_INTRSTR_LEN]; @@ -927,6 +972,7 @@ vmxnet3_setup_legacy_interrupt(struct vm intr = &sc->vmx_intrs[0]; ihs = sc->vmx_ihs; + vmxq = &sc->vmx_queue[0]; intrstr = pci_intr_string(pc, *intr, intrbuf, sizeof(intrbuf)); @@ -941,6 +987,14 @@ vmxnet3_setup_legacy_interrupt(struct vm } aprint_normal_dev(sc->vmx_dev, "interrupting at %s\n", intrstr); + vmxq->vxq_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, + vmxnet3_handle_queue, vmxq); + if (vmxq->vxq_si == NULL) { + aprint_error_dev(sc->vmx_dev, + "softint_establish for vxq_si failed\n"); + return (-1); + } + for (i = 0; i < MIN(sc->vmx_nrxqueues, sc->vmx_nrxqueues); i++) sc->vmx_queue[i].vxq_intr_idx = 0; sc->vmx_event_intr_idx = 0; @@ -1750,6 +1804,12 @@ vmxnet3_setup_interface(struct vmxnet3_s ether_set_ifflags_cb(&sc->vmx_ethercom, vmxnet3_ifflags_cb); vmxnet3_link_status(sc); + /* should set before setting interrupts */ + sc->vmx_rx_intr_process_limit = VMXNET3_RX_INTR_PROCESS_LIMIT; + sc->vmx_rx_process_limit = VMXNET3_RX_PROCESS_LIMIT; + sc->vmx_tx_intr_process_limit = VMXNET3_TX_INTR_PROCESS_LIMIT; + sc->vmx_tx_process_limit = VMXNET3_TX_PROCESS_LIMIT; + return (0); } @@ -1800,8 +1860,8 @@ vmxnet3_evintr(struct vmxnet3_softc *sc) VMXNET3_CORE_UNLOCK(sc); } -void -vmxnet3_txq_eof(struct vmxnet3_txqueue *txq) +bool +vmxnet3_txq_eof(struct vmxnet3_txqueue *txq, u_int limit) { struct vmxnet3_softc *sc; struct vmxnet3_txring *txr; @@ -1810,6 +1870,7 @@ vmxnet3_txq_eof(struct vmxnet3_txqueue * struct vmxnet3_txbuf *txb; struct mbuf *m; u_int sop; + bool more = false; sc = txq->vxtxq_sc; txr = &txq->vxtxq_cmd_ring; @@ -1818,6 +1879,11 @@ vmxnet3_txq_eof(struct vmxnet3_txqueue * VMXNET3_TXQ_LOCK_ASSERT(txq); for (;;) { + if (limit-- == 0) { + more = true; + break; + } + txcd = &txc->vxcr_u.txcd[txc->vxcr_next]; if (txcd->gen != txc->vxcr_gen) break; @@ -1851,6 +1917,8 @@ vmxnet3_txq_eof(struct vmxnet3_txqueue * if (txr->vxtxr_head == txr->vxtxr_next) txq->vxtxq_watchdog = 0; + + return more; } int @@ -2018,8 +2086,8 @@ vmxnet3_rxq_input(struct vmxnet3_rxqueue if_percpuq_enqueue(ifp->if_percpuq, m); } -void -vmxnet3_rxq_eof(struct vmxnet3_rxqueue *rxq) +bool +vmxnet3_rxq_eof(struct vmxnet3_rxqueue *rxq, u_int limit) { struct vmxnet3_softc *sc; struct ifnet *ifp; @@ -2029,6 +2097,7 @@ vmxnet3_rxq_eof(struct vmxnet3_rxqueue * struct vmxnet3_rxcompdesc *rxcd; struct mbuf *m, *m_head, *m_tail; int idx, length; + bool more = false; sc = rxq->vxrxq_sc; ifp = &sc->vmx_ethercom.ec_if; @@ -2037,7 +2106,7 @@ vmxnet3_rxq_eof(struct vmxnet3_rxqueue * VMXNET3_RXQ_LOCK_ASSERT(rxq); if ((ifp->if_flags & IFF_RUNNING) == 0) - return; + return more; m_head = rxq->vxrxq_mhead; rxq->vxrxq_mhead = NULL; @@ -2046,6 +2115,11 @@ vmxnet3_rxq_eof(struct vmxnet3_rxqueue * KASSERT(m_head == NULL || m_tail != NULL); for (;;) { + if (limit-- == 0) { + more = true; + break; + } + rxcd = &rxc->vxcr_u.rxcd[rxc->vxcr_next]; if (rxcd->gen != rxc->vxcr_gen) { rxq->vxrxq_mhead = m_head; @@ -2155,6 +2229,8 @@ nextp: vmxnet3_write_bar0(sc, r, idx); } } + + return more; } int @@ -2163,10 +2239,14 @@ vmxnet3_legacy_intr(void *xsc) struct vmxnet3_softc *sc; struct vmxnet3_rxqueue *rxq; struct vmxnet3_txqueue *txq; + u_int txlimit, rxlimit; + bool txmore, rxmore; sc = xsc; rxq = &sc->vmx_queue[0].vxq_rxqueue; txq = &sc->vmx_queue[0].vxq_txqueue; + txlimit = sc->vmx_tx_intr_process_limit; + rxlimit = sc->vmx_rx_intr_process_limit; if (sc->vmx_intr_type == VMXNET3_IT_LEGACY) { if (vmxnet3_read_bar1(sc, VMXNET3_BAR1_INTR) == 0) @@ -2179,16 +2259,19 @@ vmxnet3_legacy_intr(void *xsc) vmxnet3_evintr(sc); VMXNET3_RXQ_LOCK(rxq); - vmxnet3_rxq_eof(rxq); + rxmore = vmxnet3_rxq_eof(rxq, txlimit); VMXNET3_RXQ_UNLOCK(rxq); VMXNET3_TXQ_LOCK(txq); - vmxnet3_txq_eof(txq); - if_schedule_deferred_start(&sc->vmx_ethercom.ec_if); + txmore = vmxnet3_txq_eof(txq, rxlimit); VMXNET3_TXQ_UNLOCK(txq); - vmxnet3_enable_all_intrs(sc); - + if (txmore || rxmore) { + softint_schedule(sc->vmx_queue[0].vxq_si); + } else { + if_schedule_deferred_start(&sc->vmx_ethercom.ec_if); + vmxnet3_enable_all_intrs(sc); + } return (1); } @@ -2199,17 +2282,60 @@ vmxnet3_txrxq_intr(void *xvmxq) struct vmxnet3_queue *vmxq; struct vmxnet3_txqueue *txq; struct vmxnet3_rxqueue *rxq; + u_int txlimit, rxlimit; + bool txmore, rxmore; vmxq = xvmxq; txq = &vmxq->vxq_txqueue; rxq = &vmxq->vxq_rxqueue; sc = txq->vxtxq_sc; + txlimit = sc->vmx_tx_intr_process_limit; + rxlimit = sc->vmx_rx_intr_process_limit; if (sc->vmx_intr_mask_mode == VMXNET3_IMM_ACTIVE) vmxnet3_disable_intr(sc, vmxq->vxq_intr_idx); VMXNET3_TXQ_LOCK(txq); - vmxnet3_txq_eof(txq); + txmore = vmxnet3_txq_eof(txq, txlimit); + VMXNET3_TXQ_UNLOCK(txq); + + VMXNET3_RXQ_LOCK(rxq); + rxmore = vmxnet3_rxq_eof(rxq, rxlimit); + VMXNET3_RXQ_UNLOCK(rxq); + + if (txmore || rxmore) { + softint_schedule(vmxq->vxq_si); + } else { + /* for ALTQ */ + if (vmxq->vxq_id == 0) + if_schedule_deferred_start(&sc->vmx_ethercom.ec_if); + softint_schedule(txq->vxtxq_si); + + vmxnet3_enable_intr(sc, vmxq->vxq_intr_idx); + } + + return (1); +} + +void +vmxnet3_handle_queue(void *xvmxq) +{ + struct vmxnet3_softc *sc; + struct vmxnet3_queue *vmxq; + struct vmxnet3_txqueue *txq; + struct vmxnet3_rxqueue *rxq; + u_int txlimit, rxlimit; + bool txmore, rxmore; + + vmxq = xvmxq; + txq = &vmxq->vxq_txqueue; + rxq = &vmxq->vxq_rxqueue; + sc = txq->vxtxq_sc; + txlimit = sc->vmx_tx_process_limit; + rxlimit = sc->vmx_rx_process_limit; + + VMXNET3_TXQ_LOCK(txq); + txmore = vmxnet3_txq_eof(txq, txlimit); /* for ALTQ */ if (vmxq->vxq_id == 0) if_schedule_deferred_start(&sc->vmx_ethercom.ec_if); @@ -2217,12 +2343,13 @@ vmxnet3_txrxq_intr(void *xvmxq) VMXNET3_TXQ_UNLOCK(txq); VMXNET3_RXQ_LOCK(rxq); - vmxnet3_rxq_eof(rxq); + rxmore = vmxnet3_rxq_eof(rxq, rxlimit); VMXNET3_RXQ_UNLOCK(rxq); - vmxnet3_enable_intr(sc, vmxq->vxq_intr_idx); - - return (1); + if (txmore || rxmore) + softint_schedule(vmxq->vxq_si); + else + vmxnet3_enable_intr(sc, vmxq->vxq_intr_idx); } int