[leon] move patches to patches-2.6.36
[openwrt/svn-archive/archive.git] / target / linux / leon / patches-2.6.36 / 004-extended_irq_controller.patch
diff --git a/target/linux/leon/patches-2.6.36/004-extended_irq_controller.patch b/target/linux/leon/patches-2.6.36/004-extended_irq_controller.patch
new file mode 100644 (file)
index 0000000..b660b64
--- /dev/null
@@ -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();