diff options
Diffstat (limited to 'arch/sparc/kernel/leon_kernel.c')
-rw-r--r-- | arch/sparc/kernel/leon_kernel.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 54d8a5bd4824..87f1760c0aa2 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c | |||
@@ -12,11 +12,14 @@ | |||
12 | #include <linux/of_platform.h> | 12 | #include <linux/of_platform.h> |
13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
14 | #include <linux/of_device.h> | 14 | #include <linux/of_device.h> |
15 | |||
15 | #include <asm/oplib.h> | 16 | #include <asm/oplib.h> |
16 | #include <asm/timer.h> | 17 | #include <asm/timer.h> |
17 | #include <asm/prom.h> | 18 | #include <asm/prom.h> |
18 | #include <asm/leon.h> | 19 | #include <asm/leon.h> |
19 | #include <asm/leon_amba.h> | 20 | #include <asm/leon_amba.h> |
21 | #include <asm/traps.h> | ||
22 | #include <asm/cacheflush.h> | ||
20 | 23 | ||
21 | #include "prom.h" | 24 | #include "prom.h" |
22 | #include "irq.h" | 25 | #include "irq.h" |
@@ -115,6 +118,21 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
115 | (((1000000 / 100) - 1))); | 118 | (((1000000 / 100) - 1))); |
116 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0); | 119 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0); |
117 | 120 | ||
121 | #ifdef CONFIG_SMP | ||
122 | leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs; | ||
123 | leon_percpu_timer_dev[0].irq = leon3_gptimer_irq+1; | ||
124 | |||
125 | if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) & | ||
126 | (1<<LEON3_GPTIMER_SEPIRQ))) { | ||
127 | prom_printf("irq timer not configured with seperate irqs \n"); | ||
128 | BUG(); | ||
129 | } | ||
130 | |||
131 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].val, 0); | ||
132 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/100) - 1))); | ||
133 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0); | ||
134 | # endif | ||
135 | |||
118 | } else { | 136 | } else { |
119 | printk(KERN_ERR "No Timer/irqctrl found\n"); | 137 | printk(KERN_ERR "No Timer/irqctrl found\n"); |
120 | BUG(); | 138 | BUG(); |
@@ -130,11 +148,41 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
130 | prom_halt(); | 148 | prom_halt(); |
131 | } | 149 | } |
132 | 150 | ||
151 | # ifdef CONFIG_SMP | ||
152 | { | ||
153 | unsigned long flags; | ||
154 | struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_percpu_timer_dev[0].irq - 1)]; | ||
155 | |||
156 | /* For SMP we use the level 14 ticker, however the bootup code | ||
157 | * has copied the firmwares level 14 vector into boot cpu's | ||
158 | * trap table, we must fix this now or we get squashed. | ||
159 | */ | ||
160 | local_irq_save(flags); | ||
161 | |||
162 | patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */ | ||
163 | |||
164 | /* Adjust so that we jump directly to smpleon_ticker */ | ||
165 | trap_table->inst_three += smpleon_ticker - real_irq_entry; | ||
166 | |||
167 | local_flush_cache_all(); | ||
168 | local_irq_restore(flags); | ||
169 | } | ||
170 | # endif | ||
171 | |||
133 | if (leon3_gptimer_regs) { | 172 | if (leon3_gptimer_regs) { |
134 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, | 173 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, |
135 | LEON3_GPTIMER_EN | | 174 | LEON3_GPTIMER_EN | |
136 | LEON3_GPTIMER_RL | | 175 | LEON3_GPTIMER_RL | |
137 | LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); | 176 | LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); |
177 | |||
178 | #ifdef CONFIG_SMP | ||
179 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, | ||
180 | LEON3_GPTIMER_EN | | ||
181 | LEON3_GPTIMER_RL | | ||
182 | LEON3_GPTIMER_LD | | ||
183 | LEON3_GPTIMER_IRQEN); | ||
184 | #endif | ||
185 | |||
138 | } | 186 | } |
139 | } | 187 | } |
140 | 188 | ||
@@ -175,6 +223,42 @@ void __init leon_node_init(struct device_node *dp, struct device_node ***nextp) | |||
175 | } | 223 | } |
176 | } | 224 | } |
177 | 225 | ||
226 | #ifdef CONFIG_SMP | ||
227 | |||
228 | void leon_set_cpu_int(int cpu, int level) | ||
229 | { | ||
230 | unsigned long mask; | ||
231 | mask = get_irqmask(level); | ||
232 | LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask); | ||
233 | } | ||
234 | |||
235 | static void leon_clear_ipi(int cpu, int level) | ||
236 | { | ||
237 | unsigned long mask; | ||
238 | mask = get_irqmask(level); | ||
239 | LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask<<16); | ||
240 | } | ||
241 | |||
242 | static void leon_set_udt(int cpu) | ||
243 | { | ||
244 | } | ||
245 | |||
246 | void leon_clear_profile_irq(int cpu) | ||
247 | { | ||
248 | } | ||
249 | |||
250 | void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu) | ||
251 | { | ||
252 | unsigned long mask, flags, *addr; | ||
253 | mask = get_irqmask(irq_nr); | ||
254 | local_irq_save(flags); | ||
255 | addr = (unsigned long *)&(leon3_irqctrl_regs->mask[cpu]); | ||
256 | LEON3_BYPASS_STORE_PA(addr, (LEON3_BYPASS_LOAD_PA(addr) | (mask))); | ||
257 | local_irq_restore(flags); | ||
258 | } | ||
259 | |||
260 | #endif | ||
261 | |||
178 | void __init leon_init_IRQ(void) | 262 | void __init leon_init_IRQ(void) |
179 | { | 263 | { |
180 | sparc_init_timers = leon_init_timers; | 264 | sparc_init_timers = leon_init_timers; |