diff options
Diffstat (limited to 'target/linux/leon/patches/004-extended_irq_controller.patch')
-rw-r--r-- | target/linux/leon/patches/004-extended_irq_controller.patch | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/target/linux/leon/patches/004-extended_irq_controller.patch b/target/linux/leon/patches/004-extended_irq_controller.patch new file mode 100644 index 0000000..b660b64 --- /dev/null +++ b/target/linux/leon/patches/004-extended_irq_controller.patch @@ -0,0 +1,119 @@ +From a729672f117df3602b6d3171d8ab7a84bf53b053 Mon Sep 17 00:00:00 2001 +From: Daniel Hellstrom <daniel@gaisler.com> +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 <daniel@gaisler.com> +--- + 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 <linux/interrupt.h> + +--- 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(); |