From a729672f117df3602b6d3171d8ab7a84bf53b053 Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Thu, 16 Sep 2010 11:12:41 +0200 Subject: [PATCH] SPARC/LEON: added support for Extended IRQ controller, partial patches are already in git tree. Signed-off-by: Daniel Hellstrom --- arch/sparc/include/asm/irq_32.h | 4 ++++ arch/sparc/kernel/irq_32.c | 32 ++++++++++++++++++++++++++------ arch/sparc/kernel/leon_kernel.c | 8 +++++++- 3 files changed, 37 insertions(+), 7 deletions(-) --- a/arch/sparc/include/asm/irq_32.h +++ b/arch/sparc/include/asm/irq_32.h @@ -6,7 +6,11 @@ #ifndef _SPARC_IRQ_H #define _SPARC_IRQ_H +#ifdef CONFIG_SPARC_LEON +#define NR_IRQS 32 +#else #define NR_IRQS 16 +#endif #include --- a/arch/sparc/kernel/irq_32.c +++ b/arch/sparc/kernel/irq_32.c @@ -110,6 +110,11 @@ EXPORT_SYMBOL(__raw_local_irq_save); EXPORT_SYMBOL(raw_local_irq_enable); EXPORT_SYMBOL(raw_local_irq_restore); +#ifdef CONFIG_SPARC_LEON +extern unsigned int sparc_leon_eirq; +extern int sparc_leon_eirq_get(int eirq, int cpu); +#endif + /* * Dave Redman (djhr@tadpole.co.uk) * @@ -222,10 +227,11 @@ void free_irq(unsigned int irq, void *de return; } cpu_irq = irq & (NR_IRQS - 1); - if (cpu_irq > 14) { /* 14 irq levels on the sparc */ - printk("Trying to free bogus IRQ %d\n", irq); - return; - } + /* 14 irq levels on the sparc, however some LEON systems have 31 IRQs */ + if ((cpu_irq == 15) || (cpu_irq >= NR_IRQS)) { + printk("Trying to free bogus IRQ %d\n", irq); + return; + } spin_lock_irqsave(&irq_action_lock, flags); @@ -303,7 +309,14 @@ void unexpected_irq(int irq, void *dev_i int i; struct irqaction * action; unsigned int cpu_irq; - + +#ifdef CONFIG_SPARC_LEON + /* LEON Extended IRQ requires one extra IRQ Number fetch stage */ + if ( sparc_leon_eirq == irq ) { + irq = sparc_leon_eirq_get(irq, smp_processor_id()); + } +#endif + cpu_irq = irq & (NR_IRQS - 1); action = sparc_irq[cpu_irq].action; @@ -330,6 +343,13 @@ void handler_irq(int irq, struct pt_regs extern void smp4m_irq_rotate(int cpu); #endif +#ifdef CONFIG_SPARC_LEON + /* LEON Extended IRQ requires one extra IRQ Number fetch stage */ + if ( sparc_leon_eirq == irq ) { + irq = sparc_leon_eirq_get(irq, cpu); + } +#endif + old_regs = set_irq_regs(regs); irq_enter(); disable_pil_irq(irq); @@ -526,7 +546,7 @@ int request_irq(unsigned int irq, return sun4d_request_irq(irq, handler, irqflags, devname, dev_id); } cpu_irq = irq & (NR_IRQS - 1); - if(cpu_irq > 14) { + if(cpu_irq == 15) { ret = -EINVAL; goto out; } --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -104,7 +104,7 @@ static void leon_disable_irq(unsigned in void __init leon_init_timers(irq_handler_t counter_fn) { - int irq; + int irq, eirq; struct device_node *rootnp, *np; struct property *pp; int len; @@ -153,6 +153,12 @@ void __init leon_init_timers(irq_handler LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0); # endif + LEON3_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mask[0]), 0); + eirq = (LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->mpstatus) >> 16) & 0xf; + if ( eirq != 0 ) { + /* Extended IRQ controller available */ + sparc_leon_eirq_register(eirq); + } } else { printk(KERN_ERR "No Timer/irqctrl found\n"); BUG();