From 8affb487d4a4e223d961d7034cb41cd31982b618 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Fri, 9 Oct 2015 12:23:34 +0200 Subject: [PATCH] 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 Signed-off-by: Joerg Roedel Signed-off-by: Bjorn Helgaas Reviewed-by: Thomas Gleixner Cc: Jiang Liu --- arch/x86/pci/common.c | 8 ++++++++ 1 file changed, 8 insertions(+) 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); } -- 2.20.1