Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/pci Add MSI/MSI-X support written by Kengo Nakahara....
details: https://anonhg.NetBSD.org/src/rev/834d30e92b83
branches: trunk
changeset: 338873:834d30e92b83
user: msaitoh <msaitoh%NetBSD.org@localhost>
date: Sat Jun 13 15:47:58 2015 +0000
description:
Add MSI/MSI-X support written by Kengo Nakahara. Some old devices' support
is written by me. It's disabled by default. If you'd like to use, define
WM_MSI_MSIX.
Tested with:
8254[3405617] (INTx even if it has MSI CAP because of a errata)
8257[12], 82583 ICH8, ICH10, PCH2, PCH_LPT(I21[78]) (MSI)
8257[456], 82580, I35[04], I21[01] (MSI-X)
Not tested:
82542, 82573, 80003, ICH9, PCH,
diffstat:
sys/dev/pci/if_wm.c | 579 +++++++++++++++++++++++++++++++++++++++++++++---
sys/dev/pci/if_wmreg.h | 46 +++-
2 files changed, 588 insertions(+), 37 deletions(-)
diffs (truncated from 933 to 300 lines):
diff -r 5c9e619e44f4 -r 834d30e92b83 sys/dev/pci/if_wm.c
--- a/sys/dev/pci/if_wm.c Sat Jun 13 14:56:45 2015 +0000
+++ b/sys/dev/pci/if_wm.c Sat Jun 13 15:47:58 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_wm.c,v 1.334 2015/06/12 04:40:28 msaitoh Exp $ */
+/* $NetBSD: if_wm.c,v 1.335 2015/06/13 15:47:58 msaitoh Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -81,7 +81,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.334 2015/06/12 04:40:28 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.335 2015/06/13 15:47:58 msaitoh Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@@ -154,6 +154,31 @@
#define WM_MPSAFE 1
#endif
+#ifdef __HAVE_PCI_MSI_MSIX
+#if 0 /* off by default */
+#define WM_MSI_MSIX 1
+#endif
+#endif
+
+/*
+ * This device driver divides interrupt to TX, RX and link state.
+ * Each MSI-X vector indexes are below.
+ */
+#define WM_NINTR 3
+#define WM_TX_INTR_INDEX 0
+#define WM_RX_INTR_INDEX 1
+#define WM_LINK_INTR_INDEX 2
+#define WM_MAX_NINTR WM_NINTR
+
+/*
+ * This device driver set affinity to each interrupts like below (round-robin).
+ * If the number CPUs is less than the number of interrupts, this driver usase
+ * the same CPU for multiple interrupts.
+ */
+#define WM_TX_INTR_CPUID 0
+#define WM_RX_INTR_CPUID 1
+#define WM_LINK_INTR_CPUID 2
+
/*
* Transmit descriptor list size. Due to errata, we can only have
* 256 hardware descriptors in the ring on < 82544, but we use 4096
@@ -295,7 +320,13 @@
int sc_flowflags; /* 802.3x flow control flags */
int sc_align_tweak;
- void *sc_ih; /* interrupt cookie */
+ void *sc_ihs[WM_MAX_NINTR]; /*
+ * interrupt cookie.
+ * legacy and msi use sc_ihs[0].
+ */
+ pci_intr_handle_t *sc_intrs; /* legacy and msi use sc_intrs[0] */
+ int sc_nintrs; /* number of interrupts */
+
callout_t sc_tick_ch; /* tick callout */
bool sc_stopping;
@@ -593,13 +624,18 @@
static void wm_nq_start(struct ifnet *);
static void wm_nq_start_locked(struct ifnet *);
/* Interrupt */
-static void wm_txintr(struct wm_softc *);
-static void wm_rxintr(struct wm_softc *);
+static int wm_txeof(struct wm_softc *);
+static void wm_rxeof(struct wm_softc *);
static void wm_linkintr_gmii(struct wm_softc *, uint32_t);
static void wm_linkintr_tbi(struct wm_softc *, uint32_t);
static void wm_linkintr_serdes(struct wm_softc *, uint32_t);
static void wm_linkintr(struct wm_softc *, uint32_t);
-static int wm_intr(void *);
+static int wm_intr_legacy(void *);
+#ifdef WM_MSI_MSIX
+static int wm_txintr_msix(void *);
+static int wm_rxintr_msix(void *);
+static int wm_linkintr_msix(void *);
+#endif
/*
* Media related.
@@ -1368,7 +1404,11 @@
prop_dictionary_t dict;
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
pci_chipset_tag_t pc = pa->pa_pc;
+#ifndef WM_MSI_MSIX
pci_intr_handle_t ih;
+#else
+ bool intr_established = false;
+#endif
const char *intrstr = NULL;
const char *eetype, *xname;
bus_space_tag_t memt;
@@ -1424,6 +1464,19 @@
sc->sc_type = WM_T_82542_2_0;
}
+ /*
+ * Disable MSI for Errata:
+ * "Message Signaled Interrupt Feature May Corrupt Write Transactions"
+ *
+ * 82544: Errata 25
+ * 82540: Errata 6 (easy to reproduce device timeout)
+ * 82545: Errata 4 (easy to reproduce device timeout)
+ * 82546: Errata 26 (easy to reproduce device timeout)
+ * 82541: Errata 7 (easy to reproduce device timeout)
+ */
+ if (sc->sc_type <= WM_T_82541_2)
+ pa->pa_flags &= ~PCI_FLAGS_MSI_OKAY;
+
if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)
|| (sc->sc_type == WM_T_82580)
|| (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354)
@@ -1517,6 +1570,7 @@
return;
}
+#ifndef WM_MSI_MSIX
/*
* Map and establish our interrupt.
*/
@@ -1528,8 +1582,8 @@
#ifdef WM_MPSAFE
pci_intr_setattr(pc, &ih, PCI_INTR_MPSAFE, true);
#endif
- sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, wm_intr, sc);
- if (sc->sc_ih == NULL) {
+ sc->sc_ihs[0] = pci_intr_establish(pc, ih, IPL_NET, wm_intr_legacy,sc);
+ if (sc->sc_ihs[0] == NULL) {
aprint_error_dev(sc->sc_dev, "unable to establish interrupt");
if (intrstr != NULL)
aprint_error(" at %s", intrstr);
@@ -1537,6 +1591,171 @@
return;
}
aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
+ sc->sc_nintrs = 1;
+#else /* WM_MSI_MSIX */
+ if (pci_msix_alloc_exact(pa, &sc->sc_intrs, WM_NINTR) == 0) {
+ /* 1st, try to use MSI-X */
+ void *vih;
+ kcpuset_t *affinity;
+
+ kcpuset_create(&affinity, false);
+
+ /*
+ * for TX
+ */
+ intrstr = pci_intr_string(pc, sc->sc_intrs[WM_TX_INTR_INDEX],
+ intrbuf, sizeof(intrbuf));
+#ifdef WM_MPSAFE
+ pci_intr_setattr(pc, &sc->sc_intrs[WM_TX_INTR_INDEX],
+ PCI_INTR_MPSAFE, true);
+#endif
+ vih = pci_intr_establish(pc, sc->sc_intrs[WM_TX_INTR_INDEX],
+ IPL_NET, wm_txintr_msix, sc);
+ if (vih == NULL) {
+ aprint_error_dev(sc->sc_dev,
+ "unable to establish MSI-X(for TX)%s%s\n",
+ intrstr ? " at " : "", intrstr ? intrstr : "");
+ pci_intr_release(sc->sc_pc, sc->sc_intrs,
+ WM_NINTR);
+ goto msi;
+ }
+ kcpuset_zero(affinity);
+ /* Round-robin affinity */
+ kcpuset_set(affinity, WM_TX_INTR_CPUID % ncpu);
+ error = pci_intr_distribute(vih, affinity, NULL);
+ if (error == 0) {
+ aprint_normal_dev(sc->sc_dev,
+ "for TX interrupting at %s affinity to %u\n",
+ intrstr, WM_TX_INTR_CPUID % ncpu);
+ } else {
+ aprint_normal_dev(sc->sc_dev,
+ "for TX interrupting at %s\n",
+ intrstr);
+ }
+ sc->sc_ihs[WM_TX_INTR_INDEX] = vih;
+
+ /*
+ * for RX
+ */
+ intrstr = pci_intr_string(pc, sc->sc_intrs[WM_RX_INTR_INDEX],
+ intrbuf, sizeof(intrbuf));
+#ifdef WM_MPSAFE
+ pci_intr_setattr(pc, &sc->sc_intrs[WM_RX_INTR_INDEX],
+ PCI_INTR_MPSAFE, true);
+#endif
+ vih = pci_intr_establish(pc, sc->sc_intrs[WM_RX_INTR_INDEX],
+ IPL_NET, wm_rxintr_msix, sc);
+ if (vih == NULL) {
+ aprint_error_dev(sc->sc_dev,
+ "unable to establish MSI-X(for RX)%s%s\n",
+ intrstr ? " at " : "", intrstr ? intrstr : "");
+ pci_intr_release(sc->sc_pc, sc->sc_intrs,
+ WM_NINTR);
+ goto msi;
+ }
+ kcpuset_zero(affinity);
+ kcpuset_set(affinity, WM_RX_INTR_CPUID % ncpu);
+ error = pci_intr_distribute(vih, affinity, NULL);
+ if (error == 0) {
+ aprint_normal_dev(sc->sc_dev,
+ "for RX interrupting at %s affinity to %u\n",
+ intrstr, WM_RX_INTR_CPUID % ncpu);
+ } else {
+ aprint_normal_dev(sc->sc_dev,
+ "for RX interrupting at %s\n",
+ intrstr);
+ }
+ sc->sc_ihs[WM_RX_INTR_INDEX] = vih;
+
+ /*
+ * for link state changing
+ */
+ intrstr = pci_intr_string(pc, sc->sc_intrs[WM_LINK_INTR_INDEX],
+ intrbuf, sizeof(intrbuf));
+#ifdef WM_MPSAFE
+ pci_intr_setattr(pc, &sc->sc_intrs[WM_LINK_INTR_INDEX],
+ PCI_INTR_MPSAFE, true);
+#endif
+ vih = pci_intr_establish(pc, sc->sc_intrs[WM_LINK_INTR_INDEX],
+ IPL_NET, wm_linkintr_msix, sc);
+ if (vih == NULL) {
+ aprint_error_dev(sc->sc_dev,
+ "unable to establish MSI-X(for LINK)%s%s\n",
+ intrstr ? " at " : "", intrstr ? intrstr : "");
+ pci_intr_release(sc->sc_pc, sc->sc_intrs,
+ WM_NINTR);
+ goto msi;
+ }
+ kcpuset_zero(affinity);
+ kcpuset_set(affinity, WM_LINK_INTR_CPUID % ncpu);
+ error = pci_intr_distribute(vih, affinity, NULL);
+ if (error == 0) {
+ aprint_normal_dev(sc->sc_dev,
+ "for LINK interrupting at %s affinity to %u\n",
+ intrstr, WM_LINK_INTR_CPUID % ncpu);
+ } else {
+ aprint_normal_dev(sc->sc_dev,
+ "for LINK interrupting at %s\n",
+ intrstr);
+ }
+ sc->sc_ihs[WM_LINK_INTR_INDEX] = vih;
+
+ sc->sc_nintrs = WM_NINTR;
+ kcpuset_destroy(affinity);
+ intr_established = true;
+ }
+
+msi:
+ if ((intr_established == false)
+ && (pci_msi_alloc_exact(pa, &sc->sc_intrs, 1) == 0)) {
+ /* 2nd, try to use MSI */
+ intrstr = pci_intr_string(pc, sc->sc_intrs[0], intrbuf,
+ sizeof(intrbuf));
+#ifdef WM_MPSAFE
+ pci_intr_setattr(pc, &sc->sc_intrs[0], PCI_INTR_MPSAFE, true);
+#endif
+ sc->sc_ihs[0] = pci_intr_establish(pc, sc->sc_intrs[0],
+ IPL_NET, wm_intr_legacy, sc);
+ if (sc->sc_ihs[0] == NULL) {
+ aprint_error_dev(sc->sc_dev, "unable to establish MSI\n");
+ pci_intr_release(sc->sc_pc, sc->sc_intrs,
+ 1);
+ goto intx;
+ }
+ aprint_normal_dev(sc->sc_dev, "MSI at %s\n", intrstr);
+
+ sc->sc_nintrs = 1;
+ intr_established = true;
+ }
+
+intx:
+ if ((intr_established == false)
+ && (pci_intx_alloc(pa, &sc->sc_intrs) == 0)) {
+ /* Last, try to use INTx */
+ intrstr = pci_intr_string(pc, sc->sc_intrs[0], intrbuf,
+ sizeof(intrbuf));
+#ifdef WM_MPSAFE
+ pci_intr_setattr(pc, &sc->sc_intrs[0], PCI_INTR_MPSAFE, true);
+#endif
+ sc->sc_ihs[0] = pci_intr_establish(pc, sc->sc_intrs[0],
+ IPL_NET, wm_intr_legacy, sc);
+ if (sc->sc_ihs[0] == NULL) {
+ aprint_error_dev(sc->sc_dev, "unable to establish MSI\n");
+ pci_intr_release(sc->sc_pc, sc->sc_intrs, 1);
+ goto int_failed;
+ }
+ aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
+
+ sc->sc_nintrs = 1;
+ intr_established = true;
+ }
Home |
Main Index |
Thread Index |
Old Index