Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci/ixgbe - Add MSI/MSI-X support. The multiqueue fu...



details:   https://anonhg.NetBSD.org/src/rev/ed363cf56009
branches:  trunk
changeset: 339840:ed363cf56009
user:      msaitoh <msaitoh%NetBSD.org@localhost>
date:      Thu Aug 13 04:56:43 2015 +0000

description:
- Add MSI/MSI-X support. The multiqueue function is not supported yet.
 - Make ixv.c compilable. _NOT_TESTED_YET_

diffstat:

 sys/dev/pci/ixgbe/ixgbe.c       |  344 ++++++++++++++++++++-------------------
 sys/dev/pci/ixgbe/ixgbe_82599.c |    6 +-
 sys/dev/pci/ixgbe/ixgbe_osdep.h |   29 ++-
 sys/dev/pci/ixgbe/ixgbe_type.h  |    9 +-
 sys/dev/pci/ixgbe/ixv.c         |  244 +++++++++++++---------------
 5 files changed, 326 insertions(+), 306 deletions(-)

diffs (truncated from 1100 to 300 lines):

diff -r 12f1890a1211 -r ed363cf56009 sys/dev/pci/ixgbe/ixgbe.c
--- a/sys/dev/pci/ixgbe/ixgbe.c Thu Aug 13 04:52:40 2015 +0000
+++ b/sys/dev/pci/ixgbe/ixgbe.c Thu Aug 13 04:56:43 2015 +0000
@@ -59,7 +59,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 /*$FreeBSD: head/sys/dev/ixgbe/ixgbe.c 279805 2015-03-09 10:29:15Z araujo $*/
-/*$NetBSD: ixgbe.c,v 1.33 2015/08/05 04:08:44 msaitoh Exp $*/
+/*$NetBSD: ixgbe.c,v 1.34 2015/08/13 04:56:43 msaitoh Exp $*/
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
@@ -232,8 +232,8 @@
 
 #if defined(NETBSD_MSI_OR_MSIX)
 /* The MSI/X Interrupt handlers */
-static void    ixgbe_msix_que(void *);
-static void    ixgbe_msix_link(void *);
+static int     ixgbe_msix_que(void *);
+static int     ixgbe_msix_link(void *);
 #endif
 
 /* Software interrupts for deferred work */
@@ -317,7 +317,7 @@
  * number of cpus with a max of 8. This
  * can be overriden manually here.
  */
-static int ixgbe_num_queues = 0;
+static int ixgbe_num_queues = 1;
 SYSCTL_INT("hw.ixgbe.num_queues", &ixgbe_num_queues);
 #endif
 
@@ -508,7 +508,7 @@
 {
        struct adapter *adapter;
        struct ixgbe_hw *hw;
-       int             error = 0;
+       int             error = -1;
        u16             csum;
        u32             ctrl_ext;
        ixgbe_vendor_info_t *ent;
@@ -608,7 +608,8 @@
                */
                adapter->sfp_probe = TRUE;
                error = 0;
-       } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+       } else if ((error == IXGBE_ERR_SFP_NOT_SUPPORTED)
+           && (hw->allow_unsupported_sfp == false)) {
                aprint_error_dev(dev,"Unsupported SFP+ module detected!\n");
                error = EIO;
                goto err_late;
@@ -649,10 +650,11 @@
        /* Detect and set physical type */
        ixgbe_setup_optics(adapter);
 
+       error = -1;
        if ((adapter->msix > 1) && (ixgbe_enable_msix))
-               error = ixgbe_allocate_msix(adapter, pa); 
-       else
-               error = ixgbe_allocate_legacy(adapter, pa); 
+               error = ixgbe_allocate_msix(adapter, pa);
+       if (error != 0)
+               error = ixgbe_allocate_legacy(adapter, pa);
        if (error) 
                goto err_late;
 
@@ -1692,7 +1694,7 @@
  *  MSIX Queue Interrupt Service routine
  *
  **********************************************************************/
-void
+static int
 ixgbe_msix_que(void *arg)
 {
        struct ix_queue *que = arg;
@@ -1705,7 +1707,7 @@
 
        /* Protect against spurious interrupts */
        if ((ifp->if_flags & IFF_RUNNING) == 0)
-               return;
+               return 0;
 
        ixgbe_disable_queue(adapter, que->msix);
        ++que->irqs;
@@ -1716,6 +1718,7 @@
        ixgbe_txeof(txr);
 #ifdef IXGBE_LEGACY_TX
        if (!IFQ_IS_EMPTY(&adapter->ifp->if_snd))
+               ixgbe_start_locked(txr, ifp);
 #else
        if (!drbr_empty(ifp, txr->br))
                ixgbe_mq_start_locked(ifp, txr);
@@ -1777,11 +1780,11 @@
                softint_schedule(que->que_si);
        else
                ixgbe_enable_queue(adapter, que->msix);
-       return;
+       return 1;
 }
 
 
-static void
+static int
 ixgbe_msix_link(void *arg)
 {
        struct adapter  *adapter = arg;
@@ -1806,7 +1809,7 @@
                if (reg_eicr & IXGBE_EICR_FLOW_DIR) {
                        /* This is probably overkill :) */
                        if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1))
-                               return;
+                               return 1;
                        /* Disable the interrupt */
                        IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR);
                        softint_schedule(adapter->fdir_si);
