2008-08-03 22:02:12 +04:00
/*
* 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>
2011-05-27 17:37:25 +04:00
# include <linux/export.h>
2008-08-03 22:02:12 +04:00
# 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 ) ;
2012-10-28 12:05:49 +04:00
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 " ) ;
2008-08-03 22:02:12 +04:00
WARN_ON ( 1 ) ;
}
/**
* pci_lost_interrupt - reports a lost PCI interrupt
* @ pdev : device whose interrupt is lost
2013-11-14 22:28:18 +04:00
*
2008-08-03 22:02:12 +04:00
* 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 ) ;