2008-12-11 00:15:01 -08:00
/*
2008-12-19 13:48:34 -08:00
* NUMA irq - desc migration code
2008-12-11 00:15:01 -08:00
*
2008-12-19 13:48:34 -08:00
* Migrate IRQ data structures ( irq_desc , chip_data , etc . ) over to
* the new " home node " of the IRQ .
2008-12-11 00:15:01 -08:00
*/
# include <linux/irq.h>
# include <linux/module.h>
# include <linux/random.h>
# include <linux/interrupt.h>
# include <linux/kernel_stat.h>
# include "internals.h"
static void init_copy_kstat_irqs ( struct irq_desc * old_desc ,
struct irq_desc * desc ,
int cpu , int nr )
{
unsigned long bytes ;
init_kstat_irqs ( desc , cpu , nr ) ;
if ( desc - > kstat_irqs ! = old_desc - > kstat_irqs ) {
/* Compute how many bytes we need per irq and allocate them */
bytes = nr * sizeof ( unsigned int ) ;
memcpy ( desc - > kstat_irqs , old_desc - > kstat_irqs , bytes ) ;
}
}
static void free_kstat_irqs ( struct irq_desc * old_desc , struct irq_desc * desc )
{
if ( old_desc - > kstat_irqs = = desc - > kstat_irqs )
return ;
kfree ( old_desc - > kstat_irqs ) ;
old_desc - > kstat_irqs = NULL ;
}
static void init_copy_one_irq_desc ( int irq , struct irq_desc * old_desc ,
struct irq_desc * desc , int cpu )
{
memcpy ( desc , old_desc , sizeof ( struct irq_desc ) ) ;
2008-12-26 19:02:20 +01:00
spin_lock_init ( & desc - > lock ) ;
2008-12-11 00:15:01 -08:00
desc - > cpu = cpu ;
lockdep_set_class ( & desc - > lock , & irq_desc_lock_class ) ;
init_copy_kstat_irqs ( old_desc , desc , cpu , nr_cpu_ids ) ;
arch_init_copy_chip_data ( old_desc , desc , cpu ) ;
}
static void free_one_irq_desc ( struct irq_desc * old_desc , struct irq_desc * desc )
{
free_kstat_irqs ( old_desc , desc ) ;
arch_free_chip_data ( old_desc , desc ) ;
}
static struct irq_desc * __real_move_irq_desc ( struct irq_desc * old_desc ,
int cpu )
{
struct irq_desc * desc ;
unsigned int irq ;
unsigned long flags ;
int node ;
irq = old_desc - > irq ;
spin_lock_irqsave ( & sparse_irq_lock , flags ) ;
/* We have to check it to avoid races with another CPU */
desc = irq_desc_ptrs [ irq ] ;
if ( desc & & old_desc ! = desc )
2009-01-31 14:50:07 -08:00
goto out_unlock ;
2008-12-11 00:15:01 -08:00
node = cpu_to_node ( cpu ) ;
desc = kzalloc_node ( sizeof ( * desc ) , GFP_ATOMIC , node ) ;
if ( ! desc ) {
2008-12-26 19:10:04 +01:00
printk ( KERN_ERR " irq %d: can not get new irq_desc for migration. \n " , irq ) ;
2008-12-11 00:15:01 -08:00
/* still use old one */
desc = old_desc ;
goto out_unlock ;
}
init_copy_one_irq_desc ( irq , old_desc , desc , cpu ) ;
irq_desc_ptrs [ irq ] = desc ;
2009-01-31 14:50:07 -08:00
spin_unlock_irqrestore ( & sparse_irq_lock , flags ) ;
2008-12-11 00:15:01 -08:00
/* free the old one */
free_one_irq_desc ( old_desc , desc ) ;
2009-01-31 14:50:07 -08:00
spin_unlock ( & old_desc - > lock ) ;
2008-12-11 00:15:01 -08:00
kfree ( old_desc ) ;
2009-01-31 14:50:07 -08:00
spin_lock ( & desc - > lock ) ;
return desc ;
2008-12-11 00:15:01 -08:00
out_unlock :
spin_unlock_irqrestore ( & sparse_irq_lock , flags ) ;
return desc ;
}
struct irq_desc * move_irq_desc ( struct irq_desc * desc , int cpu )
{
int old_cpu ;
int node , old_node ;
/* those all static, do move them */
if ( desc - > irq < NR_IRQS_LEGACY )
return desc ;
old_cpu = desc - > cpu ;
if ( old_cpu ! = cpu ) {
node = cpu_to_node ( cpu ) ;
old_node = cpu_to_node ( old_cpu ) ;
if ( old_node ! = node )
desc = __real_move_irq_desc ( desc , cpu ) ;
else
desc - > cpu = cpu ;
}
return desc ;
}