If enough MSI-X vectors are available, set up multiple tx and rx queues.
authorjmatthew <jmatthew@openbsd.org>
Wed, 30 Mar 2022 00:25:27 +0000 (00:25 +0000)
committerjmatthew <jmatthew@openbsd.org>
Wed, 30 Mar 2022 00:25:27 +0000 (00:25 +0000)
In multi-vector mode, the MSI-X vector number is the same as the irq number
on the nic, so use vector/irq 0 for link interrupts, then assign one to
each pair of rx and tx queues.  We don't configure RSS yet, so packets
will only be received on the first queue, but they can be transmitted on
any queue.

ok dlg@

sys/dev/pci/files.pci
sys/dev/pci/if_aq_pci.c

index e461143..25066c2 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.pci,v 1.357 2021/10/31 14:52:57 patrick Exp $
+#      $OpenBSD: files.pci,v 1.358 2022/03/30 00:25:27 jmatthew Exp $
 #      $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
 #
 # Config file and device description for machine-independent PCI code.
@@ -231,7 +231,7 @@ attach      sili at pci with sili_pci
 file   dev/pci/sili_pci.c              sili_pci
 
 # Aquantia/Atlantic 10-Gigabit Ethernet
-device  aq: ether, ifnet, ifmedia, mii
+device  aq: ether, ifnet, ifmedia, mii, intrmap
 attach  aq at pci
 file    dev/pci/if_aq_pci.c                 aq
 
index f7cf633..0b3ba3b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_aq_pci.c,v 1.12 2022/03/26 06:04:20 jmatthew Exp $ */
+/* $OpenBSD: if_aq_pci.c,v 1.13 2022/03/30 00:25:27 jmatthew Exp $ */
 /*     $NetBSD: if_aq.c,v 1.27 2021/06/16 00:21:18 riastradh Exp $     */
 
 /*
@@ -87,6 +87,7 @@
 #include <sys/kernel.h>
 #include <sys/sockio.h>
 #include <sys/systm.h>
+#include <sys/intrmap.h>
 
 #include <net/if.h>
 #include <net/if_media.h>
@@ -846,6 +847,8 @@ void        aq_attach(struct device *, struct device *, void *);
 int    aq_detach(struct device *, int);
 int    aq_activate(struct device *, int);
 int    aq_intr(void *);
+int    aq_intr_link(void *);
+int    aq_intr_queue(void *);
 void   aq_global_software_reset(struct aq_softc *);
 int    aq_fw_reset(struct aq_softc *);
 int    aq_mac_soft_reset(struct aq_softc *, enum aq_fw_bootloader_mode *);
@@ -857,7 +860,7 @@ int aq_hw_init_ucp(struct aq_softc *);
 int    aq_fw_downld_dwords(struct aq_softc *, uint32_t, uint32_t *, uint32_t);
 int    aq_get_mac_addr(struct aq_softc *);
 int    aq_hw_reset(struct aq_softc *);
-int    aq_hw_init(struct aq_softc *, int);
+int    aq_hw_init(struct aq_softc *, int, int);
 void   aq_hw_qos_set(struct aq_softc *);
 void   aq_l3_filter_set(struct aq_softc *);
 void   aq_hw_init_tx_path(struct aq_softc *);
@@ -971,7 +974,7 @@ aq_attach(struct device *parent, struct device *self, void *aux)
        pcitag_t tag;
        struct ifnet *ifp = &sc->sc_arpcom.ac_if;
        int txmin, txmax, rxmin, rxmax;
-       int irqmode;
+       int irqmode, irqnum;
        int i;
 
        mtx_init(&sc->sc_mpi_mutex, IPL_NET);
@@ -999,8 +1002,24 @@ aq_attach(struct device *parent, struct device *self, void *aux)
        }
 
        sc->sc_nqueues = 1;
+       sc->sc_linkstat_irq = AQ_LINKSTAT_IRQ;
+       isr = aq_intr;
+       irqnum = 0;
 
        if (pci_intr_map_msix(pa, 0, &ih) == 0) {
+               int nmsix = pci_intr_msix_count(pa);
+               if (nmsix > 1) {
+                       nmsix--;
+                       sc->sc_intrmap = intrmap_create(&sc->sc_dev,
+                           nmsix, AQ_MAXQ, INTRMAP_POWEROF2);
+                       sc->sc_nqueues = intrmap_count(sc->sc_intrmap);
+                       KASSERT(sc->sc_nqueues > 0);
+                       KASSERT(powerof2(sc->sc_nqueues));
+
+                       sc->sc_linkstat_irq = 0;
+                       isr = aq_intr_link;
+                       irqnum++;
+               }
                irqmode = AQ_INTR_CTRL_IRQMODE_MSIX;
        } else if (pci_intr_map_msi(pa, &ih) == 0) {
                irqmode = AQ_INTR_CTRL_IRQMODE_MSI;
@@ -1011,13 +1030,15 @@ aq_attach(struct device *parent, struct device *self, void *aux)
                return;
        }
 
-       isr = aq_intr;
        sc->sc_ih = pci_intr_establish(pa->pa_pc, ih,
            IPL_NET | IPL_MPSAFE, isr, sc, self->dv_xname);
        intrstr = pci_intr_string(pa->pa_pc, ih);
        if (intrstr)
                printf(": %s", intrstr);
 
+       if (sc->sc_nqueues > 1)
+               printf(", %d queues", sc->sc_nqueues);
+
        if (aq_fw_reset(sc))
                return;
 
@@ -1035,7 +1056,7 @@ aq_attach(struct device *parent, struct device *self, void *aux)
        if (aq_get_mac_addr(sc))
                return;
 
-       if (aq_hw_init(sc, irqmode))
+       if (aq_hw_init(sc, irqmode, (sc->sc_nqueues > 1)))
                return;
 
        sc->sc_media_type = aqp->aq_media_type;
@@ -1117,11 +1138,11 @@ aq_attach(struct device *parent, struct device *self, void *aux)
                struct aq_queues *aq = &sc->sc_queues[i];
                struct aq_rxring *rx = &aq->q_rx;
                struct aq_txring *tx = &aq->q_tx;
+               pci_intr_handle_t ih;
 
                aq->q_sc = sc;
                aq->q_index = i;
                rx->rx_q = i;
-               rx->rx_irq = i * 2;
                rx->rx_ifiq = ifp->if_iqs[i];
                rx->rx_m_head = NULL;
                rx->rx_m_tail = &rx->rx_m_head;
@@ -1130,12 +1151,33 @@ aq_attach(struct device *parent, struct device *self, void *aux)
                timeout_set(&rx->rx_refill, aq_refill, rx);
 
                tx->tx_q = i;
-               tx->tx_irq = rx->rx_irq + 1;
                tx->tx_ifq = ifp->if_ifqs[i];
                ifp->if_ifqs[i]->ifq_softc = aq;
 
+               snprintf(aq->q_name, sizeof(aq->q_name), "%s:%u",
+                   DEVNAME(sc), i);
+
                if (sc->sc_nqueues > 1) {
-                       /* map msix */
+                       if (pci_intr_map_msix(pa, irqnum, &ih)) {
+                               printf("%s: unable to map msi-x vector %d\n",
+                                   DEVNAME(sc), irqnum);
+                               return;
+                       }
+
+                       aq->q_ihc = pci_intr_establish_cpu(sc->sc_pc, ih,
+                           IPL_NET | IPL_MPSAFE, intrmap_cpu(sc->sc_intrmap, i),
+                           aq_intr_queue, aq, aq->q_name);
+                       if (aq->q_ihc == NULL) {
+                               printf("%s: unable to establish interrupt %d\n",
+                                   DEVNAME(sc), irqnum);
+                               return;
+                       }
+                       rx->rx_irq = irqnum;
+                       tx->tx_irq = irqnum;
+                       irqnum++;
+               } else {
+                       rx->rx_irq = irqnum++;
+                       tx->tx_irq = irqnum++;
                }
 
                AQ_WRITE_REG_BIT(sc, TX_INTR_MODERATION_CTL_REG(i),
@@ -1749,7 +1791,7 @@ aq_hw_l3_filter_set(struct aq_softc *sc)
 }
 
 int
