17a8d25c0SNathan Whitehorn /*- 271e3c308SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 371e3c308SPedro F. Giffuni * 47a8d25c0SNathan Whitehorn * Copyright (c) 2008 Marcel Moolenaar 57a8d25c0SNathan Whitehorn * Copyright (c) 2009 Nathan Whitehorn 67a8d25c0SNathan Whitehorn * All rights reserved. 77a8d25c0SNathan Whitehorn * 87a8d25c0SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 97a8d25c0SNathan Whitehorn * modification, are permitted provided that the following conditions 107a8d25c0SNathan Whitehorn * are met: 117a8d25c0SNathan Whitehorn * 127a8d25c0SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 137a8d25c0SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 147a8d25c0SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 157a8d25c0SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 167a8d25c0SNathan Whitehorn * documentation and/or other materials provided with the distribution. 177a8d25c0SNathan Whitehorn * 187a8d25c0SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 197a8d25c0SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 207a8d25c0SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 217a8d25c0SNathan Whitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 227a8d25c0SNathan Whitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 237a8d25c0SNathan Whitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 247a8d25c0SNathan Whitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 257a8d25c0SNathan Whitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 267a8d25c0SNathan Whitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 277a8d25c0SNathan Whitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 287a8d25c0SNathan Whitehorn */ 297a8d25c0SNathan Whitehorn 307a8d25c0SNathan Whitehorn #include <sys/cdefs.h> 317a8d25c0SNathan Whitehorn __FBSDID("$FreeBSD$"); 327a8d25c0SNathan Whitehorn 337a8d25c0SNathan Whitehorn #include <sys/param.h> 347a8d25c0SNathan Whitehorn #include <sys/systm.h> 357a8d25c0SNathan Whitehorn #include <sys/kernel.h> 367a8d25c0SNathan Whitehorn #include <sys/bus.h> 377a8d25c0SNathan Whitehorn #include <sys/pcpu.h> 387a8d25c0SNathan Whitehorn #include <sys/proc.h> 39e21d69e9SNathan Whitehorn #include <sys/sched.h> 407a8d25c0SNathan Whitehorn #include <sys/smp.h> 417a8d25c0SNathan Whitehorn #include <vm/vm.h> 427a8d25c0SNathan Whitehorn #include <vm/pmap.h> 437a8d25c0SNathan Whitehorn 447a8d25c0SNathan Whitehorn #include <machine/bus.h> 457a8d25c0SNathan Whitehorn #include <machine/cpu.h> 467a8d25c0SNathan Whitehorn #include <machine/hid.h> 477a8d25c0SNathan Whitehorn #include <machine/platformvar.h> 487a8d25c0SNathan Whitehorn #include <machine/rtas.h> 497a8d25c0SNathan Whitehorn #include <machine/smp.h> 507a8d25c0SNathan Whitehorn #include <machine/spr.h> 51258dbffeSNathan Whitehorn #include <machine/trap.h> 527a8d25c0SNathan Whitehorn 537a8d25c0SNathan Whitehorn #include <dev/ofw/openfirm.h> 547a8d25c0SNathan Whitehorn #include <machine/ofw_machdep.h> 557a8d25c0SNathan Whitehorn 567a8d25c0SNathan Whitehorn #include "platform_if.h" 577a8d25c0SNathan Whitehorn 587a8d25c0SNathan Whitehorn #ifdef SMP 597a8d25c0SNathan Whitehorn extern void *ap_pcpu; 607a8d25c0SNathan Whitehorn #endif 617a8d25c0SNathan Whitehorn 627a8d25c0SNathan Whitehorn #ifdef __powerpc64__ 63f1e48417SNathan Whitehorn static uint8_t splpar_vpa[MAXCPU][640] __aligned(128); /* XXX: dpcpu */ 647a8d25c0SNathan Whitehorn #endif 657a8d25c0SNathan Whitehorn 667a8d25c0SNathan Whitehorn static vm_offset_t realmaxaddr = VM_MAX_ADDRESS; 677a8d25c0SNathan Whitehorn 687a8d25c0SNathan Whitehorn static int chrp_probe(platform_t); 697a8d25c0SNathan Whitehorn static int chrp_attach(platform_t); 70c1cb22d7SNathan Whitehorn void chrp_mem_regions(platform_t, struct mem_region *phys, int *physsz, 71c1cb22d7SNathan Whitehorn struct mem_region *avail, int *availsz); 727a8d25c0SNathan Whitehorn static vm_offset_t chrp_real_maxaddr(platform_t); 737a8d25c0SNathan Whitehorn static u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref); 747a8d25c0SNathan Whitehorn static int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref); 757a8d25c0SNathan Whitehorn static int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref); 767a8d25c0SNathan Whitehorn static int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref); 777a8d25c0SNathan Whitehorn static void chrp_smp_ap_init(platform_t); 787a8d25c0SNathan Whitehorn #ifdef SMP 797a8d25c0SNathan Whitehorn static int chrp_smp_start_cpu(platform_t, struct pcpu *cpu); 807a8d25c0SNathan Whitehorn static struct cpu_group *chrp_smp_topo(platform_t plat); 817a8d25c0SNathan Whitehorn #endif 827a8d25c0SNathan Whitehorn static void chrp_reset(platform_t); 837a8d25c0SNathan Whitehorn #ifdef __powerpc64__ 847a8d25c0SNathan Whitehorn #include "phyp-hvcall.h" 857a8d25c0SNathan Whitehorn static void phyp_cpu_idle(sbintime_t sbt); 867a8d25c0SNathan Whitehorn #endif 877a8d25c0SNathan Whitehorn 887a8d25c0SNathan Whitehorn static platform_method_t chrp_methods[] = { 897a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_probe, chrp_probe), 907a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_attach, chrp_attach), 917a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_mem_regions, chrp_mem_regions), 927a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_real_maxaddr, chrp_real_maxaddr), 937a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_timebase_freq, chrp_timebase_freq), 947a8d25c0SNathan Whitehorn 957a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_ap_init, chrp_smp_ap_init), 967a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_first_cpu, chrp_smp_first_cpu), 977a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_next_cpu, chrp_smp_next_cpu), 987a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_get_bsp, chrp_smp_get_bsp), 997a8d25c0SNathan Whitehorn #ifdef SMP 1007a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_start_cpu, chrp_smp_start_cpu), 1017a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_topo, chrp_smp_topo), 1027a8d25c0SNathan Whitehorn #endif 1037a8d25c0SNathan Whitehorn 1047a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_reset, chrp_reset), 1057a8d25c0SNathan Whitehorn 1067a8d25c0SNathan Whitehorn { 0, 0 } 1077a8d25c0SNathan Whitehorn }; 1087a8d25c0SNathan Whitehorn 1097a8d25c0SNathan Whitehorn static platform_def_t chrp_platform = { 1107a8d25c0SNathan Whitehorn "chrp", 1117a8d25c0SNathan Whitehorn chrp_methods, 1127a8d25c0SNathan Whitehorn 0 1137a8d25c0SNathan Whitehorn }; 1147a8d25c0SNathan Whitehorn 1157a8d25c0SNathan Whitehorn PLATFORM_DEF(chrp_platform); 1167a8d25c0SNathan Whitehorn 117*f9d6e0a5SNathan Whitehorn #define BSP_MUST_BE_CPU_ZERO 118*f9d6e0a5SNathan Whitehorn 1197a8d25c0SNathan Whitehorn static int 1207a8d25c0SNathan Whitehorn chrp_probe(platform_t plat) 1217a8d25c0SNathan Whitehorn { 1227a8d25c0SNathan Whitehorn if (OF_finddevice("/memory") != -1 || OF_finddevice("/memory@0") != -1) 1237a8d25c0SNathan Whitehorn return (BUS_PROBE_GENERIC); 1247a8d25c0SNathan Whitehorn 1257a8d25c0SNathan Whitehorn return (ENXIO); 1267a8d25c0SNathan Whitehorn } 1277a8d25c0SNathan Whitehorn 1287a8d25c0SNathan Whitehorn static int 1297a8d25c0SNathan Whitehorn chrp_attach(platform_t plat) 1307a8d25c0SNathan Whitehorn { 13166fe9464SBjoern A. Zeeb #ifdef __powerpc64__ 132f1e48417SNathan Whitehorn int i; 133f1e48417SNathan Whitehorn 1347a8d25c0SNathan Whitehorn /* XXX: check for /rtas/ibm,hypertas-functions? */ 1357a8d25c0SNathan Whitehorn if (!(mfmsr() & PSL_HV)) { 1367a8d25c0SNathan Whitehorn struct mem_region *phys, *avail; 1377a8d25c0SNathan Whitehorn int nphys, navail; 1387a8d25c0SNathan Whitehorn mem_regions(&phys, &nphys, &avail, &navail); 1397a8d25c0SNathan Whitehorn realmaxaddr = phys[0].mr_size; 1407a8d25c0SNathan Whitehorn 1417a8d25c0SNathan Whitehorn pmap_mmu_install("mmu_phyp", BUS_PROBE_SPECIFIC); 1427a8d25c0SNathan Whitehorn cpu_idle_hook = phyp_cpu_idle; 1437a8d25c0SNathan Whitehorn 1447a8d25c0SNathan Whitehorn /* Set up important VPA fields */ 145f1e48417SNathan Whitehorn for (i = 0; i < MAXCPU; i++) { 146f1e48417SNathan Whitehorn bzero(splpar_vpa[i], sizeof(splpar_vpa)); 147f1e48417SNathan Whitehorn /* First two: VPA size */ 148f1e48417SNathan Whitehorn splpar_vpa[i][4] = 149f1e48417SNathan Whitehorn (uint8_t)((sizeof(splpar_vpa[i]) >> 8) & 0xff); 150f1e48417SNathan Whitehorn splpar_vpa[i][5] = 151f1e48417SNathan Whitehorn (uint8_t)(sizeof(splpar_vpa[i]) & 0xff); 152f1e48417SNathan Whitehorn splpar_vpa[i][0xba] = 1; /* Maintain FPRs */ 153f1e48417SNathan Whitehorn splpar_vpa[i][0xbb] = 1; /* Maintain PMCs */ 154f1e48417SNathan Whitehorn splpar_vpa[i][0xfc] = 0xff; /* Maintain full SLB */ 155f1e48417SNathan Whitehorn splpar_vpa[i][0xfd] = 0xff; 156f1e48417SNathan Whitehorn splpar_vpa[i][0xff] = 1; /* Maintain Altivec */ 157f1e48417SNathan Whitehorn } 1587a8d25c0SNathan Whitehorn mb(); 1597a8d25c0SNathan Whitehorn 1607a8d25c0SNathan Whitehorn /* Set up hypervisor CPU stuff */ 1617a8d25c0SNathan Whitehorn chrp_smp_ap_init(plat); 1627a8d25c0SNathan Whitehorn } 1637a8d25c0SNathan Whitehorn #endif 1647a8d25c0SNathan Whitehorn 1659f706727SNathan Whitehorn /* Some systems (e.g. QEMU) need Open Firmware to stand down */ 1669f706727SNathan Whitehorn ofw_quiesce(); 1679f706727SNathan Whitehorn 1687a8d25c0SNathan Whitehorn return (0); 1697a8d25c0SNathan Whitehorn } 1707a8d25c0SNathan Whitehorn 171c1cb22d7SNathan Whitehorn static int 172f5dfbe2fSAndreas Tobler parse_drconf_memory(struct mem_region *ofmem, int *msz, 173f5dfbe2fSAndreas Tobler struct mem_region *ofavail, int *asz) 1747a8d25c0SNathan Whitehorn { 175c1cb22d7SNathan Whitehorn phandle_t phandle; 176c1cb22d7SNathan Whitehorn vm_offset_t base; 177c1cb22d7SNathan Whitehorn int i, idx, len, lasz, lmsz, res; 178f5dfbe2fSAndreas Tobler uint32_t flags, lmb_size[2]; 179509142e1SNathan Whitehorn uint32_t *dmem; 180c1cb22d7SNathan Whitehorn 181c1cb22d7SNathan Whitehorn lmsz = *msz; 182c1cb22d7SNathan Whitehorn lasz = *asz; 183c1cb22d7SNathan Whitehorn 184c1cb22d7SNathan Whitehorn phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory"); 185c1cb22d7SNathan Whitehorn if (phandle == -1) 186c1cb22d7SNathan Whitehorn /* No drconf node, return. */ 187c1cb22d7SNathan Whitehorn return (0); 188c1cb22d7SNathan Whitehorn 189509142e1SNathan Whitehorn res = OF_getencprop(phandle, "ibm,lmb-size", lmb_size, 190509142e1SNathan Whitehorn sizeof(lmb_size)); 191c1cb22d7SNathan Whitehorn if (res == -1) 192c1cb22d7SNathan Whitehorn return (0); 193c1cb22d7SNathan Whitehorn printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20); 194c1cb22d7SNathan Whitehorn 195c1cb22d7SNathan Whitehorn /* Parse the /ibm,dynamic-memory. 196c1cb22d7SNathan Whitehorn The first position gives the # of entries. The next two words 197c1cb22d7SNathan Whitehorn reflect the address of the memory block. The next four words are 198c1cb22d7SNathan Whitehorn the DRC index, reserved, list index and flags. 199c1cb22d7SNathan Whitehorn (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory) 200c1cb22d7SNathan Whitehorn 201c1cb22d7SNathan Whitehorn #el Addr DRC-idx res list-idx flags 202c1cb22d7SNathan Whitehorn ------------------------------------------------- 203c1cb22d7SNathan Whitehorn | 4 | 8 | 4 | 4 | 4 | 4 |.... 204c1cb22d7SNathan Whitehorn ------------------------------------------------- 205c1cb22d7SNathan Whitehorn */ 206c1cb22d7SNathan Whitehorn 207c1cb22d7SNathan Whitehorn len = OF_getproplen(phandle, "ibm,dynamic-memory"); 208c1cb22d7SNathan Whitehorn if (len > 0) { 209c1cb22d7SNathan Whitehorn 210c1cb22d7SNathan Whitehorn /* We have to use a variable length array on the stack 211c1cb22d7SNathan Whitehorn since we have very limited stack space. 212c1cb22d7SNathan Whitehorn */ 213c1cb22d7SNathan Whitehorn cell_t arr[len/sizeof(cell_t)]; 214c1cb22d7SNathan Whitehorn 215509142e1SNathan Whitehorn res = OF_getencprop(phandle, "ibm,dynamic-memory", arr, 216c1cb22d7SNathan Whitehorn sizeof(arr)); 217c1cb22d7SNathan Whitehorn if (res == -1) 218c1cb22d7SNathan Whitehorn return (0); 219c1cb22d7SNathan Whitehorn 220c1cb22d7SNathan Whitehorn /* Number of elements */ 221c1cb22d7SNathan Whitehorn idx = arr[0]; 222c1cb22d7SNathan Whitehorn 223f5dfbe2fSAndreas Tobler /* First address, in arr[1], arr[2]*/ 224509142e1SNathan Whitehorn dmem = &arr[1]; 225c1cb22d7SNathan Whitehorn 226c1cb22d7SNathan Whitehorn for (i = 0; i < idx; i++) { 227509142e1SNathan Whitehorn base = ((uint64_t)dmem[0] << 32) + dmem[1]; 228509142e1SNathan Whitehorn dmem += 4; 229509142e1SNathan Whitehorn flags = dmem[1]; 230c1cb22d7SNathan Whitehorn /* Use region only if available and not reserved. */ 231c1cb22d7SNathan Whitehorn if ((flags & 0x8) && !(flags & 0x80)) { 232c1cb22d7SNathan Whitehorn ofmem[lmsz].mr_start = base; 233c1cb22d7SNathan Whitehorn ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1]; 234c1cb22d7SNathan Whitehorn ofavail[lasz].mr_start = base; 235c1cb22d7SNathan Whitehorn ofavail[lasz].mr_size = (vm_size_t)lmb_size[1]; 236c1cb22d7SNathan Whitehorn lmsz++; 237c1cb22d7SNathan Whitehorn lasz++; 238c1cb22d7SNathan Whitehorn } 239509142e1SNathan Whitehorn dmem += 2; 240c1cb22d7SNathan Whitehorn } 241c1cb22d7SNathan Whitehorn } 242c1cb22d7SNathan Whitehorn 243c1cb22d7SNathan Whitehorn *msz = lmsz; 244c1cb22d7SNathan Whitehorn *asz = lasz; 245c1cb22d7SNathan Whitehorn 246c1cb22d7SNathan Whitehorn return (1); 247c1cb22d7SNathan Whitehorn } 248c1cb22d7SNathan Whitehorn 249c1cb22d7SNathan Whitehorn void 250c1cb22d7SNathan Whitehorn chrp_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 251c1cb22d7SNathan Whitehorn struct mem_region *avail, int *availsz) 252c1cb22d7SNathan Whitehorn { 253c1cb22d7SNathan Whitehorn vm_offset_t maxphysaddr; 254c1cb22d7SNathan Whitehorn int i; 255c1cb22d7SNathan Whitehorn 2567a8d25c0SNathan Whitehorn ofw_mem_regions(phys, physsz, avail, availsz); 257f5dfbe2fSAndreas Tobler parse_drconf_memory(phys, physsz, avail, availsz); 258c1cb22d7SNathan Whitehorn 259c1cb22d7SNathan Whitehorn /* 260c1cb22d7SNathan Whitehorn * On some firmwares (SLOF), some memory may be marked available that 261c1cb22d7SNathan Whitehorn * doesn't actually exist. This manifests as an extension of the last 262c1cb22d7SNathan Whitehorn * available segment past the end of physical memory, so truncate that 263c1cb22d7SNathan Whitehorn * one. 264c1cb22d7SNathan Whitehorn */ 265c1cb22d7SNathan Whitehorn maxphysaddr = 0; 266c1cb22d7SNathan Whitehorn for (i = 0; i < *physsz; i++) 267c1cb22d7SNathan Whitehorn if (phys[i].mr_start + phys[i].mr_size > maxphysaddr) 268c1cb22d7SNathan Whitehorn maxphysaddr = phys[i].mr_start + phys[i].mr_size; 269c1cb22d7SNathan Whitehorn 270c1cb22d7SNathan Whitehorn for (i = 0; i < *availsz; i++) 271c1cb22d7SNathan Whitehorn if (avail[i].mr_start + avail[i].mr_size > maxphysaddr) 272c1cb22d7SNathan Whitehorn avail[i].mr_size = maxphysaddr - avail[i].mr_start; 2737a8d25c0SNathan Whitehorn } 2747a8d25c0SNathan Whitehorn 2757a8d25c0SNathan Whitehorn static vm_offset_t 2767a8d25c0SNathan Whitehorn chrp_real_maxaddr(platform_t plat) 2777a8d25c0SNathan Whitehorn { 2787a8d25c0SNathan Whitehorn return (realmaxaddr); 2797a8d25c0SNathan Whitehorn } 2807a8d25c0SNathan Whitehorn 2817a8d25c0SNathan Whitehorn static u_long 2827a8d25c0SNathan Whitehorn chrp_timebase_freq(platform_t plat, struct cpuref *cpuref) 2837a8d25c0SNathan Whitehorn { 284*f9d6e0a5SNathan Whitehorn char buf[8]; 285*f9d6e0a5SNathan Whitehorn phandle_t cpu, dev, root; 286*f9d6e0a5SNathan Whitehorn int res; 2877a8d25c0SNathan Whitehorn int32_t ticks = -1; 2887a8d25c0SNathan Whitehorn 289*f9d6e0a5SNathan Whitehorn root = OF_peer(0); 2907a8d25c0SNathan Whitehorn 291*f9d6e0a5SNathan Whitehorn dev = OF_child(root); 292*f9d6e0a5SNathan Whitehorn while (dev != 0) { 293*f9d6e0a5SNathan Whitehorn res = OF_getprop(dev, "name", buf, sizeof(buf)); 294*f9d6e0a5SNathan Whitehorn if (res > 0 && strcmp(buf, "cpus") == 0) 295*f9d6e0a5SNathan Whitehorn break; 296*f9d6e0a5SNathan Whitehorn dev = OF_peer(dev); 297*f9d6e0a5SNathan Whitehorn } 298*f9d6e0a5SNathan Whitehorn 299*f9d6e0a5SNathan Whitehorn for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) { 300*f9d6e0a5SNathan Whitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 301*f9d6e0a5SNathan Whitehorn if (res > 0 && strcmp(buf, "cpu") == 0) 302*f9d6e0a5SNathan Whitehorn break; 303*f9d6e0a5SNathan Whitehorn } 304*f9d6e0a5SNathan Whitehorn if (cpu == 0) 305*f9d6e0a5SNathan Whitehorn return (512000000); 306*f9d6e0a5SNathan Whitehorn 307*f9d6e0a5SNathan Whitehorn OF_getencprop(cpu, "timebase-frequency", &ticks, sizeof(ticks)); 3087a8d25c0SNathan Whitehorn 3097a8d25c0SNathan Whitehorn if (ticks <= 0) 3107a8d25c0SNathan Whitehorn panic("Unable to determine timebase frequency!"); 3117a8d25c0SNathan Whitehorn 3127a8d25c0SNathan Whitehorn return (ticks); 3137a8d25c0SNathan Whitehorn } 3147a8d25c0SNathan Whitehorn 3157a8d25c0SNathan Whitehorn static int 316*f9d6e0a5SNathan Whitehorn chrp_cpuref_for_server(struct cpuref *cpuref, int cpu_n, int server) 3177a8d25c0SNathan Whitehorn { 3187a8d25c0SNathan Whitehorn char buf[8]; 3197a8d25c0SNathan Whitehorn phandle_t cpu, dev, root; 320*f9d6e0a5SNathan Whitehorn int res, cpuid, i, j; 3217a8d25c0SNathan Whitehorn 3227a8d25c0SNathan Whitehorn root = OF_peer(0); 3237a8d25c0SNathan Whitehorn 3247a8d25c0SNathan Whitehorn dev = OF_child(root); 3257a8d25c0SNathan Whitehorn while (dev != 0) { 3267a8d25c0SNathan Whitehorn res = OF_getprop(dev, "name", buf, sizeof(buf)); 3277a8d25c0SNathan Whitehorn if (res > 0 && strcmp(buf, "cpus") == 0) 3287a8d25c0SNathan Whitehorn break; 3297a8d25c0SNathan Whitehorn dev = OF_peer(dev); 3307a8d25c0SNathan Whitehorn } 3317a8d25c0SNathan Whitehorn if (dev == 0) { 3327a8d25c0SNathan Whitehorn /* 3337a8d25c0SNathan Whitehorn * psim doesn't have a name property on the /cpus node, 3347a8d25c0SNathan Whitehorn * but it can be found directly 3357a8d25c0SNathan Whitehorn */ 3367a8d25c0SNathan Whitehorn dev = OF_finddevice("/cpus"); 3377a8d25c0SNathan Whitehorn if (dev == 0) 3387a8d25c0SNathan Whitehorn return (ENOENT); 3397a8d25c0SNathan Whitehorn } 3407a8d25c0SNathan Whitehorn 341*f9d6e0a5SNathan Whitehorn i = 0; 342*f9d6e0a5SNathan Whitehorn for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) { 3437a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 344*f9d6e0a5SNathan Whitehorn if (res <= 0 || strcmp(buf, "cpu") != 0) 345*f9d6e0a5SNathan Whitehorn continue; 3467a8d25c0SNathan Whitehorn 347*f9d6e0a5SNathan Whitehorn res = OF_getproplen(cpu, "ibm,ppc-interrupt-server#s"); 348*f9d6e0a5SNathan Whitehorn if (res > 0) { 349*f9d6e0a5SNathan Whitehorn cell_t interrupt_servers[res/sizeof(cell_t)]; 350*f9d6e0a5SNathan Whitehorn OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", 351*f9d6e0a5SNathan Whitehorn interrupt_servers, res); 352*f9d6e0a5SNathan Whitehorn for (j = 0; j < res/sizeof(cell_t); j++) { 353*f9d6e0a5SNathan Whitehorn cpuid = interrupt_servers[j]; 354*f9d6e0a5SNathan Whitehorn if (server != -1 && cpuid == server) 355*f9d6e0a5SNathan Whitehorn break; 356*f9d6e0a5SNathan Whitehorn if (cpu_n != -1 && cpu_n == i) 357*f9d6e0a5SNathan Whitehorn break; 358*f9d6e0a5SNathan Whitehorn i++; 359*f9d6e0a5SNathan Whitehorn } 360*f9d6e0a5SNathan Whitehorn 361*f9d6e0a5SNathan Whitehorn if (j != res/sizeof(cell_t)) 362*f9d6e0a5SNathan Whitehorn break; 363*f9d6e0a5SNathan Whitehorn } else { 364509142e1SNathan Whitehorn res = OF_getencprop(cpu, "reg", &cpuid, sizeof(cpuid)); 3657a8d25c0SNathan Whitehorn if (res <= 0) 3667a8d25c0SNathan Whitehorn cpuid = 0; 367*f9d6e0a5SNathan Whitehorn if (server != -1 && cpuid == server) 368*f9d6e0a5SNathan Whitehorn break; 369*f9d6e0a5SNathan Whitehorn if (cpu_n != -1 && cpu_n == i) 370*f9d6e0a5SNathan Whitehorn break; 371*f9d6e0a5SNathan Whitehorn i++; 372*f9d6e0a5SNathan Whitehorn } 373*f9d6e0a5SNathan Whitehorn } 374*f9d6e0a5SNathan Whitehorn 375*f9d6e0a5SNathan Whitehorn if (cpu == 0) 376*f9d6e0a5SNathan Whitehorn return (ENOENT); 377*f9d6e0a5SNathan Whitehorn 378*f9d6e0a5SNathan Whitehorn cpuref->cr_hwref = cpuid; 379*f9d6e0a5SNathan Whitehorn cpuref->cr_cpuid = i; 3807a8d25c0SNathan Whitehorn 3817a8d25c0SNathan Whitehorn return (0); 3827a8d25c0SNathan Whitehorn } 3837a8d25c0SNathan Whitehorn 3847a8d25c0SNathan Whitehorn static int 385*f9d6e0a5SNathan Whitehorn chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 386*f9d6e0a5SNathan Whitehorn { 387*f9d6e0a5SNathan Whitehorn #ifdef BSP_MUST_BE_CPU_ZERO 388*f9d6e0a5SNathan Whitehorn return (chrp_smp_get_bsp(plat, cpuref)); 389*f9d6e0a5SNathan Whitehorn #else 390*f9d6e0a5SNathan Whitehorn return (chrp_cpuref_for_server(cpuref, 0, -1)); 391*f9d6e0a5SNathan Whitehorn #endif 392*f9d6e0a5SNathan Whitehorn } 393*f9d6e0a5SNathan Whitehorn 394*f9d6e0a5SNathan Whitehorn static int 3957a8d25c0SNathan Whitehorn chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 3967a8d25c0SNathan Whitehorn { 397*f9d6e0a5SNathan Whitehorn #ifdef BSP_MUST_BE_CPU_ZERO 398*f9d6e0a5SNathan Whitehorn int bsp, ncpus, err; 399*f9d6e0a5SNathan Whitehorn struct cpuref scratch; 4007a8d25c0SNathan Whitehorn 401*f9d6e0a5SNathan Whitehorn chrp_smp_get_bsp(plat, &scratch); 402*f9d6e0a5SNathan Whitehorn chrp_cpuref_for_server(&scratch, -1, scratch.cr_hwref); 403*f9d6e0a5SNathan Whitehorn bsp = scratch.cr_cpuid; 4047a8d25c0SNathan Whitehorn 405*f9d6e0a5SNathan Whitehorn for (ncpus = bsp; chrp_cpuref_for_server(&scratch, ncpus, -1) != 406*f9d6e0a5SNathan Whitehorn ENOENT; ncpus++) {} 407*f9d6e0a5SNathan Whitehorn if (cpuref->cr_cpuid + 1 == ncpus) 4087a8d25c0SNathan Whitehorn return (ENOENT); 409*f9d6e0a5SNathan Whitehorn err = chrp_cpuref_for_server(cpuref, 410*f9d6e0a5SNathan Whitehorn (cpuref->cr_cpuid + bsp + 1) % ncpus, -1); 411*f9d6e0a5SNathan Whitehorn if (cpuref->cr_cpuid >= bsp) 412*f9d6e0a5SNathan Whitehorn cpuref->cr_cpuid -= bsp; 413*f9d6e0a5SNathan Whitehorn else 414*f9d6e0a5SNathan Whitehorn cpuref->cr_cpuid = ncpus - (bsp - cpuref->cr_cpuid); 415*f9d6e0a5SNathan Whitehorn return (err); 416*f9d6e0a5SNathan Whitehorn #else 417*f9d6e0a5SNathan Whitehorn return (chrp_cpuref_for_server(cpuref, cpuref->cr_cpuid+1, -1)); 418*f9d6e0a5SNathan Whitehorn #endif 4197a8d25c0SNathan Whitehorn } 4207a8d25c0SNathan Whitehorn 4217a8d25c0SNathan Whitehorn static int 4227a8d25c0SNathan Whitehorn chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 4237a8d25c0SNathan Whitehorn { 4247a8d25c0SNathan Whitehorn ihandle_t inst; 4257a8d25c0SNathan Whitehorn phandle_t bsp, chosen; 4267a8d25c0SNathan Whitehorn int res, cpuid; 4277a8d25c0SNathan Whitehorn 4287a8d25c0SNathan Whitehorn chosen = OF_finddevice("/chosen"); 4297a8d25c0SNathan Whitehorn if (chosen == 0) 4307a8d25c0SNathan Whitehorn return (ENXIO); 4317a8d25c0SNathan Whitehorn 432509142e1SNathan Whitehorn res = OF_getencprop(chosen, "cpu", &inst, sizeof(inst)); 4337a8d25c0SNathan Whitehorn if (res < 0) 4347a8d25c0SNathan Whitehorn return (ENXIO); 4357a8d25c0SNathan Whitehorn 4367a8d25c0SNathan Whitehorn bsp = OF_instance_to_package(inst); 4377a8d25c0SNathan Whitehorn 4387a8d25c0SNathan Whitehorn /* Pick the primary thread. Can it be any other? */ 439509142e1SNathan Whitehorn res = OF_getencprop(bsp, "ibm,ppc-interrupt-server#s", &cpuid, 4407a8d25c0SNathan Whitehorn sizeof(cpuid)); 4417a8d25c0SNathan Whitehorn if (res <= 0) 442509142e1SNathan Whitehorn res = OF_getencprop(bsp, "reg", &cpuid, sizeof(cpuid)); 4437a8d25c0SNathan Whitehorn if (res <= 0) 4447a8d25c0SNathan Whitehorn cpuid = 0; 445*f9d6e0a5SNathan Whitehorn 446*f9d6e0a5SNathan Whitehorn chrp_cpuref_for_server(cpuref, -1, cpuid); 447*f9d6e0a5SNathan Whitehorn #ifdef BSP_MUST_BE_CPU_ZERO 4487a8d25c0SNathan Whitehorn cpuref->cr_cpuid = cpuid; 449*f9d6e0a5SNathan Whitehorn #endif 4507a8d25c0SNathan Whitehorn 4517a8d25c0SNathan Whitehorn return (0); 4527a8d25c0SNathan Whitehorn } 4537a8d25c0SNathan Whitehorn 4547a8d25c0SNathan Whitehorn #ifdef SMP 4557a8d25c0SNathan Whitehorn static int 4567a8d25c0SNathan Whitehorn chrp_smp_start_cpu(platform_t plat, struct pcpu *pc) 4577a8d25c0SNathan Whitehorn { 4587a8d25c0SNathan Whitehorn cell_t start_cpu; 4597a8d25c0SNathan Whitehorn int result, err, timeout; 4607a8d25c0SNathan Whitehorn 4617a8d25c0SNathan Whitehorn if (!rtas_exists()) { 4627a8d25c0SNathan Whitehorn printf("RTAS uninitialized: unable to start AP %d\n", 4637a8d25c0SNathan Whitehorn pc->pc_cpuid); 4647a8d25c0SNathan Whitehorn return (ENXIO); 4657a8d25c0SNathan Whitehorn } 4667a8d25c0SNathan Whitehorn 4677a8d25c0SNathan Whitehorn start_cpu = rtas_token_lookup("start-cpu"); 4687a8d25c0SNathan Whitehorn if (start_cpu == -1) { 4697a8d25c0SNathan Whitehorn printf("RTAS unknown method: unable to start AP %d\n", 4707a8d25c0SNathan Whitehorn pc->pc_cpuid); 4717a8d25c0SNathan Whitehorn return (ENXIO); 4727a8d25c0SNathan Whitehorn } 4737a8d25c0SNathan Whitehorn 4747a8d25c0SNathan Whitehorn ap_pcpu = pc; 4757a8d25c0SNathan Whitehorn powerpc_sync(); 4767a8d25c0SNathan Whitehorn 477*f9d6e0a5SNathan Whitehorn result = rtas_call_method(start_cpu, 3, 1, pc->pc_hwref, EXC_RST, pc, 4787a8d25c0SNathan Whitehorn &err); 4797a8d25c0SNathan Whitehorn if (result < 0 || err != 0) { 4807a8d25c0SNathan Whitehorn printf("RTAS error (%d/%d): unable to start AP %d\n", 4817a8d25c0SNathan Whitehorn result, err, pc->pc_cpuid); 4827a8d25c0SNathan Whitehorn return (ENXIO); 4837a8d25c0SNathan Whitehorn } 4847a8d25c0SNathan Whitehorn 4857a8d25c0SNathan Whitehorn timeout = 10000; 4867a8d25c0SNathan Whitehorn while (!pc->pc_awake && timeout--) 4877a8d25c0SNathan Whitehorn DELAY(100); 4887a8d25c0SNathan Whitehorn 4897a8d25c0SNathan Whitehorn return ((pc->pc_awake) ? 0 : EBUSY); 4907a8d25c0SNathan Whitehorn } 4917a8d25c0SNathan Whitehorn 4927a8d25c0SNathan Whitehorn static struct cpu_group * 4937a8d25c0SNathan Whitehorn chrp_smp_topo(platform_t plat) 4947a8d25c0SNathan Whitehorn { 495*f9d6e0a5SNathan Whitehorn char buf[8]; 496*f9d6e0a5SNathan Whitehorn phandle_t cpu, dev, root; 497*f9d6e0a5SNathan Whitehorn int res, nthreads; 4987a8d25c0SNathan Whitehorn 499*f9d6e0a5SNathan Whitehorn root = OF_peer(0); 500*f9d6e0a5SNathan Whitehorn 501*f9d6e0a5SNathan Whitehorn dev = OF_child(root); 502*f9d6e0a5SNathan Whitehorn while (dev != 0) { 503*f9d6e0a5SNathan Whitehorn res = OF_getprop(dev, "name", buf, sizeof(buf)); 504*f9d6e0a5SNathan Whitehorn if (res > 0 && strcmp(buf, "cpus") == 0) 505*f9d6e0a5SNathan Whitehorn break; 506*f9d6e0a5SNathan Whitehorn dev = OF_peer(dev); 5077a8d25c0SNathan Whitehorn } 5087a8d25c0SNathan Whitehorn 509*f9d6e0a5SNathan Whitehorn nthreads = 1; 510*f9d6e0a5SNathan Whitehorn for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) { 511*f9d6e0a5SNathan Whitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 512*f9d6e0a5SNathan Whitehorn if (res <= 0 || strcmp(buf, "cpu") != 0) 513*f9d6e0a5SNathan Whitehorn continue; 514*f9d6e0a5SNathan Whitehorn 515*f9d6e0a5SNathan Whitehorn res = OF_getproplen(cpu, "ibm,ppc-interrupt-server#s"); 516*f9d6e0a5SNathan Whitehorn 517*f9d6e0a5SNathan Whitehorn if (res >= 0) 518*f9d6e0a5SNathan Whitehorn nthreads = res / sizeof(cell_t); 519*f9d6e0a5SNathan Whitehorn else 520*f9d6e0a5SNathan Whitehorn nthreads = 1; 521*f9d6e0a5SNathan Whitehorn break; 522*f9d6e0a5SNathan Whitehorn } 523*f9d6e0a5SNathan Whitehorn 524*f9d6e0a5SNathan Whitehorn if (mp_ncpus % nthreads != 0) { 5257a8d25c0SNathan Whitehorn printf("WARNING: Irregular SMP topology. Performance may be " 526*f9d6e0a5SNathan Whitehorn "suboptimal (%d threads, %d on first core)\n", 527*f9d6e0a5SNathan Whitehorn mp_ncpus, nthreads); 5287a8d25c0SNathan Whitehorn return (smp_topo_none()); 5297a8d25c0SNathan Whitehorn } 5307a8d25c0SNathan Whitehorn 5317a8d25c0SNathan Whitehorn /* Don't do anything fancier for non-threaded SMP */ 532*f9d6e0a5SNathan Whitehorn if (nthreads == 1) 5337a8d25c0SNathan Whitehorn return (smp_topo_none()); 5347a8d25c0SNathan Whitehorn 535*f9d6e0a5SNathan Whitehorn return (smp_topo_1level(CG_SHARE_L1, nthreads, CG_FLAG_SMT)); 5367a8d25c0SNathan Whitehorn } 5377a8d25c0SNathan Whitehorn #endif 5387a8d25c0SNathan Whitehorn 5397a8d25c0SNathan Whitehorn static void 5407a8d25c0SNathan Whitehorn chrp_reset(platform_t platform) 5417a8d25c0SNathan Whitehorn { 542*f9d6e0a5SNathan Whitehorn cell_t token, status; 543*f9d6e0a5SNathan Whitehorn 544*f9d6e0a5SNathan Whitehorn if (rtas_exists()) { 545*f9d6e0a5SNathan Whitehorn token = rtas_token_lookup("system-reboot"); 546*f9d6e0a5SNathan Whitehorn if (token != -1) 547*f9d6e0a5SNathan Whitehorn rtas_call_method(token, 0, 1, &status); 548*f9d6e0a5SNathan Whitehorn } else { 5497a8d25c0SNathan Whitehorn OF_reboot(); 5507a8d25c0SNathan Whitehorn } 551*f9d6e0a5SNathan Whitehorn } 5527a8d25c0SNathan Whitehorn 5537a8d25c0SNathan Whitehorn #ifdef __powerpc64__ 5547a8d25c0SNathan Whitehorn static void 5557a8d25c0SNathan Whitehorn phyp_cpu_idle(sbintime_t sbt) 5567a8d25c0SNathan Whitehorn { 557e21d69e9SNathan Whitehorn register_t msr; 558e21d69e9SNathan Whitehorn 559e21d69e9SNathan Whitehorn msr = mfmsr(); 560e21d69e9SNathan Whitehorn 561e21d69e9SNathan Whitehorn mtmsr(msr & ~PSL_EE); 562e21d69e9SNathan Whitehorn if (sched_runnable()) { 563e21d69e9SNathan Whitehorn mtmsr(msr); 564e21d69e9SNathan Whitehorn return; 565e21d69e9SNathan Whitehorn } 566e21d69e9SNathan Whitehorn 567e21d69e9SNathan Whitehorn phyp_hcall(H_CEDE); /* Re-enables interrupts internally */ 568e21d69e9SNathan Whitehorn mtmsr(msr); 5697a8d25c0SNathan Whitehorn } 5707a8d25c0SNathan Whitehorn 5717a8d25c0SNathan Whitehorn static void 5727a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform) 5737a8d25c0SNathan Whitehorn { 5747a8d25c0SNathan Whitehorn if (!(mfmsr() & PSL_HV)) { 575f1e48417SNathan Whitehorn /* Register VPA */ 576f1e48417SNathan Whitehorn phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(cpuid), 577f1e48417SNathan Whitehorn splpar_vpa[PCPU_GET(cpuid)]); 578f1e48417SNathan Whitehorn 5797a8d25c0SNathan Whitehorn /* Set interrupt priority */ 5807a8d25c0SNathan Whitehorn phyp_hcall(H_CPPR, 0xff); 5817a8d25c0SNathan Whitehorn } 5827a8d25c0SNathan Whitehorn } 5837a8d25c0SNathan Whitehorn #else 5847a8d25c0SNathan Whitehorn static void 5857a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform) 5867a8d25c0SNathan Whitehorn { 5877a8d25c0SNathan Whitehorn } 5887a8d25c0SNathan Whitehorn #endif 5897a8d25c0SNathan Whitehorn 590