17a8d25c0SNathan Whitehorn /*- 27a8d25c0SNathan Whitehorn * Copyright (c) 2008 Marcel Moolenaar 37a8d25c0SNathan Whitehorn * Copyright (c) 2009 Nathan Whitehorn 47a8d25c0SNathan Whitehorn * All rights reserved. 57a8d25c0SNathan Whitehorn * 67a8d25c0SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 77a8d25c0SNathan Whitehorn * modification, are permitted provided that the following conditions 87a8d25c0SNathan Whitehorn * are met: 97a8d25c0SNathan Whitehorn * 107a8d25c0SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 117a8d25c0SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 127a8d25c0SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 137a8d25c0SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 147a8d25c0SNathan Whitehorn * documentation and/or other materials provided with the distribution. 157a8d25c0SNathan Whitehorn * 167a8d25c0SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 177a8d25c0SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 187a8d25c0SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 197a8d25c0SNathan Whitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 207a8d25c0SNathan Whitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 217a8d25c0SNathan Whitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 227a8d25c0SNathan Whitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 237a8d25c0SNathan Whitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 247a8d25c0SNathan Whitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 257a8d25c0SNathan Whitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 267a8d25c0SNathan Whitehorn */ 277a8d25c0SNathan Whitehorn 287a8d25c0SNathan Whitehorn #include <sys/cdefs.h> 297a8d25c0SNathan Whitehorn __FBSDID("$FreeBSD$"); 307a8d25c0SNathan Whitehorn 317a8d25c0SNathan Whitehorn #include <sys/param.h> 327a8d25c0SNathan Whitehorn #include <sys/systm.h> 337a8d25c0SNathan Whitehorn #include <sys/kernel.h> 347a8d25c0SNathan Whitehorn #include <sys/bus.h> 357a8d25c0SNathan Whitehorn #include <sys/pcpu.h> 367a8d25c0SNathan Whitehorn #include <sys/proc.h> 377a8d25c0SNathan Whitehorn #include <sys/smp.h> 387a8d25c0SNathan Whitehorn #include <vm/vm.h> 397a8d25c0SNathan Whitehorn #include <vm/pmap.h> 407a8d25c0SNathan Whitehorn 417a8d25c0SNathan Whitehorn #include <machine/bus.h> 427a8d25c0SNathan Whitehorn #include <machine/cpu.h> 437a8d25c0SNathan Whitehorn #include <machine/hid.h> 447a8d25c0SNathan Whitehorn #include <machine/platformvar.h> 457a8d25c0SNathan Whitehorn #include <machine/pmap.h> 467a8d25c0SNathan Whitehorn #include <machine/rtas.h> 477a8d25c0SNathan Whitehorn #include <machine/smp.h> 487a8d25c0SNathan Whitehorn #include <machine/spr.h> 49258dbffeSNathan Whitehorn #include <machine/trap.h> 507a8d25c0SNathan Whitehorn 517a8d25c0SNathan Whitehorn #include <dev/ofw/openfirm.h> 527a8d25c0SNathan Whitehorn #include <machine/ofw_machdep.h> 537a8d25c0SNathan Whitehorn 547a8d25c0SNathan Whitehorn #include "platform_if.h" 557a8d25c0SNathan Whitehorn 567a8d25c0SNathan Whitehorn #ifdef SMP 577a8d25c0SNathan Whitehorn extern void *ap_pcpu; 587a8d25c0SNathan Whitehorn #endif 597a8d25c0SNathan Whitehorn 607a8d25c0SNathan Whitehorn #ifdef __powerpc64__ 61*f1e48417SNathan Whitehorn static uint8_t splpar_vpa[MAXCPU][640] __aligned(128); /* XXX: dpcpu */ 627a8d25c0SNathan Whitehorn #endif 637a8d25c0SNathan Whitehorn 647a8d25c0SNathan Whitehorn static vm_offset_t realmaxaddr = VM_MAX_ADDRESS; 657a8d25c0SNathan Whitehorn 667a8d25c0SNathan Whitehorn static int chrp_probe(platform_t); 677a8d25c0SNathan Whitehorn static int chrp_attach(platform_t); 68c1cb22d7SNathan Whitehorn void chrp_mem_regions(platform_t, struct mem_region *phys, int *physsz, 69c1cb22d7SNathan Whitehorn struct mem_region *avail, int *availsz); 707a8d25c0SNathan Whitehorn static vm_offset_t chrp_real_maxaddr(platform_t); 717a8d25c0SNathan Whitehorn static u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref); 727a8d25c0SNathan Whitehorn static int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref); 737a8d25c0SNathan Whitehorn static int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref); 747a8d25c0SNathan Whitehorn static int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref); 757a8d25c0SNathan Whitehorn static void chrp_smp_ap_init(platform_t); 767a8d25c0SNathan Whitehorn #ifdef SMP 777a8d25c0SNathan Whitehorn static int chrp_smp_start_cpu(platform_t, struct pcpu *cpu); 787a8d25c0SNathan Whitehorn static struct cpu_group *chrp_smp_topo(platform_t plat); 797a8d25c0SNathan Whitehorn #endif 807a8d25c0SNathan Whitehorn static void chrp_reset(platform_t); 817a8d25c0SNathan Whitehorn #ifdef __powerpc64__ 827a8d25c0SNathan Whitehorn #include "phyp-hvcall.h" 837a8d25c0SNathan Whitehorn static void phyp_cpu_idle(sbintime_t sbt); 847a8d25c0SNathan Whitehorn #endif 857a8d25c0SNathan Whitehorn 867a8d25c0SNathan Whitehorn static platform_method_t chrp_methods[] = { 877a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_probe, chrp_probe), 887a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_attach, chrp_attach), 897a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_mem_regions, chrp_mem_regions), 907a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_real_maxaddr, chrp_real_maxaddr), 917a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_timebase_freq, chrp_timebase_freq), 927a8d25c0SNathan Whitehorn 937a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_ap_init, chrp_smp_ap_init), 947a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_first_cpu, chrp_smp_first_cpu), 957a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_next_cpu, chrp_smp_next_cpu), 967a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_get_bsp, chrp_smp_get_bsp), 977a8d25c0SNathan Whitehorn #ifdef SMP 987a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_start_cpu, chrp_smp_start_cpu), 997a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_topo, chrp_smp_topo), 1007a8d25c0SNathan Whitehorn #endif 1017a8d25c0SNathan Whitehorn 1027a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_reset, chrp_reset), 1037a8d25c0SNathan Whitehorn 1047a8d25c0SNathan Whitehorn { 0, 0 } 1057a8d25c0SNathan Whitehorn }; 1067a8d25c0SNathan Whitehorn 1077a8d25c0SNathan Whitehorn static platform_def_t chrp_platform = { 1087a8d25c0SNathan Whitehorn "chrp", 1097a8d25c0SNathan Whitehorn chrp_methods, 1107a8d25c0SNathan Whitehorn 0 1117a8d25c0SNathan Whitehorn }; 1127a8d25c0SNathan Whitehorn 1137a8d25c0SNathan Whitehorn PLATFORM_DEF(chrp_platform); 1147a8d25c0SNathan Whitehorn 1157a8d25c0SNathan Whitehorn static int 1167a8d25c0SNathan Whitehorn chrp_probe(platform_t plat) 1177a8d25c0SNathan Whitehorn { 1187a8d25c0SNathan Whitehorn if (OF_finddevice("/memory") != -1 || OF_finddevice("/memory@0") != -1) 1197a8d25c0SNathan Whitehorn return (BUS_PROBE_GENERIC); 1207a8d25c0SNathan Whitehorn 1217a8d25c0SNathan Whitehorn return (ENXIO); 1227a8d25c0SNathan Whitehorn } 1237a8d25c0SNathan Whitehorn 1247a8d25c0SNathan Whitehorn static int 1257a8d25c0SNathan Whitehorn chrp_attach(platform_t plat) 1267a8d25c0SNathan Whitehorn { 127*f1e48417SNathan Whitehorn int i; 128*f1e48417SNathan Whitehorn 1297a8d25c0SNathan Whitehorn #ifdef __powerpc64__ 1307a8d25c0SNathan Whitehorn /* XXX: check for /rtas/ibm,hypertas-functions? */ 1317a8d25c0SNathan Whitehorn if (!(mfmsr() & PSL_HV)) { 1327a8d25c0SNathan Whitehorn struct mem_region *phys, *avail; 1337a8d25c0SNathan Whitehorn int nphys, navail; 1347a8d25c0SNathan Whitehorn mem_regions(&phys, &nphys, &avail, &navail); 1357a8d25c0SNathan Whitehorn realmaxaddr = phys[0].mr_size; 1367a8d25c0SNathan Whitehorn 1377a8d25c0SNathan Whitehorn pmap_mmu_install("mmu_phyp", BUS_PROBE_SPECIFIC); 1387a8d25c0SNathan Whitehorn cpu_idle_hook = phyp_cpu_idle; 1397a8d25c0SNathan Whitehorn 1407a8d25c0SNathan Whitehorn /* Set up important VPA fields */ 141*f1e48417SNathan Whitehorn for (i = 0; i < MAXCPU; i++) { 142*f1e48417SNathan Whitehorn bzero(splpar_vpa[i], sizeof(splpar_vpa)); 143*f1e48417SNathan Whitehorn /* First two: VPA size */ 144*f1e48417SNathan Whitehorn splpar_vpa[i][4] = 145*f1e48417SNathan Whitehorn (uint8_t)((sizeof(splpar_vpa[i]) >> 8) & 0xff); 146*f1e48417SNathan Whitehorn splpar_vpa[i][5] = 147*f1e48417SNathan Whitehorn (uint8_t)(sizeof(splpar_vpa[i]) & 0xff); 148*f1e48417SNathan Whitehorn splpar_vpa[i][0xba] = 1; /* Maintain FPRs */ 149*f1e48417SNathan Whitehorn splpar_vpa[i][0xbb] = 1; /* Maintain PMCs */ 150*f1e48417SNathan Whitehorn splpar_vpa[i][0xfc] = 0xff; /* Maintain full SLB */ 151*f1e48417SNathan Whitehorn splpar_vpa[i][0xfd] = 0xff; 152*f1e48417SNathan Whitehorn splpar_vpa[i][0xff] = 1; /* Maintain Altivec */ 153*f1e48417SNathan Whitehorn } 1547a8d25c0SNathan Whitehorn mb(); 1557a8d25c0SNathan Whitehorn 1567a8d25c0SNathan Whitehorn /* Set up hypervisor CPU stuff */ 1577a8d25c0SNathan Whitehorn chrp_smp_ap_init(plat); 1587a8d25c0SNathan Whitehorn } 1597a8d25c0SNathan Whitehorn #endif 1607a8d25c0SNathan Whitehorn 1619f706727SNathan Whitehorn /* Some systems (e.g. QEMU) need Open Firmware to stand down */ 1629f706727SNathan Whitehorn ofw_quiesce(); 1639f706727SNathan Whitehorn 1647a8d25c0SNathan Whitehorn return (0); 1657a8d25c0SNathan Whitehorn } 1667a8d25c0SNathan Whitehorn 167c1cb22d7SNathan Whitehorn static int 168f5dfbe2fSAndreas Tobler parse_drconf_memory(struct mem_region *ofmem, int *msz, 169f5dfbe2fSAndreas Tobler struct mem_region *ofavail, int *asz) 1707a8d25c0SNathan Whitehorn { 171c1cb22d7SNathan Whitehorn phandle_t phandle; 172c1cb22d7SNathan Whitehorn vm_offset_t base; 173c1cb22d7SNathan Whitehorn int i, idx, len, lasz, lmsz, res; 174f5dfbe2fSAndreas Tobler uint32_t flags, lmb_size[2]; 175f5dfbe2fSAndreas Tobler uint64_t *dmem; 176c1cb22d7SNathan Whitehorn 177c1cb22d7SNathan Whitehorn lmsz = *msz; 178c1cb22d7SNathan Whitehorn lasz = *asz; 179c1cb22d7SNathan Whitehorn 180c1cb22d7SNathan Whitehorn phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory"); 181c1cb22d7SNathan Whitehorn if (phandle == -1) 182c1cb22d7SNathan Whitehorn /* No drconf node, return. */ 183c1cb22d7SNathan Whitehorn return (0); 184c1cb22d7SNathan Whitehorn 185c1cb22d7SNathan Whitehorn res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size)); 186c1cb22d7SNathan Whitehorn if (res == -1) 187c1cb22d7SNathan Whitehorn return (0); 188c1cb22d7SNathan Whitehorn printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20); 189c1cb22d7SNathan Whitehorn 190c1cb22d7SNathan Whitehorn /* Parse the /ibm,dynamic-memory. 191c1cb22d7SNathan Whitehorn The first position gives the # of entries. The next two words 192c1cb22d7SNathan Whitehorn reflect the address of the memory block. The next four words are 193c1cb22d7SNathan Whitehorn the DRC index, reserved, list index and flags. 194c1cb22d7SNathan Whitehorn (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory) 195c1cb22d7SNathan Whitehorn 196c1cb22d7SNathan Whitehorn #el Addr DRC-idx res list-idx flags 197c1cb22d7SNathan Whitehorn ------------------------------------------------- 198c1cb22d7SNathan Whitehorn | 4 | 8 | 4 | 4 | 4 | 4 |.... 199c1cb22d7SNathan Whitehorn ------------------------------------------------- 200c1cb22d7SNathan Whitehorn */ 201c1cb22d7SNathan Whitehorn 202c1cb22d7SNathan Whitehorn len = OF_getproplen(phandle, "ibm,dynamic-memory"); 203c1cb22d7SNathan Whitehorn if (len > 0) { 204c1cb22d7SNathan Whitehorn 205c1cb22d7SNathan Whitehorn /* We have to use a variable length array on the stack 206c1cb22d7SNathan Whitehorn since we have very limited stack space. 207c1cb22d7SNathan Whitehorn */ 208c1cb22d7SNathan Whitehorn cell_t arr[len/sizeof(cell_t)]; 209c1cb22d7SNathan Whitehorn 210c1cb22d7SNathan Whitehorn res = OF_getprop(phandle, "ibm,dynamic-memory", &arr, 211c1cb22d7SNathan Whitehorn sizeof(arr)); 212c1cb22d7SNathan Whitehorn if (res == -1) 213c1cb22d7SNathan Whitehorn return (0); 214c1cb22d7SNathan Whitehorn 215c1cb22d7SNathan Whitehorn /* Number of elements */ 216c1cb22d7SNathan Whitehorn idx = arr[0]; 217c1cb22d7SNathan Whitehorn 218f5dfbe2fSAndreas Tobler /* First address, in arr[1], arr[2]*/ 219f5dfbe2fSAndreas Tobler dmem = (uint64_t*)&arr[1]; 220c1cb22d7SNathan Whitehorn 221c1cb22d7SNathan Whitehorn for (i = 0; i < idx; i++) { 222c1cb22d7SNathan Whitehorn base = *dmem; 223c1cb22d7SNathan Whitehorn dmem += 2; 224c1cb22d7SNathan Whitehorn flags = *dmem; 225c1cb22d7SNathan Whitehorn /* Use region only if available and not reserved. */ 226c1cb22d7SNathan Whitehorn if ((flags & 0x8) && !(flags & 0x80)) { 227c1cb22d7SNathan Whitehorn ofmem[lmsz].mr_start = base; 228c1cb22d7SNathan Whitehorn ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1]; 229c1cb22d7SNathan Whitehorn ofavail[lasz].mr_start = base; 230c1cb22d7SNathan Whitehorn ofavail[lasz].mr_size = (vm_size_t)lmb_size[1]; 231c1cb22d7SNathan Whitehorn lmsz++; 232c1cb22d7SNathan Whitehorn lasz++; 233c1cb22d7SNathan Whitehorn } 234c1cb22d7SNathan Whitehorn dmem++; 235c1cb22d7SNathan Whitehorn } 236c1cb22d7SNathan Whitehorn } 237c1cb22d7SNathan Whitehorn 238c1cb22d7SNathan Whitehorn *msz = lmsz; 239c1cb22d7SNathan Whitehorn *asz = lasz; 240c1cb22d7SNathan Whitehorn 241c1cb22d7SNathan Whitehorn return (1); 242c1cb22d7SNathan Whitehorn } 243c1cb22d7SNathan Whitehorn 244c1cb22d7SNathan Whitehorn void 245c1cb22d7SNathan Whitehorn chrp_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 246c1cb22d7SNathan Whitehorn struct mem_region *avail, int *availsz) 247c1cb22d7SNathan Whitehorn { 248c1cb22d7SNathan Whitehorn vm_offset_t maxphysaddr; 249c1cb22d7SNathan Whitehorn int i; 250c1cb22d7SNathan Whitehorn 2517a8d25c0SNathan Whitehorn ofw_mem_regions(phys, physsz, avail, availsz); 252f5dfbe2fSAndreas Tobler parse_drconf_memory(phys, physsz, avail, availsz); 253c1cb22d7SNathan Whitehorn 254c1cb22d7SNathan Whitehorn /* 255c1cb22d7SNathan Whitehorn * On some firmwares (SLOF), some memory may be marked available that 256c1cb22d7SNathan Whitehorn * doesn't actually exist. This manifests as an extension of the last 257c1cb22d7SNathan Whitehorn * available segment past the end of physical memory, so truncate that 258c1cb22d7SNathan Whitehorn * one. 259c1cb22d7SNathan Whitehorn */ 260c1cb22d7SNathan Whitehorn maxphysaddr = 0; 261c1cb22d7SNathan Whitehorn for (i = 0; i < *physsz; i++) 262c1cb22d7SNathan Whitehorn if (phys[i].mr_start + phys[i].mr_size > maxphysaddr) 263c1cb22d7SNathan Whitehorn maxphysaddr = phys[i].mr_start + phys[i].mr_size; 264c1cb22d7SNathan Whitehorn 265c1cb22d7SNathan Whitehorn for (i = 0; i < *availsz; i++) 266c1cb22d7SNathan Whitehorn if (avail[i].mr_start + avail[i].mr_size > maxphysaddr) 267c1cb22d7SNathan Whitehorn avail[i].mr_size = maxphysaddr - avail[i].mr_start; 2687a8d25c0SNathan Whitehorn } 2697a8d25c0SNathan Whitehorn 2707a8d25c0SNathan Whitehorn static vm_offset_t 2717a8d25c0SNathan Whitehorn chrp_real_maxaddr(platform_t plat) 2727a8d25c0SNathan Whitehorn { 2737a8d25c0SNathan Whitehorn return (realmaxaddr); 2747a8d25c0SNathan Whitehorn } 2757a8d25c0SNathan Whitehorn 2767a8d25c0SNathan Whitehorn static u_long 2777a8d25c0SNathan Whitehorn chrp_timebase_freq(platform_t plat, struct cpuref *cpuref) 2787a8d25c0SNathan Whitehorn { 2797a8d25c0SNathan Whitehorn phandle_t phandle; 2807a8d25c0SNathan Whitehorn int32_t ticks = -1; 2817a8d25c0SNathan Whitehorn 2827a8d25c0SNathan Whitehorn phandle = cpuref->cr_hwref; 2837a8d25c0SNathan Whitehorn 2847a8d25c0SNathan Whitehorn OF_getprop(phandle, "timebase-frequency", &ticks, sizeof(ticks)); 2857a8d25c0SNathan Whitehorn 2867a8d25c0SNathan Whitehorn if (ticks <= 0) 2877a8d25c0SNathan Whitehorn panic("Unable to determine timebase frequency!"); 2887a8d25c0SNathan Whitehorn 2897a8d25c0SNathan Whitehorn return (ticks); 2907a8d25c0SNathan Whitehorn } 2917a8d25c0SNathan Whitehorn 2927a8d25c0SNathan Whitehorn static int 2937a8d25c0SNathan Whitehorn chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 2947a8d25c0SNathan Whitehorn { 2957a8d25c0SNathan Whitehorn char buf[8]; 2967a8d25c0SNathan Whitehorn phandle_t cpu, dev, root; 2977a8d25c0SNathan Whitehorn int res, cpuid; 2987a8d25c0SNathan Whitehorn 2997a8d25c0SNathan Whitehorn root = OF_peer(0); 3007a8d25c0SNathan Whitehorn 3017a8d25c0SNathan Whitehorn dev = OF_child(root); 3027a8d25c0SNathan Whitehorn while (dev != 0) { 3037a8d25c0SNathan Whitehorn res = OF_getprop(dev, "name", buf, sizeof(buf)); 3047a8d25c0SNathan Whitehorn if (res > 0 && strcmp(buf, "cpus") == 0) 3057a8d25c0SNathan Whitehorn break; 3067a8d25c0SNathan Whitehorn dev = OF_peer(dev); 3077a8d25c0SNathan Whitehorn } 3087a8d25c0SNathan Whitehorn if (dev == 0) { 3097a8d25c0SNathan Whitehorn /* 3107a8d25c0SNathan Whitehorn * psim doesn't have a name property on the /cpus node, 3117a8d25c0SNathan Whitehorn * but it can be found directly 3127a8d25c0SNathan Whitehorn */ 3137a8d25c0SNathan Whitehorn dev = OF_finddevice("/cpus"); 3147a8d25c0SNathan Whitehorn if (dev == 0) 3157a8d25c0SNathan Whitehorn return (ENOENT); 3167a8d25c0SNathan Whitehorn } 3177a8d25c0SNathan Whitehorn 3187a8d25c0SNathan Whitehorn cpu = OF_child(dev); 3197a8d25c0SNathan Whitehorn 3207a8d25c0SNathan Whitehorn while (cpu != 0) { 3217a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 3227a8d25c0SNathan Whitehorn if (res > 0 && strcmp(buf, "cpu") == 0) 3237a8d25c0SNathan Whitehorn break; 3247a8d25c0SNathan Whitehorn cpu = OF_peer(cpu); 3257a8d25c0SNathan Whitehorn } 3267a8d25c0SNathan Whitehorn if (cpu == 0) 3277a8d25c0SNathan Whitehorn return (ENOENT); 3287a8d25c0SNathan Whitehorn 3297a8d25c0SNathan Whitehorn cpuref->cr_hwref = cpu; 3307a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid, 3317a8d25c0SNathan Whitehorn sizeof(cpuid)); 3327a8d25c0SNathan Whitehorn if (res <= 0) 3337a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 3347a8d25c0SNathan Whitehorn if (res <= 0) 3357a8d25c0SNathan Whitehorn cpuid = 0; 3367a8d25c0SNathan Whitehorn cpuref->cr_cpuid = cpuid; 3377a8d25c0SNathan Whitehorn 3387a8d25c0SNathan Whitehorn return (0); 3397a8d25c0SNathan Whitehorn } 3407a8d25c0SNathan Whitehorn 3417a8d25c0SNathan Whitehorn static int 3427a8d25c0SNathan Whitehorn chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 3437a8d25c0SNathan Whitehorn { 3447a8d25c0SNathan Whitehorn char buf[8]; 3457a8d25c0SNathan Whitehorn phandle_t cpu; 3467a8d25c0SNathan Whitehorn int i, res, cpuid; 3477a8d25c0SNathan Whitehorn 3487a8d25c0SNathan Whitehorn /* Check for whether it should be the next thread */ 3497a8d25c0SNathan Whitehorn res = OF_getproplen(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s"); 3507a8d25c0SNathan Whitehorn if (res > 0) { 3517a8d25c0SNathan Whitehorn cell_t interrupt_servers[res/sizeof(cell_t)]; 3527a8d25c0SNathan Whitehorn OF_getprop(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s", 3537a8d25c0SNathan Whitehorn interrupt_servers, res); 3547a8d25c0SNathan Whitehorn for (i = 0; i < res/sizeof(cell_t) - 1; i++) { 3557a8d25c0SNathan Whitehorn if (interrupt_servers[i] == cpuref->cr_cpuid) { 3567a8d25c0SNathan Whitehorn cpuref->cr_cpuid = interrupt_servers[i+1]; 3577a8d25c0SNathan Whitehorn return (0); 3587a8d25c0SNathan Whitehorn } 3597a8d25c0SNathan Whitehorn } 3607a8d25c0SNathan Whitehorn } 3617a8d25c0SNathan Whitehorn 3627a8d25c0SNathan Whitehorn /* Next CPU core/package */ 3637a8d25c0SNathan Whitehorn cpu = OF_peer(cpuref->cr_hwref); 3647a8d25c0SNathan Whitehorn while (cpu != 0) { 3657a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 3667a8d25c0SNathan Whitehorn if (res > 0 && strcmp(buf, "cpu") == 0) 3677a8d25c0SNathan Whitehorn break; 3687a8d25c0SNathan Whitehorn cpu = OF_peer(cpu); 3697a8d25c0SNathan Whitehorn } 3707a8d25c0SNathan Whitehorn if (cpu == 0) 3717a8d25c0SNathan Whitehorn return (ENOENT); 3727a8d25c0SNathan Whitehorn 3737a8d25c0SNathan Whitehorn cpuref->cr_hwref = cpu; 3747a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid, 3757a8d25c0SNathan Whitehorn sizeof(cpuid)); 3767a8d25c0SNathan Whitehorn if (res <= 0) 3777a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 3787a8d25c0SNathan Whitehorn if (res <= 0) 3797a8d25c0SNathan Whitehorn cpuid = 0; 3807a8d25c0SNathan Whitehorn cpuref->cr_cpuid = cpuid; 3817a8d25c0SNathan Whitehorn 3827a8d25c0SNathan Whitehorn return (0); 3837a8d25c0SNathan Whitehorn } 3847a8d25c0SNathan Whitehorn 3857a8d25c0SNathan Whitehorn static int 3867a8d25c0SNathan Whitehorn chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 3877a8d25c0SNathan Whitehorn { 3887a8d25c0SNathan Whitehorn ihandle_t inst; 3897a8d25c0SNathan Whitehorn phandle_t bsp, chosen; 3907a8d25c0SNathan Whitehorn int res, cpuid; 3917a8d25c0SNathan Whitehorn 3927a8d25c0SNathan Whitehorn chosen = OF_finddevice("/chosen"); 3937a8d25c0SNathan Whitehorn if (chosen == 0) 3947a8d25c0SNathan Whitehorn return (ENXIO); 3957a8d25c0SNathan Whitehorn 3967a8d25c0SNathan Whitehorn res = OF_getprop(chosen, "cpu", &inst, sizeof(inst)); 3977a8d25c0SNathan Whitehorn if (res < 0) 3987a8d25c0SNathan Whitehorn return (ENXIO); 3997a8d25c0SNathan Whitehorn 4007a8d25c0SNathan Whitehorn bsp = OF_instance_to_package(inst); 4017a8d25c0SNathan Whitehorn 4027a8d25c0SNathan Whitehorn /* Pick the primary thread. Can it be any other? */ 4037a8d25c0SNathan Whitehorn cpuref->cr_hwref = bsp; 4047a8d25c0SNathan Whitehorn res = OF_getprop(bsp, "ibm,ppc-interrupt-server#s", &cpuid, 4057a8d25c0SNathan Whitehorn sizeof(cpuid)); 4067a8d25c0SNathan Whitehorn if (res <= 0) 4077a8d25c0SNathan Whitehorn res = OF_getprop(bsp, "reg", &cpuid, sizeof(cpuid)); 4087a8d25c0SNathan Whitehorn if (res <= 0) 4097a8d25c0SNathan Whitehorn cpuid = 0; 4107a8d25c0SNathan Whitehorn cpuref->cr_cpuid = cpuid; 4117a8d25c0SNathan Whitehorn 4127a8d25c0SNathan Whitehorn return (0); 4137a8d25c0SNathan Whitehorn } 4147a8d25c0SNathan Whitehorn 4157a8d25c0SNathan Whitehorn #ifdef SMP 4167a8d25c0SNathan Whitehorn static int 4177a8d25c0SNathan Whitehorn chrp_smp_start_cpu(platform_t plat, struct pcpu *pc) 4187a8d25c0SNathan Whitehorn { 4197a8d25c0SNathan Whitehorn cell_t start_cpu; 4207a8d25c0SNathan Whitehorn int result, err, timeout; 4217a8d25c0SNathan Whitehorn 4227a8d25c0SNathan Whitehorn if (!rtas_exists()) { 4237a8d25c0SNathan Whitehorn printf("RTAS uninitialized: unable to start AP %d\n", 4247a8d25c0SNathan Whitehorn pc->pc_cpuid); 4257a8d25c0SNathan Whitehorn return (ENXIO); 4267a8d25c0SNathan Whitehorn } 4277a8d25c0SNathan Whitehorn 4287a8d25c0SNathan Whitehorn start_cpu = rtas_token_lookup("start-cpu"); 4297a8d25c0SNathan Whitehorn if (start_cpu == -1) { 4307a8d25c0SNathan Whitehorn printf("RTAS unknown method: unable to start AP %d\n", 4317a8d25c0SNathan Whitehorn pc->pc_cpuid); 4327a8d25c0SNathan Whitehorn return (ENXIO); 4337a8d25c0SNathan Whitehorn } 4347a8d25c0SNathan Whitehorn 4357a8d25c0SNathan Whitehorn ap_pcpu = pc; 4367a8d25c0SNathan Whitehorn powerpc_sync(); 4377a8d25c0SNathan Whitehorn 4387a8d25c0SNathan Whitehorn result = rtas_call_method(start_cpu, 3, 1, pc->pc_cpuid, EXC_RST, pc, 4397a8d25c0SNathan Whitehorn &err); 4407a8d25c0SNathan Whitehorn if (result < 0 || err != 0) { 4417a8d25c0SNathan Whitehorn printf("RTAS error (%d/%d): unable to start AP %d\n", 4427a8d25c0SNathan Whitehorn result, err, pc->pc_cpuid); 4437a8d25c0SNathan Whitehorn return (ENXIO); 4447a8d25c0SNathan Whitehorn } 4457a8d25c0SNathan Whitehorn 4467a8d25c0SNathan Whitehorn timeout = 10000; 4477a8d25c0SNathan Whitehorn while (!pc->pc_awake && timeout--) 4487a8d25c0SNathan Whitehorn DELAY(100); 4497a8d25c0SNathan Whitehorn 4507a8d25c0SNathan Whitehorn return ((pc->pc_awake) ? 0 : EBUSY); 4517a8d25c0SNathan Whitehorn } 4527a8d25c0SNathan Whitehorn 4537a8d25c0SNathan Whitehorn static struct cpu_group * 4547a8d25c0SNathan Whitehorn chrp_smp_topo(platform_t plat) 4557a8d25c0SNathan Whitehorn { 4567a8d25c0SNathan Whitehorn struct pcpu *pc, *last_pc; 4577a8d25c0SNathan Whitehorn int i, ncores, ncpus; 4587a8d25c0SNathan Whitehorn 4597a8d25c0SNathan Whitehorn ncores = ncpus = 0; 4607a8d25c0SNathan Whitehorn last_pc = NULL; 4617a8d25c0SNathan Whitehorn for (i = 0; i <= mp_maxid; i++) { 4627a8d25c0SNathan Whitehorn pc = pcpu_find(i); 4637a8d25c0SNathan Whitehorn if (pc == NULL) 4647a8d25c0SNathan Whitehorn continue; 4657a8d25c0SNathan Whitehorn if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref) 4667a8d25c0SNathan Whitehorn ncores++; 4677a8d25c0SNathan Whitehorn last_pc = pc; 4687a8d25c0SNathan Whitehorn ncpus++; 4697a8d25c0SNathan Whitehorn } 4707a8d25c0SNathan Whitehorn 4717a8d25c0SNathan Whitehorn if (ncpus % ncores != 0) { 4727a8d25c0SNathan Whitehorn printf("WARNING: Irregular SMP topology. Performance may be " 4737a8d25c0SNathan Whitehorn "suboptimal (%d CPUS, %d cores)\n", ncpus, ncores); 4747a8d25c0SNathan Whitehorn return (smp_topo_none()); 4757a8d25c0SNathan Whitehorn } 4767a8d25c0SNathan Whitehorn 4777a8d25c0SNathan Whitehorn /* Don't do anything fancier for non-threaded SMP */ 4787a8d25c0SNathan Whitehorn if (ncpus == ncores) 4797a8d25c0SNathan Whitehorn return (smp_topo_none()); 4807a8d25c0SNathan Whitehorn 4817a8d25c0SNathan Whitehorn return (smp_topo_1level(CG_SHARE_L1, ncpus / ncores, CG_FLAG_SMT)); 4827a8d25c0SNathan Whitehorn } 4837a8d25c0SNathan Whitehorn #endif 4847a8d25c0SNathan Whitehorn 4857a8d25c0SNathan Whitehorn static void 4867a8d25c0SNathan Whitehorn chrp_reset(platform_t platform) 4877a8d25c0SNathan Whitehorn { 4887a8d25c0SNathan Whitehorn OF_reboot(); 4897a8d25c0SNathan Whitehorn } 4907a8d25c0SNathan Whitehorn 4917a8d25c0SNathan Whitehorn #ifdef __powerpc64__ 4927a8d25c0SNathan Whitehorn static void 4937a8d25c0SNathan Whitehorn phyp_cpu_idle(sbintime_t sbt) 4947a8d25c0SNathan Whitehorn { 4957a8d25c0SNathan Whitehorn phyp_hcall(H_CEDE); 4967a8d25c0SNathan Whitehorn } 4977a8d25c0SNathan Whitehorn 4987a8d25c0SNathan Whitehorn static void 4997a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform) 5007a8d25c0SNathan Whitehorn { 5017a8d25c0SNathan Whitehorn if (!(mfmsr() & PSL_HV)) { 502*f1e48417SNathan Whitehorn /* Register VPA */ 503*f1e48417SNathan Whitehorn phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(cpuid), 504*f1e48417SNathan Whitehorn splpar_vpa[PCPU_GET(cpuid)]); 505*f1e48417SNathan Whitehorn 5067a8d25c0SNathan Whitehorn /* Set interrupt priority */ 5077a8d25c0SNathan Whitehorn phyp_hcall(H_CPPR, 0xff); 5087a8d25c0SNathan Whitehorn } 5097a8d25c0SNathan Whitehorn } 5107a8d25c0SNathan Whitehorn #else 5117a8d25c0SNathan Whitehorn static void 5127a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform) 5137a8d25c0SNathan Whitehorn { 5147a8d25c0SNathan Whitehorn } 5157a8d25c0SNathan Whitehorn #endif 5167a8d25c0SNathan Whitehorn 517