From cc10c1d7095f4a3b3c104559aff55883be1cb30a Mon Sep 17 00:00:00 2001 From: Carsten Beckmann Date: Thu, 17 Sep 2026 15:13:33 +0200 Subject: [PATCH 4/8] iavf: rework arq refilling Currently iavf_arq_fill is not called directly when admin queue responses are processed in the interrupt. This is fine when it actually is a response to some command that the driver issued, then the command issuer calls iavf_arq_fill. Some messages are sent to the VF unsolicited though, for example LINK_CHANGE events. Since the admin response queue is never refilled in this case only a few of those messages can be proccessed and all further messages will then be lost. iavf_arq_fill can not be called from an interrupt because iavf_aqb_alloc is not safe in that context. The simplest solution to that is to just preallocate all buffers during attach. Since iavf_arq_fill no longer needs to allocate anything it can now always be called which fixes messages being lost. To not waste too much memory with this approach also reduce the amount of descriptors in the admin queue to 32. --- sys/dev/pci/if_iavf.c | 45 ++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/sys/dev/pci/if_iavf.c b/sys/dev/pci/if_iavf.c index 6e7921e22e1..6c17b44057a 100644 --- a/sys/dev/pci/if_iavf.c +++ b/sys/dev/pci/if_iavf.c @@ -507,7 +507,7 @@ struct iavf_rx_wb_desc_32 { #define IAVF_ITR2 0x2 #define IAVF_NOITR 0x3 -#define IAVF_AQ_NUM 256 +#define IAVF_AQ_NUM 32 #define IAVF_AQ_MASK (IAVF_AQ_NUM - 1) #define IAVF_AQ_ALIGN 64 /* lol */ #define IAVF_AQ_BUFLEN 4096 @@ -691,6 +691,9 @@ static int iavf_dmamem_alloc(struct iavf_softc *, struct iavf_dmamem *, bus_size_t, u_int); static void iavf_dmamem_free(struct iavf_softc *, struct iavf_dmamem *); +static struct iavf_aq_buf * + iavf_aqb_alloc(struct iavf_softc *); +static void iavf_aqb_free(struct iavf_softc *, struct iavf_aq_buf *); static int iavf_arq_fill(struct iavf_softc *, int); static void iavf_arq_unfill(struct iavf_softc *); static void iavf_arq_timeout(void *); @@ -709,7 +712,7 @@ static int iavf_config_rss_lut(struct iavf_softc *); static int iavf_config_irq_map(struct iavf_softc *); static int iavf_add_del_addr(struct iavf_softc *, uint8_t *, int); -static int iavf_process_arq(struct iavf_softc *, int); +static int iavf_process_arq(struct iavf_softc *); static int iavf_match(struct device *, void *, void *); static int iavf_setup_interrupts(struct iavf_softc *, struct pci_attach_args *); @@ -936,8 +939,9 @@ iavf_attach(struct device *parent, struct device *self, void *aux) struct iavf_softc *sc = (struct iavf_softc *)self; struct ifnet *ifp = &sc->sc_ac.ac_if; struct pci_attach_args *pa = aux; + struct iavf_aq_buf *aqb; pcireg_t memtype; - int nmsix, tries; + int nmsix, tries, i; unsigned int nqueues; rw_init(&sc->sc_cfg_lock, "iavfcfg"); @@ -996,6 +1000,16 @@ iavf_attach(struct device *parent, struct device *self, void *aux) goto free_atq; } + for (i = 0; i < IAVF_AQ_NUM - 1; i++) { + aqb = iavf_aqb_alloc(sc); + if (aqb == NULL) { + printf("\n" "%s: unable to allocate aqb\n", + DEVNAME(sc)); + goto free_arq; + } + SIMPLEQ_INSERT_TAIL(&sc->sc_arq_idle, aqb, aqb_entry); + } + if (!iavf_arq_fill(sc, 0)) { printf("\n" "%s: unable to fill arq descriptors\n", DEVNAME(sc)); @@ -1130,6 +1144,10 @@ shutdown: iavf_arq_unfill(sc); free_arq: + while ((aqb = SIMPLEQ_FIRST(&sc->sc_arq_idle)) != NULL) { + SIMPLEQ_REMOVE_HEAD(&sc->sc_arq_idle, aqb_entry); + iavf_aqb_free(sc, aqb); + } iavf_dmamem_free(sc, &sc->sc_arq); free_atq: iavf_dmamem_free(sc, &sc->sc_atq); @@ -2568,7 +2586,7 @@ iavf_intr(void *xsc) if (ISSET(icr, I40E_VFINT_ICR01_ADMINQ_MASK)) { iavf_atq_done(sc); - iavf_process_arq(sc, 0); + iavf_process_arq(sc); rv = 1; } @@ -2714,7 +2732,7 @@ iavf_init_admin_queue(struct iavf_softc *sc) } static int -iavf_process_arq(struct iavf_softc *sc, int fill) +iavf_process_arq(struct iavf_softc *sc) { struct iavf_aq_desc *arq, *iaq; struct iavf_aq_buf *aqb; @@ -2797,8 +2815,7 @@ iavf_process_arq(struct iavf_softc *sc, int fill) done = 1; } while (cons != prod); - if (fill) - iavf_arq_fill(sc, 1); + iavf_arq_fill(sc, 1); bus_dmamap_sync(sc->sc_dmat, IAVF_DMA_MAP(&sc->sc_arq), 0, IAVF_DMA_LEN(&sc->sc_arq), @@ -2909,7 +2926,7 @@ iavf_get_version(struct iavf_softc *sc) iavf_atq_post(sc, &iaq); for (tries = 0; tries < 100; tries++) { - iavf_process_arq(sc, 1); + iavf_process_arq(sc); if (sc->sc_major_ver != -1) break; @@ -2961,7 +2978,7 @@ iavf_get_vf_resources(struct iavf_softc *sc) iavf_atq_post(sc, &iaq); for (tries = 0; tries < 100; tries++) { - iavf_process_arq(sc, 1); + iavf_process_arq(sc); if (sc->sc_got_vf_resources != 0) return (0); @@ -3024,7 +3041,7 @@ iavf_config_irq_map(struct iavf_softc *sc) iavf_atq_post(sc, &iaq); for (tries = 0; tries < 100; tries++) { - iavf_process_arq(sc, 1); + iavf_process_arq(sc); if (sc->sc_got_irq_map != 0) return (0); @@ -3092,10 +3109,9 @@ iavf_arq_fill(struct iavf_softc *sc, int post) while (n > 0) { aqb = SIMPLEQ_FIRST(&sc->sc_arq_idle); - if (aqb != NULL) - SIMPLEQ_REMOVE_HEAD(&sc->sc_arq_idle, aqb_entry); - else if ((aqb = iavf_aqb_alloc(sc)) == NULL) + if (aqb == NULL) break; + SIMPLEQ_REMOVE_HEAD(&sc->sc_arq_idle, aqb_entry); memset(aqb->aqb_data, 0, IAVF_AQ_BUFLEN); @@ -3143,7 +3159,7 @@ iavf_arq_unfill(struct iavf_softc *sc) bus_dmamap_sync(sc->sc_dmat, aqb->aqb_map, 0, IAVF_AQ_BUFLEN, BUS_DMASYNC_POSTREAD); - iavf_aqb_free(sc, aqb); + SIMPLEQ_INSERT_TAIL(&sc->sc_arq_idle, aqb, aqb_entry); if_rxr_put(&sc->sc_arq_ring, 1); } } @@ -3167,7 +3183,6 @@ iavf_arq_wait(struct iavf_softc *sc, int msec) cond_wait(&sc->sc_admin_cond, "iavfarq"); timeout_del(&sc->sc_admin_timeout); - iavf_arq_fill(sc, 1); return sc->sc_admin_result; } -- 2.53.0