-aq_hw_init(struct aq_softc *sc, int irqmode)
+aq_hw_init(struct aq_softc *sc, int irqmode, int multivec)
 {
        uint32_t v;
 
@@ -1776,7 +1818,7 @@ aq_hw_init(struct aq_softc *sc, int irqmode)
 
        /* Enable interrupt */
        AQ_WRITE_REG(sc, AQ_INTR_CTRL_REG, AQ_INTR_CTRL_RESET_DIS);
-       AQ_WRITE_REG_BIT(sc, AQ_INTR_CTRL_REG, AQ_INTR_CTRL_MULTIVEC, 0);
+       AQ_WRITE_REG_BIT(sc, AQ_INTR_CTRL_REG, AQ_INTR_CTRL_MULTIVEC, multivec);
 
        AQ_WRITE_REG_BIT(sc, AQ_INTR_CTRL_REG, AQ_INTR_CTRL_IRQMODE, irqmode);
 
@@ -1788,7 +1830,6 @@ aq_hw_init(struct aq_softc *sc, int irqmode)
        );
 
        /* link interrupt */
-       sc->sc_linkstat_irq = AQ_LINKSTAT_IRQ;
        AQ_WRITE_REG(sc, AQ_GEN_INTR_MAP_REG(3),
            (1 << 7) | sc->sc_linkstat_irq);
 
@@ -2460,6 +2501,46 @@ aq_start(struct ifqueue *ifq)
        }
 }
 
+int
+aq_intr_queue(void *arg)
+{
+       struct aq_queues *aq = arg;
+       struct aq_softc *sc = aq->q_sc;
+       uint32_t status;
+       uint32_t clear;
+
+       status = AQ_READ_REG(sc, AQ_INTR_STATUS_REG);
+       clear = 0;
+       if (status & (1 << aq->q_tx.tx_irq)) {
+               clear |= (1 << aq->q_tx.tx_irq);
+               aq_txeof(sc, &aq->q_tx);
+       }
+
+       if (status & (1 << aq->q_rx.rx_irq)) {
+               clear |= (1 << aq->q_rx.rx_irq);
+               aq_rxeof(sc, &aq->q_rx);
+       }
+
+       AQ_WRITE_REG(sc, AQ_INTR_STATUS_CLR_REG, clear);
+       return (clear != 0);
+}
+
+int
+aq_intr_link(void *arg)
+{
+       struct aq_softc *sc = arg;
+       uint32_t status;
+
+       status = AQ_READ_REG(sc, AQ_INTR_STATUS_REG);
+       if (status & (1 << sc->sc_linkstat_irq)) {
+               aq_update_link_status(sc);
+               AQ_WRITE_REG(sc, AQ_INTR_STATUS_REG, (1 << sc->sc_linkstat_irq));
+               return 1;
+       }
+
+       return 0;
+}
+
 int
 aq_intr(void *arg)
 {