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/init.h> 9 #include <linux/delay.h> 10 #include <linux/smp.h> 11 #include <linux/interrupt.h> 12 #include <linux/kernel_stat.h> 13 #include <linux/sched.h> 14 #include <linux/module.h> 15 16 #include <asm/mmu_context.h> 17 #include <asm/system.h> 18 #include <asm/time.h> 19 20 #include <asm/octeon/octeon.h> 21 22 volatile unsigned long octeon_processor_boot = 0xff; 23 volatile unsigned long octeon_processor_sp; 24 volatile unsigned long octeon_processor_gp; 25 26 static irqreturn_t mailbox_interrupt(int irq, void *dev_id) 27 { 28 const int coreid = cvmx_get_core_num(); 29 uint64_t action; 30 31 /* Load the mailbox register to figure out what we're supposed to do */ 32 action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid)); 33 34 /* Clear the mailbox to clear the interrupt */ 35 cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action); 36 37 if (action & SMP_CALL_FUNCTION) 38 smp_call_function_interrupt(); 39 40 /* Check if we've been told to flush the icache */ 41 if (action & SMP_ICACHE_FLUSH) 42 asm volatile ("synci 0($0)\n"); 43 return IRQ_HANDLED; 44 } 45 46 /** 47 * Cause the function described by call_data to be executed on the passed 48 * cpu. When the function has finished, increment the finished field of 49 * call_data. 50 */ 51 void octeon_send_ipi_single(int cpu, unsigned int action) 52 { 53 int coreid = cpu_logical_map(cpu); 54 /* 55 pr_info("SMP: Mailbox send cpu=%d, coreid=%d, action=%u\n", cpu, 56 coreid, action); 57 */ 58 cvmx_write_csr(CVMX_CIU_MBOX_SETX(coreid), action); 59 } 60 61 static inline void octeon_send_ipi_mask(cpumask_t mask, unsigned int action) 62 { 63 unsigned int i; 64 65 for_each_cpu_mask(i, mask) 66 octeon_send_ipi_single(i, action); 67 } 68 69 /** 70 * Detect available CPUs, populate phys_cpu_present_map 71 */ 72 static void octeon_smp_setup(void) 73 { 74 const int coreid = cvmx_get_core_num(); 75 int cpus; 76 int id; 77 78 int core_mask = octeon_get_boot_coremask(); 79 80 cpus_clear(cpu_possible_map); 81 __cpu_number_map[coreid] = 0; 82 __cpu_logical_map[0] = coreid; 83 cpu_set(0, cpu_possible_map); 84 85 cpus = 1; 86 for (id = 0; id < 16; id++) { 87 if ((id != coreid) && (core_mask & (1 << id))) { 88 cpu_set(cpus, cpu_possible_map); 89 __cpu_number_map[id] = cpus; 90 __cpu_logical_map[cpus] = id; 91 cpus++; 92 } 93 } 94 } 95 96 /** 97 * Firmware CPU startup hook 98 * 99 */ 100 static void octeon_boot_secondary(int cpu, struct task_struct *idle) 101 { 102 int count; 103 104 pr_info("SMP: Booting CPU%02d (CoreId %2d)...\n", cpu, 105 cpu_logical_map(cpu)); 106 107 octeon_processor_sp = __KSTK_TOS(idle); 108 octeon_processor_gp = (unsigned long)(task_thread_info(idle)); 109 octeon_processor_boot = cpu_logical_map(cpu); 110 mb(); 111 112 count = 10000; 113 while (octeon_processor_sp && count) { 114 /* Waiting for processor to get the SP and GP */ 115 udelay(1); 116 count--; 117 } 118 if (count == 0) 119 pr_err("Secondary boot timeout\n"); 120 } 121 122 /** 123 * After we've done initial boot, this function is called to allow the 124 * board code to clean up state, if needed 125 */ 126 static void octeon_init_secondary(void) 127 { 128 const int coreid = cvmx_get_core_num(); 129 union cvmx_ciu_intx_sum0 interrupt_enable; 130 131 octeon_check_cpu_bist(); 132 octeon_init_cvmcount(); 133 /* 134 pr_info("SMP: CPU%d (CoreId %lu) started\n", cpu, coreid); 135 */ 136 /* Enable Mailbox interrupts to this core. These are the only 137 interrupts allowed on line 3 */ 138 cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), 0xffffffff); 139 interrupt_enable.u64 = 0; 140 interrupt_enable.s.mbox = 0x3; 141 cvmx_write_csr(CVMX_CIU_INTX_EN0((coreid * 2)), interrupt_enable.u64); 142 cvmx_write_csr(CVMX_CIU_INTX_EN0((coreid * 2 + 1)), 0); 143 cvmx_write_csr(CVMX_CIU_INTX_EN1((coreid * 2)), 0); 144 cvmx_write_csr(CVMX_CIU_INTX_EN1((coreid * 2 + 1)), 0); 145 /* Enable core interrupt processing for 2,3 and 7 */ 146 set_c0_status(0x8c01); 147 } 148 149 /** 150 * Callout to firmware before smp_init 151 * 152 */ 153 void octeon_prepare_cpus(unsigned int max_cpus) 154 { 155 cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffffffff); 156 if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt, IRQF_SHARED, 157 "mailbox0", mailbox_interrupt)) { 158 panic("Cannot request_irq(OCTEON_IRQ_MBOX0)\n"); 159 } 160 if (request_irq(OCTEON_IRQ_MBOX1, mailbox_interrupt, IRQF_SHARED, 161 "mailbox1", mailbox_interrupt)) { 162 panic("Cannot request_irq(OCTEON_IRQ_MBOX1)\n"); 163 } 164 } 165 166 /** 167 * Last chance for the board code to finish SMP initialization before 168 * the CPU is "online". 169 */ 170 static void octeon_smp_finish(void) 171 { 172 #ifdef CONFIG_CAVIUM_GDB 173 unsigned long tmp; 174 /* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also set the MCD0 175 to be not masked by this core so we know the signal is received by 176 someone */ 177 asm volatile ("dmfc0 %0, $22\n" 178 "ori %0, %0, 0x9100\n" "dmtc0 %0, $22\n" : "=r" (tmp)); 179 #endif 180 181 octeon_user_io_init(); 182 183 /* to generate the first CPU timer interrupt */ 184 write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ); 185 } 186 187 /** 188 * Hook for after all CPUs are online 189 */ 190 static void octeon_cpus_done(void) 191 { 192 #ifdef CONFIG_CAVIUM_GDB 193 unsigned long tmp; 194 /* Pulse MCD0 signal on Ctrl-C to stop all the cores. Also set the MCD0 195 to be not masked by this core so we know the signal is received by 196 someone */ 197 asm volatile ("dmfc0 %0, $22\n" 198 "ori %0, %0, 0x9100\n" "dmtc0 %0, $22\n" : "=r" (tmp)); 199 #endif 200 } 201 202 struct plat_smp_ops octeon_smp_ops = { 203 .send_ipi_single = octeon_send_ipi_single, 204 .send_ipi_mask = octeon_send_ipi_mask, 205 .init_secondary = octeon_init_secondary, 206 .smp_finish = octeon_smp_finish, 207 .cpus_done = octeon_cpus_done, 208 .boot_secondary = octeon_boot_secondary, 209 .smp_setup = octeon_smp_setup, 210 .prepare_cpus = octeon_prepare_cpus, 211 }; 212