From cffe0a2b5a34c95a4dadc9ec7132690a5b0f6687 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 27 Oct 2014 13:21:42 +0800 Subject: x86, irq: Keep balance of IOAPIC pin reference count To keep balance of IOAPIC pin reference count, we need to protect pirq_enable_irq(), acpi_pci_irq_enable() and intel_mid_pci_irq_enable() from reentrance. There are two cases which will cause reentrance. The first case is caused by suspend/hibernation. If pcibios_disable_irq is called during suspending/hibernating, we don't release the assigned IRQ number, otherwise it may break the suspend/hibernation. So late when pcibios_enable_irq is called during resume, we shouldn't allocate IRQ number again. The second case is that function acpi_pci_irq_enable() may be called twice for PCI devices present at boot time as below: 1) pci_acpi_init() --> acpi_pci_irq_enable() if pci_routeirq is true 2) pci_enable_device() --> pcibios_enable_device() --> acpi_pci_irq_enable() We can't kill kernel parameter pci_routeirq yet because it's still needed for debugging purpose. So flag irq_managed is introduced to track whether IRQ number is assigned by OS and to protect pirq_enable_irq(), acpi_pci_irq_enable() and intel_mid_pci_irq_enable() from reentrance. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Cc: Len Brown Link: http://lkml.kernel.org/r/1414387308-27148-13-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/pci/intel_mid_pci.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'arch/x86/pci/intel_mid_pci.c') diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index b9958c364075..44b9271580b5 100644 --- a/arch/x86/pci/intel_mid_pci.c +++ b/arch/x86/pci/intel_mid_pci.c @@ -210,6 +210,9 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) { int polarity; + if (dev->irq_managed && dev->irq > 0) + return 0; + if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) polarity = 0; /* active high */ else @@ -224,13 +227,18 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) if (mp_map_gsi_to_irq(dev->irq, IOAPIC_MAP_ALLOC) < 0) return -EBUSY; + dev->irq_managed = 1; + return 0; } static void intel_mid_pci_irq_disable(struct pci_dev *dev) { - if (!mp_should_keep_irq(&dev->dev) && dev->irq > 0) + if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed && + dev->irq > 0) { mp_unmap_irq(dev->irq); + dev->irq_managed = 0; + } } struct pci_ops intel_mid_pci_ops = { -- cgit v1.2.3