]>
Commit | Line | Data |
---|---|---|
dd87eb3a TG |
1 | /* |
2 | * linux/kernel/irq/chip.c | |
3 | * | |
4 | * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar | |
5 | * Copyright (C) 2005-2006, Thomas Gleixner, Russell King | |
6 | * | |
7 | * This file contains the core interrupt handling code, for irq-chip | |
8 | * based architectures. | |
9 | * | |
10 | * Detailed information is available in Documentation/DocBook/genericirq | |
11 | */ | |
12 | ||
13 | #include <linux/irq.h> | |
7fe3730d | 14 | #include <linux/msi.h> |
dd87eb3a TG |
15 | #include <linux/module.h> |
16 | #include <linux/interrupt.h> | |
17 | #include <linux/kernel_stat.h> | |
18 | ||
19 | #include "internals.h" | |
20 | ||
21 | /** | |
a0cd9ca2 | 22 | * irq_set_chip - set the irq chip for an irq |
dd87eb3a TG |
23 | * @irq: irq number |
24 | * @chip: pointer to irq chip description structure | |
25 | */ | |
a0cd9ca2 | 26 | int irq_set_chip(unsigned int irq, struct irq_chip *chip) |
dd87eb3a | 27 | { |
dd87eb3a | 28 | unsigned long flags; |
02725e74 | 29 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags); |
dd87eb3a | 30 | |
02725e74 | 31 | if (!desc) |
dd87eb3a | 32 | return -EINVAL; |
dd87eb3a TG |
33 | |
34 | if (!chip) | |
35 | chip = &no_irq_chip; | |
36 | ||
dd87eb3a | 37 | irq_chip_set_defaults(chip); |
6b8ff312 | 38 | desc->irq_data.chip = chip; |
02725e74 | 39 | irq_put_desc_unlock(desc, flags); |
dd87eb3a TG |
40 | return 0; |
41 | } | |
a0cd9ca2 | 42 | EXPORT_SYMBOL(irq_set_chip); |
dd87eb3a TG |
43 | |
44 | /** | |
a0cd9ca2 | 45 | * irq_set_type - set the irq trigger type for an irq |
dd87eb3a | 46 | * @irq: irq number |
0c5d1eb7 | 47 | * @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h |
dd87eb3a | 48 | */ |
a0cd9ca2 | 49 | int irq_set_irq_type(unsigned int irq, unsigned int type) |
dd87eb3a | 50 | { |
dd87eb3a | 51 | unsigned long flags; |
02725e74 TG |
52 | struct irq_desc *desc = irq_get_desc_buslock(irq, &flags); |
53 | int ret = 0; | |
dd87eb3a | 54 | |
02725e74 TG |
55 | if (!desc) |
56 | return -EINVAL; | |
dd87eb3a | 57 | |
f2b662da | 58 | type &= IRQ_TYPE_SENSE_MASK; |
02725e74 TG |
59 | if (type != IRQ_TYPE_NONE) |
60 | ret = __irq_set_trigger(desc, irq, type); | |
61 | irq_put_desc_busunlock(desc, flags); | |
dd87eb3a TG |
62 | return ret; |
63 | } | |
a0cd9ca2 | 64 | EXPORT_SYMBOL(irq_set_irq_type); |
dd87eb3a TG |
65 | |
66 | /** | |
a0cd9ca2 | 67 | * irq_set_handler_data - set irq handler data for an irq |
dd87eb3a TG |
68 | * @irq: Interrupt number |
69 | * @data: Pointer to interrupt specific data | |
70 | * | |
71 | * Set the hardware irq controller data for an irq | |
72 | */ | |
a0cd9ca2 | 73 | int irq_set_handler_data(unsigned int irq, void *data) |
dd87eb3a | 74 | { |
dd87eb3a | 75 | unsigned long flags; |
02725e74 | 76 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags); |
dd87eb3a | 77 | |
02725e74 | 78 | if (!desc) |
dd87eb3a | 79 | return -EINVAL; |
6b8ff312 | 80 | desc->irq_data.handler_data = data; |
02725e74 | 81 | irq_put_desc_unlock(desc, flags); |
dd87eb3a TG |
82 | return 0; |
83 | } | |
a0cd9ca2 | 84 | EXPORT_SYMBOL(irq_set_handler_data); |
dd87eb3a | 85 | |
5b912c10 | 86 | /** |
a0cd9ca2 | 87 | * irq_set_msi_desc - set MSI descriptor data for an irq |
5b912c10 | 88 | * @irq: Interrupt number |
472900b8 | 89 | * @entry: Pointer to MSI descriptor data |
5b912c10 | 90 | * |
24b26d42 | 91 | * Set the MSI descriptor entry for an irq |
5b912c10 | 92 | */ |
a0cd9ca2 | 93 | int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry) |
5b912c10 | 94 | { |
5b912c10 | 95 | unsigned long flags; |
02725e74 | 96 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags); |
5b912c10 | 97 | |
02725e74 | 98 | if (!desc) |
5b912c10 | 99 | return -EINVAL; |
6b8ff312 | 100 | desc->irq_data.msi_desc = entry; |
7fe3730d ME |
101 | if (entry) |
102 | entry->irq = irq; | |
02725e74 | 103 | irq_put_desc_unlock(desc, flags); |
5b912c10 EB |
104 | return 0; |
105 | } | |
106 | ||
dd87eb3a | 107 | /** |
a0cd9ca2 | 108 | * irq_set_chip_data - set irq chip data for an irq |
dd87eb3a TG |
109 | * @irq: Interrupt number |
110 | * @data: Pointer to chip specific data | |
111 | * | |
112 | * Set the hardware irq chip data for an irq | |
113 | */ | |
a0cd9ca2 | 114 | int irq_set_chip_data(unsigned int irq, void *data) |
dd87eb3a | 115 | { |
dd87eb3a | 116 | unsigned long flags; |
02725e74 | 117 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags); |
dd87eb3a | 118 | |
02725e74 | 119 | if (!desc) |
dd87eb3a | 120 | return -EINVAL; |
6b8ff312 | 121 | desc->irq_data.chip_data = data; |
02725e74 | 122 | irq_put_desc_unlock(desc, flags); |
dd87eb3a TG |
123 | return 0; |
124 | } | |
a0cd9ca2 | 125 | EXPORT_SYMBOL(irq_set_chip_data); |
dd87eb3a | 126 | |
f303a6dd TG |
127 | struct irq_data *irq_get_irq_data(unsigned int irq) |
128 | { | |
129 | struct irq_desc *desc = irq_to_desc(irq); | |
130 | ||
131 | return desc ? &desc->irq_data : NULL; | |
132 | } | |
133 | EXPORT_SYMBOL_GPL(irq_get_irq_data); | |
134 | ||
c1594b77 TG |
135 | static void irq_state_clr_disabled(struct irq_desc *desc) |
136 | { | |
137 | desc->istate &= ~IRQS_DISABLED; | |
138 | irq_compat_clr_disabled(desc); | |
139 | } | |
140 | ||
141 | static void irq_state_set_disabled(struct irq_desc *desc) | |
142 | { | |
143 | desc->istate |= IRQS_DISABLED; | |
144 | irq_compat_set_disabled(desc); | |
145 | } | |
146 | ||
6e40262e TG |
147 | static void irq_state_clr_masked(struct irq_desc *desc) |
148 | { | |
149 | desc->istate &= ~IRQS_MASKED; | |
150 | irq_compat_clr_masked(desc); | |
151 | } | |
152 | ||
153 | static void irq_state_set_masked(struct irq_desc *desc) | |
154 | { | |
155 | desc->istate |= IRQS_MASKED; | |
156 | irq_compat_set_masked(desc); | |
157 | } | |
158 | ||
46999238 TG |
159 | int irq_startup(struct irq_desc *desc) |
160 | { | |
c1594b77 | 161 | irq_state_clr_disabled(desc); |
46999238 TG |
162 | desc->depth = 0; |
163 | ||
3aae994f TG |
164 | if (desc->irq_data.chip->irq_startup) { |
165 | int ret = desc->irq_data.chip->irq_startup(&desc->irq_data); | |
6e40262e | 166 | irq_state_clr_masked(desc); |
3aae994f TG |
167 | return ret; |
168 | } | |
46999238 | 169 | |
87923470 | 170 | irq_enable(desc); |
46999238 TG |
171 | return 0; |
172 | } | |
173 | ||
174 | void irq_shutdown(struct irq_desc *desc) | |
175 | { | |
c1594b77 | 176 | irq_state_set_disabled(desc); |
46999238 | 177 | desc->depth = 1; |
50f7c032 TG |
178 | if (desc->irq_data.chip->irq_shutdown) |
179 | desc->irq_data.chip->irq_shutdown(&desc->irq_data); | |
180 | if (desc->irq_data.chip->irq_disable) | |
181 | desc->irq_data.chip->irq_disable(&desc->irq_data); | |
182 | else | |
183 | desc->irq_data.chip->irq_mask(&desc->irq_data); | |
6e40262e | 184 | irq_state_set_masked(desc); |
46999238 TG |
185 | } |
186 | ||
87923470 TG |
187 | void irq_enable(struct irq_desc *desc) |
188 | { | |
c1594b77 | 189 | irq_state_clr_disabled(desc); |
50f7c032 TG |
190 | if (desc->irq_data.chip->irq_enable) |
191 | desc->irq_data.chip->irq_enable(&desc->irq_data); | |
192 | else | |
193 | desc->irq_data.chip->irq_unmask(&desc->irq_data); | |
6e40262e | 194 | irq_state_clr_masked(desc); |
dd87eb3a TG |
195 | } |
196 | ||
50f7c032 | 197 | void irq_disable(struct irq_desc *desc) |
89d694b9 | 198 | { |
c1594b77 | 199 | irq_state_set_disabled(desc); |
50f7c032 TG |
200 | if (desc->irq_data.chip->irq_disable) { |
201 | desc->irq_data.chip->irq_disable(&desc->irq_data); | |
50f7c032 | 202 | } |
6e40262e | 203 | irq_state_set_masked(desc); |
89d694b9 TG |
204 | } |
205 | ||
bd151412 | 206 | #ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED |
3876ec9e | 207 | /* Temporary migration helpers */ |
e2c0f8ff TG |
208 | static void compat_irq_mask(struct irq_data *data) |
209 | { | |
210 | data->chip->mask(data->irq); | |
211 | } | |
212 | ||
0eda58b7 TG |
213 | static void compat_irq_unmask(struct irq_data *data) |
214 | { | |
215 | data->chip->unmask(data->irq); | |
216 | } | |
217 | ||
22a49163 TG |
218 | static void compat_irq_ack(struct irq_data *data) |
219 | { | |
220 | data->chip->ack(data->irq); | |
221 | } | |
222 | ||
9205e31d TG |
223 | static void compat_irq_mask_ack(struct irq_data *data) |
224 | { | |
225 | data->chip->mask_ack(data->irq); | |
226 | } | |
227 | ||
0c5c1557 TG |
228 | static void compat_irq_eoi(struct irq_data *data) |
229 | { | |
230 | data->chip->eoi(data->irq); | |
231 | } | |
232 | ||
c5f75634 TG |
233 | static void compat_irq_enable(struct irq_data *data) |
234 | { | |
235 | data->chip->enable(data->irq); | |
236 | } | |
237 | ||
bc310dda TG |
238 | static void compat_irq_disable(struct irq_data *data) |
239 | { | |
240 | data->chip->disable(data->irq); | |
241 | } | |
242 | ||
243 | static void compat_irq_shutdown(struct irq_data *data) | |
244 | { | |
245 | data->chip->shutdown(data->irq); | |
246 | } | |
247 | ||
37e12df7 TG |
248 | static unsigned int compat_irq_startup(struct irq_data *data) |
249 | { | |
250 | return data->chip->startup(data->irq); | |
251 | } | |
252 | ||
c96b3b3c TG |
253 | static int compat_irq_set_affinity(struct irq_data *data, |
254 | const struct cpumask *dest, bool force) | |
255 | { | |
256 | return data->chip->set_affinity(data->irq, dest); | |
257 | } | |
258 | ||
b2ba2c30 TG |
259 | static int compat_irq_set_type(struct irq_data *data, unsigned int type) |
260 | { | |
261 | return data->chip->set_type(data->irq, type); | |
262 | } | |
263 | ||
2f7e99bb TG |
264 | static int compat_irq_set_wake(struct irq_data *data, unsigned int on) |
265 | { | |
266 | return data->chip->set_wake(data->irq, on); | |
267 | } | |
268 | ||
21e2b8c6 TG |
269 | static int compat_irq_retrigger(struct irq_data *data) |
270 | { | |
271 | return data->chip->retrigger(data->irq); | |
272 | } | |
273 | ||
3876ec9e TG |
274 | static void compat_bus_lock(struct irq_data *data) |
275 | { | |
276 | data->chip->bus_lock(data->irq); | |
277 | } | |
278 | ||
279 | static void compat_bus_sync_unlock(struct irq_data *data) | |
280 | { | |
281 | data->chip->bus_sync_unlock(data->irq); | |
282 | } | |
bd151412 | 283 | #endif |
3876ec9e | 284 | |
dd87eb3a TG |
285 | /* |
286 | * Fixup enable/disable function pointers | |
287 | */ | |
288 | void irq_chip_set_defaults(struct irq_chip *chip) | |
289 | { | |
bd151412 | 290 | #ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED |
c5f75634 TG |
291 | if (chip->enable) |
292 | chip->irq_enable = compat_irq_enable; | |
bc310dda TG |
293 | if (chip->disable) |
294 | chip->irq_disable = compat_irq_disable; | |
295 | if (chip->shutdown) | |
296 | chip->irq_shutdown = compat_irq_shutdown; | |
37e12df7 TG |
297 | if (chip->startup) |
298 | chip->irq_startup = compat_irq_startup; | |
b86432b4 ZY |
299 | if (!chip->end) |
300 | chip->end = dummy_irq_chip.end; | |
3876ec9e TG |
301 | if (chip->bus_lock) |
302 | chip->irq_bus_lock = compat_bus_lock; | |
303 | if (chip->bus_sync_unlock) | |
304 | chip->irq_bus_sync_unlock = compat_bus_sync_unlock; | |
e2c0f8ff TG |
305 | if (chip->mask) |
306 | chip->irq_mask = compat_irq_mask; | |
0eda58b7 TG |
307 | if (chip->unmask) |
308 | chip->irq_unmask = compat_irq_unmask; | |
22a49163 TG |
309 | if (chip->ack) |
310 | chip->irq_ack = compat_irq_ack; | |
9205e31d TG |
311 | if (chip->mask_ack) |
312 | chip->irq_mask_ack = compat_irq_mask_ack; | |
0c5c1557 TG |
313 | if (chip->eoi) |
314 | chip->irq_eoi = compat_irq_eoi; | |
c96b3b3c TG |
315 | if (chip->set_affinity) |
316 | chip->irq_set_affinity = compat_irq_set_affinity; | |
b2ba2c30 TG |
317 | if (chip->set_type) |
318 | chip->irq_set_type = compat_irq_set_type; | |
2f7e99bb TG |
319 | if (chip->set_wake) |
320 | chip->irq_set_wake = compat_irq_set_wake; | |
21e2b8c6 TG |
321 | if (chip->retrigger) |
322 | chip->irq_retrigger = compat_irq_retrigger; | |
bd151412 | 323 | #endif |
dd87eb3a TG |
324 | } |
325 | ||
9205e31d | 326 | static inline void mask_ack_irq(struct irq_desc *desc) |
dd87eb3a | 327 | { |
9205e31d TG |
328 | if (desc->irq_data.chip->irq_mask_ack) |
329 | desc->irq_data.chip->irq_mask_ack(&desc->irq_data); | |
dd87eb3a | 330 | else { |
e2c0f8ff | 331 | desc->irq_data.chip->irq_mask(&desc->irq_data); |
22a49163 TG |
332 | if (desc->irq_data.chip->irq_ack) |
333 | desc->irq_data.chip->irq_ack(&desc->irq_data); | |
dd87eb3a | 334 | } |
6e40262e | 335 | irq_state_set_masked(desc); |
0b1adaa0 TG |
336 | } |
337 | ||
d4d5e089 | 338 | void mask_irq(struct irq_desc *desc) |
0b1adaa0 | 339 | { |
e2c0f8ff TG |
340 | if (desc->irq_data.chip->irq_mask) { |
341 | desc->irq_data.chip->irq_mask(&desc->irq_data); | |
6e40262e | 342 | irq_state_set_masked(desc); |
0b1adaa0 TG |
343 | } |
344 | } | |
345 | ||
d4d5e089 | 346 | void unmask_irq(struct irq_desc *desc) |
0b1adaa0 | 347 | { |
0eda58b7 TG |
348 | if (desc->irq_data.chip->irq_unmask) { |
349 | desc->irq_data.chip->irq_unmask(&desc->irq_data); | |
6e40262e | 350 | irq_state_clr_masked(desc); |
0b1adaa0 | 351 | } |
dd87eb3a TG |
352 | } |
353 | ||
399b5da2 TG |
354 | /* |
355 | * handle_nested_irq - Handle a nested irq from a irq thread | |
356 | * @irq: the interrupt number | |
357 | * | |
358 | * Handle interrupts which are nested into a threaded interrupt | |
359 | * handler. The handler function is called inside the calling | |
360 | * threads context. | |
361 | */ | |
362 | void handle_nested_irq(unsigned int irq) | |
363 | { | |
364 | struct irq_desc *desc = irq_to_desc(irq); | |
365 | struct irqaction *action; | |
366 | irqreturn_t action_ret; | |
367 | ||
368 | might_sleep(); | |
369 | ||
239007b8 | 370 | raw_spin_lock_irq(&desc->lock); |
399b5da2 TG |
371 | |
372 | kstat_incr_irqs_this_cpu(irq, desc); | |
373 | ||
374 | action = desc->action; | |
c1594b77 | 375 | if (unlikely(!action || (desc->istate & IRQS_DISABLED))) |
399b5da2 TG |
376 | goto out_unlock; |
377 | ||
009b4c3b TG |
378 | irq_compat_set_progress(desc); |
379 | desc->istate |= IRQS_INPROGRESS; | |
239007b8 | 380 | raw_spin_unlock_irq(&desc->lock); |
399b5da2 TG |
381 | |
382 | action_ret = action->thread_fn(action->irq, action->dev_id); | |
383 | if (!noirqdebug) | |
384 | note_interrupt(irq, desc, action_ret); | |
385 | ||
239007b8 | 386 | raw_spin_lock_irq(&desc->lock); |
009b4c3b TG |
387 | desc->istate &= ~IRQS_INPROGRESS; |
388 | irq_compat_clr_progress(desc); | |
399b5da2 TG |
389 | |
390 | out_unlock: | |
239007b8 | 391 | raw_spin_unlock_irq(&desc->lock); |
399b5da2 TG |
392 | } |
393 | EXPORT_SYMBOL_GPL(handle_nested_irq); | |
394 | ||
fe200ae4 TG |
395 | static bool irq_check_poll(struct irq_desc *desc) |
396 | { | |
6954b75b | 397 | if (!(desc->istate & IRQS_POLL_INPROGRESS)) |
fe200ae4 TG |
398 | return false; |
399 | return irq_wait_for_poll(desc); | |
400 | } | |
401 | ||
dd87eb3a TG |
402 | /** |
403 | * handle_simple_irq - Simple and software-decoded IRQs. | |
404 | * @irq: the interrupt number | |
405 | * @desc: the interrupt description structure for this irq | |
dd87eb3a TG |
406 | * |
407 | * Simple interrupts are either sent from a demultiplexing interrupt | |
408 | * handler or come from hardware, where no interrupt hardware control | |
409 | * is necessary. | |
410 | * | |
411 | * Note: The caller is expected to handle the ack, clear, mask and | |
412 | * unmask issues if necessary. | |
413 | */ | |
7ad5b3a5 | 414 | void |
7d12e780 | 415 | handle_simple_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a | 416 | { |
239007b8 | 417 | raw_spin_lock(&desc->lock); |
dd87eb3a | 418 | |
009b4c3b | 419 | if (unlikely(desc->istate & IRQS_INPROGRESS)) |
fe200ae4 TG |
420 | if (!irq_check_poll(desc)) |
421 | goto out_unlock; | |
422 | ||
163ef309 | 423 | desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
d6c88a50 | 424 | kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a | 425 | |
c1594b77 | 426 | if (unlikely(!desc->action || (desc->istate & IRQS_DISABLED))) |
dd87eb3a TG |
427 | goto out_unlock; |
428 | ||
107781e7 | 429 | handle_irq_event(desc); |
dd87eb3a | 430 | |
dd87eb3a | 431 | out_unlock: |
239007b8 | 432 | raw_spin_unlock(&desc->lock); |
dd87eb3a TG |
433 | } |
434 | ||
435 | /** | |
436 | * handle_level_irq - Level type irq handler | |
437 | * @irq: the interrupt number | |
438 | * @desc: the interrupt description structure for this irq | |
dd87eb3a TG |
439 | * |
440 | * Level type interrupts are active as long as the hardware line has | |
441 | * the active level. This may require to mask the interrupt and unmask | |
442 | * it after the associated handler has acknowledged the device, so the | |
443 | * interrupt line is back to inactive. | |
444 | */ | |
7ad5b3a5 | 445 | void |
7d12e780 | 446 | handle_level_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a | 447 | { |
239007b8 | 448 | raw_spin_lock(&desc->lock); |
9205e31d | 449 | mask_ack_irq(desc); |
dd87eb3a | 450 | |
009b4c3b | 451 | if (unlikely(desc->istate & IRQS_INPROGRESS)) |
fe200ae4 TG |
452 | if (!irq_check_poll(desc)) |
453 | goto out_unlock; | |
454 | ||
163ef309 | 455 | desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
d6c88a50 | 456 | kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a TG |
457 | |
458 | /* | |
459 | * If its disabled or no action available | |
460 | * keep it masked and get out of here | |
461 | */ | |
c1594b77 | 462 | if (unlikely(!desc->action || (desc->istate & IRQS_DISABLED))) |
86998aa6 | 463 | goto out_unlock; |
dd87eb3a | 464 | |
1529866c | 465 | handle_irq_event(desc); |
b25c340c | 466 | |
c1594b77 | 467 | if (!(desc->istate & (IRQS_DISABLED | IRQS_ONESHOT))) |
0eda58b7 | 468 | unmask_irq(desc); |
86998aa6 | 469 | out_unlock: |
239007b8 | 470 | raw_spin_unlock(&desc->lock); |
dd87eb3a | 471 | } |
14819ea1 | 472 | EXPORT_SYMBOL_GPL(handle_level_irq); |
dd87eb3a TG |
473 | |
474 | /** | |
47c2a3aa | 475 | * handle_fasteoi_irq - irq handler for transparent controllers |
dd87eb3a TG |
476 | * @irq: the interrupt number |
477 | * @desc: the interrupt description structure for this irq | |
dd87eb3a | 478 | * |
47c2a3aa | 479 | * Only a single callback will be issued to the chip: an ->eoi() |
dd87eb3a TG |
480 | * call when the interrupt has been serviced. This enables support |
481 | * for modern forms of interrupt handlers, which handle the flow | |
482 | * details in hardware, transparently. | |
483 | */ | |
7ad5b3a5 | 484 | void |
7d12e780 | 485 | handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a | 486 | { |
239007b8 | 487 | raw_spin_lock(&desc->lock); |
dd87eb3a | 488 | |
009b4c3b | 489 | if (unlikely(desc->istate & IRQS_INPROGRESS)) |
fe200ae4 TG |
490 | if (!irq_check_poll(desc)) |
491 | goto out; | |
dd87eb3a | 492 | |
163ef309 | 493 | desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
d6c88a50 | 494 | kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a TG |
495 | |
496 | /* | |
497 | * If its disabled or no action available | |
76d21601 | 498 | * then mask it and get out of here: |
dd87eb3a | 499 | */ |
c1594b77 | 500 | if (unlikely(!desc->action || (desc->istate & IRQS_DISABLED))) { |
2a0d6fb3 TG |
501 | irq_compat_set_pending(desc); |
502 | desc->istate |= IRQS_PENDING; | |
e2c0f8ff | 503 | mask_irq(desc); |
dd87eb3a | 504 | goto out; |
98bb244b | 505 | } |
a7ae4de5 | 506 | handle_irq_event(desc); |
dd87eb3a | 507 | out: |
0c5c1557 | 508 | desc->irq_data.chip->irq_eoi(&desc->irq_data); |
239007b8 | 509 | raw_spin_unlock(&desc->lock); |
dd87eb3a TG |
510 | } |
511 | ||
512 | /** | |
513 | * handle_edge_irq - edge type IRQ handler | |
514 | * @irq: the interrupt number | |
515 | * @desc: the interrupt description structure for this irq | |
dd87eb3a TG |
516 | * |
517 | * Interrupt occures on the falling and/or rising edge of a hardware | |
518 | * signal. The occurence is latched into the irq controller hardware | |
519 | * and must be acked in order to be reenabled. After the ack another | |
520 | * interrupt can happen on the same source even before the first one | |
dfff0615 | 521 | * is handled by the associated event handler. If this happens it |
dd87eb3a TG |
522 | * might be necessary to disable (mask) the interrupt depending on the |
523 | * controller hardware. This requires to reenable the interrupt inside | |
524 | * of the loop which handles the interrupts which have arrived while | |
525 | * the handler was running. If all pending interrupts are handled, the | |
526 | * loop is left. | |
527 | */ | |
7ad5b3a5 | 528 | void |
7d12e780 | 529 | handle_edge_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a | 530 | { |
239007b8 | 531 | raw_spin_lock(&desc->lock); |
dd87eb3a | 532 | |
163ef309 | 533 | desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
dd87eb3a TG |
534 | /* |
535 | * If we're currently running this IRQ, or its disabled, | |
536 | * we shouldn't process the IRQ. Mark it pending, handle | |
537 | * the necessary masking and go out | |
538 | */ | |
c1594b77 TG |
539 | if (unlikely((desc->istate & (IRQS_DISABLED | IRQS_INPROGRESS) || |
540 | !desc->action))) { | |
fe200ae4 | 541 | if (!irq_check_poll(desc)) { |
2a0d6fb3 TG |
542 | irq_compat_set_pending(desc); |
543 | desc->istate |= IRQS_PENDING; | |
fe200ae4 TG |
544 | mask_ack_irq(desc); |
545 | goto out_unlock; | |
546 | } | |
dd87eb3a | 547 | } |
d6c88a50 | 548 | kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a TG |
549 | |
550 | /* Start handling the irq */ | |
22a49163 | 551 | desc->irq_data.chip->irq_ack(&desc->irq_data); |
dd87eb3a | 552 | |
dd87eb3a | 553 | do { |
a60a5dc2 | 554 | if (unlikely(!desc->action)) { |
e2c0f8ff | 555 | mask_irq(desc); |
dd87eb3a TG |
556 | goto out_unlock; |
557 | } | |
558 | ||
559 | /* | |
560 | * When another irq arrived while we were handling | |
561 | * one, we could have masked the irq. | |
562 | * Renable it, if it was not disabled in meantime. | |
563 | */ | |
2a0d6fb3 | 564 | if (unlikely(desc->istate & IRQS_PENDING)) { |
c1594b77 | 565 | if (!(desc->istate & IRQS_DISABLED) && |
6e40262e | 566 | (desc->istate & IRQS_MASKED)) |
c1594b77 | 567 | unmask_irq(desc); |
dd87eb3a TG |
568 | } |
569 | ||
a60a5dc2 | 570 | handle_irq_event(desc); |
dd87eb3a | 571 | |
2a0d6fb3 | 572 | } while ((desc->istate & IRQS_PENDING) && |
c1594b77 | 573 | !(desc->istate & IRQS_DISABLED)); |
dd87eb3a | 574 | |
dd87eb3a | 575 | out_unlock: |
239007b8 | 576 | raw_spin_unlock(&desc->lock); |
dd87eb3a TG |
577 | } |
578 | ||
dd87eb3a | 579 | /** |
24b26d42 | 580 | * handle_percpu_irq - Per CPU local irq handler |
dd87eb3a TG |
581 | * @irq: the interrupt number |
582 | * @desc: the interrupt description structure for this irq | |
dd87eb3a TG |
583 | * |
584 | * Per CPU interrupts on SMP machines without locking requirements | |
585 | */ | |
7ad5b3a5 | 586 | void |
7d12e780 | 587 | handle_percpu_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a | 588 | { |
35e857cb | 589 | struct irq_chip *chip = irq_desc_get_chip(desc); |
dd87eb3a | 590 | |
d6c88a50 | 591 | kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a | 592 | |
849f061c TG |
593 | if (chip->irq_ack) |
594 | chip->irq_ack(&desc->irq_data); | |
dd87eb3a | 595 | |
849f061c | 596 | handle_irq_event_percpu(desc, desc->action); |
dd87eb3a | 597 | |
849f061c TG |
598 | if (chip->irq_eoi) |
599 | chip->irq_eoi(&desc->irq_data); | |
dd87eb3a TG |
600 | } |
601 | ||
dd87eb3a | 602 | void |
3836ca08 | 603 | __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, |
a460e745 | 604 | const char *name) |
dd87eb3a | 605 | { |
dd87eb3a | 606 | unsigned long flags; |
02725e74 | 607 | struct irq_desc *desc = irq_get_desc_buslock(irq, &flags); |
dd87eb3a | 608 | |
02725e74 | 609 | if (!desc) |
dd87eb3a | 610 | return; |
dd87eb3a | 611 | |
091738a2 | 612 | if (!handle) { |
dd87eb3a | 613 | handle = handle_bad_irq; |
091738a2 TG |
614 | } else { |
615 | if (WARN_ON(desc->irq_data.chip == &no_irq_chip)) | |
02725e74 | 616 | goto out; |
f8b5473f | 617 | } |
dd87eb3a | 618 | |
dd87eb3a TG |
619 | /* Uninstall? */ |
620 | if (handle == handle_bad_irq) { | |
6b8ff312 | 621 | if (desc->irq_data.chip != &no_irq_chip) |
9205e31d | 622 | mask_ack_irq(desc); |
c1594b77 TG |
623 | irq_compat_set_disabled(desc); |
624 | desc->istate |= IRQS_DISABLED; | |
dd87eb3a TG |
625 | desc->depth = 1; |
626 | } | |
627 | desc->handle_irq = handle; | |
a460e745 | 628 | desc->name = name; |
dd87eb3a TG |
629 | |
630 | if (handle != handle_bad_irq && is_chained) { | |
1ccb4e61 TG |
631 | irq_settings_set_noprobe(desc); |
632 | irq_settings_set_norequest(desc); | |
46999238 | 633 | irq_startup(desc); |
dd87eb3a | 634 | } |
02725e74 TG |
635 | out: |
636 | irq_put_desc_busunlock(desc, flags); | |
dd87eb3a | 637 | } |
3836ca08 | 638 | EXPORT_SYMBOL_GPL(__irq_set_handler); |
dd87eb3a TG |
639 | |
640 | void | |
3836ca08 | 641 | irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, |
a460e745 | 642 | irq_flow_handler_t handle, const char *name) |
dd87eb3a | 643 | { |
35e857cb | 644 | irq_set_chip(irq, chip); |
3836ca08 | 645 | __irq_set_handler(irq, handle, 0, name); |
dd87eb3a | 646 | } |
46f4f8f6 | 647 | |
44247184 | 648 | void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) |
46f4f8f6 | 649 | { |
46f4f8f6 | 650 | unsigned long flags; |
02725e74 | 651 | struct irq_desc *desc = irq_get_desc_lock(irq, &flags); |
46f4f8f6 | 652 | |
44247184 | 653 | if (!desc) |
46f4f8f6 | 654 | return; |
a005677b TG |
655 | irq_settings_clr_and_set(desc, clr, set); |
656 | ||
876dbd4c | 657 | irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU | |
e1ef8241 | 658 | IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT); |
a005677b TG |
659 | if (irq_settings_has_no_balance_set(desc)) |
660 | irqd_set(&desc->irq_data, IRQD_NO_BALANCING); | |
661 | if (irq_settings_is_per_cpu(desc)) | |
662 | irqd_set(&desc->irq_data, IRQD_PER_CPU); | |
e1ef8241 TG |
663 | if (irq_settings_can_move_pcntxt(desc)) |
664 | irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT); | |
a005677b | 665 | |
876dbd4c TG |
666 | irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc)); |
667 | ||
02725e74 | 668 | irq_put_desc_unlock(desc, flags); |
46f4f8f6 | 669 | } |