Prechádzať zdrojové kódy

ARM: 6197/2: preliminary support for sparse IRQ

So to allow NR_IRQS to be dynamic and platforms to specify the number
of IRQs really needed.

Acked-by: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Eric Miao <eric.y.miao@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
eric miao 15 rokov pred
rodič
commit
354e6f72d6

+ 12 - 0
arch/arm/Kconfig

@@ -1289,6 +1289,18 @@ config HW_PERF_EVENTS
 	  Enable hardware performance counter support for perf events. If
 	  Enable hardware performance counter support for perf events. If
 	  disabled, perf events will use software events only.
 	  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"
 source "mm/Kconfig"
 
 
 config LEDS
 config LEDS

+ 2 - 0
arch/arm/include/asm/irq.h

@@ -7,6 +7,8 @@
 #define irq_canonicalize(i)	(i)
 #define irq_canonicalize(i)	(i)
 #endif
 #endif
 
 
+#define NR_IRQS_LEGACY	16
+
 /*
 /*
  * Use this value to indicate lack of interrupt
  * Use this value to indicate lack of interrupt
  * capability
  * capability

+ 1 - 0
arch/arm/include/asm/mach/arch.h

@@ -20,6 +20,7 @@ struct machine_desc {
 	 * by assembler code in head.S, head-common.S
 	 * by assembler code in head.S, head-common.S
 	 */
 	 */
 	unsigned int		nr;		/* architecture number	*/
 	unsigned int		nr;		/* architecture number	*/
+	unsigned int		nr_irqs;	/* number of IRQs */
 	unsigned int		phys_io;	/* start of physical io	*/
 	unsigned int		phys_io;	/* start of physical io	*/
 	unsigned int		io_pg_offst;	/* byte offset for io 
 	unsigned int		io_pg_offst;	/* byte offset for io 
 						 * page tabe entry	*/
 						 * page tabe entry	*/

+ 1 - 0
arch/arm/include/asm/mach/irq.h

@@ -17,6 +17,7 @@ struct seq_file;
 /*
 /*
  * This is internal.  Do not use it.
  * This is internal.  Do not use it.
  */
  */
+extern unsigned int arch_nr_irqs;
 extern void (*init_arch_irq)(void);
 extern void (*init_arch_irq)(void);
 extern void init_FIQ(void);
 extern void init_FIQ(void);
 extern int show_fiq_list(struct seq_file *, void *);
 extern int show_fiq_list(struct seq_file *, void *);

+ 27 - 14
arch/arm/kernel/irq.c

@@ -47,12 +47,14 @@
 #define irq_finish(irq) do { } while (0)
 #define irq_finish(irq) do { } while (0)
 #endif
 #endif
 
 
+unsigned int arch_nr_irqs;
 void (*init_arch_irq)(void) __initdata = NULL;
 void (*init_arch_irq)(void) __initdata = NULL;
 unsigned long irq_err_count;
 unsigned long irq_err_count;
 
 
 int show_interrupts(struct seq_file *p, void *v)
 int show_interrupts(struct seq_file *p, void *v)
 {
 {
 	int i = *(loff_t *) v, cpu;
 	int i = *(loff_t *) v, cpu;
+	struct irq_desc *desc;
 	struct irqaction * action;
 	struct irqaction * action;
 	unsigned long flags;
 	unsigned long flags;
 
 
@@ -67,24 +69,25 @@ int show_interrupts(struct seq_file *p, void *v)
 		seq_putc(p, '\n');
 		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)
 		if (!action)
 			goto unlock;
 			goto unlock;
 
 
 		seq_printf(p, "%3d: ", i);
 		seq_printf(p, "%3d: ", i);
 		for_each_present_cpu(cpu)
 		for_each_present_cpu(cpu)
 			seq_printf(p, "%10u ", kstat_irqs_cpu(i, 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);
 		seq_printf(p, "  %s", action->name);
 		for (action = action->next; action; action = action->next)
 		for (action = action->next; action; action = action->next)
 			seq_printf(p, ", %s", action->name);
 			seq_printf(p, ", %s", action->name);
 
 
 		seq_putc(p, '\n');
 		seq_putc(p, '\n');
 unlock:
 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
 #ifdef CONFIG_FIQ
 		show_fiq_list(p, v);
 		show_fiq_list(p, v);
 #endif
 #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
 	 * Some hardware gives randomly wrong interrupts.  Rather
 	 * than crashing, do something sensible.
 	 * than crashing, do something sensible.
 	 */
 	 */
-	if (unlikely(irq >= NR_IRQS)) {
+	if (unlikely(irq >= nr_irqs)) {
 		if (printk_ratelimit())
 		if (printk_ratelimit())
 			printk(KERN_WARNING "Bad IRQ%u\n", irq);
 			printk(KERN_WARNING "Bad IRQ%u\n", irq);
 		ack_bad_irq(irq);
 		ack_bad_irq(irq);
@@ -132,12 +135,12 @@ void set_irq_flags(unsigned int irq, unsigned int iflags)
 	struct irq_desc *desc;
 	struct irq_desc *desc;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (irq >= NR_IRQS) {
+	if (irq >= nr_irqs) {
 		printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
 		printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
 		return;
 		return;
 	}
 	}
 
 
-	desc = irq_desc + irq;
+	desc = irq_to_desc(irq);
 	raw_spin_lock_irqsave(&desc->lock, flags);
 	raw_spin_lock_irqsave(&desc->lock, flags);
 	desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
 	desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
 	if (iflags & IRQF_VALID)
 	if (iflags & IRQF_VALID)
@@ -151,14 +154,25 @@ void set_irq_flags(unsigned int irq, unsigned int iflags)
 
 
 void __init init_IRQ(void)
 void __init init_IRQ(void)
 {
 {
+	struct irq_desc *desc;
 	int irq;
 	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();
 	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
 #ifdef CONFIG_HOTPLUG_CPU
 
 
 static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int 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)
 void migrate_irqs(void)
 {
 {
 	unsigned int i, cpu = smp_processor_id();
 	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) {
 		if (desc->node == cpu) {
 			unsigned int newcpu = cpumask_any_and(desc->affinity,
 			unsigned int newcpu = cpumask_any_and(desc->affinity,
 							      cpu_online_mask);
 							      cpu_online_mask);

+ 1 - 0
arch/arm/kernel/setup.c

@@ -729,6 +729,7 @@ void __init setup_arch(char **cmdline_p)
 	/*
 	/*
 	 * Set up various architecture-specific pointers
 	 * Set up various architecture-specific pointers
 	 */
 	 */
+	arch_nr_irqs = mdesc->nr_irqs;
 	init_arch_irq = mdesc->init_irq;
 	init_arch_irq = mdesc->init_irq;
 	system_timer = mdesc->timer;
 	system_timer = mdesc->timer;
 	init_machine = mdesc->init_machine;
 	init_machine = mdesc->init_machine;