1 /* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2004-2008 Cavium Networks 7 */ 8 #include <linux/cpu.h> 9 #include <linux/init.h> 10 #include <linux/delay.h> 11 #include <linux/smp.h> 12 #include <linux/interrupt.h> 13 #include <linux/kernel_stat.h> 14 #include <linux/sched.h> 15 #include <linux/module.h> 16 17 #include <asm/mmu_context.h> 18 #include <asm/system.h> 19 #include <asm/time.h> 20 21 #include <asm/octeon/octeon.h> 22 23 #include "octeon_boot.h" 24 25 volatile unsigned long octeon_processor_boot = 0xff; 26 volatile unsigned long octeon_processor_sp; 27 volatile unsigned long octeon_processor_gp; 28 29 #ifdef CONFIG_HOTPLUG_CPU 30 static unsigned int InitTLBStart_addr; 31 #endif 32 33 static irqreturn_t mailbox_interrupt(int irq, void *dev_id) 34 { 35 const int coreid = cvmx_get_core_num(); 36 uint64_t action; 37 38 /* Load the mailbox register to figure out what we're supposed to do */ 39 action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid)); 40 41 /* Clear the mailbox to clear the interrupt */ 42 cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action); 43 44 if (action & SMP_CALL_FUNCTION) 45 smp_call_function_interrupt(); 46 47 /* Check if we've been told to flush the icache */ 48 if (action & SMP_ICACHE_FLUSH) 49 asm volatile ("synci 0($0)\n"); 50 return IRQ_HANDLED; 51 } 52 53 /** 54 * Cause the function described by call_data to be executed on the passed 55 * cpu. When the function has finished, increment the finished field of 56 * call_data. 57 */ 58 void octeon_send_ipi_single(int cpu, unsigned int action) 59 { 60 int coreid = cpu_logical_map(cpu); 61 /* 62 pr_info("SMP: Mailbox send cpu=%d, coreid=%d, action=%u\n", cpu, 63 coreid, action); 64 */ 65 cvmx_write_csr(CVMX_CIU_MBOX_SETX(coreid), action); 66 } 67 68 static inline void octeon_send_ipi_mask(cpumask_t mask, unsigned int action) 69 { 70 unsigned int i; 71 72 for_each_cpu_mask(i, mask) 73 octeon_send_ipi_single(i, action); 74 } 75 76 /** 77 * Detect available CPUs, populate cpu_possible_map 78 */ 79 static void octeon_smp_hotplug_setup(void) 80 { 81 #ifdef CONFIG_HOTPLUG_CPU 82 uint32_t labi_signature; 83 84 labi_signature = 85 cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 86 LABI_ADDR_IN_BOOTLOADER + 87 offsetof(struct linux_app_boot_info, 88 labi_signature))); 89 if (labi_signature != LABI_SIGNATURE) 90 pr_err("The bootloader version on this board is incorrect\n"); 91 InitTLBStart_addr = 92 cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 93 LABI_ADDR_IN_BOOTLOADER + 94 offsetof(struct linux_app_boot_info, 95 InitTLBStart_addr))); 96 #endif 97 } 98 99 static void octeon_smp_setup(void) 100 { 101 const int coreid = cvmx_get_core_num(); 102 int cpus; 103 int id; 104 105 int core_mask = octeon_get_boot_coremask(); 106 107 cpus_clear(cpu_possible_map); 108 __cpu_number_map[coreid] = 0; 109 __cpu_logical_map[0] = coreid; 110 cpu_set(0, cpu_possible_map); 111 112 cpus = 1; 113 for (id = 0; id < 16; id++) { 114 if ((id != coreid) && (core_mask & (1 << id))) { 115 cpu_set(cpus, cpu_possible_map); 116 __cpu_number_map[id] = cpus; 117 __cpu_logical_map[cpus] = id; 118 cpus++; 119 } 120 } 121 cpu_present_map = cpu_possible_map; 122 123 octeon_smp_hotplug_setup(); 124 } 125 126 /** 127 * Firmware CPU startup hook 128 * 129 */ 130 static void octeon_boot_secondary(int cpu, struct task_struct *idle) 131 { 132 int count; 133 134 pr_info("SMP: Booting CPU%02d (CoreId %2d)...\n", cpu, 135 cpu_logical_map(cpu)); 136 137 octeon_processor_sp = __KSTK_TOS(idle); 138 octeon_processor_gp = (unsigned long)(task_thread_info(idle)); 139 octeon_processor_boot = cpu_logical_map(cpu); 140 mb(); 141 142 count = 10000; 143 while (octeon_processor_sp && count) { 144 /* Waiting for processor to get the SP and GP */ 145 udelay(1); 146 count--; 147 } 148 if (count == 0) 149 pr_err("Secondary boot timeout\n"); 150 } 151 152 /** 153 * After we've done initial boot, this function is called to allow the 154 * board code to clean up state, if needed 155 */ 156 static void octeon_init_secondary(void) 157 { 158 const int coreid = cvmx_get_core_num(); 159 union cvmx_ciu_intx_sum0 interrupt_enable; 160 161 #ifdef CONFIG_HOTPLUG_CPU 162 unsigned int cur_exception_base; 163 164 cur_exception_base = cvmx_read64_uint32( 165 CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 166 LABI_ADDR_IN_BOOTLOADER + 167 offsetof(struct linux_app_boot_info, 168 cur_exception_base))); 169 /* cur_exception_base is incremented in bootloader after setting */ 170 write_c0_ebase((unsigned int)(cur_exception_base - EXCEPTION_BASE_INCR)); 171 #endif 172 octeon_check_cpu_bist(); 173 octeon_init_cvmcount(); 174 /* 175 pr_info("SMP: CPU%d (CoreId %lu) started\n", cpu, coreid); 176 */ 177 /* Enable Mailbox interrupts to this core. These are the only 178 interrupts allowed on line 3 */ 179 cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), 0xffffffff); 180 interrupt_enable.u64 = 0; 181 interrupt_enable.s.mbox = 0x3; 182 cvmx_write_csr(CVMX_CIU_INTX_EN0((coreid * 2)), interrupt_enable.u64); 183 cvmx_write_csr(CVMX_CIU_INTX_EN0((coreid * 2 + 1)), 0); 184 cvmx_write_csr(CVMX_CIU_INTX_EN1((coreid * 2)), 0); 185 cvmx_write_csr(CVMX_CIU_INTX_EN1((coreid * 2 + 1)), 0); 186 /* Enable core interrupt processing for 2,3 and 7 */ 187 set_c0_status(0x8c01); 188 } 189 190 /** 191 * Callout to firmware before smp_init 192 * 193 */ 194 void octeon_prepare_cpus(unsigned int max_cpus) 195 { 196 cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffffffff); 197 if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt, IRQF_DISABLED, 198 "mailbox0", mailbox_interrupt)) { 199 panic("Cannot request_irq(OCTEON_IRQ_MBOX0)\n"); 200 } 201 if (request_irq(OCTEON_IRQ_MBOX1, mailbox_interrupt, IRQF_DISABLED, 202 "mailbox1", mailbox_interrupt)) { 203 panic("Cannot request_irq(OCTEON_IRQ_MBOX1)\n"); 204 } 205 } 206 207 /** 208 * Last chance for the board code to finish SMP initialization before 209 * the CPU is "online". 210 */ 211 static void octeon_smp_finish(void) 212 { 213 #ifdef CONFIG_CAVIUM_GDB 214 unsigned long tmp; 215 /* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also set the MCD0 216 to be not masked by this core so we know the signal is received by 217 someone */ 218 asm volatile ("dmfc0 %0, $22\n" 219 "ori %0, %0, 0x9100\n" "dmtc0 %0, $22\n" : "=r" (tmp)); 220 #endif 221 222 octeon_user_io_init(); 223 224 /* to generate the first CPU timer interrupt */ 225 write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ); 226 } 227 228 /** 229 * Hook for after all CPUs are online 230 */ 231 static void octeon_cpus_done(void) 232 { 233 #ifdef CONFIG_CAVIUM_GDB 234 unsigned long tmp; 235 /* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also set the MCD0 236 to be not masked by this core so we know the signal is received by 237 someone */ 238 asm volatile ("dmfc0 %0, $22\n" 239 "ori %0, %0, 0x9100\n" "dmtc0 %0, $22\n" : "=r" (tmp)); 240 #endif 241 } 242 243 #ifdef CONFIG_HOTPLUG_CPU 244 245 /* State of each CPU. */ 246 DEFINE_PER_CPU(int, cpu_state); 247 248 extern void fixup_irqs(void); 249 250 static DEFINE_SPINLOCK(smp_reserve_lock); 251 252 static int octeon_cpu_disable(void) 253 { 254 unsigned int cpu = smp_processor_id(); 255 256 if (cpu == 0) 257 return -EBUSY; 258 259 spin_lock(&smp_reserve_lock); 260 261 cpu_clear(cpu, cpu_online_map); 262 cpu_clear(cpu, cpu_callin_map); 263 local_irq_disable(); 264 fixup_irqs(); 265 local_irq_enable(); 266 267 flush_cache_all(); 268 local_flush_tlb_all(); 269 270 spin_unlock(&smp_reserve_lock); 271 272 return 0; 273 } 274 275 static void octeon_cpu_die(unsigned int cpu) 276 { 277 int coreid = cpu_logical_map(cpu); 278 uint32_t avail_coremask; 279 struct cvmx_bootmem_named_block_desc *block_desc; 280 281 #ifdef CONFIG_CAVIUM_OCTEON_WATCHDOG 282 /* Disable the watchdog */ 283 cvmx_ciu_wdogx_t ciu_wdog; 284 ciu_wdog.u64 = cvmx_read_csr(CVMX_CIU_WDOGX(cpu)); 285 ciu_wdog.s.mode = 0; 286 cvmx_write_csr(CVMX_CIU_WDOGX(cpu), ciu_wdog.u64); 287 #endif 288 289 while (per_cpu(cpu_state, cpu) != CPU_DEAD) 290 cpu_relax(); 291 292 /* 293 * This is a bit complicated strategics of getting/settig available 294 * cores mask, copied from bootloader 295 */ 296 /* LINUX_APP_BOOT_BLOCK is initialized in bootoct binary */ 297 block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME); 298 299 if (!block_desc) { 300 avail_coremask = 301 cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 302 LABI_ADDR_IN_BOOTLOADER + 303 offsetof 304 (struct linux_app_boot_info, 305 avail_coremask))); 306 } else { /* alternative, already initialized */ 307 avail_coremask = 308 cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 309 block_desc->base_addr + 310 AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK)); 311 } 312 313 avail_coremask |= 1 << coreid; 314 315 /* Setting avail_coremask for bootoct binary */ 316 if (!block_desc) { 317 cvmx_write64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 318 LABI_ADDR_IN_BOOTLOADER + 319 offsetof(struct linux_app_boot_info, 320 avail_coremask)), 321 avail_coremask); 322 } else { 323 cvmx_write64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 324 block_desc->base_addr + 325 AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK), 326 avail_coremask); 327 } 328 329 pr_info("Reset core %d. Available Coremask = %x \n", coreid, 330 avail_coremask); 331 cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid); 332 cvmx_write_csr(CVMX_CIU_PP_RST, 0); 333 } 334 335 void play_dead(void) 336 { 337 int coreid = cvmx_get_core_num(); 338 339 idle_task_exit(); 340 octeon_processor_boot = 0xff; 341 per_cpu(cpu_state, coreid) = CPU_DEAD; 342 343 while (1) /* core will be reset here */ 344 ; 345 } 346 347 extern void kernel_entry(unsigned long arg1, ...); 348 349 static void start_after_reset(void) 350 { 351 kernel_entry(0, 0, 0); /* set a2 = 0 for secondary core */ 352 } 353 354 int octeon_update_boot_vector(unsigned int cpu) 355 { 356 357 int coreid = cpu_logical_map(cpu); 358 unsigned int avail_coremask; 359 struct cvmx_bootmem_named_block_desc *block_desc; 360 struct boot_init_vector *boot_vect = 361 (struct boot_init_vector *) cvmx_phys_to_ptr(0x0 + 362 BOOTLOADER_BOOT_VECTOR); 363 364 block_desc = cvmx_bootmem_find_named_block(LINUX_APP_BOOT_BLOCK_NAME); 365 366 if (!block_desc) { 367 avail_coremask = 368 cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 369 LABI_ADDR_IN_BOOTLOADER + 370 offsetof(struct linux_app_boot_info, 371 avail_coremask))); 372 } else { /* alternative, already initialized */ 373 avail_coremask = 374 cvmx_read64_uint32(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, 375 block_desc->base_addr + 376 AVAIL_COREMASK_OFFSET_IN_LINUX_APP_BOOT_BLOCK)); 377 } 378 379 if (!(avail_coremask & (1 << coreid))) { 380 /* core not available, assume, that catched by simple-executive */ 381 cvmx_write_csr(CVMX_CIU_PP_RST, 1 << coreid); 382 cvmx_write_csr(CVMX_CIU_PP_RST, 0); 383 } 384 385 boot_vect[coreid].app_start_func_addr = 386 (uint32_t) (unsigned long) start_after_reset; 387 boot_vect[coreid].code_addr = InitTLBStart_addr; 388 389 CVMX_SYNC; 390 391 cvmx_write_csr(CVMX_CIU_NMI, (1 << coreid) & avail_coremask); 392 393 return 0; 394 } 395 396 static int __cpuinit octeon_cpu_callback(struct notifier_block *nfb, 397 unsigned long action, void *hcpu) 398 { 399 unsigned int cpu = (unsigned long)hcpu; 400 401 switch (action) { 402 case CPU_UP_PREPARE: 403 octeon_update_boot_vector(cpu); 404 break; 405 case CPU_ONLINE: 406 pr_info("Cpu %d online\n", cpu); 407 break; 408 case CPU_DEAD: 409 break; 410 } 411 412 return NOTIFY_OK; 413 } 414 415 static struct notifier_block __cpuinitdata octeon_cpu_notifier = { 416 .notifier_call = octeon_cpu_callback, 417 }; 418 419 static int __cpuinit register_cavium_notifier(void) 420 { 421 register_hotcpu_notifier(&octeon_cpu_notifier); 422 423 return 0; 424 } 425 426 late_initcall(register_cavium_notifier); 427 428 #endif /* CONFIG_HOTPLUG_CPU */ 429 430 struct plat_smp_ops octeon_smp_ops = { 431 .send_ipi_single = octeon_send_ipi_single, 432 .send_ipi_mask = octeon_send_ipi_mask, 433 .init_secondary = octeon_init_secondary, 434 .smp_finish = octeon_smp_finish, 435 .cpus_done = octeon_cpus_done, 436 .boot_secondary = octeon_boot_secondary, 437 .smp_setup = octeon_smp_setup, 438 .prepare_cpus = octeon_prepare_cpus, 439 #ifdef CONFIG_HOTPLUG_CPU 440 .cpu_disable = octeon_cpu_disable, 441 .cpu_die = octeon_cpu_die, 442 #endif 443 }; 444