1 /* 2 * linux/kernel/irq/spurious.c 3 * 4 * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar 5 * 6 * This file contains spurious interrupt handling. 7 */ 8 9 #include <linux/irq.h> 10 #include <linux/module.h> 11 #include <linux/kallsyms.h> 12 #include <linux/interrupt.h> 13 14 /* 15 * If 99,900 of the previous 100,000 interrupts have not been handled 16 * then assume that the IRQ is stuck in some manner. Drop a diagnostic 17 * and try to turn the IRQ off. 18 * 19 * (The other 100-of-100,000 interrupts may have been a correctly 20 * functioning device sharing an IRQ with the failing one) 21 * 22 * Called under desc->lock 23 */ 24 25 static void 26 __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret) 27 { 28 struct irqaction *action; 29 30 if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { 31 printk(KERN_ERR "irq event %d: bogus return value %x\n", 32 irq, action_ret); 33 } else { 34 printk(KERN_ERR "irq %d: nobody cared!\n", irq); 35 } 36 dump_stack(); 37 printk(KERN_ERR "handlers:\n"); 38 action = desc->action; 39 while (action) { 40 printk(KERN_ERR "[<%p>]", action->handler); 41 print_symbol(" (%s)", 42 (unsigned long)action->handler); 43 printk("\n"); 44 action = action->next; 45 } 46 } 47 48 void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret) 49 { 50 static int count = 100; 51 52 if (count > 0) { 53 count--; 54 __report_bad_irq(irq, desc, action_ret); 55 } 56 } 57 58 void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret) 59 { 60 if (action_ret != IRQ_HANDLED) { 61 desc->irqs_unhandled++; 62 if (action_ret != IRQ_NONE) 63 report_bad_irq(irq, desc, action_ret); 64 } 65 66 desc->irq_count++; 67 if (desc->irq_count < 100000) 68 return; 69 70 desc->irq_count = 0; 71 if (desc->irqs_unhandled > 99900) { 72 /* 73 * The interrupt is stuck 74 */ 75 __report_bad_irq(irq, desc, action_ret); 76 /* 77 * Now kill the IRQ 78 */ 79 printk(KERN_EMERG "Disabling IRQ #%d\n", irq); 80 desc->status |= IRQ_DISABLED; 81 desc->handler->disable(irq); 82 } 83 desc->irqs_unhandled = 0; 84 } 85 86 int noirqdebug; 87 88 int __init noirqdebug_setup(char *str) 89 { 90 noirqdebug = 1; 91 printk(KERN_INFO "IRQ lockup detection disabled\n"); 92 return 1; 93 } 94 95 __setup("noirqdebug", noirqdebug_setup); 96 97