On 26/03/20(Thu) 12:13, Martin Pieuchot wrote:
> Previous diff had a bug in the interrupt handler refactoring that showed
> up on i386.  The version below has been tested on i386 and doesn't seem
> to cause any regression.
> 
> Here's the original explanation, diff below has msix toggle to "off":
> 
> > Diff below allows ix(4) to establish two MSI-X handlers.  Multiqueue
> > support is intentionally not included in this diff.
> > 
> > One handler is for the single queue (index ":0") and one for the
> > link interrupt:
> > 
> >   # vmstat -i |grep ix0
> >   irq114/ix0:0                 73178178     3758
> >   irq115/ix0                          2        0
> >
> > A per-driver toggle allows to switch MSI-X support on/off.  My plan is
> > to commit with the switch "off" for the moment.  Switching it to "on"
> > should be better done in the beginning of a release cycle.  However it
> > is "on" in the diff below for testing purposes.
> 
> I appreciate more tests and oks :)

Updated diff that only unable interrupt moderation on the link interrupt
if MSI-X is used.  Without this change the !msix path was receiving less
packets as found by Hrvoje.

This has been tested on both i386 and amd64, I'm quite confident, any
ok?

Index: dev/pci/if_ix.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_ix.c,v
retrieving revision 1.163
diff -u -p -r1.163 if_ix.c
--- dev/pci/if_ix.c     25 Mar 2020 17:20:46 -0000      1.163
+++ dev/pci/if_ix.c     30 Mar 2020 12:55:04 -0000
@@ -114,6 +114,8 @@ int ixgbe_media_change(struct ifnet *);
 void   ixgbe_identify_hardware(struct ix_softc *);
 int    ixgbe_allocate_pci_resources(struct ix_softc *);
 int    ixgbe_allocate_legacy(struct ix_softc *);
+int    ixgbe_allocate_msix(struct ix_softc *);
+int    ixgbe_setup_msix(struct ix_softc *);
 int    ixgbe_allocate_queues(struct ix_softc *);
 void   ixgbe_free_pci_resources(struct ix_softc *);
 void   ixgbe_local_timer(void *);
@@ -140,6 +142,7 @@ void        ixgbe_initialize_rss_mapping(struct
 int    ixgbe_rxfill(struct rx_ring *);
 void   ixgbe_rxrefill(void *);
 
+int    ixgbe_intr(struct ix_softc *sc);
 void   ixgbe_enable_intr(struct ix_softc *);
 void   ixgbe_disable_intr(struct ix_softc *);
 void   ixgbe_update_stats_counters(struct ix_softc *);
@@ -172,11 +175,16 @@ void      ixgbe_handle_msf(struct ix_softc *)
 void   ixgbe_handle_phy(struct ix_softc *);
 
 /* Legacy (single vector interrupt handler */
-int    ixgbe_intr(void *);
+int    ixgbe_legacy_intr(void *);
 void   ixgbe_enable_queue(struct ix_softc *, uint32_t);
+void   ixgbe_enable_queues(struct ix_softc *);
 void   ixgbe_disable_queue(struct ix_softc *, uint32_t);
 void   ixgbe_rearm_queue(struct ix_softc *, uint32_t);
 
+/* MSI-X (multiple vectors interrupt handlers)  */
+int    ixgbe_link_intr(void *);
+int    ixgbe_queue_intr(void *);
+
 /*********************************************************************
  *  OpenBSD Device Interface Entry Points
  *********************************************************************/
@@ -190,6 +198,7 @@ struct cfattach ix_ca = {
 };
 
 int ixgbe_smart_speed = ixgbe_smart_speed_on;
+int ixgbe_enable_msix = 0;
 
 /*********************************************************************
  *  Device identification routine
@@ -292,7 +301,10 @@ ixgbe_attach(struct device *parent, stru
        bcopy(sc->hw.mac.addr, sc->arpcom.ac_enaddr,
            IXGBE_ETH_LENGTH_OF_ADDRESS);
 
-       error = ixgbe_allocate_legacy(sc);
+       if (sc->msix > 1)
+               error = ixgbe_allocate_msix(sc);
+       else
+               error = ixgbe_allocate_legacy(sc);
        if (error)
                goto err_late;
 
@@ -524,6 +536,7 @@ ixgbe_ioctl(struct ifnet * ifp, u_long c
                        ixgbe_disable_intr(sc);
                        ixgbe_iff(sc);
                        ixgbe_enable_intr(sc);
+                       ixgbe_enable_queues(sc);
                }
                error = 0;
        }
@@ -819,6 +832,12 @@ ixgbe_init(void *arg)
                itr |= IXGBE_EITR_LLI_MOD | IXGBE_EITR_CNT_WDIS;
        IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(0), itr);
 
+       if (sc->msix > 1) {
+               /* Set moderation on the Link interrupt */
+               IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(sc->linkvec),
+                   IXGBE_LINK_ITR);
+       }
+
        /* Enable power to the phy */
        if (sc->hw.phy.ops.set_phy_power)
                sc->hw.phy.ops.set_phy_power(&sc->hw, TRUE);
