aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2015-09-18 17:08:54 -0400
committerBjorn Helgaas <helgaas@kernel.org>2015-09-24 18:06:32 -0400
commit38ea72bdb65df2f40ec77b2c9d1413e7f5e34465 (patch)
tree9356d810f4575ff20e2615043de2005439202845
parentb838b39e930aa1cfd099ea82ac40ed6d6413af26 (diff)
PCI/MSI: Fix MSI IRQ domains for VFs on virtual buses
SR-IOV creates a virtual bus where bus->self is NULL. When we add VFs and scan for an MSI domain, pci_set_bus_msi_domain() dereferences bus->self, which causes a kernel NULL pointer dereference oops. Scan up to the parent bus until we find a real bridge where we can get the MSI domain. [bhelgaas: changelog] Fixes: 44aa0c657e3e ("PCI/MSI: Add hooks to populate the msi_domain field") Tested-by: Joerg Roedel <joro@8bytes.org> Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Bjorn Helgaas <helgaas@kernel.org> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--drivers/pci/probe.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index c8cc0e62a7b9..8361d27e5eca 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -676,15 +676,20 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
676static void pci_set_bus_msi_domain(struct pci_bus *bus) 676static void pci_set_bus_msi_domain(struct pci_bus *bus)
677{ 677{
678 struct irq_domain *d; 678 struct irq_domain *d;
679 struct pci_bus *b;
679 680
680 /* 681 /*
681 * Either bus is the root, and we must obtain it from the 682 * The bus can be a root bus, a subordinate bus, or a virtual bus
682 * firmware, or we inherit it from the bridge device. 683 * created by an SR-IOV device. Walk up to the first bridge device
684 * found or derive the domain from the host bridge.
683 */ 685 */
684 if (pci_is_root_bus(bus)) 686 for (b = bus, d = NULL; !d && !pci_is_root_bus(b); b = b->parent) {
685 d = pci_host_bridge_msi_domain(bus); 687 if (b->self)
686 else 688 d = dev_get_msi_domain(&b->self->dev);
687 d = dev_get_msi_domain(&bus->self->dev); 689 }
690
691 if (!d)
692 d = pci_host_bridge_msi_domain(b);
688 693
689 dev_set_msi_domain(&bus->dev, d); 694 dev_set_msi_domain(&bus->dev, d);
690} 695}