diff options
Diffstat (limited to 'kernel/irq/manage.c')
| -rw-r--r-- | kernel/irq/manage.c | 73 | 
1 files changed, 66 insertions, 7 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index ef0bc02c3a70..73a2b786b5e9 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -115,12 +115,12 @@ EXPORT_SYMBOL(synchronize_irq);  #ifdef CONFIG_SMP  cpumask_var_t irq_default_affinity; -static int __irq_can_set_affinity(struct irq_desc *desc) +static bool __irq_can_set_affinity(struct irq_desc *desc)  {  	if (!desc || !irqd_can_balance(&desc->irq_data) ||  	    !desc->irq_data.chip || !desc->irq_data.chip->irq_set_affinity) -		return 0; -	return 1; +		return false; +	return true;  }  /** @@ -134,6 +134,21 @@ int irq_can_set_affinity(unsigned int irq)  }  /** + * irq_can_set_affinity_usr - Check if affinity of a irq can be set from user space + * @irq:	Interrupt to check + * + * Like irq_can_set_affinity() above, but additionally checks for the + * AFFINITY_MANAGED flag. + */ +bool irq_can_set_affinity_usr(unsigned int irq) +{ +	struct irq_desc *desc = irq_to_desc(irq); + +	return __irq_can_set_affinity(desc) && +		!irqd_affinity_is_managed(&desc->irq_data); +} + +/**   *	irq_set_thread_affinity - Notify irq threads to adjust affinity   *	@desc:		irq descriptor which has affitnity changed   * @@ -338,10 +353,11 @@ static int setup_affinity(struct irq_desc *desc, struct cpumask *mask)  		return 0;  	/* -	 * Preserve an userspace affinity setup, but make sure that -	 * one of the targets is online. +	 * Preserve the managed affinity setting and an userspace affinity +	 * setup, but make sure that one of the targets is online.  	 */ -	if (irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) { +	if (irqd_affinity_is_managed(&desc->irq_data) || +	    irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) {  		if (cpumask_intersects(desc->irq_common_data.affinity,  				       cpu_online_mask))  			set = desc->irq_common_data.affinity; @@ -1117,6 +1133,13 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)  	new->irq = irq;  	/* +	 * If the trigger type is not specified by the caller, +	 * then use the default for this interrupt. +	 */ +	if (!(new->flags & IRQF_TRIGGER_MASK)) +		new->flags |= irqd_get_trigger_type(&desc->irq_data); + +	/*  	 * Check whether the interrupt nests into another interrupt  	 * thread.  	 */ @@ -1409,10 +1432,18 @@ int setup_irq(unsigned int irq, struct irqaction *act)  	if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))  		return -EINVAL; + +	retval = irq_chip_pm_get(&desc->irq_data); +	if (retval < 0) +		return retval; +  	chip_bus_lock(desc);  	retval = __setup_irq(irq, desc, act);  	chip_bus_sync_unlock(desc); +	if (retval) +		irq_chip_pm_put(&desc->irq_data); +  	return retval;  }  EXPORT_SYMBOL_GPL(setup_irq); @@ -1506,6 +1537,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)  		}  	} +	irq_chip_pm_put(&desc->irq_data);  	module_put(desc->owner);  	kfree(action->secondary);  	return action; @@ -1648,11 +1680,16 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,  	action->name = devname;  	action->dev_id = dev_id; +	retval = irq_chip_pm_get(&desc->irq_data); +	if (retval < 0) +		return retval; +  	chip_bus_lock(desc);  	retval = __setup_irq(irq, desc, action);  	chip_bus_sync_unlock(desc);  	if (retval) { +		irq_chip_pm_put(&desc->irq_data);  		kfree(action->secondary);  		kfree(action);  	} @@ -1730,7 +1767,14 @@ void enable_percpu_irq(unsigned int irq, unsigned int type)  	if (!desc)  		return; +	/* +	 * If the trigger type is not specified by the caller, then +	 * use the default for this interrupt. +	 */  	type &= IRQ_TYPE_SENSE_MASK; +	if (type == IRQ_TYPE_NONE) +		type = irqd_get_trigger_type(&desc->irq_data); +  	if (type != IRQ_TYPE_NONE) {  		int ret; @@ -1822,6 +1866,7 @@ static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_  	unregister_handler_proc(irq, action); +	irq_chip_pm_put(&desc->irq_data);  	module_put(desc->owner);  	return action; @@ -1884,10 +1929,18 @@ int setup_percpu_irq(unsigned int irq, struct irqaction *act)  	if (!desc || !irq_settings_is_per_cpu_devid(desc))  		return -EINVAL; + +	retval = irq_chip_pm_get(&desc->irq_data); +	if (retval < 0) +		return retval; +  	chip_bus_lock(desc);  	retval = __setup_irq(irq, desc, act);  	chip_bus_sync_unlock(desc); +	if (retval) +		irq_chip_pm_put(&desc->irq_data); +  	return retval;  } @@ -1931,12 +1984,18 @@ int request_percpu_irq(unsigned int irq, irq_handler_t handler,  	action->name = devname;  	action->percpu_dev_id = dev_id; +	retval = irq_chip_pm_get(&desc->irq_data); +	if (retval < 0) +		return retval; +  	chip_bus_lock(desc);  	retval = __setup_irq(irq, desc, action);  	chip_bus_sync_unlock(desc); -	if (retval) +	if (retval) { +		irq_chip_pm_put(&desc->irq_data);  		kfree(action); +	}  	return retval;  }  |