diff options
| -rw-r--r-- | include/linux/irq.h | 9 | ||||
| -rw-r--r-- | include/linux/irqdesc.h | 3 | ||||
| -rw-r--r-- | kernel/irq/chip.c | 1 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 16 | ||||
| -rw-r--r-- | kernel/irq/resend.c | 8 | 
5 files changed, 37 insertions, 0 deletions
diff --git a/include/linux/irq.h b/include/linux/irq.h index 216b0ba109d..526f10a637c 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -392,6 +392,15 @@ static inline void irq_move_masked_irq(struct irq_data *data) { }  extern int no_irq_affinity; +#ifdef CONFIG_HARDIRQS_SW_RESEND +int irq_set_parent(int irq, int parent_irq); +#else +static inline int irq_set_parent(int irq, int parent_irq) +{ +	return 0; +} +#endif +  /*   * Built-in IRQ handlers for various IRQ types,   * callable via desc->handle_irq() diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 0ba014c5505..623325e2ff9 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -11,6 +11,8 @@  struct irq_affinity_notify;  struct proc_dir_entry;  struct module; +struct irq_desc; +  /**   * struct irq_desc - interrupt descriptor   * @irq_data:		per irq and chip data passed down to chip functions @@ -65,6 +67,7 @@ struct irq_desc {  #ifdef CONFIG_PROC_FS  	struct proc_dir_entry	*dir;  #endif +	int			parent_irq;  	struct module		*owner;  	const char		*name;  } ____cacheline_internodealigned_in_smp; diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 57d86d07221..3aca9f29d30 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -272,6 +272,7 @@ void handle_nested_irq(unsigned int irq)  	raw_spin_lock_irq(&desc->lock); +	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);  	kstat_incr_irqs_this_cpu(irq, desc);  	action = desc->action; diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 4c69326aa77..d06a396c7ce 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -616,6 +616,22 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,  	return ret;  } +#ifdef CONFIG_HARDIRQS_SW_RESEND +int irq_set_parent(int irq, int parent_irq) +{ +	unsigned long flags; +	struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); + +	if (!desc) +		return -EINVAL; + +	desc->parent_irq = parent_irq; + +	irq_put_desc_unlock(desc, flags); +	return 0; +} +#endif +  /*   * Default primary interrupt handler for threaded interrupts. Is   * assigned as primary handler when request_threaded_irq is called diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index 6454db7b6a4..9065107f083 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c @@ -74,6 +74,14 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq)  		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);  |