@@ -1847,7 +1850,7 @@
        }
 
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
-       return;
+       return 1;
 }
 #endif
 
@@ -2477,32 +2480,79 @@
  *
  **********************************************************************/
 static int
-ixgbe_allocate_legacy(struct adapter *adapter, const struct pci_attach_args *pa)
+ixgbe_allocate_legacy(struct adapter *adapter,
+    const struct pci_attach_args *pa)
 {
        device_t        dev = adapter->dev;
        struct          ix_queue *que = adapter->queues;
 #ifndef IXGBE_LEGACY_TX
        struct tx_ring          *txr = adapter->tx_rings;
 #endif
+#ifndef NETBSD_MSI_OR_MSIX
+       pci_intr_handle_t       ih;
+#else
+       int             counts[PCI_INTR_TYPE_SIZE];
+       pci_intr_type_t intr_type, max_type;
+#endif
        char intrbuf[PCI_INTRSTR_LEN];
-#if 0
-       int             rid = 0;
-
-       /* MSI RID at 1 */
-       if (adapter->msix == 1)
-               rid = 1;
-#endif
+       const char      *intrstr = NULL;
  
+#ifndef NETBSD_MSI_OR_MSIX
        /* We allocate a single interrupt resource */
-       if (pci_intr_map(pa, &adapter->osdep.ih) != 0) {
+       if (pci_intr_map(pa, &ih) != 0) {
                aprint_error_dev(dev, "unable to map interrupt\n");
                return ENXIO;
        } else {
-               aprint_normal_dev(dev, "interrupting at %s\n",
-                   pci_intr_string(adapter->osdep.pc, adapter->osdep.ih,
-                       intrbuf, sizeof(intrbuf)));
-       }
-
+               intrstr = pci_intr_string(adapter->osdep.pc, ih, intrbuf,
+                   sizeof(intrbuf));
+       }
+       adapter->osdep.ihs[0] = pci_intr_establish(adapter->osdep.pc, ih,
+           IPL_NET, ixgbe_legacy_irq, que);
+#else
+       /* Allocation settings */
+       max_type = PCI_INTR_TYPE_MSI;
+       counts[PCI_INTR_TYPE_MSIX] = 0;
+       counts[PCI_INTR_TYPE_MSI] = 1;
+       counts[PCI_INTR_TYPE_INTX] = 1;
+
+alloc_retry:
+       if (pci_intr_alloc(pa, &adapter->osdep.intrs, counts, max_type) != 0) {
+               aprint_error_dev(dev, "couldn't alloc interrupt\n");
+               return ENXIO;
+       }
+       adapter->osdep.nintrs = 1;
+       intrstr = pci_intr_string(adapter->osdep.pc, adapter->osdep.intrs[0],
+           intrbuf, sizeof(intrbuf));
+       adapter->osdep.ihs[0] = pci_intr_establish(adapter->osdep.pc,
+           adapter->osdep.intrs[0], IPL_NET, ixgbe_legacy_irq, que);
+       if (adapter->osdep.ihs[0] == NULL) {
+               intr_type = pci_intr_type(adapter->osdep.intrs[0]);
+               aprint_error_dev(dev,"unable to establish %s\n",
+                   (intr_type == PCI_INTR_TYPE_MSI) ? "MSI" : "INTx");
+               pci_intr_release(adapter->osdep.pc, adapter->osdep.intrs, 1);
+               switch (intr_type) {
+               case PCI_INTR_TYPE_MSI:
+                       /* The next try is for INTx: Disable MSI */
+                       max_type = PCI_INTR_TYPE_INTX;
+                       counts[PCI_INTR_TYPE_INTX] = 1;
+                       goto alloc_retry;
+               case PCI_INTR_TYPE_INTX:
+               default:
+                       /* See below */
+                       break;
+               }
+       }
+#endif
+       if (adapter->osdep.ihs[0] == NULL) {
+               aprint_error_dev(dev,
+                   "couldn't establish interrupt%s%s\n",
+                   intrstr ? " at " : "", intrstr ? intrstr : "");
+#ifdef NETBSD_MSI_OR_MSIX
+               pci_intr_release(adapter->osdep.pc, adapter->osdep.intrs, 1);
+#endif
+               return ENXIO;
+       }
+       aprint_normal_dev(dev, "interrupting at %s\n", intrstr);
        /*
         * Try allocating a fast interrupt and the associated deferred
         * processing contexts.
@@ -2537,19 +2587,6 @@
                return ENXIO;
        }
 
-       adapter->osdep.intr = pci_intr_establish(adapter->osdep.pc,
-           adapter->osdep.ih, IPL_NET, ixgbe_legacy_irq, que);
-       if (adapter->osdep.intr == NULL) {
-               aprint_error_dev(dev, "failed to register interrupt handler\n");
-               softint_disestablish(que->que_si);
-               softint_disestablish(adapter->link_si);
-               softint_disestablish(adapter->mod_si);
-               softint_disestablish(adapter->msf_si);
-#ifdef IXGBE_FDIR
-               softint_disestablish(adapter->fdir_si);
-#endif
-               return ENXIO;
-       }
        /* For simplicity in the handlers */
        adapter->que_mask = IXGBE_EIMS_ENABLE_MASK;
 
@@ -2571,13 +2608,16 @@
        device_t        dev = adapter->dev;
        struct          ix_queue *que = adapter->queues;
        struct          tx_ring *txr = adapter->tx_rings;
-       int             error, rid, vector = 0;
+       pci_chipset_tag_t pc;
+       char            intrbuf[PCI_INTRSTR_LEN];
+       const char      *intrstr = NULL;
+       int             error, vector = 0;
        int             cpu_id = 0;
+       kcpuset_t       *affinity;
+
+       pc = adapter->osdep.pc;
 #ifdef RSS
        cpuset_t cpu_mask;
-#endif
-
-#ifdef RSS
        /*
         * If we're doing RSS, the number of queues needs to
         * match the number of RSS buckets that are configured.
@@ -2599,28 +2639,33 @@
        }
 #endif
 
+       adapter->osdep.nintrs = adapter->num_queues + 1;
+       if (pci_msix_alloc_exact(pa, &adapter->osdep.intrs,
+           adapter->osdep.nintrs) != 0) {
+               aprint_error_dev(dev,
+                   "failed to allocate MSI-X interrupt\n");
+               return (ENXIO);
+       }
+
+       kcpuset_create(&affinity, false);
        for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) {
-               rid = vector + 1;
-               que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
-                   RF_SHAREABLE | RF_ACTIVE);
+               intrstr = pci_intr_string(pc, adapter->osdep.intrs[i], intrbuf,
+                   sizeof(intrbuf));
+#ifdef IXG_MPSAFE
+               pci_intr_setattr(pc, adapter->osdep.intrs[i], PCI_INTR_MPSAFE,
+                   true);
+#endif
+               /* Set the handler function */
+               que->res = adapter->osdep.ihs[i] = pci_intr_establish(pc,
+                   adapter->osdep.intrs[i], IPL_NET, ixgbe_msix_que, que);
                if (que->res == NULL) {
-                       aprint_error_dev(dev,"Unable to allocate"
-                           " bus resource: que interrupt [%d]\n", vector);
-                       return (ENXIO);
-               }
-               /* Set the handler function */
-               error = bus_setup_intr(dev, que->res,
-                   INTR_TYPE_NET | INTR_MPSAFE, NULL,
-                   ixgbe_msix_que, que, &que->tag);
-               if (error) {
-                       que->res = NULL;
+                       pci_intr_release(pc, adapter->osdep.intrs,
+                           adapter->osdep.nintrs);
                        aprint_error_dev(dev,
                            "Failed to register QUE handler\n");



Home | Main Index | Thread Index | Old Index