Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / kernel / irq / spurious.c
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