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__ 617a8d25c0SNathan Whitehorn static uint8_t splpar_vpa[640] __aligned(64); 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); 68*c1cb22d7SNathan Whitehorn void chrp_mem_regions(platform_t, struct mem_region *phys, int *physsz, 69*c1cb22d7SNathan 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 { 1277a8d25c0SNathan Whitehorn #ifdef __powerpc64__ 1287a8d25c0SNathan Whitehorn /* XXX: check for /rtas/ibm,hypertas-functions? */ 1297a8d25c0SNathan Whitehorn if (!(mfmsr() & PSL_HV)) { 1307a8d25c0SNathan Whitehorn struct mem_region *phys, *avail; 1317a8d25c0SNathan Whitehorn int nphys, navail; 1327a8d25c0SNathan Whitehorn mem_regions(&phys, &nphys, &avail, &navail); 1337a8d25c0SNathan Whitehorn realmaxaddr = phys[0].mr_size; 1347a8d25c0SNathan Whitehorn 1357a8d25c0SNathan Whitehorn pmap_mmu_install("mmu_phyp", BUS_PROBE_SPECIFIC); 1367a8d25c0SNathan Whitehorn cpu_idle_hook = phyp_cpu_idle; 1377a8d25c0SNathan Whitehorn 1387a8d25c0SNathan Whitehorn /* Set up important VPA fields */ 1397a8d25c0SNathan Whitehorn bzero(splpar_vpa, sizeof(splpar_vpa)); 1407a8d25c0SNathan Whitehorn splpar_vpa[4] = (uint8_t)((sizeof(splpar_vpa) >> 8) & 0xff); 1417a8d25c0SNathan Whitehorn splpar_vpa[5] = (uint8_t)(sizeof(splpar_vpa) & 0xff); 1427a8d25c0SNathan Whitehorn splpar_vpa[0xba] = 1; /* Maintain FPRs */ 1437a8d25c0SNathan Whitehorn splpar_vpa[0xbb] = 1; /* Maintain PMCs */ 1447a8d25c0SNathan Whitehorn splpar_vpa[0xfc] = 0xff; /* Maintain full SLB */ 1457a8d25c0SNathan Whitehorn splpar_vpa[0xfd] = 0xff; 1467a8d25c0SNathan Whitehorn splpar_vpa[0xff] = 1; /* Maintain Altivec */ 1477a8d25c0SNathan Whitehorn mb(); 1487a8d25c0SNathan Whitehorn 1497a8d25c0SNathan Whitehorn /* Set up hypervisor CPU stuff */ 1507a8d25c0SNathan Whitehorn chrp_smp_ap_init(plat); 1517a8d25c0SNathan Whitehorn } 1527a8d25c0SNathan Whitehorn #endif 1537a8d25c0SNathan Whitehorn 1549f706727SNathan Whitehorn /* Some systems (e.g. QEMU) need Open Firmware to stand down */ 1559f706727SNathan Whitehorn ofw_quiesce(); 1569f706727SNathan Whitehorn 1577a8d25c0SNathan Whitehorn return (0); 1587a8d25c0SNathan Whitehorn } 1597a8d25c0SNathan Whitehorn 160*c1cb22d7SNathan Whitehorn static int 161*c1cb22d7SNathan Whitehorn parse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem, 162*c1cb22d7SNathan Whitehorn struct mem_region *ofavail) 1637a8d25c0SNathan Whitehorn { 164*c1cb22d7SNathan Whitehorn phandle_t phandle; 165*c1cb22d7SNathan Whitehorn vm_offset_t base; 166*c1cb22d7SNathan Whitehorn int i, idx, len, lasz, lmsz, res; 167*c1cb22d7SNathan Whitehorn uint32_t lmb_size[2]; 168*c1cb22d7SNathan Whitehorn unsigned long *dmem, flags; 169*c1cb22d7SNathan Whitehorn 170*c1cb22d7SNathan Whitehorn lmsz = *msz; 171*c1cb22d7SNathan Whitehorn lasz = *asz; 172*c1cb22d7SNathan Whitehorn 173*c1cb22d7SNathan Whitehorn phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory"); 174*c1cb22d7SNathan Whitehorn if (phandle == -1) 175*c1cb22d7SNathan Whitehorn /* No drconf node, return. */ 176*c1cb22d7SNathan Whitehorn return (0); 177*c1cb22d7SNathan Whitehorn 178*c1cb22d7SNathan Whitehorn res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size)); 179*c1cb22d7SNathan Whitehorn if (res == -1) 180*c1cb22d7SNathan Whitehorn return (0); 181*c1cb22d7SNathan Whitehorn printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20); 182*c1cb22d7SNathan Whitehorn 183*c1cb22d7SNathan Whitehorn /* Parse the /ibm,dynamic-memory. 184*c1cb22d7SNathan Whitehorn The first position gives the # of entries. The next two words 185*c1cb22d7SNathan Whitehorn reflect the address of the memory block. The next four words are 186*c1cb22d7SNathan Whitehorn the DRC index, reserved, list index and flags. 187*c1cb22d7SNathan Whitehorn (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory) 188*c1cb22d7SNathan Whitehorn 189*c1cb22d7SNathan Whitehorn #el Addr DRC-idx res list-idx flags 190*c1cb22d7SNathan Whitehorn ------------------------------------------------- 191*c1cb22d7SNathan Whitehorn | 4 | 8 | 4 | 4 | 4 | 4 |.... 192*c1cb22d7SNathan Whitehorn ------------------------------------------------- 193*c1cb22d7SNathan Whitehorn */ 194*c1cb22d7SNathan Whitehorn 195*c1cb22d7SNathan Whitehorn len = OF_getproplen(phandle, "ibm,dynamic-memory"); 196*c1cb22d7SNathan Whitehorn if (len > 0) { 197*c1cb22d7SNathan Whitehorn 198*c1cb22d7SNathan Whitehorn /* We have to use a variable length array on the stack 199*c1cb22d7SNathan Whitehorn since we have very limited stack space. 200*c1cb22d7SNathan Whitehorn */ 201*c1cb22d7SNathan Whitehorn cell_t arr[len/sizeof(cell_t)]; 202*c1cb22d7SNathan Whitehorn 203*c1cb22d7SNathan Whitehorn res = OF_getprop(phandle, "ibm,dynamic-memory", &arr, 204*c1cb22d7SNathan Whitehorn sizeof(arr)); 205*c1cb22d7SNathan Whitehorn if (res == -1) 206*c1cb22d7SNathan Whitehorn return (0); 207*c1cb22d7SNathan Whitehorn 208*c1cb22d7SNathan Whitehorn /* Number of elements */ 209*c1cb22d7SNathan Whitehorn idx = arr[0]; 210*c1cb22d7SNathan Whitehorn 211*c1cb22d7SNathan Whitehorn /* First address. */ 212*c1cb22d7SNathan Whitehorn dmem = (void*)&arr[1]; 213*c1cb22d7SNathan Whitehorn 214*c1cb22d7SNathan Whitehorn for (i = 0; i < idx; i++) { 215*c1cb22d7SNathan Whitehorn base = *dmem; 216*c1cb22d7SNathan Whitehorn dmem += 2; 217*c1cb22d7SNathan Whitehorn flags = *dmem; 218*c1cb22d7SNathan Whitehorn /* Use region only if available and not reserved. */ 219*c1cb22d7SNathan Whitehorn if ((flags & 0x8) && !(flags & 0x80)) { 220*c1cb22d7SNathan Whitehorn ofmem[lmsz].mr_start = base; 221*c1cb22d7SNathan Whitehorn ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1]; 222*c1cb22d7SNathan Whitehorn ofavail[lasz].mr_start = base; 223*c1cb22d7SNathan Whitehorn ofavail[lasz].mr_size = (vm_size_t)lmb_size[1]; 224*c1cb22d7SNathan Whitehorn lmsz++; 225*c1cb22d7SNathan Whitehorn lasz++; 226*c1cb22d7SNathan Whitehorn } 227*c1cb22d7SNathan Whitehorn dmem++; 228*c1cb22d7SNathan Whitehorn } 229*c1cb22d7SNathan Whitehorn } 230*c1cb22d7SNathan Whitehorn 231*c1cb22d7SNathan Whitehorn *msz = lmsz; 232*c1cb22d7SNathan Whitehorn *asz = lasz; 233*c1cb22d7SNathan Whitehorn 234*c1cb22d7SNathan Whitehorn return (1); 235*c1cb22d7SNathan Whitehorn } 236*c1cb22d7SNathan Whitehorn 237*c1cb22d7SNathan Whitehorn void 238*c1cb22d7SNathan Whitehorn chrp_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 239*c1cb22d7SNathan Whitehorn struct mem_region *avail, int *availsz) 240*c1cb22d7SNathan Whitehorn { 241*c1cb22d7SNathan Whitehorn vm_offset_t maxphysaddr; 242*c1cb22d7SNathan Whitehorn int i; 243*c1cb22d7SNathan Whitehorn 2447a8d25c0SNathan Whitehorn ofw_mem_regions(phys, physsz, avail, availsz); 245*c1cb22d7SNathan Whitehorn parse_drconf_memory(physsz, availsz, phys, avail); 246*c1cb22d7SNathan Whitehorn 247*c1cb22d7SNathan Whitehorn /* 248*c1cb22d7SNathan Whitehorn * On some firmwares (SLOF), some memory may be marked available that 249*c1cb22d7SNathan Whitehorn * doesn't actually exist. This manifests as an extension of the last 250*c1cb22d7SNathan Whitehorn * available segment past the end of physical memory, so truncate that 251*c1cb22d7SNathan Whitehorn * one. 252*c1cb22d7SNathan Whitehorn */ 253*c1cb22d7SNathan Whitehorn maxphysaddr = 0; 254*c1cb22d7SNathan Whitehorn for (i = 0; i < *physsz; i++) 255*c1cb22d7SNathan Whitehorn if (phys[i].mr_start + phys[i].mr_size > maxphysaddr) 256*c1cb22d7SNathan Whitehorn maxphysaddr = phys[i].mr_start + phys[i].mr_size; 257*c1cb22d7SNathan Whitehorn 258*c1cb22d7SNathan Whitehorn for (i = 0; i < *availsz; i++) 259*c1cb22d7SNathan Whitehorn if (avail[i].mr_start + avail[i].mr_size > maxphysaddr) 260*c1cb22d7SNathan Whitehorn avail[i].mr_size = maxphysaddr - avail[i].mr_start; 2617a8d25c0SNathan Whitehorn } 2627a8d25c0SNathan Whitehorn 2637a8d25c0SNathan Whitehorn static vm_offset_t 2647a8d25c0SNathan Whitehorn chrp_real_maxaddr(platform_t plat) 2657a8d25c0SNathan Whitehorn { 2667a8d25c0SNathan Whitehorn return (realmaxaddr); 2677a8d25c0SNathan Whitehorn } 2687a8d25c0SNathan Whitehorn 2697a8d25c0SNathan Whitehorn static u_long 2707a8d25c0SNathan Whitehorn chrp_timebase_freq(platform_t plat, struct cpuref *cpuref) 2717a8d25c0SNathan Whitehorn { 2727a8d25c0SNathan Whitehorn phandle_t phandle; 2737a8d25c0SNathan Whitehorn int32_t ticks = -1; 2747a8d25c0SNathan Whitehorn 2757a8d25c0SNathan Whitehorn phandle = cpuref->cr_hwref; 2767a8d25c0SNathan Whitehorn 2777a8d25c0SNathan Whitehorn OF_getprop(phandle, "timebase-frequency", &ticks, sizeof(ticks)); 2787a8d25c0SNathan Whitehorn 2797a8d25c0SNathan Whitehorn if (ticks <= 0) 2807a8d25c0SNathan Whitehorn panic("Unable to determine timebase frequency!"); 2817a8d25c0SNathan Whitehorn 2827a8d25c0SNathan Whitehorn return (ticks); 2837a8d25c0SNathan Whitehorn } 2847a8d25c0SNathan Whitehorn 2857a8d25c0SNathan Whitehorn static int 2867a8d25c0SNathan Whitehorn chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 2877a8d25c0SNathan Whitehorn { 2887a8d25c0SNathan Whitehorn char buf[8]; 2897a8d25c0SNathan Whitehorn phandle_t cpu, dev, root; 2907a8d25c0SNathan Whitehorn int res, cpuid; 2917a8d25c0SNathan Whitehorn 2927a8d25c0SNathan Whitehorn root = OF_peer(0); 2937a8d25c0SNathan Whitehorn 2947a8d25c0SNathan Whitehorn dev = OF_child(root); 2957a8d25c0SNathan Whitehorn while (dev != 0) { 2967a8d25c0SNathan Whitehorn res = OF_getprop(dev, "name", buf, sizeof(buf)); 2977a8d25c0SNathan Whitehorn if (res > 0 && strcmp(buf, "cpus") == 0) 2987a8d25c0SNathan Whitehorn break; 2997a8d25c0SNathan Whitehorn dev = OF_peer(dev); 3007a8d25c0SNathan Whitehorn } 3017a8d25c0SNathan Whitehorn if (dev == 0) { 3027a8d25c0SNathan Whitehorn /* 3037a8d25c0SNathan Whitehorn * psim doesn't have a name property on the /cpus node, 3047a8d25c0SNathan Whitehorn * but it can be found directly 3057a8d25c0SNathan Whitehorn */ 3067a8d25c0SNathan Whitehorn dev = OF_finddevice("/cpus"); 3077a8d25c0SNathan Whitehorn if (dev == 0) 3087a8d25c0SNathan Whitehorn return (ENOENT); 3097a8d25c0SNathan Whitehorn } 3107a8d25c0SNathan Whitehorn 3117a8d25c0SNathan Whitehorn cpu = OF_child(dev); 3127a8d25c0SNathan Whitehorn 3137a8d25c0SNathan Whitehorn while (cpu != 0) { 3147a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 3157a8d25c0SNathan Whitehorn if (res > 0 && strcmp(buf, "cpu") == 0) 3167a8d25c0SNathan Whitehorn break; 3177a8d25c0SNathan Whitehorn cpu = OF_peer(cpu); 3187a8d25c0SNathan Whitehorn } 3197a8d25c0SNathan Whitehorn if (cpu == 0) 3207a8d25c0SNathan Whitehorn return (ENOENT); 3217a8d25c0SNathan Whitehorn 3227a8d25c0SNathan Whitehorn cpuref->cr_hwref = cpu; 3237a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid, 3247a8d25c0SNathan Whitehorn sizeof(cpuid)); 3257a8d25c0SNathan Whitehorn if (res <= 0) 3267a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 3277a8d25c0SNathan Whitehorn if (res <= 0) 3287a8d25c0SNathan Whitehorn cpuid = 0; 3297a8d25c0SNathan Whitehorn cpuref->cr_cpuid = cpuid; 3307a8d25c0SNathan Whitehorn 3317a8d25c0SNathan Whitehorn return (0); 3327a8d25c0SNathan Whitehorn } 3337a8d25c0SNathan Whitehorn 3347a8d25c0SNathan Whitehorn static int 3357a8d25c0SNathan Whitehorn chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 3367a8d25c0SNathan Whitehorn { 3377a8d25c0SNathan Whitehorn char buf[8]; 3387a8d25c0SNathan Whitehorn phandle_t cpu; 3397a8d25c0SNathan Whitehorn int i, res, cpuid; 3407a8d25c0SNathan Whitehorn 3417a8d25c0SNathan Whitehorn /* Check for whether it should be the next thread */ 3427a8d25c0SNathan Whitehorn res = OF_getproplen(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s"); 3437a8d25c0SNathan Whitehorn if (res > 0) { 3447a8d25c0SNathan Whitehorn cell_t interrupt_servers[res/sizeof(cell_t)]; 3457a8d25c0SNathan Whitehorn OF_getprop(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s", 3467a8d25c0SNathan Whitehorn interrupt_servers, res); 3477a8d25c0SNathan Whitehorn for (i = 0; i < res/sizeof(cell_t) - 1; i++) { 3487a8d25c0SNathan Whitehorn if (interrupt_servers[i] == cpuref->cr_cpuid) { 3497a8d25c0SNathan Whitehorn cpuref->cr_cpuid = interrupt_servers[i+1]; 3507a8d25c0SNathan Whitehorn return (0); 3517a8d25c0SNathan Whitehorn } 3527a8d25c0SNathan Whitehorn } 3537a8d25c0SNathan Whitehorn } 3547a8d25c0SNathan Whitehorn 3557a8d25c0SNathan Whitehorn /* Next CPU core/package */ 3567a8d25c0SNathan Whitehorn cpu = OF_peer(cpuref->cr_hwref); 3577a8d25c0SNathan Whitehorn while (cpu != 0) { 3587a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 3597a8d25c0SNathan Whitehorn if (res > 0 && strcmp(buf, "cpu") == 0) 3607a8d25c0SNathan Whitehorn break; 3617a8d25c0SNathan Whitehorn cpu = OF_peer(cpu); 3627a8d25c0SNathan Whitehorn } 3637a8d25c0SNathan Whitehorn if (cpu == 0) 3647a8d25c0SNathan Whitehorn return (ENOENT); 3657a8d25c0SNathan Whitehorn 3667a8d25c0SNathan Whitehorn cpuref->cr_hwref = cpu; 3677a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid, 3687a8d25c0SNathan Whitehorn sizeof(cpuid)); 3697a8d25c0SNathan Whitehorn if (res <= 0) 3707a8d25c0SNathan Whitehorn res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 3717a8d25c0SNathan Whitehorn if (res <= 0) 3727a8d25c0SNathan Whitehorn cpuid = 0; 3737a8d25c0SNathan Whitehorn cpuref->cr_cpuid = cpuid; 3747a8d25c0SNathan Whitehorn 3757a8d25c0SNathan Whitehorn return (0); 3767a8d25c0SNathan Whitehorn } 3777a8d25c0SNathan Whitehorn 3787a8d25c0SNathan Whitehorn static int 3797a8d25c0SNathan Whitehorn chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 3807a8d25c0SNathan Whitehorn { 3817a8d25c0SNathan Whitehorn ihandle_t inst; 3827a8d25c0SNathan Whitehorn phandle_t bsp, chosen; 3837a8d25c0SNathan Whitehorn int res, cpuid; 3847a8d25c0SNathan Whitehorn 3857a8d25c0SNathan Whitehorn chosen = OF_finddevice("/chosen"); 3867a8d25c0SNathan Whitehorn if (chosen == 0) 3877a8d25c0SNathan Whitehorn return (ENXIO); 3887a8d25c0SNathan Whitehorn 3897a8d25c0SNathan Whitehorn res = OF_getprop(chosen, "cpu", &inst, sizeof(inst)); 3907a8d25c0SNathan Whitehorn if (res < 0) 3917a8d25c0SNathan Whitehorn return (ENXIO); 3927a8d25c0SNathan Whitehorn 3937a8d25c0SNathan Whitehorn bsp = OF_instance_to_package(inst); 3947a8d25c0SNathan Whitehorn 3957a8d25c0SNathan Whitehorn /* Pick the primary thread. Can it be any other? */ 3967a8d25c0SNathan Whitehorn cpuref->cr_hwref = bsp; 3977a8d25c0SNathan Whitehorn res = OF_getprop(bsp, "ibm,ppc-interrupt-server#s", &cpuid, 3987a8d25c0SNathan Whitehorn sizeof(cpuid)); 3997a8d25c0SNathan Whitehorn if (res <= 0) 4007a8d25c0SNathan Whitehorn res = OF_getprop(bsp, "reg", &cpuid, sizeof(cpuid)); 4017a8d25c0SNathan Whitehorn if (res <= 0) 4027a8d25c0SNathan Whitehorn cpuid = 0; 4037a8d25c0SNathan Whitehorn cpuref->cr_cpuid = cpuid; 4047a8d25c0SNathan Whitehorn 4057a8d25c0SNathan Whitehorn return (0); 4067a8d25c0SNathan Whitehorn } 4077a8d25c0SNathan Whitehorn 4087a8d25c0SNathan Whitehorn #ifdef SMP 4097a8d25c0SNathan Whitehorn static int 4107a8d25c0SNathan Whitehorn chrp_smp_start_cpu(platform_t plat, struct pcpu *pc) 4117a8d25c0SNathan Whitehorn { 4127a8d25c0SNathan Whitehorn cell_t start_cpu; 4137a8d25c0SNathan Whitehorn int result, err, timeout; 4147a8d25c0SNathan Whitehorn 4157a8d25c0SNathan Whitehorn if (!rtas_exists()) { 4167a8d25c0SNathan Whitehorn printf("RTAS uninitialized: unable to start AP %d\n", 4177a8d25c0SNathan Whitehorn pc->pc_cpuid); 4187a8d25c0SNathan Whitehorn return (ENXIO); 4197a8d25c0SNathan Whitehorn } 4207a8d25c0SNathan Whitehorn 4217a8d25c0SNathan Whitehorn start_cpu = rtas_token_lookup("start-cpu"); 4227a8d25c0SNathan Whitehorn if (start_cpu == -1) { 4237a8d25c0SNathan Whitehorn printf("RTAS unknown method: unable to start AP %d\n", 4247a8d25c0SNathan Whitehorn pc->pc_cpuid); 4257a8d25c0SNathan Whitehorn return (ENXIO); 4267a8d25c0SNathan Whitehorn } 4277a8d25c0SNathan Whitehorn 4287a8d25c0SNathan Whitehorn ap_pcpu = pc; 4297a8d25c0SNathan Whitehorn powerpc_sync(); 4307a8d25c0SNathan Whitehorn 4317a8d25c0SNathan Whitehorn result = rtas_call_method(start_cpu, 3, 1, pc->pc_cpuid, EXC_RST, pc, 4327a8d25c0SNathan Whitehorn &err); 4337a8d25c0SNathan Whitehorn if (result < 0 || err != 0) { 4347a8d25c0SNathan Whitehorn printf("RTAS error (%d/%d): unable to start AP %d\n", 4357a8d25c0SNathan Whitehorn result, err, pc->pc_cpuid); 4367a8d25c0SNathan Whitehorn return (ENXIO); 4377a8d25c0SNathan Whitehorn } 4387a8d25c0SNathan Whitehorn 4397a8d25c0SNathan Whitehorn timeout = 10000; 4407a8d25c0SNathan Whitehorn while (!pc->pc_awake && timeout--) 4417a8d25c0SNathan Whitehorn DELAY(100); 4427a8d25c0SNathan Whitehorn 4437a8d25c0SNathan Whitehorn return ((pc->pc_awake) ? 0 : EBUSY); 4447a8d25c0SNathan Whitehorn } 4457a8d25c0SNathan Whitehorn 4467a8d25c0SNathan Whitehorn static struct cpu_group * 4477a8d25c0SNathan Whitehorn chrp_smp_topo(platform_t plat) 4487a8d25c0SNathan Whitehorn { 4497a8d25c0SNathan Whitehorn struct pcpu *pc, *last_pc; 4507a8d25c0SNathan Whitehorn int i, ncores, ncpus; 4517a8d25c0SNathan Whitehorn 4527a8d25c0SNathan Whitehorn ncores = ncpus = 0; 4537a8d25c0SNathan Whitehorn last_pc = NULL; 4547a8d25c0SNathan Whitehorn for (i = 0; i <= mp_maxid; i++) { 4557a8d25c0SNathan Whitehorn pc = pcpu_find(i); 4567a8d25c0SNathan Whitehorn if (pc == NULL) 4577a8d25c0SNathan Whitehorn continue; 4587a8d25c0SNathan Whitehorn if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref) 4597a8d25c0SNathan Whitehorn ncores++; 4607a8d25c0SNathan Whitehorn last_pc = pc; 4617a8d25c0SNathan Whitehorn ncpus++; 4627a8d25c0SNathan Whitehorn } 4637a8d25c0SNathan Whitehorn 4647a8d25c0SNathan Whitehorn if (ncpus % ncores != 0) { 4657a8d25c0SNathan Whitehorn printf("WARNING: Irregular SMP topology. Performance may be " 4667a8d25c0SNathan Whitehorn "suboptimal (%d CPUS, %d cores)\n", ncpus, ncores); 4677a8d25c0SNathan Whitehorn return (smp_topo_none()); 4687a8d25c0SNathan Whitehorn } 4697a8d25c0SNathan Whitehorn 4707a8d25c0SNathan Whitehorn /* Don't do anything fancier for non-threaded SMP */ 4717a8d25c0SNathan Whitehorn if (ncpus == ncores) 4727a8d25c0SNathan Whitehorn return (smp_topo_none()); 4737a8d25c0SNathan Whitehorn 4747a8d25c0SNathan Whitehorn return (smp_topo_1level(CG_SHARE_L1, ncpus / ncores, CG_FLAG_SMT)); 4757a8d25c0SNathan Whitehorn } 4767a8d25c0SNathan Whitehorn #endif 4777a8d25c0SNathan Whitehorn 4787a8d25c0SNathan Whitehorn static void 4797a8d25c0SNathan Whitehorn chrp_reset(platform_t platform) 4807a8d25c0SNathan Whitehorn { 4817a8d25c0SNathan Whitehorn OF_reboot(); 4827a8d25c0SNathan Whitehorn } 4837a8d25c0SNathan Whitehorn 4847a8d25c0SNathan Whitehorn #ifdef __powerpc64__ 4857a8d25c0SNathan Whitehorn static void 4867a8d25c0SNathan Whitehorn phyp_cpu_idle(sbintime_t sbt) 4877a8d25c0SNathan Whitehorn { 4887a8d25c0SNathan Whitehorn phyp_hcall(H_CEDE); 4897a8d25c0SNathan Whitehorn } 4907a8d25c0SNathan Whitehorn 4917a8d25c0SNathan Whitehorn static void 4927a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform) 4937a8d25c0SNathan Whitehorn { 4947a8d25c0SNathan Whitehorn if (!(mfmsr() & PSL_HV)) { 4957a8d25c0SNathan Whitehorn /* Set interrupt priority */ 4967a8d25c0SNathan Whitehorn phyp_hcall(H_CPPR, 0xff); 4977a8d25c0SNathan Whitehorn 4987a8d25c0SNathan Whitehorn /* Register VPA */ 4997a8d25c0SNathan Whitehorn phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(cpuid), splpar_vpa); 5007a8d25c0SNathan Whitehorn } 5017a8d25c0SNathan Whitehorn } 5027a8d25c0SNathan Whitehorn #else 5037a8d25c0SNathan Whitehorn static void 5047a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform) 5057a8d25c0SNathan Whitehorn { 5067a8d25c0SNathan Whitehorn } 5077a8d25c0SNathan Whitehorn #endif 5087a8d25c0SNathan Whitehorn 509