[Patch v4 09/16] 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 --- arch/x86/pci/intel_mid_pci.c |9 - arch/x86/pci/irq.c |7 ++- drivers/acpi/pci_irq.c | 11 +-- include/linux/pci.h |1 + 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index 3865116c51fb..6a855fef78fc 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,17 @@ 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 (!dev->dev.power.is_prepared && dev->irq > 0) + if (!dev->dev.power.is_prepared && dev->irq_managed && dev->irq > 0) { mp_unmap_irq(dev->irq); + dev->irq_managed = 0; + } } struct pci_ops intel_mid_pci_ops = { diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index bc1a2c341891..dd1369dbcc42 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -1202,6 +1202,9 @@ static int pirq_enable_irq(struct pci_dev *dev) int irq; struct io_apic_irq_attr irq_attr; + if (dev->irq_managed && dev->irq > 0) + return 0; + irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin - 1, _attr); @@ -1228,6 +1231,7 @@ static int pirq_enable_irq(struct pci_dev *dev) } dev = temp_dev; if (irq >= 0) { + dev->irq_managed = 1; dev->irq = irq; dev_info(>dev, "PCI->APIC IRQ transform: " "INT %c -> IRQ %d\n", 'A' + pin - 1, irq); @@ -1257,8 +1261,9 @@ 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 && - dev->irq) { + dev->irq_managed && dev->irq > 0) { mp_unmap_irq(dev->irq); dev->irq = 0; + dev->irq_managed = 0; } } diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index c96887d5289e..4a89701dfe36 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -413,6 +413,9 @@ int acpi_pci_irq_enable(struct pci_dev *dev) return 0; } + if (dev->irq_managed && dev->irq > 0) + return 0; + entry = acpi_pci_irq_lookup(dev, pin); if (!entry) { /* @@ -456,6 +459,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) return rc; } dev->irq = rc; + dev->irq_managed = 1; if (link) snprintf(link_desc, sizeof(link_desc), " -> Link[%s]", link); @@ -478,7 +482,7 @@ void acpi_pci_irq_disable(struct pci_dev *dev) u8 pin; pin = dev->pin; - if (!pin) + if (!pin || !dev->irq_managed || dev->irq <= 0) return; /* Keep IOAPIC pin configuration when suspending */ @@ -502,6 +506,9 @@ void acpi_pci_irq_disable(struct pci_dev *dev) */ dev_dbg(>dev, "PCI INT %c disabled\n", pin_name(pin)); - if (gsi >= 0 && dev->irq > 0) + if (gsi >= 0)
[Patch v4 09/16] 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 jiang@linux.intel.com --- arch/x86/pci/intel_mid_pci.c |9 - arch/x86/pci/irq.c |7 ++- drivers/acpi/pci_irq.c | 11 +-- include/linux/pci.h |1 + 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index 3865116c51fb..6a855fef78fc 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,17 @@ 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 (!dev-dev.power.is_prepared dev-irq 0) + if (!dev-dev.power.is_prepared dev-irq_managed dev-irq 0) { mp_unmap_irq(dev-irq); + dev-irq_managed = 0; + } } struct pci_ops intel_mid_pci_ops = { diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index bc1a2c341891..dd1369dbcc42 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -1202,6 +1202,9 @@ static int pirq_enable_irq(struct pci_dev *dev) int irq; struct io_apic_irq_attr irq_attr; + if (dev-irq_managed dev-irq 0) + return 0; + irq = IO_APIC_get_PCI_irq_vector(dev-bus-number, PCI_SLOT(dev-devfn), pin - 1, irq_attr); @@ -1228,6 +1231,7 @@ static int pirq_enable_irq(struct pci_dev *dev) } dev = temp_dev; if (irq = 0) { + dev-irq_managed = 1; dev-irq = irq; dev_info(dev-dev, PCI-APIC IRQ transform: INT %c - IRQ %d\n, 'A' + pin - 1, irq); @@ -1257,8 +1261,9 @@ 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 - dev-irq) { + dev-irq_managed dev-irq 0) { mp_unmap_irq(dev-irq); dev-irq = 0; + dev-irq_managed = 0; } } diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index c96887d5289e..4a89701dfe36 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -413,6 +413,9 @@ int acpi_pci_irq_enable(struct pci_dev *dev) return 0; } + if (dev-irq_managed dev-irq 0) + return 0; + entry = acpi_pci_irq_lookup(dev, pin); if (!entry) { /* @@ -456,6 +459,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) return rc; } dev-irq = rc; + dev-irq_managed = 1; if (link) snprintf(link_desc, sizeof(link_desc), - Link[%s], link); @@ -478,7 +482,7 @@ void acpi_pci_irq_disable(struct pci_dev *dev) u8 pin; pin = dev-pin; - if (!pin) + if (!pin || !dev-irq_managed || dev-irq = 0) return; /* Keep IOAPIC pin configuration when suspending */ @@ -502,6 +506,9 @@ void acpi_pci_irq_disable(struct pci_dev *dev) */ dev_dbg(dev-dev, PCI INT %c disabled\n, pin_name(pin)); - if (gsi = 0 dev-irq 0) + if (gsi = 0) { acpi_unregister_gsi(gsi); +