Module Name: src
Committed By: knakahara
Date: Fri Jan 26 16:25:28 UTC 2018
Modified Files:
src/sys/dev/pci: if_wm.c
Log Message:
Fix 82574 MSI-X mode cannot receive packets after 82574 receives high rate
traffic.
In short, 82574 MSI-X mode does not cause RXQ MSI-X vector when 82574's
phys FIFO overflows. I don't know why but 82574 causes not RXQ MSI-X vector
but OTHER MSI-X vector at the situation.
see:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?h=v4.15-rc9&id=4aea7a5c5e940c1723add439f4088844cd26196d
advised by [email protected], thanks.
To generate a diff of this commit:
cvs rdiff -u -r1.558 -r1.559 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.558 src/sys/dev/pci/if_wm.c:1.559
--- src/sys/dev/pci/if_wm.c:1.558 Sun Jan 21 04:07:49 2018
+++ src/sys/dev/pci/if_wm.c Fri Jan 26 16:25:28 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wm.c,v 1.558 2018/01/21 04:07:49 christos Exp $ */
+/* $NetBSD: if_wm.c,v 1.559 2018/01/26 16:25:28 knakahara Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -83,7 +83,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.558 2018/01/21 04:07:49 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.559 2018/01/26 16:25:28 knakahara Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@@ -8962,8 +8962,14 @@ wm_txrxintr_enable(struct wm_queue *wmq)
wm_itrs_calculate(sc, wmq);
+ /*
+ * ICR_OTHER which is disabled in wm_linkintr_msix() is enabled here.
+ * There is no need to care about which of RXQ(0) and RXQ(1) enable
+ * ICR_OTHER in first, because each RXQ/TXQ interrupt is disabled
+ * while each wm_handle_queue(wmq) is runnig.
+ */
if (sc->sc_type == WM_T_82574)
- CSR_WRITE(sc, WMREG_IMS, ICR_TXQ(wmq->wmq_id) | ICR_RXQ(wmq->wmq_id));
+ CSR_WRITE(sc, WMREG_IMS, ICR_TXQ(wmq->wmq_id) | ICR_RXQ(wmq->wmq_id) | ICR_OTHER);
else if (sc->sc_type == WM_T_82575)
CSR_WRITE(sc, WMREG_EIMS, EITR_TX_QUEUE(wmq->wmq_id) | EITR_RX_QUEUE(wmq->wmq_id));
else
@@ -9060,24 +9066,59 @@ wm_linkintr_msix(void *arg)
{
struct wm_softc *sc = arg;
uint32_t reg;
+ bool has_rxo;
DPRINTF(WM_DEBUG_LINK,
("%s: LINK: got link intr\n", device_xname(sc->sc_dev)));
reg = CSR_READ(sc, WMREG_ICR);
WM_CORE_LOCK(sc);
- if ((sc->sc_core_stopping) || ((reg & ICR_LSC) == 0))
+ if (sc->sc_core_stopping)
goto out;
- WM_EVCNT_INCR(&sc->sc_ev_linkintr);
- wm_linkintr(sc, ICR_LSC);
+ if((reg & ICR_LSC) != 0) {
+ WM_EVCNT_INCR(&sc->sc_ev_linkintr);
+ wm_linkintr(sc, ICR_LSC);
+ }
+
+ /*
+ * XXX 82574 MSI-X mode workaround
+ *
+ * 82574 MSI-X mode causes receive overrun(RXO) interrupt as ICR_OTHER
+ * MSI-X vector, furthermore it does not cause neigher ICR_RXQ(0) nor
+ * ICR_RXQ(1) vector. So, we generate ICR_RXQ(0) and ICR_RXQ(1)
+ * interrupts by writing WMREG_ICS to process receive packets.
+ */
+ if (sc->sc_type == WM_T_82574 && ((reg & ICR_RXO) != 0)) {
+#if defined(WM_DEBUG)
+ log(LOG_WARNING, "%s: Receive overrun\n",
+ device_xname(sc->sc_dev));
+#endif /* defined(WM_DEBUG) */
+
+ has_rxo = true;
+ /*
+ * The RXO interrupt is very high rate when receive traffic is
+ * high rate. We use polling mode for ICR_OTHER like Tx/Rx
+ * interrupts. ICR_OTHER will be enabled at the end of
+ * wm_txrxintr_msix() which is kicked by both ICR_RXQ(0) and
+ * ICR_RXQ(1) interrupts.
+ */
+ CSR_WRITE(sc, WMREG_IMC, ICR_OTHER);
+
+ CSR_WRITE(sc, WMREG_ICS, ICR_RXQ(0) | ICR_RXQ(1));
+ }
+
+
out:
WM_CORE_UNLOCK(sc);
- if (sc->sc_type == WM_T_82574)
- CSR_WRITE(sc, WMREG_IMS, ICR_OTHER | ICR_LSC);
- else if (sc->sc_type == WM_T_82575)
+ if (sc->sc_type == WM_T_82574) {
+ if (!has_rxo)
+ CSR_WRITE(sc, WMREG_IMS, ICR_OTHER | ICR_LSC);
+ else
+ CSR_WRITE(sc, WMREG_IMS, ICR_LSC);
+ } else if (sc->sc_type == WM_T_82575)
CSR_WRITE(sc, WMREG_EIMS, EITR_OTHER);
else
CSR_WRITE(sc, WMREG_EIMS, 1 << sc->sc_link_intr_idx);