@@ -834,6 +853,7 @@ ixgbe_init(void *arg)
 
        /* And now turn on interrupts */
        ixgbe_enable_intr(sc);
+       ixgbe_enable_queues(sc);
 
        /* Now inform the stack we're ready */
        ifp->if_flags |= IFF_RUNNING;
@@ -964,6 +984,16 @@ ixgbe_enable_queue(struct ix_softc *sc, 
 }
 
 void
+ixgbe_enable_queues(struct ix_softc *sc)
+{
+       struct ix_queue *que;
+       int i;
+
+       for (i = 0, que = sc->queues; i < sc->num_queues; i++, que++)
+               ixgbe_enable_queue(sc, que->msix);
+}
+
+void
 ixgbe_disable_queue(struct ix_softc *sc, uint32_t vector)
 {
        uint64_t queue = 1ULL << vector;
@@ -982,6 +1012,41 @@ ixgbe_disable_queue(struct ix_softc *sc,
        }
 }
 
+/*
+ * MSIX Interrupt Handlers
+ */
+int
+ixgbe_link_intr(void *vsc)
+{
+       struct ix_softc *sc = (struct ix_softc *)vsc;
+
+       return ixgbe_intr(sc);
+}
+
+int
+ixgbe_queue_intr(void *vque)
+{
+       struct ix_queue *que = vque;
+       struct ix_softc *sc = que->sc;
+       struct ifnet    *ifp = &sc->arpcom.ac_if;
+       struct tx_ring  *txr = sc->tx_rings;
+
+       if (ISSET(ifp->if_flags, IFF_RUNNING)) {
+               ixgbe_rxeof(que);
+               ixgbe_txeof(txr);
+               if (ixgbe_rxfill(que->rxr)) {
+                       /* Advance the Rx Queue "Tail Pointer" */
+                       IXGBE_WRITE_REG(&sc->hw, IXGBE_RDT(que->rxr->me),
+                           que->rxr->last_desc_filled);
+               } else
+                       timeout_add(&sc->rx_refill, 1);
+       }
+
+       ixgbe_enable_queue(sc, que->msix);
+
+       return (1);
+}
+
 /*********************************************************************
  *
  *  Legacy Interrupt Service routine
@@ -989,29 +1054,24 @@ ixgbe_disable_queue(struct ix_softc *sc,
  **********************************************************************/
 
 int
