diff options
Diffstat (limited to 'kernel/irq/resend.c')
| -rw-r--r-- | kernel/irq/resend.c | 31 | 
1 files changed, 20 insertions, 11 deletions
diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index 891115a929a..9065107f083 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c @@ -23,7 +23,7 @@  #ifdef CONFIG_HARDIRQS_SW_RESEND  /* Bitmap to handle software resend of interrupts: */ -static DECLARE_BITMAP(irqs_resend, NR_IRQS); +static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS);  /*   * Run software resends of IRQ's @@ -55,24 +55,33 @@ static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0);   */  void check_irq_resend(struct irq_desc *desc, unsigned int irq)  { -	unsigned int status = desc->status; - -	/* -	 * Make sure the interrupt is enabled, before resending it: -	 */ -	desc->irq_data.chip->irq_enable(&desc->irq_data); -  	/*  	 * We do not resend level type interrupts. Level type  	 * interrupts are resent by hardware when they are still -	 * active. +	 * active. Clear the pending bit so suspend/resume does not +	 * get confused.  	 */ -	if ((status & (IRQ_LEVEL | IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { -		desc->status = (status & ~IRQ_PENDING) | IRQ_REPLAY; +	if (irq_settings_is_level(desc)) { +		desc->istate &= ~IRQS_PENDING; +		return; +	} +	if (desc->istate & IRQS_REPLAY) +		return; +	if (desc->istate & IRQS_PENDING) { +		desc->istate &= ~IRQS_PENDING; +		desc->istate |= IRQS_REPLAY;  		if (!desc->irq_data.chip->irq_retrigger ||  		    !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) {  #ifdef CONFIG_HARDIRQS_SW_RESEND +			/* +			 * 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;  			/* Set it pending and activate the softirq: */  			set_bit(irq, irqs_resend);  			tasklet_schedule(&resend_tasklet);  | 
