1 /* sun4d_smp.c: Sparc SS1000/SC2000 SMP support. 2 * 3 * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 4 * 5 * Based on sun4m's smp.c, which is: 6 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) 7 */ 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> 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> 22 #include <linux/delay.h> 23 #include <linux/cpu.h> 24 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> 35 #include <asm/tlbflush.h> 36 #include <asm/cacheflush.h> 37 #include <asm/cpudata.h> 38 39 #include "irq.h" 40 #define IRQ_CROSS_CALL 15 41 42 extern ctxd_t *srmmu_ctx_table_phys; 43 44 static volatile int smp_processors_ready = 0; 45 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 63 static inline unsigned long sun4d_swap(volatile unsigned long *ptr, unsigned long val) 64 { 65 __asm__ __volatile__("swap [%1], %0\n\t" : 66 "=&r" (val), "=&r" (ptr) : 67 "0" (val), "1" (ptr)); 68 return val; 69 } 70 71 static void smp_setup_percpu_timer(void); 72 extern void cpu_probe(void); 73 extern void sun4d_distribute_irqs(void); 74 75 static unsigned char cpu_leds[32]; 76 77 static inline void show_leds(int cpuid) 78 { 79 cpuid &= 0x1e; 80 __asm__ __volatile__ ("stba %0, [%1] %2" : : 81 "r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]), 82 "r" (ECSR_BASE(cpuid) | BB_LEDS), 83 "i" (ASI_M_CTL)); 84 } 85 86 void __cpuinit smp4d_callin(void) 87 { 88 int cpuid = hard_smp4d_processor_id(); 89 extern spinlock_t sun4d_imsk_lock; 90 unsigned long flags; 91 92 /* Show we are alive */ 93 cpu_leds[cpuid] = 0x6; 94 show_leds(cpuid); 95 96 /* Enable level15 interrupt, disable level14 interrupt for now */ 97 cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000); 98 99 local_flush_cache_all(); 100 local_flush_tlb_all(); 101 102 notify_cpu_starting(cpuid); 103 /* 104 * Unblock the master CPU _only_ when the scheduler state 105 * of all secondary CPUs will be up-to-date, so after 106 * the SMP initialization the master will be just allowed 107 * to call the scheduler code. 108 */ 109 /* Get our local ticker going. */ 110 smp_setup_percpu_timer(); 111 112 calibrate_delay(); 113 smp_store_cpu_info(cpuid); 114 local_flush_cache_all(); 115 local_flush_tlb_all(); 116 117 /* Allow master to continue. */ 118 sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1); 119 local_flush_cache_all(); 120 local_flush_tlb_all(); 121 122 cpu_probe(); 123 124 while((unsigned long)current_set[cpuid] < PAGE_OFFSET) 125 barrier(); 126 127 while(current_set[cpuid]->cpu != cpuid) 128 barrier(); 129 130 /* Fix idle thread fields. */ 131 __asm__ __volatile__("ld [%0], %%g6\n\t" 132 : : "r" (¤t_set[cpuid]) 133 : "memory" /* paranoid */); 134 135 cpu_leds[cpuid] = 0x9; 136 show_leds(cpuid); 137 138 /* Attach to the address space of init_task. */ 139 atomic_inc(&init_mm.mm_count); 140 current->active_mm = &init_mm; 141 142 local_flush_cache_all(); 143 local_flush_tlb_all(); 144 145 local_irq_enable(); /* We don't allow PIL 14 yet */ 146 147 while (!cpu_isset(cpuid, smp_commenced_mask)) 148 barrier(); 149 150 spin_lock_irqsave(&sun4d_imsk_lock, flags); 151 cc_set_imsk(cc_get_imsk() & ~0x4000); /* Allow PIL 14 as well */ 152 spin_unlock_irqrestore(&sun4d_imsk_lock, flags); 153 set_cpu_online(cpuid, true); 154 155 } 156 157 extern void init_IRQ(void); 158 extern void cpu_panic(void); 159 160 /* 161 * Cycle through the processors asking the PROM to start each one. 162 */ 163 164 extern struct linux_prom_registers smp_penguin_ctable; 165 extern unsigned long trapbase_cpu1[]; 166 extern unsigned long trapbase_cpu2[]; 167 extern unsigned long trapbase_cpu3[]; 168 169 void __init smp4d_boot_cpus(void) 170 { 171 if (boot_cpu_id) 172 current_set[0] = NULL; 173 smp_setup_percpu_timer(); 174 local_flush_cache_all(); 175 } 176 177 int __cpuinit smp4d_boot_one_cpu(int i) 178 { 179 extern unsigned long sun4d_cpu_startup; 180 unsigned long *entry = &sun4d_cpu_startup; 181 struct task_struct *p; 182 int timeout; 183 int cpu_node; 184 185 cpu_find_by_instance(i, &cpu_node,NULL); 186 /* Cook up an idler for this guy. */ 187 p = fork_idle(i); 188 current_set[i] = task_thread_info(p); 189 190 /* 191 * Initialize the contexts table 192 * Since the call to prom_startcpu() trashes the structure, 193 * we need to re-initialize it for each cpu 194 */ 195 smp_penguin_ctable.which_io = 0; 196 smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys; 197 smp_penguin_ctable.reg_size = 0; 198 199 /* whirrr, whirrr, whirrrrrrrrr... */ 200 SMP_PRINTK(("Starting CPU %d at %p \n", i, entry)); 201 local_flush_cache_all(); 202 prom_startcpu(cpu_node, 203 &smp_penguin_ctable, 0, (char *)entry); 204 205 SMP_PRINTK(("prom_startcpu returned :)\n")); 206 207 /* wheee... it's going... */ 208 for(timeout = 0; timeout < 10000; timeout++) { 209 if(cpu_callin_map[i]) 210 break; 211 udelay(200); 212 } 213 214 if (!(cpu_callin_map[i])) { 215 printk("Processor %d is stuck.\n", i); 216 return -ENODEV; 217 218 } 219 local_flush_cache_all(); 220 return 0; 221 } 222 223 void __init smp4d_smp_done(void) 224 { 225 int i, first; 226 int *prev; 227 228 /* setup cpu list for irq rotation */ 229 first = 0; 230 prev = &first; 231 for_each_online_cpu(i) { 232 *prev = i; 233 prev = &cpu_data(i).next; 234 } 235 *prev = first; 236 local_flush_cache_all(); 237 238 /* Free unneeded trap tables */ 239 ClearPageReserved(virt_to_page(trapbase_cpu1)); 240 init_page_count(virt_to_page(trapbase_cpu1)); 241 free_page((unsigned long)trapbase_cpu1); 242 totalram_pages++; 243 num_physpages++; 244 245 ClearPageReserved(virt_to_page(trapbase_cpu2)); 246 init_page_count(virt_to_page(trapbase_cpu2)); 247 free_page((unsigned long)trapbase_cpu2); 248 totalram_pages++; 249 num_physpages++; 250 251 ClearPageReserved(virt_to_page(trapbase_cpu3)); 252 init_page_count(virt_to_page(trapbase_cpu3)); 253 free_page((unsigned long)trapbase_cpu3); 254 totalram_pages++; 255 num_physpages++; 256 257 /* Ok, they are spinning and ready to go. */ 258 smp_processors_ready = 1; 259 sun4d_distribute_irqs(); 260 } 261 262 static struct smp_funcall { 263 smpfunc_t func; 264 unsigned long arg1; 265 unsigned long arg2; 266 unsigned long arg3; 267 unsigned long arg4; 268 unsigned long arg5; 269 unsigned char processors_in[NR_CPUS]; /* Set when ipi entered. */ 270 unsigned char processors_out[NR_CPUS]; /* Set when ipi exited. */ 271 } ccall_info __attribute__((aligned(8))); 272 273 static DEFINE_SPINLOCK(cross_call_lock); 274 275 /* Cross calls must be serialized, at least currently. */ 276 static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, 277 unsigned long arg2, unsigned long arg3, 278 unsigned long arg4) 279 { 280 if(smp_processors_ready) { 281 register int high = smp_highest_cpu; 282 unsigned long flags; 283 284 spin_lock_irqsave(&cross_call_lock, flags); 285 286 { 287 /* If you make changes here, make sure gcc generates proper code... */ 288 register smpfunc_t f asm("i0") = func; 289 register unsigned long a1 asm("i1") = arg1; 290 register unsigned long a2 asm("i2") = arg2; 291 register unsigned long a3 asm("i3") = arg3; 292 register unsigned long a4 asm("i4") = arg4; 293 register unsigned long a5 asm("i5") = 0; 294 295 __asm__ __volatile__( 296 "std %0, [%6]\n\t" 297 "std %2, [%6 + 8]\n\t" 298 "std %4, [%6 + 16]\n\t" : : 299 "r"(f), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), 300 "r" (&ccall_info.func)); 301 } 302 303 /* Init receive/complete mapping, plus fire the IPI's off. */ 304 { 305 register int i; 306 307 cpu_clear(smp_processor_id(), mask); 308 cpus_and(mask, cpu_online_map, mask); 309 for(i = 0; i <= high; i++) { 310 if (cpu_isset(i, mask)) { 311 ccall_info.processors_in[i] = 0; 312 ccall_info.processors_out[i] = 0; 313 sun4d_send_ipi(i, IRQ_CROSS_CALL); 314 } 315 } 316 } 317 318 { 319 register int i; 320 321 i = 0; 322 do { 323 if (!cpu_isset(i, mask)) 324 continue; 325 while(!ccall_info.processors_in[i]) 326 barrier(); 327 } while(++i <= high); 328 329 i = 0; 330 do { 331 if (!cpu_isset(i, mask)) 332 continue; 333 while(!ccall_info.processors_out[i]) 334 barrier(); 335 } while(++i <= high); 336 } 337 338 spin_unlock_irqrestore(&cross_call_lock, flags); 339 } 340 } 341 342 /* Running cross calls. */ 343 void smp4d_cross_call_irq(void) 344 { 345 int i = hard_smp4d_processor_id(); 346 347 ccall_info.processors_in[i] = 1; 348 ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3, 349 ccall_info.arg4, ccall_info.arg5); 350 ccall_info.processors_out[i] = 1; 351 } 352 353 void smp4d_percpu_timer_interrupt(struct pt_regs *regs) 354 { 355 struct pt_regs *old_regs; 356 int cpu = hard_smp4d_processor_id(); 357 static int cpu_tick[NR_CPUS]; 358 static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd }; 359 360 old_regs = set_irq_regs(regs); 361 bw_get_prof_limit(cpu); 362 bw_clear_intr_mask(0, 1); /* INTR_TABLE[0] & 1 is Profile IRQ */ 363 364 cpu_tick[cpu]++; 365 if (!(cpu_tick[cpu] & 15)) { 366 if (cpu_tick[cpu] == 0x60) 367 cpu_tick[cpu] = 0; 368 cpu_leds[cpu] = led_mask[cpu_tick[cpu] >> 4]; 369 show_leds(cpu); 370 } 371 372 profile_tick(CPU_PROFILING); 373 374 if(!--prof_counter(cpu)) { 375 int user = user_mode(regs); 376 377 irq_enter(); 378 update_process_times(user); 379 irq_exit(); 380 381 prof_counter(cpu) = prof_multiplier(cpu); 382 } 383 set_irq_regs(old_regs); 384 } 385 386 extern unsigned int lvl14_resolution; 387 388 static void __cpuinit smp_setup_percpu_timer(void) 389 { 390 int cpu = hard_smp4d_processor_id(); 391 392 prof_counter(cpu) = prof_multiplier(cpu) = 1; 393 load_profile_irq(cpu, lvl14_resolution); 394 } 395 396 void __init smp4d_blackbox_id(unsigned *addr) 397 { 398 int rd = *addr & 0x3e000000; 399 400 addr[0] = 0xc0800800 | rd; /* lda [%g0] ASI_M_VIKING_TMP1, reg */ 401 addr[1] = 0x01000000; /* nop */ 402 addr[2] = 0x01000000; /* nop */ 403 } 404 405 void __init smp4d_blackbox_current(unsigned *addr) 406 { 407 int rd = *addr & 0x3e000000; 408 409 addr[0] = 0xc0800800 | rd; /* lda [%g0] ASI_M_VIKING_TMP1, reg */ 410 addr[2] = 0x81282002 | rd | (rd >> 11); /* sll reg, 2, reg */ 411 addr[4] = 0x01000000; /* nop */ 412 } 413 414 void __init sun4d_init_smp(void) 415 { 416 int i; 417 extern unsigned int t_nmi[], linux_trap_ipi15_sun4d[], linux_trap_ipi15_sun4m[]; 418 419 /* Patch ipi15 trap table */ 420 t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_sun4d - linux_trap_ipi15_sun4m); 421 422 /* And set btfixup... */ 423 BTFIXUPSET_BLACKBOX(hard_smp_processor_id, smp4d_blackbox_id); 424 BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current); 425 BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM); 426 BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM); 427 428 for (i = 0; i < NR_CPUS; i++) { 429 ccall_info.processors_in[i] = 1; 430 ccall_info.processors_out[i] = 1; 431 } 432 } 433