1#include <linux/linkage.h> 2#include <linux/sched.h> 3 4#include <asm/pmon.h> 5#include <asm/titan_dep.h> 6#include <asm/time.h> 7 8#define LAUNCHSTACK_SIZE 256 9 10static __initdata DEFINE_SPINLOCK(launch_lock); 11 12static unsigned long secondary_sp __initdata; 13static unsigned long secondary_gp __initdata; 14 15static unsigned char launchstack[LAUNCHSTACK_SIZE] __initdata 16 __attribute__((aligned(2 * sizeof(long)))); 17 18static void __init prom_smp_bootstrap(void) 19{ 20 local_irq_disable(); 21 22 while (spin_is_locked(&launch_lock)); 23 24 __asm__ __volatile__( 25 " move $sp, %0 \n" 26 " move $gp, %1 \n" 27 " j smp_bootstrap \n" 28 : 29 : "r" (secondary_sp), "r" (secondary_gp)); 30} 31 32/* 33 * PMON is a fragile beast. It'll blow up once the mappings it's littering 34 * right into the middle of KSEG3 are blown away so we have to grab the slave 35 * core early and keep it in a waiting loop. 36 */ 37void __init prom_grab_secondary(void) 38{ 39 spin_lock(&launch_lock); 40 41 pmon_cpustart(1, &prom_smp_bootstrap, 42 launchstack + LAUNCHSTACK_SIZE, 0); 43} 44 45/* 46 * Detect available CPUs, populate phys_cpu_present_map before smp_init 47 * 48 * We don't want to start the secondary CPU yet nor do we have a nice probing 49 * feature in PMON so we just assume presence of the secondary core. 50 */ 51void __init plat_smp_setup(void) 52{ 53 int i; 54 55 cpus_clear(phys_cpu_present_map); 56 57 for (i = 0; i < 2; i++) { 58 cpu_set(i, phys_cpu_present_map); 59 __cpu_number_map[i] = i; 60 __cpu_logical_map[i] = i; 61 } 62} 63 64void __init plat_prepare_cpus(unsigned int max_cpus) 65{ 66 /* 67 * Be paranoid. Enable the IPI only if we're really about to go SMP. 68 */ 69 if (cpus_weight(cpu_possible_map)) 70 set_c0_status(STATUSF_IP5); 71} 72 73/* 74 * Firmware CPU startup hook 75 * Complicated by PMON's weird interface which tries to minimic the UNIX fork. 76 * It launches the next * available CPU and copies some information on the 77 * stack so the first thing we do is throw away that stuff and load useful 78 * values into the registers ... 79 */ 80void prom_boot_secondary(int cpu, struct task_struct *idle) 81{ 82 unsigned long gp = (unsigned long) task_thread_info(idle); 83 unsigned long sp = __KSTK_TOS(idle); 84 85 secondary_sp = sp; 86 secondary_gp = gp; 87 88 spin_unlock(&launch_lock); 89} 90 91/* Hook for after all CPUs are online */ 92void prom_cpus_done(void) 93{ 94} 95 96/* 97 * After we've done initial boot, this function is called to allow the 98 * board code to clean up state, if needed 99 */ 100void prom_init_secondary(void) 101{ 102 set_c0_status(ST0_CO | ST0_IE | ST0_IM); 103} 104 105void prom_smp_finish(void) 106{ 107} 108 109asmlinkage void titan_mailbox_irq(void) 110{ 111 int cpu = smp_processor_id(); 112 unsigned long status; 113 114 if (cpu == 0) { 115 status = OCD_READ(RM9000x2_OCD_INTP0STATUS3); 116 OCD_WRITE(RM9000x2_OCD_INTP0CLEAR3, status); 117 } 118 119 if (cpu == 1) { 120 status = OCD_READ(RM9000x2_OCD_INTP1STATUS3); 121 OCD_WRITE(RM9000x2_OCD_INTP1CLEAR3, status); 122 } 123 124 if (status & 0x2) 125 smp_call_function_interrupt(); 126} 127 128/* 129 * Send inter-processor interrupt 130 */ 131void core_send_ipi(int cpu, unsigned int action) 132{ 133 /* 134 * Generate an INTMSG so that it can be sent over to the 135 * destination CPU. The INTMSG will put the STATUS bits 136 * based on the action desired. An alternative strategy 137 * is to write to the Interrupt Set register, read the 138 * Interrupt Status register and clear the Interrupt 139 * Clear register. The latter is preffered. 140 */ 141 switch (action) { 142 case SMP_RESCHEDULE_YOURSELF: 143 if (cpu == 1) 144 OCD_WRITE(RM9000x2_OCD_INTP1SET3, 4); 145 else 146 OCD_WRITE(RM9000x2_OCD_INTP0SET3, 4); 147 break; 148 149 case SMP_CALL_FUNCTION: 150 if (cpu == 1) 151 OCD_WRITE(RM9000x2_OCD_INTP1SET3, 2); 152 else 153 OCD_WRITE(RM9000x2_OCD_INTP0SET3, 2); 154 break; 155 } 156} 157