aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/autoprobe.c4
-rw-r--r--kernel/irq/chip.c42
-rw-r--r--kernel/irq/internals.h2
-rw-r--r--kernel/irq/manage.c2
4 files changed, 37 insertions, 13 deletions
diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c
index 342d8f44e401..0119b9d467ae 100644
--- a/kernel/irq/autoprobe.c
+++ b/kernel/irq/autoprobe.c
@@ -53,7 +53,7 @@ unsigned long probe_irq_on(void)
53 if (desc->irq_data.chip->irq_set_type) 53 if (desc->irq_data.chip->irq_set_type)
54 desc->irq_data.chip->irq_set_type(&desc->irq_data, 54 desc->irq_data.chip->irq_set_type(&desc->irq_data,
55 IRQ_TYPE_PROBE); 55 IRQ_TYPE_PROBE);
56 irq_startup(desc); 56 irq_startup(desc, false);
57 } 57 }
58 raw_spin_unlock_irq(&desc->lock); 58 raw_spin_unlock_irq(&desc->lock);
59 } 59 }
@@ -70,7 +70,7 @@ unsigned long probe_irq_on(void)
70 raw_spin_lock_irq(&desc->lock); 70 raw_spin_lock_irq(&desc->lock);
71 if (!desc->action && irq_settings_can_probe(desc)) { 71 if (!desc->action && irq_settings_can_probe(desc)) {
72 desc->istate |= IRQS_AUTODETECT | IRQS_WAITING; 72 desc->istate |= IRQS_AUTODETECT | IRQS_WAITING;
73 if (irq_startup(desc)) 73 if (irq_startup(desc, false))
74 desc->istate |= IRQS_PENDING; 74 desc->istate |= IRQS_PENDING;
75 } 75 }
76 raw_spin_unlock_irq(&desc->lock); 76 raw_spin_unlock_irq(&desc->lock);
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index f7c543a801d9..fb7db75ee0c8 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -157,19 +157,22 @@ static void irq_state_set_masked(struct irq_desc *desc)
157 irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); 157 irqd_set(&desc->irq_data, IRQD_IRQ_MASKED);
158} 158}
159 159
160int irq_startup(struct irq_desc *desc) 160int irq_startup(struct irq_desc *desc, bool resend)
161{ 161{
162 int ret = 0;
163
162 irq_state_clr_disabled(desc); 164 irq_state_clr_disabled(desc);
163 desc->depth = 0; 165 desc->depth = 0;
164 166
165 if (desc->irq_data.chip->irq_startup) { 167 if (desc->irq_data.chip->irq_startup) {
166 int ret = desc->irq_data.chip->irq_startup(&desc->irq_data); 168 ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
167 irq_state_clr_masked(desc); 169 irq_state_clr_masked(desc);
168 return ret; 170 } else {
171 irq_enable(desc);
169 } 172 }
170 173 if (resend)
171 irq_enable(desc); 174 check_irq_resend(desc, desc->irq_data.irq);
172 return 0; 175 return ret;
173} 176}
174 177
175void irq_shutdown(struct irq_desc *desc) 178void irq_shutdown(struct irq_desc *desc)
@@ -330,6 +333,24 @@ out_unlock:
330} 333}
331EXPORT_SYMBOL_GPL(handle_simple_irq); 334EXPORT_SYMBOL_GPL(handle_simple_irq);
332 335
336/*
337 * Called unconditionally from handle_level_irq() and only for oneshot
338 * interrupts from handle_fasteoi_irq()
339 */
340static void cond_unmask_irq(struct irq_desc *desc)
341{
342 /*
343 * We need to unmask in the following cases:
344 * - Standard level irq (IRQF_ONESHOT is not set)
345 * - Oneshot irq which did not wake the thread (caused by a
346 * spurious interrupt or a primary handler handling it
347 * completely).
348 */
349 if (!irqd_irq_disabled(&desc->irq_data) &&
350 irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot)
351 unmask_irq(desc);
352}
353
333/** 354/**
334 * handle_level_irq - Level type irq handler 355 * handle_level_irq - Level type irq handler
335 * @irq: the interrupt number 356 * @irq: the interrupt number
@@ -362,8 +383,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
362 383
363 handle_irq_event(desc); 384 handle_irq_event(desc);
364 385
365 if (!irqd_irq_disabled(&desc->irq_data) && !(desc->istate & IRQS_ONESHOT)) 386 cond_unmask_irq(desc);
366 unmask_irq(desc); 387
367out_unlock: 388out_unlock:
368 raw_spin_unlock(&desc->lock); 389 raw_spin_unlock(&desc->lock);
369} 390}
@@ -417,6 +438,9 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
417 preflow_handler(desc); 438 preflow_handler(desc);
418 handle_irq_event(desc); 439 handle_irq_event(desc);
419 440
441 if (desc->istate & IRQS_ONESHOT)
442 cond_unmask_irq(desc);
443
420out_eoi: 444out_eoi:
421 desc->irq_data.chip->irq_eoi(&desc->irq_data); 445 desc->irq_data.chip->irq_eoi(&desc->irq_data);
422out_unlock: 446out_unlock:
@@ -625,7 +649,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
625 irq_settings_set_noprobe(desc); 649 irq_settings_set_noprobe(desc);
626 irq_settings_set_norequest(desc); 650 irq_settings_set_norequest(desc);
627 irq_settings_set_nothread(desc); 651 irq_settings_set_nothread(desc);
628 irq_startup(desc); 652 irq_startup(desc, true);
629 } 653 }
630out: 654out:
631 irq_put_desc_busunlock(desc, flags); 655 irq_put_desc_busunlock(desc, flags);
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index b7952316016a..40378ff877e7 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -67,7 +67,7 @@ extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
67extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp); 67extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp);
68extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume); 68extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume);
69 69
70extern int irq_startup(struct irq_desc *desc); 70extern int irq_startup(struct irq_desc *desc, bool resend);
71extern void irq_shutdown(struct irq_desc *desc); 71extern void irq_shutdown(struct irq_desc *desc);
72extern void irq_enable(struct irq_desc *desc); 72extern void irq_enable(struct irq_desc *desc);
73extern void irq_disable(struct irq_desc *desc); 73extern void irq_disable(struct irq_desc *desc);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index a9a9dbe49fea..32313c084442 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1027,7 +1027,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
1027 desc->istate |= IRQS_ONESHOT; 1027 desc->istate |= IRQS_ONESHOT;
1028 1028
1029 if (irq_settings_can_autoenable(desc)) 1029 if (irq_settings_can_autoenable(desc))
1030 irq_startup(desc); 1030 irq_startup(desc, true);
1031 else 1031 else
1032 /* Undo nested disables: */ 1032 /* Undo nested disables: */
1033 desc->depth = 1; 1033 desc->depth = 1;