PCI: vmd: Fix secondary bus reset for Intel bridges
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: 6aab562229
("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>
This commit is contained in:
parent
d899aa6684
commit
0a584655ef
1 changed files with 20 additions and 2 deletions
|
@ -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;
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Reference in a new issue