diff options
-rw-r--r-- | drivers/acpi/pci_irq.c | 29 | ||||
-rw-r--r-- | include/linux/interrupt.h | 10 | ||||
-rw-r--r-- | kernel/irq/manage.c | 9 |
3 files changed, 43 insertions, 5 deletions
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index c8e169e46673..2c45dd3acc17 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/pci.h> | 33 | #include <linux/pci.h> |
34 | #include <linux/acpi.h> | 34 | #include <linux/acpi.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/interrupt.h> | ||
36 | 37 | ||
37 | #define PREFIX "ACPI: " | 38 | #define PREFIX "ACPI: " |
38 | 39 | ||
@@ -387,6 +388,23 @@ static inline int acpi_isa_register_gsi(struct pci_dev *dev) | |||
387 | } | 388 | } |
388 | #endif | 389 | #endif |
389 | 390 | ||
391 | static inline bool acpi_pci_irq_valid(struct pci_dev *dev, u8 pin) | ||
392 | { | ||
393 | #ifdef CONFIG_X86 | ||
394 | /* | ||
395 | * On x86 irq line 0xff means "unknown" or "no connection" | ||
396 | * (PCI 3.0, Section 6.2.4, footnote on page 223). | ||
397 | */ | ||
398 | if (dev->irq == 0xff) { | ||
399 | dev->irq = IRQ_NOTCONNECTED; | ||
400 | dev_warn(&dev->dev, "PCI INT %c: not connected\n", | ||
401 | pin_name(pin)); | ||
402 | return false; | ||
403 | } | ||
404 | #endif | ||
405 | return true; | ||
406 | } | ||
407 | |||
390 | int acpi_pci_irq_enable(struct pci_dev *dev) | 408 | int acpi_pci_irq_enable(struct pci_dev *dev) |
391 | { | 409 | { |
392 | struct acpi_prt_entry *entry; | 410 | struct acpi_prt_entry *entry; |
@@ -431,11 +449,14 @@ int acpi_pci_irq_enable(struct pci_dev *dev) | |||
431 | } else | 449 | } else |
432 | gsi = -1; | 450 | gsi = -1; |
433 | 451 | ||
434 | /* | ||
435 | * No IRQ known to the ACPI subsystem - maybe the BIOS / | ||
436 | * driver reported one, then use it. Exit in any case. | ||
437 | */ | ||
438 | if (gsi < 0) { | 452 | if (gsi < 0) { |
453 | /* | ||
454 | * No IRQ known to the ACPI subsystem - maybe the BIOS / | ||
455 | * driver reported one, then use it. Exit in any case. | ||
456 | */ | ||
457 | if (!acpi_pci_irq_valid(dev, pin)) | ||
458 | return 0; | ||
459 | |||
439 | if (acpi_isa_register_gsi(dev)) | 460 | if (acpi_isa_register_gsi(dev)) |
440 | dev_warn(&dev->dev, "PCI INT %c: no GSI\n", | 461 | dev_warn(&dev->dev, "PCI INT %c: no GSI\n", |
441 | pin_name(pin)); | 462 | pin_name(pin)); |
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 0e95fcc75b2a..358076eda364 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h | |||
@@ -125,6 +125,16 @@ struct irqaction { | |||
125 | 125 | ||
126 | extern irqreturn_t no_action(int cpl, void *dev_id); | 126 | extern irqreturn_t no_action(int cpl, void *dev_id); |
127 | 127 | ||
128 | /* | ||
129 | * If a (PCI) device interrupt is not connected we set dev->irq to | ||
130 | * IRQ_NOTCONNECTED. This causes request_irq() to fail with -ENOTCONN, so we | ||
131 | * can distingiush that case from other error returns. | ||
132 | * | ||
133 | * 0x80000000 is guaranteed to be outside the available range of interrupts | ||
134 | * and easy to distinguish from other possible incorrect values. | ||
135 | */ | ||
136 | #define IRQ_NOTCONNECTED (1U << 31) | ||
137 | |||
128 | extern int __must_check | 138 | extern int __must_check |
129 | request_threaded_irq(unsigned int irq, irq_handler_t handler, | 139 | request_threaded_irq(unsigned int irq, irq_handler_t handler, |
130 | irq_handler_t thread_fn, | 140 | irq_handler_t thread_fn, |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 841187239adc..e79e60f50bce 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -1609,6 +1609,9 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, | |||
1609 | struct irq_desc *desc; | 1609 | struct irq_desc *desc; |
1610 | int retval; | 1610 | int retval; |
1611 | 1611 | ||
1612 | if (irq == IRQ_NOTCONNECTED) | ||
1613 | return -ENOTCONN; | ||
1614 | |||
1612 | /* | 1615 | /* |
1613 | * Sanity-check: shared interrupts must pass in a real dev-ID, | 1616 | * Sanity-check: shared interrupts must pass in a real dev-ID, |
1614 | * otherwise we'll have trouble later trying to figure out | 1617 | * otherwise we'll have trouble later trying to figure out |
@@ -1699,9 +1702,13 @@ EXPORT_SYMBOL(request_threaded_irq); | |||
1699 | int request_any_context_irq(unsigned int irq, irq_handler_t handler, | 1702 | int request_any_context_irq(unsigned int irq, irq_handler_t handler, |
1700 | unsigned long flags, const char *name, void *dev_id) | 1703 | unsigned long flags, const char *name, void *dev_id) |
1701 | { | 1704 | { |
1702 | struct irq_desc *desc = irq_to_desc(irq); | 1705 | struct irq_desc *desc; |
1703 | int ret; | 1706 | int ret; |
1704 | 1707 | ||
1708 | if (irq == IRQ_NOTCONNECTED) | ||
1709 | return -ENOTCONN; | ||
1710 | |||
1711 | desc = irq_to_desc(irq); | ||
1705 | if (!desc) | 1712 | if (!desc) |
1706 | return -EINVAL; | 1713 | return -EINVAL; |
1707 | 1714 | ||