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
* active .
*/
2011-02-03 14:27:44 +03:00
if ( desc - > status & IRQ_LEVEL )
return ;
2011-02-08 13:39:15 +03:00
if ( desc - > istate & IRQS_REPLAY )
return ;
if ( desc - > status & IRQ_PENDING ) {
desc - > status & = ~ IRQ_PENDING ;
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
/* Set it pending and activate the softirq: */
set_bit ( irq , irqs_resend ) ;
tasklet_schedule ( & resend_tasklet ) ;
# endif
}
}
}