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>
This commit is contained in:
Родитель
4fe7ffb7e1
Коммит
02cea39586
|
@ -9,7 +9,7 @@
|
|||
|
||||
|
||||
extern void synchronize_irq(unsigned int irq);
|
||||
extern void synchronize_hardirq(unsigned int irq);
|
||||
extern bool synchronize_hardirq(unsigned int irq);
|
||||
|
||||
#if defined(CONFIG_TINY_RCU)
|
||||
|
||||
|
|
|
@ -184,6 +184,7 @@ extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
|
|||
#endif
|
||||
|
||||
extern void disable_irq_nosync(unsigned int irq);
|
||||
extern bool disable_hardirq(unsigned int irq);
|
||||
extern void disable_irq(unsigned int irq);
|
||||
extern void disable_percpu_irq(unsigned int irq);
|
||||
extern void enable_irq(unsigned int irq);
|
||||
|
|
|
@ -68,14 +68,20 @@ static void __synchronize_hardirq(struct irq_desc *desc)
|
|||
* Do not use this for shutdown scenarios where you must be sure
|
||||
* that all parts (hardirq and threaded handler) have completed.
|
||||
*
|
||||
* Returns: false if a threaded handler is active.
|
||||
*
|
||||
* This function may be called - with care - from IRQ context.
|
||||
*/
|
||||
void synchronize_hardirq(unsigned int irq)
|
||||
bool synchronize_hardirq(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
if (desc)
|
||||
if (desc) {
|
||||
__synchronize_hardirq(desc);
|
||||
return !atomic_read(&desc->threads_active);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(synchronize_hardirq);
|
||||
|
||||
|
@ -440,6 +446,32 @@ void disable_irq(unsigned int irq)
|
|||
}
|
||||
EXPORT_SYMBOL(disable_irq);
|
||||
|
||||
/**
|
||||
* disable_hardirq - disables an irq and waits for hardirq completion
|
||||
* @irq: Interrupt to disable
|
||||
*
|
||||
* Disable the selected interrupt line. Enables and Disables are
|
||||
* nested.
|
||||
* This function waits for any pending hard IRQ handlers for this
|
||||
* interrupt to complete before returning. If you use this function while
|
||||
* holding a resource the hard IRQ handler may need you will deadlock.
|
||||
*
|
||||
* When used to optimistically disable an interrupt from atomic context
|
||||
* the return value must be checked.
|
||||
*
|
||||
* Returns: false if a threaded handler is active.
|
||||
*
|
||||
* This function may be called - with care - from IRQ context.
|
||||
*/
|
||||
bool disable_hardirq(unsigned int irq)
|
||||
{
|
||||
if (!__disable_irq_nosync(irq))
|
||||
return synchronize_hardirq(irq);
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(disable_hardirq);
|
||||
|
||||
void __enable_irq(struct irq_desc *desc, unsigned int irq)
|
||||
{
|
||||
switch (desc->depth) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче