diff options
Diffstat (limited to 'kernel/irq/handle.c')
-rw-r--r-- | kernel/irq/handle.c | 144 |
1 files changed, 113 insertions, 31 deletions
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 3540a719012..517561fc731 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c | |||
@@ -51,30 +51,92 @@ static void warn_no_thread(unsigned int irq, struct irqaction *action) | |||
51 | "but no thread function available.", irq, action->name); | 51 | "but no thread function available.", irq, action->name); |
52 | } | 52 | } |
53 | 53 | ||
54 | /** | 54 | static void irq_wake_thread(struct irq_desc *desc, struct irqaction *action) |
55 | * handle_IRQ_event - irq action chain handler | 55 | { |
56 | * @irq: the interrupt number | 56 | /* |
57 | * @action: the interrupt action chain for this irq | 57 | * Wake up the handler thread for this action. In case the |
58 | * | 58 | * thread crashed and was killed we just pretend that we |
59 | * Handles the action chain of an irq event | 59 | * handled the interrupt. The hardirq handler has disabled the |
60 | */ | 60 | * device interrupt, so no irq storm is lurking. If the |
61 | irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) | 61 | * RUNTHREAD bit is already set, nothing to do. |
62 | */ | ||
63 | if (test_bit(IRQTF_DIED, &action->thread_flags) || | ||
64 | test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags)) | ||
65 | return; | ||
66 | |||
67 | /* | ||
68 | * It's safe to OR the mask lockless here. We have only two | ||
69 | * places which write to threads_oneshot: This code and the | ||
70 | * irq thread. | ||
71 | * | ||
72 | * This code is the hard irq context and can never run on two | ||
73 | * cpus in parallel. If it ever does we have more serious | ||
74 | * problems than this bitmask. | ||
75 | * | ||
76 | * The irq threads of this irq which clear their "running" bit | ||
77 | * in threads_oneshot are serialized via desc->lock against | ||
78 | * each other and they are serialized against this code by | ||
79 | * IRQS_INPROGRESS. | ||
80 | * | ||
81 | * Hard irq handler: | ||
82 | * | ||
83 | * spin_lock(desc->lock); | ||
84 | * desc->state |= IRQS_INPROGRESS; | ||
85 | * spin_unlock(desc->lock); | ||
86 | * set_bit(IRQTF_RUNTHREAD, &action->thread_flags); | ||
87 | * desc->threads_oneshot |= mask; | ||
88 | * spin_lock(desc->lock); | ||
89 | * desc->state &= ~IRQS_INPROGRESS; | ||
90 | * spin_unlock(desc->lock); | ||
91 | * | ||
92 | * irq thread: | ||
93 | * | ||
94 | * again: | ||
95 | * spin_lock(desc->lock); | ||
96 | * if (desc->state & IRQS_INPROGRESS) { | ||
97 | * spin_unlock(desc->lock); | ||
98 | * while(desc->state & IRQS_INPROGRESS) | ||
99 | * cpu_relax(); | ||
100 | * goto again; | ||
101 | * } | ||
102 | * if (!test_bit(IRQTF_RUNTHREAD, &action->thread_flags)) | ||
103 | * desc->threads_oneshot &= ~mask; | ||
104 | * spin_unlock(desc->lock); | ||
105 | * | ||
106 | * So either the thread waits for us to clear IRQS_INPROGRESS | ||
107 | * or we are waiting in the flow handler for desc->lock to be | ||
108 | * released before we reach this point. The thread also checks | ||
109 | * IRQTF_RUNTHREAD under desc->lock. If set it leaves | ||
110 | * threads_oneshot untouched and runs the thread another time. | ||
111 | */ | ||
112 | desc->threads_oneshot |= action->thread_mask; | ||
113 | wake_up_process(action->thread); | ||
114 | } | ||
115 | |||
116 | irqreturn_t | ||
117 | handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action) | ||
62 | { | 118 | { |
63 | irqreturn_t ret, retval = IRQ_NONE; | 119 | irqreturn_t retval = IRQ_NONE; |
64 | unsigned int status = 0; | 120 | unsigned int random = 0, irq = desc->irq_data.irq; |
65 | 121 | ||
66 | do { | 122 | do { |
123 | irqreturn_t res; | ||
124 | |||
67 | trace_irq_handler_entry(irq, action); | 125 | trace_irq_handler_entry(irq, action); |
68 | ret = action->handler(irq, action->dev_id); | 126 | res = action->handler(irq, action->dev_id); |
69 | trace_irq_handler_exit(irq, action, ret); | 127 | trace_irq_handler_exit(irq, action, res); |
70 | 128 | ||
71 | switch (ret) { | 129 | if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n", |
130 | irq, action->handler)) | ||
131 | local_irq_disable(); | ||
132 | |||
133 | switch (res) { | ||
72 | case IRQ_WAKE_THREAD: | 134 | case IRQ_WAKE_THREAD: |
73 | /* | 135 | /* |
74 | * Set result to handled so the spurious check | 136 | * Set result to handled so the spurious check |
75 | * does not trigger. | 137 | * does not trigger. |
76 | */ | 138 | */ |
77 | ret = IRQ_HANDLED; | 139 | res = IRQ_HANDLED; |
78 | 140 | ||
79 | /* | 141 | /* |
80 | * Catch drivers which return WAKE_THREAD but | 142 | * Catch drivers which return WAKE_THREAD but |
@@ -85,36 +147,56 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) | |||
85 | break; | 147 | break; |
86 | } | 148 | } |
87 | 149 | ||
88 | /* | 150 | irq_wake_thread(desc, action); |
89 | * Wake up the handler thread for this | ||
90 | * action. In case the thread crashed and was | ||
91 | * killed we just pretend that we handled the | ||
92 | * interrupt. The hardirq handler above has | ||
93 | * disabled the device interrupt, so no irq | ||
94 | * storm is lurking. | ||
95 | */ | ||
96 | if (likely(!test_bit(IRQTF_DIED, | ||
97 | &action->thread_flags))) { | ||
98 | set_bit(IRQTF_RUNTHREAD, &action->thread_flags); | ||
99 | wake_up_process(action->thread); | ||
100 | } | ||
101 | 151 | ||
102 | /* Fall through to add to randomness */ | 152 | /* Fall through to add to randomness */ |
103 | case IRQ_HANDLED: | 153 | case IRQ_HANDLED: |
104 | status |= action->flags; | 154 | random |= action->flags; |
105 | break; | 155 | break; |
106 | 156 | ||
107 | default: | 157 | default: |
108 | break; | 158 | break; |
109 | } | 159 | } |
110 | 160 | ||
111 | retval |= ret; | 161 | retval |= res; |
112 | action = action->next; | 162 | action = action->next; |
113 | } while (action); | 163 | } while (action); |
114 | 164 | ||
115 | if (status & IRQF_SAMPLE_RANDOM) | 165 | if (random & IRQF_SAMPLE_RANDOM) |
116 | add_interrupt_randomness(irq); | 166 | add_interrupt_randomness(irq); |
117 | local_irq_disable(); | ||
118 | 167 | ||
168 | if (!noirqdebug) | ||
169 | note_interrupt(irq, desc, retval); | ||
119 | return retval; | 170 | return retval; |
120 | } | 171 | } |
172 | |||
173 | irqreturn_t handle_irq_event(struct irq_desc *desc) | ||
174 | { | ||
175 | struct irqaction *action = desc->action; | ||
176 | irqreturn_t ret; | ||
177 | |||
178 | irq_compat_clr_pending(desc); | ||
179 | desc->istate &= ~IRQS_PENDING; | ||
180 | irq_compat_set_progress(desc); | ||
181 | desc->istate |= IRQS_INPROGRESS; | ||
182 | raw_spin_unlock(&desc->lock); | ||
183 | |||
184 | ret = handle_irq_event_percpu(desc, action); | ||
185 | |||
186 | raw_spin_lock(&desc->lock); | ||
187 | desc->istate &= ~IRQS_INPROGRESS; | ||
188 | irq_compat_clr_progress(desc); | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * handle_IRQ_event - irq action chain handler | ||
194 | * @irq: the interrupt number | ||
195 | * @action: the interrupt action chain for this irq | ||
196 | * | ||
197 | * Handles the action chain of an irq event | ||
198 | */ | ||
199 | irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) | ||
200 | { | ||
201 | return handle_irq_event_percpu(irq_to_desc(irq), action); | ||
202 | } | ||