| /* |
| * PCI IRQ failure handing code |
| * |
| * Copyright (c) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> |
| */ |
| |
| #include <linux/acpi.h> |
| #include <linux/device.h> |
| #include <linux/kernel.h> |
| #include <linux/export.h> |
| #include <linux/pci.h> |
| |
| static void pci_note_irq_problem(struct pci_dev *pdev, const char *reason) |
| { |
| struct pci_dev *parent = to_pci_dev(pdev->dev.parent); |
| |
| dev_err(&pdev->dev, |
| "Potentially misrouted IRQ (Bridge %s %04x:%04x)\n", |
| dev_name(&parent->dev), parent->vendor, parent->device); |
| dev_err(&pdev->dev, "%s\n", reason); |
| dev_err(&pdev->dev, "Please report to linux-kernel@vger.kernel.org\n"); |
| WARN_ON(1); |
| } |
| |
| /** |
| * pci_lost_interrupt - reports a lost PCI interrupt |
| * @pdev: device whose interrupt is lost |
| * |
| * The primary function of this routine is to report a lost interrupt |
| * in a standard way which users can recognise (instead of blaming the |
| * driver). |
| * |
| * Returns: |
| * a suggestion for fixing it (although the driver is not required to |
| * act on this). |
| */ |
| enum pci_lost_interrupt_reason pci_lost_interrupt(struct pci_dev *pdev) |
| { |
| if (pdev->msi_enabled || pdev->msix_enabled) { |
| enum pci_lost_interrupt_reason ret; |
| |
| if (pdev->msix_enabled) { |
| pci_note_irq_problem(pdev, "MSIX routing failure"); |
| ret = PCI_LOST_IRQ_DISABLE_MSIX; |
| } else { |
| pci_note_irq_problem(pdev, "MSI routing failure"); |
| ret = PCI_LOST_IRQ_DISABLE_MSI; |
| } |
| return ret; |
| } |
| #ifdef CONFIG_ACPI |
| if (!(acpi_disabled || acpi_noirq)) { |
| pci_note_irq_problem(pdev, "Potential ACPI misrouting please reboot with acpi=noirq"); |
| /* currently no way to fix acpi on the fly */ |
| return PCI_LOST_IRQ_DISABLE_ACPI; |
| } |
| #endif |
| pci_note_irq_problem(pdev, "unknown cause (not MSI or ACPI)"); |
| return PCI_LOST_IRQ_NO_INFORMATION; |
| } |
| EXPORT_SYMBOL(pci_lost_interrupt); |