Skip to content

Commit

Permalink
Revert "x86/PCI: Refine the way to release PCI IRQ resources"
Browse files Browse the repository at this point in the history
Commit b4b55cd (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 b4b55cd 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>
  • Loading branch information
Rafael J. Wysocki committed Mar 20, 2015
1 parent 06e5801 commit 9e8ce4b
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 32 deletions.
2 changes: 2 additions & 0 deletions arch/x86/include/asm/pci_x86.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ extern raw_spinlock_t pci_config_lock;
extern int (*pcibios_enable_irq)(struct pci_dev *dev);
extern void (*pcibios_disable_irq)(struct pci_dev *dev);

extern bool mp_should_keep_irq(struct device *dev);

struct pci_raw_ops {
int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,
int reg, int len, u32 *val);
Expand Down
34 changes: 6 additions & 28 deletions arch/x86/pci/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -513,31 +513,6 @@ void __init pcibios_set_cache_line_size(void)
}
}

/*
* Some device drivers assume dev->irq won't change after calling
* pci_disable_device(). So delay releasing of IRQ resource to driver
* unbinding time. Otherwise it will break PM subsystem and drivers
* like xen-pciback etc.
*/
static int pci_irq_notifier(struct notifier_block *nb, unsigned long action,
void *data)
{
struct pci_dev *dev = to_pci_dev(data);

if (action != BUS_NOTIFY_UNBOUND_DRIVER)
return NOTIFY_DONE;

if (pcibios_disable_irq)
pcibios_disable_irq(dev);

return NOTIFY_OK;
}

static struct notifier_block pci_irq_nb = {
.notifier_call = pci_irq_notifier,
.priority = INT_MIN,
};

int __init pcibios_init(void)
{
if (!raw_pci_ops) {
Expand All @@ -550,9 +525,6 @@ int __init pcibios_init(void)

if (pci_bf_sort >= pci_force_bf)
pci_sort_breadthfirst();

bus_register_notifier(&pci_bus_type, &pci_irq_nb);

return 0;
}

Expand Down Expand Up @@ -711,6 +683,12 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
return 0;
}

void pcibios_disable_device (struct pci_dev *dev)
{
if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq)
pcibios_disable_irq(dev);
}

int pci_ext_cfg_avail(void)
{
if (raw_pci_ext_ops)
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/pci/intel_mid_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,10 @@ 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_managed && 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;
dev->irq = 0;
}
}

Expand Down
15 changes: 14 additions & 1 deletion arch/x86/pci/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1256,9 +1256,22 @@ static int pirq_enable_irq(struct pci_dev *dev)
return 0;
}

bool mp_should_keep_irq(struct device *dev)
{
if (dev->power.is_prepared)
return true;
#ifdef CONFIG_PM
if (dev->power.runtime_status == RPM_SUSPENDING)
return true;
#endif

return false;
}

static void pirq_disable_irq(struct pci_dev *dev)
{
if (io_apic_assign_pci_irqs && dev->irq_managed && dev->irq) {
if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) &&
dev->irq_managed && dev->irq) {
mp_unmap_irq(dev->irq);
dev->irq = 0;
dev->irq_managed = 0;
Expand Down
9 changes: 8 additions & 1 deletion drivers/acpi/pci_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,14 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
if (!pin || !dev->irq_managed || dev->irq <= 0)
return;

/* Keep IOAPIC pin configuration when suspending */
if (dev->dev.power.is_prepared)
return;
#ifdef CONFIG_PM
if (dev->dev.power.runtime_status == RPM_SUSPENDING)
return;
#endif

entry = acpi_pci_irq_lookup(dev, pin);
if (!entry)
return;
Expand All @@ -505,6 +513,5 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
if (gsi >= 0) {
acpi_unregister_gsi(gsi);
dev->irq_managed = 0;
dev->irq = 0;
}
}

0 comments on commit 9e8ce4b

Please sign in to comment.