Re: [PATCH v9 1/5] vfio: selftests: igb: Add driver for Intel 82576 device
Alex Williamson <[email protected]> Fri, 31 Jul 2026 12:15:02 -0600
| Newsgroups | org.kernel.vger.linux-kselftest,org.kernel.vger.kvm,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On Thu, 30 Jul 2026 23:31:29 +0000 Josh Hilke <[email protected]> wrote: > +static void igb_init(struct vfio_pci_device *device) > +{ > + struct igb *igb = to_igb_state(device); > + u64 iova_tx, iova_rx; > + u32 ctrl, rctl; > + u16 cmd_reg; > + int retries; > + > + VFIO_ASSERT_GE(device->driver.region.size, sizeof(struct igb)); > + > + /* Set up rings and calculate IOVAs */ > + igb->bar0 = device->bars[0].vaddr; > + > + iova_tx = to_iova(device, igb->tx_ring); > + iova_rx = to_iova(device, igb->rx_ring); > + > + igb_reset(igb); > + > + /* Signal that the driver is loaded */ > + ctrl = igb_read32(igb, E1000_CTRL_EXT); > + ctrl |= E1000_CTRL_EXT_DRV_LOAD; > + ctrl &= ~E1000_CTRL_EXT_LINK_MODE_MASK; > + igb_write32(igb, E1000_CTRL_EXT, ctrl); > + > + /* Enable PCI Bus Master. */ > + cmd_reg = vfio_pci_config_readw(device, PCI_COMMAND); > + if ((cmd_reg & (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY)) != > + (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY)) { > + cmd_reg |= (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); > + vfio_pci_config_writew(device, PCI_COMMAND, cmd_reg); > + } > + > + /* Configure PHY internal loopback for testing. */ > + igb_setup_loopback(igb); > + > + /* > + * Disable DMA re-send on PCIe completion timeout (82576 datasheet > + * section 8.6.1, GCR.Completion_Timeout_Resend, bit 16). The > + * mix_and_match test intentionally submits descriptors targeting > + * unmapped IOVAs; with the default (set) value, the device keeps > + * retrying the failed read indefinitely, which keeps PCIe AER and > + * IOMMU error handling busy and interferes with reset recovery. > + */ > + ctrl = igb_read32(igb, E1000_GCR); > + ctrl &= ~E1000_GCR_CMPL_TMOUT_RESEND; > + igb_write32(igb, E1000_GCR, ctrl); > + > + /* Configure TX and RX descriptor rings */ > + igb_write32(igb, E1000_TDBAL(0), (u32)iova_tx); > + igb_write32(igb, E1000_TDBAH(0), (u32)(iova_tx >> 32)); > + igb_write32(igb, E1000_TDLEN(0), RING_SIZE * sizeof(struct igb_tx_desc)); > + igb_write32(igb, E1000_TDH(0), 0); > + igb_write32(igb, E1000_TDT(0), 0); > + igb_write32(igb, E1000_TXDCTL(0), E1000_TXDCTL_QUEUE_ENABLE); > + > + igb_write32(igb, E1000_RDBAL(0), (u32)iova_rx); > + igb_write32(igb, E1000_RDBAH(0), (u32)(iova_rx >> 32)); > + igb_write32(igb, E1000_RDLEN(0), RING_SIZE * sizeof(struct igb_rx_desc)); > + igb_write32(igb, E1000_RDH(0), 0); > + igb_write32(igb, E1000_RDT(0), 0); > + > + /* > + * Select the advanced one-buffer descriptor format. Per 82576 > + * datasheet section 7.1.5.2: "SRRCTL[n].DESCTYPE must be set to a > + * value other than 000b for the 82576 to write back the special > + * descriptors." struct igb_rx_desc matches the advanced one-buffer > + * writeback layout (section 7.1.5.2), so polling rx.wb.status_error > + * requires this format. Section 8.10.2 specifies DESCTYPE[27:25]. > + * > + * The direct write also zeroes SRRCTL.BSIZEPACKET, which is > + * intentional: per section 7.1.3.1 a zero BSIZEPACKET falls back to > + * the RCTL.BSIZE buffer size, whose reset default (00b) is 2048 > + * bytes -- ample for the loopback frames here. > + */ > + igb_write32(igb, E1000_SRRCTL(0), E1000_SRRCTL_DESCTYPE_ADV_ONEBUF); > + > + igb_write32(igb, E1000_RXDCTL(0), E1000_RXDCTL_QUEUE_ENABLE); > + > + /* Wait for TX and RX queues to be enabled */ > + retries = 2000; > + while (retries-- > 0) { > + if ((igb_read32(igb, E1000_TXDCTL(0)) & E1000_TXDCTL_QUEUE_ENABLE) && > + (igb_read32(igb, E1000_RXDCTL(0)) & E1000_RXDCTL_QUEUE_ENABLE)) > + break; > + usleep(10); > + } > + VFIO_ASSERT_GE(retries, 0); I'm not sure how I missed this in the previous iteration, but this new-ish assert exposes a latent ordering issue on real hardware. As per the below referenced register definitions, the per-queue enable bits are zero until the global enable bits are set. diff --git a/tools/testing/selftests/vfio/lib/drivers/igb/igb.c b/tools/testing/selftests/vfio/lib/drivers/igb/igb.c index 97a2f29aade3..fae523059f86 100644 --- a/tools/testing/selftests/vfio/lib/drivers/igb/igb.c +++ b/tools/testing/selftests/vfio/lib/drivers/igb/igb.c @@ -303,16 +303,6 @@ static void igb_hw_init(struct vfio_pci_device *device) igb_write32(igb, E1000_RXDCTL(0), E1000_RXDCTL_QUEUE_ENABLE); - /* Wait for TX and RX queues to be enabled */ - retries = 2000; - while (retries-- > 0) { - if ((igb_read32(igb, E1000_TXDCTL(0)) & E1000_TXDCTL_QUEUE_ENABLE) && - (igb_read32(igb, E1000_RXDCTL(0)) & E1000_RXDCTL_QUEUE_ENABLE)) - break; - usleep(10); - } - VFIO_ASSERT_GE(retries, 0); - /* * Enable Receiver and Transmitter. RCTL.LBM_MAC is set in addition * to PHY loopback as a QEMU-only accommodation: QEMU's emulated igb @@ -335,6 +325,21 @@ static void igb_hw_init(struct vfio_pci_device *device) igb_write32(igb, E1000_RCTL, rctl); igb_write32(igb, E1000_TCTL, E1000_TCTL_EN | E1000_TCTL_PSP); + /* + * Wait for TX and RX queues to be enabled. Per the RXDCTL/TXDCTL + * register definitions (8.10.10/8.12.13), the per-queue enable bit + * "remains zero" until the global RCTL.RXEN/TCTL.TXEN are set, so + * E1000_RCTL_EN and E1000_TCTL_EN must already be written above. + */ + retries = 2000; + while (retries-- > 0) { + if ((igb_read32(igb, E1000_TXDCTL(0)) & E1000_TXDCTL_QUEUE_ENABLE) && + (igb_read32(igb, E1000_RXDCTL(0)) & E1000_RXDCTL_QUEUE_ENABLE)) + break; + usleep(10); + } + VFIO_ASSERT_GE(retries, 0); + /* * Program MSI-X interrupt routing per 82576 datasheet: * Back to 35/35 on real hardware with this. NB, patch is against fully applied series, so lands in igb_hw_init() but the source of the ordering issue is in patch 1 here, where it's igb_init(). Thanks, Alex > + > + /* > + * Enable Receiver and Transmitter. RCTL.LBM_MAC is set in addition > + * to PHY loopback as a QEMU-only accommodation: QEMU's emulated igb > + * does not honor PHY register 0 bit 14 (PHY internal loopback) and > + * relies on RCTL.LBM_MAC to wrap TX descriptors back to the RX > + * queue. Datasheet 8.10.1 (RCTL register) advises "When using the > + * internal PHY, LBM should remain set to 00b", so setting LBM_MAC > + * here deviates from datasheet guidance; empirically the bit has > + * no observable effect on real 82576 hardware because MAC loopback > + * is not implemented (datasheet 3.5.6.2). Setting both lets the > + * selftest work on both real hardware and QEMU without conditional > + * code paths. > + */ > + rctl = E1000_RCTL_EN | /* Receiver Enable */ > + E1000_RCTL_UPE | /* Unicast Promiscuous (for dummy MAC) */ > + E1000_RCTL_MPE | /* Multicast Promiscuous */ > + E1000_RCTL_BAM | /* Broadcast Accept Mode */ > + E1000_RCTL_LBM_MAC | /* MAC Loopback - for QEMU emulation only */ > + E1000_RCTL_SECRC; /* Strip CRC (needed for memcmp) */ > + igb_write32(igb, E1000_RCTL, rctl); > + igb_write32(igb, E1000_TCTL, E1000_TCTL_EN | E1000_TCTL_PSP);