diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1f254bd6c937..9a0ed364d4f7 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1289,6 +1289,18 @@ config HW_PERF_EVENTS Enable hardware performance counter support for perf events. If disabled, perf events will use software events only. +config SPARSE_IRQ + bool "Support sparse irq numbering" + depends on EXPERIMENTAL + help + This enables support for sparse irqs. This is useful in general + as most CPUs have a fairly sparse array of IRQ vectors, which + the irq_desc then maps directly on to. Systems with a high + number of off-chip IRQs will want to treat this as + experimental until they have been independently verified. + + If you don't know what to do here, say N. + source "mm/Kconfig" config LEDS diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h index 237282f7c762..2721a5814cb9 100644 --- a/arch/arm/include/asm/irq.h +++ b/arch/arm/include/asm/irq.h @@ -7,6 +7,8 @@ #define irq_canonicalize(i) (i) #endif +#define NR_IRQS_LEGACY 16 + /* * Use this value to indicate lack of interrupt * capability diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index c59842dc7cb8..5ee6f85236a4 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -20,6 +20,7 @@ struct machine_desc { * by assembler code in head.S, head-common.S */ unsigned int nr; /* architecture number */ + unsigned int nr_irqs; /* number of IRQs */ unsigned int phys_io; /* start of physical io */ unsigned int io_pg_offst; /* byte offset for io * page tabe entry */ diff --git a/arch/arm/include/asm/mach/irq.h b/arch/arm/include/asm/mach/irq.h index 8920b2d6e3b8..ce3eee9fe26c 100644 --- a/arch/arm/include/asm/mach/irq.h +++ b/arch/arm/include/asm/mach/irq.h @@ -17,6 +17,7 @@ struct seq_file; /* * This is internal. Do not use it. */ +extern unsigned int arch_nr_irqs; extern void (*init_arch_irq)(void); extern void init_FIQ(void); extern int show_fiq_list(struct seq_file *, void *); diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 3b3d2c80509c..c0d5c3b3a760 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -47,12 +47,14 @@ #define irq_finish(irq) do { } while (0) #endif +unsigned int arch_nr_irqs; void (*init_arch_irq)(void) __initdata = NULL; unsigned long irq_err_count; int show_interrupts(struct seq_file *p, void *v) { int i = *(loff_t *) v, cpu; + struct irq_desc *desc; struct irqaction * action; unsigned long flags; @@ -67,24 +69,25 @@ int show_interrupts(struct seq_file *p, void *v) seq_putc(p, '\n'); } - if (i < NR_IRQS) { - raw_spin_lock_irqsave(&irq_desc[i].lock, flags); - action = irq_desc[i].action; + if (i < nr_irqs) { + desc = irq_to_desc(i); + raw_spin_lock_irqsave(&desc->lock, flags); + action = desc->action; if (!action) goto unlock; seq_printf(p, "%3d: ", i); for_each_present_cpu(cpu) seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu)); - seq_printf(p, " %10s", irq_desc[i].chip->name ? : "-"); + seq_printf(p, " %10s", desc->chip->name ? : "-"); seq_printf(p, " %s", action->name); for (action = action->next; action; action = action->next) seq_printf(p, ", %s", action->name); seq_putc(p, '\n'); unlock: - raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); - } else if (i == NR_IRQS) { + raw_spin_unlock_irqrestore(&desc->lock, flags); + } else if (i == nr_irqs) { #ifdef CONFIG_FIQ show_fiq_list(p, v); #endif @@ -112,7 +115,7 @@ asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs) * Some hardware gives randomly wrong interrupts. Rather * than crashing, do something sensible. */ - if (unlikely(irq >= NR_IRQS)) { + if (unlikely(irq >= nr_irqs)) { if (printk_ratelimit()) printk(KERN_WARNING "Bad IRQ%u\n", irq); ack_bad_irq(irq); @@ -132,12 +135,12 @@ void set_irq_flags(unsigned int irq, unsigned int iflags) struct irq_desc *desc; unsigned long flags; - if (irq >= NR_IRQS) { + if (irq >= nr_irqs) { printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq); return; } - desc = irq_desc + irq; + desc = irq_to_desc(irq); raw_spin_lock_irqsave(&desc->lock, flags); desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; if (iflags & IRQF_VALID) @@ -151,14 +154,25 @@ void set_irq_flags(unsigned int irq, unsigned int iflags) void __init init_IRQ(void) { + struct irq_desc *desc; int irq; - for (irq = 0; irq < NR_IRQS; irq++) - irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE; + for (irq = 0; irq < nr_irqs; irq++) { + desc = irq_to_desc_alloc_node(irq, 0); + desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE; + } init_arch_irq(); } +#ifdef CONFIG_SPARSE_IRQ +int __init arch_probe_nr_irqs(void) +{ + nr_irqs = arch_nr_irqs ? arch_nr_irqs : NR_IRQS; + return 0; +} +#endif + #ifdef CONFIG_HOTPLUG_CPU static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu) @@ -178,10 +192,9 @@ static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu) void migrate_irqs(void) { unsigned int i, cpu = smp_processor_id(); + struct irq_desc *desc; - for (i = 0; i < NR_IRQS; i++) { - struct irq_desc *desc = irq_desc + i; - + for_each_irq_desc(i, desc) { if (desc->node == cpu) { unsigned int newcpu = cpumask_any_and(desc->affinity, cpu_online_mask); diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 122d999bdc7c..7ae65dc594a4 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -729,6 +729,7 @@ void __init setup_arch(char **cmdline_p) /* * Set up various architecture-specific pointers */ + arch_nr_irqs = mdesc->nr_irqs; init_arch_irq = mdesc->init_irq; system_timer = mdesc->timer; init_machine = mdesc->init_machine;