| 1 | From 300f3ee36c3019ee36f81befd91cd1b32544cefe Mon Sep 17 00:00:00 2001 |
| 2 | From: Daniel Hellstrom <daniel@gaisler.com> |
| 3 | Date: Wed, 22 Sep 2010 15:39:05 +0200 |
| 4 | Subject: [PATCH] SPARC/LEON: Removed the need for two timers, per-cpu ticker is shared with system clock timer. |
| 5 | |
| 6 | Signed-off-by: Daniel Hellstrom <daniel@gaisler.com> |
| 7 | --- |
| 8 | arch/sparc/include/asm/leon.h | 2 +- |
| 9 | arch/sparc/include/asm/leon_amba.h | 3 +- |
| 10 | arch/sparc/kernel/entry.S | 3 +- |
| 11 | arch/sparc/kernel/leon_kernel.c | 37 ++++++++--------------------------- |
| 12 | arch/sparc/kernel/leon_smp.c | 8 ++++++- |
| 13 | 5 files changed, 21 insertions(+), 32 deletions(-) |
| 14 | |
| 15 | --- a/arch/sparc/include/asm/leon.h |
| 16 | +++ b/arch/sparc/include/asm/leon.h |
| 17 | @@ -240,7 +240,7 @@ static inline int sparc_leon3_cpuid(void |
| 18 | |
| 19 | #ifdef CONFIG_SMP |
| 20 | # define LEON3_IRQ_RESCHEDULE 13 |
| 21 | -# define LEON3_IRQ_TICKER (leon_percpu_timer_dev[0].irq) |
| 22 | +# define LEON3_IRQ_TICKER (leon3_gptimer_irq + leon3_gptimer_idx) |
| 23 | # define LEON3_IRQ_CROSS_CALL 15 |
| 24 | #endif |
| 25 | |
| 26 | --- a/arch/sparc/include/asm/leon_amba.h |
| 27 | +++ b/arch/sparc/include/asm/leon_amba.h |
| 28 | @@ -182,11 +182,12 @@ void _amba_init(struct device_node *dp, |
| 29 | |
| 30 | extern struct leon3_irqctrl_regs_map *leon3_irqctrl_regs; |
| 31 | extern struct leon3_gptimer_regs_map *leon3_gptimer_regs; |
| 32 | -extern struct amba_apb_device leon_percpu_timer_dev[16]; |
| 33 | extern int leondebug_irq_disable; |
| 34 | extern int leon_debug_irqout; |
| 35 | extern unsigned long leon3_gptimer_irq; |
| 36 | +extern unsigned long leon3_gptimer_idx; /* Timer Index (starting at 0) with Timer Core */ |
| 37 | extern unsigned int sparc_leon_eirq; |
| 38 | +extern unsigned long leon3_cpu_idx; |
| 39 | |
| 40 | #endif /* __ASSEMBLY__ */ |
| 41 | |
| 42 | --- a/arch/sparc/kernel/entry.S |
| 43 | +++ b/arch/sparc/kernel/entry.S |
| 44 | @@ -411,8 +411,9 @@ smpleon_ticker: |
| 45 | WRITE_PAUSE |
| 46 | wr %g2, PSR_ET, %psr |
| 47 | WRITE_PAUSE |
| 48 | + mov %l7, %o0 ! irq level |
| 49 | call leon_percpu_timer_interrupt |
| 50 | - add %sp, STACKFRAME_SZ, %o0 |
| 51 | + add %sp, STACKFRAME_SZ, %o1 ! pt_regs |
| 52 | wr %l0, PSR_ET, %psr |
| 53 | WRITE_PAUSE |
| 54 | RESTORE_ALL |
| 55 | --- a/arch/sparc/kernel/leon_kernel.c |
| 56 | +++ b/arch/sparc/kernel/leon_kernel.c |
| 57 | @@ -25,7 +25,6 @@ |
| 58 | |
| 59 | struct leon3_irqctrl_regs_map *leon3_irqctrl_regs = NULL; /* interrupt controller base address, initialized by amba_init() */ |
| 60 | struct leon3_gptimer_regs_map *leon3_gptimer_regs = NULL; /* timer controller base address, initialized by amba_init() */ |
| 61 | -struct amba_apb_device leon_percpu_timer_dev[16]; |
| 62 | |
| 63 | int leondebug_irq_disable; |
| 64 | int leon_debug_irqout; |
| 65 | @@ -34,6 +33,7 @@ static int dummy_master_l10_counter; |
| 66 | unsigned long leon3_gptimer_irq = 0; /* interrupt controller irq number, initialized by amba_init() */ |
| 67 | unsigned long leon3_gptimer_idx = 0; /* Timer Index (starting at 0) with Timer Core */ |
| 68 | unsigned int sparc_leon_eirq; |
| 69 | +unsigned long leon3_cpu_idx = 0; /* Boot CPU Index */ |
| 70 | #define LEON_IMASK ((&leon3_irqctrl_regs->mask[0])) |
| 71 | |
| 72 | /* Return the IRQ of the pending IRQ on the extended IRQ controller */ |
| 73 | @@ -109,13 +109,14 @@ void __init leon_init_timers(irq_handler |
| 74 | struct device_node *rootnp, *np; |
| 75 | struct property *pp; |
| 76 | int len; |
| 77 | - int cpu, icsel; |
| 78 | + int icsel; |
| 79 | int ampopts; |
| 80 | |
| 81 | leondebug_irq_disable = 0; |
| 82 | leon_debug_irqout = 0; |
| 83 | master_l10_counter = (unsigned int *)&dummy_master_l10_counter; |
| 84 | dummy_master_l10_counter = 0; |
| 85 | + leon3_cpu_idx = sparc_leon3_cpuid(); |
| 86 | |
| 87 | /* Find IRQMP IRQ Controller Registers base address otherwise bail out. */ |
| 88 | rootnp = of_find_node_by_path("/ambapp0"); |
| 89 | @@ -152,21 +153,11 @@ void __init leon_init_timers(irq_handler |
| 90 | (((1000000 / HZ) - 1))); |
| 91 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0); |
| 92 | |
| 93 | -#ifdef CONFIG_SMP |
| 94 | - leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs; |
| 95 | - leon_percpu_timer_dev[0].irq = leon3_gptimer_irq+1+leon3_gptimer_idx; |
| 96 | - |
| 97 | if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) & |
| 98 | (1<<LEON3_GPTIMER_SEPIRQ))) { |
| 99 | - prom_printf("irq timer not configured with separate irqs\n"); |
| 100 | - BUG(); |
| 101 | + prom_printf("LEON-SMP: GPTIMER use shared irqs, using other timers will fail.\n"); |
| 102 | } |
| 103 | |
| 104 | - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].val, 0); |
| 105 | - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld, (((1000000 / HZ) - 1))); |
| 106 | - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, 0); |
| 107 | -# endif |
| 108 | - |
| 109 | /* The IRQ controller may (if implemented) consist of multiple |
| 110 | * IRQ controllers, each mapped on a 4Kb boundary. |
| 111 | * Each CPU may be routed to different IRQCTRLs, however |
| 112 | @@ -175,9 +166,8 @@ void __init leon_init_timers(irq_handler |
| 113 | * accessed anyway. |
| 114 | * In AMP systems, Linux may not be run on CPU0. |
| 115 | */ |
| 116 | - cpu = sparc_leon3_cpuid(); |
| 117 | - icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[cpu/8]); |
| 118 | - icsel = (icsel >> ((7 - (cpu&0x7)) * 4)) & 0xf; |
| 119 | + icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[leon3_cpu_idx/8]); |
| 120 | + icsel = (icsel >> ((7 - (leon3_cpu_idx & 0x7)) * 4)) & 0xf; |
| 121 | leon3_irqctrl_regs += icsel; |
| 122 | |
| 123 | LEON3_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mask[0]), 0); |
| 124 | @@ -204,7 +194,8 @@ void __init leon_init_timers(irq_handler |
| 125 | # ifdef CONFIG_SMP |
| 126 | { |
| 127 | unsigned long flags; |
| 128 | - struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_percpu_timer_dev[0].irq - 1)]; |
| 129 | + struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + |
| 130 | + (leon3_gptimer_irq + leon3_gptimer_idx - 1)]; |
| 131 | |
| 132 | /* For SMP we use the level 14 ticker, however the bootup code |
| 133 | * has copied the firmwares level 14 vector into boot cpu's |
| 134 | @@ -222,21 +213,11 @@ void __init leon_init_timers(irq_handler |
| 135 | } |
| 136 | # endif |
| 137 | |
| 138 | - if (leon3_gptimer_regs) { |
| 139 | - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, |
| 140 | + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, |
| 141 | LEON3_GPTIMER_EN | |
| 142 | LEON3_GPTIMER_RL | |
| 143 | LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); |
| 144 | |
| 145 | -#ifdef CONFIG_SMP |
| 146 | - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, |
| 147 | - LEON3_GPTIMER_EN | |
| 148 | - LEON3_GPTIMER_RL | |
| 149 | - LEON3_GPTIMER_LD | |
| 150 | - LEON3_GPTIMER_IRQEN); |
| 151 | -#endif |
| 152 | - |
| 153 | - } |
| 154 | } |
| 155 | |
| 156 | void leon_clear_clock_irq(void) |
| 157 | --- a/arch/sparc/kernel/leon_smp.c |
| 158 | +++ b/arch/sparc/kernel/leon_smp.c |
| 159 | @@ -52,6 +52,7 @@ extern volatile unsigned long cpu_callin |
| 160 | extern unsigned char boot_cpu_id; |
| 161 | extern cpumask_t smp_commenced_mask; |
| 162 | void __init leon_configure_cache_smp(void); |
| 163 | +extern void handler_irq(int irq, struct pt_regs * regs); |
| 164 | |
| 165 | static inline unsigned long do_swap(volatile unsigned long *ptr, |
| 166 | unsigned long val) |
| 167 | @@ -385,7 +386,7 @@ void leon_cross_call_irq(void) |
| 168 | ccall_info.processors_out[i] = 1; |
| 169 | } |
| 170 | |
| 171 | -void leon_percpu_timer_interrupt(struct pt_regs *regs) |
| 172 | +void leon_percpu_timer_interrupt(int irq, struct pt_regs *regs) |
| 173 | { |
| 174 | struct pt_regs *old_regs; |
| 175 | int cpu = smp_processor_id(); |
| 176 | @@ -406,6 +407,11 @@ void leon_percpu_timer_interrupt(struct |
| 177 | prof_counter(cpu) = prof_multiplier(cpu); |
| 178 | } |
| 179 | set_irq_regs(old_regs); |
| 180 | + |
| 181 | + if ( cpu == leon3_cpu_idx ) { |
| 182 | + /* Ticker Clock is shared with the System Clock */ |
| 183 | + handler_irq(irq, regs); |
| 184 | + } |
| 185 | } |
| 186 | |
| 187 | static void __init smp_setup_percpu_timer(void) |
| 188 | |