| 1 | From 25a68b8cd8ea1553f8b56278418d6c1ecc12e247 Mon Sep 17 00:00:00 2001 |
| 2 | From: Daniel Hellstrom <daniel@gaisler.com> |
| 3 | Date: Wed, 22 Sep 2010 10:19:34 +0200 |
| 4 | Subject: [PATCH] SPARC/LEON: added support for AMP systems with IRQAMP IRQ Controller. |
| 5 | |
| 6 | Signed-off-by: Daniel Hellstrom <daniel@gaisler.com> |
| 7 | --- |
| 8 | arch/sparc/include/asm/leon.h | 12 ++++++++++++ |
| 9 | arch/sparc/include/asm/leon_amba.h | 6 +++--- |
| 10 | arch/sparc/kernel/leon_kernel.c | 14 ++++++++++++++ |
| 11 | 3 files changed, 29 insertions(+), 3 deletions(-) |
| 12 | |
| 13 | --- a/arch/sparc/include/asm/leon.h |
| 14 | +++ b/arch/sparc/include/asm/leon.h |
| 15 | @@ -224,6 +224,18 @@ static inline void sparc_leon3_disable_c |
| 16 | "sta %%l2, [%%g0] 2\n\t" : : : "l1", "l2"); |
| 17 | }; |
| 18 | |
| 19 | +static inline unsigned long sparc_leon3_asr17(void) |
| 20 | +{ |
| 21 | + u32 asr17; |
| 22 | + __asm__ __volatile__ ("rd %%asr17, %0\n\t" : "=r"(asr17)); |
| 23 | + return asr17; |
| 24 | +}; |
| 25 | + |
| 26 | +static inline int sparc_leon3_cpuid(void) |
| 27 | +{ |
| 28 | + return sparc_leon3_asr17() >> 28; |
| 29 | +} |
| 30 | + |
| 31 | #endif /*!__ASSEMBLY__*/ |
| 32 | |
| 33 | #ifdef CONFIG_SMP |
| 34 | --- a/arch/sparc/include/asm/leon_amba.h |
| 35 | +++ b/arch/sparc/include/asm/leon_amba.h |
| 36 | @@ -100,9 +100,8 @@ struct leon3_irqctrl_regs_map { |
| 37 | u32 mpbroadcast; |
| 38 | u32 notused02; |
| 39 | u32 notused03; |
| 40 | - u32 notused10; |
| 41 | - u32 notused11; |
| 42 | - u32 notused12; |
| 43 | + u32 ampctrl; |
| 44 | + u32 icsel[2]; |
| 45 | u32 notused13; |
| 46 | u32 notused20; |
| 47 | u32 notused21; |
| 48 | @@ -112,6 +111,7 @@ struct leon3_irqctrl_regs_map { |
| 49 | u32 force[16]; |
| 50 | /* Extended IRQ registers */ |
| 51 | u32 intid[16]; /* 0xc0 */ |
| 52 | + u32 unused[(0x1000-0x100)/4]; |
| 53 | }; |
| 54 | |
| 55 | struct leon3_apbuart_regs_map { |
| 56 | --- a/arch/sparc/kernel/leon_kernel.c |
| 57 | +++ b/arch/sparc/kernel/leon_kernel.c |
| 58 | @@ -108,6 +108,7 @@ void __init leon_init_timers(irq_handler |
| 59 | struct device_node *rootnp, *np; |
| 60 | struct property *pp; |
| 61 | int len; |
| 62 | + int cpu, icsel; |
| 63 | |
| 64 | leondebug_irq_disable = 0; |
| 65 | leon_debug_irqout = 0; |
| 66 | @@ -153,6 +154,19 @@ void __init leon_init_timers(irq_handler |
| 67 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0); |
| 68 | # endif |
| 69 | |
| 70 | + /* The IRQ controller may (if implemented) consist of multiple |
| 71 | + * IRQ controllers, each mapped on a 4Kb boundary. |
| 72 | + * Each CPU may be routed to different IRQCTRLs, however |
| 73 | + * we assume that all CPUs (in SMP system) is routed to the |
| 74 | + * same IRQ Controller, and for non-SMP only one IRQCTRL is |
| 75 | + * accessed anyway. |
| 76 | + * In AMP systems, Linux may not be run on CPU0. |
| 77 | + */ |
| 78 | + cpu = sparc_leon3_cpuid(); |
| 79 | + icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[cpu/8]); |
| 80 | + icsel = (icsel >> ((7 - (cpu&0x7)) * 4)) & 0xf; |
| 81 | + leon3_irqctrl_regs += icsel; |
| 82 | + |
| 83 | LEON3_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mask[0]), 0); |
| 84 | eirq = (LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->mpstatus) >> 16) & 0xf; |
| 85 | if ( eirq != 0 ) { |
| 86 | |