/* Tell the hardware to boot TP1 - runs on TP0 */ static void brcmstb_boot_secondary(int cpu, struct task_struct *idle) { brcmstb_smp_boot_sp = __KSTK_TOS(idle); brcmstb_smp_boot_gp = (unsigned long)task_thread_info(idle); mb(); /* * TP1 initial boot sequence: * brcm_reset_nmi_vec @ a000_0000 -> * brcmstb_tp1_entry -> * brcm_upper_tlb_setup (cached function call) -> * start_secondary (cached jump) * * TP1 warm restart sequence: * play_dead WAIT loop -> * brcm_tp1_int_vec @ BRCM_WARM_RESTART_VEC -> * eret to play_dead -> * brcmstb_tp1_reentry -> * start_secondary * * Vector relocation code is in arch/mips/brcmstb/prom.c * Actual boot vectors are in arch/mips/brcmstb/vector.S */ printk(KERN_INFO "SMP: Booting CPU%d...\n", cpu); /* warm restart */ brcmstb_send_ipi_single(1, 0); #if defined(CONFIG_BMIPS4380) set_c0_brcm_cmt_ctrl(0x01); #elif defined(CONFIG_BMIPS5000) write_c0_brcm_action(0x9); #endif }
/** * Firmware CPU startup hook * */ static int octeon_boot_secondary(int cpu, struct task_struct *idle) { int count; pr_info("SMP: Booting CPU%02d (CoreId %2d)...\n", cpu, cpu_logical_map(cpu)); octeon_processor_sp = __KSTK_TOS(idle); octeon_processor_gp = (unsigned long)(task_thread_info(idle)); octeon_processor_boot = cpu_logical_map(cpu); mb(); count = 10000; while (octeon_processor_sp && count) { /* Waiting for processor to get the SP and GP */ udelay(1); count--; } if (count == 0) { pr_err("Secondary boot timeout\n"); return -ETIMEDOUT; } return 0; }
/* * Launch a slave into smp_bootstrap(). It doesn't take an argument, and we * set sp to the kernel stack of the newly created idle process, gp to the proc * struct so that current_thread_info() will work. */ static void __cpuinit ip27_boot_secondary(int cpu, struct task_struct *idle) { unsigned long gp = (unsigned long)task_thread_info(idle); unsigned long sp = __KSTK_TOS(idle); LAUNCH_SLAVE(cputonasid(cpu), cputoslice(cpu), (launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap), 0, (void *) sp, (void *) gp); }
/* * Firmware CPU startup hook * Complicated by PMON's weird interface which tries to minimic the UNIX fork. * It launches the next * available CPU and copies some information on the * stack so the first thing we do is throw away that stuff and load useful * values into the registers ... */ static void __cpuinit yos_boot_secondary(int cpu, struct task_struct *idle) { unsigned long gp = (unsigned long) task_thread_info(idle); unsigned long sp = __KSTK_TOS(idle); secondary_sp = sp; secondary_gp = gp; arch_spin_unlock(&launch_lock); }
/* * Setup the PC, SP, and GP of a secondary processor and start it * running! */ void prom_boot_secondary(int cpu, struct task_struct *idle) { int retval; retval = cfe_cpu_start(cpu_logical_map(cpu), &smp_bootstrap, __KSTK_TOS(idle), (unsigned long)task_thread_info(idle), 0); if (retval != 0) printk("cfe_start_cpu(%i) returned %i\n" , cpu, retval); }
static void __cpuinit jzsoc_boot_secondary(int cpu, struct task_struct *idle) { int err; unsigned long flags,ctrl; printk("jzsoc_boot_secondary start\n"); local_irq_save(flags); /* set reset bit! */ ctrl = get_smp_ctrl(); ctrl |= (1 << cpu); set_smp_ctrl(ctrl); /* blast all cache before booting secondary cpu */ blast_dcache_jz(); blast_icache_jz(); cpm_clear_bit(15,CPM_CLKGR1); cpm_pwc_enable(scpu_pwc); preempt_disable(); preempt_enable_no_resched(); /* clear reset bit! */ ctrl = get_smp_ctrl(); ctrl &= ~(1 << cpu); set_smp_ctrl(ctrl); wait: if (!cpumask_test_cpu(cpu, cpu_ready)) goto wait; pr_info("[SMP] Booting CPU%d ...\n", cpu); // pr_debug("[SMP] Booting CPU%d ...\n", cpu); err = cpu_boot(cpu_logical_map(cpu), __KSTK_TOS(idle), (unsigned long)task_thread_info(idle)); if (err != 0) pr_err("start_cpu(%i) returned %i\n" , cpu, err); local_irq_restore(flags); }
static void paravirt_boot_secondary(int cpu, struct task_struct *idle) { paravirt_smp_gp[cpu] = (unsigned long)task_thread_info(idle); smp_wmb(); paravirt_smp_sp[cpu] = __KSTK_TOS(idle); }
/* * Setup the PC, SP, and GP of a secondary processor and start it * running! */ void prom_boot_secondary(int cpu, struct task_struct *idle) { register unsigned long temp; volatile unsigned long *start_addr = (volatile unsigned long * ) 0x80000000; asmlinkage void kernel_entry(void); // Temp fix - CFE thinks 0x80000000 points to the Linux start addr but Linux overwrites it with // Tlb refill handler, set it to the real Linux start addr, once TP1 is booted to // Linux, it will overwrite it again with the Tlb refill handler:) printk("TP%d: prom_boot_secondary: Adjust CFE's idea of the Linux start addr...\n", smp_processor_id()); *start_addr = (unsigned long) &kernel_entry; printk("TP%d: prom_boot_secondary: switching to blocking mode...\n", smp_processor_id()); // disable non-blocking mode temp = read_c0_brcm_config_0(); temp &= ~0x20000; write_c0_brcm_config_0(temp); // Configure the s/w interrupt that TP0 will use to kick TP1. By default, // s/w interrupt 0 will be vectored to the TP that generated it, so we need // to set the interrupt routing bit to make it cross over to the other TP. // This is bit 15 (SIR) of CP0 Reg 22 Sel 1. We also want to make h/w IRQ 1 // go to TP1. To do this, we need to set the appropriate bit in the h/w // interrupt crossover. To set the h/w interrupt crossover, we need to set // a different bit in that same CP0 register. The XIR bits (31:27) // control h/w IRQ 4..0, respectively. printk("TP%d: prom_boot_secondary: adjustting s/w interrupt crossover\n", smp_processor_id()); temp = read_c0_cmt_interrupt(); temp |= 0x00018000; write_c0_cmt_interrupt(temp); printk("TP%d: prom_boot_secondary: c0 22,1=%lx\n", smp_processor_id(),temp); // first save the boot data... boot_config->func_addr = (unsigned long) smp_bootstrap; // function boot_config->sp = (unsigned long) __KSTK_TOS(idle); // sp boot_config->gp = (unsigned long) idle->thread_info; // gp boot_config->arg = 0; printk("TP%d: prom_boot_secondary: Kick off 2nd CPU, and adjust TLB serialization...\n", smp_processor_id()); temp = read_c0_cmt_control(); temp |= 0x01; // Takes second CPU out of reset // The following flags can be adjusted to suit performance and debugging needs //temp |= (1<<4); // TP0 priority //temp |= (1<<5); // TP1 priority // adjust tlb serialization temp &= ~(0x0F << 16); // mask off old tlb serialization thingie... // temp |= (0x06 << 16); // adjust tlb serialization (only exception serialization) // temp |= (0x04 << 16); // adjust tlb serialization (full serialization) // temp |= (0x00 << 16); // adjust tlb serialization (no serialization) // temp |= (0x07 << 16); // adjust tlb serialization (USE THIS!) temp |= (0x01 << 16); // adjust tlb serialization (no serialization RECOMMENDED!) temp |= (0x01 << 31); // Debug and profile TP1 thread printk("TP%d: prom_boot_secondary: cp0 22,2 => %08lx\n", smp_processor_id(), temp); write_c0_cmt_control(temp); }