-/* $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 $ */
/*
#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>
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 *);
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 *);
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);
}
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;
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;
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;
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;
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),
}
int
-aq_hw_init(struct aq_softc *sc, int irqmode)
+aq_hw_init(struct aq_softc *sc, int irqmode, int multivec)
{
uint32_t v;
/* 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);
);
/* 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);
}
}
+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)
{