1/* 2 * NUMA irq-desc migration code 3 * 4 * Migrate IRQ data structures (irq_desc, chip_data, etc.) over to 5 * the new "home node" of the IRQ. 6 */ 7 8#include <linux/irq.h> 9#include <linux/slab.h> 10#include <linux/module.h> 11#include <linux/random.h> 12#include <linux/interrupt.h> 13#include <linux/kernel_stat.h> 14 15#include "internals.h" 16 17static void init_copy_kstat_irqs(struct irq_desc *old_desc, 18 struct irq_desc *desc, 19 int node, int nr) 20{ 21 init_kstat_irqs(desc, node, nr); 22 23 if (desc->kstat_irqs != old_desc->kstat_irqs) 24 memcpy(desc->kstat_irqs, old_desc->kstat_irqs, 25 nr * sizeof(*desc->kstat_irqs)); 26} 27 28static void free_kstat_irqs(struct irq_desc *old_desc, struct irq_desc *desc) 29{ 30 if (old_desc->kstat_irqs == desc->kstat_irqs) 31 return; 32 33 kfree(old_desc->kstat_irqs); 34 old_desc->kstat_irqs = NULL; 35} 36 37static bool init_copy_one_irq_desc(int irq, struct irq_desc *old_desc, 38 struct irq_desc *desc, int node) 39{ 40 memcpy(desc, old_desc, sizeof(struct irq_desc)); 41 if (!alloc_desc_masks(desc, node, false)) { 42 printk(KERN_ERR "irq %d: can not get new irq_desc cpumask " 43 "for migration.\n", irq); 44 return false; 45 } 46 raw_spin_lock_init(&desc->lock); 47 desc->node = node; 48 lockdep_set_class(&desc->lock, &irq_desc_lock_class); 49 init_copy_kstat_irqs(old_desc, desc, node, nr_cpu_ids); 50 init_copy_desc_masks(old_desc, desc); 51 arch_init_copy_chip_data(old_desc, desc, node); 52 return true; 53} 54 55static void free_one_irq_desc(struct irq_desc *old_desc, struct irq_desc *desc) 56{ 57 free_kstat_irqs(old_desc, desc); 58 free_desc_masks(old_desc, desc); 59 arch_free_chip_data(old_desc, desc); 60} 61 62static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc, 63 int node) 64{ 65 struct irq_desc *desc; 66 unsigned int irq; 67 unsigned long flags; 68 69 irq = old_desc->irq; 70 71 raw_spin_lock_irqsave(&sparse_irq_lock, flags); 72 73 /* We have to check it to avoid races with another CPU */ 74 desc = irq_to_desc(irq); 75 76 if (desc && old_desc != desc) 77 goto out_unlock; 78 79 desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node); 80 if (!desc) { 81 printk(KERN_ERR "irq %d: can not get new irq_desc " 82 "for migration.\n", irq); 83 /* still use old one */ 84 desc = old_desc; 85 goto out_unlock; 86 } 87 if (!init_copy_one_irq_desc(irq, old_desc, desc, node)) { 88 /* still use old one */ 89 kfree(desc); 90 desc = old_desc; 91 goto out_unlock; 92 } 93 94 replace_irq_desc(irq, desc); 95 raw_spin_unlock_irqrestore(&sparse_irq_lock, flags); 96 97 /* free the old one */ 98 free_one_irq_desc(old_desc, desc); 99 kfree(old_desc); 100 101 return desc; 102 103out_unlock: 104 raw_spin_unlock_irqrestore(&sparse_irq_lock, flags); 105 106 return desc; 107} 108 109struct irq_desc *move_irq_desc(struct irq_desc *desc, int node) 110{ 111 /* those static or target node is -1, do not move them */ 112 if (desc->irq < NR_IRQS_LEGACY || node == -1) 113 return desc; 114 115 if (desc->node != node) 116 desc = __real_move_irq_desc(desc, node); 117 118 return desc; 119} 120