summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoerg Roedel <jroedel@suse.de>2015-10-09 12:23:34 +0200
committerBjorn Helgaas <bhelgaas@google.com>2015-10-21 11:19:25 -0500
commit8affb487d4a4e223d961d7034cb41cd31982b618 (patch)
tree99a2d0f9079342996a6a2ed73998e2b81d3659bc
parenta86760664f4cf44c0981ac0c91777eed3a2970e4 (diff)
x86/PCI: Don't alloc pcibios-irq when MSI is enabled
The pcibios-irq and MSI both use dev->irq to store the IRQ number. While the MSI code checks for that and frees the pcibios-irq before overwriting dev->irq, the pcibios_alloc_irq() function does not. Usually this is not a problem, as the pcibios-irq is allocated before probe time of the device and the MSI IRQ is allocted from the driver's probe path. But there are PCI devices handled by the core kernel and not by a standard PCI driver, like the AMD IOMMU for example. For the AMD IOMMU a normal PCI device driver does not make sense, because a driver can be forcibly unbound from its device, which is not a good idea for an IOMMU. Nevertheless the PCI core code tries to match the PCI device implementing the AMD IOMMU against drivers, and allocates/frees a pcibios IRQ every time it tries out a new driver. This overwrites the dev->irq field set by pci_enable_msi() and sets it to 0 in the end (because the probe fails and the pcibios-irq is freed again). On suspend/resume this breaks the kernel, because the IRQ descriptor for IRQ 0 is NULL. Fix this by not allocating a pcibios-irq when MSI is already active. This also has the benefit, that a device claimed by the core kernel can not be probed by a PCI driver later. Reported-by: Borislav Petkov <bp@alien8.de> Signed-off-by: Joerg Roedel <jroedel@suse.de> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Cc: Jiang Liu <jiang.liu@linux.intel.com>
-rw-r--r--arch/x86/pci/common.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 09d3afc0a181..b106c67f88c5 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -674,6 +674,14 @@ int pcibios_add_device(struct pci_dev *dev)
int pcibios_alloc_irq(struct pci_dev *dev)
{
+ /*
+ * If the PCI device was already claimed by core code and has
+ * MSI enabled, probing of the pcibios IRQ will overwrite
+ * dev->irq. So bail out if MSI is already enabled.
+ */
+ if (pci_dev_msi_enabled(dev))
+ return -EBUSY;
+
return pcibios_enable_irq(dev);
}