Import 2.3.18pre1
[davej-history.git] / arch / sparc / kernel / sun4d_smp.c
blobb52cd08a83c22b1ccfe6183c042983d71a9a9cac
1 /* sun4d_smp.c: Sparc SS1000/SC2000 SMP support.
3 * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5 * Based on sun4m's smp.c, which is:
6 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
7 */
9 #include <asm/head.h>
11 #include <linux/config.h>
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/threads.h>
15 #include <linux/smp.h>
16 #include <linux/smp_lock.h>
17 #include <linux/interrupt.h>
18 #include <linux/kernel_stat.h>
19 #include <linux/init.h>
20 #include <linux/spinlock.h>
22 #include <asm/ptrace.h>
23 #include <asm/atomic.h>
25 #include <asm/delay.h>
26 #include <asm/irq.h>
27 #include <asm/page.h>
28 #include <asm/pgtable.h>
29 #include <asm/oplib.h>
30 #include <asm/atops.h>
31 #include <asm/hardirq.h>
32 #include <asm/softirq.h>
33 #include <asm/sbus.h>
34 #include <asm/sbi.h>
36 #define __KERNEL_SYSCALLS__
37 #include <linux/unistd.h>
39 #define IRQ_CROSS_CALL 15
41 extern ctxd_t *srmmu_ctx_table_phys;
42 extern int linux_num_cpus;
44 extern void calibrate_delay(void);
46 extern struct task_struct *current_set[NR_CPUS];
47 extern volatile int smp_processors_ready;
48 extern unsigned long cpu_present_map;
49 extern int smp_num_cpus;
50 static int smp_highest_cpu = 0;
51 extern int smp_threads_ready;
52 extern unsigned char mid_xlate[NR_CPUS];
53 extern volatile unsigned long cpu_callin_map[NR_CPUS];
54 extern unsigned long smp_proc_in_lock[NR_CPUS];
55 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
56 extern unsigned long cpu_offset[NR_CPUS];
57 extern unsigned char boot_cpu_id;
58 extern int smp_activated;
59 extern volatile int cpu_number_map[NR_CPUS];
60 extern volatile int __cpu_logical_map[NR_CPUS];
61 extern volatile unsigned long ipi_count;
62 extern volatile int smp_process_available;
63 extern volatile int smp_commenced;
64 extern int __smp4d_processor_id(void);
66 /* #define SMP_DEBUG */
68 #ifdef SMP_DEBUG
69 #define SMP_PRINTK(x) printk x
70 #else
71 #define SMP_PRINTK(x)
72 #endif
74 static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val)
76 __asm__ __volatile__("swap [%1], %0\n\t" :
77 "=&r" (val), "=&r" (ptr) :
78 "0" (val), "1" (ptr));
79 return val;
82 static void smp_setup_percpu_timer(void);
83 extern void cpu_probe(void);
84 extern void sun4d_distribute_irqs(void);
86 void __init smp4d_callin(void)
88 int cpuid = hard_smp4d_processor_id();
89 extern spinlock_t sun4d_imsk_lock;
90 unsigned long flags;
92 /* Show we are alive */
93 cpu_leds[cpuid] = 0x6;
94 show_leds(cpuid);
96 /* Enable level15 interrupt, disable level14 interrupt for now */
97 cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000);
99 local_flush_cache_all();
100 local_flush_tlb_all();
102 /* Get our local ticker going. */
103 smp_setup_percpu_timer();
105 calibrate_delay();
106 smp_store_cpu_info(cpuid);
107 local_flush_cache_all();
108 local_flush_tlb_all();
110 /* Allow master to continue. */
111 swap((unsigned long *)&cpu_callin_map[cpuid], 1);
112 local_flush_cache_all();
113 local_flush_tlb_all();
115 cpu_probe();
117 while((unsigned long)current_set[cpuid] < PAGE_OFFSET)
118 barrier();
120 while(current_set[cpuid]->processor != cpuid)
121 barrier();
123 /* Fix idle thread fields. */
124 __asm__ __volatile__("ld [%0], %%g6\n\t"
125 "sta %%g6, [%%g0] %1\n\t"
126 : : "r" (&current_set[cpuid]), "i" (ASI_M_VIKING_TMP2)
127 : "memory" /* paranoid */);
129 cpu_leds[cpuid] = 0x9;
130 show_leds(cpuid);
132 current->mm->mmap->vm_page_prot = PAGE_SHARED;
133 current->mm->mmap->vm_start = PAGE_OFFSET;
134 current->mm->mmap->vm_end = init_mm.mmap->vm_end;
136 local_flush_cache_all();
137 local_flush_tlb_all();
139 __sti(); /* We don't allow PIL 14 yet */
141 while(!smp_commenced)
142 barrier();
144 spin_lock_irqsave(&sun4d_imsk_lock, flags);
145 cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */
146 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
149 extern int cpu_idle(void *unused);
150 extern void init_IRQ(void);
151 extern void cpu_panic(void);
152 extern int start_secondary(void *unused);
155 * Cycle through the processors asking the PROM to start each one.
158 extern struct prom_cpuinfo linux_cpus[NR_CPUS];
159 extern struct linux_prom_registers smp_penguin_ctable;
160 extern unsigned long trapbase_cpu1[];
161 extern unsigned long trapbase_cpu2[];
162 extern unsigned long trapbase_cpu3[];
164 void __init smp4d_boot_cpus(void)
166 int cpucount = 0;
167 int i = 0;
169 printk("Entering SMP Mode...\n");
171 for (i = 0; i < NR_CPUS; i++)
172 cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data;
174 if (boot_cpu_id)
175 current_set[0] = NULL;
177 __sti();
178 cpu_present_map = 0;
179 for(i=0; i < linux_num_cpus; i++)
180 cpu_present_map |= (1<<linux_cpus[i].mid);
181 SMP_PRINTK(("cpu_present_map %08lx\n", cpu_present_map));
182 for(i=0; i < NR_CPUS; i++)
183 cpu_number_map[i] = -1;
184 for(i=0; i < NR_CPUS; i++)
185 __cpu_logical_map[i] = -1;
186 for(i=0; i < NR_CPUS; i++)
187 mid_xlate[i] = i;
188 cpu_number_map[boot_cpu_id] = 0;
189 __cpu_logical_map[0] = boot_cpu_id;
190 current->processor = boot_cpu_id;
191 smp_store_cpu_info(boot_cpu_id);
192 smp_setup_percpu_timer();
193 init_idle();
194 local_flush_cache_all();
195 if(linux_num_cpus == 1)
196 return; /* Not an MP box. */
197 SMP_PRINTK(("Iterating over CPUs\n"));
198 for(i = 0; i < NR_CPUS; i++) {
199 if(i == boot_cpu_id)
200 continue;
202 if(cpu_present_map & (1 << i)) {
203 extern unsigned long sun4d_cpu_startup;
204 unsigned long *entry = &sun4d_cpu_startup;
205 struct task_struct *p;
206 int timeout;
207 int no;
209 /* Cook up an idler for this guy. */
210 kernel_thread(start_secondary, NULL, CLONE_PID);
212 p = task[++cpucount];
214 p->processor = i;
215 p->has_cpu = 1; /* we schedule the first task manually */
216 current_set[i] = p;
218 for (no = 0; no < linux_num_cpus; no++)
219 if (linux_cpus[no].mid == i)
220 break;
223 * Initialize the contexts table
224 * Since the call to prom_startcpu() trashes the structure,
225 * we need to re-initialize it for each cpu
227 smp_penguin_ctable.which_io = 0;
228 smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys;
229 smp_penguin_ctable.reg_size = 0;
231 /* whirrr, whirrr, whirrrrrrrrr... */
232 SMP_PRINTK(("Starting CPU %d at %p task %d node %08x\n", i, entry, cpucount, linux_cpus[no].prom_node));
233 local_flush_cache_all();
234 prom_startcpu(linux_cpus[no].prom_node,
235 &smp_penguin_ctable, 0, (char *)entry);
237 SMP_PRINTK(("prom_startcpu returned :)\n"));
239 /* wheee... it's going... */
240 for(timeout = 0; timeout < 10000; timeout++) {
241 if(cpu_callin_map[i])
242 break;
243 udelay(200);
246 if(cpu_callin_map[i]) {
247 /* Another "Red Snapper". */
248 cpu_number_map[i] = cpucount;
249 __cpu_logical_map[cpucount] = i;
250 } else {
251 cpucount--;
252 printk("Processor %d is stuck.\n", i);
255 if(!(cpu_callin_map[i])) {
256 cpu_present_map &= ~(1 << i);
257 cpu_number_map[i] = -1;
260 local_flush_cache_all();
261 if(cpucount == 0) {
262 printk("Error: only one Processor found.\n");
263 cpu_present_map = (1 << hard_smp4d_processor_id());
264 } else {
265 unsigned long bogosum = 0;
267 for(i = 0; i < NR_CPUS; i++) {
268 if(cpu_present_map & (1 << i)) {
269 bogosum += cpu_data[i].udelay_val;
270 smp_highest_cpu = i;
273 SMP_PRINTK(("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n", cpucount + 1, (bogosum + 2500)/500000, ((bogosum + 2500)/5000)%100));
274 printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n",
275 cpucount + 1,
276 (bogosum + 2500)/500000,
277 ((bogosum + 2500)/5000)%100);
278 smp_activated = 1;
279 smp_num_cpus = cpucount + 1;
282 /* Free unneeded trap tables */
284 mem_map[MAP_NR((unsigned long)trapbase_cpu1)].flags &= ~(1 << PG_reserved);
285 free_page((unsigned long)trapbase_cpu1);
286 mem_map[MAP_NR((unsigned long)trapbase_cpu2)].flags &= ~(1 << PG_reserved);
287 free_page((unsigned long)trapbase_cpu2);
288 mem_map[MAP_NR((unsigned long)trapbase_cpu3)].flags &= ~(1 << PG_reserved);
289 free_page((unsigned long)trapbase_cpu3);
291 /* Ok, they are spinning and ready to go. */
292 smp_processors_ready = 1;
293 sun4d_distribute_irqs();
296 static struct smp_funcall {
297 smpfunc_t func;
298 unsigned long arg1;
299 unsigned long arg2;
300 unsigned long arg3;
301 unsigned long arg4;
302 unsigned long arg5;
303 unsigned char processors_in[NR_CPUS]; /* Set when ipi entered. */
304 unsigned char processors_out[NR_CPUS]; /* Set when ipi exited. */
305 } ccall_info __attribute__((aligned(8)));
307 static spinlock_t cross_call_lock = SPIN_LOCK_UNLOCKED;
309 /* Cross calls must be serialized, at least currently. */
310 void smp4d_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
311 unsigned long arg3, unsigned long arg4, unsigned long arg5)
313 if(smp_processors_ready) {
314 register int high = smp_highest_cpu;
315 unsigned long flags;
317 spin_lock_irqsave(&cross_call_lock, flags);
320 /* If you make changes here, make sure gcc generates proper code... */
321 smpfunc_t f asm("i0") = func;
322 unsigned long a1 asm("i1") = arg1;
323 unsigned long a2 asm("i2") = arg2;
324 unsigned long a3 asm("i3") = arg3;
325 unsigned long a4 asm("i4") = arg4;
326 unsigned long a5 asm("i5") = arg5;
328 __asm__ __volatile__("
329 std %0, [%6]
330 std %2, [%6 + 8]
331 std %4, [%6 + 16]" : :
332 "r"(f), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5),
333 "r" (&ccall_info.func));
336 /* Init receive/complete mapping, plus fire the IPI's off. */
338 register unsigned long mask;
339 register int i;
341 mask = (cpu_present_map & ~(1 << hard_smp4d_processor_id()));
342 for(i = 0; i <= high; i++) {
343 if(mask & (1 << i)) {
344 ccall_info.processors_in[i] = 0;
345 ccall_info.processors_out[i] = 0;
346 sun4d_send_ipi(i, IRQ_CROSS_CALL);
351 /* First, run local copy. */
352 func(arg1, arg2, arg3, arg4, arg5);
355 register int i;
357 i = 0;
358 do {
359 while(!ccall_info.processors_in[i])
360 barrier();
361 } while(++i <= high);
363 i = 0;
364 do {
365 while(!ccall_info.processors_out[i])
366 barrier();
367 } while(++i <= high);
370 spin_unlock_irqrestore(&cross_call_lock, flags);
371 } else
372 func(arg1, arg2, arg3, arg4, arg5); /* Just need to run local copy. */
375 /* Running cross calls. */
376 void smp4d_cross_call_irq(void)
378 int i = hard_smp4d_processor_id();
380 ccall_info.processors_in[i] = 1;
381 ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
382 ccall_info.arg4, ccall_info.arg5);
383 ccall_info.processors_out[i] = 1;
386 static int smp4d_stop_cpu_sender;
388 static void smp4d_stop_cpu(void)
390 int me = hard_smp4d_processor_id();
392 if (me != smp4d_stop_cpu_sender)
393 while(1) barrier();
396 /* Cross calls, in order to work efficiently and atomically do all
397 * the message passing work themselves, only stopcpu and reschedule
398 * messages come through here.
400 void smp4d_message_pass(int target, int msg, unsigned long data, int wait)
402 int me = hard_smp4d_processor_id();
404 SMP_PRINTK(("smp4d_message_pass %d %d %08lx %d\n", target, msg, data, wait));
405 if (msg == MSG_STOP_CPU && target == MSG_ALL_BUT_SELF) {
406 unsigned long flags;
407 static spinlock_t stop_cpu_lock = SPIN_LOCK_UNLOCKED;
408 spin_lock_irqsave(&stop_cpu_lock, flags);
409 smp4d_stop_cpu_sender = me;
410 smp4d_cross_call((smpfunc_t)smp4d_stop_cpu, 0, 0, 0, 0, 0);
411 spin_unlock_irqrestore(&stop_cpu_lock, flags);
413 printk("Yeeee, trying to send SMP msg(%d) to %d on cpu %d\n", msg, target, me);
414 panic("Bogon SMP message pass.");
417 /* Protects counters touched during level14 ticker */
418 static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
420 #ifdef CONFIG_PROFILE
422 /* 32-bit Sparc specific profiling function. */
423 static inline void sparc_do_profile(unsigned long pc)
425 if(prof_buffer && current->pid) {
426 extern int _stext;
428 pc -= (unsigned long) &_stext;
429 pc >>= prof_shift;
431 spin_lock(&ticker_lock);
432 if(pc < prof_len)
433 prof_buffer[pc]++;
434 else
435 prof_buffer[prof_len - 1]++;
436 spin_unlock(&ticker_lock);
440 #endif
442 extern unsigned int prof_multiplier[NR_CPUS];
443 extern unsigned int prof_counter[NR_CPUS];
445 extern void update_one_process(struct task_struct *p, unsigned long ticks,
446 unsigned long user, unsigned long system,
447 int cpu);
450 void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
452 int cpu = hard_smp4d_processor_id();
453 static int cpu_tick[NR_CPUS];
454 static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd };
456 bw_get_prof_limit(cpu);
457 bw_clear_intr_mask(0, 1); /* INTR_TABLE[0] & 1 is Profile IRQ */
459 cpu_tick[cpu]++;
460 if (!(cpu_tick[cpu] & 15)) {
461 if (cpu_tick[cpu] == 0x60)
462 cpu_tick[cpu] = 0;
463 cpu_leds[cpu] = led_mask[cpu_tick[cpu] >> 4];
464 show_leds(cpu);
467 #ifdef CONFIG_PROFILE
468 if(!user_mode(regs))
469 sparc_do_profile(regs->pc);
470 #endif
471 if(!--prof_counter[cpu]) {
472 int user = user_mode(regs);
473 if(current->pid) {
474 update_one_process(current, 1, user, !user, cpu);
476 if(--current->counter <= 0) {
477 current->counter = 0;
478 current->need_resched = 1;
481 spin_lock(&ticker_lock);
482 if(user) {
483 if(current->priority < DEF_PRIORITY) {
484 kstat.cpu_nice++;
485 kstat.per_cpu_nice[cpu]++;
486 } else {
487 kstat.cpu_user++;
488 kstat.per_cpu_user[cpu]++;
490 } else {
491 kstat.cpu_system++;
492 kstat.per_cpu_system[cpu]++;
494 spin_unlock(&ticker_lock);
496 prof_counter[cpu] = prof_multiplier[cpu];
500 extern unsigned int lvl14_resolution;
502 static void __init smp_setup_percpu_timer(void)
504 int cpu = hard_smp4d_processor_id();
506 prof_counter[cpu] = prof_multiplier[cpu] = 1;
507 load_profile_irq(cpu, lvl14_resolution);
510 void __init smp4d_blackbox_id(unsigned *addr)
512 int rd = *addr & 0x3e000000;
514 addr[0] = 0xc0800800 | rd; /* lda [%g0] ASI_M_VIKING_TMP1, reg */
515 addr[1] = 0x01000000; /* nop */
516 addr[2] = 0x01000000; /* nop */
519 void __init smp4d_blackbox_current(unsigned *addr)
521 /* We have a nice Linux current register :) */
522 int rd = addr[1] & 0x3e000000;
524 addr[0] = 0x10800006; /* b .+24 */
525 addr[1] = 0xc0800820 | rd; /* lda [%g0] ASI_M_VIKING_TMP2, reg */
528 void __init sun4d_init_smp(void)
530 int i;
531 extern unsigned int patchme_store_new_current[];
532 extern unsigned int t_nmi[], linux_trap_ipi15_sun4d[], linux_trap_ipi15_sun4m[];
534 /* Store current into Linux current register :) */
535 __asm__ __volatile__("sta %%g6, [%%g0] %0" : : "i"(ASI_M_VIKING_TMP2));
537 /* Patch switch_to */
538 patchme_store_new_current[0] = (patchme_store_new_current[0] & 0x3e000000) | 0xc0a00820;
540 /* Patch ipi15 trap table */
541 t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_sun4d - linux_trap_ipi15_sun4m);
543 /* And set btfixup... */
544 BTFIXUPSET_BLACKBOX(smp_processor_id, smp4d_blackbox_id);
545 BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current);
546 BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM);
547 BTFIXUPSET_CALL(smp_message_pass, smp4d_message_pass, BTFIXUPCALL_NORM);
548 BTFIXUPSET_CALL(__smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM);
550 for (i = 0; i < NR_CPUS; i++) {
551 ccall_info.processors_in[i] = 1;
552 ccall_info.processors_out[i] = 1;