1/*- 2 * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com> 3 * Copyright (c) 2012-2015 Robert N. M. Watson 4 * Copyright (c) 2013 SRI International 5 * All rights reserved. 6 * 7 * This software was developed by SRI International and the University of 8 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 9 * ("CTSRD"), as part of the DARPA CRASH research programme. 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 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD$"); 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/smp.h> 39 40#include <machine/hwfunc.h> 41#include <machine/smp.h> 42 43#include <mips/beri/beri_mp.h> 44 45#include <dev/fdt/fdt_common.h> 46 47struct spin_entry { 48 uint64_t entry_addr; 49 uint64_t a0; 50 uint32_t rsvd1; 51 uint32_t pir; 52 uint64_t rsvd2; 53}; 54 55static phandle_t cpu_of_nodes[MAXCPU]; 56static device_t picmap[MAXCPU]; 57 58int 59platform_processor_id(void) 60{ 61 int cpu; 62 63 cpu = beri_get_cpu(); 64 65 return (cpu); 66} 67 68void 69platform_cpu_mask(cpuset_t *mask) 70{ 71 int ncores, ncpus, nthreads; 72 phandle_t cpus, cpu; 73 pcell_t reg; 74 char prop[16]; 75 struct spin_entry *se; 76 77 ncores = beri_get_ncores(); 78 nthreads = beri_get_nthreads(); 79 KASSERT(ncores <= 0x10000, ("%s: too many cores %d", __func__, ncores)); 80 KASSERT(nthreads <= 0x10000, ("%s: too many threads %d", __func__, 81 nthreads)); 82 KASSERT(ncores < 0xffff || nthreads < 0xffff, 83 ("%s: cores x thread (%d x %d) would overflow", __func__, ncores, 84 nthreads)); 85 ncpus = ncores * nthreads; 86 if (MAXCPU > 1 && ncpus > MAXCPU) 87 printf("%s: Hardware supports more CPUs (%d) than kernel (%d)\n", 88 __func__, ncpus, MAXCPU); 89 printf("%s: hardware has %d cores with %d threads each\n", __func__, 90 ncores, nthreads); 91 92 if ((cpus = OF_finddevice("/cpus")) <= 0) { 93 printf("%s: no \"/cpus\" device found in FDT\n", __func__); 94 goto error; 95 } 96 if ((cpu = OF_child(cpus)) <= 0) { 97 printf("%s: no children of \"/cpus\" found in FDT\n", __func__); 98 goto error; 99 } 100 CPU_ZERO(mask); 101 do { 102 if (OF_getprop(cpu, "reg", ®, sizeof(reg)) <= 0) { 103 printf("%s: cpu device with no reg property\n", 104 __func__); 105 goto error; 106 } 107 if (reg > MAXCPU) { 108 printf("%s: cpu ID too large (%d > %d)\n", __func__, 109 reg, MAXCPU); 110 continue; 111 } 112 cpu_of_nodes[reg] = cpu; 113 114 if (reg != 0) { 115 if (OF_getprop(cpu, "enable-method", &prop, 116 sizeof(prop)) <= 0 && OF_getprop(OF_parent(cpu), 117 "enable-method", &prop, sizeof(prop)) <= 0) { 118 printf("%s: CPU %d has no enable-method " 119 "property\n", __func__, reg); 120 continue; 121 } 122 if (strcmp("spin-table", prop) != 0) { 123 printf("%s: CPU %d enable-method is '%s' not " 124 "'spin-table'\n", __func__, reg, prop); 125 continue; 126 } 127 128 if (OF_getprop(cpu, "cpu-release-addr", &se, 129 sizeof(se)) <= 0) { 130 printf("%s: CPU %d has missing or invalid " 131 "cpu-release-addr\n", __func__, reg); 132 continue; 133 } 134 if (se->entry_addr != 1) { 135 printf("%s: CPU %d has uninitialized spin " 136 "entry\n", __func__, reg); 137 continue; 138 } 139 } 140 141 CPU_SET(reg, mask); 142 } while ((cpu = OF_peer(cpu)) > 0); 143 return; 144 145error: 146 /* 147 * If we run into any problems determining the CPU layout, 148 * fall back to UP. 149 * 150 * XXX: panic instead? 151 */ 152 CPU_ZERO(mask); 153 CPU_SET(0, mask); 154} 155 156void 157platform_init_secondary(int cpuid) 158{ 159 device_t ic; 160 int ipi; 161 162 ipi = platform_ipi_hardintr_num(); 163 164 ic = devclass_get_device(devclass_find("beripic"), cpuid); 165 picmap[cpuid] = ic; 166 beripic_setup_ipi(ic, cpuid, ipi); 167 168 /* Unmask the interrupt */ 169 if (cpuid != 0) { 170 mips_wr_status(mips_rd_status() | (((1 << ipi) << 8) << 2)); 171 } 172} 173 174void 175platform_ipi_send(int cpuid) 176{ 177 178 mips_sync(); /* Ordering, liveness. */ 179 180 beripic_send_ipi(picmap[cpuid], cpuid); 181} 182 183void 184platform_ipi_clear(void) 185{ 186 int cpuid; 187 188 cpuid = platform_processor_id(); 189 190 beripic_clear_ipi(picmap[cpuid], cpuid); 191} 192 193/* 194 * XXXBED: Set via FDT? 195 */ 196int 197platform_ipi_hardintr_num(void) 198{ 199 200 return (4); 201} 202 203int 204platform_ipi_softintr_num(void) 205{ 206 207 return (-1); 208} 209 210/* 211 * XXXBED: Fine for MT, will need something better for multi-core. 212 */ 213struct cpu_group * 214platform_smp_topo(void) 215{ 216 217 return (smp_topo_none()); 218} 219 220void 221platform_init_ap(int cpuid) 222{ 223 uint32_t status; 224 u_int clock_int_mask; 225 226 KASSERT(cpuid < MAXCPU, ("%s: invalid CPU id %d", __func__, cpuid)); 227 228 /* Make sure coprocessors are enabled. */ 229 status = mips_rd_status(); 230 status |= (MIPS_SR_COP_0_BIT | MIPS_SR_COP_1_BIT); 231#if defined(CPU_CHERI) 232 status |= MIPS_SR_COP_2_BIT; 233#endif 234 mips_wr_status(status); 235 236#if 0 237 register_t hwrena; 238 /* Enable HDWRD instruction in userspace. Also enables statcounters. */ 239 hwrena = mips_rd_hwrena(); 240 hwrena |= (MIPS_HWRENA_CC | MIPS_HWRENA_CCRES | MIPS_HWRENA_CPUNUM | 241 MIPS_HWRENA_BERI_STATCOUNTERS_MASK); 242 mips_wr_hwrena(hwrena); 243#endif 244 245 /* 246 * Enable per-thread timer. 247 */ 248 clock_int_mask = hard_int_mask(5); 249 set_intr_mask(clock_int_mask); 250} 251 252/* 253 * BERI startup conforms to the spin-table start method defined in the 254 * ePAPR 1.0 spec. The initial spin waiting for an address is started 255 * by the CPU firmware. 256 */ 257int 258platform_start_ap(int cpuid) 259{ 260 phandle_t cpu; 261 char prop[16]; 262 struct spin_entry *se; 263 264 KASSERT(cpuid != 0, ("%s: can't start CPU 0!\n", __func__)); 265 KASSERT((cpuid > 0 && cpuid < MAXCPU), 266 ("%s: invalid CPU id %d", __func__, cpuid)); 267 268 cpu = cpu_of_nodes[cpuid]; 269 if (OF_getprop(cpu, "status", &prop, sizeof(prop)) <= 0) { 270 if (bootverbose) 271 printf("%s: CPU %d has no status property, " 272 "trying parent\n", __func__, cpuid); 273 if (OF_getprop(OF_parent(cpu), "status", &prop, 274 sizeof(prop)) <= 0) 275 panic("%s: CPU %d has no status property", __func__, 276 cpuid); 277 } 278 if (strcmp("disabled", prop) != 0) 279 panic("%s: CPU %d status is '%s' not 'disabled'", 280 __func__, cpuid, prop); 281 282 if (OF_getprop(cpu, "enable-method", &prop, sizeof(prop)) <= 0) { 283 if (bootverbose) 284 printf("%s: CPU %d has no enable-method, " 285 "trying parent\n", __func__, cpuid); 286 if (OF_getprop(OF_parent(cpu), "enable-method", &prop, 287 sizeof(prop)) <= 0) 288 panic("%s: CPU %d has no enable-method property", 289 __func__, cpuid); 290 } 291 if (strcmp("spin-table", prop) != 0) 292 panic("%s: CPU %d enable-method is '%s' not " 293 "'spin-table'", __func__, cpuid, prop); 294 295 if (OF_getprop(cpu, "cpu-release-addr", &se, sizeof(se)) <= 0) 296 panic("%s: CPU %d has missing or invalid cpu-release-addr", 297 __func__, cpuid); 298 se->pir = cpuid; 299 if (bootverbose) 300 printf("%s: writing %p to %p\n", __func__, mpentry, 301 &se->entry_addr); 302 303 mips_sync(); /* Ordering. */ 304 se->entry_addr = (intptr_t)mpentry; 305 mips_sync(); /* Liveness. */ 306 307 return (0); 308} 309