upgrade to linux 2.6.10-1.12_FC2
[linux-2.6.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 static int irqfixup;
15
16 /*
17  *      Recovery handler for misrouted interrupts. 
18  */
19
20 static int misrouted_irq(int irq, struct pt_regs *regs)
21 {
22         int i;
23         irq_desc_t *desc;
24         int ok = 0;
25         int work = 0;   /* Did we do work for a real IRQ */
26         for(i = 1; i < NR_IRQS; i++)
27         {
28                 struct irqaction *action;
29                 if(i == irq)    /* Already tried */
30                         continue;
31                 desc = &irq_desc[i];
32                 spin_lock(&desc->lock);
33                 action = desc->action;
34                 /* Already running on another processor */
35                 if(desc->status & IRQ_INPROGRESS)
36                 {
37                         /* Already running: If it is shared get the other
38                            CPU to go looking for our mystery interrupt too */
39                         if(desc->action && (desc->action->flags & SA_SHIRQ))
40                                 desc->status |= IRQ_PENDING;
41                         spin_unlock(&desc->lock);
42                         continue;
43                 }
44                 /* Honour the normal IRQ locking */
45                 desc->status |= IRQ_INPROGRESS;
46                 spin_unlock(&desc->lock);
47                 while(action)
48                 {
49                         /* Only shared IRQ handlers are safe to call */
50                         if(action->flags & SA_SHIRQ)
51                         {
52                                 if(action->handler(i, action->dev_id, regs) == IRQ_HANDLED)
53                                         ok = 1;
54                         }
55                         action = action->next;
56                 }
57                 local_irq_disable();
58                 /* Now clean up the flags */
59                 spin_lock(&desc->lock);
60                 action = desc->action;
61
62                 /* While we were looking for a fixup someone queued a real
63                    IRQ clashing with our walk */
64
65                 while((desc->status & IRQ_PENDING) && action)
66                 {
67                         /* Perform real IRQ processing for the IRQ we deferred */
68                         work = 1;
69                         spin_unlock(&desc->lock);
70                         handle_IRQ_event(i, regs, action);
71                         spin_lock(&desc->lock);
72                         desc->status &= ~IRQ_PENDING;
73                 }
74                 desc->status &= ~IRQ_INPROGRESS;
75                 /* If we did actual work for the real IRQ line we must
76                    let the IRQ controller clean up too */
77                 if(work)
78                         desc->handler->end(i);
79                 spin_unlock(&desc->lock);
80         }
81         /* So the caller can adjust the irq error counts */
82         return ok;
83 }
84
85 /*
86  * If 99,900 of the previous 100,000 interrupts have not been handled
87  * then assume that the IRQ is stuck in some manner. Drop a diagnostic
88  * and try to turn the IRQ off.
89  *
90  * (The other 100-of-100,000 interrupts may have been a correctly
91  *  functioning device sharing an IRQ with the failing one)
92  *
93  * Called under desc->lock
94  */
95
96 static void
97 __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
98 {
99         struct irqaction *action;
100
101         if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
102                 printk(KERN_ERR "irq event %d: bogus return value %x\n",
103                                 irq, action_ret);
104         } else {
105                 printk(KERN_ERR "irq %d: nobody cared (try booting with the \"irqpoll\" option.\n", irq);
106         }
107         dump_stack();
108         printk(KERN_ERR "handlers:\n");
109         action = desc->action;
110         while (action) {
111                 printk(KERN_ERR "[<%p>]", action->handler);
112                 print_symbol(" (%s)",
113                         (unsigned long)action->handler);
114                 printk("\n");
115                 action = action->next;
116         }
117 }
118
119 void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
120 {
121         static int count = 100;
122
123         if (count > 0) {
124                 count--;
125                 __report_bad_irq(irq, desc, action_ret);
126         }
127 }
128
129 void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret, struct pt_regs *regs)
130 {
131         if (action_ret != IRQ_HANDLED) {
132                 desc->irqs_unhandled++;
133                 if (action_ret != IRQ_NONE)
134                         report_bad_irq(irq, desc, action_ret);
135         }
136
137         if(unlikely(irqfixup)) { /* Don't punish working computers */
138                 if((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) {
139                         int ok;
140                         ok = misrouted_irq(irq, regs);
141                         if(action_ret == IRQ_NONE)
142                                 desc->irqs_unhandled -= ok;
143                 }
144         }
145
146         desc->irq_count++;
147         if (desc->irq_count < 100000)
148                 return;
149
150         desc->irq_count = 0;
151         if (desc->irqs_unhandled > 99900) {
152                 /*
153                  * The interrupt is stuck
154                  */
155                 __report_bad_irq(irq, desc, action_ret);
156                 /*
157                  * Now kill the IRQ
158                  */
159                 printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
160                 desc->status |= IRQ_DISABLED;
161                 desc->handler->disable(irq);
162         }
163         desc->irqs_unhandled = 0;
164 }
165
166 int noirqdebug;
167
168 int __init noirqdebug_setup(char *str)
169 {
170         noirqdebug = 1;
171         printk(KERN_INFO "IRQ lockup detection disabled\n");
172         return 1;
173 }
174
175 __setup("noirqdebug", noirqdebug_setup);
176
177 static int __init irqfixup_setup(char *str)
178 {
179         irqfixup = 1;
180         printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n");
181         printk(KERN_WARNING "This may impact system performance.\n");
182         return 1;
183 }
184
185 __setup("irqfixup", irqfixup_setup);
186
187 static int __init irqpoll_setup(char *str)
188 {
189         irqfixup = 2;
190         printk(KERN_WARNING "Misrouted IRQ fixup and polling support enabled.\n");
191         printk(KERN_WARNING "This may significantly impact system performance.\n");
192         return 1;
193 }
194
195 __setup("irqpoll", irqpoll_setup);