1 /*- 2 * Copyright (c) 2015 Nathan Whitehorn 3 * Copyright (c) 2017-2018 Semihalf 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/bus.h> 35 #include <sys/pcpu.h> 36 #include <sys/proc.h> 37 #include <sys/smp.h> 38 #include <vm/vm.h> 39 #include <vm/pmap.h> 40 41 #include <machine/bus.h> 42 #include <machine/cpu.h> 43 #include <machine/hid.h> 44 #include <machine/platformvar.h> 45 #include <machine/pmap.h> 46 #include <machine/rtas.h> 47 #include <machine/smp.h> 48 #include <machine/spr.h> 49 #include <machine/trap.h> 50 51 #include <dev/ofw/openfirm.h> 52 #include <machine/ofw_machdep.h> 53 #include <powerpc/aim/mmu_oea64.h> 54 55 #include "platform_if.h" 56 #include "opal.h" 57 58 #ifdef SMP 59 extern void *ap_pcpu; 60 #endif 61 62 void (*powernv_smp_ap_extra_init)(void); 63 64 static int powernv_probe(platform_t); 65 static int powernv_attach(platform_t); 66 void powernv_mem_regions(platform_t, struct mem_region *phys, int *physsz, 67 struct mem_region *avail, int *availsz); 68 static u_long powernv_timebase_freq(platform_t, struct cpuref *cpuref); 69 static int powernv_smp_first_cpu(platform_t, struct cpuref *cpuref); 70 static int powernv_smp_next_cpu(platform_t, struct cpuref *cpuref); 71 static int powernv_smp_get_bsp(platform_t, struct cpuref *cpuref); 72 static void powernv_smp_ap_init(platform_t); 73 #ifdef SMP 74 static int powernv_smp_start_cpu(platform_t, struct pcpu *cpu); 75 static void powernv_smp_probe_threads(platform_t); 76 static struct cpu_group *powernv_smp_topo(platform_t plat); 77 #endif 78 static void powernv_reset(platform_t); 79 static void powernv_cpu_idle(sbintime_t sbt); 80 static int powernv_cpuref_init(void); 81 82 static platform_method_t powernv_methods[] = { 83 PLATFORMMETHOD(platform_probe, powernv_probe), 84 PLATFORMMETHOD(platform_attach, powernv_attach), 85 PLATFORMMETHOD(platform_mem_regions, powernv_mem_regions), 86 PLATFORMMETHOD(platform_timebase_freq, powernv_timebase_freq), 87 88 PLATFORMMETHOD(platform_smp_ap_init, powernv_smp_ap_init), 89 PLATFORMMETHOD(platform_smp_first_cpu, powernv_smp_first_cpu), 90 PLATFORMMETHOD(platform_smp_next_cpu, powernv_smp_next_cpu), 91 PLATFORMMETHOD(platform_smp_get_bsp, powernv_smp_get_bsp), 92 #ifdef SMP 93 PLATFORMMETHOD(platform_smp_start_cpu, powernv_smp_start_cpu), 94 PLATFORMMETHOD(platform_smp_probe_threads, powernv_smp_probe_threads), 95 PLATFORMMETHOD(platform_smp_topo, powernv_smp_topo), 96 #endif 97 98 PLATFORMMETHOD(platform_reset, powernv_reset), 99 100 { 0, 0 } 101 }; 102 103 static platform_def_t powernv_platform = { 104 "powernv", 105 powernv_methods, 106 0 107 }; 108 109 static struct cpuref platform_cpuref[MAXCPU]; 110 static int platform_cpuref_cnt; 111 static int platform_cpuref_valid; 112 113 PLATFORM_DEF(powernv_platform); 114 115 static uint64_t powernv_boot_pir; 116 117 static int 118 powernv_probe(platform_t plat) 119 { 120 if (opal_check() == 0) 121 return (BUS_PROBE_SPECIFIC); 122 123 return (ENXIO); 124 } 125 126 static int 127 powernv_attach(platform_t plat) 128 { 129 uint32_t nptlp, shift = 0, slb_encoding = 0; 130 int32_t lp_size, lp_encoding; 131 char buf[255]; 132 pcell_t prop; 133 phandle_t cpu; 134 int res, len, idx; 135 register_t msr; 136 137 /* Ping OPAL again just to make sure */ 138 opal_check(); 139 140 #if BYTE_ORDER == LITTLE_ENDIAN 141 opal_call(OPAL_REINIT_CPUS, 2 /* Little endian */); 142 #else 143 opal_call(OPAL_REINIT_CPUS, 1 /* Big endian */); 144 #endif 145 146 if (cpu_idle_hook == NULL) 147 cpu_idle_hook = powernv_cpu_idle; 148 149 powernv_boot_pir = mfspr(SPR_PIR); 150 151 /* LPID must not be altered when PSL_DR or PSL_IR is set */ 152 msr = mfmsr(); 153 mtmsr(msr & ~(PSL_DR | PSL_IR)); 154 155 /* Direct interrupts to SRR instead of HSRR and reset LPCR otherwise */ 156 mtspr(SPR_LPID, 0); 157 isync(); 158 159 if (cpu_features2 & PPC_FEATURE2_ARCH_3_00) 160 lpcr |= LPCR_HVICE; 161 162 mtspr(SPR_LPCR, lpcr); 163 isync(); 164 165 mtmsr(msr); 166 167 powernv_cpuref_init(); 168 169 /* Set SLB count from device tree */ 170 cpu = OF_peer(0); 171 cpu = OF_child(cpu); 172 while (cpu != 0) { 173 res = OF_getprop(cpu, "name", buf, sizeof(buf)); 174 if (res > 0 && strcmp(buf, "cpus") == 0) 175 break; 176 cpu = OF_peer(cpu); 177 } 178 if (cpu == 0) 179 goto out; 180 181 cpu = OF_child(cpu); 182 while (cpu != 0) { 183 res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 184 if (res > 0 && strcmp(buf, "cpu") == 0) 185 break; 186 cpu = OF_peer(cpu); 187 } 188 if (cpu == 0) 189 goto out; 190 191 res = OF_getencprop(cpu, "ibm,slb-size", &prop, sizeof(prop)); 192 if (res > 0) 193 n_slbs = prop; 194 195 /* 196 * Scan the large page size property for PAPR compatible machines. 197 * See PAPR D.5 Changes to Section 5.1.4, 'CPU Node Properties' 198 * for the encoding of the property. 199 */ 200 201 len = OF_getproplen(cpu, "ibm,segment-page-sizes"); 202 if (len > 0) { 203 /* 204 * We have to use a variable length array on the stack 205 * since we have very limited stack space. 206 */ 207 pcell_t arr[len/sizeof(cell_t)]; 208 res = OF_getencprop(cpu, "ibm,segment-page-sizes", arr, 209 sizeof(arr)); 210 len /= 4; 211 idx = 0; 212 while (len > 0) { 213 shift = arr[idx]; 214 slb_encoding = arr[idx + 1]; 215 nptlp = arr[idx + 2]; 216 idx += 3; 217 len -= 3; 218 while (len > 0 && nptlp) { 219 lp_size = arr[idx]; 220 lp_encoding = arr[idx+1]; 221 if (slb_encoding == SLBV_L && lp_encoding == 0) 222 break; 223 224 idx += 2; 225 len -= 2; 226 nptlp--; 227 } 228 if (nptlp && slb_encoding == SLBV_L && lp_encoding == 0) 229 break; 230 } 231 232 if (len == 0) 233 panic("Standard large pages (SLB[L] = 1, PTE[LP] = 0) " 234 "not supported by this system."); 235 236 moea64_large_page_shift = shift; 237 moea64_large_page_size = 1ULL << lp_size; 238 } 239 240 out: 241 return (0); 242 } 243 244 245 void 246 powernv_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 247 struct mem_region *avail, int *availsz) 248 { 249 250 ofw_mem_regions(phys, physsz, avail, availsz); 251 } 252 253 static u_long 254 powernv_timebase_freq(platform_t plat, struct cpuref *cpuref) 255 { 256 char buf[8]; 257 phandle_t cpu, dev, root; 258 int res; 259 int32_t ticks = -1; 260 261 root = OF_peer(0); 262 dev = OF_child(root); 263 while (dev != 0) { 264 res = OF_getprop(dev, "name", buf, sizeof(buf)); 265 if (res > 0 && strcmp(buf, "cpus") == 0) 266 break; 267 dev = OF_peer(dev); 268 } 269 270 for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) { 271 res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 272 if (res > 0 && strcmp(buf, "cpu") == 0) 273 break; 274 } 275 if (cpu == 0) 276 return (512000000); 277 278 OF_getencprop(cpu, "timebase-frequency", &ticks, sizeof(ticks)); 279 280 if (ticks <= 0) 281 panic("Unable to determine timebase frequency!"); 282 283 return (ticks); 284 285 } 286 287 static int 288 powernv_cpuref_init(void) 289 { 290 phandle_t cpu, dev; 291 char buf[32]; 292 int a, res, tmp_cpuref_cnt; 293 static struct cpuref tmp_cpuref[MAXCPU]; 294 cell_t interrupt_servers[32]; 295 uint64_t bsp; 296 297 if (platform_cpuref_valid) 298 return (0); 299 300 dev = OF_peer(0); 301 dev = OF_child(dev); 302 while (dev != 0) { 303 res = OF_getprop(dev, "name", buf, sizeof(buf)); 304 if (res > 0 && strcmp(buf, "cpus") == 0) 305 break; 306 dev = OF_peer(dev); 307 } 308 309 bsp = 0; 310 tmp_cpuref_cnt = 0; 311 for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) { 312 res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 313 if (res > 0 && strcmp(buf, "cpu") == 0) { 314 res = OF_getproplen(cpu, "ibm,ppc-interrupt-server#s"); 315 if (res > 0) { 316 317 318 OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", 319 interrupt_servers, res); 320 321 for (a = 0; a < res/sizeof(cell_t); a++) { 322 tmp_cpuref[tmp_cpuref_cnt].cr_hwref = interrupt_servers[a]; 323 tmp_cpuref[tmp_cpuref_cnt].cr_cpuid = tmp_cpuref_cnt; 324 325 if (interrupt_servers[a] == (uint32_t)powernv_boot_pir) 326 bsp = tmp_cpuref_cnt; 327 328 tmp_cpuref_cnt++; 329 } 330 } 331 } 332 } 333 334 /* Map IDs, so BSP has CPUID 0 regardless of hwref */ 335 for (a = bsp; a < tmp_cpuref_cnt; a++) { 336 platform_cpuref[platform_cpuref_cnt].cr_hwref = tmp_cpuref[a].cr_hwref; 337 platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt; 338 platform_cpuref_cnt++; 339 } 340 for (a = 0; a < bsp; a++) { 341 platform_cpuref[platform_cpuref_cnt].cr_hwref = tmp_cpuref[a].cr_hwref; 342 platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt; 343 platform_cpuref_cnt++; 344 } 345 346 platform_cpuref_valid = 1; 347 348 return (0); 349 } 350 351 static int 352 powernv_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 353 { 354 if (platform_cpuref_valid == 0) 355 return (EINVAL); 356 357 cpuref->cr_cpuid = 0; 358 cpuref->cr_hwref = platform_cpuref[0].cr_hwref; 359 360 return (0); 361 } 362 363 static int 364 powernv_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 365 { 366 int id; 367 368 if (platform_cpuref_valid == 0) 369 return (EINVAL); 370 371 id = cpuref->cr_cpuid + 1; 372 if (id >= platform_cpuref_cnt) 373 return (ENOENT); 374 375 cpuref->cr_cpuid = platform_cpuref[id].cr_cpuid; 376 cpuref->cr_hwref = platform_cpuref[id].cr_hwref; 377 378 return (0); 379 } 380 381 static int 382 powernv_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 383 { 384 385 cpuref->cr_cpuid = platform_cpuref[0].cr_cpuid; 386 cpuref->cr_hwref = platform_cpuref[0].cr_hwref; 387 return (0); 388 } 389 390 #ifdef SMP 391 static int 392 powernv_smp_start_cpu(platform_t plat, struct pcpu *pc) 393 { 394 int result; 395 396 ap_pcpu = pc; 397 powerpc_sync(); 398 399 result = opal_call(OPAL_START_CPU, pc->pc_hwref, EXC_RST); 400 if (result != OPAL_SUCCESS) { 401 printf("OPAL error (%d): unable to start AP %d\n", 402 result, (int)pc->pc_hwref); 403 return (ENXIO); 404 } 405 406 return (0); 407 } 408 409 static void 410 powernv_smp_probe_threads(platform_t plat) 411 { 412 char buf[8]; 413 phandle_t cpu, dev, root; 414 int res, nthreads; 415 416 root = OF_peer(0); 417 418 dev = OF_child(root); 419 while (dev != 0) { 420 res = OF_getprop(dev, "name", buf, sizeof(buf)); 421 if (res > 0 && strcmp(buf, "cpus") == 0) 422 break; 423 dev = OF_peer(dev); 424 } 425 426 nthreads = 1; 427 for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) { 428 res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 429 if (res <= 0 || strcmp(buf, "cpu") != 0) 430 continue; 431 432 res = OF_getproplen(cpu, "ibm,ppc-interrupt-server#s"); 433 434 if (res >= 0) 435 nthreads = res / sizeof(cell_t); 436 else 437 nthreads = 1; 438 break; 439 } 440 441 smp_threads_per_core = nthreads; 442 if (mp_ncpus % nthreads == 0) 443 mp_ncores = mp_ncpus / nthreads; 444 } 445 446 static struct cpu_group * 447 powernv_smp_topo(platform_t plat) 448 { 449 if (mp_ncpus % smp_threads_per_core != 0) { 450 printf("WARNING: Irregular SMP topology. Performance may be " 451 "suboptimal (%d threads, %d on first core)\n", 452 mp_ncpus, smp_threads_per_core); 453 return (smp_topo_none()); 454 } 455 456 /* Don't do anything fancier for non-threaded SMP */ 457 if (smp_threads_per_core == 1) 458 return (smp_topo_none()); 459 460 return (smp_topo_1level(CG_SHARE_L1, smp_threads_per_core, 461 CG_FLAG_SMT)); 462 } 463 464 #endif 465 466 static void 467 powernv_reset(platform_t platform) 468 { 469 470 opal_call(OPAL_CEC_REBOOT); 471 } 472 473 static void 474 powernv_smp_ap_init(platform_t platform) 475 { 476 477 if (powernv_smp_ap_extra_init != NULL) 478 powernv_smp_ap_extra_init(); 479 } 480 481 static void 482 powernv_cpu_idle(sbintime_t sbt) 483 { 484 } 485