aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2014-03-13 14:03:51 -0400
committerThomas Gleixner <tglx@linutronix.de>2014-03-14 08:43:33 -0400
commit328a4978df833249b099c9875738d7b72042ffe1 (patch)
tree8d35f45b166d16d5bdcbf40d12331118453384d6 /kernel/irq
parent4f6e4f71c9d39cf49e0cb1be5b7721db5fbe92ac (diff)
genirq: Add a new IRQCHIP_EOI_THREADED flag
The flag is necessary for interrupt chips which require an ACK/EOI after the handler has run. In case of threaded handlers this needs to happen after the threaded handler has completed before the unmask of the interrupt. The flag is only unseful in combination with the handle_fasteoi_irq flow control handler. It can be combined with the flag IRQCHIP_EOI_IF_HANDLED, so the EOI is not issued when the interrupt is disabled or in progress. Tested-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Cc: linux-arm-kernel@lists.infradead.org Cc: linux-sunxi@googlegroups.com Cc: Maxime Ripard <maxime.ripard@free-electrons.com> Link: http://lkml.kernel.org/r/1394733834-26839-2-git-send-email-hdegoede@redhat.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/chip.c48
-rw-r--r--kernel/irq/internals.h1
-rw-r--r--kernel/irq/manage.c2
3 files changed, 42 insertions, 9 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index dc04c166c54d..6397df2d6945 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -281,6 +281,19 @@ void unmask_irq(struct irq_desc *desc)
281 } 281 }
282} 282}
283 283
284void unmask_threaded_irq(struct irq_desc *desc)
285{
286 struct irq_chip *chip = desc->irq_data.chip;
287
288 if (chip->flags & IRQCHIP_EOI_THREADED)
289 chip->irq_eoi(&desc->irq_data);
290
291 if (chip->irq_unmask) {
292 chip->irq_unmask(&desc->irq_data);
293 irq_state_clr_masked(desc);
294 }
295}
296
284/* 297/*
285 * handle_nested_irq - Handle a nested irq from a irq thread 298 * handle_nested_irq - Handle a nested irq from a irq thread
286 * @irq: the interrupt number 299 * @irq: the interrupt number
@@ -435,6 +448,27 @@ static inline void preflow_handler(struct irq_desc *desc)
435static inline void preflow_handler(struct irq_desc *desc) { } 448static inline void preflow_handler(struct irq_desc *desc) { }
436#endif 449#endif
437 450
451static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
452{
453 if (!(desc->istate & IRQS_ONESHOT)) {
454 chip->irq_eoi(&desc->irq_data);
455 return;
456 }
457 /*
458 * We need to unmask in the following cases:
459 * - Oneshot irq which did not wake the thread (caused by a
460 * spurious interrupt or a primary handler handling it
461 * completely).
462 */
463 if (!irqd_irq_disabled(&desc->irq_data) &&
464 irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) {
465 chip->irq_eoi(&desc->irq_data);
466 unmask_irq(desc);
467 } else if (!(chip->flags & IRQCHIP_EOI_THREADED)) {
468 chip->irq_eoi(&desc->irq_data);
469 }
470}
471
438/** 472/**
439 * handle_fasteoi_irq - irq handler for transparent controllers 473 * handle_fasteoi_irq - irq handler for transparent controllers
440 * @irq: the interrupt number 474 * @irq: the interrupt number
@@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { }
448void 482void
449handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) 483handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
450{ 484{
485 struct irq_chip *chip = desc->irq_data.chip;
486
451 raw_spin_lock(&desc->lock); 487 raw_spin_lock(&desc->lock);
452 488
453 if (unlikely(irqd_irq_inprogress(&desc->irq_data))) 489 if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
@@ -473,18 +509,14 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
473 preflow_handler(desc); 509 preflow_handler(desc);
474 handle_irq_event(desc); 510 handle_irq_event(desc);
475 511
476 if (desc->istate & IRQS_ONESHOT) 512 cond_unmask_eoi_irq(desc, chip);
477 cond_unmask_irq(desc);
478 513
479out_eoi:
480 desc->irq_data.chip->irq_eoi(&desc->irq_data);
481out_unlock:
482 raw_spin_unlock(&desc->lock); 514 raw_spin_unlock(&desc->lock);
483 return; 515 return;
484out: 516out:
485 if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED)) 517 if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))
486 goto out_eoi; 518 chip->irq_eoi(&desc->irq_data);
487 goto out_unlock; 519 raw_spin_unlock(&desc->lock);
488} 520}
489 521
490/** 522/**
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 17b671713d5f..ddf1ffeb79f1 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -74,6 +74,7 @@ extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
74extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu); 74extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu);
75extern void mask_irq(struct irq_desc *desc); 75extern void mask_irq(struct irq_desc *desc);
76extern void unmask_irq(struct irq_desc *desc); 76extern void unmask_irq(struct irq_desc *desc);
77extern void unmask_threaded_irq(struct irq_desc *desc);
77 78
78extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); 79extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
79 80
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index de1a8ed29b40..2486a4c1a710 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -748,7 +748,7 @@ again:
748 748
749 if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && 749 if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) &&
750 irqd_irq_masked(&desc->irq_data)) 750 irqd_irq_masked(&desc->irq_data))
751 unmask_irq(desc); 751 unmask_threaded_irq(desc);
752 752
753out_unlock: 753out_unlock:
754 raw_spin_unlock_irq(&desc->lock); 754 raw_spin_unlock_irq(&desc->lock);