OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [kernel/] [irq/] [spurious.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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 __read_mostly;
15
 
16
/*
17
 * Recovery handler for misrouted interrupts.
18
 */
19
static int misrouted_irq(int irq)
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) ==
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, 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
 
101
static 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
 
127
static void
128
report_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
 
138
static inline int try_misrouted_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
139
{
140
        struct irqaction *action;
141
 
142
        if (!irqfixup)
143
                return 0;
144
 
145
        /* We didn't actually handle the IRQ - see if it was misrouted? */
146
        if (action_ret == IRQ_NONE)
147
                return 1;
148
 
149
        /*
150
         * But for 'irqfixup == 2' we also do it for handled interrupts if
151
         * they are marked as IRQF_IRQPOLL (or for irq zero, which is the
152
         * traditional PC timer interrupt.. Legacy)
153
         */
154
        if (irqfixup < 2)
155
                return 0;
156
 
157
        if (!irq)
158
                return 1;
159
 
160
        /*
161
         * Since we don't get the descriptor lock, "action" can
162
         * change under us.  We don't really care, but we don't
163
         * want to follow a NULL pointer. So tell the compiler to
164
         * just load it once by using a barrier.
165
         */
166
        action = desc->action;
167
        barrier();
168
        return action && (action->flags & IRQF_IRQPOLL);
169
}
170
 
171
void note_interrupt(unsigned int irq, struct irq_desc *desc,
172
                    irqreturn_t action_ret)
173
{
174
        if (unlikely(action_ret != IRQ_HANDLED)) {
175
                /*
176
                 * If we are seeing only the odd spurious IRQ caused by
177
                 * bus asynchronicity then don't eventually trigger an error,
178
                 * otherwise the couter becomes a doomsday timer for otherwise
179
                 * working systems
180
                 */
181
                if (jiffies - desc->last_unhandled > HZ/10)
182
                        desc->irqs_unhandled = 1;
183
                else
184
                        desc->irqs_unhandled++;
185
                desc->last_unhandled = jiffies;
186
                if (unlikely(action_ret != IRQ_NONE))
187
                        report_bad_irq(irq, desc, action_ret);
188
        }
189
 
190
        if (unlikely(try_misrouted_irq(irq, desc, action_ret))) {
191
                int ok = misrouted_irq(irq);
192
                if (action_ret == IRQ_NONE)
193
                        desc->irqs_unhandled -= ok;
194
        }
195
 
196
        desc->irq_count++;
197
        if (likely(desc->irq_count < 100000))
198
                return;
199
 
200
        desc->irq_count = 0;
201
        if (unlikely(desc->irqs_unhandled > 99900)) {
202
                /*
203
                 * The interrupt is stuck
204
                 */
205
                __report_bad_irq(irq, desc, action_ret);
206
                /*
207
                 * Now kill the IRQ
208
                 */
209
                printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
210
                desc->status |= IRQ_DISABLED;
211
                desc->depth = 1;
212
                desc->chip->disable(irq);
213
        }
214
        desc->irqs_unhandled = 0;
215
}
216
 
217
int noirqdebug __read_mostly;
218
 
219
int noirqdebug_setup(char *str)
220
{
221
        noirqdebug = 1;
222
        printk(KERN_INFO "IRQ lockup detection disabled\n");
223
 
224
        return 1;
225
}
226
 
227
__setup("noirqdebug", noirqdebug_setup);
228
 
229
static int __init irqfixup_setup(char *str)
230
{
231
        irqfixup = 1;
232
        printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n");
233
        printk(KERN_WARNING "This may impact system performance.\n");
234
 
235
        return 1;
236
}
237
 
238
__setup("irqfixup", irqfixup_setup);
239
 
240
static int __init irqpoll_setup(char *str)
241
{
242
        irqfixup = 2;
243
        printk(KERN_WARNING "Misrouted IRQ fixup and polling support "
244
                                "enabled\n");
245
        printk(KERN_WARNING "This may significantly impact system "
246
                                "performance\n");
247
        return 1;
248
}
249
 
250
__setup("irqpoll", irqpoll_setup);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.