Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights |
| 3 | * reserved. |
| 4 | * |
| 5 | * This software is available to you under a choice of one of two |
| 6 | * licenses. You may choose to be licensed under the terms of the GNU |
| 7 | * General Public License (GPL) Version 2, available from the file |
| 8 | * COPYING in the main directory of this source tree, or the NetLogic |
| 9 | * license below: |
| 10 | * |
| 11 | * Redistribution and use in source and binary forms, with or without |
| 12 | * modification, are permitted provided that the following conditions |
| 13 | * are met: |
| 14 | * |
| 15 | * 1. Redistributions of source code must retain the above copyright |
| 16 | * notice, this list of conditions and the following disclaimer. |
| 17 | * 2. Redistributions in binary form must reproduce the above copyright |
| 18 | * notice, this list of conditions and the following disclaimer in |
| 19 | * the documentation and/or other materials provided with the |
| 20 | * distribution. |
| 21 | * |
| 22 | * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR |
| 23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 25 | * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE |
| 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| 29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| 30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| 31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| 32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 33 | */ |
| 34 | |
| 35 | #include <linux/kernel.h> |
| 36 | #include <linux/delay.h> |
| 37 | #include <linux/init.h> |
| 38 | #include <linux/smp.h> |
| 39 | #include <linux/irq.h> |
| 40 | |
| 41 | #include <asm/mmu_context.h> |
| 42 | |
| 43 | #include <asm/netlogic/interrupt.h> |
| 44 | #include <asm/netlogic/mips-extns.h> |
Jayachandran C | 0c96540 | 2011-11-11 17:08:29 +0530 | [diff] [blame] | 45 | #include <asm/netlogic/haldefs.h> |
| 46 | #include <asm/netlogic/common.h> |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 47 | |
Jayachandran C | 65040e2 | 2011-11-16 00:21:28 +0000 | [diff] [blame] | 48 | #if defined(CONFIG_CPU_XLP) |
| 49 | #include <asm/netlogic/xlp-hal/iomap.h> |
Jayachandran C | 66d2998 | 2011-11-16 00:21:29 +0000 | [diff] [blame] | 50 | #include <asm/netlogic/xlp-hal/xlp.h> |
Jayachandran C | 65040e2 | 2011-11-16 00:21:28 +0000 | [diff] [blame] | 51 | #include <asm/netlogic/xlp-hal/pic.h> |
| 52 | #elif defined(CONFIG_CPU_XLR) |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 53 | #include <asm/netlogic/xlr/iomap.h> |
| 54 | #include <asm/netlogic/xlr/pic.h> |
Jayachandran C | 66d2998 | 2011-11-16 00:21:29 +0000 | [diff] [blame] | 55 | #include <asm/netlogic/xlr/xlr.h> |
Jayachandran C | 65040e2 | 2011-11-16 00:21:28 +0000 | [diff] [blame] | 56 | #else |
| 57 | #error "Unknown CPU" |
| 58 | #endif |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 59 | |
Jayachandran C | 0c96540 | 2011-11-11 17:08:29 +0530 | [diff] [blame] | 60 | void nlm_send_ipi_single(int logical_cpu, unsigned int action) |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 61 | { |
| 62 | int cpu = cpu_logical_map(logical_cpu); |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 63 | |
| 64 | if (action & SMP_CALL_FUNCTION) |
Jayachandran C | 0c96540 | 2011-11-11 17:08:29 +0530 | [diff] [blame] | 65 | nlm_pic_send_ipi(nlm_pic_base, cpu, IRQ_IPI_SMP_FUNCTION, 0); |
| 66 | if (action & SMP_RESCHEDULE_YOURSELF) |
| 67 | nlm_pic_send_ipi(nlm_pic_base, cpu, IRQ_IPI_SMP_RESCHEDULE, 0); |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) |
| 71 | { |
| 72 | int cpu; |
| 73 | |
| 74 | for_each_cpu(cpu, mask) { |
Jayachandran C | 0c96540 | 2011-11-11 17:08:29 +0530 | [diff] [blame] | 75 | nlm_send_ipi_single(cpu, action); |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 76 | } |
| 77 | } |
| 78 | |
| 79 | /* IRQ_IPI_SMP_FUNCTION Handler */ |
| 80 | void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) |
| 81 | { |
Jayachandran C | 0c96540 | 2011-11-11 17:08:29 +0530 | [diff] [blame] | 82 | write_c0_eirr(1ull << irq); |
Jayachandran C | 65040e2 | 2011-11-16 00:21:28 +0000 | [diff] [blame] | 83 | smp_call_function_interrupt(); |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | /* IRQ_IPI_SMP_RESCHEDULE handler */ |
| 87 | void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc) |
| 88 | { |
Jayachandran C | 0c96540 | 2011-11-11 17:08:29 +0530 | [diff] [blame] | 89 | write_c0_eirr(1ull << irq); |
Jayachandran C | 65040e2 | 2011-11-16 00:21:28 +0000 | [diff] [blame] | 90 | scheduler_ipi(); |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | /* |
| 94 | * Called before going into mips code, early cpu init |
| 95 | */ |
Jayachandran C | 0c96540 | 2011-11-11 17:08:29 +0530 | [diff] [blame] | 96 | void nlm_early_init_secondary(int cpu) |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 97 | { |
Jayachandran C | 65040e2 | 2011-11-16 00:21:28 +0000 | [diff] [blame] | 98 | change_c0_config(CONF_CM_CMASK, 0x3); |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 99 | write_c0_ebase((uint32_t)nlm_common_ebase); |
Jayachandran C | 65040e2 | 2011-11-16 00:21:28 +0000 | [diff] [blame] | 100 | #ifdef CONFIG_CPU_XLP |
Jayachandran C | feddaf7 | 2012-10-31 12:01:35 +0000 | [diff] [blame] | 101 | if (cpu % 4 == 0) |
Jayachandran C | 0c96540 | 2011-11-11 17:08:29 +0530 | [diff] [blame] | 102 | xlp_mmu_init(); |
| 103 | #endif |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 104 | } |
| 105 | |
| 106 | /* |
| 107 | * Code to run on secondary just after probing the CPU |
| 108 | */ |
| 109 | static void __cpuinit nlm_init_secondary(void) |
| 110 | { |
Hillf Danton | b3ea581 | 2011-11-16 00:21:29 +0000 | [diff] [blame] | 111 | current_cpu_data.core = hard_smp_processor_id() / 4; |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 112 | nlm_smp_irq_init(); |
| 113 | } |
| 114 | |
Hillf Danton | b3ea581 | 2011-11-16 00:21:29 +0000 | [diff] [blame] | 115 | void nlm_prepare_cpus(unsigned int max_cpus) |
| 116 | { |
| 117 | /* declare we are SMT capable */ |
| 118 | smp_num_siblings = nlm_threads_per_core; |
| 119 | } |
| 120 | |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 121 | void nlm_smp_finish(void) |
| 122 | { |
| 123 | #ifdef notyet |
| 124 | nlm_common_msgring_cpu_init(); |
| 125 | #endif |
Jayachandran C | 39263ee | 2011-06-07 03:14:12 +0530 | [diff] [blame] | 126 | local_irq_enable(); |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 127 | } |
| 128 | |
| 129 | void nlm_cpus_done(void) |
| 130 | { |
| 131 | } |
| 132 | |
| 133 | /* |
| 134 | * Boot all other cpus in the system, initialize them, and bring them into |
| 135 | * the boot function |
| 136 | */ |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 137 | int nlm_cpu_ready[NR_CPUS]; |
| 138 | unsigned long nlm_next_gp; |
| 139 | unsigned long nlm_next_sp; |
Jayachandran C | 66d2998 | 2011-11-16 00:21:29 +0000 | [diff] [blame] | 140 | |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 141 | cpumask_t phys_cpu_present_map; |
| 142 | |
| 143 | void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) |
| 144 | { |
| 145 | unsigned long gp = (unsigned long)task_thread_info(idle); |
| 146 | unsigned long sp = (unsigned long)__KSTK_TOS(idle); |
| 147 | int cpu = cpu_logical_map(logical_cpu); |
| 148 | |
| 149 | nlm_next_sp = sp; |
| 150 | nlm_next_gp = gp; |
| 151 | |
| 152 | /* barrier */ |
| 153 | __sync(); |
Jayachandran C | 66d2998 | 2011-11-16 00:21:29 +0000 | [diff] [blame] | 154 | nlm_pic_send_ipi(nlm_pic_base, cpu, 1, 1); |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 155 | } |
| 156 | |
| 157 | void __init nlm_smp_setup(void) |
| 158 | { |
| 159 | unsigned int boot_cpu; |
| 160 | int num_cpus, i; |
| 161 | |
| 162 | boot_cpu = hard_smp_processor_id(); |
| 163 | cpus_clear(phys_cpu_present_map); |
| 164 | |
| 165 | cpu_set(boot_cpu, phys_cpu_present_map); |
| 166 | __cpu_number_map[boot_cpu] = 0; |
| 167 | __cpu_logical_map[0] = boot_cpu; |
Rusty Russell | 0b5f9c0 | 2012-03-29 15:38:30 +1030 | [diff] [blame] | 168 | set_cpu_possible(0, true); |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 169 | |
| 170 | num_cpus = 1; |
| 171 | for (i = 0; i < NR_CPUS; i++) { |
Hillf Danton | b278896 | 2011-09-24 02:29:54 +0200 | [diff] [blame] | 172 | /* |
Jayachandran C | 0c96540 | 2011-11-11 17:08:29 +0530 | [diff] [blame] | 173 | * nlm_cpu_ready array is not set for the boot_cpu, |
| 174 | * it is only set for ASPs (see smpboot.S) |
Hillf Danton | b278896 | 2011-09-24 02:29:54 +0200 | [diff] [blame] | 175 | */ |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 176 | if (nlm_cpu_ready[i]) { |
| 177 | cpu_set(i, phys_cpu_present_map); |
| 178 | __cpu_number_map[i] = num_cpus; |
| 179 | __cpu_logical_map[num_cpus] = i; |
Rusty Russell | 0b5f9c0 | 2012-03-29 15:38:30 +1030 | [diff] [blame] | 180 | set_cpu_possible(num_cpus, true); |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 181 | ++num_cpus; |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | pr_info("Phys CPU present map: %lx, possible map %lx\n", |
| 186 | (unsigned long)phys_cpu_present_map.bits[0], |
Rusty Russell | 0b5f9c0 | 2012-03-29 15:38:30 +1030 | [diff] [blame] | 187 | (unsigned long)cpumask_bits(cpu_possible_mask)[0]); |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 188 | |
| 189 | pr_info("Detected %i Slave CPU(s)\n", num_cpus); |
Jayachandran C | 66d2998 | 2011-11-16 00:21:29 +0000 | [diff] [blame] | 190 | nlm_set_nmi_handler(nlm_boot_secondary_cpus); |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 191 | } |
| 192 | |
Jayachandran C | 66d2998 | 2011-11-16 00:21:29 +0000 | [diff] [blame] | 193 | static int nlm_parse_cpumask(u32 cpu_mask) |
| 194 | { |
| 195 | uint32_t core0_thr_mask, core_thr_mask; |
| 196 | int threadmode, i; |
| 197 | |
| 198 | core0_thr_mask = cpu_mask & 0xf; |
| 199 | switch (core0_thr_mask) { |
| 200 | case 1: |
| 201 | nlm_threads_per_core = 1; |
| 202 | threadmode = 0; |
| 203 | break; |
| 204 | case 3: |
| 205 | nlm_threads_per_core = 2; |
| 206 | threadmode = 2; |
| 207 | break; |
| 208 | case 0xf: |
| 209 | nlm_threads_per_core = 4; |
| 210 | threadmode = 3; |
| 211 | break; |
| 212 | default: |
| 213 | goto unsupp; |
| 214 | } |
| 215 | |
| 216 | /* Verify other cores CPU masks */ |
| 217 | nlm_coremask = 1; |
| 218 | nlm_cpumask = core0_thr_mask; |
| 219 | for (i = 1; i < 8; i++) { |
| 220 | core_thr_mask = (cpu_mask >> (i * 4)) & 0xf; |
| 221 | if (core_thr_mask) { |
| 222 | if (core_thr_mask != core0_thr_mask) |
| 223 | goto unsupp; |
| 224 | nlm_coremask |= 1 << i; |
| 225 | nlm_cpumask |= core0_thr_mask << (4 * i); |
| 226 | } |
| 227 | } |
| 228 | return threadmode; |
| 229 | |
| 230 | unsupp: |
| 231 | panic("Unsupported CPU mask %x\n", cpu_mask); |
| 232 | return 0; |
| 233 | } |
| 234 | |
| 235 | int __cpuinit nlm_wakeup_secondary_cpus(u32 wakeup_mask) |
| 236 | { |
| 237 | unsigned long reset_vec; |
| 238 | char *reset_data; |
| 239 | int threadmode; |
| 240 | |
| 241 | /* Update reset entry point with CPU init code */ |
| 242 | reset_vec = CKSEG1ADDR(RESET_VEC_PHYS); |
| 243 | memcpy((void *)reset_vec, (void *)nlm_reset_entry, |
| 244 | (nlm_reset_entry_end - nlm_reset_entry)); |
| 245 | |
| 246 | /* verify the mask and setup core config variables */ |
| 247 | threadmode = nlm_parse_cpumask(wakeup_mask); |
| 248 | |
| 249 | /* Setup CPU init parameters */ |
| 250 | reset_data = (char *)CKSEG1ADDR(RESET_DATA_PHYS); |
| 251 | *(int *)(reset_data + BOOT_THREAD_MODE) = threadmode; |
| 252 | |
| 253 | #ifdef CONFIG_CPU_XLP |
| 254 | xlp_wakeup_secondary_cpus(); |
| 255 | #else |
| 256 | xlr_wakeup_secondary_cpus(); |
| 257 | #endif |
| 258 | return 0; |
| 259 | } |
| 260 | |
Jayachandran C | 5c6425067 | 2011-05-07 01:36:40 +0530 | [diff] [blame] | 261 | struct plat_smp_ops nlm_smp_ops = { |
| 262 | .send_ipi_single = nlm_send_ipi_single, |
| 263 | .send_ipi_mask = nlm_send_ipi_mask, |
| 264 | .init_secondary = nlm_init_secondary, |
| 265 | .smp_finish = nlm_smp_finish, |
| 266 | .cpus_done = nlm_cpus_done, |
| 267 | .boot_secondary = nlm_boot_secondary, |
| 268 | .smp_setup = nlm_smp_setup, |
| 269 | .prepare_cpus = nlm_prepare_cpus, |
| 270 | }; |