diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2022-12-10 19:36:39 +0300 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2022-12-10 19:36:39 +0300 |
commit | ba7deaa2a8e48d8a31608b5dca58dbe119c0d72a (patch) | |
tree | 4f3e821a3a432230991e4c793fdc05615faf496e /drivers/pci | |
parent | 4e5db7983de0d4bed83e2cdaf9f04093e8b8e1c4 (diff) | |
parent | 0a584655ef89541dae4d48d2c523b1480ae80284 (diff) | |
download | linux-ba7deaa2a8e48d8a31608b5dca58dbe119c0d72a.tar.xz |
Merge branch 'remotes/lorenzo/pci/vmd'
- Restore MSI remapping configuration during resume because the
configuration is cleared out by firmware when suspending (Nirmal Patel)
- Reset the hierarchy below VMD when probing the VMD; we attempted this
before, but with the wrong device, so it didn't work (Francisco Munoz)
* remotes/lorenzo/pci/vmd:
PCI: vmd: Fix secondary bus reset for Intel bridges
PCI: vmd: Disable MSI remapping after suspend
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/controller/vmd.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index e06e9f4fc50f..769eedeb8802 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -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); /* @@ -980,6 +998,11 @@ static int vmd_resume(struct device *dev) struct vmd_dev *vmd = pci_get_drvdata(pdev); int err, i; + if (vmd->irq_domain) + vmd_set_msi_remapping(vmd, true); + else + vmd_set_msi_remapping(vmd, false); + for (i = 0; i < vmd->msix_count; i++) { err = devm_request_irq(dev, vmd->irqs[i].virq, vmd_irq, IRQF_NO_THREAD, |