1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
|
/*
* 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_printk(KERN_ERR, &pdev->dev,
"Potentially misrouted IRQ (Bridge %s %04x:%04x)\n",
dev_name(&parent->dev), parent->vendor, parent->device);
dev_printk(KERN_ERR, &pdev->dev, "%s\n", reason);
dev_printk(KERN_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);
|