Skip to content

Commit cffe0a2

Browse files
Jiang LiuKAGA-KOKO
authored andcommitted
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 <[email protected]> Cc: Konrad Rzeszutek Wilk <[email protected]> Cc: Tony Luck <[email protected]> Cc: Joerg Roedel <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: Rafael J. Wysocki <[email protected]> Cc: Bjorn Helgaas <[email protected]> Cc: Randy Dunlap <[email protected]> Cc: Yinghai Lu <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Len Brown <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 67dc5e7 commit cffe0a2

File tree

4 files changed

+25
-4
lines changed

4 files changed

+25
-4
lines changed

arch/x86/pci/intel_mid_pci.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
210210
{
211211
int polarity;
212212

213+
if (dev->irq_managed && dev->irq > 0)
214+
return 0;
215+
213216
if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER)
214217
polarity = 0; /* active high */
215218
else
@@ -224,13 +227,18 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
224227
if (mp_map_gsi_to_irq(dev->irq, IOAPIC_MAP_ALLOC) < 0)
225228
return -EBUSY;
226229

230+
dev->irq_managed = 1;
231+
227232
return 0;
228233
}
229234

230235
static void intel_mid_pci_irq_disable(struct pci_dev *dev)
231236
{
232-
if (!mp_should_keep_irq(&dev->dev) && dev->irq > 0)
237+
if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed &&
238+
dev->irq > 0) {
233239
mp_unmap_irq(dev->irq);
240+
dev->irq_managed = 0;
241+
}
234242
}
235243

236244
struct pci_ops intel_mid_pci_ops = {

arch/x86/pci/irq.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,9 @@ static int pirq_enable_irq(struct pci_dev *dev)
12021202
int irq;
12031203
struct io_apic_irq_attr irq_attr;
12041204

1205+
if (dev->irq_managed && dev->irq > 0)
1206+
return 0;
1207+
12051208
irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
12061209
PCI_SLOT(dev->devfn),
12071210
pin - 1, &irq_attr);
@@ -1228,6 +1231,7 @@ static int pirq_enable_irq(struct pci_dev *dev)
12281231
}
12291232
dev = temp_dev;
12301233
if (irq >= 0) {
1234+
dev->irq_managed = 1;
12311235
dev->irq = irq;
12321236
dev_info(&dev->dev, "PCI->APIC IRQ transform: "
12331237
"INT %c -> IRQ %d\n", 'A' + pin - 1, irq);
@@ -1269,8 +1273,9 @@ bool mp_should_keep_irq(struct device *dev)
12691273
static void pirq_disable_irq(struct pci_dev *dev)
12701274
{
12711275
if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) &&
1272-
dev->irq) {
1276+
dev->irq_managed && dev->irq) {
12731277
mp_unmap_irq(dev->irq);
12741278
dev->irq = 0;
1279+
dev->irq_managed = 0;
12751280
}
12761281
}

drivers/acpi/pci_irq.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,9 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
413413
return 0;
414414
}
415415

416+
if (dev->irq_managed && dev->irq > 0)
417+
return 0;
418+
416419
entry = acpi_pci_irq_lookup(dev, pin);
417420
if (!entry) {
418421
/*
@@ -456,6 +459,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
456459
return rc;
457460
}
458461
dev->irq = rc;
462+
dev->irq_managed = 1;
459463

460464
if (link)
461465
snprintf(link_desc, sizeof(link_desc), " -> Link[%s]", link);
@@ -478,7 +482,7 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
478482
u8 pin;
479483

480484
pin = dev->pin;
481-
if (!pin)
485+
if (!pin || !dev->irq_managed || dev->irq <= 0)
482486
return;
483487

484488
/* Keep IOAPIC pin configuration when suspending */
@@ -506,6 +510,9 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
506510
*/
507511

508512
dev_dbg(&dev->dev, "PCI INT %c disabled\n", pin_name(pin));
509-
if (gsi >= 0 && dev->irq > 0)
513+
if (gsi >= 0) {
510514
acpi_unregister_gsi(gsi);
515+
dev->irq = 0;
516+
dev->irq_managed = 0;
517+
}
511518
}

include/linux/pci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ struct pci_dev {
349349
unsigned int __aer_firmware_first:1;
350350
unsigned int broken_intx_masking:1;
351351
unsigned int io_window_1k:1; /* Intel P2P bridge 1K I/O windows */
352+
unsigned int irq_managed:1;
352353
pci_dev_flags_t dev_flags;
353354
atomic_t enable_cnt; /* pci_enable_device has been called */
354355

0 commit comments

Comments
 (0)