Skip to content

Commit 6aab562

Browse files
Nirmal PatelLorenzo Pieralisi
authored andcommitted
PCI: vmd: Clean up domain before enumeration
During VT-d pass-through, the VMD driver occasionally fails to enumerate underlying NVMe devices when repetitive reboots are performed in the guest OS. The issue can be resolved by resetting VMD root ports for proper enumeration and triggering secondary bus reset which will also propagate reset through downstream bridges. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Nirmal Patel <[email protected]> Signed-off-by: Lorenzo Pieralisi <[email protected]> Reviewed-by: Jon Derrick <[email protected]>
1 parent fa55b7d commit 6aab562

File tree

1 file changed

+37
-0
lines changed
  • drivers/pci/controller

1 file changed

+37
-0
lines changed

drivers/pci/controller/vmd.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,40 @@ static inline void vmd_acpi_begin(void) { }
501501
static inline void vmd_acpi_end(void) { }
502502
#endif /* CONFIG_ACPI */
503503

504+
static void vmd_domain_reset(struct vmd_dev *vmd)
505+
{
506+
u16 bus, max_buses = resource_size(&vmd->resources[0]);
507+
u8 dev, functions, fn, hdr_type;
508+
char __iomem *base;
509+
510+
for (bus = 0; bus < max_buses; bus++) {
511+
for (dev = 0; dev < 32; dev++) {
512+
base = vmd->cfgbar + PCIE_ECAM_OFFSET(bus,
513+
PCI_DEVFN(dev, 0), 0);
514+
515+
hdr_type = readb(base + PCI_HEADER_TYPE) &
516+
PCI_HEADER_TYPE_MASK;
517+
518+
functions = (hdr_type & 0x80) ? 8 : 1;
519+
for (fn = 0; fn < functions; fn++) {
520+
base = vmd->cfgbar + PCIE_ECAM_OFFSET(bus,
521+
PCI_DEVFN(dev, fn), 0);
522+
523+
hdr_type = readb(base + PCI_HEADER_TYPE) &
524+
PCI_HEADER_TYPE_MASK;
525+
526+
if (hdr_type != PCI_HEADER_TYPE_BRIDGE ||
527+
(readw(base + PCI_CLASS_DEVICE) !=
528+
PCI_CLASS_BRIDGE_PCI))
529+
continue;
530+
531+
memset_io(base + PCI_IO_BASE, 0,
532+
PCI_ROM_ADDRESS1 - PCI_IO_BASE);
533+
}
534+
}
535+
}
536+
}
537+
504538
static void vmd_attach_resources(struct vmd_dev *vmd)
505539
{
506540
vmd->dev->resource[VMD_MEMBAR1].child = &vmd->resources[1];
@@ -805,6 +839,9 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
805839
vmd_acpi_begin();
806840

807841
pci_scan_child_bus(vmd->bus);
842+
vmd_domain_reset(vmd);
843+
list_for_each_entry(child, &vmd->bus->children, node)
844+
pci_reset_bus(child->self);
808845
pci_assign_unassigned_bus_resources(vmd->bus);
809846

810847
/*

0 commit comments

Comments
 (0)