aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-03-20 09:56:19 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-03-20 09:56:19 -0400
commit9e8ce4b96b781b003e3174fbbc62e1d4388c8b8f (patch)
tree3823451bc7aba0d2601ec67bdb9b43a3e51ea2f3
parent06e5801b8cb3fc057d88cb4dc03c0b64b2744cda (diff)
Revert "x86/PCI: Refine the way to release PCI IRQ resources"
Commit b4b55cda5874 (Refine the way to release PCI IRQ resources) introduced a regression in the PCI IRQ resource management by causing the IRQ resource of a device, established when pci_enabled_device() is called on a fully disabled device, to be released when the driver is unbound from the device, regardless of the enable_cnt. This leads to the situation that an ill-behaved driver can now make a device unusable to subsequent drivers by an imbalance in their use of pci_enable/disable_device(). That is a serious problem for secondary drivers like vfio-pci, which are innocent of the transgressions of the previous driver. Since the solution of this problem is not immediate and requires further discussion, revert commit b4b55cda5874 and the issue it was supposed to address (a bug related to xen-pciback) will be taken care of in a different way going forward. Reported-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--arch/x86/include/asm/pci_x86.h2
-rw-r--r--arch/x86/pci/common.c34
-rw-r--r--arch/x86/pci/intel_mid_pci.c4
-rw-r--r--arch/x86/pci/irq.c15
-rw-r--r--drivers/acpi/pci_irq.c9
5 files changed, 32 insertions, 32 deletions
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index fa1195dae425..164e3f8d3c3d 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -93,6 +93,8 @@ extern raw_spinlock_t pci_config_lock;
93extern int (*pcibios_enable_irq)(struct pci_dev *dev); 93extern int (*pcibios_enable_irq)(struct pci_dev *dev);
94extern void (*pcibios_disable_irq)(struct pci_dev *dev); 94extern void (*pcibios_disable_irq)(struct pci_dev *dev);
95 95
96extern bool mp_should_keep_irq(struct device *dev);
97
96struct pci_raw_ops { 98struct pci_raw_ops {
97 int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn, 99 int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,
98 int reg, int len, u32 *val); 100 int reg, int len, u32 *val);
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 3d2612b68694..2fb384724ebb 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -513,31 +513,6 @@ void __init pcibios_set_cache_line_size(void)
513 } 513 }
514} 514}
515 515
516/*
517 * Some device drivers assume dev->irq won't change after calling
518 * pci_disable_device(). So delay releasing of IRQ resource to driver
519 * unbinding time. Otherwise it will break PM subsystem and drivers
520 * like xen-pciback etc.
521 */
522static int pci_irq_notifier(struct notifier_block *nb, unsigned long action,
523 void *data)
524{
525 struct pci_dev *dev = to_pci_dev(data);
526
527 if (action != BUS_NOTIFY_UNBOUND_DRIVER)
528 return NOTIFY_DONE;
529
530 if (pcibios_disable_irq)
531 pcibios_disable_irq(dev);
532
533 return NOTIFY_OK;
534}
535
536static struct notifier_block pci_irq_nb = {
537 .notifier_call = pci_irq_notifier,
538 .priority = INT_MIN,
539};
540
541int __init pcibios_init(void) 516int __init pcibios_init(void)
542{ 517{
543 if (!raw_pci_ops) { 518 if (!raw_pci_ops) {
@@ -550,9 +525,6 @@ int __init pcibios_init(void)
550 525
551 if (pci_bf_sort >= pci_force_bf) 526 if (pci_bf_sort >= pci_force_bf)
552 pci_sort_breadthfirst(); 527 pci_sort_breadthfirst();
553
554 bus_register_notifier(&pci_bus_type, &pci_irq_nb);
555
556 return 0; 528 return 0;
557} 529}
558 530
@@ -711,6 +683,12 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
711 return 0; 683 return 0;
712} 684}
713 685
686void pcibios_disable_device (struct pci_dev *dev)
687{
688 if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq)
689 pcibios_disable_irq(dev);
690}
691
714int pci_ext_cfg_avail(void) 692int pci_ext_cfg_avail(void)
715{ 693{
716 if (raw_pci_ext_ops) 694 if (raw_pci_ext_ops)
diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c
index efb849323c74..852aa4c92da0 100644
--- a/arch/x86/pci/intel_mid_pci.c
+++ b/arch/x86/pci/intel_mid_pci.c
@@ -234,10 +234,10 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
234 234
235static void intel_mid_pci_irq_disable(struct pci_dev *dev) 235static void intel_mid_pci_irq_disable(struct pci_dev *dev)
236{ 236{
237 if (dev->irq_managed && dev->irq > 0) { 237 if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed &&
238 dev->irq > 0) {
238 mp_unmap_irq(dev->irq); 239 mp_unmap_irq(dev->irq);
239 dev->irq_managed = 0; 240 dev->irq_managed = 0;
240 dev->irq = 0;
241 } 241 }
242} 242}
243 243
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index e71b3dbd87b8..5dc6ca5e1741 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -1256,9 +1256,22 @@ static int pirq_enable_irq(struct pci_dev *dev)
1256 return 0; 1256 return 0;
1257} 1257}
1258 1258
1259bool mp_should_keep_irq(struct device *dev)
1260{
1261 if (dev->power.is_prepared)
1262 return true;
1263#ifdef CONFIG_PM
1264 if (dev->power.runtime_status == RPM_SUSPENDING)
1265 return true;
1266#endif
1267
1268 return false;
1269}
1270
1259static void pirq_disable_irq(struct pci_dev *dev) 1271static void pirq_disable_irq(struct pci_dev *dev)
1260{ 1272{
1261 if (io_apic_assign_pci_irqs && dev->irq_managed && dev->irq) { 1273 if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) &&
1274 dev->irq_managed && dev->irq) {
1262 mp_unmap_irq(dev->irq); 1275 mp_unmap_irq(dev->irq);
1263 dev->irq = 0; 1276 dev->irq = 0;
1264 dev->irq_managed = 0; 1277 dev->irq_managed = 0;
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index e7f718d6918a..b1def411c0b8 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -485,6 +485,14 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
485 if (!pin || !dev->irq_managed || dev->irq <= 0) 485 if (!pin || !dev->irq_managed || dev->irq <= 0)
486 return; 486 return;
487 487
488 /* Keep IOAPIC pin configuration when suspending */
489 if (dev->dev.power.is_prepared)
490 return;
491#ifdef CONFIG_PM
492 if (dev->dev.power.runtime_status == RPM_SUSPENDING)
493 return;
494#endif
495
488 entry = acpi_pci_irq_lookup(dev, pin); 496 entry = acpi_pci_irq_lookup(dev, pin);
489 if (!entry) 497 if (!entry)
490 return; 498 return;
@@ -505,6 +513,5 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
505 if (gsi >= 0) { 513 if (gsi >= 0) {
506 acpi_unregister_gsi(gsi); 514 acpi_unregister_gsi(gsi);
507 dev->irq_managed = 0; 515 dev->irq_managed = 0;
508 dev->irq = 0;
509 } 516 }
510} 517}