-ixgbe_intr(void *arg)
+ixgbe_legacy_intr(void *arg)
 {
        struct ix_softc *sc = (struct ix_softc *)arg;
-       struct ix_queue *que = sc->queues;
        struct ifnet    *ifp = &sc->arpcom.ac_if;
        struct tx_ring  *txr = sc->tx_rings;
-       struct ixgbe_hw *hw = &sc->hw;
-       uint32_t         reg_eicr, mod_mask, msf_mask;
-       int              i, refill = 0;
+       int rv;
 
-       reg_eicr = IXGBE_READ_REG(&sc->hw, IXGBE_EICR);
-       if (reg_eicr == 0) {
-               ixgbe_enable_intr(sc);
+       rv = ixgbe_intr(sc);
+       if (rv == 0) {
+               ixgbe_enable_queues(sc);
                return (0);
        }
 
        if (ISSET(ifp->if_flags, IFF_RUNNING)) {
+               struct ix_queue *que = sc->queues;
+
                ixgbe_rxeof(que);
                ixgbe_txeof(txr);
-               refill = 1;
-       }
-
-       if (refill) {
                if (ixgbe_rxfill(que->rxr)) {
                        /* Advance the Rx Queue "Tail Pointer" */
                        IXGBE_WRITE_REG(&sc->hw, IXGBE_RDT(que->rxr->me),
@@ -1020,6 +1080,23 @@ ixgbe_intr(void *arg)
                        timeout_add(&sc->rx_refill, 1);
        }
 
+       ixgbe_enable_queues(sc);
+       return (rv);
+}
+
+int
+ixgbe_intr(struct ix_softc *sc)
+{
+       struct ifnet    *ifp = &sc->arpcom.ac_if;
+       struct ixgbe_hw *hw = &sc->hw;
+       uint32_t         reg_eicr, mod_mask, msf_mask;
+
+       reg_eicr = IXGBE_READ_REG(&sc->hw, IXGBE_EICR);
+       if (reg_eicr == 0) {
+               ixgbe_enable_intr(sc);
+               return (0);
+       }
+
        /* Link status change */
        if (reg_eicr & IXGBE_EICR_LSC) {
                KERNEL_LOCK();
@@ -1090,9 +1167,6 @@ ixgbe_intr(void *arg)
                KERNEL_UNLOCK();
        }
 
-       for (i = 0; i < sc->num_queues; i++, que++)
-               ixgbe_enable_queue(sc, que->msix);
-
        return (1);
 }
 
@@ -1626,7 +1700,7 @@ ixgbe_allocate_legacy(struct ix_softc *s
 
        intrstr = pci_intr_string(pc, ih);
        sc->tag = pci_intr_establish(pc, ih, IPL_NET | IPL_MPSAFE,
-           ixgbe_intr, sc, sc->dev.dv_xname);
+           ixgbe_legacy_intr, sc, sc->dev.dv_xname);
        if (sc->tag == NULL) {
                printf(": couldn't establish interrupt");
                if (intrstr != NULL)
@@ -1642,6 +1716,92 @@ ixgbe_allocate_legacy(struct ix_softc *s
        return (0);
 }
 
+/*********************************************************************
+ *
+ *  Setup the MSI-X Interrupt handlers
+ *
+ **********************************************************************/
+int
+ixgbe_allocate_msix(struct ix_softc *sc)
+{
+       struct ixgbe_osdep      *os = &sc->osdep;
+       struct pci_attach_args  *pa  = &os->os_pa;
+       int                      vec, error = 0;
+       struct ix_queue         *que = sc->queues;
+       const char              *intrstr = NULL;
+       pci_chipset_tag_t       pc = pa->pa_pc;
+       pci_intr_handle_t       ih;
+
+       vec = 0;
+       if (pci_intr_map_msix(pa, vec, &ih)) {
+               printf(": couldn't map interrupt\n");
+               return (ENXIO);
+       }
+
+       que->msix = vec;
+       snprintf(que->name, sizeof(que->name), "%s:%d", sc->dev.dv_xname, vec);
+
+       intrstr = pci_intr_string(pc, ih);
+       que->tag = pci_intr_establish(pc, ih, IPL_NET | IPL_MPSAFE,
+           ixgbe_queue_intr, que, que->name);
+       if (que->tag == NULL) {
+               printf(": couldn't establish interrupt");
+               if (intrstr != NULL)
+                       printf(" at %s", intrstr);
+               printf("\n");
+               return (ENXIO);
+       }
+
+       /* Now the link status/control last MSI-X vector */
+       vec++;
+       if (pci_intr_map_msix(pa, vec, &ih)) {
+               printf(": couldn't map link vector\n");
+               error = ENXIO;
+               goto fail;
+       }
+
+       intrstr = pci_intr_string(pc, ih);
+       sc->tag = pci_intr_establish(pc, ih, IPL_NET | IPL_MPSAFE,
+           ixgbe_link_intr, sc, sc->dev.dv_xname);
+       if (sc->tag == NULL) {
+               printf(": couldn't establish interrupt");
+               if (intrstr != NULL)
+                       printf(" at %s", intrstr);
+               printf("\n");
+               error = ENXIO;
+               goto fail;
+       }
+
+       sc->linkvec = vec;
+       printf(", %s, %d queue%s", intrstr, vec, (vec > 1) ? "s" : "");
+
+       return (0);
+fail:
+       pci_intr_disestablish(pc, que->tag);
+       que->tag = NULL;
+       return (error);
+}
+
+int
+ixgbe_setup_msix(struct ix_softc *sc)
+{
+       struct ixgbe_osdep      *os = &sc->osdep;
+       struct pci_attach_args  *pa = &os->os_pa;
+       pci_intr_handle_t        dummy;
+
+       if (!ixgbe_enable_msix)
+               return (0);
+
+       /*
+        * Try a dummy map, maybe this bus doesn't like MSI, this function
+        * has no side effects.
+        */
+       if (pci_intr_map_msix(pa, 0, &dummy))
+               return (0);
+
+       return (2); /* queue vector + link vector */
+}
+
 int
 ixgbe_allocate_pci_resources(struct ix_softc *sc)
 {
@@ -1666,10 +1826,8 @@ ixgbe_allocate_pci_resources(struct ix_s
        sc->num_queues = 1;
        sc->hw.back = os;
 
-#ifdef notyet
        /* Now setup MSI or MSI/X, return us the number of supported vectors. */
        sc->msix = ixgbe_setup_msix(sc);
-#endif
 
        return (0);
 }
@@ -3085,9 +3243,7 @@ void
 ixgbe_enable_intr(struct ix_softc *sc)
 {
        struct ixgbe_hw *hw = &sc->hw;
-       struct ix_queue *que = sc->queues;
        uint32_t        mask, fwsm;
-       int i;
 
        mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE);
        /* Enable Fan Failure detection */
@@ -3135,14 +3291,6 @@ ixgbe_enable_intr(struct ix_softc *sc)
                IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask);
        }
 
-       /*
-        * Now enable all queues, this is done separately to
-        * allow for handling the extended (beyond 32) MSIX
-        * vectors that can be used by 82599
-        */
-       for (i = 0; i < sc->num_queues; i++, que++)
-               ixgbe_enable_queue(sc, que->msix);
-
        IXGBE_WRITE_FLUSH(hw);
 }
 
@@ -3258,15 +3406,11 @@ ixgbe_set_ivar(struct ix_softc *sc, uint
 void
 ixgbe_configure_ivars(struct ix_softc *sc)
 {
-#if notyet
        struct ix_queue *que = sc->queues;
        uint32_t newitr;
        int i;
 
-       if (ixgbe_max_interrupt_rate > 0)
-               newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8;
-       else
-               newitr = 0;
+       newitr = (4000000 / IXGBE_INTS_PER_SEC) & 0x0FF8;
 
        for (i = 0; i < sc->num_queues; i++, que++) {
                /* First the RX queue entry */
@@ -3280,7 +3424,6 @@ ixgbe_configure_ivars(struct ix_softc *s
 
        /* For the Link interrupt */
        ixgbe_set_ivar(sc, 1, sc->linkvec, -1);
-#endif
 }
 
 /*
Index: dev/pci/if_ix.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_ix.h,v
retrieving revision 1.39
diff -u -p -r1.39 if_ix.h
--- dev/pci/if_ix.h     25 Mar 2020 17:20:46 -0000      1.39
+++ dev/pci/if_ix.h     30 Mar 2020 12:54:31 -0000
@@ -120,6 +120,7 @@
  * Interrupt Moderation parameters
  */
 #define IXGBE_INTS_PER_SEC             8000
+#define IXGBE_LINK_ITR                 1000
 
 struct ixgbe_tx_buf {
        uint32_t                eop_index;
@@ -154,6 +155,8 @@ struct ix_queue {
        uint32_t                msix;           /* This queue's MSIX vector */
        uint32_t                eims;           /* This queue's EIMS bit */
        uint32_t                eitr_setting;
+       char                    name[8];
+       pci_intr_handle_t       ih;
        void                    *tag;
        struct tx_ring          *txr;
        struct rx_ring          *rxr;

Reply via email to