diff options
Diffstat (limited to 'kernel/irq/manage.c')
| -rw-r--r-- | kernel/irq/manage.c | 41 | 
1 files changed, 39 insertions, 2 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 4c69326aa77..35c70c9e24d 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 @@ -716,6 +732,7 @@ static void  irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)  {  	cpumask_var_t mask; +	bool valid = true;  	if (!test_and_clear_bit(IRQTF_AFFINITY, &action->thread_flags))  		return; @@ -730,10 +747,18 @@ irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)  	}  	raw_spin_lock_irq(&desc->lock); -	cpumask_copy(mask, desc->irq_data.affinity); +	/* +	 * This code is triggered unconditionally. Check the affinity +	 * mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out. +	 */ +	if (desc->irq_data.affinity) +		cpumask_copy(mask, desc->irq_data.affinity); +	else +		valid = false;  	raw_spin_unlock_irq(&desc->lock); -	set_cpus_allowed_ptr(current, mask); +	if (valid) +		set_cpus_allowed_ptr(current, mask);  	free_cpumask_var(mask);  }  #else @@ -833,6 +858,8 @@ static int irq_thread(void *data)  	init_task_work(&on_exit_work, irq_thread_dtor);  	task_work_add(current, &on_exit_work, false); +	irq_thread_check_affinity(desc, action); +  	while (!irq_wait_for_interrupt(action)) {  		irqreturn_t action_ret; @@ -936,6 +963,16 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  		 */  		get_task_struct(t);  		new->thread = t; +		/* +		 * Tell the thread to set its affinity. This is +		 * important for shared interrupt handlers as we do +		 * not invoke setup_affinity() for the secondary +		 * handlers as everything is already set up. Even for +		 * interrupts marked with IRQF_NO_BALANCE this is +		 * correct as we want the thread to move to the cpu(s) +		 * on which the requesting code placed the interrupt. +		 */ +		set_bit(IRQTF_AFFINITY, &new->thread_flags);  	}  	if (!alloc_cpumask_var(&mask, GFP_KERNEL)) {  |