Linux-2.6.12-rc2
[linux-2.6.git] / kernel / irq / handle.c
1 /*
2  * linux/kernel/irq/handle.c
3  *
4  * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
5  *
6  * This file contains the core interrupt handling code.
7  */
8
9 #include <linux/irq.h>
10 #include <linux/module.h>
11 #include <linux/random.h>
12 #include <linux/interrupt.h>
13 #include <linux/kernel_stat.h>
14
15 #include "internals.h"
16
17 /*
18  * Linux has a controller-independent interrupt architecture.
19  * Every controller has a 'controller-template', that is used
20  * by the main code to do the right thing. Each driver-visible
21  * interrupt source is transparently wired to the apropriate
22  * controller. Thus drivers need not be aware of the
23  * interrupt-controller.
24  *
25  * The code is designed to be easily extended with new/different
26  * interrupt controllers, without having to do assembly magic or
27  * having to touch the generic code.
28  *
29  * Controller mappings for all interrupt sources:
30  */
31 irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
32         [0 ... NR_IRQS-1] = {
33                 .handler = &no_irq_type,
34                 .lock = SPIN_LOCK_UNLOCKED
35         }
36 };
37
38 /*
39  * Generic 'no controller' code
40  */
41 static void end_none(unsigned int irq) { }
42 static void enable_none(unsigned int irq) { }
43 static void disable_none(unsigned int irq) { }
44 static void shutdown_none(unsigned int irq) { }
45 static unsigned int startup_none(unsigned int irq) { return 0; }
46
47 static void ack_none(unsigned int irq)
48 {
49         /*
50          * 'what should we do if we get a hw irq event on an illegal vector'.
51          * each architecture has to answer this themself.
52          */
53         ack_bad_irq(irq);
54 }
55
56 struct hw_interrupt_type no_irq_type = {
57         .typename =     "none",
58         .startup =      startup_none,
59         .shutdown =     shutdown_none,
60         .enable =       enable_none,
61         .disable =      disable_none,
62         .ack =          ack_none,
63         .end =          end_none,
64         .set_affinity = NULL
65 };
66
67 /*
68  * Special, empty irq handler:
69  */
70 irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
71 {
72         return IRQ_NONE;
73 }
74
75 /*
76  * Have got an event to handle:
77  */
78 fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
79                                 struct irqaction *action)
80 {
81         int ret, retval = 0, status = 0;
82
83         if (!(action->flags & SA_INTERRUPT))
84                 local_irq_enable();
85
86         do {
87                 ret = action->handler(irq, action->dev_id, regs);
88                 if (ret == IRQ_HANDLED)
89                         status |= action->flags;
90                 retval |= ret;
91                 action = action->next;
92         } while (action);
93
94         if (status & SA_SAMPLE_RANDOM)
95                 add_interrupt_randomness(irq);
96         local_irq_disable();
97
98         return retval;
99 }
100
101 /*
102  * do_IRQ handles all normal device IRQ's (the special
103  * SMP cross-CPU interrupts have their own specific
104  * handlers).
105  */
106 fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
107 {
108         irq_desc_t *desc = irq_desc + irq;
109         struct irqaction * action;
110         unsigned int status;
111
112         kstat_this_cpu.irqs[irq]++;
113         if (desc->status & IRQ_PER_CPU) {
114                 irqreturn_t action_ret;
115
116                 /*
117                  * No locking required for CPU-local interrupts:
118                  */
119                 desc->handler->ack(irq);
120                 action_ret = handle_IRQ_event(irq, regs, desc->action);
121                 if (!noirqdebug)
122                         note_interrupt(irq, desc, action_ret);
123                 desc->handler->end(irq);
124                 return 1;
125         }
126
127         spin_lock(&desc->lock);
128         desc->handler->ack(irq);
129         /*
130          * REPLAY is when Linux resends an IRQ that was dropped earlier
131          * WAITING is used by probe to mark irqs that are being tested
132          */
133         status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
134         status |= IRQ_PENDING; /* we _want_ to handle it */
135
136         /*
137          * If the IRQ is disabled for whatever reason, we cannot
138          * use the action we have.
139          */
140         action = NULL;
141         if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
142                 action = desc->action;
143                 status &= ~IRQ_PENDING; /* we commit to handling */
144                 status |= IRQ_INPROGRESS; /* we are handling it */
145         }
146         desc->status = status;
147
148         /*
149          * If there is no IRQ handler or it was disabled, exit early.
150          * Since we set PENDING, if another processor is handling
151          * a different instance of this same irq, the other processor
152          * will take care of it.
153          */
154         if (unlikely(!action))
155                 goto out;
156
157         /*
158          * Edge triggered interrupts need to remember
159          * pending events.
160          * This applies to any hw interrupts that allow a second
161          * instance of the same irq to arrive while we are in do_IRQ
162          * or in the handler. But the code here only handles the _second_
163          * instance of the irq, not the third or fourth. So it is mostly
164          * useful for irq hardware that does not mask cleanly in an
165          * SMP environment.
166          */
167         for (;;) {
168                 irqreturn_t action_ret;
169
170                 spin_unlock(&desc->lock);
171
172                 action_ret = handle_IRQ_event(irq, regs, action);
173
174                 spin_lock(&desc->lock);
175                 if (!noirqdebug)
176                         note_interrupt(irq, desc, action_ret);
177                 if (likely(!(desc->status & IRQ_PENDING)))
178                         break;
179                 desc->status &= ~IRQ_PENDING;
180         }
181         desc->status &= ~IRQ_INPROGRESS;
182
183 out:
184         /*
185          * The ->end() handler has to deal with interrupts which got
186          * disabled while the handler was running.
187          */
188         desc->handler->end(irq);
189         spin_unlock(&desc->lock);
190
191         return 1;
192 }
193