source: trunk/packages/xen-3.1/xen-3.1/linux-2.6-xen-sparse/kernel/irq/spurious.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

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