aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/manage.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2014-02-14 19:55:18 -0500
committerThomas Gleixner <tglx@linutronix.de>2014-02-19 11:22:44 -0500
commit18258f7239a61d8929b8e0c7b6d46c446459074c (patch)
treedce8fcb83bdf02120fa6ae419262936aa33b49ca /kernel/irq/manage.c
parent6d0abeca3242a88cab8232e4acd7e2bf088f3bc2 (diff)
genirq: Provide synchronize_hardirq()
synchronize_irq() waits for hard irq and threaded handlers to complete before returning. For some special cases we only need to make sure that the hard interrupt part of the irq line is not in progress when we disabled the - possibly shared - interrupt at the device level. A proper use case for this was provided by Russell. The sdhci driver requires some irq triggered functions to be run in thread context. The current implementation of the thread context is a sdio private kthread construct, which has quite some shortcomings. These can be avoided when the thread is directly associated to the device interrupt via the generic threaded irq infrastructure. Though there is a corner case related to run time power management where one side disables the device interrupts at the device level and needs to make sure, that an already running hard interrupt handler has completed before proceeding further. Though that hard interrupt handler might wake the associated thread, which in turn can request the runtime PM to reenable the device. Using synchronize_irq() leads to an immediate deadlock of the irq thread waiting for the PM lock and the synchronize_irq() waiting for the irq thread to complete. Due to the fact that it is sufficient for this case to ensure that no hard irq handler is executing a new function which avoids the check for the thread is required. Add a function, which just monitors the hard irq parts and ignores the threaded handlers. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Russell King <linux@arm.linux.org.uk> Cc: Chris Ball <chris@printf.net> Acked-by: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20140215003823.653236081@linutronix.de
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r--kernel/irq/manage.c70
1 files changed, 50 insertions, 20 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 481a13c43b17..274ba9238fb7 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -32,24 +32,10 @@ static int __init setup_forced_irqthreads(char *arg)
32early_param("threadirqs", setup_forced_irqthreads); 32early_param("threadirqs", setup_forced_irqthreads);
33#endif 33#endif
34 34
35/** 35static void __synchronize_hardirq(struct irq_desc *desc)
36 * synchronize_irq - wait for pending IRQ handlers (on other CPUs)
37 * @irq: interrupt number to wait for
38 *
39 * This function waits for any pending IRQ handlers for this interrupt
40 * to complete before returning. If you use this function while
41 * holding a resource the IRQ handler may need you will deadlock.
42 *
43 * This function may be called - with care - from IRQ context.
44 */
45void synchronize_irq(unsigned int irq)
46{ 36{
47 struct irq_desc *desc = irq_to_desc(irq);
48 bool inprogress; 37 bool inprogress;
49 38
50 if (!desc)
51 return;
52
53 do { 39 do {
54 unsigned long flags; 40 unsigned long flags;
55 41
@@ -67,12 +53,56 @@ void synchronize_irq(unsigned int irq)
67 53
68 /* Oops, that failed? */ 54 /* Oops, that failed? */
69 } while (inprogress); 55 } while (inprogress);
56}
70 57
71 /* 58/**
72 * We made sure that no hardirq handler is running. Now verify 59 * synchronize_hardirq - wait for pending hard IRQ handlers (on other CPUs)
73 * that no threaded handlers are active. 60 * @irq: interrupt number to wait for
74 */ 61 *
75 wait_event(desc->wait_for_threads, !atomic_read(&desc->threads_active)); 62 * This function waits for any pending hard IRQ handlers for this
63 * interrupt to complete before returning. If you use this
64 * function while holding a resource the IRQ handler may need you
65 * will deadlock. It does not take associated threaded handlers
66 * into account.
67 *
68 * Do not use this for shutdown scenarios where you must be sure
69 * that all parts (hardirq and threaded handler) have completed.
70 *
71 * This function may be called - with care - from IRQ context.
72 */
73void synchronize_hardirq(unsigned int irq)
74{
75 struct irq_desc *desc = irq_to_desc(irq);
76
77 if (desc)
78 __synchronize_hardirq(desc);
79}
80EXPORT_SYMBOL(synchronize_hardirq);
81
82/**
83 * synchronize_irq - wait for pending IRQ handlers (on other CPUs)
84 * @irq: interrupt number to wait for
85 *
86 * This function waits for any pending IRQ handlers for this interrupt
87 * to complete before returning. If you use this function while
88 * holding a resource the IRQ handler may need you will deadlock.
89 *
90 * This function may be called - with care - from IRQ context.
91 */
92void synchronize_irq(unsigned int irq)
93{
94 struct irq_desc *desc = irq_to_desc(irq);
95
96 if (desc) {
97 __synchronize_hardirq(desc);
98 /*
99 * We made sure that no hardirq handler is
100 * running. Now verify that no threaded handlers are
101 * active.
102 */
103 wait_event(desc->wait_for_threads,
104 !atomic_read(&desc->threads_active));
105 }
76} 106}
77EXPORT_SYMBOL(synchronize_irq); 107EXPORT_SYMBOL(synchronize_irq);
78 108