diff options
Diffstat (limited to 'arch/sparc/kernel/sun4d_smp.c')
-rw-r--r-- | arch/sparc/kernel/sun4d_smp.c | 176 |
1 files changed, 65 insertions, 111 deletions
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 482f2ab92692..475d50b96cd0 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* sun4d_smp.c: Sparc SS1000/SC2000 SMP support. | 1 | /* Sparc SS1000/SC2000 SMP support. |
2 | * | 2 | * |
3 | * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | 3 | * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) |
4 | * | 4 | * |
@@ -6,59 +6,23 @@ | |||
6 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) | 6 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <asm/head.h> | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/threads.h> | ||
14 | #include <linux/smp.h> | ||
15 | #include <linux/interrupt.h> | 9 | #include <linux/interrupt.h> |
16 | #include <linux/kernel_stat.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/mm.h> | ||
20 | #include <linux/swap.h> | ||
21 | #include <linux/profile.h> | 10 | #include <linux/profile.h> |
22 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
23 | #include <linux/cpu.h> | 12 | #include <linux/cpu.h> |
24 | 13 | ||
25 | #include <asm/ptrace.h> | ||
26 | #include <asm/atomic.h> | ||
27 | #include <asm/irq_regs.h> | ||
28 | |||
29 | #include <asm/irq.h> | ||
30 | #include <asm/page.h> | ||
31 | #include <asm/pgalloc.h> | ||
32 | #include <asm/pgtable.h> | ||
33 | #include <asm/oplib.h> | ||
34 | #include <asm/sbi.h> | 14 | #include <asm/sbi.h> |
15 | #include <asm/mmu.h> | ||
35 | #include <asm/tlbflush.h> | 16 | #include <asm/tlbflush.h> |
36 | #include <asm/cacheflush.h> | 17 | #include <asm/cacheflush.h> |
37 | #include <asm/cpudata.h> | ||
38 | 18 | ||
19 | #include "kernel.h" | ||
39 | #include "irq.h" | 20 | #include "irq.h" |
40 | #define IRQ_CROSS_CALL 15 | ||
41 | 21 | ||
42 | extern ctxd_t *srmmu_ctx_table_phys; | 22 | #define IRQ_CROSS_CALL 15 |
43 | 23 | ||
44 | static volatile int smp_processors_ready = 0; | 24 | static volatile int smp_processors_ready; |
45 | static int smp_highest_cpu; | 25 | static int smp_highest_cpu; |
46 | extern volatile unsigned long cpu_callin_map[NR_CPUS]; | ||
47 | extern cpuinfo_sparc cpu_data[NR_CPUS]; | ||
48 | extern unsigned char boot_cpu_id; | ||
49 | extern volatile int smp_process_available; | ||
50 | |||
51 | extern cpumask_t smp_commenced_mask; | ||
52 | |||
53 | extern int __smp4d_processor_id(void); | ||
54 | |||
55 | /* #define SMP_DEBUG */ | ||
56 | |||
57 | #ifdef SMP_DEBUG | ||
58 | #define SMP_PRINTK(x) printk x | ||
59 | #else | ||
60 | #define SMP_PRINTK(x) | ||
61 | #endif | ||
62 | 26 | ||
63 | static inline unsigned long sun4d_swap(volatile unsigned long *ptr, unsigned long val) | 27 | static inline unsigned long sun4d_swap(volatile unsigned long *ptr, unsigned long val) |
64 | { | 28 | { |
@@ -69,8 +33,6 @@ static inline unsigned long sun4d_swap(volatile unsigned long *ptr, unsigned lon | |||
69 | } | 33 | } |
70 | 34 | ||
71 | static void smp_setup_percpu_timer(void); | 35 | static void smp_setup_percpu_timer(void); |
72 | extern void cpu_probe(void); | ||
73 | extern void sun4d_distribute_irqs(void); | ||
74 | 36 | ||
75 | static unsigned char cpu_leds[32]; | 37 | static unsigned char cpu_leds[32]; |
76 | 38 | ||
@@ -86,9 +48,8 @@ static inline void show_leds(int cpuid) | |||
86 | void __cpuinit smp4d_callin(void) | 48 | void __cpuinit smp4d_callin(void) |
87 | { | 49 | { |
88 | int cpuid = hard_smp4d_processor_id(); | 50 | int cpuid = hard_smp4d_processor_id(); |
89 | extern spinlock_t sun4d_imsk_lock; | ||
90 | unsigned long flags; | 51 | unsigned long flags; |
91 | 52 | ||
92 | /* Show we are alive */ | 53 | /* Show we are alive */ |
93 | cpu_leds[cpuid] = 0x6; | 54 | cpu_leds[cpuid] = 0x6; |
94 | show_leds(cpuid); | 55 | show_leds(cpuid); |
@@ -118,15 +79,15 @@ void __cpuinit smp4d_callin(void) | |||
118 | sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1); | 79 | sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1); |
119 | local_flush_cache_all(); | 80 | local_flush_cache_all(); |
120 | local_flush_tlb_all(); | 81 | local_flush_tlb_all(); |
121 | 82 | ||
122 | cpu_probe(); | 83 | cpu_probe(); |
123 | 84 | ||
124 | while((unsigned long)current_set[cpuid] < PAGE_OFFSET) | 85 | while ((unsigned long)current_set[cpuid] < PAGE_OFFSET) |
125 | barrier(); | 86 | barrier(); |
126 | 87 | ||
127 | while(current_set[cpuid]->cpu != cpuid) | 88 | while (current_set[cpuid]->cpu != cpuid) |
128 | barrier(); | 89 | barrier(); |
129 | 90 | ||
130 | /* Fix idle thread fields. */ | 91 | /* Fix idle thread fields. */ |
131 | __asm__ __volatile__("ld [%0], %%g6\n\t" | 92 | __asm__ __volatile__("ld [%0], %%g6\n\t" |
132 | : : "r" (¤t_set[cpuid]) | 93 | : : "r" (¤t_set[cpuid]) |
@@ -134,16 +95,16 @@ void __cpuinit smp4d_callin(void) | |||
134 | 95 | ||
135 | cpu_leds[cpuid] = 0x9; | 96 | cpu_leds[cpuid] = 0x9; |
136 | show_leds(cpuid); | 97 | show_leds(cpuid); |
137 | 98 | ||
138 | /* Attach to the address space of init_task. */ | 99 | /* Attach to the address space of init_task. */ |
139 | atomic_inc(&init_mm.mm_count); | 100 | atomic_inc(&init_mm.mm_count); |
140 | current->active_mm = &init_mm; | 101 | current->active_mm = &init_mm; |
141 | 102 | ||
142 | local_flush_cache_all(); | 103 | local_flush_cache_all(); |
143 | local_flush_tlb_all(); | 104 | local_flush_tlb_all(); |
144 | 105 | ||
145 | local_irq_enable(); /* We don't allow PIL 14 yet */ | 106 | local_irq_enable(); /* We don't allow PIL 14 yet */ |
146 | 107 | ||
147 | while (!cpu_isset(cpuid, smp_commenced_mask)) | 108 | while (!cpu_isset(cpuid, smp_commenced_mask)) |
148 | barrier(); | 109 | barrier(); |
149 | 110 | ||
@@ -154,15 +115,9 @@ void __cpuinit smp4d_callin(void) | |||
154 | 115 | ||
155 | } | 116 | } |
156 | 117 | ||
157 | extern void init_IRQ(void); | ||
158 | extern void cpu_panic(void); | ||
159 | |||
160 | /* | 118 | /* |
161 | * Cycle through the processors asking the PROM to start each one. | 119 | * Cycle through the processors asking the PROM to start each one. |
162 | */ | 120 | */ |
163 | |||
164 | extern struct linux_prom_registers smp_penguin_ctable; | ||
165 | |||
166 | void __init smp4d_boot_cpus(void) | 121 | void __init smp4d_boot_cpus(void) |
167 | { | 122 | { |
168 | if (boot_cpu_id) | 123 | if (boot_cpu_id) |
@@ -173,43 +128,42 @@ void __init smp4d_boot_cpus(void) | |||
173 | 128 | ||
174 | int __cpuinit smp4d_boot_one_cpu(int i) | 129 | int __cpuinit smp4d_boot_one_cpu(int i) |
175 | { | 130 | { |
176 | extern unsigned long sun4d_cpu_startup; | 131 | unsigned long *entry = &sun4d_cpu_startup; |
177 | unsigned long *entry = &sun4d_cpu_startup; | 132 | struct task_struct *p; |
178 | struct task_struct *p; | 133 | int timeout; |
179 | int timeout; | 134 | int cpu_node; |
180 | int cpu_node; | ||
181 | 135 | ||
182 | cpu_find_by_instance(i, &cpu_node,NULL); | 136 | cpu_find_by_instance(i, &cpu_node, NULL); |
183 | /* Cook up an idler for this guy. */ | 137 | /* Cook up an idler for this guy. */ |
184 | p = fork_idle(i); | 138 | p = fork_idle(i); |
185 | current_set[i] = task_thread_info(p); | 139 | current_set[i] = task_thread_info(p); |
140 | |||
141 | /* | ||
142 | * Initialize the contexts table | ||
143 | * Since the call to prom_startcpu() trashes the structure, | ||
144 | * we need to re-initialize it for each cpu | ||
145 | */ | ||
146 | smp_penguin_ctable.which_io = 0; | ||
147 | smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys; | ||
148 | smp_penguin_ctable.reg_size = 0; | ||
149 | |||
150 | /* whirrr, whirrr, whirrrrrrrrr... */ | ||
151 | printk(KERN_INFO "Starting CPU %d at %p\n", i, entry); | ||
152 | local_flush_cache_all(); | ||
153 | prom_startcpu(cpu_node, | ||
154 | &smp_penguin_ctable, 0, (char *)entry); | ||
155 | |||
156 | printk(KERN_INFO "prom_startcpu returned :)\n"); | ||
157 | |||
158 | /* wheee... it's going... */ | ||
159 | for (timeout = 0; timeout < 10000; timeout++) { | ||
160 | if (cpu_callin_map[i]) | ||
161 | break; | ||
162 | udelay(200); | ||
163 | } | ||
186 | 164 | ||
187 | /* | ||
188 | * Initialize the contexts table | ||
189 | * Since the call to prom_startcpu() trashes the structure, | ||
190 | * we need to re-initialize it for each cpu | ||
191 | */ | ||
192 | smp_penguin_ctable.which_io = 0; | ||
193 | smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys; | ||
194 | smp_penguin_ctable.reg_size = 0; | ||
195 | |||
196 | /* whirrr, whirrr, whirrrrrrrrr... */ | ||
197 | SMP_PRINTK(("Starting CPU %d at %p\n", i, entry)); | ||
198 | local_flush_cache_all(); | ||
199 | prom_startcpu(cpu_node, | ||
200 | &smp_penguin_ctable, 0, (char *)entry); | ||
201 | |||
202 | SMP_PRINTK(("prom_startcpu returned :)\n")); | ||
203 | |||
204 | /* wheee... it's going... */ | ||
205 | for(timeout = 0; timeout < 10000; timeout++) { | ||
206 | if(cpu_callin_map[i]) | ||
207 | break; | ||
208 | udelay(200); | ||
209 | } | ||
210 | |||
211 | if (!(cpu_callin_map[i])) { | 165 | if (!(cpu_callin_map[i])) { |
212 | printk("Processor %d is stuck.\n", i); | 166 | printk(KERN_ERR "Processor %d is stuck.\n", i); |
213 | return -ENODEV; | 167 | return -ENODEV; |
214 | 168 | ||
215 | } | 169 | } |
@@ -255,14 +209,17 @@ static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, | |||
255 | unsigned long arg2, unsigned long arg3, | 209 | unsigned long arg2, unsigned long arg3, |
256 | unsigned long arg4) | 210 | unsigned long arg4) |
257 | { | 211 | { |
258 | if(smp_processors_ready) { | 212 | if (smp_processors_ready) { |
259 | register int high = smp_highest_cpu; | 213 | register int high = smp_highest_cpu; |
260 | unsigned long flags; | 214 | unsigned long flags; |
261 | 215 | ||
262 | spin_lock_irqsave(&cross_call_lock, flags); | 216 | spin_lock_irqsave(&cross_call_lock, flags); |
263 | 217 | ||
264 | { | 218 | { |
265 | /* If you make changes here, make sure gcc generates proper code... */ | 219 | /* |
220 | * If you make changes here, make sure | ||
221 | * gcc generates proper code... | ||
222 | */ | ||
266 | register smpfunc_t f asm("i0") = func; | 223 | register smpfunc_t f asm("i0") = func; |
267 | register unsigned long a1 asm("i1") = arg1; | 224 | register unsigned long a1 asm("i1") = arg1; |
268 | register unsigned long a2 asm("i2") = arg2; | 225 | register unsigned long a2 asm("i2") = arg2; |
@@ -284,7 +241,7 @@ static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, | |||
284 | 241 | ||
285 | cpu_clear(smp_processor_id(), mask); | 242 | cpu_clear(smp_processor_id(), mask); |
286 | cpus_and(mask, cpu_online_map, mask); | 243 | cpus_and(mask, cpu_online_map, mask); |
287 | for(i = 0; i <= high; i++) { | 244 | for (i = 0; i <= high; i++) { |
288 | if (cpu_isset(i, mask)) { | 245 | if (cpu_isset(i, mask)) { |
289 | ccall_info.processors_in[i] = 0; | 246 | ccall_info.processors_in[i] = 0; |
290 | ccall_info.processors_out[i] = 0; | 247 | ccall_info.processors_out[i] = 0; |
@@ -300,17 +257,17 @@ static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, | |||
300 | do { | 257 | do { |
301 | if (!cpu_isset(i, mask)) | 258 | if (!cpu_isset(i, mask)) |
302 | continue; | 259 | continue; |
303 | while(!ccall_info.processors_in[i]) | 260 | while (!ccall_info.processors_in[i]) |
304 | barrier(); | 261 | barrier(); |
305 | } while(++i <= high); | 262 | } while (++i <= high); |
306 | 263 | ||
307 | i = 0; | 264 | i = 0; |
308 | do { | 265 | do { |
309 | if (!cpu_isset(i, mask)) | 266 | if (!cpu_isset(i, mask)) |
310 | continue; | 267 | continue; |
311 | while(!ccall_info.processors_out[i]) | 268 | while (!ccall_info.processors_out[i]) |
312 | barrier(); | 269 | barrier(); |
313 | } while(++i <= high); | 270 | } while (++i <= high); |
314 | } | 271 | } |
315 | 272 | ||
316 | spin_unlock_irqrestore(&cross_call_lock, flags); | 273 | spin_unlock_irqrestore(&cross_call_lock, flags); |
@@ -336,7 +293,7 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs) | |||
336 | static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd }; | 293 | static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd }; |
337 | 294 | ||
338 | old_regs = set_irq_regs(regs); | 295 | old_regs = set_irq_regs(regs); |
339 | bw_get_prof_limit(cpu); | 296 | bw_get_prof_limit(cpu); |
340 | bw_clear_intr_mask(0, 1); /* INTR_TABLE[0] & 1 is Profile IRQ */ | 297 | bw_clear_intr_mask(0, 1); /* INTR_TABLE[0] & 1 is Profile IRQ */ |
341 | 298 | ||
342 | cpu_tick[cpu]++; | 299 | cpu_tick[cpu]++; |
@@ -349,7 +306,7 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs) | |||
349 | 306 | ||
350 | profile_tick(CPU_PROFILING); | 307 | profile_tick(CPU_PROFILING); |
351 | 308 | ||
352 | if(!--prof_counter(cpu)) { | 309 | if (!--prof_counter(cpu)) { |
353 | int user = user_mode(regs); | 310 | int user = user_mode(regs); |
354 | 311 | ||
355 | irq_enter(); | 312 | irq_enter(); |
@@ -361,8 +318,6 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs) | |||
361 | set_irq_regs(old_regs); | 318 | set_irq_regs(old_regs); |
362 | } | 319 | } |
363 | 320 | ||
364 | extern unsigned int lvl14_resolution; | ||
365 | |||
366 | static void __cpuinit smp_setup_percpu_timer(void) | 321 | static void __cpuinit smp_setup_percpu_timer(void) |
367 | { | 322 | { |
368 | int cpu = hard_smp4d_processor_id(); | 323 | int cpu = hard_smp4d_processor_id(); |
@@ -374,16 +329,16 @@ static void __cpuinit smp_setup_percpu_timer(void) | |||
374 | void __init smp4d_blackbox_id(unsigned *addr) | 329 | void __init smp4d_blackbox_id(unsigned *addr) |
375 | { | 330 | { |
376 | int rd = *addr & 0x3e000000; | 331 | int rd = *addr & 0x3e000000; |
377 | 332 | ||
378 | addr[0] = 0xc0800800 | rd; /* lda [%g0] ASI_M_VIKING_TMP1, reg */ | 333 | addr[0] = 0xc0800800 | rd; /* lda [%g0] ASI_M_VIKING_TMP1, reg */ |
379 | addr[1] = 0x01000000; /* nop */ | 334 | addr[1] = 0x01000000; /* nop */ |
380 | addr[2] = 0x01000000; /* nop */ | 335 | addr[2] = 0x01000000; /* nop */ |
381 | } | 336 | } |
382 | 337 | ||
383 | void __init smp4d_blackbox_current(unsigned *addr) | 338 | void __init smp4d_blackbox_current(unsigned *addr) |
384 | { | 339 | { |
385 | int rd = *addr & 0x3e000000; | 340 | int rd = *addr & 0x3e000000; |
386 | 341 | ||
387 | addr[0] = 0xc0800800 | rd; /* lda [%g0] ASI_M_VIKING_TMP1, reg */ | 342 | addr[0] = 0xc0800800 | rd; /* lda [%g0] ASI_M_VIKING_TMP1, reg */ |
388 | addr[2] = 0x81282002 | rd | (rd >> 11); /* sll reg, 2, reg */ | 343 | addr[2] = 0x81282002 | rd | (rd >> 11); /* sll reg, 2, reg */ |
389 | addr[4] = 0x01000000; /* nop */ | 344 | addr[4] = 0x01000000; /* nop */ |
@@ -392,17 +347,16 @@ void __init smp4d_blackbox_current(unsigned *addr) | |||
392 | void __init sun4d_init_smp(void) | 347 | void __init sun4d_init_smp(void) |
393 | { | 348 | { |
394 | int i; | 349 | int i; |
395 | extern unsigned int t_nmi[], linux_trap_ipi15_sun4d[], linux_trap_ipi15_sun4m[]; | ||
396 | 350 | ||
397 | /* Patch ipi15 trap table */ | 351 | /* Patch ipi15 trap table */ |
398 | t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_sun4d - linux_trap_ipi15_sun4m); | 352 | t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_sun4d - linux_trap_ipi15_sun4m); |
399 | 353 | ||
400 | /* And set btfixup... */ | 354 | /* And set btfixup... */ |
401 | BTFIXUPSET_BLACKBOX(hard_smp_processor_id, smp4d_blackbox_id); | 355 | BTFIXUPSET_BLACKBOX(hard_smp_processor_id, smp4d_blackbox_id); |
402 | BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current); | 356 | BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current); |
403 | BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM); | 357 | BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM); |
404 | BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM); | 358 | BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM); |
405 | 359 | ||
406 | for (i = 0; i < NR_CPUS; i++) { | 360 | for (i = 0; i < NR_CPUS; i++) { |
407 | ccall_info.processors_in[i] = 1; | 361 | ccall_info.processors_in[i] = 1; |
408 | ccall_info.processors_out[i] = 1; | 362 | ccall_info.processors_out[i] = 1; |