2005-04-17 02:20:36 +04:00
/*
* linux / kernel / irq / spurious . c
*
* Copyright ( C ) 1992 , 1998 - 2004 Linus Torvalds , Ingo Molnar
*
* This file contains spurious interrupt handling .
*/
# include <linux/irq.h>
# include <linux/module.h>
# include <linux/kallsyms.h>
# include <linux/interrupt.h>
/*
* If 99 , 900 of the previous 100 , 000 interrupts have not been handled
* then assume that the IRQ is stuck in some manner . Drop a diagnostic
* and try to turn the IRQ off .
*
* ( The other 100 - of - 100 , 000 interrupts may have been a correctly
* functioning device sharing an IRQ with the failing one )
*
* Called under desc - > lock
*/
static void
__report_bad_irq ( unsigned int irq , irq_desc_t * desc , irqreturn_t action_ret )
{
struct irqaction * action ;
if ( action_ret ! = IRQ_HANDLED & & action_ret ! = IRQ_NONE ) {
printk ( KERN_ERR " irq event %d: bogus return value %x \n " ,
irq , action_ret ) ;
} else {
printk ( KERN_ERR " irq %d: nobody cared! \n " , irq ) ;
}
dump_stack ( ) ;
printk ( KERN_ERR " handlers: \n " ) ;
action = desc - > action ;
while ( action ) {
printk ( KERN_ERR " [<%p>] " , action - > handler ) ;
print_symbol ( " (%s) " ,
( unsigned long ) action - > handler ) ;
printk ( " \n " ) ;
action = action - > next ;
}
}
2005-06-24 09:05:33 +04:00
static void report_bad_irq ( unsigned int irq , irq_desc_t * desc , irqreturn_t action_ret )
2005-04-17 02:20:36 +04:00
{
static int count = 100 ;
if ( count > 0 ) {
count - - ;
__report_bad_irq ( irq , desc , action_ret ) ;
}
}
void note_interrupt ( unsigned int irq , irq_desc_t * desc , irqreturn_t action_ret )
{
if ( action_ret ! = IRQ_HANDLED ) {
desc - > irqs_unhandled + + ;
if ( action_ret ! = IRQ_NONE )
report_bad_irq ( irq , desc , action_ret ) ;
}
desc - > irq_count + + ;
if ( desc - > irq_count < 100000 )
return ;
desc - > irq_count = 0 ;
if ( desc - > irqs_unhandled > 99900 ) {
/*
* The interrupt is stuck
*/
__report_bad_irq ( irq , desc , action_ret ) ;
/*
* Now kill the IRQ
*/
printk ( KERN_EMERG " Disabling IRQ #%d \n " , irq ) ;
desc - > status | = IRQ_DISABLED ;
desc - > handler - > disable ( irq ) ;
}
desc - > irqs_unhandled = 0 ;
}
int noirqdebug ;
int __init noirqdebug_setup ( char * str )
{
noirqdebug = 1 ;
printk ( KERN_INFO " IRQ lockup detection disabled \n " ) ;
return 1 ;
}
__setup ( " noirqdebug " , noirqdebug_setup ) ;