diff options
Diffstat (limited to 'kernel/irq/manage.c')
| -rw-r--r-- | kernel/irq/manage.c | 37 | 
1 files changed, 35 insertions, 2 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 4c2ef8084e32..daeabd791d58 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -205,6 +205,39 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,  	return ret;  } +#ifdef CONFIG_GENERIC_PENDING_IRQ +static inline int irq_set_affinity_pending(struct irq_data *data, +					   const struct cpumask *dest) +{ +	struct irq_desc *desc = irq_data_to_desc(data); + +	irqd_set_move_pending(data); +	irq_copy_pending(desc, dest); +	return 0; +} +#else +static inline int irq_set_affinity_pending(struct irq_data *data, +					   const struct cpumask *dest) +{ +	return -EBUSY; +} +#endif + +static int irq_try_set_affinity(struct irq_data *data, +				const struct cpumask *dest, bool force) +{ +	int ret = irq_do_set_affinity(data, dest, force); + +	/* +	 * In case that the underlying vector management is busy and the +	 * architecture supports the generic pending mechanism then utilize +	 * this to avoid returning an error to user space. +	 */ +	if (ret == -EBUSY && !force) +		ret = irq_set_affinity_pending(data, dest); +	return ret; +} +  int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,  			    bool force)  { @@ -215,8 +248,8 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,  	if (!chip || !chip->irq_set_affinity)  		return -EINVAL; -	if (irq_can_move_pcntxt(data)) { -		ret = irq_do_set_affinity(data, mask, force); +	if (irq_can_move_pcntxt(data) && !irqd_is_setaffinity_pending(data)) { +		ret = irq_try_set_affinity(data, mask, force);  	} else {  		irqd_set_move_pending(data);  		irq_copy_pending(desc, mask);  | 
