Skip to content

Commit

Permalink
genirq: Add CPU mask affinity hint
Browse files Browse the repository at this point in the history
This patch adds a cpumask affinity hint to the irq_desc structure,
along with a registration function and a read-only proc entry for each
interrupt.

This affinity_hint handle for each interrupt can be used by underlying
drivers that need a better mechanism to control interrupt affinity.
The underlying driver can register a cpumask for the interrupt, which
will allow the driver to provide the CPU mask for the interrupt to
anything that requests it.  The intent is to extend the userspace
daemon, irqbalance, to help hint to it a preferred CPU mask to balance
the interrupt into.

[ tglx: Fixed compile warnings, added WARN_ON, made SMP only ]

Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Cc: davem@davemloft.net
Cc: arjan@linux.jf.intel.com
Cc: bhutchings@solarflare.com
LKML-Reference: <20100430214445.3992.41647.stgit@ppwaskie-hc2.jf.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Peter P Waskiewicz Jr authored and Thomas Gleixner committed May 3, 2010
1 parent 6932bf3 commit e7a297b
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 0 deletions.
6 changes: 6 additions & 0 deletions include/linux/interrupt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions include/linux/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
22 changes: 22 additions & 0 deletions kernel/irq/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down
39 changes: 39 additions & 0 deletions kernel/irq/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit e7a297b

Please sign in to comment.