genirq: Add CPU mask affinity hint
authorPeter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Fri, 30 Apr 2010 21:44:50 +0000 (14:44 -0700)
committerThomas Gleixner <tglx@linutronix.de>
Mon, 3 May 2010 09:50:57 +0000 (11:50 +0200)
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>
include/linux/interrupt.h
include/linux/irq.h
kernel/irq/manage.c
kernel/irq/proc.c

index e6d2f4441fda6baa9d45e19a5dbca8df67911ac4..5137db3317f9341d86ad35c17d341dca67bd2493 100644 (file)
@@ -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
index 707ab122e2e68cf7e3e1d7af284cbfd419c2d6c2..c03243ad84b46b220324d499b18e0805e9fb827b 100644 (file)
@@ -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;
index 444d5a81a20919d15a9762247ad88a3137f43649..3164ba7ce151cf6c228613ddce2195450af30012 100644 (file)
@@ -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);
index fe92dc5190dd724441b30df9c25e1a4219353d93..4f9427a30e141c816091b4b797f790fcf1815746 100644 (file)
@@ -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