2006-06-29 13:24:48 +04:00
/*
* linux / kernel / irq / resend . c
*
* Copyright ( C ) 1992 , 1998 - 2006 Linus Torvalds , Ingo Molnar
* Copyright ( C ) 2005 - 2006 , Thomas Gleixner
*
* This file contains the IRQ - resend code
*
* If the interrupt is waiting to be processed , we try to re - run it .
* We can ' t directly run it from here since the caller might be in an
* interrupt - protected region . Not all irq controller chips can
* retrigger interrupts at the hardware level , so in those cases
* we allow the resending of IRQs via a tasklet .
*/
# include <linux/irq.h>
# include <linux/module.h>
# include <linux/random.h>
# include <linux/interrupt.h>
# include "internals.h"
# ifdef CONFIG_HARDIRQS_SW_RESEND
/* Bitmap to handle software resend of interrupts: */
2011-02-17 19:45:15 +03:00
static DECLARE_BITMAP ( irqs_resend , IRQ_BITMAP_BITS ) ;
2006-06-29 13:24:48 +04:00
/*
* Run software resends of IRQ ' s
*/
static void resend_irqs ( unsigned long arg )
{
struct irq_desc * desc ;
int irq ;
2008-08-20 07:49:47 +04:00
while ( ! bitmap_empty ( irqs_resend , nr_irqs ) ) {
irq = find_first_bit ( irqs_resend , nr_irqs ) ;
2006-06-29 13:24:48 +04:00
clear_bit ( irq , irqs_resend ) ;
2008-08-20 07:50:05 +04:00
desc = irq_to_desc ( irq ) ;
2006-06-29 13:24:51 +04:00
local_irq_disable ( ) ;
2006-10-06 22:58:24 +04:00
desc - > handle_irq ( irq , desc ) ;
2006-06-29 13:24:51 +04:00
local_irq_enable ( ) ;
2006-06-29 13:24:48 +04:00
}
}
/* Tasklet to handle resend: */
static DECLARE_TASKLET ( resend_tasklet , resend_irqs , 0 ) ;
# endif
/*
* IRQ resend
*
* Is called with interrupts disabled and desc - > lock held .
*/
void check_irq_resend ( struct irq_desc * desc , unsigned int irq )
{
2007-08-12 19:46:35 +04:00
/*
* We do not resend level type interrupts . Level type
* interrupts are resent by hardware when they are still
2012-04-25 14:54:54 +04:00
* active . Clear the pending bit so suspend / resume does not
* get confused .
2007-08-12 19:46:35 +04:00
*/
2012-04-25 14:54:54 +04:00
if ( irq_settings_is_level ( desc ) ) {
desc - > istate & = ~ IRQS_PENDING ;
2011-02-03 14:27:44 +03:00
return ;
2012-04-25 14:54:54 +04:00
}
2011-02-08 13:39:15 +03:00
if ( desc - > istate & IRQS_REPLAY )
return ;
2011-02-08 14:17:57 +03:00
if ( desc - > istate & IRQS_PENDING ) {
desc - > istate & = ~ IRQS_PENDING ;
2011-02-08 13:39:15 +03:00
desc - > istate | = IRQS_REPLAY ;
2006-06-29 13:24:48 +04:00
2010-09-27 16:45:53 +04:00
if ( ! desc - > irq_data . chip - > irq_retrigger | |
! desc - > irq_data . chip - > irq_retrigger ( & desc - > irq_data ) ) {
2006-06-29 13:24:48 +04:00
# ifdef CONFIG_HARDIRQS_SW_RESEND
2012-10-17 02:07:49 +04:00
/*
* If the interrupt has a parent irq and runs
* in the thread context of the parent irq ,
* retrigger the parent .
*/
if ( desc - > parent_irq & &
irq_settings_is_nested_thread ( desc ) )
irq = desc - > parent_irq ;
2006-06-29 13:24:48 +04:00
/* Set it pending and activate the softirq: */
set_bit ( irq , irqs_resend ) ;
tasklet_schedule ( & resend_tasklet ) ;
# endif
}
}
}