1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2008 Marcel Moolenaar 5 * Copyright (c) 2009 Nathan Whitehorn 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 #include <sys/endian.h> 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/bus.h> 36 #include <sys/pcpu.h> 37 #include <sys/proc.h> 38 #include <sys/sched.h> 39 #include <sys/smp.h> 40 #include <vm/vm.h> 41 #include <vm/pmap.h> 42 43 #include <machine/bus.h> 44 #include <machine/cpu.h> 45 #include <machine/hid.h> 46 #include <machine/platformvar.h> 47 #include <machine/rtas.h> 48 #include <machine/smp.h> 49 #include <machine/spr.h> 50 #include <machine/trap.h> 51 52 #include <dev/ofw/openfirm.h> 53 #include <machine/ofw_machdep.h> 54 55 #include "platform_if.h" 56 57 #ifdef SMP 58 extern void *ap_pcpu; 59 #endif 60 61 #ifdef __powerpc64__ 62 static uint8_t splpar_vpa[MAXCPU][640] __aligned(128); /* XXX: dpcpu */ 63 #endif 64 65 static vm_offset_t realmaxaddr = VM_MAX_ADDRESS; 66 67 static int chrp_probe(platform_t); 68 static int chrp_attach(platform_t); 69 void chrp_mem_regions(platform_t, struct mem_region *phys, int *physsz, 70 struct mem_region *avail, int *availsz); 71 static vm_offset_t chrp_real_maxaddr(platform_t); 72 static u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref); 73 static int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref); 74 static int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref); 75 static int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref); 76 static void chrp_smp_ap_init(platform_t); 77 static int chrp_cpuref_init(void); 78 #ifdef SMP 79 static int chrp_smp_start_cpu(platform_t, struct pcpu *cpu); 80 static void chrp_smp_probe_threads(platform_t plat); 81 static struct cpu_group *chrp_smp_topo(platform_t plat); 82 #endif 83 static void chrp_reset(platform_t); 84 #ifdef __powerpc64__ 85 #include "phyp-hvcall.h" 86 static void phyp_cpu_idle(sbintime_t sbt); 87 #endif 88 89 static struct cpuref platform_cpuref[MAXCPU]; 90 static int platform_cpuref_cnt; 91 static int platform_cpuref_valid; 92 93 static platform_method_t chrp_methods[] = { 94 PLATFORMMETHOD(platform_probe, chrp_probe), 95 PLATFORMMETHOD(platform_attach, chrp_attach), 96 PLATFORMMETHOD(platform_mem_regions, chrp_mem_regions), 97 PLATFORMMETHOD(platform_real_maxaddr, chrp_real_maxaddr), 98 PLATFORMMETHOD(platform_timebase_freq, chrp_timebase_freq), 99 100 PLATFORMMETHOD(platform_smp_ap_init, chrp_smp_ap_init), 101 PLATFORMMETHOD(platform_smp_first_cpu, chrp_smp_first_cpu), 102 PLATFORMMETHOD(platform_smp_next_cpu, chrp_smp_next_cpu), 103 PLATFORMMETHOD(platform_smp_get_bsp, chrp_smp_get_bsp), 104 #ifdef SMP 105 PLATFORMMETHOD(platform_smp_start_cpu, chrp_smp_start_cpu), 106 PLATFORMMETHOD(platform_smp_probe_threads, chrp_smp_probe_threads), 107 PLATFORMMETHOD(platform_smp_topo, chrp_smp_topo), 108 #endif 109 110 PLATFORMMETHOD(platform_reset, chrp_reset), 111 { 0, 0 } 112 }; 113 114 static platform_def_t chrp_platform = { 115 "chrp", 116 chrp_methods, 117 0 118 }; 119 120 PLATFORM_DEF(chrp_platform); 121 122 static int 123 chrp_probe(platform_t plat) 124 { 125 if (OF_finddevice("/memory") != -1 || OF_finddevice("/memory@0") != -1) 126 return (BUS_PROBE_GENERIC); 127 128 return (ENXIO); 129 } 130 131 static int 132 chrp_attach(platform_t plat) 133 { 134 int quiesce; 135 #ifdef __powerpc64__ 136 int i; 137 #if BYTE_ORDER == LITTLE_ENDIAN 138 int result; 139 #endif 140 141 /* XXX: check for /rtas/ibm,hypertas-functions? */ 142 if (!(mfmsr() & PSL_HV)) { 143 struct mem_region *phys, *avail; 144 int nphys, navail; 145 vm_offset_t off; 146 147 mem_regions(&phys, &nphys, &avail, &navail); 148 149 realmaxaddr = 0; 150 for (i = 0; i < nphys; i++) { 151 off = phys[i].mr_start + phys[i].mr_size; 152 realmaxaddr = MAX(off, realmaxaddr); 153 } 154 155 if (!radix_mmu) 156 pmap_mmu_install("mmu_phyp", BUS_PROBE_SPECIFIC); 157 cpu_idle_hook = phyp_cpu_idle; 158 159 /* Set up important VPA fields */ 160 for (i = 0; i < MAXCPU; i++) { 161 /* First two: VPA size */ 162 splpar_vpa[i][4] = 163 (uint8_t)((sizeof(splpar_vpa[i]) >> 8) & 0xff); 164 splpar_vpa[i][5] = 165 (uint8_t)(sizeof(splpar_vpa[i]) & 0xff); 166 splpar_vpa[i][0xba] = 1; /* Maintain FPRs */ 167 splpar_vpa[i][0xbb] = 1; /* Maintain PMCs */ 168 splpar_vpa[i][0xfc] = 0xff; /* Maintain full SLB */ 169 splpar_vpa[i][0xfd] = 0xff; 170 splpar_vpa[i][0xff] = 1; /* Maintain Altivec */ 171 } 172 mb(); 173 174 /* Set up hypervisor CPU stuff */ 175 chrp_smp_ap_init(plat); 176 177 #if BYTE_ORDER == LITTLE_ENDIAN 178 /* 179 * Ask the hypervisor to update the LPAR ILE bit. 180 * 181 * This involves all processors reentering the hypervisor 182 * so the change appears simultaneously in all processors. 183 * This can take a long time. 184 */ 185 for(;;) { 186 result = phyp_hcall(H_SET_MODE, 1UL, 187 H_SET_MODE_RSRC_ILE, 0, 0); 188 if (result == H_SUCCESS) 189 break; 190 DELAY(1000); 191 } 192 #endif 193 194 } 195 #endif 196 chrp_cpuref_init(); 197 198 /* Some systems (e.g. QEMU) need Open Firmware to stand down */ 199 quiesce = 1; 200 TUNABLE_INT_FETCH("debug.quiesce_ofw", &quiesce); 201 if (quiesce) 202 ofw_quiesce(); 203 204 return (0); 205 } 206 207 static int 208 parse_drconf_memory(struct mem_region *ofmem, int *msz, 209 struct mem_region *ofavail, int *asz) 210 { 211 phandle_t phandle; 212 vm_offset_t base; 213 int i, idx, len, lasz, lmsz, res; 214 uint32_t flags, lmb_size[2]; 215 uint32_t *dmem; 216 217 lmsz = *msz; 218 lasz = *asz; 219 220 phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory"); 221 if (phandle == -1) 222 /* No drconf node, return. */ 223 return (0); 224 225 res = OF_getencprop(phandle, "ibm,lmb-size", lmb_size, 226 sizeof(lmb_size)); 227 if (res == -1) 228 return (0); 229 printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20); 230 231 /* Parse the /ibm,dynamic-memory. 232 The first position gives the # of entries. The next two words 233 reflect the address of the memory block. The next four words are 234 the DRC index, reserved, list index and flags. 235 (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory) 236 237 #el Addr DRC-idx res list-idx flags 238 ------------------------------------------------- 239 | 4 | 8 | 4 | 4 | 4 | 4 |.... 240 ------------------------------------------------- 241 */ 242 243 len = OF_getproplen(phandle, "ibm,dynamic-memory"); 244 if (len > 0) { 245 /* We have to use a variable length array on the stack 246 since we have very limited stack space. 247 */ 248 cell_t arr[len/sizeof(cell_t)]; 249 250 res = OF_getencprop(phandle, "ibm,dynamic-memory", arr, 251 sizeof(arr)); 252 if (res == -1) 253 return (0); 254 255 /* Number of elements */ 256 idx = arr[0]; 257 258 /* First address, in arr[1], arr[2]*/ 259 dmem = &arr[1]; 260 261 for (i = 0; i < idx; i++) { 262 base = ((uint64_t)dmem[0] << 32) + dmem[1]; 263 dmem += 4; 264 flags = dmem[1]; 265 /* Use region only if available and not reserved. */ 266 if ((flags & 0x8) && !(flags & 0x80)) { 267 ofmem[lmsz].mr_start = base; 268 ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1]; 269 ofavail[lasz].mr_start = base; 270 ofavail[lasz].mr_size = (vm_size_t)lmb_size[1]; 271 lmsz++; 272 lasz++; 273 } 274 dmem += 2; 275 } 276 } 277 278 *msz = lmsz; 279 *asz = lasz; 280 281 return (1); 282 } 283 284 void 285 chrp_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 286 struct mem_region *avail, int *availsz) 287 { 288 vm_offset_t maxphysaddr; 289 int i; 290 291 ofw_mem_regions(phys, physsz, avail, availsz); 292 parse_drconf_memory(phys, physsz, avail, availsz); 293 294 /* 295 * On some firmwares (SLOF), some memory may be marked available that 296 * doesn't actually exist. This manifests as an extension of the last 297 * available segment past the end of physical memory, so truncate that 298 * one. 299 */ 300 maxphysaddr = 0; 301 for (i = 0; i < *physsz; i++) 302 if (phys[i].mr_start + phys[i].mr_size > maxphysaddr) 303 maxphysaddr = phys[i].mr_start + phys[i].mr_size; 304 305 for (i = 0; i < *availsz; i++) 306 if (avail[i].mr_start + avail[i].mr_size > maxphysaddr) 307 avail[i].mr_size = maxphysaddr - avail[i].mr_start; 308 } 309 310 static vm_offset_t 311 chrp_real_maxaddr(platform_t plat) 312 { 313 return (realmaxaddr); 314 } 315 316 static u_long 317 chrp_timebase_freq(platform_t plat, struct cpuref *cpuref) 318 { 319 phandle_t cpus, cpunode; 320 int32_t ticks = -1; 321 int res; 322 char buf[8]; 323 324 cpus = OF_finddevice("/cpus"); 325 if (cpus == -1) 326 panic("CPU tree not found on Open Firmware\n"); 327 328 for (cpunode = OF_child(cpus); cpunode != 0; cpunode = OF_peer(cpunode)) { 329 res = OF_getprop(cpunode, "device_type", buf, sizeof(buf)); 330 if (res > 0 && strcmp(buf, "cpu") == 0) 331 break; 332 } 333 if (cpunode <= 0) 334 panic("CPU node not found on Open Firmware\n"); 335 336 OF_getencprop(cpunode, "timebase-frequency", &ticks, sizeof(ticks)); 337 338 if (ticks <= 0) 339 panic("Unable to determine timebase frequency!"); 340 341 return (ticks); 342 } 343 344 static int 345 chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 346 { 347 348 if (platform_cpuref_valid == 0) 349 return (EINVAL); 350 351 cpuref->cr_cpuid = 0; 352 cpuref->cr_hwref = platform_cpuref[0].cr_hwref; 353 354 return (0); 355 } 356 357 static int 358 chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 359 { 360 int id; 361 362 if (platform_cpuref_valid == 0) 363 return (EINVAL); 364 365 id = cpuref->cr_cpuid + 1; 366 if (id >= platform_cpuref_cnt) 367 return (ENOENT); 368 369 cpuref->cr_cpuid = platform_cpuref[id].cr_cpuid; 370 cpuref->cr_hwref = platform_cpuref[id].cr_hwref; 371 372 return (0); 373 } 374 375 static int 376 chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 377 { 378 379 cpuref->cr_cpuid = platform_cpuref[0].cr_cpuid; 380 cpuref->cr_hwref = platform_cpuref[0].cr_hwref; 381 return (0); 382 } 383 384 static void 385 get_cpu_reg(phandle_t cpu, cell_t *reg) 386 { 387 int res; 388 389 res = OF_getproplen(cpu, "reg"); 390 if (res != sizeof(cell_t)) 391 panic("Unexpected length for CPU property reg on Open Firmware\n"); 392 OF_getencprop(cpu, "reg", reg, res); 393 } 394 395 static int 396 chrp_cpuref_init(void) 397 { 398 phandle_t cpu, dev, chosen, pbsp; 399 ihandle_t ibsp; 400 char buf[32]; 401 int a, bsp, res, res2, tmp_cpuref_cnt; 402 static struct cpuref tmp_cpuref[MAXCPU]; 403 cell_t interrupt_servers[32], addr_cells, size_cells, reg, bsp_reg; 404 405 if (platform_cpuref_valid) 406 return (0); 407 408 dev = OF_peer(0); 409 dev = OF_child(dev); 410 while (dev != 0) { 411 res = OF_getprop(dev, "name", buf, sizeof(buf)); 412 if (res > 0 && strcmp(buf, "cpus") == 0) 413 break; 414 dev = OF_peer(dev); 415 } 416 417 /* Make sure that cpus reg property have 1 address cell and 0 size cells */ 418 res = OF_getproplen(dev, "#address-cells"); 419 res2 = OF_getproplen(dev, "#size-cells"); 420 if (res != res2 || res != sizeof(cell_t)) 421 panic("CPU properties #address-cells and #size-cells not found on Open Firmware\n"); 422 OF_getencprop(dev, "#address-cells", &addr_cells, sizeof(addr_cells)); 423 OF_getencprop(dev, "#size-cells", &size_cells, sizeof(size_cells)); 424 if (addr_cells != 1 || size_cells != 0) 425 panic("Unexpected values for CPU properties #address-cells and #size-cells on Open Firmware\n"); 426 427 /* Look for boot CPU in /chosen/cpu and /chosen/fdtbootcpu */ 428 429 chosen = OF_finddevice("/chosen"); 430 if (chosen == -1) 431 panic("Device /chosen not found on Open Firmware\n"); 432 433 bsp_reg = -1; 434 435 /* /chosen/cpu */ 436 if (OF_getproplen(chosen, "cpu") == sizeof(ihandle_t)) { 437 OF_getprop(chosen, "cpu", &ibsp, sizeof(ibsp)); 438 pbsp = OF_instance_to_package(be32toh(ibsp)); 439 if (pbsp != -1) 440 get_cpu_reg(pbsp, &bsp_reg); 441 } 442 443 /* /chosen/fdtbootcpu */ 444 if (bsp_reg == -1) { 445 if (OF_getproplen(chosen, "fdtbootcpu") == sizeof(cell_t)) 446 OF_getprop(chosen, "fdtbootcpu", &bsp_reg, sizeof(bsp_reg)); 447 } 448 449 if (bsp_reg == -1) 450 panic("Boot CPU not found on Open Firmware\n"); 451 452 bsp = -1; 453 tmp_cpuref_cnt = 0; 454 for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) { 455 res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 456 if (res > 0 && strcmp(buf, "cpu") == 0) { 457 res = OF_getproplen(cpu, "ibm,ppc-interrupt-server#s"); 458 if (res > 0) { 459 OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", 460 interrupt_servers, res); 461 462 get_cpu_reg(cpu, ®); 463 if (reg == bsp_reg) 464 bsp = tmp_cpuref_cnt; 465 466 for (a = 0; a < res/sizeof(cell_t); a++) { 467 tmp_cpuref[tmp_cpuref_cnt].cr_hwref = interrupt_servers[a]; 468 tmp_cpuref[tmp_cpuref_cnt].cr_cpuid = tmp_cpuref_cnt; 469 tmp_cpuref_cnt++; 470 } 471 } 472 } 473 } 474 475 if (bsp == -1) 476 panic("Boot CPU not found\n"); 477 478 /* Map IDs, so BSP has CPUID 0 regardless of hwref */ 479 for (a = bsp; a < tmp_cpuref_cnt; a++) { 480 platform_cpuref[platform_cpuref_cnt].cr_hwref = tmp_cpuref[a].cr_hwref; 481 platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt; 482 platform_cpuref_cnt++; 483 } 484 for (a = 0; a < bsp; a++) { 485 platform_cpuref[platform_cpuref_cnt].cr_hwref = tmp_cpuref[a].cr_hwref; 486 platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt; 487 platform_cpuref_cnt++; 488 } 489 490 platform_cpuref_valid = 1; 491 492 return (0); 493 } 494 495 #ifdef SMP 496 static int 497 chrp_smp_start_cpu(platform_t plat, struct pcpu *pc) 498 { 499 cell_t start_cpu; 500 int result, err, timeout; 501 502 if (!rtas_exists()) { 503 printf("RTAS uninitialized: unable to start AP %d\n", 504 pc->pc_cpuid); 505 return (ENXIO); 506 } 507 508 start_cpu = rtas_token_lookup("start-cpu"); 509 if (start_cpu == -1) { 510 printf("RTAS unknown method: unable to start AP %d\n", 511 pc->pc_cpuid); 512 return (ENXIO); 513 } 514 515 ap_pcpu = pc; 516 powerpc_sync(); 517 518 result = rtas_call_method(start_cpu, 3, 1, pc->pc_hwref, EXC_RST, pc, 519 &err); 520 if (result < 0 || err != 0) { 521 printf("RTAS error (%d/%d): unable to start AP %d\n", 522 result, err, pc->pc_cpuid); 523 return (ENXIO); 524 } 525 526 timeout = 10000; 527 while (!pc->pc_awake && timeout--) 528 DELAY(100); 529 530 return ((pc->pc_awake) ? 0 : EBUSY); 531 } 532 533 static void 534 chrp_smp_probe_threads(platform_t plat) 535 { 536 struct pcpu *pc, *last_pc; 537 int i, ncores; 538 539 ncores = 0; 540 last_pc = NULL; 541 for (i = 0; i <= mp_maxid; i++) { 542 pc = pcpu_find(i); 543 if (pc == NULL) 544 continue; 545 if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref) 546 ncores++; 547 last_pc = pc; 548 } 549 550 mp_ncores = ncores; 551 if (mp_ncpus % ncores == 0) 552 smp_threads_per_core = mp_ncpus / ncores; 553 } 554 555 static struct cpu_group * 556 chrp_smp_topo(platform_t plat) 557 { 558 559 if (mp_ncpus % mp_ncores != 0) { 560 printf("WARNING: Irregular SMP topology. Performance may be " 561 "suboptimal (%d CPUS, %d cores)\n", mp_ncpus, mp_ncores); 562 return (smp_topo_none()); 563 } 564 565 /* Don't do anything fancier for non-threaded SMP */ 566 if (mp_ncpus == mp_ncores) 567 return (smp_topo_none()); 568 569 return (smp_topo_1level(CG_SHARE_L1, smp_threads_per_core, 570 CG_FLAG_SMT)); 571 } 572 #endif 573 574 static void 575 chrp_reset(platform_t platform) 576 { 577 OF_reboot(); 578 } 579 580 #ifdef __powerpc64__ 581 static void 582 phyp_cpu_idle(sbintime_t sbt) 583 { 584 register_t msr; 585 586 msr = mfmsr(); 587 588 mtmsr(msr & ~PSL_EE); 589 if (sched_runnable()) { 590 mtmsr(msr); 591 return; 592 } 593 594 phyp_hcall(H_CEDE); /* Re-enables interrupts internally */ 595 mtmsr(msr); 596 } 597 598 static void 599 chrp_smp_ap_init(platform_t platform) 600 { 601 if (!(mfmsr() & PSL_HV)) { 602 /* Register VPA */ 603 phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(hwref), 604 splpar_vpa[PCPU_GET(hwref)]); 605 606 /* Set interrupt priority */ 607 phyp_hcall(H_CPPR, 0xff); 608 } 609 } 610 #else 611 static void 612 chrp_smp_ap_init(platform_t platform) 613 { 614 } 615 #endif 616