diff options
| -rw-r--r-- | include/linux/interrupt.h | 6 | ||||
| -rw-r--r-- | include/linux/irq.h | 1 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 22 | ||||
| -rw-r--r-- | kernel/irq/proc.c | 39 | 
4 files changed, 68 insertions, 0 deletions
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index e6d2f4441fd..5137db3317f 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -233,6 +233,7 @@ extern int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask);  extern int irq_can_set_affinity(unsigned int irq);  extern int irq_select_affinity(unsigned int irq); +extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m);  #else /* CONFIG_SMP */  static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m) @@ -247,6 +248,11 @@ static inline int irq_can_set_affinity(unsigned int irq)  static inline int irq_select_affinity(unsigned int irq)  { return 0; } +static inline int irq_set_affinity_hint(unsigned int irq, +                                        const struct cpumask *m) +{ +	return -EINVAL; +}  #endif /* CONFIG_SMP && CONFIG_GENERIC_HARDIRQS */  #ifdef CONFIG_GENERIC_HARDIRQS diff --git a/include/linux/irq.h b/include/linux/irq.h index 707ab122e2e..c03243ad84b 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -195,6 +195,7 @@ struct irq_desc {  	raw_spinlock_t		lock;  #ifdef CONFIG_SMP  	cpumask_var_t		affinity; +	const struct cpumask	*affinity_hint;  	unsigned int		node;  #ifdef CONFIG_GENERIC_PENDING_IRQ  	cpumask_var_t		pending_mask; diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 444d5a81a20..3164ba7ce15 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -138,6 +138,22 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)  	return 0;  } +int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m) +{ +	struct irq_desc *desc = irq_to_desc(irq); +	unsigned long flags; + +	if (!desc) +		return -EINVAL; + +	raw_spin_lock_irqsave(&desc->lock, flags); +	desc->affinity_hint = m; +	raw_spin_unlock_irqrestore(&desc->lock, flags); + +	return 0; +} +EXPORT_SYMBOL_GPL(irq_set_affinity_hint); +  #ifndef CONFIG_AUTO_IRQ_AFFINITY  /*   * Generic version of the affinity autoselector. @@ -906,6 +922,12 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)  			desc->chip->disable(irq);  	} +#ifdef CONFIG_SMP +	/* make sure affinity_hint is cleaned up */ +	if (WARN_ON_ONCE(desc->affinity_hint)) +		desc->affinity_hint = NULL; +#endif +  	raw_spin_unlock_irqrestore(&desc->lock, flags);  	unregister_handler_proc(irq, action); diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index fe92dc5190d..4f9427a30e1 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -32,6 +32,29 @@ static int irq_affinity_proc_show(struct seq_file *m, void *v)  	return 0;  } +static int irq_affinity_hint_proc_show(struct seq_file *m, void *v) +{ +	struct irq_desc *desc = irq_to_desc((long)m->private); +	unsigned long flags; +	cpumask_var_t mask; + +	if (!alloc_cpumask_var(&mask, GFP_KERNEL)) +		return -ENOMEM; + +	raw_spin_lock_irqsave(&desc->lock, flags); +	if (desc->affinity_hint) +		cpumask_copy(mask, desc->affinity_hint); +	else +		cpumask_setall(mask); +	raw_spin_unlock_irqrestore(&desc->lock, flags); + +	seq_cpumask(m, mask); +	seq_putc(m, '\n'); +	free_cpumask_var(mask); + +	return 0; +} +  #ifndef is_affinity_mask_valid  #define is_affinity_mask_valid(val) 1  #endif @@ -84,6 +107,11 @@ static int irq_affinity_proc_open(struct inode *inode, struct file *file)  	return single_open(file, irq_affinity_proc_show, PDE(inode)->data);  } +static int irq_affinity_hint_proc_open(struct inode *inode, struct file *file) +{ +	return single_open(file, irq_affinity_hint_proc_show, PDE(inode)->data); +} +  static const struct file_operations irq_affinity_proc_fops = {  	.open		= irq_affinity_proc_open,  	.read		= seq_read, @@ -92,6 +120,13 @@ static const struct file_operations irq_affinity_proc_fops = {  	.write		= irq_affinity_proc_write,  }; +static const struct file_operations irq_affinity_hint_proc_fops = { +	.open		= irq_affinity_hint_proc_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +}; +  static int default_affinity_show(struct seq_file *m, void *v)  {  	seq_cpumask(m, irq_default_affinity); @@ -252,6 +287,10 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)  	proc_create_data("smp_affinity", 0600, desc->dir,  			 &irq_affinity_proc_fops, (void *)(long)irq); +	/* create /proc/irq/<irq>/affinity_hint */ +	proc_create_data("affinity_hint", 0400, desc->dir, +			 &irq_affinity_hint_proc_fops, (void *)(long)irq); +  	proc_create_data("node", 0444, desc->dir,  			 &irq_node_proc_fops, (void *)(long)irq);  #endif  |