From 9506063992cc0785246fd314a4a40b6314685aa8 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:20:00 +0800 Subject: x86, irq, mpparse: Use common irqdomain map interface to program IOAPIC pins Refine mpparse to use common irqdomain map interface to program IOAPIC pins, so we can unify the callsite to progam IOAPIC pins. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Link: http://lkml.kernel.org/r/1402302011-23642-32-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/pci/irq.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'arch/x86/pci/irq.c') diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 84112f55dd7a..e4200e5e775e 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -1227,8 +1227,6 @@ static int pirq_enable_irq(struct pci_dev *dev) } dev = temp_dev; if (irq >= 0) { - io_apic_set_pci_routing(&dev->dev, irq, - &irq_attr); dev->irq = irq; dev_info(&dev->dev, "PCI->APIC IRQ transform: " "INT %c -> IRQ %d\n", 'A' + pin - 1, irq); -- cgit v1.2.3 From c03b3b0738a56cf283b0d05256988d5e3c8bd719 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:20:08 +0800 Subject: x86, irq, mpparse: Release IOAPIC pin when PCI device is disabled Release IOAPIC pin associated with PCI device when the PCI device is disabled. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Link: http://lkml.kernel.org/r/1402302011-23642-40-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/mpparse.c | 1 + arch/x86/pci/irq.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'arch/x86/pci/irq.c') diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index faf503aa3b70..fde86d2b79f8 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -115,6 +115,7 @@ static void __init MP_bus_info(struct mpc_bus *m) static struct irq_domain_ops mp_ioapic_irqdomain_ops = { .map = mp_irqdomain_map, + .unmap = mp_irqdomain_unmap, }; static void __init MP_ioapic_info(struct mpc_ioapic *m) diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index e4200e5e775e..748cfe8ab322 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -26,6 +26,7 @@ static int acer_tm360_irqrouting; static struct irq_routing_table *pirq_table; static int pirq_enable_irq(struct pci_dev *dev); +static void pirq_disable_irq(struct pci_dev *dev); /* * Never use: 0, 1, 2 (timer, keyboard, and cascade) @@ -53,7 +54,7 @@ struct irq_router_handler { }; int (*pcibios_enable_irq)(struct pci_dev *dev) = pirq_enable_irq; -void (*pcibios_disable_irq)(struct pci_dev *dev) = NULL; +void (*pcibios_disable_irq)(struct pci_dev *dev) = pirq_disable_irq; /* * Check passed address for the PCI IRQ Routing Table signature @@ -1186,7 +1187,7 @@ void pcibios_penalize_isa_irq(int irq, int active) static int pirq_enable_irq(struct pci_dev *dev) { - u8 pin; + u8 pin = 0; pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); if (pin && !pcibios_lookup_irq(dev, 1)) { @@ -1252,3 +1253,11 @@ static int pirq_enable_irq(struct pci_dev *dev) } return 0; } + +static void pirq_disable_irq(struct pci_dev *dev) +{ + if (io_apic_assign_pci_irqs && dev->irq) { + mp_unmap_irq(dev->irq); + dev->irq = 0; + } +} -- cgit v1.2.3 From 3eec595235c17a74094daa1e02d1b0af2e9a7125 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Fri, 8 Aug 2014 14:07:51 +0800 Subject: 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 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: Grant Likely Cc: Len Brown Link: http://lkml.kernel.org/r/1407478071-29399-1-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/pci/intel_mid_pci.c | 2 +- arch/x86/pci/irq.c | 3 ++- drivers/acpi/pci_irq.c | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'arch/x86/pci/irq.c') 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) static void intel_mid_pci_irq_disable(struct pci_dev *dev) { - if (dev->irq > 0) + if (!dev->dev.power.is_prepared && dev->irq > 0) mp_unmap_irq(dev->irq); } 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) static void pirq_disable_irq(struct pci_dev *dev) { - if (io_apic_assign_pci_irqs && dev->irq) { + if (io_apic_assign_pci_irqs && !dev->dev.power.is_prepared && + dev->irq) { mp_unmap_irq(dev->irq); dev->irq = 0; } 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) if (!pin) return; + /* Keep IOAPIC pin configuration when suspending */ + if (dev->dev.power.is_prepared) + return; + entry = acpi_pci_irq_lookup(dev, pin); if (!entry) return; -- cgit v1.2.3 From 9eabc99a635a77cbf0948ce17d3cbc2b51680d4a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Fri, 29 Aug 2014 17:26:23 +0800 Subject: x86, irq, PCI: Keep IRQ assignment for runtime power management Now IOAPIC driver dynamically allocates IRQ numbers for IOAPIC pins. We need to keep IRQ assignment for PCI devices during runtime power management, otherwise it may cause failure of device wakeups. Commit 3eec595235c17a7 "x86, irq, PCI: Keep IRQ assignment for PCI devices during suspend/hibernation" has fixed the issue for suspend/ hibernation, we also need the same fix for runtime device sleep too. Fix: https://bugzilla.kernel.org/show_bug.cgi?id=83271 Reported-and-Tested-by: EmanueL Czirai Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Greg Kroah-Hartman Cc: EmanueL Czirai Cc: Benjamin Herrenschmidt Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Cc: Grant Likely Link: http://lkml.kernel.org/r/1409304383-18806-1-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/io_apic.h | 2 ++ arch/x86/kernel/apic/io_apic.c | 12 ++++++++++++ arch/x86/pci/intel_mid_pci.c | 2 +- arch/x86/pci/irq.c | 2 +- drivers/acpi/pci_irq.c | 4 ++++ 5 files changed, 20 insertions(+), 2 deletions(-) (limited to 'arch/x86/pci/irq.c') diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index 0aeed5ca356e..478c490f3654 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -227,6 +227,8 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned extern void io_apic_eoi(unsigned int apic, unsigned int vector); +extern bool mp_should_keep_irq(struct device *dev); + #else /* !CONFIG_X86_IO_APIC */ #define io_apic_assign_pci_irqs 0 diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 40a4aa3f4061..337ce5a9b15c 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -3959,6 +3959,18 @@ int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node) return ret; } +bool mp_should_keep_irq(struct device *dev) +{ + if (dev->power.is_prepared) + return true; +#ifdef CONFIG_PM_RUNTIME + if (dev->power.runtime_status == RPM_SUSPENDING) + return true; +#endif + + return false; +} + /* Enable IOAPIC early just for system timer */ void __init pre_init_apic_IRQ0(void) { diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index 3865116c51fb..b9958c364075 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) static void intel_mid_pci_irq_disable(struct pci_dev *dev) { - if (!dev->dev.power.is_prepared && dev->irq > 0) + if (!mp_should_keep_irq(&dev->dev) && dev->irq > 0) mp_unmap_irq(dev->irq); } diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index bc1a2c341891..eb500c2592ad 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -1256,7 +1256,7 @@ static int pirq_enable_irq(struct pci_dev *dev) static void pirq_disable_irq(struct pci_dev *dev) { - if (io_apic_assign_pci_irqs && !dev->dev.power.is_prepared && + if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) && dev->irq) { mp_unmap_irq(dev->irq); dev->irq = 0; diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index c96887d5289e..6e6b80eb0bba 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -484,6 +484,10 @@ void acpi_pci_irq_disable(struct pci_dev *dev) /* Keep IOAPIC pin configuration when suspending */ if (dev->dev.power.is_prepared) return; +#ifdef CONFIG_PM_RUNTIME + if (dev->dev.power.runtime_status == RPM_SUSPENDING) + return; +#endif entry = acpi_pci_irq_lookup(dev, pin); if (!entry) -- cgit v1.2.3