aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2014-08-08 02:07:51 -0400
committerThomas Gleixner <tglx@linutronix.de>2014-08-08 05:14:45 -0400
commit3eec595235c17a74094daa1e02d1b0af2e9a7125 (patch)
tree8311a41b3eef9c2758d342238ec78a6fc14d3567
parent5e3bf215f4f2efc0af89e6dbc5da789744aeb5d7 (diff)
x86, irq, PCI: Keep IRQ assignment for PCI devices during suspend/hibernation
Now IOAPIC driver dynamically allocates IRQ numbers for IOAPIC pins. We need to keep IRQ assignment for PCI devices during suspend/hibernation, otherwise it may cause failure of suspend/hibernation due to: 1) Device driver calls pci_enable_device() to allocate an IRQ number and register interrupt handler on the returned IRQ. 2) Device driver's suspend callback calls pci_disable_device() and release assigned IRQ in turn. 3) Device driver's resume callback calls pci_enable_device() to allocate IRQ number again. A different IRQ number may be assigned by IOAPIC driver this time. 4) Now the hardware delivers interrupt to the new IRQ but interrupt handler is still registered against the old IRQ, so it breaks suspend/hibernation. To fix this issue, we keep IRQ assignment during suspend/hibernation. Flag pci_dev.dev.power.is_prepared is used to detect that pci_disable_device() is called during suspend/hibernation. Reported-and-Tested-by: Borislav Petkov <bp@suse.de> Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Joerg Roedel <joro@8bytes.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: Yinghai Lu <yinghai@kernel.org> Cc: Grant Likely <grant.likely@linaro.org> Cc: Len Brown <lenb@kernel.org> Link: http://lkml.kernel.org/r/1407478071-29399-1-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/pci/intel_mid_pci.c2
-rw-r--r--arch/x86/pci/irq.c3
-rw-r--r--drivers/acpi/pci_irq.c4
3 files changed, 7 insertions, 2 deletions
diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c
index 09fece368592..3865116c51fb 100644
--- a/arch/x86/pci/intel_mid_pci.c
+++ b/arch/x86/pci/intel_mid_pci.c
@@ -229,7 +229,7 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
229 229
230static void intel_mid_pci_irq_disable(struct pci_dev *dev) 230static void intel_mid_pci_irq_disable(struct pci_dev *dev)
231{ 231{
232 if (dev->irq > 0) 232 if (!dev->dev.power.is_prepared && dev->irq > 0)
233 mp_unmap_irq(dev->irq); 233 mp_unmap_irq(dev->irq);
234} 234}
235 235
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 748cfe8ab322..bc1a2c341891 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -1256,7 +1256,8 @@ static int pirq_enable_irq(struct pci_dev *dev)
1256 1256
1257static void pirq_disable_irq(struct pci_dev *dev) 1257static void pirq_disable_irq(struct pci_dev *dev)
1258{ 1258{
1259 if (io_apic_assign_pci_irqs && dev->irq) { 1259 if (io_apic_assign_pci_irqs && !dev->dev.power.is_prepared &&
1260 dev->irq) {
1260 mp_unmap_irq(dev->irq); 1261 mp_unmap_irq(dev->irq);
1261 dev->irq = 0; 1262 dev->irq = 0;
1262 } 1263 }
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 6ba463ceccc6..c96887d5289e 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -481,6 +481,10 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
481 if (!pin) 481 if (!pin)
482 return; 482 return;
483 483
484 /* Keep IOAPIC pin configuration when suspending */
485 if (dev->dev.power.is_prepared)
486 return;
487
484 entry = acpi_pci_irq_lookup(dev, pin); 488 entry = acpi_pci_irq_lookup(dev, pin);
485 if (!entry) 489 if (!entry)
486 return; 490 return;