diff options
Diffstat (limited to 'kernel/irq/chip.c')
-rw-r--r-- | kernel/irq/chip.c | 47 |
1 files changed, 36 insertions, 11 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index f7c543a801d9..6080f6bc8c33 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/kernel_stat.h> | 17 | #include <linux/kernel_stat.h> |
18 | 18 | ||
19 | #include <trace/events/irq.h> | ||
20 | |||
19 | #include "internals.h" | 21 | #include "internals.h" |
20 | 22 | ||
21 | /** | 23 | /** |
@@ -61,8 +63,7 @@ int irq_set_irq_type(unsigned int irq, unsigned int type) | |||
61 | return -EINVAL; | 63 | return -EINVAL; |
62 | 64 | ||
63 | type &= IRQ_TYPE_SENSE_MASK; | 65 | type &= IRQ_TYPE_SENSE_MASK; |
64 | if (type != IRQ_TYPE_NONE) | 66 | ret = __irq_set_trigger(desc, irq, type); |
65 | ret = __irq_set_trigger(desc, irq, type); | ||
66 | irq_put_desc_busunlock(desc, flags); | 67 | irq_put_desc_busunlock(desc, flags); |
67 | return ret; | 68 | return ret; |
68 | } | 69 | } |
@@ -157,19 +158,22 @@ static void irq_state_set_masked(struct irq_desc *desc) | |||
157 | irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); | 158 | irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); |
158 | } | 159 | } |
159 | 160 | ||
160 | int irq_startup(struct irq_desc *desc) | 161 | int irq_startup(struct irq_desc *desc, bool resend) |
161 | { | 162 | { |
163 | int ret = 0; | ||
164 | |||
162 | irq_state_clr_disabled(desc); | 165 | irq_state_clr_disabled(desc); |
163 | desc->depth = 0; | 166 | desc->depth = 0; |
164 | 167 | ||
165 | if (desc->irq_data.chip->irq_startup) { | 168 | if (desc->irq_data.chip->irq_startup) { |
166 | int ret = desc->irq_data.chip->irq_startup(&desc->irq_data); | 169 | ret = desc->irq_data.chip->irq_startup(&desc->irq_data); |
167 | irq_state_clr_masked(desc); | 170 | irq_state_clr_masked(desc); |
168 | return ret; | 171 | } else { |
172 | irq_enable(desc); | ||
169 | } | 173 | } |
170 | 174 | if (resend) | |
171 | irq_enable(desc); | 175 | check_irq_resend(desc, desc->irq_data.irq); |
172 | return 0; | 176 | return ret; |
173 | } | 177 | } |
174 | 178 | ||
175 | void irq_shutdown(struct irq_desc *desc) | 179 | void irq_shutdown(struct irq_desc *desc) |
@@ -330,6 +334,24 @@ out_unlock: | |||
330 | } | 334 | } |
331 | EXPORT_SYMBOL_GPL(handle_simple_irq); | 335 | EXPORT_SYMBOL_GPL(handle_simple_irq); |
332 | 336 | ||
337 | /* | ||
338 | * Called unconditionally from handle_level_irq() and only for oneshot | ||
339 | * interrupts from handle_fasteoi_irq() | ||
340 | */ | ||
341 | static void cond_unmask_irq(struct irq_desc *desc) | ||
342 | { | ||
343 | /* | ||
344 | * We need to unmask in the following cases: | ||
345 | * - Standard level irq (IRQF_ONESHOT is not set) | ||
346 | * - Oneshot irq which did not wake the thread (caused by a | ||
347 | * spurious interrupt or a primary handler handling it | ||
348 | * completely). | ||
349 | */ | ||
350 | if (!irqd_irq_disabled(&desc->irq_data) && | ||
351 | irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) | ||
352 | unmask_irq(desc); | ||
353 | } | ||
354 | |||
333 | /** | 355 | /** |
334 | * handle_level_irq - Level type irq handler | 356 | * handle_level_irq - Level type irq handler |
335 | * @irq: the interrupt number | 357 | * @irq: the interrupt number |
@@ -362,8 +384,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
362 | 384 | ||
363 | handle_irq_event(desc); | 385 | handle_irq_event(desc); |
364 | 386 | ||
365 | if (!irqd_irq_disabled(&desc->irq_data) && !(desc->istate & IRQS_ONESHOT)) | 387 | cond_unmask_irq(desc); |
366 | unmask_irq(desc); | 388 | |
367 | out_unlock: | 389 | out_unlock: |
368 | raw_spin_unlock(&desc->lock); | 390 | raw_spin_unlock(&desc->lock); |
369 | } | 391 | } |
@@ -417,6 +439,9 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | |||
417 | preflow_handler(desc); | 439 | preflow_handler(desc); |
418 | handle_irq_event(desc); | 440 | handle_irq_event(desc); |
419 | 441 | ||
442 | if (desc->istate & IRQS_ONESHOT) | ||
443 | cond_unmask_irq(desc); | ||
444 | |||
420 | out_eoi: | 445 | out_eoi: |
421 | desc->irq_data.chip->irq_eoi(&desc->irq_data); | 446 | desc->irq_data.chip->irq_eoi(&desc->irq_data); |
422 | out_unlock: | 447 | out_unlock: |
@@ -625,7 +650,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
625 | irq_settings_set_noprobe(desc); | 650 | irq_settings_set_noprobe(desc); |
626 | irq_settings_set_norequest(desc); | 651 | irq_settings_set_norequest(desc); |
627 | irq_settings_set_nothread(desc); | 652 | irq_settings_set_nothread(desc); |
628 | irq_startup(desc); | 653 | irq_startup(desc, true); |
629 | } | 654 | } |
630 | out: | 655 | out: |
631 | irq_put_desc_busunlock(desc, flags); | 656 | irq_put_desc_busunlock(desc, flags); |