* [PATCH v5] x86/PCI: Recognize that Interrupt Line 255 means "not connected"
@ 2016-02-15 3:25 Chen Fan
2016-02-15 3:49 ` kbuild test robot
2016-02-15 4:53 ` Chen Fan
0 siblings, 2 replies; 3+ messages in thread
From: Chen Fan @ 2016-02-15 3:25 UTC (permalink / raw)
To: linux-acpi; +Cc: linux-kernel, rjw, lenb, bhelgaas, rafael
Per the x86-specific footnote to PCI spec r3.0, sec 6.2.4, the value 255 in
the Interrupt Line register means "unknown" or "no connection."
Previously, when we couldn't derive an IRQ from the _PRT, we fell back to
using the value from Interrupt Line as an IRQ. It's questionable whether
we should do that at all, but the spec clearly suggests we shouldn't do it
for the value 255 on x86.
Calling request_irq() with IRQ 255 may succeed, but the driver won't
receive any interrupts. Or, if IRQ 255 is shared with another device, it
may succeed, and the driver's ISR will be called at random times when the
*other* device interrupts. Or it may fail if another device is using IRQ
255 with incompatible flags. What we *want* is for request_irq() to fail
predictably so the driver can fall back to polling.
On x86, assume 255 in the Interrupt Line means the INTx line is not
connected. In that case, set dev->irq to IRQ_NOTCONNECTED so request_irq()
will fail gracefully with -ENOTCONN.
We found this problem on a system where Secure Boot firmware assigned
Interrupt Line 255 to an i801_smbus device and another device was already
using MSI-X IRQ 255. This was in v3.10, where i801_probe() fails if
request_irq() fails:
i801_smbus 0000:00:1f.3: enabling device (0140 -> 0143)
i801_smbus 0000:00:1f.3: can't derive routing for PCI INT C
i801_smbus 0000:00:1f.3: PCI INT C: no GSI
genirq: Flags mismatch irq 255. 00000080 (i801_smbus) vs. 00000000 (megasa)
CPU: 0 PID: 2487 Comm: kworker/0:1 Not tainted 3.10.0-229.el7.x86_64 #1
Hardware name: FUJITSU PRIMEQUEST 2800E2/D3736, BIOS PRIMEQUEST 2000 Serie5
Call Trace:
dump_stack+0x19/0x1b
__setup_irq+0x54a/0x570
request_threaded_irq+0xcc/0x170
i801_probe+0x32f/0x508 [i2c_i801]
local_pci_probe+0x45/0xa0
i801_smbus 0000:00:1f.3: Failed to allocate irq 255: -16
i801_smbus: probe of 0000:00:1f.3 failed with error -16
After aeb8a3d16ae0 ("i2c: i801: Check if interrupts are disabled"),
i801_probe() will fall back to polling if request_irq() fails. But we
still need this patch because request_irq() may succeed or fail depending
on other devices in the system. If request_irq() fails, i801_smbus will
work by falling back to polling, but if it succeeds, i801_smbus won't work
because it expects interrupts that it may not receive.
Signed-off-by: Chen Fan <chen.fan.fnst@cn.fujitsu.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
---
drivers/acpi/pci_irq.c | 29 +++++++++++++++++++++++++----
include/linux/interrupt.h | 10 ++++++++++
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 d30184c..0227cc6 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -33,6 +33,7 @@
#include <linux/pci.h>
#include <linux/acpi.h>
#include <linux/slab.h>
+#include <linux/interrupt.h>
#define PREFIX "ACPI: "
@@ -387,6 +388,23 @@ static inline int acpi_isa_register_gsi(struct pci_dev *dev)
}
#endif
+static inline bool acpi_pci_irq_valid(struct pci_dev *dev)
+{
+#ifdef CONFIG_X86
+ /*
+ * On x86 irq line 0xff means "unknown" or "no connection"
+ * (PCI 3.0, Section 6.2.4, footnote on page 223).
+ */
+ if (dev->irq == 0xff) {
+ dev->irq = IRQ_NOTCONNECTED;
+ dev_warn(&dev->dev, "PCI INT %c: not connected\n",
+ pin_name(pin));
+ return false;
+ }
+#endif
+ return true;
+}
+
int acpi_pci_irq_enable(struct pci_dev *dev)
{
struct acpi_prt_entry *entry;
@@ -431,11 +449,14 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
} else
gsi = -1;
- /*
- * No IRQ known to the ACPI subsystem - maybe the BIOS /
- * driver reported one, then use it. Exit in any case.
- */
if (gsi < 0) {
+ /*
+ * No IRQ known to the ACPI subsystem - maybe the BIOS /
+ * driver reported one, then use it. Exit in any case.
+ */
+ if (!acpi_pci_irq_valid(dev, pin))
+ return 0;
+
if (acpi_isa_register_gsi(dev))
dev_warn(&dev->dev, "PCI INT %c: no GSI\n",
pin_name(pin));
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index cb30edb..12f7da4 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -125,6 +125,16 @@ struct irqaction {
extern irqreturn_t no_action(int cpl, void *dev_id);
+/*
+ * If a (PCI) device interrupt is not connected we set dev->irq to
+ * IRQ_NOTCONNECTED. This causes request_irq() to fail with -ENOTCONN, so we
+ * can distingiush that case from other error returns.
+ *
+ * 0x80000000 is guaranteed to be outside the available range of interrupts
+ * and easy to distinguish from other possible incorrect values.
+ */
+#define IRQ_NOTCONNECTED (1U << 31)
+
extern int __must_check
request_threaded_irq(unsigned int irq, irq_handler_t handler,
irq_handler_t thread_fn,
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 8411872..e79e60f 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,
struct irq_desc *desc;
int retval;
+ if (irq == IRQ_NOTCONNECTED)
+ return -ENOTCONN;
+
/*
* Sanity-check: shared interrupts must pass in a real dev-ID,
* otherwise we'll have trouble later trying to figure out
@@ -1699,9 +1702,13 @@ EXPORT_SYMBOL(request_threaded_irq);
int request_any_context_irq(unsigned int irq, irq_handler_t handler,
unsigned long flags, const char *name, void *dev_id)
{
- struct irq_desc *desc = irq_to_desc(irq);
+ struct irq_desc *desc;
int ret;
+ if (irq == IRQ_NOTCONNECTED)
+ return -ENOTCONN;
+
+ desc = irq_to_desc(irq);
if (!desc)
return -EINVAL;
--
1.9.3
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v5] x86/PCI: Recognize that Interrupt Line 255 means "not connected"
2016-02-15 3:25 [PATCH v5] x86/PCI: Recognize that Interrupt Line 255 means "not connected" Chen Fan
@ 2016-02-15 3:49 ` kbuild test robot
2016-02-15 4:53 ` Chen Fan
1 sibling, 0 replies; 3+ messages in thread
From: kbuild test robot @ 2016-02-15 3:49 UTC (permalink / raw)
To: Chen Fan
Cc: kbuild-all, linux-acpi, linux-kernel, rjw, lenb, bhelgaas, rafael
[-- Attachment #1: Type: text/plain, Size: 6036 bytes --]
Hi Chen,
[auto build test ERROR on pm/linux-next]
[also build test ERROR on v4.5-rc4 next-20160212]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Chen-Fan/x86-PCI-Recognize-that-Interrupt-Line-255-means-not-connected/20160215-113403
base: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
config: x86_64-randconfig-x004-201607 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All error/warnings (new ones prefixed by >>):
drivers/acpi/pci_irq.c: In function 'acpi_pci_irq_valid':
>> drivers/acpi/pci_irq.c:401:14: error: 'pin' undeclared (first use in this function)
pin_name(pin));
^
drivers/acpi/pci_irq.c:401:14: note: each undeclared identifier is reported only once for each function it appears in
In file included from include/uapi/linux/stddef.h:1:0,
from include/linux/stddef.h:4,
from include/uapi/linux/posix_types.h:4,
from include/uapi/linux/types.h:13,
from include/linux/types.h:5,
from include/linux/list.h:4,
from include/linux/dmi.h:4,
from drivers/acpi/pci_irq.c:26:
drivers/acpi/pci_irq.c: In function 'acpi_pci_irq_enable':
>> drivers/acpi/pci_irq.c:457:8: error: too many arguments to function 'acpi_pci_irq_valid'
if (!acpi_pci_irq_valid(dev, pin))
^
include/linux/compiler.h:147:28: note: in definition of macro '__trace_if'
if (__builtin_constant_p((cond)) ? !!(cond) : \
^
>> drivers/acpi/pci_irq.c:457:3: note: in expansion of macro 'if'
if (!acpi_pci_irq_valid(dev, pin))
^
drivers/acpi/pci_irq.c:391:20: note: declared here
static inline bool acpi_pci_irq_valid(struct pci_dev *dev)
^
In file included from include/uapi/linux/stddef.h:1:0,
from include/linux/stddef.h:4,
from include/uapi/linux/posix_types.h:4,
from include/uapi/linux/types.h:13,
from include/linux/types.h:5,
from include/linux/list.h:4,
from include/linux/dmi.h:4,
from drivers/acpi/pci_irq.c:26:
>> drivers/acpi/pci_irq.c:457:8: error: too many arguments to function 'acpi_pci_irq_valid'
if (!acpi_pci_irq_valid(dev, pin))
^
include/linux/compiler.h:147:40: note: in definition of macro '__trace_if'
if (__builtin_constant_p((cond)) ? !!(cond) : \
^
>> drivers/acpi/pci_irq.c:457:3: note: in expansion of macro 'if'
if (!acpi_pci_irq_valid(dev, pin))
^
drivers/acpi/pci_irq.c:391:20: note: declared here
static inline bool acpi_pci_irq_valid(struct pci_dev *dev)
^
In file included from include/uapi/linux/stddef.h:1:0,
from include/linux/stddef.h:4,
from include/uapi/linux/posix_types.h:4,
from include/uapi/linux/types.h:13,
from include/linux/types.h:5,
from include/linux/list.h:4,
from include/linux/dmi.h:4,
from drivers/acpi/pci_irq.c:26:
>> drivers/acpi/pci_irq.c:457:8: error: too many arguments to function 'acpi_pci_irq_valid'
if (!acpi_pci_irq_valid(dev, pin))
^
include/linux/compiler.h:158:16: note: in definition of macro '__trace_if'
______r = !!(cond); \
^
>> drivers/acpi/pci_irq.c:457:3: note: in expansion of macro 'if'
if (!acpi_pci_irq_valid(dev, pin))
^
drivers/acpi/pci_irq.c:391:20: note: declared here
static inline bool acpi_pci_irq_valid(struct pci_dev *dev)
^
vim +/pin +401 drivers/acpi/pci_irq.c
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
408 int acpi_pci_irq_enable(struct pci_dev *dev)
409 {
410 struct acpi_prt_entry *entry;
411 int gsi;
412 u8 pin;
413 int triggering = ACPI_LEVEL_SENSITIVE;
414 int polarity = ACPI_ACTIVE_LOW;
415 char *link = NULL;
416 char link_desc[16];
417 int rc;
418
419 pin = dev->pin;
420 if (!pin) {
421 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
422 "No interrupt pin configured for device %s\n",
423 pci_name(dev)));
424 return 0;
425 }
426
427 if (pci_has_managed_irq(dev))
428 return 0;
429
430 entry = acpi_pci_irq_lookup(dev, pin);
431 if (!entry) {
432 /*
433 * IDE legacy mode controller IRQs are magic. Why do compat
434 * extensions always make such a nasty mess.
435 */
436 if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE &&
437 (dev->class & 0x05) == 0)
438 return 0;
439 }
440
441 if (entry) {
442 if (entry->link)
443 gsi = acpi_pci_link_allocate_irq(entry->link,
444 entry->index,
445 &triggering, &polarity,
446 &link);
447 else
448 gsi = entry->index;
449 } else
450 gsi = -1;
451
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
460 if (acpi_isa_register_gsi(dev))
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 21969 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v5] x86/PCI: Recognize that Interrupt Line 255 means "not connected"
2016-02-15 3:25 [PATCH v5] x86/PCI: Recognize that Interrupt Line 255 means "not connected" Chen Fan
2016-02-15 3:49 ` kbuild test robot
@ 2016-02-15 4:53 ` Chen Fan
1 sibling, 0 replies; 3+ messages in thread
From: Chen Fan @ 2016-02-15 4:53 UTC (permalink / raw)
To: linux-acpi; +Cc: linux-kernel, rjw, lenb, bhelgaas, rafael
Oh, it's my fault to send this wrong patch, so sorry for that. pls
ignore this patch.
I has tested the new patch, it works fine on my environment. I have
resent it.
Thanks,
Chen
On 02/15/2016 11:25 AM, Chen Fan wrote:
> Per the x86-specific footnote to PCI spec r3.0, sec 6.2.4, the value 255 in
> the Interrupt Line register means "unknown" or "no connection."
> Previously, when we couldn't derive an IRQ from the _PRT, we fell back to
> using the value from Interrupt Line as an IRQ. It's questionable whether
> we should do that at all, but the spec clearly suggests we shouldn't do it
> for the value 255 on x86.
>
> Calling request_irq() with IRQ 255 may succeed, but the driver won't
> receive any interrupts. Or, if IRQ 255 is shared with another device, it
> may succeed, and the driver's ISR will be called at random times when the
> *other* device interrupts. Or it may fail if another device is using IRQ
> 255 with incompatible flags. What we *want* is for request_irq() to fail
> predictably so the driver can fall back to polling.
>
> On x86, assume 255 in the Interrupt Line means the INTx line is not
> connected. In that case, set dev->irq to IRQ_NOTCONNECTED so request_irq()
> will fail gracefully with -ENOTCONN.
>
> We found this problem on a system where Secure Boot firmware assigned
> Interrupt Line 255 to an i801_smbus device and another device was already
> using MSI-X IRQ 255. This was in v3.10, where i801_probe() fails if
> request_irq() fails:
>
> i801_smbus 0000:00:1f.3: enabling device (0140 -> 0143)
> i801_smbus 0000:00:1f.3: can't derive routing for PCI INT C
> i801_smbus 0000:00:1f.3: PCI INT C: no GSI
> genirq: Flags mismatch irq 255. 00000080 (i801_smbus) vs. 00000000 (megasa)
> CPU: 0 PID: 2487 Comm: kworker/0:1 Not tainted 3.10.0-229.el7.x86_64 #1
> Hardware name: FUJITSU PRIMEQUEST 2800E2/D3736, BIOS PRIMEQUEST 2000 Serie5
> Call Trace:
> dump_stack+0x19/0x1b
> __setup_irq+0x54a/0x570
> request_threaded_irq+0xcc/0x170
> i801_probe+0x32f/0x508 [i2c_i801]
> local_pci_probe+0x45/0xa0
> i801_smbus 0000:00:1f.3: Failed to allocate irq 255: -16
> i801_smbus: probe of 0000:00:1f.3 failed with error -16
>
> After aeb8a3d16ae0 ("i2c: i801: Check if interrupts are disabled"),
> i801_probe() will fall back to polling if request_irq() fails. But we
> still need this patch because request_irq() may succeed or fail depending
> on other devices in the system. If request_irq() fails, i801_smbus will
> work by falling back to polling, but if it succeeds, i801_smbus won't work
> because it expects interrupts that it may not receive.
>
> Signed-off-by: Chen Fan <chen.fan.fnst@cn.fujitsu.com>
> Acked-by: Thomas Gleixner <tglx@linutronix.de>
> Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> ---
> drivers/acpi/pci_irq.c | 29 +++++++++++++++++++++++++----
> include/linux/interrupt.h | 10 ++++++++++
> 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 d30184c..0227cc6 100644
> --- a/drivers/acpi/pci_irq.c
> +++ b/drivers/acpi/pci_irq.c
> @@ -33,6 +33,7 @@
> #include <linux/pci.h>
> #include <linux/acpi.h>
> #include <linux/slab.h>
> +#include <linux/interrupt.h>
>
> #define PREFIX "ACPI: "
>
> @@ -387,6 +388,23 @@ static inline int acpi_isa_register_gsi(struct pci_dev *dev)
> }
> #endif
>
> +static inline bool acpi_pci_irq_valid(struct pci_dev *dev)
> +{
> +#ifdef CONFIG_X86
> + /*
> + * On x86 irq line 0xff means "unknown" or "no connection"
> + * (PCI 3.0, Section 6.2.4, footnote on page 223).
> + */
> + if (dev->irq == 0xff) {
> + dev->irq = IRQ_NOTCONNECTED;
> + dev_warn(&dev->dev, "PCI INT %c: not connected\n",
> + pin_name(pin));
> + return false;
> + }
> +#endif
> + return true;
> +}
> +
> int acpi_pci_irq_enable(struct pci_dev *dev)
> {
> struct acpi_prt_entry *entry;
> @@ -431,11 +449,14 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
> } else
> gsi = -1;
>
> - /*
> - * No IRQ known to the ACPI subsystem - maybe the BIOS /
> - * driver reported one, then use it. Exit in any case.
> - */
> if (gsi < 0) {
> + /*
> + * No IRQ known to the ACPI subsystem - maybe the BIOS /
> + * driver reported one, then use it. Exit in any case.
> + */
> + if (!acpi_pci_irq_valid(dev, pin))
> + return 0;
> +
> if (acpi_isa_register_gsi(dev))
> dev_warn(&dev->dev, "PCI INT %c: no GSI\n",
> pin_name(pin));
> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
> index cb30edb..12f7da4 100644
> --- a/include/linux/interrupt.h
> +++ b/include/linux/interrupt.h
> @@ -125,6 +125,16 @@ struct irqaction {
>
> extern irqreturn_t no_action(int cpl, void *dev_id);
>
> +/*
> + * If a (PCI) device interrupt is not connected we set dev->irq to
> + * IRQ_NOTCONNECTED. This causes request_irq() to fail with -ENOTCONN, so we
> + * can distingiush that case from other error returns.
> + *
> + * 0x80000000 is guaranteed to be outside the available range of interrupts
> + * and easy to distinguish from other possible incorrect values.
> + */
> +#define IRQ_NOTCONNECTED (1U << 31)
> +
> extern int __must_check
> request_threaded_irq(unsigned int irq, irq_handler_t handler,
> irq_handler_t thread_fn,
> diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
> index 8411872..e79e60f 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,
> struct irq_desc *desc;
> int retval;
>
> + if (irq == IRQ_NOTCONNECTED)
> + return -ENOTCONN;
> +
> /*
> * Sanity-check: shared interrupts must pass in a real dev-ID,
> * otherwise we'll have trouble later trying to figure out
> @@ -1699,9 +1702,13 @@ EXPORT_SYMBOL(request_threaded_irq);
> int request_any_context_irq(unsigned int irq, irq_handler_t handler,
> unsigned long flags, const char *name, void *dev_id)
> {
> - struct irq_desc *desc = irq_to_desc(irq);
> + struct irq_desc *desc;
> int ret;
>
> + if (irq == IRQ_NOTCONNECTED)
> + return -ENOTCONN;
> +
> + desc = irq_to_desc(irq);
> if (!desc)
> return -EINVAL;
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2016-02-15 4:58 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-02-15 3:25 [PATCH v5] x86/PCI: Recognize that Interrupt Line 255 means "not connected" Chen Fan
2016-02-15 3:49 ` kbuild test robot
2016-02-15 4:53 ` Chen Fan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox