Skip to content

Commit

Permalink
PCI: vmd: Fix secondary bus reset for Intel bridges
Browse files Browse the repository at this point in the history
The reset was never applied in the current implementation because Intel
Bridges owned by VMD are parentless. Internally, pci_reset_bus() applies
a reset to the parent of the PCI device supplied as argument, but in this
case it failed because there wasn't a parent.

In more detail, this change allows the VMD driver to enumerate NVMe devices
in pass-through configurations when guest reboots are performed. There was
an attempted to fix this, but later we discovered that the code inside
pci_reset_bus() wasn’t triggering secondary bus resets. Therefore, we
updated the parameters passed to it, and now NVMe SSDs attached to VMD
bridges are properly enumerated in VT-d pass-through scenarios.

Link: https://lore.kernel.org/r/20221206001637.4744-1-francisco.munoz.ruiz@linux.intel.com
Fixes: 6aab562 ("PCI: vmd: Clean up domain before enumeration")
Signed-off-by: Francisco Munoz <francisco.munoz.ruiz@linux.intel.com>
Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
Reviewed-by: Nirmal Patel <nirmal.patel@linux.intel.com>
Reviewed-by: Jonathan Derrick <jonathan.derrick@linux.dev>
  • Loading branch information
Francisco Munoz authored and Lorenzo Pieralisi committed Dec 6, 2022
1 parent d899aa6 commit 0a58465
Showing 1 changed file with 20 additions and 2 deletions.
22 changes: 20 additions & 2 deletions drivers/pci/controller/vmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
resource_size_t offset[2] = {0};
resource_size_t membar2_offset = 0x2000;
struct pci_bus *child;
struct pci_dev *dev;
int ret;

/*
Expand Down Expand Up @@ -859,8 +860,25 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)

pci_scan_child_bus(vmd->bus);
vmd_domain_reset(vmd);
list_for_each_entry(child, &vmd->bus->children, node)
pci_reset_bus(child->self);

/* When Intel VMD is enabled, the OS does not discover the Root Ports
* owned by Intel VMD within the MMCFG space. pci_reset_bus() applies
* a reset to the parent of the PCI device supplied as argument. This
* is why we pass a child device, so the reset can be triggered at
* the Intel bridge level and propagated to all the children in the
* hierarchy.
*/
list_for_each_entry(child, &vmd->bus->children, node) {
if (!list_empty(&child->devices)) {
dev = list_first_entry(&child->devices,
struct pci_dev, bus_list);
if (pci_reset_bus(dev))
pci_warn(dev, "can't reset device: %d\n", ret);

break;
}
}

pci_assign_unassigned_bus_resources(vmd->bus);

/*
Expand Down

0 comments on commit 0a58465

Please sign in to comment.