sparse irq enabling v5
Subsystems (7)
PATCH 1/5 sparse irq enabling v5
impact: new feature sparseirq
add pointers array as Ingo suggesting.
remove dyna_array
when sparse_irq is used (CONFIG_SPARSE_IRQ), use kzalloc_node to get irq_desc, irq_cfg
use desc->chip_data for x86 to store irq_cfg
--- arch/x86/Kconfig | 10 + arch/x86/include/asm/irq_vectors.h | 9 + arch/x86/kernel/io_apic.c | 301 +++++++++++++++++++++++-------------- arch/x86/kernel/irq.c | 3 arch/x86/kernel/irq_32.c | 2 arch/x86/kernel/irq_64.c | 2 arch/x86/kernel/irqinit_32.c | 1 arch/x86/kernel/irqinit_64.c | 1 drivers/char/random.c | 22 -- drivers/pci/intr_remapping.c | 76 +++++++++ drivers/xen/events.c | 12 - fs/proc/stat.c | 17 +- include/linux/interrupt.h | 2 include/linux/irq.h | 54 ++++++ include/linux/irqnr.h | 14 - include/linux/kernel_stat.h | 14 + include/linux/random.h | 51 ++++++ init/main.c | 11 + kernel/irq/autoprobe.c | 15 + kernel/irq/chip.c | 3 kernel/irq/handle.c | 181 +++++++++++++++++++++- kernel/irq/proc.c | 6 kernel/irq/spurious.c | 5 23 files changed, 649 insertions(+), 163 deletions(-)
arch/x86/Kconfig +10 -0
@@ -243,6 +243,16 @@ config X86_HAS_BOOT_CPU_ID def_bool y depends on X86_VOYAGER +config SPARSE_IRQ + bool "Support sparse irq numbering" + depends on PCI_MSI || HT_IRQ + default y + help + This enables support for sparse irq, esp for msi/msi-x. You may need + if you have lots of cards supports msi-x installed. + + If you don't know what to do here, say Y. + config X86_FIND_SMP_CONFIG def_bool y depends on X86_MPPARSE || X86_VOYAGER
arch/x86/include/asm/irq_vectors.h +9 -0
@@ -102,11 +102,20 @@#define invalid_vm86_irq (irq) ((irq) < 3 || (irq) > 15)#if defined(CONFIG_X86_IO_APIC ) && !defined(CONFIG_X86_VOYAGER ) + +#ifndef CONFIG_SPARSE_IRQ # if NR_CPUS <MAX_IO_APICS # define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))# else # define NR_IRQS (NR_VECTORS + (32 * MAX_IO_APICS))# endif +#else +# if (8 *NR_CPUS ) > (32 *MAX_IO_APICS ) +# define NR_IRQS (NR_VECTORS + (8 * NR_CPUS)) +# else +# define NR_IRQS (NR_VECTORS + (32 * MAX_IO_APICS)) +# endif +#endif #elif defined(CONFIG_X86_VOYAGER )
arch/x86/kernel/io_apic.c +190 -111
541 lines not on this page · raw message
arch/x86/kernel/irq.c +3 -0
@@ -118,6 +118,9 @@ int show_interrupts(struct seq_file *p, } desc =irq_to_desc (i); +if (!desc) +return 0 ; +spin_lock_irqsave (&desc->lock, flags);#ifndef CONFIG_SMP any_count =kstat_irqs (i);
arch/x86/kernel/irq_32.c +2 -0
@@ -242,6 +242,8 @@ void fixup_irqs(cpumask_t map)for_each_irq_desc (irq, desc) {cpumask_t mask; +if (!desc) +continue ;if (irq ==2 )continue ;
arch/x86/kernel/irq_64.c +2 -0
@@ -90,6 +90,8 @@ void fixup_irqs(cpumask_t map)int break_affinity =0 ;int set_affinity =1 ; +if (!desc) +continue ;if (irq ==2 )continue ;
arch/x86/kernel/irqinit_32.c +0 -1
@@ -69,7 +69,6 @@ void __init init_ISA_irqs (void)* 16 old-style INTA-cycle interrupts: */ for (i =0 ; i <16 ; i++) { -/* first time call this irq_desc */ struct irq_desc *desc =irq_to_desc (i); desc->status =IRQ_DISABLED ;
arch/x86/kernel/irqinit_64.c +0 -1
@@ -77,7 +77,6 @@ void __init init_ISA_irqs(void)init_8259A (0 );for (i =0 ; i <16 ; i++) { -/* first time call this irq_desc */ struct irq_desc *desc =irq_to_desc (i); desc->status =IRQ_DISABLED ;
drivers/char/random.c +5 -17
@@ -558,23 +558,9 @@ struct timer_rand_state { unsigned dont_count_entropy:1; }; -static struct timer_rand_state *irq_timer_state[NR_IRQS ]; - -static struct timer_rand_state *get_timer_rand_state (unsigned int irq) -{ -if (irq >= nr_irqs) -return NULL ; - -return irq_timer_state[irq]; -} - -static void set_timer_rand_state (unsigned int irq,struct timer_rand_state *state) -{ -if (irq >= nr_irqs) -return ; - - irq_timer_state[irq] = state; -} +#ifndef CONFIG_SPARSE_IRQ +struct timer_rand_state *irq_timer_state[NR_IRQS ]; +#endif static struct timer_rand_state input_timer_state;
@@ -933,8 +919,10 @@ void rand_initialize_irq(int irq) {struct timer_rand_state *state; +#ifndef CONFIG_SPARSE_IRQ if (irq >= nr_irqs)return ; +#endif state =get_timer_rand_state (irq);
drivers/pci/intr_remapping.c +74 -2
112 lines not on this page · raw message
drivers/xen/events.c +8 -4
@@ -141,8 +141,12 @@ static void init_evtchn_cpu_bindings(voiint i;/* By default all event channels notify CPU#0. */ -for_each_irq_desc (i, desc) +for_each_irq_desc (i, desc) { +if (!desc) +continue ; + desc->affinity =cpumask_of_cpu (0 ); + }#endif memset (cpu_evtchn,0 ,sizeof (cpu_evtchn));
@@ -231,7 +235,7 @@ static int find_unbound_irq(void)int irq;/* Only allocate from dynirq range */ -for_each_irq_nr (irq) +for (irq =0 ; irq < nr_irqs; irq++)if (irq_bindcount[irq] ==0 )break ;
@@ -792,7 +796,7 @@ void xen_irq_resume(void)mask_evtchn (evtchn);/* No IRQ <-> event-channel mappings. */ -for_each_irq_nr (irq) +for (irq =0 ; irq < nr_irqs; irq++) irq_info[irq].evtchn =0 ;/* zap event-channel binding */ for (evtchn =0 ; evtchn <NR_EVENT_CHANNELS ; evtchn++)
@@ -824,7 +828,7 @@ void __init xen_init_IRQ(void)mask_evtchn (i);/* Dynamic IRQ space is currently unbound. Zero the refcnts. */ -for_each_irq_nr (i) +for (i =0 ; i < nr_irqs; i++) irq_bindcount[i] =0 ;irq_ctx_init (smp_processor_id ());
fs/proc/stat.c +11 -6
@@ -27,6 +27,7 @@ static int show_stat(struct seq_file *p,u64 sum =0 ;struct timespec boottime;unsigned int per_irq_sum; +struct irq_desc *desc; user = nice = system = idle = iowait = irq = softirq = steal = cputime64_zero;
@@ -44,10 +45,11 @@ static int show_stat(struct seq_file *p, softirq =cputime64_add (softirq,kstat_cpu (i).cpustat.softirq); steal =cputime64_add (steal,kstat_cpu (i).cpustat.steal); guest =cputime64_add (guest,kstat_cpu (i).cpustat.guest); - -for_each_irq_nr (j) +for_each_irq_desc (j, desc) { +if (!desc) +continue ; sum +=kstat_irqs_cpu (j, i); - + } sum +=arch_irq_stat_cpu (i); } sum +=arch_irq_stat ();
@@ -90,11 +92,14 @@ static int show_stat(struct seq_file *p,seq_printf (p,"intr %llu" , (unsigned long long )sum);/* sum again ? it could be updated? */ -for_each_irq_nr (j) { +for (j =0 ; j <NR_IRQS ; j++) { + desc =irq_to_desc (j); per_irq_sum =0 ; -for_each_possible_cpu (i) - per_irq_sum +=kstat_irqs_cpu (j, i); +if (desc) { +for_each_possible_cpu (i) + per_irq_sum +=kstat_irqs_cpu (j, i); + }seq_printf (p," %u" , per_irq_sum); }
include/linux/interrupt.h +2 -0
@@ -18,6 +18,8 @@#include <asm/ptrace.h> #include <asm/system.h> +extern int nr_irqs; +/* * These correspond to the IORESOURCE_IRQ_* defines in * linux/ioport.h to select the interrupt line behaviour. When
include/linux/irq.h +53 -1
85 lines not on this page · raw message
include/linux/irqnr.h +3 -11
@@ -7,18 +7,10 @@# define for_each_irq_desc (irq, desc) \ for (irq = 0; irq < nr_irqs; irq++) -#else -extern int nr_irqs; -# define for_each_irq_desc (irq, desc) \ - for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++) - -# define for_each_irq_desc_reverse (irq, desc) \ - for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1); \ - irq >= 0; irq--, desc--) +static inline early_sparse_irq_init (void) +{ +}#endif -#define for_each_irq_nr (irq) \ - for (irq = 0; irq < nr_irqs; irq++) -#endif
include/linux/kernel_stat.h +13 -1
@@ -28,7 +28,9 @@ struct cpu_usage_stat {struct kernel_stat {struct cpu_usage_stat cpustat; -unsigned int irqs[NR_IRQS ]; +#ifndef CONFIG_SPARSE_IRQ +unsigned int irqs[NR_IRQS ]; +#endif }; DECLARE_PER_CPU(struct kernel_stat, kstat);
@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, kstaextern unsigned long long nr_context_switches (void ); +#ifndef CONFIG_SPARSE_IRQ +#define kstat_irqs_this_cpu (irq) \ + (kstat_this_cpu.irqs[irq]) +struct irq_desc ; static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_ { kstat_this_cpu.irqs[irq]++; } +#endif + +#ifndef CONFIG_SPARSE_IRQ static inline unsigned int kstat_irqs_cpu (unsigned int irq,int cpu) {return kstat_cpu (cpu).irqs[irq]; } +#else +extern unsigned int kstat_irqs_cpu (unsigned int irq,int cpu); +#endif /* * Number of interrupts per specific IRQ source, since bootup
include/linux/random.h +51 -0
57 lines not on this page · raw message
init/main.c +11 -0
@@ -542,6 +542,15 @@ void __init __weak thread_info_cache_ini { } +void __init __weak arch_early_irq_init (void ) +{ +} + +void __init __weak early_irq_init (void ) +{ +arch_early_irq_init (); +} + asmlinkage void __init start_kernel(void) {char * command_line;
@@ -612,6 +621,8 @@ asmlinkage void __init start_kernel(voidsort_main_extable ();trap_init ();rcu_init (); +/* init some links before init_ISA_irqs() */ +early_irq_init ();init_IRQ ();pidhash_init ();init_timers ();
kernel/irq/autoprobe.c +15 -0
@@ -40,6 +40,9 @@ unsigned long probe_irq_on(void)* flush such a longstanding irq before considering it as spurious. */ for_each_irq_desc_reverse (i, desc) { +if (!desc) +continue ; +spin_lock_irq (&desc->lock);if (!desc->action && !(desc->status &IRQ_NOPROBE )) {/*
@@ -68,6 +71,9 @@ unsigned long probe_irq_on(void)* happened in the previous stage, it may have masked itself) */ for_each_irq_desc_reverse (i, desc) { +if (!desc) +continue ; +spin_lock_irq (&desc->lock);if (!desc->action && !(desc->status &IRQ_NOPROBE )) { desc->status |=IRQ_AUTODETECT |IRQ_WAITING ;
@@ -86,6 +92,9 @@ unsigned long probe_irq_on(void)* Now filter out any obviously spurious interrupts */ for_each_irq_desc (i, desc) { +if (!desc) +continue ; +spin_lock_irq (&desc->lock); status = desc->status;
@@ -124,6 +133,9 @@ unsigned int probe_irq_mask(unsigned lonint i;for_each_irq_desc (i, desc) { +if (!desc) +continue ; +spin_lock_irq (&desc->lock); status = desc->status;
@@ -166,6 +178,9 @@ int probe_irq_off(unsigned long val)unsigned int status;for_each_irq_desc (i, desc) { +if (!desc) +continue ; +spin_lock_irq (&desc->lock); status = desc->status;
kernel/irq/chip.c +2 -1
@@ -24,9 +24,10 @@*/ void dynamic_irq_init (unsigned int irq) { -struct irq_desc *desc =irq_to_desc (irq); +struct irq_desc *desc;unsigned long flags; + desc =irq_to_desc (irq);if (!desc) {WARN (1 ,KERN_ERR "Trying to initialize invalid IRQ%d\n" , irq);return ;
kernel/irq/handle.c +175 -6
213 lines not on this page · raw message
kernel/irq/proc.c +5 -1
@@ -243,7 +243,11 @@ void init_irq_proc(void)/* * Create entries for all existing IRQs. */ -for_each_irq_desc (irq, desc) +for_each_irq_desc (irq, desc) { +if (!desc) +continue ; +register_irq_proc (irq, desc); + } }
kernel/irq/spurious.c +5 -0
@@ -91,6 +91,9 @@ static int misrouted_irq(int irq)int i, ok =0 ;for_each_irq_desc (i, desc) { +if (!desc) +continue ; +if (!i)continue ;
@@ -112,6 +115,8 @@ static void poll_spurious_irqs(unsignedfor_each_irq_desc (i, desc) {unsigned int status; +if (!desc) +continue ;if (!i)continue ;
PATCH 2/5 use NR_IRQS_LEGACY
impact: cleanup
instead of use hard code number
--- arch/x86/include/asm/irq_vectors.h | 2 ++ arch/x86/kernel/io_apic.c | 10 +++++----- arch/x86/kernel/irqinit_32.c | 2 +- arch/x86/kernel/irqinit_64.c | 2 +- kernel/irq/handle.c | 6 +++--- 5 files changed, 12 insertions(+), 10 deletions(-)
arch/x86/include/asm/irq_vectors.h +2 -0
@@ -101,6 +101,8 @@#define LAST_VM86_IRQ 15#define invalid_vm86_irq (irq) ((irq) < 3 || (irq) > 15) +#define NR_IRQS_LEGACY 16 +#if defined(CONFIG_X86_IO_APIC ) && !defined(CONFIG_X86_VOYAGER )#ifndef CONFIG_SPARSE_IRQ
arch/x86/kernel/io_apic.c +5 -5
@@ -847,7 +847,7 @@ EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector*/ static int EISA_ELCR (unsigned int irq) { -if (irq <16 ) { +if (irq <NR_IRQS_LEGACY ) {unsigned int port =0x4d0 + (irq >>3 );return (inb (port) >> (irq &7 )) &1 ; }
@@ -1388,7 +1388,7 @@ static void setup_IO_APIC_irq(int apic, }ioapic_register_intr (irq, trigger); -if (irq <16 ) +if (irq <NR_IRQS_LEGACY )disable_8259A_irq (irq);ioapic_write_entry (apic, pin, entry);
@@ -2080,7 +2080,7 @@ static unsigned int startup_ioapic_irq(ustruct irq_cfg *cfg;spin_lock_irqsave (&ioapic_lock, flags); -if (irq <16 ) { +if (irq <NR_IRQS_LEGACY ) {disable_8259A_irq (irq);if (i8259A_irq_pending (irq)) was_pending =1 ;
@@ -2504,7 +2504,7 @@ static inline void init_IO_APIC_traps(vo* so default to an old-fashioned 8259 * interrupt if we can.. */ -if (irq <16 ) +if (irq <NR_IRQS_LEGACY )make_8259A_irq (irq);else /* Strange. Oh, well.. */
@@ -3794,7 +3794,7 @@ int io_apic_set_pci_routing (int ioapic,/* * IRQs < 16 are already in the irq_2_pin[] map */ -if (irq >=16 ) { +if (irq >=NR_IRQS_LEGACY ) { cfg = desc->chip_data;add_pin_to_irq_cpu (irq, cpu, ioapic, pin); }
arch/x86/kernel/irqinit_32.c +1 -1
@@ -68,7 +68,7 @@ void __init init_ISA_irqs (void)/* * 16 old-style INTA-cycle interrupts: */ -for (i =0 ; i <16 ; i++) { +for (i =0 ; i <NR_IRQS_LEGACY ; i++) {struct irq_desc *desc =irq_to_desc (i); desc->status =IRQ_DISABLED ;
arch/x86/kernel/irqinit_64.c +1 -1
@@ -76,7 +76,7 @@ void __init init_ISA_irqs(void)init_bsp_APIC ();init_8259A (0 ); -for (i =0 ; i <16 ; i++) { +for (i =0 ; i <NR_IRQS_LEGACY ; i++) {struct irq_desc *desc =irq_to_desc (i); desc->status =IRQ_DISABLED ;
kernel/irq/handle.c +3 -3
@@ -117,8 +117,8 @@ static DEFINE_SPINLOCK(sparse_irq_lock);struct irq_desc *irq_desc_ptrs[NR_IRQS ]__read_mostly ; -static struct irq_desc irq_desc_legacy[16] __cacheline_aligned_in_smp = { - [0 ...15 ] = { +static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = { + [0 ...NR_IRQS_LEGACY -1 ] = { .irq =-1 , .status =IRQ_DISABLED , .chip = &no_irq_chip,
@@ -132,7 +132,7 @@ static struct irq_desc irq_desc_legacy[1 };/* FIXME: use bootmem alloc ...*/ -static unsigned int kstat_irqs_legacy[16 ][NR_CPUS ]; +static unsigned int kstat_irqs_legacy[NR_IRQS_LEGACY ][NR_CPUS ];void __init early_irq_init (void ) {
PATCH 3/5 MSI irq start from nr_irqs_gsi
In reply to Yinghai Luimpact: msr irq number ordering
increase that from nr_irqs_gsi instead of decresing from NR_IRQS
--- arch/x86/include/asm/io_apic.h | 2 +- arch/x86/kernel/io_apic.c | 24 +++++++++++++++++------- arch/x86/kernel/setup.c | 2 +- 3 files changed, 19 insertions(+), 9 deletions(-)
arch/x86/include/asm/io_apic.h +1 -1
@@ -198,7 +198,7 @@ extern void restore_IO_APIC_setup(void);extern void reinit_intr_remapped_IO_APIC (int );#endif -extern int probe_nr_irqs (void ); +extern void probe_nr_irqs_gsi (void );#else /* !CONFIG_X86_IO_APIC */ #define io_apic_assign_pci_irqs 0
arch/x86/kernel/io_apic.c +17 -7
@@ -2973,7 +2973,7 @@ unsigned int create_irq_nr(unsigned int irq =0 ;spin_lock_irqsave (&vector_lock, flags); -for (new = irq_want; new >0 ; new--) { +for (new = irq_want; new <NR_IRQS ; new++) {if (platform_legacy_irq (new))continue ;
@@ -3001,11 +3001,14 @@ unsigned int create_irq_nr(unsigned intreturn irq; } +static int nr_irqs_gsi =NR_IRQS_LEGACY ;int create_irq (void ) { +unsigned int irq_want;int irq; - irq =create_irq_nr (nr_irqs -1 ); + irq_want = nr_irqs_gsi; + irq =create_irq_nr (irq_want);if (irq ==0 ) irq =-1 ;
@@ -3281,7 +3284,7 @@ int arch_setup_msi_irq(struct pci_dev *dint ret;unsigned int irq_want; - irq_want = nr_irqs -1 ; + irq_want = nr_irqs_gsi; irq =create_irq_nr (irq_want);if (irq ==0 )return -1 ;
@@ -3321,11 +3324,11 @@ int arch_setup_msi_irqs(struct pci_dev *int index =0 ;#endif - irq_want = nr_irqs -1 ; + irq_want = nr_irqs_gsi; sub_handle =0 ;list_for_each_entry (msidesc, &dev->msi_list, list) { irq =create_irq_nr (irq_want); - irq_want--; + irq_want++;if (irq ==0 )return -1 ;#ifdef CONFIG_INTR_REMAP
@@ -3674,9 +3677,16 @@ int __init io_apic_get_redir_entries (inreturn reg_01.bits.entries; } -int __init probe_nr_irqs (void ) +void __init probe_nr_irqs_gsi (void ) { -return NR_IRQS ; +int idx; +int nr =0 ; + +for (idx =0 ; idx < nr_ioapics; idx++) + nr +=io_apic_get_redir_entries (idx) +1 ; + +if (nr > nr_irqs_gsi) + nr_irqs_gsi = nr; }/* --------------------------------------------------------------------------
arch/x86/kernel/setup.c +1 -1
@@ -954,7 +954,7 @@ void __init setup_arch(char **cmdline_p)ioapic_init_mappings ();/* need to wait for io_apic is mapped */ - nr_irqs =probe_nr_irqs (); +probe_nr_irqs_gsi ();kvm_guest_init ();
PATCH 4/5 pass irq_cfg and irq_desc
In reply to Yinghai Luimpact: only need pass cfg and desc
instead of keep look up for it
--- arch/x86/kernel/io_apic.c | 318 ++++++++++++++++++++++++++-------------------- drivers/pci/msi.c | 55 +++++-- include/linux/msi.h | 3 3 files changed, 222 insertions(+), 154 deletions(-)
arch/x86/kernel/io_apic.c +181 -137
@@ -231,6 +231,10 @@ static struct irq_cfg *irq_cfg(unsigned#endif +static inline void set_extra_move_desc (struct irq_desc *desc,cpumask_t mask) +{ +} +struct io_apic {unsigned int index;unsigned int unused[3 ];
@@ -272,11 +276,10 @@ static inline void io_apic_modify(unsignwritel (value, &io_apic->data); } -static bool io_apic_level_ack_pending (unsigned int irq) +static bool io_apic_level_ack_pending (struct irq_cfg *cfg) {struct irq_pin_list *entry;unsigned long flags; -struct irq_cfg *cfg =irq_cfg (irq);spin_lock_irqsave (&ioapic_lock, flags); entry = cfg->irq_2_pin;
@@ -358,13 +361,12 @@ static void ioapic_mask_entry(int apic, }#ifdef CONFIG_SMP -static void __target_IO_APIC_irq (unsigned int irq,unsigned int dest,u8 vector) +static void __target_IO_APIC_irq (unsigned int irq,unsigned int dest,struct irq_cfg *cfg) {int apic, pin; -struct irq_cfg *cfg;struct irq_pin_list *entry; +u8 vector = cfg->vector; - cfg =irq_cfg (irq); entry = cfg->irq_2_pin;for (;;) {unsigned int reg;
@@ -394,24 +396,27 @@ static void __target_IO_APIC_irq(unsigne } } -static int assign_irq_vector (int irq,cpumask_t mask); +static int assign_irq_vector (int irq,struct irq_cfg *cfg,cpumask_t mask); -static void set_ioapic_affinity_irq (unsigned int irq,cpumask_t mask) +static void set_ioapic_affinity_irq_desc (struct irq_desc *desc,cpumask_t mask) {struct irq_cfg *cfg;unsigned long flags;unsigned int dest;cpumask_t tmp; -struct irq_desc *desc; +unsigned int irq;cpus_and (tmp, mask, cpu_online_map);if (cpus_empty (tmp))return ; - cfg =irq_cfg (irq); -if (assign_irq_vector (irq, mask)) + irq = desc->irq; + cfg = desc->chip_data; +if (assign_irq_vector (irq, cfg, mask))return ; +set_extra_move_desc (desc, mask); +cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp);/*
@@ -419,12 +424,20 @@ static void set_ioapic_affinity_irq(unsi*/ dest =SET_APIC_LOGICAL_ID (dest); - desc =irq_to_desc (irq);spin_lock_irqsave (&ioapic_lock, flags); -__target_IO_APIC_irq (irq, dest, cfg->vector); +__target_IO_APIC_irq (irq, dest, cfg); desc->affinity = mask; spin_unlock_irqrestore(&ioapic_lock, flags); } + +static void set_ioapic_affinity_irq (unsigned int irq,cpumask_t mask) +{ +struct irq_desc *desc; + + desc =irq_to_desc (irq); + +set_ioapic_affinity_irq_desc (desc, mask); +}#endif /* CONFIG_SMP */ /*
@@ -432,10 +445,9 @@ static void set_ioapic_affinity_irq(unsi* shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */ -static void add_pin_to_irq_cpu (unsigned int irq,int cpu,int apic,int pin) +static void add_pin_to_irq_cpu (struct irq_cfg *cfg,int cpu,int apic,int pin) {struct irq_pin_list *entry; -struct irq_cfg *cfg =irq_cfg (irq); entry = cfg->irq_2_pin;if (!entry) {
@@ -468,11 +480,10 @@ static void add_pin_to_irq_cpu(unsigned/* * Reroute an IRQ to a different pin. */ -static void __init replace_pin_at_irq (unsigned int irq,int cpu, +static void __init replace_pin_at_irq_cpu (struct irq_cfg *cfg,int cpu,int oldapic,int oldpin,int newapic,int newpin) { -struct irq_cfg *cfg =irq_cfg (irq);struct irq_pin_list *entry = cfg->irq_2_pin;int replaced =0 ;
@@ -489,18 +500,16 @@ static void __init replace_pin_at_irq(un/* why? call replace before add? */ if (!replaced) -add_pin_to_irq_cpu (irq, cpu, newapic, newpin); +add_pin_to_irq_cpu (cfg, cpu, newapic, newpin); } -static inline void io_apic_modify_irq (unsigned int irq, +static inline void io_apic_modify_irq (struct irq_cfg *cfg,int mask_and,int mask_or,void (*final)(struct irq_pin_list *entry)) {int pin; -struct irq_cfg *cfg;struct irq_pin_list *entry; - cfg =irq_cfg (irq);for (entry = cfg->irq_2_pin; entry !=NULL ; entry = entry->next) {unsigned int reg; pin = entry->pin;
@@ -513,9 +522,9 @@ static inline void io_apic_modify_irq(un } } -static void __unmask_IO_APIC_irq (unsigned int irq) +static void __unmask_IO_APIC_irq (struct irq_cfg *cfg) { -io_apic_modify_irq (irq, ~IO_APIC_REDIR_MASKED ,0 ,NULL ); +io_apic_modify_irq (cfg, ~IO_APIC_REDIR_MASKED ,0 ,NULL ); }#ifdef CONFIG_X86_64
@@ -530,47 +539,64 @@ void io_apic_sync(struct irq_pin_list *ereadl (&io_apic->data); } -static void __mask_IO_APIC_irq (unsigned int irq) +static void __mask_IO_APIC_irq (struct irq_cfg *cfg) { -io_apic_modify_irq (irq, ~0 ,IO_APIC_REDIR_MASKED , &io_apic_sync); +io_apic_modify_irq (cfg, ~0 ,IO_APIC_REDIR_MASKED , &io_apic_sync); }#else /* CONFIG_X86_32 */ -static void __mask_IO_APIC_irq (unsigned int irq) +static void __mask_IO_APIC_irq (struct irq_cfg *cfg) { -io_apic_modify_irq (irq, ~0 ,IO_APIC_REDIR_MASKED ,NULL ); +io_apic_modify_irq (cfg, ~0 ,IO_APIC_REDIR_MASKED ,NULL ); } -static void __mask_and_edge_IO_APIC_irq (unsigned int irq) +static void __mask_and_edge_IO_APIC_irq (struct irq_cfg *cfg) { -io_apic_modify_irq (irq, ~IO_APIC_REDIR_LEVEL_TRIGGER , +io_apic_modify_irq (cfg, ~IO_APIC_REDIR_LEVEL_TRIGGER ,IO_APIC_REDIR_MASKED ,NULL ); } -static void __unmask_and_level_IO_APIC_irq (unsigned int irq) +static void __unmask_and_level_IO_APIC_irq (struct irq_cfg *cfg) { -io_apic_modify_irq (irq, ~IO_APIC_REDIR_MASKED , +io_apic_modify_irq (cfg, ~IO_APIC_REDIR_MASKED ,IO_APIC_REDIR_LEVEL_TRIGGER ,NULL ); }#endif /* CONFIG_X86_32 */ -static void mask_IO_APIC_irq (unsigned int irq) +static void mask_IO_APIC_irq_desc (struct irq_desc *desc) { +struct irq_cfg *cfg = desc->chip_data;unsigned long flags; +BUG_ON (!cfg); +spin_lock_irqsave (&ioapic_lock, flags); -__mask_IO_APIC_irq (irq); +__mask_IO_APIC_irq (cfg);spin_unlock_irqrestore (&ioapic_lock, flags); } -static void unmask_IO_APIC_irq (unsigned int irq) +static void unmask_IO_APIC_irq_desc (struct irq_desc *desc) { +struct irq_cfg *cfg = desc->chip_data;unsigned long flags;spin_lock_irqsave (&ioapic_lock, flags); -__unmask_IO_APIC_irq (irq); +__unmask_IO_APIC_irq (cfg);spin_unlock_irqrestore (&ioapic_lock, flags); } +static void mask_IO_APIC_irq (unsigned int irq) +{ +struct irq_desc *desc =irq_to_desc (irq); + +mask_IO_APIC_irq_desc (desc); +} +static void unmask_IO_APIC_irq (unsigned int irq) +{ +struct irq_desc *desc =irq_to_desc (irq); + +unmask_IO_APIC_irq_desc (desc); +} +static void clear_IO_APIC_pin (unsigned int apic,unsigned int pin) {struct IO_APIC_route_entry entry;
@@ -1072,7 +1098,7 @@ void unlock_vector_lock(void)spin_unlock (&vector_lock); } -static int __assign_irq_vector (int irq,cpumask_t mask) +static int __assign_irq_vector (int irq,struct irq_cfg *cfg,cpumask_t mask) {/* * NOTE! The local APIC isn't very good at handling
@@ -1088,16 +1114,13 @@ static int __assign_irq_vector(int irq,static int current_vector =FIRST_DEVICE_VECTOR , current_offset =0 ;unsigned int old_vector;int cpu; -struct irq_cfg *cfg; - cfg =irq_cfg (irq); +if ((cfg->move_in_progress) || cfg->move_cleanup_count) +return -EBUSY ;/* Only try and allocate irqs on cpus that are present */ cpus_and (mask, mask, cpu_online_map); -if ((cfg->move_in_progress) || cfg->move_cleanup_count) -return -EBUSY ; - old_vector = cfg->vector;if (old_vector) {cpumask_t tmp;
@@ -1151,24 +1174,22 @@ next:return -ENOSPC ; } -static int assign_irq_vector (int irq,cpumask_t mask) +static int assign_irq_vector (int irq,struct irq_cfg *cfg,cpumask_t mask) {int err;unsigned long flags;spin_lock_irqsave (&vector_lock, flags); - err =__assign_irq_vector (irq, mask); + err =__assign_irq_vector (irq, cfg, mask);spin_unlock_irqrestore (&vector_lock, flags);return err; } -static void __clear_irq_vector (int irq) +static void __clear_irq_vector (int irq,struct irq_cfg *cfg) { -struct irq_cfg *cfg;cpumask_t mask;int cpu, vector; - cfg =irq_cfg (irq);BUG_ON (!cfg->vector); vector = cfg->vector;
@@ -1257,11 +1278,8 @@ static inline int IO_APIC_irq_trigger(in }#endif -static void ioapic_register_intr (int irq,unsigned long trigger) +static void ioapic_register_intr (int irq,struct irq_desc *desc,unsigned long trigger) { -struct irq_desc *desc; - - desc =irq_to_desc (irq);if ((trigger ==IOAPIC_AUTO &&IO_APIC_irq_trigger (irq)) || trigger ==IOAPIC_LEVEL )
@@ -1353,7 +1371,7 @@ static int setup_ioapic_entry(int apic,return 0 ; } -static void setup_IO_APIC_irq (int apic,int pin,unsigned int irq, +static void setup_IO_APIC_irq (int apic,int pin,unsigned int irq,struct irq_desc *desc,int trigger,int polarity) {struct irq_cfg *cfg;
@@ -1363,10 +1381,10 @@ static void setup_IO_APIC_irq(int apic,if (!IO_APIC_IRQ (irq))return ; - cfg =irq_cfg (irq); + cfg = desc->chip_data; mask =TARGET_CPUS ; -if (assign_irq_vector (irq, mask)) +if (assign_irq_vector (irq, cfg, mask))return ;cpus_and (mask, cfg->domain, mask);
@@ -1383,11 +1401,11 @@ static void setup_IO_APIC_irq(int apic, cfg->vector)) {printk ("Failed to setup ioapic entry for ioapic %d, pin %d\n" , mp_ioapics[apic].mp_apicid, pin); -__clear_irq_vector (irq); +__clear_irq_vector (irq, cfg);return ; } -ioapic_register_intr (irq, trigger); +ioapic_register_intr (irq, desc, trigger);if (irq <NR_IRQS_LEGACY )disable_8259A_irq (irq);
@@ -1399,6 +1417,7 @@ static void __init setup_IO_APIC_irqs(voint apic, pin, idx, irq;int notcon =0 ;struct irq_desc *desc; +struct irq_cfg *cfg;int cpu = boot_cpu_id;apic_printk (APIC_VERBOSE ,KERN_DEBUG "init IO_APIC IRQs\n" );
@@ -1436,9 +1455,10 @@ static void __init setup_IO_APIC_irqs(voprintk (KERN_INFO "can not get irq_desc for %d\n" , irq);continue ; } -add_pin_to_irq_cpu (irq, cpu, apic, pin); + cfg = desc->chip_data; +add_pin_to_irq_cpu (cfg, cpu, apic, pin); -setup_IO_APIC_irq (apic, pin, irq, +setup_IO_APIC_irq (apic, pin, irq, desc,irq_trigger (idx),irq_polarity (idx)); } }
@@ -2086,7 +2106,7 @@ static unsigned int startup_ioapic_irq(u was_pending =1 ; } cfg =irq_cfg (irq); -__unmask_IO_APIC_irq (irq); +__unmask_IO_APIC_irq (cfg);spin_unlock_irqrestore (&ioapic_lock, flags);return was_pending;
@@ -2149,35 +2169,37 @@ static DECLARE_DELAYED_WORK(ir_migration* as simple as edge triggered migration and we can do the irq migration * with a simple atomic update to IO-APIC RTE. */ -static void migrate_ioapic_irq (int irq,cpumask_t mask) +static void migrate_ioapic_irq_desc (struct irq_desc *desc,cpumask_t mask) {struct irq_cfg *cfg; -struct irq_desc *desc;cpumask_t tmp, cleanup_mask;struct irte irte;int modify_ioapic_rte;unsigned int dest;unsigned long flags; +unsigned int irq;cpus_and (tmp, mask, cpu_online_map);if (cpus_empty (tmp))return ; + irq = desc->irq;if (get_irte (irq, &irte))return ; -if (assign_irq_vector (irq, mask)) + cfg = desc->chip_data; +if (assign_irq_vector (irq, cfg, mask))return ; - cfg =irq_cfg (irq); +set_extra_move_desc (desc, mask); +cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp); - desc =irq_to_desc (irq); modify_ioapic_rte = desc->status &IRQ_LEVEL ;if (modify_ioapic_rte) {spin_lock_irqsave (&ioapic_lock, flags); -__target_IO_APIC_irq (irq, dest, cfg->vector); +__target_IO_APIC_irq (irq, dest, cfg);spin_unlock_irqrestore (&ioapic_lock, flags); }
@@ -2199,14 +2221,14 @@ static void migrate_ioapic_irq(int irq, desc->affinity = mask; } -static int migrate_irq_remapped_level (int irq) +static int migrate_irq_remapped_level_desc (struct irq_desc *desc) {int ret =-1 ; -struct irq_desc *desc =irq_to_desc (irq); +struct irq_cfg *cfg = desc->chip_data; -mask_IO_APIC_irq (irq); +mask_IO_APIC_irq_desc (desc); -if (io_apic_level_ack_pending (irq)) { +if (io_apic_level_ack_pending (cfg)) {/* * Interrupt in progress. Migrating irq now will change the * vector information in the IO-APIC RTE and that will confuse
@@ -2218,14 +2240,15 @@ static int migrate_irq_remapped_level(in }/* everthing is clear. we have right of way */ -migrate_ioapic_irq (irq, desc->pending_mask); +migrate_ioapic_irq_desc (desc, desc->pending_mask); ret =0 ; desc->status &= ~IRQ_MOVE_PENDING ;cpus_clear (desc->pending_mask); unmask: -unmask_IO_APIC_irq (irq); +unmask_IO_APIC_irq_desc (desc); +return ret; }
@@ -2258,18 +2281,22 @@ static void ir_irq_migration(struct work/* * Migrates the IRQ destination in the process context. */ -static void set_ir_ioapic_affinity_irq (unsigned int irq,cpumask_t mask) +static void set_ir_ioapic_affinity_irq_desc (struct irq_desc *desc,cpumask_t mask) { -struct irq_desc *desc =irq_to_desc (irq); -if (desc->status &IRQ_LEVEL ) { desc->status |=IRQ_MOVE_PENDING ; desc->pending_mask = mask; -migrate_irq_remapped_level (irq); +migrate_irq_remapped_level_desc (desc);return ; } -migrate_ioapic_irq (irq, mask); +migrate_ioapic_irq_desc (desc, mask); +} +static void set_ir_ioapic_affinity_irq (unsigned int irq,cpumask_t mask) +{ +struct irq_desc *desc =irq_to_desc (irq); + +set_ir_ioapic_affinity_irq_desc (desc, mask); }#endif
@@ -2313,9 +2340,10 @@ unlock:irq_exit (); } -static void irq_complete_move (unsigned int irq) +static void irq_complete_move (struct irq_desc **descp) { -struct irq_cfg *cfg =irq_cfg (irq); +struct irq_desc *desc = *descp; +struct irq_cfg *cfg = desc->chip_data;unsigned vector, me;if (likely (!cfg->move_in_progress))
@@ -2333,8 +2361,9 @@ static void irq_complete_move(unsigned i } }#else -static inline void irq_complete_move (unsigned int irq) {} +static inline void irq_complete_move (struct irq_desc **descp) {}#endif +#ifdef CONFIG_INTR_REMAP static void ack_x2apic_level (unsigned int irq) {
@@ -2345,11 +2374,14 @@ static void ack_x2apic_edge(unsigned int {ack_x2APIC_irq (); } +#endif static void ack_apic_edge (unsigned int irq) { -irq_complete_move (irq); +struct irq_desc *desc =irq_to_desc (irq); + +irq_complete_move (&desc);move_native_irq (irq);ack_APIC_irq (); }
@@ -2358,18 +2390,21 @@ atomic_t irq_mis_count;static void ack_apic_level (unsigned int irq) { +struct irq_desc *desc =irq_to_desc (irq); +#ifdef CONFIG_X86_32 unsigned long v;int i;#endif +struct irq_cfg *cfg;int do_unmask_irq =0 ; -irq_complete_move (irq); +irq_complete_move (&desc);#ifdef CONFIG_GENERIC_PENDING_IRQ /* If we are moving the irq we need to mask it */ -if (unlikely (irq_to_desc (irq)->status &IRQ_MOVE_PENDING )) { +if (unlikely (desc->status &IRQ_MOVE_PENDING )) { do_unmask_irq =1 ; -mask_IO_APIC_irq (irq); +mask_IO_APIC_irq_desc (desc); }#endif
@@ -2393,7 +2428,8 @@ static void ack_apic_level(unsigned int* operation to prevent an edge-triggered interrupt escaping meanwhile. * The idea is from Manfred Spraul. --macro */ - i =irq_cfg (irq)->vector; + cfg = desc->chip_data; + i = cfg->vector; v =apic_read (APIC_TMR + ((i & ~0x1f ) >>1 ));#endif
@@ -2432,17 +2468,18 @@ static void ack_apic_level(unsigned int* accurate and is causing problems then it is a hardware bug * and you can go talk to the chipset vendor about it. */ -if (!io_apic_level_ack_pending (irq)) + cfg = desc->chip_data; +if (!io_apic_level_ack_pending (cfg))move_masked_irq (irq); -unmask_IO_APIC_irq (irq); +unmask_IO_APIC_irq_desc (desc); }#ifdef CONFIG_X86_32 if (!(v & (1 << (i &0x1f )))) {atomic_inc (&irq_mis_count);spin_lock (&ioapic_lock); -__mask_and_edge_IO_APIC_irq (irq); -__unmask_and_level_IO_APIC_irq (irq); +__mask_and_edge_IO_APIC_irq (cfg); +__unmask_and_level_IO_APIC_irq (cfg);spin_unlock (&ioapic_lock); }#endif
@@ -2533,7 +2570,7 @@ static void unmask_lapic_irq(unsigned inapic_write (APIC_LVT0 , v & ~APIC_LVT_MASKED ); } -static void ack_lapic_irq (unsigned int irq) +static void ack_lapic_irq (unsigned int irq) {ack_APIC_irq (); }
@@ -2545,11 +2582,8 @@ static struct irq_chip lapic_chip __read .ack = ack_lapic_irq, }; -static void lapic_register_intr (int irq) +static void lapic_register_intr (int irq,struct irq_desc *desc) { -struct irq_desc *desc; - - desc =irq_to_desc (irq); desc->status &= ~IRQ_LEVEL ;set_irq_chip_and_handler_name (irq, &lapic_chip, handle_edge_irq,"edge" );
@@ -2653,7 +2687,9 @@ int timer_through_8259 __initdata;*/ static inline void __init check_timer (void ) { -struct irq_cfg *cfg =irq_cfg (0 ); +struct irq_desc *desc =irq_to_desc (0 ); +struct irq_cfg *cfg = desc->chip_data; +int cpu = boot_cpu_id;int apic1, pin1, apic2, pin2;unsigned long flags;unsigned int ver;
@@ -2668,7 +2704,7 @@ static inline void __init check_timer(vo* get/set the timer IRQ vector: */ disable_8259A_irq (0 ); -assign_irq_vector (0 ,TARGET_CPUS ); +assign_irq_vector (0 , cfg,TARGET_CPUS );/* * As IRQ0 is to be enabled in the 8259A, the virtual
@@ -2719,10 +2755,10 @@ static inline void __init check_timer(vo* Ok, does IRQ0 through the IOAPIC work? */ if (no_pin1) { -add_pin_to_irq_cpu (0 , boot_cpu_id, apic1, pin1); +add_pin_to_irq_cpu (cfg, cpu, apic1, pin1);setup_timer_IRQ0_pin (apic1, pin1, cfg->vector); } -unmask_IO_APIC_irq (0 ); +unmask_IO_APIC_irq_desc (desc);if (timer_irq_works ()) {if (nmi_watchdog ==NMI_IO_APIC ) {setup_nmi ();
@@ -2748,9 +2784,9 @@ static inline void __init check_timer(vo/* * legacy devices should be connected to IO APIC #0 */ -replace_pin_at_irq (0 , boot_cpu_id, apic1, pin1, apic2, pin2); +replace_pin_at_irq_cpu (cfg, cpu, apic1, pin1, apic2, pin2);setup_timer_IRQ0_pin (apic2, pin2, cfg->vector); -unmask_IO_APIC_irq (0 ); +unmask_IO_APIC_irq_desc (desc);enable_8259A_irq (0 );if (timer_irq_works ()) {apic_printk (APIC_QUIET ,KERN_INFO "....... works.\n" );
@@ -2782,7 +2818,7 @@ static inline void __init check_timer(voapic_printk (APIC_QUIET ,KERN_INFO "...trying to set up timer as Virtual Wire IRQ...\n" ); -lapic_register_intr (0 ); +lapic_register_intr (0 , desc);apic_write (APIC_LVT0 ,APIC_DM_FIXED | cfg->vector);/* Fixed mode */ enable_8259A_irq (0 );
@@ -2986,7 +3022,7 @@ unsigned int create_irq_nr(unsigned intif (cfg_new->vector !=0 )continue ; -if (__assign_irq_vector (new,TARGET_CPUS ) ==0 ) +if (__assign_irq_vector (new, cfg_new,TARGET_CPUS ) ==0 ) irq = new;break ; }
@@ -3034,7 +3070,7 @@ void destroy_irq(unsigned int irq)free_irte (irq);#endif spin_lock_irqsave (&vector_lock, flags); -__clear_irq_vector (irq); +__clear_irq_vector (irq, cfg);spin_unlock_irqrestore (&vector_lock, flags); }
@@ -3049,12 +3085,12 @@ static int msi_compose_msg(struct pci_deunsigned dest;cpumask_t tmp; + cfg =irq_cfg (irq); tmp =TARGET_CPUS ; - err =assign_irq_vector (irq, tmp); + err =assign_irq_vector (irq, cfg, tmp);if (err)return err; - cfg =irq_cfg (irq);cpus_and (tmp, cfg->domain, tmp); dest =cpu_mask_to_apicid (tmp);
@@ -3112,35 +3148,35 @@ static int msi_compose_msg(struct pci_de#ifdef CONFIG_SMP static void set_msi_irq_affinity (unsigned int irq,cpumask_t mask) { +struct irq_desc *desc =irq_to_desc (irq);struct irq_cfg *cfg;struct msi_msg msg;unsigned int dest;cpumask_t tmp; -struct irq_desc *desc;cpus_and (tmp, mask, cpu_online_map);if (cpus_empty (tmp))return ; -if (assign_irq_vector (irq, mask)) + cfg = desc->chip_data; +if (assign_irq_vector (irq, cfg, mask))return ; - cfg =irq_cfg (irq); +set_extra_move_desc (desc, mask); +cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp); -read_msi_msg (irq, &msg); +read_msi_msg_desc (desc, &msg); msg.data &= ~MSI_DATA_VECTOR_MASK ; msg.data |=MSI_DATA_VECTOR (cfg->vector); msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK ; msg.address_lo |=MSI_ADDR_DEST_ID (dest); -write_msi_msg (irq, &msg); - desc =irq_to_desc (irq); +write_msi_msg_desc (desc, &msg); desc->affinity = mask; } -#ifdef CONFIG_INTR_REMAP /* * Migrate the MSI irq to another cpumask. This migration is
@@ -3148,11 +3184,11 @@ static void set_msi_irq_affinity(unsigne*/ static void ir_set_msi_irq_affinity (unsigned int irq,cpumask_t mask) { +struct irq_desc *desc =irq_to_desc (irq);struct irq_cfg *cfg;unsigned int dest;cpumask_t tmp, cleanup_mask;struct irte irte; -struct irq_desc *desc;cpus_and (tmp, mask, cpu_online_map);if (cpus_empty (tmp))
@@ -3161,10 +3197,12 @@ static void ir_set_msi_irq_affinity(unsiif (get_irte (irq, &irte))return ; -if (assign_irq_vector (irq, mask)) + cfg = desc->chip_data; +if (assign_irq_vector (irq, cfg, mask))return ; - cfg =irq_cfg (irq); +set_extra_move_desc (desc, mask); +cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp);
@@ -3188,9 +3226,9 @@ static void ir_set_msi_irq_affinity(unsi cfg->move_in_progress =0 ; } - desc =irq_to_desc (irq); desc->affinity = mask; } +#endif #endif /* CONFIG_SMP */
@@ -3249,7 +3287,7 @@ static int msi_alloc_irte(struct pci_dev }#endif -static int setup_msi_irq (struct pci_dev *dev,struct msi_desc *desc,int irq) +static int setup_msi_irq (struct pci_dev *dev,struct msi_desc *msidesc,int irq) {int ret;struct msi_msg msg;
@@ -3258,7 +3296,7 @@ static int setup_msi_irq(struct pci_devif (ret <0 )return ret; -set_irq_msi (irq, desc); +set_irq_msi (irq, msidesc);write_msi_msg (irq, &msg);#ifdef CONFIG_INTR_REMAP
@@ -3381,20 +3419,22 @@ void arch_teardown_msi_irq(unsigned int#ifdef CONFIG_SMP static void dmar_msi_set_affinity (unsigned int irq,cpumask_t mask) { +struct irq_desc *desc =irq_to_desc (irq);struct irq_cfg *cfg;struct msi_msg msg;unsigned int dest;cpumask_t tmp; -struct irq_desc *desc;cpus_and (tmp, mask, cpu_online_map);if (cpus_empty (tmp))return ; -if (assign_irq_vector (irq, mask)) + cfg = desc->chip_data; +if (assign_irq_vector (irq, cfg, mask))return ; - cfg =irq_cfg (irq); +set_extra_move_desc (desc, mask); +cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp);
@@ -3406,9 +3446,9 @@ static void dmar_msi_set_affinity(unsign msg.address_lo |=MSI_ADDR_DEST_ID (dest);dmar_msi_write (irq, &msg); - desc =irq_to_desc (irq); desc->affinity = mask; } +#endif /* CONFIG_SMP */ struct irq_chip dmar_msi_type = {
@@ -3442,8 +3482,8 @@ int arch_setup_dmar_msi(unsigned int irq#ifdef CONFIG_SMP static void hpet_msi_set_affinity (unsigned int irq,cpumask_t mask) { +struct irq_desc *desc =irq_to_desc (irq);struct irq_cfg *cfg; -struct irq_desc *desc;struct msi_msg msg;unsigned int dest;cpumask_t tmp;
@@ -3452,10 +3492,12 @@ static void hpet_msi_set_affinity(unsignif (cpus_empty (tmp))return ; -if (assign_irq_vector (irq, mask)) + cfg = desc->chip_data; +if (assign_irq_vector (irq, cfg, mask))return ; - cfg =irq_cfg (irq); +set_extra_move_desc (desc, mask); +cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp);
@@ -3467,9 +3509,9 @@ static void hpet_msi_set_affinity(unsign msg.address_lo |=MSI_ADDR_DEST_ID (dest);hpet_msi_write (irq, &msg); - desc =irq_to_desc (irq); desc->affinity = mask; } +#endif /* CONFIG_SMP */ struct irq_chip hpet_msi_type = {
@@ -3524,26 +3566,28 @@ static void target_ht_irq(unsigned int istatic void set_ht_irq_affinity (unsigned int irq,cpumask_t mask) { +struct irq_desc *desc =irq_to_desc (irq);struct irq_cfg *cfg;unsigned int dest;cpumask_t tmp; -struct irq_desc *desc;cpus_and (tmp, mask, cpu_online_map);if (cpus_empty (tmp))return ; -if (assign_irq_vector (irq, mask)) + cfg = desc->chip_data; +if (assign_irq_vector (irq, cfg, mask))return ; - cfg =irq_cfg (irq); +set_extra_move_desc (desc, mask); +cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp);target_ht_irq (irq, dest, cfg->vector); - desc =irq_to_desc (irq); desc->affinity = mask; } +#endif static struct irq_chip ht_irq_chip = {
@@ -3563,13 +3607,13 @@ int arch_setup_ht_irq(unsigned int irq,int err;cpumask_t tmp; + cfg =irq_cfg (irq); tmp =TARGET_CPUS ; - err =assign_irq_vector (irq, tmp); + err =assign_irq_vector (irq, cfg, tmp);if (!err) {struct ht_irq_msg msg;unsigned dest; - cfg =irq_cfg (irq);cpus_and (tmp, cfg->domain, tmp); dest =cpu_mask_to_apicid (tmp);
@@ -3615,7 +3659,9 @@ int arch_enable_uv_irq(char *irq_name, uunsigned long flags;int err; - err =assign_irq_vector (irq, *eligible_cpu); + cfg =irq_cfg (irq); + + err =assign_irq_vector (irq, cfg, *eligible_cpu);if (err !=0 )return err;
@@ -3624,8 +3670,6 @@ int arch_enable_uv_irq(char *irq_name, u irq_name);spin_unlock_irqrestore (&vector_lock, flags); - cfg =irq_cfg (irq); - mmr_value =0 ; entry = (struct uv_IO_APIC_route_entry *)&mmr_value;BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) !=sizeof (unsigned long ));
@@ -3806,10 +3850,10 @@ int io_apic_set_pci_routing (int ioapic,*/ if (irq >=NR_IRQS_LEGACY ) { cfg = desc->chip_data; -add_pin_to_irq_cpu (irq, cpu, ioapic, pin); +add_pin_to_irq_cpu (cfg, cpu, ioapic, pin); } -setup_IO_APIC_irq (ioapic, pin, irq, triggering, polarity); +setup_IO_APIC_irq (ioapic, pin, irq, desc, triggering, polarity);return 0 ; }
@@ -3866,7 +3910,7 @@ void __init setup_ioapic_dest(void) desc =irq_to_desc (irq); cfg = desc->chip_data;if (!cfg->vector) { -setup_IO_APIC_irq (ioapic, pin, irq, +setup_IO_APIC_irq (ioapic, pin, irq, desc,irq_trigger (irq_entry),irq_polarity (irq_entry));continue ;
@@ -3884,10 +3928,10 @@ void __init setup_ioapic_dest(void)#ifdef CONFIG_INTR_REMAP if (intr_remapping_enabled) -set_ir_ioapic_affinity_irq (irq, mask); +set_ir_ioapic_affinity_irq_desc (desc, mask); else#endif -set_ioapic_affinity_irq (irq, mask); +set_ioapic_affinity_irq_desc (desc, mask); } }
drivers/pci/msi.c +38 -17
123 lines not on this page · raw message
include/linux/msi.h +3 -0
@@ -10,8 +10,11 @@ struct msi_msg { };/* Helper functions */ +struct irq_desc ;extern void mask_msi_irq (unsigned int irq);extern void unmask_msi_irq (unsigned int irq); +extern void read_msi_msg_desc (struct irq_desc *desc,struct msi_msg *msg); +extern void write_msi_msg_desc (struct irq_desc *desc,struct msi_msg *msg);extern void read_msi_msg (unsigned int irq,struct msi_msg *msg);extern void write_msi_msg (unsigned int irq,struct msi_msg *msg);
add back sparseirq v5
In reply to Yinghai Luimpact: new feature sparseirq
for sparse_irq, irq_desc, and irq_cfg is not using list_head to chain up also not add per_cpu_dyn_array... no user now
v2: add some kind of hash table as Ingo suggesting.
v3: default to use dyna_array only, aka SPARSE_IRQ = N
and remove check nr_irqs with NR_IRQS in probe_nr_irqs
v4: remove dyna_array, and enable sparse_irq by default
use kzalloc_node to get it
v5: use desc->chip_data for x86 to store irq_cfg
to do: make irq_desc and go with affinity aka irq_desc moving etc
--- arch/x86/Kconfig | 4 arch/x86/include/asm/io_apic.h | 4 arch/x86/include/asm/irq_vectors.h | 2 arch/x86/kernel/io_apic.c | 275 +++++++++++++++++++++---------------- arch/x86/kernel/irq.c | 19 +- arch/x86/kernel/irq_32.c | 1 arch/x86/kernel/irq_64.c | 1 arch/x86/kernel/irqinit_32.c | 3 arch/x86/kernel/irqinit_64.c | 3 arch/x86/kernel/setup_percpu.c | 4 arch/x86/mm/init_32.c | 3 drivers/char/random.c | 31 ++++ drivers/pci/htirq.c | 18 ++ drivers/pci/intr_remapping.c | 65 ++++++++ drivers/xen/events.c | 7 fs/proc/interrupts.c | 13 + fs/proc/stat.c | 16 +- include/linux/interrupt.h | 2 include/linux/irq.h | 54 ++++++- include/linux/irqnr.h | 15 -- include/linux/kernel_stat.h | 14 + init/main.c | 7 kernel/irq/autoprobe.c | 5 kernel/irq/chip.c | 4 kernel/irq/handle.c | 214 ++++++++++++++++++++++++++++ kernel/irq/proc.c | 1 kernel/irq/spurious.c | 2 27 files changed, 627 insertions(+), 160 deletions(-)
arch/x86/Kconfig +4 -0
@@ -236,6 +236,10 @@ config X86_HAS_BOOT_CPU_ID def_bool y depends on X86_VOYAGER +config HAVE_SPARSE_IRQ + bool + default y + config X86_FIND_SMP_CONFIG def_bool y depends on X86_MPPARSE || X86_VOYAGER
arch/x86/kernel/io_apic.c +161 -114
618 lines not on this page · raw message
arch/x86/kernel/irqinit_32.c +1 -2
@@ -68,8 +68,7 @@ void __init init_ISA_irqs (void)/* * 16 old-style INTA-cycle interrupts: */ -for (i =0 ; i <16 ; i++) { -/* first time call this irq_desc */ +for (i =0 ; i <NR_IRQS_LEGACY ; i++) {struct irq_desc *desc =irq_to_desc (i); desc->status =IRQ_DISABLED ;
arch/x86/kernel/irqinit_64.c +1 -2
@@ -142,8 +142,7 @@ void __init init_ISA_irqs(void)init_bsp_APIC ();init_8259A (0 ); -for (i =0 ; i <16 ; i++) { -/* first time call this irq_desc */ +for (i =0 ; i <NR_IRQS_LEGACY ; i++) {struct irq_desc *desc =irq_to_desc (i); desc->status =IRQ_DISABLED ;
arch/x86/mm/init_32.c +3 -0
@@ -66,6 +66,7 @@ static unsigned long __meminitdata tablestatic unsigned long __meminitdata table_top;static int __initdata after_init_bootmem; +int after_bootmem;static __init void *alloc_low_page (unsigned long *phys) {
@@ -987,6 +988,8 @@ void __init mem_init(void)set_highmem_pages_init (); + after_bootmem =1 ; + codesize = (unsigned long ) &_etext - (unsigned long ) &_text; datasize = (unsigned long ) &_edata - (unsigned long ) &_etext; initsize = (unsigned long ) &__init_end - (unsigned long ) &__init_begin;
drivers/char/random.c +31 -0
@@ -558,6 +558,8 @@ struct timer_rand_state { unsigned dont_count_entropy:1; }; +#ifndef CONFIG_HAVE_SPARSE_IRQ +static struct timer_rand_state *irq_timer_state[NR_IRQS ];static struct timer_rand_state *get_timer_rand_state (unsigned int irq)
@@ -576,6 +578,33 @@ static void set_timer_rand_state(unsigne irq_timer_state[irq] = state; } +#else + +static struct timer_rand_state *get_timer_rand_state (unsigned int irq) +{ +struct irq_desc *desc; + + desc =irq_to_desc (irq); + +if (!desc) +return NULL ; + +return desc->timer_rand_state; +} + +static void set_timer_rand_state (unsigned int irq,struct timer_rand_state *state) +{ +struct irq_desc *desc; + + desc =irq_to_desc (irq); + +if (!desc) +return ; + + desc->timer_rand_state = state; +} +#endif +static struct timer_rand_state input_timer_state;/*
@@ -933,8 +962,10 @@ void rand_initialize_irq(int irq) {struct timer_rand_state *state; +#ifndef CONFIG_HAVE_SPARSE_IRQ if (irq >= nr_irqs)return ; +#endif state =get_timer_rand_state (irq);
drivers/pci/htirq.c +18 -0
@@ -82,6 +82,18 @@ void unmask_ht_irq(unsigned int irq)write_ht_irq_msg (irq, &msg); } +static unsigned int build_irq_for_pci_dev (struct pci_dev *dev) +{ +unsigned int irq; + + irq = dev->bus->number; + irq <<=8 ; + irq |= dev->devfn; + irq <<=12 ; + +return irq; +} +/** * __ht_create_irq - create an irq and attach it to a device. * @dev: The hypertransport device to find the irq capability on.
@@ -98,6 +110,7 @@ int __ht_create_irq(struct pci_dev *dev,int max_irq;int pos;int irq; +unsigned int irq_want; pos =pci_find_ht_capability (dev,HT_CAPTYPE_IRQ );if (!pos)
@@ -125,7 +138,12 @@ int __ht_create_irq(struct pci_dev *dev, cfg->msg.address_lo =0xffffffff ; cfg->msg.address_hi =0xffffffff ; + irq_want =build_irq_for_pci_dev (dev); +#ifdef CONFIG_HAVE_SPARSE_IRQ + irq =create_irq_nr (irq_want + idx); +#else irq =create_irq (); +#endif if (irq <=0 ) {kfree (cfg);
drivers/pci/intr_remapping.c +63 -2
89 lines not on this page · raw message
drivers/xen/events.c +4 -3
@@ -143,6 +143,7 @@ static void init_evtchn_cpu_bindings(voi/* By default all event channels notify CPU#0. */ for_each_irq_desc (i, desc) desc->affinity =cpumask_of_cpu (0 ); + end_for_each_irq_desc();#endif memset (cpu_evtchn,0 ,sizeof (cpu_evtchn));
@@ -231,7 +232,7 @@ static int find_unbound_irq(void)int irq;/* Only allocate from dynirq range */ -for_each_irq_nr (irq) +for (irq =0 ; irq < nr_irqs; irq++)if (irq_bindcount[irq] ==0 )break ;
@@ -792,7 +793,7 @@ void xen_irq_resume(void)mask_evtchn (evtchn);/* No IRQ <-> event-channel mappings. */ -for_each_irq_nr (irq) +for (irq =0 ; irq < nr_irqs; irq++) irq_info[irq].evtchn =0 ;/* zap event-channel binding */ for (evtchn =0 ; evtchn <NR_EVENT_CHANNELS ; evtchn++)
@@ -824,7 +825,7 @@ void __init xen_init_IRQ(void)mask_evtchn (i);/* Dynamic IRQ space is currently unbound. Zero the refcnts. */ -for_each_irq_nr (i) +for (i =0 ; i < nr_irqs; i++) irq_bindcount[i] =0 ;irq_ctx_init (smp_processor_id ());
fs/proc/stat.c +11 -5
@@ -27,6 +27,9 @@ static int show_stat(struct seq_file *p,u64 sum =0 ;struct timespec boottime;unsigned int per_irq_sum; +#ifdef CONFIG_GENERIC_HARDIRQS +struct irq_desc *desc; +#endif user = nice = system = idle = iowait = irq = softirq = steal = cputime64_zero;
@@ -44,10 +47,9 @@ static int show_stat(struct seq_file *p, softirq =cputime64_add (softirq,kstat_cpu (i).cpustat.softirq); steal =cputime64_add (steal,kstat_cpu (i).cpustat.steal); guest =cputime64_add (guest,kstat_cpu (i).cpustat.guest); - -for_each_irq_nr (j) +for_each_irq_desc (j, desc) sum +=kstat_irqs_cpu (j, i); - + end_for_each_irq_desc(); sum +=arch_irq_stat_cpu (i); } sum +=arch_irq_stat ();
@@ -90,14 +92,18 @@ static int show_stat(struct seq_file *p,seq_printf (p,"intr %llu" , (unsigned long long )sum);/* sum again ? it could be updated? */ -for_each_irq_nr (j) { +for_each_irq_desc (j, desc) { per_irq_sum =0 ; -for_each_possible_cpu (i) per_irq_sum +=kstat_irqs_cpu (j, i); +#ifdef CONFIG_HAVE_SPARSE_IRQ +seq_printf (p," %#x:%u" , j, per_irq_sum); +#else seq_printf (p," %u" , per_irq_sum); +#endif } + end_for_each_irq_desc();seq_printf (p, "\nctxt %llu\n"
fs/proc/interrupts.c +12 -1
@@ -10,20 +10,31 @@*/ static void *int_seq_start (struct seq_file *f,loff_t *pos) { +#ifdef CONFIG_HAVE_SPARSE_IRQ +rcu_read_lock (); +return seq_list_start (&sparse_irqs_head, *pos); +#else return (*pos <= nr_irqs) ? pos :NULL ; +#endif }static void *int_seq_next (struct seq_file *f,void *v,loff_t *pos) { +#ifdef CONFIG_HAVE_SPARSE_IRQ +return seq_list_next (v, &sparse_irqs_head, pos); +#else (*pos)++;if (*pos > nr_irqs)return NULL ;return pos; +#endif }static void int_seq_stop (struct seq_file *f,void *v) { -/* Nothing to do */ +#ifdef CONFIG_HAVE_SPARSE_IRQ +rcu_read_unlock (); +#endif }static const struct seq_operations int_seq_ops = {
include/linux/interrupt.h +2 -0
@@ -18,6 +18,8 @@#include <asm/ptrace.h> #include <asm/system.h> +extern int nr_irqs; +/* * These correspond to the IORESOURCE_IRQ_* defines in * linux/ioport.h to select the interrupt line behaviour. When
include/linux/irq.h +52 -2
78 lines not on this page · raw message
include/linux/kernel_stat.h +13 -1
@@ -28,7 +28,9 @@ struct cpu_usage_stat {struct kernel_stat {struct cpu_usage_stat cpustat; -unsigned int irqs[NR_IRQS ]; +#ifndef CONFIG_HAVE_SPARSE_IRQ +unsigned int irqs[NR_IRQS ]; +#endif }; DECLARE_PER_CPU(struct kernel_stat, kstat);
@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, kstaextern unsigned long long nr_context_switches (void ); +#ifndef CONFIG_HAVE_SPARSE_IRQ +#define kstat_irqs_this_cpu (irq) \ + (kstat_this_cpu.irqs[irq]) +struct irq_desc ; static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_ { kstat_this_cpu.irqs[irq]++; } +#endif + +#ifndef CONFIG_HAVE_SPARSE_IRQ static inline unsigned int kstat_irqs_cpu (unsigned int irq,int cpu) {return kstat_cpu (cpu).irqs[irq]; } +#else +extern unsigned int kstat_irqs_cpu (unsigned int irq,int cpu); +#endif /* * Number of interrupts per specific IRQ source, since bootup
kernel/irq/autoprobe.c +5 -0
@@ -58,6 +58,7 @@ unsigned long probe_irq_on(void) }spin_unlock_irq (&desc->lock); } + end_for_each_irq_desc();/* Wait for longstanding interrupts to trigger. */ msleep (20 );
@@ -76,6 +77,7 @@ unsigned long probe_irq_on(void) }spin_unlock_irq (&desc->lock); } + end_for_each_irq_desc();/* * Wait for spurious interrupts to trigger
@@ -100,6 +102,7 @@ unsigned long probe_irq_on(void) }spin_unlock_irq (&desc->lock); } + end_for_each_irq_desc();return mask; }
@@ -136,6 +139,7 @@ unsigned int probe_irq_mask(unsigned lon }spin_unlock_irq (&desc->lock); } + end_for_each_irq_desc();mutex_unlock (&probing_active);return mask & val;
@@ -180,6 +184,7 @@ int probe_irq_off(unsigned long val) }spin_unlock_irq (&desc->lock); } + end_for_each_irq_desc();mutex_unlock (&probing_active);if (nr_of_irqs >1 )
kernel/irq/chip.c +3 -1
@@ -24,9 +24,11 @@*/ void dynamic_irq_init (unsigned int irq) { -struct irq_desc *desc =irq_to_desc (irq); +struct irq_desc *desc;unsigned long flags; +/* first time to use this irq_desc */ + desc =irq_to_desc_alloc (irq);if (!desc) {WARN (1 ,KERN_ERR "Trying to initialize invalid IRQ%d\n" , irq);return ;
kernel/irq/handle.c +209 -5
247 lines not on this page · raw message
arch/x86/kernel/irq.c +9 -10
@@ -99,25 +99,20 @@ static int show_other_interrupts(structint show_interrupts (struct seq_file *p,void *v) {unsigned long flags, any_count =0 ; -int i = *(loff_t *) v, j; +int i, j;struct irqaction *action;struct irq_desc *desc; -if (i > nr_irqs) -return 0 ; - -if (i == nr_irqs) -return show_other_interrupts (p); - -/* print header */ -if (i ==0 ) { + desc = list_entry(v, struct irq_desc, list); + i = desc->irq; +if (&desc->list == sparse_irqs_head.next) { +/* print header */ seq_printf (p," " );for_each_online_cpu (j)seq_printf (p,"CPU%-8d" , j);seq_putc (p,'\n' ); } - desc =irq_to_desc (i);spin_lock_irqsave (&desc->lock, flags);#ifndef CONFIG_SMP any_count =kstat_irqs (i);
@@ -148,6 +143,10 @@ int show_interrupts(struct seq_file *p,seq_putc (p,'\n' ); out:spin_unlock_irqrestore (&desc->lock, flags); + +if (&desc->list == sparse_irqs_head.prev) +show_other_interrupts (p); +return 0 ; }
include/linux/irqnr.h +4 -11
@@ -7,18 +7,11 @@# define for_each_irq_desc (irq, desc) \ for (irq = 0; irq < nr_irqs; irq++) -#else -extern int nr_irqs; +# define end_for_each_irq_desc () -# define for_each_irq_desc (irq, desc) \ - for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++) - -# define for_each_irq_desc_reverse (irq, desc) \ - for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1); \ - irq >= 0; irq--, desc--) +static inline early_sparse_irq_init_work (void) +{ +}#endif -#define for_each_irq_nr (irq) \ - for (irq = 0; irq < nr_irqs; irq++) -#endif
arch/x86/kernel/irq_32.c +1 -0
@@ -255,6 +255,7 @@ void fixup_irqs(cpumask_t map)else if (desc->action && !(warned++))printk ("Cannot set affinity for irq %i\n" , irq); } + end_for_each_irq_desc();#if 0 barrier ();
arch/x86/kernel/irq_64.c +1 -0
@@ -130,6 +130,7 @@ void fixup_irqs(cpumask_t map)else if (!set_affinity)printk ("Cannot set affinity for irq %i\n" , irq); } + end_for_each_irq_desc();/* That doesn't seem sufficient. Give it 1ms. */ local_irq_enable ();
kernel/irq/proc.c +1 -0
@@ -245,5 +245,6 @@ void init_irq_proc(void)*/ for_each_irq_desc (irq, desc)register_irq_proc (irq, desc); + end_for_each_irq_desc(); }
kernel/irq/spurious.c +2 -0
@@ -100,6 +100,7 @@ static int misrouted_irq(int irq)if (try_one_irq (i, desc)) ok =1 ; } + end_for_each_irq_desc();/* So the caller can adjust the irq error counts */ return ok; }
@@ -124,6 +125,7 @@ static void poll_spurious_irqs(unsignedtry_one_irq (i, desc); } + end_for_each_irq_desc();mod_timer (&poll_spurious_irq_timer, jiffies +POLL_SPURIOUS_IRQ_INTERVAL ); }
arch/x86/kernel/setup_percpu.c +4 -0
@@ -191,6 +191,10 @@ void __init setup_per_cpu_areas(void)/* Setup node to cpumask map */ setup_node_to_cpumask_map (); + +/* init_work to init list for sparseirq */ +early_sparse_irq_init_work (); + early_irq_cfg_init_work(); }#endif
init/main.c +6 -1
@@ -363,7 +363,10 @@ static void __init smp_init(void)#define smp_init () do { } while (0)#endif -static inline void setup_per_cpu_areas (void ) { } +static inline void setup_per_cpu_areas (void ) +{ +early_sparse_irq_init_work (); +}static inline void setup_nr_cpu_ids (void ) { }static inline void smp_prepare_cpus (unsigned int maxcpus) { }
@@ -409,6 +412,8 @@ static void __init setup_per_cpu_areas(vmemcpy (ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); ptr += size; } + +early_sparse_irq_init_work (); }#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */
arch/x86/include/asm/io_apic.h +4 -0
@@ -199,6 +199,7 @@ extern void reinit_intr_remapped_IO_APIC#endif extern int probe_nr_irqs (void ); +void early_irq_cfg_init_work (void );#else /* !CONFIG_X86_IO_APIC */ #define io_apic_assign_pci_irqs 0
@@ -209,6 +210,9 @@ static inline int probe_nr_irqs(void) {return NR_IRQS ; } +static inline void early_irq_cfg_init_work (void ) +{ +}#endif #endif /* _ASM_X86_IO_APIC_H */
arch/x86/include/asm/irq_vectors.h +2 -0
@@ -101,6 +101,8 @@#define LAST_VM86_IRQ 15#define invalid_vm86_irq (irq) ((irq) < 3 || (irq) > 15) +#define NR_IRQS_LEGACY 16 +#if defined(CONFIG_X86_IO_APIC ) && !defined(CONFIG_X86_VOYAGER )# if NR_CPUS <MAX_IO_APICS # define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))
Re: add back sparseirq v5
this one is outdated...
YH
Quoted 1,757 lines · Yinghai Lu
impact: new feature sparseirq
for
sparse_irq,irq_desc, andirq_cfgis not usinglist_headto chain up also not addper_cpu_dyn_array... no user nowv2: add some kind of hash table as Ingo suggesting.
v3: default to usedyna_arrayonly, akaSPARSE_IRQ= N
and remove checknr_irqswithNR_IRQSinprobe_nr_irqs
v4: removedyna_array, and enablesparse_irqby default
usekzalloc_nodeto get it
v5: usedesc->chip_datafor x86 to storeirq_cfgto do: make
irq_descand go with affinity akairq_descmoving etcSigned-off-by Yinghai Lu <[email protected]>--- arch/x86/Kconfig | 4 arch/x86/include/asm/io_apic.h | 4 arch/x86/include/asm/irq_vectors.h | 2 arch/x86/kernel/io_apic.c | 275 +++++++++++++++++++++---------------- arch/x86/kernel/irq.c | 19 +- arch/x86/kernel/irq_32.c | 1 arch/x86/kernel/irq_64.c | 1 arch/x86/kernel/irqinit_32.c | 3 arch/x86/kernel/irqinit_64.c | 3 arch/x86/kernel/setup_percpu.c | 4 arch/x86/mm/init_32.c | 3 drivers/char/random.c | 31 ++++ drivers/pci/htirq.c | 18 ++ drivers/pci/intr_remapping.c | 65 ++++++++ drivers/xen/events.c | 7 fs/proc/interrupts.c | 13 + fs/proc/stat.c | 16 +- include/linux/interrupt.h | 2 include/linux/irq.h | 54 ++++++- include/linux/irqnr.h | 15 -- include/linux/kernel_stat.h | 14 + init/main.c | 7 kernel/irq/autoprobe.c | 5 kernel/irq/chip.c | 4 kernel/irq/handle.c | 214 ++++++++++++++++++++++++++++ kernel/irq/proc.c | 1 kernel/irq/spurious.c | 2 27 files changed, 627 insertions(+), 160 deletions(-)Index: linux-2.6/arch/x86/Kconfig
===================================================================arch/x86/Kconfig +4
-0@@ -236,6 +236,10 @@ config X86_HAS_BOOT_CPU_ID def_bool y depends on X86_VOYAGER +config HAVE_SPARSE_IRQ + bool + default y + config X86_FIND_SMP_CONFIG def_bool y depends on X86_MPPARSE || X86_VOYAGERIndex:
linux-2.6/arch/x86/kernel/io_apic.c
===================================================================arch/x86/kernel/io_apic.c +161
-114@@ -108,8 +108,8 @@ static int __init parse_noapic(char *strearly_param ("noapic" , parse_noapic);struct irq_pin_list ; +struct irq_cfg { -unsigned int irq;struct irq_pin_list *irq_2_pin;cpumask_t domain;cpumask_t old_domain;@@ -119,44 +119,72 @@ struct irq_cfg { };/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ -static struct irq_cfg irq_cfgx[NR_IRQS ] = { - [0 ] = { .irq =0 , .domain =CPU_MASK_ALL , .vector =IRQ0_VECTOR , }, - [1 ] = { .irq =1 , .domain =CPU_MASK_ALL , .vector =IRQ1_VECTOR , }, - [2 ] = { .irq =2 , .domain =CPU_MASK_ALL , .vector =IRQ2_VECTOR , }, - [3 ] = { .irq =3 , .domain =CPU_MASK_ALL , .vector =IRQ3_VECTOR , }, - [4 ] = { .irq =4 , .domain =CPU_MASK_ALL , .vector =IRQ4_VECTOR , }, - [5 ] = { .irq =5 , .domain =CPU_MASK_ALL , .vector =IRQ5_VECTOR , }, - [6 ] = { .irq =6 , .domain =CPU_MASK_ALL , .vector =IRQ6_VECTOR , }, - [7 ] = { .irq =7 , .domain =CPU_MASK_ALL , .vector =IRQ7_VECTOR , }, - [8 ] = { .irq =8 , .domain =CPU_MASK_ALL , .vector =IRQ8_VECTOR , }, - [9 ] = { .irq =9 , .domain =CPU_MASK_ALL , .vector =IRQ9_VECTOR , }, - [10 ] = { .irq =10 , .domain =CPU_MASK_ALL , .vector =IRQ10_VECTOR , }, - [11 ] = { .irq =11 , .domain =CPU_MASK_ALL , .vector =IRQ11_VECTOR , }, - [12 ] = { .irq =12 , .domain =CPU_MASK_ALL , .vector =IRQ12_VECTOR , }, - [13 ] = { .irq =13 , .domain =CPU_MASK_ALL , .vector =IRQ13_VECTOR , }, - [14 ] = { .irq =14 , .domain =CPU_MASK_ALL , .vector =IRQ14_VECTOR , }, - [15 ] = { .irq =15 , .domain =CPU_MASK_ALL , .vector =IRQ15_VECTOR , }, +static struct irq_cfg irq_cfg_legacy[] = { + [0 ] = { .domain =CPU_MASK_ALL , .vector =IRQ0_VECTOR , }, + [1 ] = { .domain =CPU_MASK_ALL , .vector =IRQ1_VECTOR , }, + [2 ] = { .domain =CPU_MASK_ALL , .vector =IRQ2_VECTOR , }, + [3 ] = { .domain =CPU_MASK_ALL , .vector =IRQ3_VECTOR , }, + [4 ] = { .domain =CPU_MASK_ALL , .vector =IRQ4_VECTOR , }, + [5 ] = { .domain =CPU_MASK_ALL , .vector =IRQ5_VECTOR , }, + [6 ] = { .domain =CPU_MASK_ALL , .vector =IRQ6_VECTOR , }, + [7 ] = { .domain =CPU_MASK_ALL , .vector =IRQ7_VECTOR , }, + [8 ] = { .domain =CPU_MASK_ALL , .vector =IRQ8_VECTOR , }, + [9 ] = { .domain =CPU_MASK_ALL , .vector =IRQ9_VECTOR , }, + [10 ] = { .domain =CPU_MASK_ALL , .vector =IRQ10_VECTOR , }, + [11 ] = { .domain =CPU_MASK_ALL , .vector =IRQ11_VECTOR , }, + [12 ] = { .domain =CPU_MASK_ALL , .vector =IRQ12_VECTOR , }, + [13 ] = { .domain =CPU_MASK_ALL , .vector =IRQ13_VECTOR , }, + [14 ] = { .domain =CPU_MASK_ALL , .vector =IRQ14_VECTOR , }, + [15 ] = { .domain =CPU_MASK_ALL , .vector =IRQ15_VECTOR , }, }; -#define for_each_irq_cfg (irq, cfg) \ - for (irq = 0, cfg = irq_cfgx; irq < nr_irqs; irq++, cfg++) +/* +* Protect the irq_cfgx_free freelist: +*/ +void __init early_irq_cfg_init_work (void ) +{ +struct irq_cfg *cfg; +struct irq_desc *desc; +int legacy_count; +int i; + + cfg = irq_cfg_legacy; + legacy_count =ARRAY_SIZE (irq_cfg_legacy); + +BUG_ON (legacy_count >NR_IRQS_LEGACY ); + +for (i =0 ; i < legacy_count; i++) { + desc =irq_to_desc (i); + desc->chip_data = &cfg[i]; + } +}static struct irq_cfg *irq_cfg (unsigned int irq) { -return irq < nr_irqs ? irq_cfgx + irq :NULL ; +struct irq_cfg *cfg =NULL ; +struct irq_desc *desc; + + desc =irq_to_desc (irq); +if (desc) + cfg = desc->chip_data; + +return cfg; } -static struct irq_cfg *irq_cfg_alloc (unsigned int irq) +static struct irq_cfg *get_one_free_irq_cfg (int cpu) { -return irq_cfg (irq); -} +struct irq_cfg *cfg; +int node; -/* -* Rough estimation of how many shared IRQs there are, can be changed -* anytime. -*/ -#define MAX_PLUS_SHARED_IRQS NR_IRQS -#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS) +if (cpu <0 ) + cpu =smp_processor_id (); + node =cpu_to_node (cpu); + + cfg =kzalloc_node (sizeof (*cfg),GFP_KERNEL , node); +printk (KERN_DEBUG " alloc irq_cfg on cpu %d node %d\n" , cpu, node); + +return cfg; +}/* * This is performance-critical, we want to do it O(1) @@ -170,29 +198,18 @@ struct irq_pin_list {struct irq_pin_list *next; }; -static struct irq_pin_list irq_2_pin_head[PIN_MAP_SIZE ]; -static struct irq_pin_list *irq_2_pin_ptr; - -static void __init irq_2_pin_init (void ) +static struct irq_pin_list *get_one_free_irq_2_pin (int cpu) { -struct irq_pin_list *pin = irq_2_pin_head; -int i; - -for (i =1 ; i <PIN_MAP_SIZE ; i++) - pin[i-1 ].next = &pin[i]; - - irq_2_pin_ptr = &pin[0 ]; -} +struct irq_pin_list *pin; +int node; -static struct irq_pin_list *get_one_free_irq_2_pin (void ) -{ -struct irq_pin_list *pin = irq_2_pin_ptr; +if (cpu <0 ) + cpu =smp_processor_id (); + node =cpu_to_node (cpu); -if (!pin) -panic ("can not get more irq_2_pin\n" ); + pin =kzalloc_node (sizeof (*pin),GFP_KERNEL , node); +printk (KERN_DEBUG " alloc irq_2_pin on cpu %d node %d\n" , cpu, node); - irq_2_pin_ptr = pin->next; - pin->next =NULL ;return pin; }@@ -359,7 +376,7 @@ static void __target_IO_APIC_irq(unsigne } } -static int assign_irq_vector (int irq,cpumask_t mask); +static int assign_irq_vector (int irq,struct irq_cfg *cfg,cpumask_t mask);static void set_ioapic_affinity_irq (unsigned int irq,cpumask_t mask) {@@ -374,7 +391,7 @@ static void set_ioapic_affinity_irq(unsireturn ; cfg =irq_cfg (irq); -if (assign_irq_vector (irq, mask)) +if (assign_irq_vector (irq, cfg, mask))return ;cpus_and (tmp, cfg->domain, mask);@@ -399,14 +416,21 @@ static void set_ioapic_affinity_irq(unsi*/ static void add_pin_to_irq (unsigned int irq,int apic,int pin) { +struct irq_desc *desc;struct irq_cfg *cfg;struct irq_pin_list *entry; +int cpu =smp_processor_id ();/* first time to refer irq_cfg, so with new */ - cfg =irq_cfg_alloc (irq); + desc =irq_to_desc_alloc_cpu (irq, cpu); + cfg = desc->chip_data; +if (!cfg) { + cfg =get_one_free_irq_cfg (cpu); + desc->chip_data = cfg; + } entry = cfg->irq_2_pin;if (!entry) { - entry =get_one_free_irq_2_pin (); + entry =get_one_free_irq_2_pin (cpu); cfg->irq_2_pin = entry; entry->apic = apic; entry->pin = pin;@@ -421,7 +445,7 @@ static void add_pin_to_irq(unsigned int entry = entry->next; } - entry->next =get_one_free_irq_2_pin (); + entry->next =get_one_free_irq_2_pin (cpu); entry = entry->next; entry->apic = apic; entry->pin = pin;@@ -809,7 +833,7 @@ EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector*/ static int EISA_ELCR (unsigned int irq) { -if (irq <16 ) { +if (irq <NR_IRQS_LEGACY ) {unsigned int port =0x4d0 + (irq >>3 );return (inb (port) >> (irq &7 )) &1 ; }@@ -1034,7 +1058,7 @@ void unlock_vector_lock(void)spin_unlock (&vector_lock); } -static int __assign_irq_vector (int irq,cpumask_t mask) +static int __assign_irq_vector (int irq,struct irq_cfg *cfg,cpumask_t mask) {/* * NOTE! The local APIC isn't very good at handling @@ -1050,9 +1074,6 @@ static int __assign_irq_vector(int irq,static int current_vector =FIRST_DEVICE_VECTOR , current_offset =0 ;unsigned int old_vector;int cpu; -struct irq_cfg *cfg; - - cfg =irq_cfg (irq);/* Only try and allocate irqs on cpus that are present */ cpus_and (mask, mask, cpu_online_map);@@ -1113,24 +1134,22 @@ next:return -ENOSPC ; } -static int assign_irq_vector (int irq,cpumask_t mask) +static int assign_irq_vector (int irq,struct irq_cfg *cfg,cpumask_t mask) {int err;unsigned long flags;spin_lock_irqsave (&vector_lock, flags); - err =__assign_irq_vector (irq, mask); + err =__assign_irq_vector (irq, cfg, mask);spin_unlock_irqrestore (&vector_lock, flags);return err; } -static void __clear_irq_vector (int irq) +static void __clear_irq_vector (int irq,struct irq_cfg *cfg) { -struct irq_cfg *cfg;cpumask_t mask;int cpu, vector; - cfg =irq_cfg (irq);BUG_ON (!cfg->vector); vector = cfg->vector;@@ -1148,14 +1167,17 @@ void __setup_vector_irq(int cpu)/* This function must be called with vector_lock held */ int irq, vector;struct irq_cfg *cfg; +struct irq_desc *desc;/* Mark the inuse vectors */ -for_each_irq_cfg (irq, cfg) { +for_each_irq_desc (irq, desc) { + cfg = desc->chip_data;if (!cpu_isset (cpu, cfg->domain))continue ; vector = cfg->vector;per_cpu (vector_irq, cpu)[vector] = irq; } + end_for_each_irq_desc();/* Mark the free vectors */ for (vector =0 ; vector <NR_VECTORS ; ++vector) { irq =per_cpu (vector_irq, cpu)[vector];@@ -1205,7 +1227,8 @@ static void ioapic_register_intr(int irq {struct irq_desc *desc; - desc =irq_to_desc (irq); +/* could be first time to use this irq_desc */ + desc =irq_to_desc_alloc (irq);if ((trigger ==IOAPIC_AUTO &&IO_APIC_irq_trigger (irq)) || trigger ==IOAPIC_LEVEL )@@ -1310,7 +1333,7 @@ static void setup_IO_APIC_irq(int apic, cfg =irq_cfg (irq); mask =TARGET_CPUS ; -if (assign_irq_vector (irq, mask)) +if (assign_irq_vector (irq, cfg, mask))return ;cpus_and (mask, cfg->domain, mask);@@ -1327,12 +1350,12 @@ static void setup_IO_APIC_irq(int apic, cfg->vector)) {printk ("Failed to setup ioapic entry for ioapic %d, pin %d\n" , mp_ioapics[apic].mp_apicid, pin); -__clear_irq_vector (irq); +__clear_irq_vector (irq, cfg);return ; }ioapic_register_intr (irq, trigger); -if (irq <16 ) +if (irq <NR_IRQS_LEGACY )disable_8259A_irq (irq);ioapic_write_entry (apic, pin, entry);@@ -1434,6 +1457,7 @@ __apicdebuginit(void) print_IO_APIC(voidunion IO_APIC_reg_03 reg_03;unsigned long flags;struct irq_cfg *cfg; +struct irq_desc *desc;unsigned int irq;if (apic_verbosity ==APIC_QUIET )@@ -1523,8 +1547,11 @@ __apicdebuginit(void) print_IO_APIC(void } }printk (KERN_DEBUG "IRQ to pin mappings:\n" ); -for_each_irq_cfg (irq, cfg) { -struct irq_pin_list *entry = cfg->irq_2_pin; +for_each_irq_desc (irq, desc) { +struct irq_pin_list *entry; + + cfg = desc->chip_data; + entry = cfg->irq_2_pin;if (!entry)continue ;printk (KERN_DEBUG "IRQ%d " , irq);@@ -1536,6 +1563,7 @@ __apicdebuginit(void) print_IO_APIC(void }printk ("\n" ); } + end_for_each_irq_desc();printk (KERN_INFO ".................................... done.\n" );@@ -2010,7 +2038,7 @@ static unsigned int startup_ioapic_irq(uunsigned long flags;spin_lock_irqsave (&ioapic_lock, flags); -if (irq <16 ) { +if (irq <NR_IRQS_LEGACY ) {disable_8259A_irq (irq);if (i8259A_irq_pending (irq)) was_pending =1 ;@@ -2095,10 +2123,10 @@ static void migrate_ioapic_irq(int irq,if (get_irte (irq, &irte))return ; -if (assign_irq_vector (irq, mask)) + cfg =irq_cfg (irq); +if (assign_irq_vector (irq, cfg, mask))return ; - cfg =irq_cfg (irq);cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp);@@ -2179,6 +2207,7 @@ static void ir_irq_migration(struct workspin_unlock_irqrestore (&desc->lock, flags); } } + end_for_each_irq_desc(); }/* @@ -2416,22 +2445,22 @@ static inline void init_IO_APIC_traps(vo* Also, we've got to be careful not to trash gate * 0x80, because int 0x80 is hm, kind of importantish. ;) */ -for_each_irq_cfg (irq, cfg) { -if (IO_APIC_IRQ (irq) && !cfg->vector) { +for_each_irq_desc (irq, desc) { + cfg = desc->chip_data; +if (IO_APIC_IRQ (irq) && cfg && !cfg->vector) {/* * Hmm.. We don't have an entry for this, * so default to an old-fashioned 8259 * interrupt if we can.. */ -if (irq <16 ) +if (irq <NR_IRQS_LEGACY )make_8259A_irq (irq); -else { - desc =irq_to_desc (irq); +else /* Strange. Oh, well.. */ desc->chip = &no_irq_chip; - } } } + end_for_each_irq_desc(); }/* @@ -2589,7 +2618,7 @@ static inline void __init check_timer(vo* get/set the timer IRQ vector: */ disable_8259A_irq (0 ); -assign_irq_vector (0 ,TARGET_CPUS ); +assign_irq_vector (0 , cfg,TARGET_CPUS );/* * As IRQ0 is to be enabled in the 8259A, the virtual @@ -2888,22 +2917,31 @@ unsigned int create_irq_nr(unsigned intunsigned int irq;unsigned int new;unsigned long flags; -struct irq_cfg *cfg_new; - - irq_want = nr_irqs -1 ; +struct irq_cfg *cfg_new =NULL ; +struct irq_desc *desc_new =NULL ; +int cpu; irq =0 ;spin_lock_irqsave (&vector_lock, flags); + cpu =smp_processor_id ();for (new = irq_want; new >0 ; new--) {if (platform_legacy_irq (new))continue ; - cfg_new =irq_cfg (new); + + cfg_new =NULL ; + desc_new =irq_to_desc (new); +if (desc_new) + cfg_new = desc_new->chip_data;if (cfg_new && cfg_new->vector !=0 )continue ;/* check if need to create one */ -if (!cfg_new) - cfg_new =irq_cfg_alloc (new); -if (__assign_irq_vector (new,TARGET_CPUS ) ==0 ) +if (!cfg_new) { + cfg_new =get_one_free_irq_cfg (cpu); +if (!desc_new) + desc_new =irq_to_desc_alloc_cpu (new, cpu); + desc_new->chip_data = cfg_new; + } +if (__assign_irq_vector (new, cfg_new,TARGET_CPUS ) ==0 ) irq = new;break ; }@@ -2911,6 +2949,9 @@ unsigned int create_irq_nr(unsigned intif (irq >0 ) {dynamic_irq_init (irq); +/* restore it, in case dynamic_irq_init clear it */ +if (desc_new) + desc_new->chip_data = cfg_new; }return irq; }@@ -2930,14 +2971,22 @@ int create_irq(void)void destroy_irq (unsigned int irq) {unsigned long flags; +struct irq_cfg *cfg; +struct irq_desc *desc; +/* store it, in case dynamic_irq_cleanup clear it */ + desc =irq_to_desc (irq); + cfg = desc->chip_data;dynamic_irq_cleanup (irq); +/* connect back irq_cfg */ +if (desc) + desc->chip_data = cfg;#ifdef CONFIG_INTR_REMAP free_irte (irq);#endif spin_lock_irqsave (&vector_lock, flags); -__clear_irq_vector (irq); +__clear_irq_vector (irq, cfg);spin_unlock_irqrestore (&vector_lock, flags); }@@ -2952,12 +3001,12 @@ static int msi_compose_msg(struct pci_deunsigned dest;cpumask_t tmp; + cfg =irq_cfg (irq); tmp =TARGET_CPUS ; - err =assign_irq_vector (irq, tmp); + err =assign_irq_vector (irq, cfg, tmp);if (err)return err; - cfg =irq_cfg (irq);cpus_and (tmp, cfg->domain, tmp); dest =cpu_mask_to_apicid (tmp);@@ -3025,10 +3074,10 @@ static void set_msi_irq_affinity(unsigneif (cpus_empty (tmp))return ; -if (assign_irq_vector (irq, mask)) + cfg =irq_cfg (irq); +if (assign_irq_vector (irq, cfg, mask))return ; - cfg =irq_cfg (irq);cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp);@@ -3064,10 +3113,10 @@ static void ir_set_msi_irq_affinity(unsiif (get_irte (irq, &irte))return ; -if (assign_irq_vector (irq, mask)) + cfg =irq_cfg (irq); +if (assign_irq_vector (irq, cfg, mask))return ; - cfg =irq_cfg (irq);cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp);@@ -3176,7 +3225,7 @@ static int setup_msi_irq(struct pci_dev#endif set_irq_chip_and_handler_name (irq, &msi_chip, handle_edge_irq,"edge" ); -dev_printk (KERN_DEBUG , &dev->dev,"irq %d for MSI/MSI-X\n" , irq); +dev_printk (KERN_DEBUG , &dev->dev,"irq %d aka 0x%08x for MSI/MSI-X\n" , irq, irq);return 0 ; }@@ -3199,7 +3248,7 @@ int arch_setup_msi_irq(struct pci_dev *dint ret;unsigned int irq_want; - irq_want =build_irq_for_pci_dev (dev) +0x100 ; + irq_want =build_irq_for_pci_dev (dev) +0xfff ; irq =create_irq_nr (irq_want);if (irq ==0 )@@ -3240,7 +3289,7 @@ int arch_setup_msi_irqs(struct pci_dev *int index =0 ;#endif - irq_want =build_irq_for_pci_dev (dev) +0x100 ; + irq_want =build_irq_for_pci_dev (dev) +0xfff ; sub_handle =0 ;list_for_each_entry (desc, &dev->msi_list, list) { irq =create_irq_nr (irq_want--);@@ -3306,10 +3355,10 @@ static void dmar_msi_set_affinity(unsignif (cpus_empty (tmp))return ; -if (assign_irq_vector (irq, mask)) + cfg =irq_cfg (irq); +if (assign_irq_vector (irq, cfg, mask))return ; - cfg =irq_cfg (irq);cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp);@@ -3367,10 +3416,10 @@ static void hpet_msi_set_affinity(unsignif (cpus_empty (tmp))return ; -if (assign_irq_vector (irq, mask)) + cfg =irq_cfg (irq); +if (assign_irq_vector (irq, cfg, mask))return ; - cfg =irq_cfg (irq);cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp);@@ -3448,10 +3497,10 @@ static void set_ht_irq_affinity(unsignedif (cpus_empty (tmp))return ; -if (assign_irq_vector (irq, mask)) + cfg =irq_cfg (irq); +if (assign_irq_vector (irq, cfg, mask))return ; - cfg =irq_cfg (irq);cpus_and (tmp, cfg->domain, mask); dest =cpu_mask_to_apicid (tmp);@@ -3478,13 +3527,13 @@ int arch_setup_ht_irq(unsigned int irq,int err;cpumask_t tmp; + cfg =irq_cfg (irq); tmp =TARGET_CPUS ; - err =assign_irq_vector (irq, tmp); + err =assign_irq_vector (irq, cfg, tmp);if (!err) {struct ht_irq_msg msg;unsigned dest; - cfg =irq_cfg (irq);cpus_and (tmp, cfg->domain, tmp); dest =cpu_mask_to_apicid (tmp);@@ -3508,7 +3557,8 @@ int arch_setup_ht_irq(unsigned int irq,set_irq_chip_and_handler_name (irq, &ht_irq_chip, handle_edge_irq,"edge" ); -dev_printk (KERN_DEBUG , &dev->dev,"irq %d for HT\n" , irq); +dev_printk (KERN_DEBUG , &dev->dev,"irq %d aka 0x%08x for HT\n" , + irq, irq); }return err; }@@ -3530,7 +3580,9 @@ int arch_enable_uv_irq(char *irq_name, uunsigned long flags;int err; - err =assign_irq_vector (irq, *eligible_cpu); + cfg =irq_cfg (irq); + + err =assign_irq_vector (irq, cfg, *eligible_cpu);if (err !=0 )return err;@@ -3539,8 +3591,6 @@ int arch_enable_uv_irq(char *irq_name, u irq_name);spin_unlock_irqrestore (&vector_lock, flags); - cfg =irq_cfg (irq); - mmr_value =0 ; entry = (struct uv_IO_APIC_route_entry *)&mmr_value;BUG_ON (sizeof (struct uv_IO_APIC_route_entry ) !=sizeof (unsigned long ));@@ -3611,8 +3661,6 @@ int __init probe_nr_irqs(void)/* something wrong ? */ if (nr < nr_min) nr = nr_min; -if (WARN_ON (nr >NR_IRQS )) - nr =NR_IRQS ;return nr; }@@ -3722,7 +3770,7 @@ int io_apic_set_pci_routing (int ioapic,/* * IRQs < 16 are already in the irq_2_pin[] map */ -if (irq >=16 ) +if (irq >=NR_IRQS_LEGACY )add_pin_to_irq (irq, ioapic, pin);setup_IO_APIC_irq (ioapic, pin, irq, triggering, polarity);@@ -3836,7 +3884,6 @@ void __init ioapic_init_mappings(void)struct resource *ioapic_res;int i; -irq_2_pin_init (); ioapic_res =ioapic_setup_resources ();for (i =0 ; i < nr_ioapics; i++) {if (smp_found_config) {Index:
linux-2.6/arch/x86/kernel/irqinit_32.c
===================================================================arch/x86/kernel/irqinit_32.c +1
-2@@ -68,8 +68,7 @@ void __init init_ISA_irqs (void)/* * 16 old-style INTA-cycle interrupts: */ -for (i =0 ; i <16 ; i++) { -/* first time call this irq_desc */ +for (i =0 ; i <NR_IRQS_LEGACY ; i++) {struct irq_desc *desc =irq_to_desc (i); desc->status =IRQ_DISABLED ;Index:
linux-2.6/arch/x86/kernel/irqinit_64.c
===================================================================arch/x86/kernel/irqinit_64.c +1
-2@@ -142,8 +142,7 @@ void __init init_ISA_irqs(void)init_bsp_APIC ();init_8259A (0 ); -for (i =0 ; i <16 ; i++) { -/* first time call this irq_desc */ +for (i =0 ; i <NR_IRQS_LEGACY ; i++) {struct irq_desc *desc =irq_to_desc (i); desc->status =IRQ_DISABLED ;Index:
linux-2.6/arch/x86/mm/init_32.c
===================================================================arch/x86/mm/init_32.c +3
-0@@ -66,6 +66,7 @@ static unsigned long __meminitdata tablestatic unsigned long __meminitdata table_top;static int __initdata after_init_bootmem; +int after_bootmem;static __init void *alloc_low_page (unsigned long *phys) {@@ -987,6 +988,8 @@ void __init mem_init(void)set_highmem_pages_init (); + after_bootmem =1 ; + codesize = (unsigned long ) &_etext - (unsigned long ) &_text; datasize = (unsigned long ) &_edata - (unsigned long ) &_etext; initsize = (unsigned long ) &__init_end - (unsigned long ) &__init_begin;Index:
linux-2.6/drivers/char/random.c
===================================================================drivers/char/random.c +31
-0@@ -558,6 +558,8 @@ struct timer_rand_state { unsigned dont_count_entropy:1; }; +#ifndef CONFIG_HAVE_SPARSE_IRQ +static struct timer_rand_state *irq_timer_state[NR_IRQS ];static struct timer_rand_state *get_timer_rand_state (unsigned int irq)@@ -576,6 +578,33 @@ static void set_timer_rand_state(unsigne irq_timer_state[irq] = state; } +#else + +static struct timer_rand_state *get_timer_rand_state (unsigned int irq) +{ +struct irq_desc *desc; + + desc =irq_to_desc (irq); + +if (!desc) +return NULL ; + +return desc->timer_rand_state; +} + +static void set_timer_rand_state (unsigned int irq,struct timer_rand_state *state) +{ +struct irq_desc *desc; + + desc =irq_to_desc (irq); + +if (!desc) +return ; + + desc->timer_rand_state = state; +} +#endif +static struct timer_rand_state input_timer_state;/* @@ -933,8 +962,10 @@ void rand_initialize_irq(int irq) {struct timer_rand_state *state; +#ifndef CONFIG_HAVE_SPARSE_IRQ if (irq >= nr_irqs)return ; +#endif state =get_timer_rand_state (irq);Index:
linux-2.6/drivers/pci/htirq.c
===================================================================drivers/pci/htirq.c +18
-0@@ -82,6 +82,18 @@ void unmask_ht_irq(unsigned int irq)write_ht_irq_msg (irq, &msg); } +static unsigned int build_irq_for_pci_dev (struct pci_dev *dev) +{ +unsigned int irq; + + irq = dev->bus->number; + irq <<=8 ; + irq |= dev->devfn; + irq <<=12 ; + +return irq; +} +/** * __ht_create_irq - create an irq and attach it to a device. * @dev: The hypertransport device to find the irq capability on. @@ -98,6 +110,7 @@ int __ht_create_irq(struct pci_dev *dev,int max_irq;int pos;int irq; +unsigned int irq_want; pos =pci_find_ht_capability (dev,HT_CAPTYPE_IRQ );if (!pos)@@ -125,7 +138,12 @@ int __ht_create_irq(struct pci_dev *dev, cfg->msg.address_lo =0xffffffff ; cfg->msg.address_hi =0xffffffff ; + irq_want =build_irq_for_pci_dev (dev); +#ifdef CONFIG_HAVE_SPARSE_IRQ + irq =create_irq_nr (irq_want + idx); +#else irq =create_irq (); +#endif if (irq <=0 ) {kfree (cfg);Index:
linux-2.6/drivers/pci/intr_remapping.c
===================================================================drivers/pci/intr_remapping.c +63
-2@@ -19,17 +19,76 @@ struct irq_2_iommu {u8 irte_mask; }; -static struct irq_2_iommu irq_2_iommuX[NR_IRQS ]; +#ifdef CONFIG_HAVE_SPARSE_IRQ +static struct irq_2_iommu *get_one_free_irq_2_iommu (int cpu) +{ +struct irq_2_iommu *iommu; +int node; + +if (cpu <0 ) + cpu =smp_processor_id (); + node =cpu_to_node (cpu); + + iommu =kzalloc_node (sizeof (*iommu),GFP_KERNEL , node); +printk (KERN_DEBUG "alloc irq_2_iommu on cpu %d node %d\n" , cpu, node); + +return iommu; +}static struct irq_2_iommu *irq_2_iommu (unsigned int irq) { -return (irq < nr_irqs) ? irq_2_iommuX + irq :NULL ; +struct irq_desc *desc; + + desc =irq_to_desc (irq); + +BUG_ON (!desc); + +return desc->irq_2_iommu; } +static struct irq_2_iommu *irq_2_iommu_alloc_cpu (unsigned int irq,int cpu) +{ +struct irq_desc *desc; +struct irq_2_iommu *irq_iommu; + +/* +* alloc irq desc if not allocated already. +*/ + desc =irq_to_desc_alloc_cpu (irq, cpu); + + irq_iommu = desc->irq_2_iommu; + +if (!irq_iommu) + desc->irq_2_iommu =get_one_free_irq_2_iommu (cpu); + +return desc->irq_2_iommu; +} + +static struct irq_2_iommu *irq_2_iommu_alloc (unsigned int irq) +{ +return irq_2_iommu_alloc_cpu (irq,-1 ); +} + +#else /* !CONFIG_HAVE_SPARSE_IRQ */ + +static struct irq_2_iommu irq_2_iommuX[NR_IRQS ]; + +static struct irq_2_iommu *irq_2_iommu (unsigned int irq) +{ +if (irq < nr_irqs) +return &irq_2_iommuX[irq]; + +return NULL ; +} +static struct irq_2_iommu *irq_2_iommu_alloc_cpu (unsigned int irq,int cpu) +{ +return irq_2_iommu (irq); +}static struct irq_2_iommu *irq_2_iommu_alloc (unsigned int irq) {return irq_2_iommu (irq); } +#endif static DEFINE_SPINLOCK (irq_2_ir_lock);@@ -86,9 +145,11 @@ int alloc_irte(struct intel_iommu *iommuif (!count)return -1 ; +#ifndef CONFIG_HAVE_SPARSE_IRQ /* protect irq_2_iommu_alloc later */ if (irq >= nr_irqs)return -1 ; +#endif /* * start the IRTE search from index 0. Index:
linux-2.6/drivers/xen/events.c
===================================================================drivers/xen/events.c +4
-3@@ -143,6 +143,7 @@ static void init_evtchn_cpu_bindings(voi/* By default all event channels notify CPU#0. */ for_each_irq_desc (i, desc) desc->affinity =cpumask_of_cpu (0 ); + end_for_each_irq_desc();#endif memset (cpu_evtchn,0 ,sizeof (cpu_evtchn));@@ -231,7 +232,7 @@ static int find_unbound_irq(void)int irq;/* Only allocate from dynirq range */ -for_each_irq_nr (irq) +for (irq =0 ; irq < nr_irqs; irq++)if (irq_bindcount[irq] ==0 )break ;@@ -792,7 +793,7 @@ void xen_irq_resume(void)mask_evtchn (evtchn);/* No IRQ <-> event-channel mappings. */ -for_each_irq_nr (irq) +for (irq =0 ; irq < nr_irqs; irq++) irq_info[irq].evtchn =0 ;/* zap event-channel binding */ for (evtchn =0 ; evtchn <NR_EVENT_CHANNELS ; evtchn++)@@ -824,7 +825,7 @@ void __init xen_init_IRQ(void)mask_evtchn (i);/* Dynamic IRQ space is currently unbound. Zero the refcnts. */ -for_each_irq_nr (i) +for (i =0 ; i < nr_irqs; i++) irq_bindcount[i] =0 ;irq_ctx_init (smp_processor_id ());Index:
linux-2.6/fs/proc/stat.c
===================================================================fs/proc/stat.c +11
-5@@ -27,6 +27,9 @@ static int show_stat(struct seq_file *p,u64 sum =0 ;struct timespec boottime;unsigned int per_irq_sum; +#ifdef CONFIG_GENERIC_HARDIRQS +struct irq_desc *desc; +#endif user = nice = system = idle = iowait = irq = softirq = steal = cputime64_zero;@@ -44,10 +47,9 @@ static int show_stat(struct seq_file *p, softirq =cputime64_add (softirq,kstat_cpu (i).cpustat.softirq); steal =cputime64_add (steal,kstat_cpu (i).cpustat.steal); guest =cputime64_add (guest,kstat_cpu (i).cpustat.guest); - -for_each_irq_nr (j) +for_each_irq_desc (j, desc) sum +=kstat_irqs_cpu (j, i); - + end_for_each_irq_desc(); sum +=arch_irq_stat_cpu (i); } sum +=arch_irq_stat ();@@ -90,14 +92,18 @@ static int show_stat(struct seq_file *p,seq_printf (p,"intr %llu" , (unsigned long long )sum);/* sum again ? it could be updated? */ -for_each_irq_nr (j) { +for_each_irq_desc (j, desc) { per_irq_sum =0 ; -for_each_possible_cpu (i) per_irq_sum +=kstat_irqs_cpu (j, i); +#ifdef CONFIG_HAVE_SPARSE_IRQ +seq_printf (p," %#x:%u" , j, per_irq_sum); +#else seq_printf (p," %u" , per_irq_sum); +#endif } + end_for_each_irq_desc();seq_printf (p, "\nctxt %llu\n"Index:
linux-2.6/fs/proc/interrupts.c
===================================================================fs/proc/interrupts.c +12
-1@@ -10,20 +10,31 @@*/ static void *int_seq_start (struct seq_file *f,loff_t *pos) { +#ifdef CONFIG_HAVE_SPARSE_IRQ +rcu_read_lock (); +return seq_list_start (&sparse_irqs_head, *pos); +#else return (*pos <= nr_irqs) ? pos :NULL ; +#endif }static void *int_seq_next (struct seq_file *f,void *v,loff_t *pos) { +#ifdef CONFIG_HAVE_SPARSE_IRQ +return seq_list_next (v, &sparse_irqs_head, pos); +#else (*pos)++;if (*pos > nr_irqs)return NULL ;return pos; +#endif }static void int_seq_stop (struct seq_file *f,void *v) { -/* Nothing to do */ +#ifdef CONFIG_HAVE_SPARSE_IRQ +rcu_read_unlock (); +#endif }static const struct seq_operations int_seq_ops = {Index:
linux-2.6/include/linux/interrupt.h
===================================================================include/linux/interrupt.h +2
-0@@ -18,6 +18,8 @@#include <asm/ptrace.h> #include <asm/system.h> +extern int nr_irqs; +/* * These correspond to the IORESOURCE_IRQ_* defines in * linux/ioport.h to select the interrupt line behaviour. When Index:
linux-2.6/include/linux/irq.h
===================================================================include/linux/irq.h +52
-2@@ -128,6 +128,8 @@ struct irq_chip {const char *typename; }; +struct timer_rand_state ; +struct irq_2_iommu ;/** * struct irq_desc - interrupt descriptor * @@ -154,6 +156,15 @@ struct irq_chip {*/ struct irq_desc {unsigned int irq; +#ifdef CONFIG_HAVE_SPARSE_IRQ +struct list_head list; +struct list_head hash_entry; +struct timer_rand_state *timer_rand_state; +unsigned int *kstat_irqs; +# ifdef CONFIG_INTR_REMAP +struct irq_2_iommu *irq_2_iommu; +# endif +#endif irq_flow_handler_t handle_irq;struct irq_chip *chip;struct msi_desc *msi_desc;@@ -181,14 +192,53 @@ struct irq_desc {const char *name; }____cacheline_internodealigned_in_smp ; +extern struct irq_desc *irq_to_desc (unsigned int irq); +extern struct irq_desc *irq_to_desc_alloc_cpu (unsigned int irq,int cpu); +extern struct irq_desc *irq_to_desc_alloc (unsigned int irq); + +#ifndef CONFIG_HAVE_SPARSE_IRQ +/* could be removed if we get rid of all irq_desc reference */ extern struct irq_desc irq_desc[NR_IRQS ]; -static inline struct irq_desc *irq_to_desc (unsigned int irq) +#ifdef CONFIG_GENERIC_HARDIRQS +# define for_each_irq_desc (irq, desc) \ + for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++) +# define for_each_irq_desc_reverse (irq, desc) \ + for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1); \ + irq >= 0; irq--, desc--) + +#define end_for_each_irq_desc () +#endif + +static inline early_sparse_irq_init_work (void) { -return (irq < nr_irqs) ? irq_desc + irq :NULL ; } +#else + +void early_sparse_irq_init_work (void ); +extern struct list_head sparse_irqs_head; +#define for_each_irq_desc (irqX, desc) \ + rcu_read_lock(); \ + for (desc = list_entry(rcu_dereference(sparse_irqs_head.next), typeof(*desc), list), irqX = desc->irq; \ + prefetch(desc->list.next), &desc->list != &sparse_irqs_head; \ + desc = list_entry(rcu_dereference(desc->list.next), typeof(*desc), list), irqX = desc ? desc->irq : -1U) + +#define for_each_irq_desc_reverse (irqX, desc) \ + rcu_read_lock(); \ + for (desc = list_entry(rcu_dereference(sparse_irqs_head.prev), typeof(*desc), list), irqX = desc->irq; \ + prefetch(desc->list.prev), &desc->list != &sparse_irqs_head; \ + desc = list_entry(rcu_dereference(desc->list.prev), typeof(*desc), list), irqX = desc ? desc->irq : -1U) + +#define end_for_each_irq_desc () rcu_read_unlock() + +#define kstat_irqs_this_cpu (DESC ) \ + ((DESC)->kstat_irqs[smp_processor_id()]) +#define kstat_incr_irqs_this_cpu (irqno,DESC ) \ + ((DESC)->kstat_irqs[smp_processor_id()]++) +#endif +/* * Migration helpers for obsolete names, they will go away: */ Index:
linux-2.6/include/linux/kernel_stat.h
===================================================================include/linux/kernel_stat.h +13
-1@@ -28,7 +28,9 @@ struct cpu_usage_stat {struct kernel_stat {struct cpu_usage_stat cpustat; -unsigned int irqs[NR_IRQS ]; +#ifndef CONFIG_HAVE_SPARSE_IRQ +unsigned int irqs[NR_IRQS ]; +#endif }; DECLARE_PER_CPU(struct kernel_stat, kstat);@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, kstaextern unsigned long long nr_context_switches (void ); +#ifndef CONFIG_HAVE_SPARSE_IRQ +#define kstat_irqs_this_cpu (irq) \ + (kstat_this_cpu.irqs[irq]) +struct irq_desc ; static inline void kstat_incr_irqs_this_cpu(unsigned int irq,@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_ { kstat_this_cpu.irqs[irq]++; } +#endif + +#ifndef CONFIG_HAVE_SPARSE_IRQ static inline unsigned int kstat_irqs_cpu (unsigned int irq,int cpu) {return kstat_cpu (cpu).irqs[irq]; } +#else +extern unsigned int kstat_irqs_cpu (unsigned int irq,int cpu); +#endif /* * Number of interrupts per specific IRQ source, since bootup Index:
linux-2.6/kernel/irq/autoprobe.c
===================================================================kernel/irq/autoprobe.c +5
-0@@ -58,6 +58,7 @@ unsigned long probe_irq_on(void) }spin_unlock_irq (&desc->lock); } + end_for_each_irq_desc();/* Wait for longstanding interrupts to trigger. */ msleep (20 );@@ -76,6 +77,7 @@ unsigned long probe_irq_on(void) }spin_unlock_irq (&desc->lock); } + end_for_each_irq_desc();/* * Wait for spurious interrupts to trigger @@ -100,6 +102,7 @@ unsigned long probe_irq_on(void) }spin_unlock_irq (&desc->lock); } + end_for_each_irq_desc();return mask; }@@ -136,6 +139,7 @@ unsigned int probe_irq_mask(unsigned lon }spin_unlock_irq (&desc->lock); } + end_for_each_irq_desc();mutex_unlock (&probing_active);return mask & val;@@ -180,6 +184,7 @@ int probe_irq_off(unsigned long val) }spin_unlock_irq (&desc->lock); } + end_for_each_irq_desc();mutex_unlock (&probing_active);if (nr_of_irqs >1 )Index:
linux-2.6/kernel/irq/chip.c
===================================================================kernel/irq/chip.c +3
-1@@ -24,9 +24,11 @@*/ void dynamic_irq_init (unsigned int irq) { -struct irq_desc *desc =irq_to_desc (irq); +struct irq_desc *desc;unsigned long flags; +/* first time to use this irq_desc */ + desc =irq_to_desc_alloc (irq);if (!desc) {WARN (1 ,KERN_ERR "Trying to initialize invalid IRQ%d\n" , irq);return ;Index:
linux-2.6/kernel/irq/handle.c
===================================================================kernel/irq/handle.c +209
-5@@ -15,9 +15,16 @@#include <linux/random.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> +#include <linux/rculist.h> +#include <linux/hash.h> #include "internals.h" +/* +* lockdep: we want to handle all irq_desc locks as a single lock-class: +*/ +static struct lock_class_key irq_desc_lock_class; +/** * handle_bad_irq - handle spurious and unhandled irqs * @irq: the interrupt number @@ -49,6 +56,179 @@ void handle_bad_irq(unsigned int irq, stint nr_irqs =NR_IRQS ;EXPORT_SYMBOL_GPL (nr_irqs); +#ifdef CONFIG_HAVE_SPARSE_IRQ +static struct irq_desc irq_desc_init = { + .irq = -1U, + .status = IRQ_DISABLED, + .chip = &no_irq_chip, + .handle_irq = handle_bad_irq, + .depth = 1, + .lock = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock), +#ifdef CONFIG_SMP + .affinity = CPU_MASK_ALL +#endif +}; + +static void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr) +{ + unsigned long bytes; + char *ptr; + int node; + unsigned int irq; + + /* Compute how many bytes we need per irq and allocate them */ + bytes = nr * sizeof(unsigned int); + irq = desc->irq; + + if (cpu < 0) + cpu = smp_processor_id(); + + node = cpu_to_node(cpu); + ptr = kzalloc_node(bytes, GFP_KERNEL, node); + printk(KERN_DEBUG " alloc kstat_irqs for %d aka %#x on cpu %d node %d\n", + irq, irq, cpu, node); + + desc->kstat_irqs = (unsigned int *)ptr; +} + +static void init_one_irq_desc(struct irq_desc *desc) +{ + memcpy(desc, &irq_desc_init, sizeof(struct irq_desc)); + lockdep_set_class(&desc->lock, &irq_desc_lock_class); +} + +/* + * Protect the sparse_irqs_free freelist: + */ +static DEFINE_SPINLOCK(sparse_irq_lock); +LIST_HEAD(sparse_irqs_head); + +/* + * The sparse irqs are in a hash-table as well, for fast lookup: + */ +#define SPARSEIRQHASH_BITS (13 - 1) +#define SPARSEIRQHASH_SIZE (1UL << SPARSEIRQHASH_BITS) +#define __sparseirqhashfn(key) hash_long((unsigned long)key, SPARSEIRQHASH_BITS) +#define sparseirqhashentry(key) (sparseirqhash_table + __sparseirqhashfn((key))) + +static struct list_head sparseirqhash_table[SPARSEIRQHASH_SIZE]; + +static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = { + [0 ... NR_IRQS_LEGACY-1] = { + .irq = -1U, + .status = IRQ_DISABLED, + .chip = &no_irq_chip, + .handle_irq = handle_bad_irq, + .depth = 1, + .lock = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock), +#ifdef CONFIG_SMP + .affinity = CPU_MASK_ALL +#endif + } +}; + +/* FIXME: use bootmem alloc ...*/ +static unsigned int kstat_irqs_legacy[NR_IRQS_LEGACY][NR_CPUS]; + +void __init early_sparse_irq_init_work(void) +{ + struct irq_desc *desc; + int legacy_count; + int i; + + for (i = 0; i < SPARSEIRQHASH_SIZE; i++) + INIT_LIST_HEAD(sparseirqhash_table + i); + + desc = irq_desc_legacy; + legacy_count = ARRAY_SIZE(irq_desc_legacy); + + for (i = 0; i < legacy_count; i++) { + struct list_head *hash_head; + + hash_head = sparseirqhashentry(i); + desc[i].irq = i; + desc[i].kstat_irqs = kstat_irqs_legacy[i]; + list_add_tail(&desc[i].hash_entry, hash_head); + list_add_tail(&desc[i].list, &sparse_irqs_head); + } +} + +struct irq_desc *irq_to_desc(unsigned int irq) +{ + struct irq_desc *desc; + struct list_head *hash_head; + + hash_head = sparseirqhashentry(irq); + + /* + * We can walk the hash lockfree, because the hash only + * grows, and we are careful when adding entries to the end: + */ + list_for_each_entry(desc, hash_head, hash_entry) { + if (desc->irq == irq) + return desc; + } + + return NULL; +} + +struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu) +{ + struct irq_desc *desc; + struct list_head *hash_head; + unsigned long flags; + int node; + + desc = irq_to_desc(irq); + if (desc) + return desc; + + hash_head = sparseirqhashentry(irq); + + spin_lock_irqsave(&sparse_irq_lock, flags); + + /* + * We have to do the hash-walk again, to avoid races + * with another CPU: + */ + list_for_each_entry(desc, hash_head, hash_entry) + if (desc->irq == irq) + goto out_unlock; + + if (cpu < 0) + cpu = smp_processor_id(); + + node = cpu_to_node(cpu); + desc = kzalloc_node(sizeof(*desc), GFP_KERNEL, node); + init_one_irq_desc(desc); + desc->irq = irq; + init_kstat_irqs(desc, cpu, nr_cpu_ids); + printk(KERN_DEBUG " alloc irq_desc for %d aka %#x on cpu %d node %d\n", + irq, irq, cpu, node); + + /* + * We use RCU's safe list-add method to make + * parallel walking of the hash-list safe: + */ + list_add_tail_rcu(&desc->hash_entry, hash_head); + /* + * Add it to the global list: + */ + list_add_tail_rcu(&desc->list, &sparse_irqs_head); + +out_unlock: + spin_unlock_irqrestore(&sparse_irq_lock, flags); + + return desc; +} + +struct irq_desc *irq_to_desc_alloc(unsigned int irq) +{ + return irq_to_desc_alloc_cpu(irq, -1); +} + +#else + struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { [0 ... NR_IRQS-1] = { .status = IRQ_DISABLED,@@ -62,6 +242,23 @@ struct irq_desc irq_desc[NR_IRQS] __cach } }; +struct irq_desc *irq_to_desc (unsigned int irq) +{ +if (irq < nr_irqs) +return &irq_desc[irq]; + +return NULL ; +} +struct irq_desc *irq_to_desc_alloc_cpu (unsigned int irq,int cpu) +{ +return irq_to_desc (irq); +} +struct irq_desc *irq_to_desc_alloc (unsigned int irq) +{ +return irq_to_desc (irq); +} +#endif +/* * What should we do if we get a hw irq event on an illegal vector? * Each architecture has to answer this themself. @@ -261,17 +458,24 @@ out:#ifdef CONFIG_TRACE_IRQFLAGS -/* -* lockdep: we want to handle all irq_desc locks as a single lock-class: -*/ -static struct lock_class_key irq_desc_lock_class; -void early_init_irq_lock_class (void ) { +#ifndef CONFIG_HAVE_SPARSE_IRQ struct irq_desc *desc;int i;for_each_irq_desc (i, desc)lockdep_set_class (&desc->lock, &irq_desc_lock_class); +#endif }#endif + +#ifdef CONFIG_HAVE_SPARSE_IRQ +unsigned int kstat_irqs_cpu (unsigned int irq,int cpu) +{ +struct irq_desc *desc =irq_to_desc (irq); +return desc->kstat_irqs[cpu]; +} +#endif +EXPORT_SYMBOL (kstat_irqs_cpu); +Index:
linux-2.6/arch/x86/kernel/irq.c
===================================================================arch/x86/kernel/irq.c +9
-10@@ -99,25 +99,20 @@ static int show_other_interrupts(structint show_interrupts (struct seq_file *p,void *v) {unsigned long flags, any_count =0 ; -int i = *(loff_t *) v, j; +int i, j;struct irqaction *action;struct irq_desc *desc; -if (i > nr_irqs) -return 0 ; - -if (i == nr_irqs) -return show_other_interrupts (p); - -/* print header */ -if (i ==0 ) { + desc = list_entry(v, struct irq_desc, list); + i = desc->irq; +if (&desc->list == sparse_irqs_head.next) { +/* print header */ seq_printf (p," " );for_each_online_cpu (j)seq_printf (p,"CPU%-8d" , j);seq_putc (p,'\n' ); } - desc =irq_to_desc (i);spin_lock_irqsave (&desc->lock, flags);#ifndef CONFIG_SMP any_count =kstat_irqs (i);@@ -148,6 +143,10 @@ int show_interrupts(struct seq_file *p,seq_putc (p,'\n' ); out:spin_unlock_irqrestore (&desc->lock, flags); + +if (&desc->list == sparse_irqs_head.prev) +show_other_interrupts (p); +return 0 ; }Index:
linux-2.6/include/linux/irqnr.h
===================================================================include/linux/irqnr.h +4
-11@@ -7,18 +7,11 @@# define for_each_irq_desc (irq, desc) \ for (irq = 0; irq < nr_irqs; irq++) -#else -extern int nr_irqs; +# define end_for_each_irq_desc () -# define for_each_irq_desc (irq, desc) \ - for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++) - -# define for_each_irq_desc_reverse (irq, desc) \ - for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1); \ - irq >= 0; irq--, desc--) +static inline early_sparse_irq_init_work (void) +{ +}#endif -#define for_each_irq_nr (irq) \ - for (irq = 0; irq < nr_irqs; irq++) -#endif Index:
linux-2.6/arch/x86/kernel/irq_32.c
===================================================================arch/x86/kernel/irq_32.c +1
-0@@ -255,6 +255,7 @@ void fixup_irqs(cpumask_t map)else if (desc->action && !(warned++))printk ("Cannot set affinity for irq %i\n" , irq); } + end_for_each_irq_desc();#if 0 barrier ();Index:
linux-2.6/arch/x86/kernel/irq_64.c
===================================================================arch/x86/kernel/irq_64.c +1
-0@@ -130,6 +130,7 @@ void fixup_irqs(cpumask_t map)else if (!set_affinity)printk ("Cannot set affinity for irq %i\n" , irq); } + end_for_each_irq_desc();/* That doesn't seem sufficient. Give it 1ms. */ local_irq_enable ();Index:
linux-2.6/kernel/irq/proc.c
===================================================================kernel/irq/proc.c +1
-0@@ -245,5 +245,6 @@ void init_irq_proc(void)*/ for_each_irq_desc (irq, desc)register_irq_proc (irq, desc); + end_for_each_irq_desc(); }Index:
linux-2.6/kernel/irq/spurious.c
===================================================================kernel/irq/spurious.c +2
-0@@ -100,6 +100,7 @@ static int misrouted_irq(int irq)if (try_one_irq (i, desc)) ok =1 ; } + end_for_each_irq_desc();/* So the caller can adjust the irq error counts */ return ok; }@@ -124,6 +125,7 @@ static void poll_spurious_irqs(unsignedtry_one_irq (i, desc); } + end_for_each_irq_desc();mod_timer (&poll_spurious_irq_timer, jiffies +POLL_SPURIOUS_IRQ_INTERVAL ); }Index:
linux-2.6/arch/x86/kernel/setup_percpu.c
===================================================================arch/x86/kernel/setup_percpu.c +4
-0@@ -191,6 +191,10 @@ void __init setup_per_cpu_areas(void)/* Setup node to cpumask map */ setup_node_to_cpumask_map (); + +/* init_work to init list for sparseirq */ +early_sparse_irq_init_work (); + early_irq_cfg_init_work(); }#endif Index:
linux-2.6/init/main.c
===================================================================init/main.c +6
-1@@ -363,7 +363,10 @@ static void __init smp_init(void)#define smp_init () do { } while (0)#endif -static inline void setup_per_cpu_areas (void ) { } +static inline void setup_per_cpu_areas (void ) +{ +early_sparse_irq_init_work (); +}static inline void setup_nr_cpu_ids (void ) { }static inline void smp_prepare_cpus (unsigned int maxcpus) { }@@ -409,6 +412,8 @@ static void __init setup_per_cpu_areas(vmemcpy (ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); ptr += size; } + +early_sparse_irq_init_work (); }#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */ Index:
linux-2.6/arch/x86/include/asm/io_apic.h
===================================================================arch/x86/include/asm/io_apic.h +4
-0@@ -199,6 +199,7 @@ extern void reinit_intr_remapped_IO_APIC#endif extern int probe_nr_irqs (void ); +void early_irq_cfg_init_work (void );#else /* !CONFIG_X86_IO_APIC */ #define io_apic_assign_pci_irqs 0@@ -209,6 +210,9 @@ static inline int probe_nr_irqs(void) {return NR_IRQS ; } +static inline void early_irq_cfg_init_work (void ) +{ +}#endif #endif /* _ASM_X86_IO_APIC_H */ Index:
linux-2.6/arch/x86/include/asm/irq_vectors.h
===================================================================arch/x86/include/asm/irq_vectors.h +2
-0@@ -101,6 +101,8 @@#define LAST_VM86_IRQ 15#define invalid_vm86_irq (irq) ((irq) < 3 || (irq) > 15) +#define NR_IRQS_LEGACY 16 +#if defined(CONFIG_X86_IO_APIC ) && !defined(CONFIG_X86_VOYAGER )# if NR_CPUS <MAX_IO_APICS # define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))
Quoted 9 lines · Yinghai Lu
impact: new feature sparseirq
add pointers array as Ingo suggesting.
removedyna_arraywhen
sparse_irqis used (CONFIG_SPARSE_IRQ), usekzalloc_nodeto getirq_desc,irq_cfg
usedesc->chip_datafor x86 to storeirq_cfgSigned-off-by Yinghai Lu <[email protected]>
thanks Yinghai - i've applied your four patches to tip/irq/sparseirq, with the changelogs below.
Jesse, any objections to the MSI IRQ renumbering? It's a much saner static numbering scheme counting upwards, independent of NR_CPUS.
Ingo
---------------->
commit 0b8f1efad30bd58f89961b82dfe68b9edf8fd2ac
Author: Yinghai Lu <[email protected]> Date: Fri Dec 5 18:58:31 2008 -0800
sparse irq_desc[] array: core kernel and x86 changes
Impact: new feature
Problem on distro kernels: irq_desc[NR_IRQS] takes megabytes of RAM with NR_CPUS set to large values. The goal is to be able to scale up to much larger NR_IRQS value without impacting the (important) common case.
To solve this, we generalize irq_desc[NR_IRQS] to an (optional) array of irq_desc pointers.
When CONFIG_SPARSE_IRQ=y is used, we use kzalloc_node to get irq_desc, this also makes the IRQ descriptors NUMA-local (to the site that calls request_irq()).
This gets rid of the irq_cfg[] static array on x86 as well: irq_cfg now uses desc->chip_data for x86 to store irq_cfg.
arch/x86/Kconfig +10 -0
@@ -238,6 +238,16 @@ config X86_HAS_BOOT_CPU_ID def_bool y depends on X86_VOYAGER +config SPARSE_IRQ + bool "Support sparse irq numbering" + depends on PCI_MSI || HT_IRQ + default y + help + This enables support for sparse irq, esp for msi/msi-x. You may need + if you have lots of cards supports msi-x installed. + + If you don't know what to do here, say Y. + config X86_FIND_SMP_CONFIG def_bool y depends on X86_MPPARSE || X86_VOYAGER
arch/x86/include/asm/irq_vectors.h +9 -0
@@ -102,11 +102,20 @@#define invalid_vm86_irq (irq) ((irq) < 3 || (irq) > 15)#if defined(CONFIG_X86_IO_APIC ) && !defined(CONFIG_X86_VOYAGER ) + +#ifndef CONFIG_SPARSE_IRQ # if NR_CPUS <MAX_IO_APICS # define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))# else # define NR_IRQS (NR_VECTORS + (32 * MAX_IO_APICS))# endif +#else +# if (8 *NR_CPUS ) > (32 *MAX_IO_APICS ) +# define NR_IRQS (NR_VECTORS + (8 * NR_CPUS)) +# else +# define NR_IRQS (NR_VECTORS + (32 * MAX_IO_APICS)) +# endif +#endif #elif defined(CONFIG_X86_VOYAGER )
arch/x86/kernel/io_apic.c +190 -111
541 lines not on this page · raw message
arch/x86/kernel/irq.c +3 -0
@@ -118,6 +118,9 @@ int show_interrupts(struct seq_file *p, void *v) } desc =irq_to_desc (i); +if (!desc) +return 0 ; +spin_lock_irqsave (&desc->lock, flags);#ifndef CONFIG_SMP any_count =kstat_irqs (i);
arch/x86/kernel/irq_32.c +2 -0
@@ -242,6 +242,8 @@ void fixup_irqs(cpumask_t map)for_each_irq_desc (irq, desc) {cpumask_t mask; +if (!desc) +continue ;if (irq ==2 )continue ;
arch/x86/kernel/irq_64.c +2 -0
@@ -94,6 +94,8 @@ void fixup_irqs(cpumask_t map)int break_affinity =0 ;int set_affinity =1 ; +if (!desc) +continue ;if (irq ==2 )continue ;
arch/x86/kernel/irqinit_32.c +0 -1
@@ -69,7 +69,6 @@ void __init init_ISA_irqs (void)* 16 old-style INTA-cycle interrupts: */ for (i =0 ; i <16 ; i++) { -/* first time call this irq_desc */ struct irq_desc *desc =irq_to_desc (i); desc->status =IRQ_DISABLED ;
arch/x86/kernel/irqinit_64.c +0 -1
@@ -143,7 +143,6 @@ void __init init_ISA_irqs(void)init_8259A (0 );for (i =0 ; i <16 ; i++) { -/* first time call this irq_desc */ struct irq_desc *desc =irq_to_desc (i); desc->status =IRQ_DISABLED ;
drivers/char/random.c +5 -17
@@ -558,23 +558,9 @@ struct timer_rand_state { unsigned dont_count_entropy:1; }; -static struct timer_rand_state *irq_timer_state[NR_IRQS ]; - -static struct timer_rand_state *get_timer_rand_state (unsigned int irq) -{ -if (irq >= nr_irqs) -return NULL ; - -return irq_timer_state[irq]; -} - -static void set_timer_rand_state (unsigned int irq,struct timer_rand_state *state) -{ -if (irq >= nr_irqs) -return ; - - irq_timer_state[irq] = state; -} +#ifndef CONFIG_SPARSE_IRQ +struct timer_rand_state *irq_timer_state[NR_IRQS ]; +#endif static struct timer_rand_state input_timer_state;
@@ -933,8 +919,10 @@ void rand_initialize_irq(int irq) {struct timer_rand_state *state; +#ifndef CONFIG_SPARSE_IRQ if (irq >= nr_irqs)return ; +#endif state =get_timer_rand_state (irq);
drivers/pci/intr_remapping.c +74 -2
112 lines not on this page · raw message
drivers/xen/events.c +8 -4
@@ -141,8 +141,12 @@ static void init_evtchn_cpu_bindings(void)int i;/* By default all event channels notify CPU#0. */ -for_each_irq_desc (i, desc) +for_each_irq_desc (i, desc) { +if (!desc) +continue ; + desc->affinity =cpumask_of_cpu (0 ); + }#endif memset (cpu_evtchn,0 ,sizeof (cpu_evtchn));
@@ -231,7 +235,7 @@ static int find_unbound_irq(void)int irq;/* Only allocate from dynirq range */ -for_each_irq_nr (irq) +for (irq =0 ; irq < nr_irqs; irq++)if (irq_bindcount[irq] ==0 )break ;
@@ -792,7 +796,7 @@ void xen_irq_resume(void)mask_evtchn (evtchn);/* No IRQ <-> event-channel mappings. */ -for_each_irq_nr (irq) +for (irq =0 ; irq < nr_irqs; irq++) irq_info[irq].evtchn =0 ;/* zap event-channel binding */ for (evtchn =0 ; evtchn <NR_EVENT_CHANNELS ; evtchn++)
@@ -824,7 +828,7 @@ void __init xen_init_IRQ(void)mask_evtchn (i);/* Dynamic IRQ space is currently unbound. Zero the refcnts. */ -for_each_irq_nr (i) +for (i =0 ; i < nr_irqs; i++) irq_bindcount[i] =0 ;irq_ctx_init (smp_processor_id ());
fs/proc/stat.c +11 -6
@@ -27,6 +27,7 @@ static int show_stat(struct seq_file *p, void *v)u64 sum =0 ;struct timespec boottime;unsigned int per_irq_sum; +struct irq_desc *desc; user = nice = system = idle = iowait = irq = softirq = steal = cputime64_zero;
@@ -44,10 +45,11 @@ static int show_stat(struct seq_file *p, void *v) softirq =cputime64_add (softirq,kstat_cpu (i).cpustat.softirq); steal =cputime64_add (steal,kstat_cpu (i).cpustat.steal); guest =cputime64_add (guest,kstat_cpu (i).cpustat.guest); - -for_each_irq_nr (j) +for_each_irq_desc (j, desc) { +if (!desc) +continue ; sum +=kstat_irqs_cpu (j, i); - + } sum +=arch_irq_stat_cpu (i); } sum +=arch_irq_stat ();
@@ -90,11 +92,14 @@ static int show_stat(struct seq_file *p, void *v)seq_printf (p,"intr %llu" , (unsigned long long )sum);/* sum again ? it could be updated? */ -for_each_irq_nr (j) { +for (j =0 ; j <NR_IRQS ; j++) { + desc =irq_to_desc (j); per_irq_sum =0 ; -for_each_possible_cpu (i) - per_irq_sum +=kstat_irqs_cpu (j, i); +if (desc) { +for_each_possible_cpu (i) + per_irq_sum +=kstat_irqs_cpu (j, i); + }seq_printf (p," %u" , per_irq_sum); }
include/linux/interrupt.h +2 -0
@@ -18,6 +18,8 @@#include <asm/ptrace.h> #include <asm/system.h> +extern int nr_irqs; +/* * These correspond to the IORESOURCE_IRQ_* defines in * linux/ioport.h to select the interrupt line behaviour. When
include/linux/irq.h +53 -1
85 lines not on this page · raw message
include/linux/irqnr.h +3 -11
@@ -7,18 +7,10 @@# define for_each_irq_desc (irq, desc) \ for (irq = 0; irq < nr_irqs; irq++) -#else -extern int nr_irqs; -# define for_each_irq_desc (irq, desc) \ - for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++) - -# define for_each_irq_desc_reverse (irq, desc) \ - for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1); \ - irq >= 0; irq--, desc--) +static inline early_sparse_irq_init (void) +{ +}#endif -#define for_each_irq_nr (irq) \ - for (irq = 0; irq < nr_irqs; irq++) -#endif
include/linux/kernel_stat.h +13 -1
@@ -28,7 +28,9 @@ struct cpu_usage_stat {struct kernel_stat {struct cpu_usage_stat cpustat; -unsigned int irqs[NR_IRQS ]; +#ifndef CONFIG_SPARSE_IRQ +unsigned int irqs[NR_IRQS ]; +#endif }; DECLARE_PER_CPU(struct kernel_stat, kstat);
@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, kstat);extern unsigned long long nr_context_switches (void ); +#ifndef CONFIG_SPARSE_IRQ +#define kstat_irqs_this_cpu (irq) \ + (kstat_this_cpu.irqs[irq]) +struct irq_desc ; static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq, { kstat_this_cpu.irqs[irq]++; } +#endif + +#ifndef CONFIG_SPARSE_IRQ static inline unsigned int kstat_irqs_cpu (unsigned int irq,int cpu) {return kstat_cpu (cpu).irqs[irq]; } +#else +extern unsigned int kstat_irqs_cpu (unsigned int irq,int cpu); +#endif /* * Number of interrupts per specific IRQ source, since bootup
include/linux/random.h +51 -0
57 lines not on this page · raw message
init/main.c +11 -0
@@ -539,6 +539,15 @@ void __init __weak thread_info_cache_init(void) { } +void __init __weak arch_early_irq_init (void ) +{ +} + +void __init __weak early_irq_init (void ) +{ +arch_early_irq_init (); +} + asmlinkage void __init start_kernel(void) {char * command_line;
@@ -603,6 +612,8 @@ asmlinkage void __init start_kernel(void)sort_main_extable ();trap_init ();rcu_init (); +/* init some links before init_ISA_irqs() */ +early_irq_init ();init_IRQ ();pidhash_init ();init_timers ();
kernel/irq/autoprobe.c +15 -0
@@ -40,6 +40,9 @@ unsigned long probe_irq_on(void)* flush such a longstanding irq before considering it as spurious. */ for_each_irq_desc_reverse (i, desc) { +if (!desc) +continue ; +spin_lock_irq (&desc->lock);if (!desc->action && !(desc->status &IRQ_NOPROBE )) {/*
@@ -68,6 +71,9 @@ unsigned long probe_irq_on(void)* happened in the previous stage, it may have masked itself) */ for_each_irq_desc_reverse (i, desc) { +if (!desc) +continue ; +spin_lock_irq (&desc->lock);if (!desc->action && !(desc->status &IRQ_NOPROBE )) { desc->status |=IRQ_AUTODETECT |IRQ_WAITING ;
@@ -86,6 +92,9 @@ unsigned long probe_irq_on(void)* Now filter out any obviously spurious interrupts */ for_each_irq_desc (i, desc) { +if (!desc) +continue ; +spin_lock_irq (&desc->lock); status = desc->status;
@@ -124,6 +133,9 @@ unsigned int probe_irq_mask(unsigned long val)int i;for_each_irq_desc (i, desc) { +if (!desc) +continue ; +spin_lock_irq (&desc->lock); status = desc->status;
@@ -166,6 +178,9 @@ int probe_irq_off(unsigned long val)unsigned int status;for_each_irq_desc (i, desc) { +if (!desc) +continue ; +spin_lock_irq (&desc->lock); status = desc->status;
kernel/irq/chip.c +2 -1
@@ -24,9 +24,10 @@*/ void dynamic_irq_init (unsigned int irq) { -struct irq_desc *desc =irq_to_desc (irq); +struct irq_desc *desc;unsigned long flags; + desc =irq_to_desc (irq);if (!desc) {WARN (1 ,KERN_ERR "Trying to initialize invalid IRQ%d\n" , irq);return ;
kernel/irq/handle.c +175 -6
213 lines not on this page · raw message
kernel/irq/proc.c +5 -1
@@ -243,7 +243,11 @@ void init_irq_proc(void)/* * Create entries for all existing IRQs. */ -for_each_irq_desc (irq, desc) +for_each_irq_desc (irq, desc) { +if (!desc) +continue ; +register_irq_proc (irq, desc); + } }
kernel/irq/spurious.c +5 -0
@@ -91,6 +91,9 @@ static int misrouted_irq(int irq)int i, ok =0 ;for_each_irq_desc (i, desc) { +if (!desc) +continue ; +if (!i)continue ;
@@ -112,6 +115,8 @@ static void poll_spurious_irqs(unsigned long dummy)for_each_irq_desc (i, desc) {unsigned int status; +if (!desc) +continue ;if (!i)continue ;
commit 99d093d12897562a253540a902bbf65ec16042ac
Author: Yinghai Lu <[email protected]> Date: Fri Dec 5 18:58:32 2008 -0800
x86: use NR_IRQS_LEGACY
Impact: cleanup
Introduce NR_IRQS_LEGACY instead of hard coded number.
arch/x86/include/asm/irq_vectors.h +2 -0
@@ -101,6 +101,8 @@#define LAST_VM86_IRQ 15#define invalid_vm86_irq (irq) ((irq) < 3 || (irq) > 15) +#define NR_IRQS_LEGACY 16 +#if defined(CONFIG_X86_IO_APIC ) && !defined(CONFIG_X86_VOYAGER )#ifndef CONFIG_SPARSE_IRQ
arch/x86/kernel/io_apic.c +5 -5
@@ -847,7 +847,7 @@ EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);*/ static int EISA_ELCR (unsigned int irq) { -if (irq <16 ) { +if (irq <NR_IRQS_LEGACY ) {unsigned int port =0x4d0 + (irq >>3 );return (inb (port) >> (irq &7 )) &1 ; }
@@ -1388,7 +1388,7 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq, }ioapic_register_intr (irq, trigger); -if (irq <16 ) +if (irq <NR_IRQS_LEGACY )disable_8259A_irq (irq);ioapic_write_entry (apic, pin, entry);
@@ -2080,7 +2080,7 @@ static unsigned int startup_ioapic_irq(unsigned int irq)struct irq_cfg *cfg;spin_lock_irqsave (&ioapic_lock, flags); -if (irq <16 ) { +if (irq <NR_IRQS_LEGACY ) {disable_8259A_irq (irq);if (i8259A_irq_pending (irq)) was_pending =1 ;
@@ -2504,7 +2504,7 @@ static inline void init_IO_APIC_traps(void)* so default to an old-fashioned 8259 * interrupt if we can.. */ -if (irq <16 ) +if (irq <NR_IRQS_LEGACY )make_8259A_irq (irq);else /* Strange. Oh, well.. */
@@ -3794,7 +3794,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p/* * IRQs < 16 are already in the irq_2_pin[] map */ -if (irq >=16 ) { +if (irq >=NR_IRQS_LEGACY ) { cfg = desc->chip_data;add_pin_to_irq_cpu (irq, cpu, ioapic, pin); }
arch/x86/kernel/irqinit_32.c +1 -1
@@ -68,7 +68,7 @@ void __init init_ISA_irqs (void)/* * 16 old-style INTA-cycle interrupts: */ -for (i =0 ; i <16 ; i++) { +for (i =0 ; i <NR_IRQS_LEGACY ; i++) {struct irq_desc *desc =irq_to_desc (i); desc->status =IRQ_DISABLED ;
arch/x86/kernel/irqinit_64.c +1 -1
@@ -142,7 +142,7 @@ void __init init_ISA_irqs(void)init_bsp_APIC ();init_8259A (0 ); -for (i =0 ; i <16 ; i++) { +for (i =0 ; i <NR_IRQS_LEGACY ; i++) {struct irq_desc *desc =irq_to_desc (i); desc->status =IRQ_DISABLED ;
kernel/irq/handle.c +3 -3
@@ -117,8 +117,8 @@ static DEFINE_SPINLOCK(sparse_irq_lock);struct irq_desc *irq_desc_ptrs[NR_IRQS ]__read_mostly ; -static struct irq_desc irq_desc_legacy[16] __cacheline_aligned_in_smp = { - [0 ...15 ] = { +static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = { + [0 ...NR_IRQS_LEGACY -1 ] = { .irq =-1 , .status =IRQ_DISABLED , .chip = &no_irq_chip,
@@ -132,7 +132,7 @@ static struct irq_desc irq_desc_legacy[16] __cacheline_aligned_in_smp = { };/* FIXME: use bootmem alloc ...*/ -static unsigned int kstat_irqs_legacy[16 ][NR_CPUS ]; +static unsigned int kstat_irqs_legacy[NR_IRQS_LEGACY ][NR_CPUS ];void __init early_irq_init (void ) {
commit be5d5350a937cd8513b258739f1099420129e96f
Author: Yinghai Lu <[email protected]> Date: Fri Dec 5 18:58:33 2008 -0800
x86: MSI start irq numbering from nr_irqs_gsi
Impact: sanitize MSI irq number ordering from top-down to bottom-up
Increase new MSI IRQs starting from nr_irqs_gsi (which is somewhere below 256), instead of decreasing from NR_IRQS. (The latter method can result in confusingly high IRQ numbers - if NR_CPUS is set to a high value and NR_IRQS scales up to a high value.)
arch/x86/include/asm/io_apic.h +1 -1
@@ -188,7 +188,7 @@ extern void restore_IO_APIC_setup(void);extern void reinit_intr_remapped_IO_APIC (int );#endif -extern int probe_nr_irqs (void ); +extern void probe_nr_irqs_gsi (void );#else /* !CONFIG_X86_IO_APIC */ #define io_apic_assign_pci_irqs 0
arch/x86/kernel/io_apic.c +17 -7
@@ -2973,7 +2973,7 @@ unsigned int create_irq_nr(unsigned int irq_want) irq =0 ;spin_lock_irqsave (&vector_lock, flags); -for (new = irq_want; new >0 ; new--) { +for (new = irq_want; new <NR_IRQS ; new++) {if (platform_legacy_irq (new))continue ;
@@ -3001,11 +3001,14 @@ unsigned int create_irq_nr(unsigned int irq_want)return irq; } +static int nr_irqs_gsi =NR_IRQS_LEGACY ;int create_irq (void ) { +unsigned int irq_want;int irq; - irq =create_irq_nr (nr_irqs -1 ); + irq_want = nr_irqs_gsi; + irq =create_irq_nr (irq_want);if (irq ==0 ) irq =-1 ;
@@ -3281,7 +3284,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc)int ret;unsigned int irq_want; - irq_want = nr_irqs -1 ; + irq_want = nr_irqs_gsi; irq =create_irq_nr (irq_want);if (irq ==0 )return -1 ;
@@ -3321,11 +3324,11 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)int index =0 ;#endif - irq_want = nr_irqs -1 ; + irq_want = nr_irqs_gsi; sub_handle =0 ;list_for_each_entry (msidesc, &dev->msi_list, list) { irq =create_irq_nr (irq_want); - irq_want--; + irq_want++;if (irq ==0 )return -1 ;#ifdef CONFIG_INTR_REMAP
@@ -3674,9 +3677,16 @@ int __init io_apic_get_redir_entries (int ioapic)return reg_01.bits.entries; } -int __init probe_nr_irqs (void ) +void __init probe_nr_irqs_gsi (void ) { -return NR_IRQS ; +int idx; +int nr =0 ; + +for (idx =0 ; idx < nr_ioapics; idx++) + nr +=io_apic_get_redir_entries (idx) +1 ; + +if (nr > nr_irqs_gsi) + nr_irqs_gsi = nr; }/* --------------------------------------------------------------------------
arch/x86/kernel/setup.c +1 -1
@@ -1082,7 +1082,7 @@ void __init setup_arch(char **cmdline_p)ioapic_init_mappings ();/* need to wait for io_apic is mapped */ - nr_irqs =probe_nr_irqs (); +probe_nr_irqs_gsi ();kvm_guest_init ();
commit 3145e941fcfe2548fa2270afb1a05bab3a6bc418
Author: Yinghai Lu <[email protected]> Date: Fri Dec 5 18:58:34 2008 -0800
x86, MSI: pass irq_cfg and irq_desc
Impact: simplify code
Pass irq_desc and cfg around, instead of raw IRQ numbers - this way we dont have to look it up again and again.
arch/x86/kernel/io_apic.c +181 -137
901 lines not on this page · raw message
drivers/pci/msi.c +38 -17
123 lines not on this page · raw message
include/linux/msi.h +3 -0
@@ -10,8 +10,11 @@ struct msi_msg { };/* Helper functions */ +struct irq_desc ;extern void mask_msi_irq (unsigned int irq);extern void unmask_msi_irq (unsigned int irq); +extern void read_msi_msg_desc (struct irq_desc *desc,struct msi_msg *msg); +extern void write_msi_msg_desc (struct irq_desc *desc,struct msi_msg *msg);extern void read_msi_msg (unsigned int irq,struct msi_msg *msg);extern void write_msi_msg (unsigned int irq,struct msi_msg *msg);
Quoted 9 lines · Ingo Molnar
Quoted 8 lines · Yinghai Lu
impact: new feature sparseirq
add pointers array as Ingo suggesting.
removedyna_arraywhen
sparse_irqis used (CONFIG_SPARSE_IRQ), usekzalloc_nodeto getirq_desc,irq_cfgusedesc->chip_datafor x86 to storeirq_cfg
Quoted 7 lines
Quoted 1 line
Signed-off-by Yinghai Lu <[email protected]>thanks Yinghai - i've applied your four patches to tip/irq/sparseirq, with the changelogs below.
Jesse, any objections to the MSI IRQ renumbering? It's a much saner static numbering scheme counting upwards, independent of
NR_CPUS.
No, I like the idea of the sparse stuff. I'd like to get Matthew's ack though too; he's been working in this area a bit lately.
Jesse