diff options
| author | Peter Zijlstra <peterz@infradead.org> | 2015-02-05 08:06:23 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2015-02-18 09:08:33 -0500 |
| commit | 02cea3958664723a5d2236f0f0058de97c7e4693 (patch) | |
| tree | 0bf1e7116f925131c34dc1bc217942a6e6f00688 /kernel/irq | |
| parent | 4fe7ffb7e17ca6ad9173b8de35f260c9c8fc2f79 (diff) | |
genirq: Provide disable_hardirq()
For things like netpoll there is a need to disable an interrupt from
atomic context. Currently netpoll uses disable_irq() which will
sleep-wait on threaded handlers and thus forced_irqthreads breaks
things.
Provide disable_hardirq(), which uses synchronize_hardirq() to only wait
for active hardirq handlers; also change synchronize_hardirq() to
return the status of threaded handlers.
This will allow one to try-disable an interrupt from atomic context, or
in case of request_threaded_irq() to only wait for the hardirq part.
Suggested-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: David Miller <davem@davemloft.net>
Cc: Eyal Perry <eyalpe@mellanox.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Quentin Lambert <lambert.quentin@gmail.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Russell King <linux@arm.linux.org.uk>
Link: http://lkml.kernel.org/r/20150205130623.GH5029@twins.programming.kicks-ass.net
[ Fixed typos and such. ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/irq')
| -rw-r--r-- | kernel/irq/manage.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 196a06fbc122..03329c2287eb 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -68,14 +68,20 @@ static void __synchronize_hardirq(struct irq_desc *desc) | |||
| 68 | * Do not use this for shutdown scenarios where you must be sure | 68 | * Do not use this for shutdown scenarios where you must be sure |
| 69 | * that all parts (hardirq and threaded handler) have completed. | 69 | * that all parts (hardirq and threaded handler) have completed. |
| 70 | * | 70 | * |
| 71 | * Returns: false if a threaded handler is active. | ||
| 72 | * | ||
| 71 | * This function may be called - with care - from IRQ context. | 73 | * This function may be called - with care - from IRQ context. |
| 72 | */ | 74 | */ |
| 73 | void synchronize_hardirq(unsigned int irq) | 75 | bool synchronize_hardirq(unsigned int irq) |
| 74 | { | 76 | { |
| 75 | struct irq_desc *desc = irq_to_desc(irq); | 77 | struct irq_desc *desc = irq_to_desc(irq); |
| 76 | 78 | ||
| 77 | if (desc) | 79 | if (desc) { |
| 78 | __synchronize_hardirq(desc); | 80 | __synchronize_hardirq(desc); |
| 81 | return !atomic_read(&desc->threads_active); | ||
| 82 | } | ||
| 83 | |||
| 84 | return true; | ||
| 79 | } | 85 | } |
| 80 | EXPORT_SYMBOL(synchronize_hardirq); | 86 | EXPORT_SYMBOL(synchronize_hardirq); |
| 81 | 87 | ||
| @@ -440,6 +446,32 @@ void disable_irq(unsigned int irq) | |||
| 440 | } | 446 | } |
| 441 | EXPORT_SYMBOL(disable_irq); | 447 | EXPORT_SYMBOL(disable_irq); |
| 442 | 448 | ||
| 449 | /** | ||
| 450 | * disable_hardirq - disables an irq and waits for hardirq completion | ||
| 451 | * @irq: Interrupt to disable | ||
| 452 | * | ||
| 453 | * Disable the selected interrupt line. Enables and Disables are | ||
| 454 | * nested. | ||
| 455 | * This function waits for any pending hard IRQ handlers for this | ||
| 456 | * interrupt to complete before returning. If you use this function while | ||
| 457 | * holding a resource the hard IRQ handler may need you will deadlock. | ||
| 458 | * | ||
| 459 | * When used to optimistically disable an interrupt from atomic context | ||
| 460 | * the return value must be checked. | ||
| 461 | * | ||
| 462 | * Returns: false if a threaded handler is active. | ||
| 463 | * | ||
| 464 | * This function may be called - with care - from IRQ context. | ||
| 465 | */ | ||
| 466 | bool disable_hardirq(unsigned int irq) | ||
| 467 | { | ||
| 468 | if (!__disable_irq_nosync(irq)) | ||
| 469 | return synchronize_hardirq(irq); | ||
| 470 | |||
| 471 | return false; | ||
| 472 | } | ||
| 473 | EXPORT_SYMBOL_GPL(disable_hardirq); | ||
| 474 | |||
| 443 | void __enable_irq(struct irq_desc *desc, unsigned int irq) | 475 | void __enable_irq(struct irq_desc *desc, unsigned int irq) |
| 444 | { | 476 | { |
| 445 | switch (desc->depth) { | 477 | switch (desc->depth) { |
