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