| 1 | From a729672f117df3602b6d3171d8ab7a84bf53b053 Mon Sep 17 00:00:00 2001 |
| 2 | From: Daniel Hellstrom <daniel@gaisler.com> |
| 3 | Date: Thu, 16 Sep 2010 11:12:41 +0200 |
| 4 | Subject: [PATCH] SPARC/LEON: added support for Extended IRQ controller, partial patches are already in git tree. |
| 5 | |
| 6 | Signed-off-by: Daniel Hellstrom <daniel@gaisler.com> |
| 7 | --- |
| 8 | arch/sparc/include/asm/irq_32.h | 4 ++++ |
| 9 | arch/sparc/kernel/irq_32.c | 32 ++++++++++++++++++++++++++------ |
| 10 | arch/sparc/kernel/leon_kernel.c | 8 +++++++- |
| 11 | 3 files changed, 37 insertions(+), 7 deletions(-) |
| 12 | |
| 13 | --- a/arch/sparc/include/asm/irq_32.h |
| 14 | +++ b/arch/sparc/include/asm/irq_32.h |
| 15 | @@ -6,7 +6,11 @@ |
| 16 | #ifndef _SPARC_IRQ_H |
| 17 | #define _SPARC_IRQ_H |
| 18 | |
| 19 | +#ifdef CONFIG_SPARC_LEON |
| 20 | +#define NR_IRQS 32 |
| 21 | +#else |
| 22 | #define NR_IRQS 16 |
| 23 | +#endif |
| 24 | |
| 25 | #include <linux/interrupt.h> |
| 26 | |
| 27 | --- a/arch/sparc/kernel/irq_32.c |
| 28 | +++ b/arch/sparc/kernel/irq_32.c |
| 29 | @@ -110,6 +110,11 @@ EXPORT_SYMBOL(__raw_local_irq_save); |
| 30 | EXPORT_SYMBOL(raw_local_irq_enable); |
| 31 | EXPORT_SYMBOL(raw_local_irq_restore); |
| 32 | |
| 33 | +#ifdef CONFIG_SPARC_LEON |
| 34 | +extern unsigned int sparc_leon_eirq; |
| 35 | +extern int sparc_leon_eirq_get(int eirq, int cpu); |
| 36 | +#endif |
| 37 | + |
| 38 | /* |
| 39 | * Dave Redman (djhr@tadpole.co.uk) |
| 40 | * |
| 41 | @@ -222,10 +227,11 @@ void free_irq(unsigned int irq, void *de |
| 42 | return; |
| 43 | } |
| 44 | cpu_irq = irq & (NR_IRQS - 1); |
| 45 | - if (cpu_irq > 14) { /* 14 irq levels on the sparc */ |
| 46 | - printk("Trying to free bogus IRQ %d\n", irq); |
| 47 | - return; |
| 48 | - } |
| 49 | + /* 14 irq levels on the sparc, however some LEON systems have 31 IRQs */ |
| 50 | + if ((cpu_irq == 15) || (cpu_irq >= NR_IRQS)) { |
| 51 | + printk("Trying to free bogus IRQ %d\n", irq); |
| 52 | + return; |
| 53 | + } |
| 54 | |
| 55 | spin_lock_irqsave(&irq_action_lock, flags); |
| 56 | |
| 57 | @@ -303,7 +309,14 @@ void unexpected_irq(int irq, void *dev_i |
| 58 | int i; |
| 59 | struct irqaction * action; |
| 60 | unsigned int cpu_irq; |
| 61 | - |
| 62 | + |
| 63 | +#ifdef CONFIG_SPARC_LEON |
| 64 | + /* LEON Extended IRQ requires one extra IRQ Number fetch stage */ |
| 65 | + if ( sparc_leon_eirq == irq ) { |
| 66 | + irq = sparc_leon_eirq_get(irq, smp_processor_id()); |
| 67 | + } |
| 68 | +#endif |
| 69 | + |
| 70 | cpu_irq = irq & (NR_IRQS - 1); |
| 71 | action = sparc_irq[cpu_irq].action; |
| 72 | |
| 73 | @@ -330,6 +343,13 @@ void handler_irq(int irq, struct pt_regs |
| 74 | extern void smp4m_irq_rotate(int cpu); |
| 75 | #endif |
| 76 | |
| 77 | +#ifdef CONFIG_SPARC_LEON |
| 78 | + /* LEON Extended IRQ requires one extra IRQ Number fetch stage */ |
| 79 | + if ( sparc_leon_eirq == irq ) { |
| 80 | + irq = sparc_leon_eirq_get(irq, cpu); |
| 81 | + } |
| 82 | +#endif |
| 83 | + |
| 84 | old_regs = set_irq_regs(regs); |
| 85 | irq_enter(); |
| 86 | disable_pil_irq(irq); |
| 87 | @@ -526,7 +546,7 @@ int request_irq(unsigned int irq, |
| 88 | return sun4d_request_irq(irq, handler, irqflags, devname, dev_id); |
| 89 | } |
| 90 | cpu_irq = irq & (NR_IRQS - 1); |
| 91 | - if(cpu_irq > 14) { |
| 92 | + if(cpu_irq == 15) { |
| 93 | ret = -EINVAL; |
| 94 | goto out; |
| 95 | } |
| 96 | --- a/arch/sparc/kernel/leon_kernel.c |
| 97 | +++ b/arch/sparc/kernel/leon_kernel.c |
| 98 | @@ -104,7 +104,7 @@ static void leon_disable_irq(unsigned in |
| 99 | |
| 100 | void __init leon_init_timers(irq_handler_t counter_fn) |
| 101 | { |
| 102 | - int irq; |
| 103 | + int irq, eirq; |
| 104 | struct device_node *rootnp, *np; |
| 105 | struct property *pp; |
| 106 | int len; |
| 107 | @@ -153,6 +153,12 @@ void __init leon_init_timers(irq_handler |
| 108 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0); |
| 109 | # endif |
| 110 | |
| 111 | + LEON3_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mask[0]), 0); |
| 112 | + eirq = (LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->mpstatus) >> 16) & 0xf; |
| 113 | + if ( eirq != 0 ) { |
| 114 | + /* Extended IRQ controller available */ |
| 115 | + sparc_leon_eirq_register(eirq); |
| 116 | + } |
| 117 | } else { |
| 118 | printk(KERN_ERR "No Timer/irqctrl found\n"); |
| 119 | BUG(); |
| 120 | |