Subject: [RFC PATCH v2] preliminary support for sparse IRQ

From: [email-masked] (Marek Vasut)
Date: Tue, 18 May 2010 23:45:07 +0200

Dne ?t 18. kv?tna 2010 12:34:49 Eric Miao napsal(a):
> commit 2e2e087d96630c95dbce57036680cf917e906cf1
> Author: Eric Miao <[email-masked]>
> Date:   Mon Dec 28 12:59:59 2009 +0800
> 
>     [ARM] preliminary support for sparse IRQ
> 
>     So to allow NR_IRQS to be dynamic and platforms to specify the number
>     of IRQs really needed.
> 
>     Signed-off-by: Eric Miao <[email-masked]>
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index c5408bf..727703c 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1282,6 +1282,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 237282f..2721a58 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 c59842d..5ee6f85 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 8920b2d..ce3eee9 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 3b3d2c8..c0d5c3b 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;

Possibly stupid question, but shouldn't you asign 'desc' after locking ?

>  		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 c91c77b..112cd1b 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -727,6 +727,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;
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel