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); 78f0393bbfSWojciech Macek static int chrp_cpuref_init(void); 797a8d25c0SNathan Whitehorn #ifdef SMP 807a8d25c0SNathan Whitehorn static int chrp_smp_start_cpu(platform_t, struct pcpu *cpu); 817a8d25c0SNathan Whitehorn static struct cpu_group *chrp_smp_topo(platform_t plat); 827a8d25c0SNathan Whitehorn #endif 837a8d25c0SNathan Whitehorn static void chrp_reset(platform_t); 847a8d25c0SNathan Whitehorn #ifdef __powerpc64__ 857a8d25c0SNathan Whitehorn #include "phyp-hvcall.h" 867a8d25c0SNathan Whitehorn static void phyp_cpu_idle(sbintime_t sbt); 877a8d25c0SNathan Whitehorn #endif 887a8d25c0SNathan Whitehorn 89f0393bbfSWojciech Macek static struct cpuref platform_cpuref[MAXCPU]; 90f0393bbfSWojciech Macek static int platform_cpuref_cnt; 91f0393bbfSWojciech Macek static int platform_cpuref_valid; 92f0393bbfSWojciech Macek 937a8d25c0SNathan Whitehorn static platform_method_t chrp_methods[] = { 947a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_probe, chrp_probe), 957a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_attach, chrp_attach), 967a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_mem_regions, chrp_mem_regions), 977a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_real_maxaddr, chrp_real_maxaddr), 987a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_timebase_freq, chrp_timebase_freq), 997a8d25c0SNathan Whitehorn 1007a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_ap_init, chrp_smp_ap_init), 1017a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_first_cpu, chrp_smp_first_cpu), 1027a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_next_cpu, chrp_smp_next_cpu), 1037a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_get_bsp, chrp_smp_get_bsp), 1047a8d25c0SNathan Whitehorn #ifdef SMP 1057a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_start_cpu, chrp_smp_start_cpu), 1067a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_smp_topo, chrp_smp_topo), 1077a8d25c0SNathan Whitehorn #endif 1087a8d25c0SNathan Whitehorn 1097a8d25c0SNathan Whitehorn PLATFORMMETHOD(platform_reset, chrp_reset), 1107a8d25c0SNathan Whitehorn 1117a8d25c0SNathan Whitehorn { 0, 0 } 1127a8d25c0SNathan Whitehorn }; 1137a8d25c0SNathan Whitehorn 1147a8d25c0SNathan Whitehorn static platform_def_t chrp_platform = { 1157a8d25c0SNathan Whitehorn "chrp", 1167a8d25c0SNathan Whitehorn chrp_methods, 1177a8d25c0SNathan Whitehorn 0 1187a8d25c0SNathan Whitehorn }; 1197a8d25c0SNathan Whitehorn 1207a8d25c0SNathan Whitehorn PLATFORM_DEF(chrp_platform); 1217a8d25c0SNathan Whitehorn 1227a8d25c0SNathan Whitehorn static int 1237a8d25c0SNathan Whitehorn chrp_probe(platform_t plat) 1247a8d25c0SNathan Whitehorn { 1257a8d25c0SNathan Whitehorn if (OF_finddevice("/memory") != -1 || OF_finddevice("/memory@0") != -1) 1267a8d25c0SNathan Whitehorn return (BUS_PROBE_GENERIC); 1277a8d25c0SNathan Whitehorn 1287a8d25c0SNathan Whitehorn return (ENXIO); 1297a8d25c0SNathan Whitehorn } 1307a8d25c0SNathan Whitehorn 1317a8d25c0SNathan Whitehorn static int 1327a8d25c0SNathan Whitehorn chrp_attach(platform_t plat) 1337a8d25c0SNathan Whitehorn { 13466fe9464SBjoern A. Zeeb #ifdef __powerpc64__ 135f1e48417SNathan Whitehorn int i; 136f1e48417SNathan Whitehorn 1377a8d25c0SNathan Whitehorn /* XXX: check for /rtas/ibm,hypertas-functions? */ 1387a8d25c0SNathan Whitehorn if (!(mfmsr() & PSL_HV)) { 1397a8d25c0SNathan Whitehorn struct mem_region *phys, *avail; 1407a8d25c0SNathan Whitehorn int nphys, navail; 1417a8d25c0SNathan Whitehorn mem_regions(&phys, &nphys, &avail, &navail); 1427a8d25c0SNathan Whitehorn realmaxaddr = phys[0].mr_size; 1437a8d25c0SNathan Whitehorn 1447a8d25c0SNathan Whitehorn pmap_mmu_install("mmu_phyp", BUS_PROBE_SPECIFIC); 1457a8d25c0SNathan Whitehorn cpu_idle_hook = phyp_cpu_idle; 1467a8d25c0SNathan Whitehorn 1477a8d25c0SNathan Whitehorn /* Set up important VPA fields */ 148f1e48417SNathan Whitehorn for (i = 0; i < MAXCPU; i++) { 149f1e48417SNathan Whitehorn bzero(splpar_vpa[i], sizeof(splpar_vpa)); 150f1e48417SNathan Whitehorn /* First two: VPA size */ 151f1e48417SNathan Whitehorn splpar_vpa[i][4] = 152f1e48417SNathan Whitehorn (uint8_t)((sizeof(splpar_vpa[i]) >> 8) & 0xff); 153f1e48417SNathan Whitehorn splpar_vpa[i][5] = 154f1e48417SNathan Whitehorn (uint8_t)(sizeof(splpar_vpa[i]) & 0xff); 155f1e48417SNathan Whitehorn splpar_vpa[i][0xba] = 1; /* Maintain FPRs */ 156f1e48417SNathan Whitehorn splpar_vpa[i][0xbb] = 1; /* Maintain PMCs */ 157f1e48417SNathan Whitehorn splpar_vpa[i][0xfc] = 0xff; /* Maintain full SLB */ 158f1e48417SNathan Whitehorn splpar_vpa[i][0xfd] = 0xff; 159f1e48417SNathan Whitehorn splpar_vpa[i][0xff] = 1; /* Maintain Altivec */ 160f1e48417SNathan Whitehorn } 1617a8d25c0SNathan Whitehorn mb(); 1627a8d25c0SNathan Whitehorn 1637a8d25c0SNathan Whitehorn /* Set up hypervisor CPU stuff */ 1647a8d25c0SNathan Whitehorn chrp_smp_ap_init(plat); 1657a8d25c0SNathan Whitehorn } 1667a8d25c0SNathan Whitehorn #endif 167f0393bbfSWojciech Macek chrp_cpuref_init(); 1687a8d25c0SNathan Whitehorn 1699f706727SNathan Whitehorn /* Some systems (e.g. QEMU) need Open Firmware to stand down */ 1709f706727SNathan Whitehorn ofw_quiesce(); 1719f706727SNathan Whitehorn 1727a8d25c0SNathan Whitehorn return (0); 1737a8d25c0SNathan Whitehorn } 1747a8d25c0SNathan Whitehorn 175c1cb22d7SNathan Whitehorn static int 176f5dfbe2fSAndreas Tobler parse_drconf_memory(struct mem_region *ofmem, int *msz, 177f5dfbe2fSAndreas Tobler struct mem_region *ofavail, int *asz) 1787a8d25c0SNathan Whitehorn { 179c1cb22d7SNathan Whitehorn phandle_t phandle; 180c1cb22d7SNathan Whitehorn vm_offset_t base; 181c1cb22d7SNathan Whitehorn int i, idx, len, lasz, lmsz, res; 182f5dfbe2fSAndreas Tobler uint32_t flags, lmb_size[2]; 183509142e1SNathan Whitehorn uint32_t *dmem; 184c1cb22d7SNathan Whitehorn 185c1cb22d7SNathan Whitehorn lmsz = *msz; 186c1cb22d7SNathan Whitehorn lasz = *asz; 187c1cb22d7SNathan Whitehorn 188c1cb22d7SNathan Whitehorn phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory"); 189c1cb22d7SNathan Whitehorn if (phandle == -1) 190c1cb22d7SNathan Whitehorn /* No drconf node, return. */ 191c1cb22d7SNathan Whitehorn return (0); 192c1cb22d7SNathan Whitehorn 193509142e1SNathan Whitehorn res = OF_getencprop(phandle, "ibm,lmb-size", lmb_size, 194509142e1SNathan Whitehorn sizeof(lmb_size)); 195c1cb22d7SNathan Whitehorn if (res == -1) 196c1cb22d7SNathan Whitehorn return (0); 197c1cb22d7SNathan Whitehorn printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20); 198c1cb22d7SNathan Whitehorn 199c1cb22d7SNathan Whitehorn /* Parse the /ibm,dynamic-memory. 200c1cb22d7SNathan Whitehorn The first position gives the # of entries. The next two words 201c1cb22d7SNathan Whitehorn reflect the address of the memory block. The next four words are 202c1cb22d7SNathan Whitehorn the DRC index, reserved, list index and flags. 203c1cb22d7SNathan Whitehorn (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory) 204c1cb22d7SNathan Whitehorn 205c1cb22d7SNathan Whitehorn #el Addr DRC-idx res list-idx flags 206c1cb22d7SNathan Whitehorn ------------------------------------------------- 207c1cb22d7SNathan Whitehorn | 4 | 8 | 4 | 4 | 4 | 4 |.... 208c1cb22d7SNathan Whitehorn ------------------------------------------------- 209c1cb22d7SNathan Whitehorn */ 210c1cb22d7SNathan Whitehorn 211c1cb22d7SNathan Whitehorn len = OF_getproplen(phandle, "ibm,dynamic-memory"); 212c1cb22d7SNathan Whitehorn if (len > 0) { 213c1cb22d7SNathan Whitehorn 214c1cb22d7SNathan Whitehorn /* We have to use a variable length array on the stack 215c1cb22d7SNathan Whitehorn since we have very limited stack space. 216c1cb22d7SNathan Whitehorn */ 217c1cb22d7SNathan Whitehorn cell_t arr[len/sizeof(cell_t)]; 218c1cb22d7SNathan Whitehorn 219509142e1SNathan Whitehorn res = OF_getencprop(phandle, "ibm,dynamic-memory", arr, 220c1cb22d7SNathan Whitehorn sizeof(arr)); 221c1cb22d7SNathan Whitehorn if (res == -1) 222c1cb22d7SNathan Whitehorn return (0); 223c1cb22d7SNathan Whitehorn 224c1cb22d7SNathan Whitehorn /* Number of elements */ 225c1cb22d7SNathan Whitehorn idx = arr[0]; 226c1cb22d7SNathan Whitehorn 227f5dfbe2fSAndreas Tobler /* First address, in arr[1], arr[2]*/ 228509142e1SNathan Whitehorn dmem = &arr[1]; 229c1cb22d7SNathan Whitehorn 230c1cb22d7SNathan Whitehorn for (i = 0; i < idx; i++) { 231509142e1SNathan Whitehorn base = ((uint64_t)dmem[0] << 32) + dmem[1]; 232509142e1SNathan Whitehorn dmem += 4; 233509142e1SNathan Whitehorn flags = dmem[1]; 234c1cb22d7SNathan Whitehorn /* Use region only if available and not reserved. */ 235c1cb22d7SNathan Whitehorn if ((flags & 0x8) && !(flags & 0x80)) { 236c1cb22d7SNathan Whitehorn ofmem[lmsz].mr_start = base; 237c1cb22d7SNathan Whitehorn ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1]; 238c1cb22d7SNathan Whitehorn ofavail[lasz].mr_start = base; 239c1cb22d7SNathan Whitehorn ofavail[lasz].mr_size = (vm_size_t)lmb_size[1]; 240c1cb22d7SNathan Whitehorn lmsz++; 241c1cb22d7SNathan Whitehorn lasz++; 242c1cb22d7SNathan Whitehorn } 243509142e1SNathan Whitehorn dmem += 2; 244c1cb22d7SNathan Whitehorn } 245c1cb22d7SNathan Whitehorn } 246c1cb22d7SNathan Whitehorn 247c1cb22d7SNathan Whitehorn *msz = lmsz; 248c1cb22d7SNathan Whitehorn *asz = lasz; 249c1cb22d7SNathan Whitehorn 250c1cb22d7SNathan Whitehorn return (1); 251c1cb22d7SNathan Whitehorn } 252c1cb22d7SNathan Whitehorn 253c1cb22d7SNathan Whitehorn void 254c1cb22d7SNathan Whitehorn chrp_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 255c1cb22d7SNathan Whitehorn struct mem_region *avail, int *availsz) 256c1cb22d7SNathan Whitehorn { 257c1cb22d7SNathan Whitehorn vm_offset_t maxphysaddr; 258c1cb22d7SNathan Whitehorn int i; 259c1cb22d7SNathan Whitehorn 2607a8d25c0SNathan Whitehorn ofw_mem_regions(phys, physsz, avail, availsz); 261f5dfbe2fSAndreas Tobler parse_drconf_memory(phys, physsz, avail, availsz); 262c1cb22d7SNathan Whitehorn 263c1cb22d7SNathan Whitehorn /* 264c1cb22d7SNathan Whitehorn * On some firmwares (SLOF), some memory may be marked available that 265c1cb22d7SNathan Whitehorn * doesn't actually exist. This manifests as an extension of the last 266c1cb22d7SNathan Whitehorn * available segment past the end of physical memory, so truncate that 267c1cb22d7SNathan Whitehorn * one. 268c1cb22d7SNathan Whitehorn */ 269c1cb22d7SNathan Whitehorn maxphysaddr = 0; 270c1cb22d7SNathan Whitehorn for (i = 0; i < *physsz; i++) 271c1cb22d7SNathan Whitehorn if (phys[i].mr_start + phys[i].mr_size > maxphysaddr) 272c1cb22d7SNathan Whitehorn maxphysaddr = phys[i].mr_start + phys[i].mr_size; 273c1cb22d7SNathan Whitehorn 274c1cb22d7SNathan Whitehorn for (i = 0; i < *availsz; i++) 275c1cb22d7SNathan Whitehorn if (avail[i].mr_start + avail[i].mr_size > maxphysaddr) 276c1cb22d7SNathan Whitehorn avail[i].mr_size = maxphysaddr - avail[i].mr_start; 2777a8d25c0SNathan Whitehorn } 2787a8d25c0SNathan Whitehorn 2797a8d25c0SNathan Whitehorn static vm_offset_t 2807a8d25c0SNathan Whitehorn chrp_real_maxaddr(platform_t plat) 2817a8d25c0SNathan Whitehorn { 2827a8d25c0SNathan Whitehorn return (realmaxaddr); 2837a8d25c0SNathan Whitehorn } 2847a8d25c0SNathan Whitehorn 2857a8d25c0SNathan Whitehorn static u_long 2867a8d25c0SNathan Whitehorn chrp_timebase_freq(platform_t plat, struct cpuref *cpuref) 2877a8d25c0SNathan Whitehorn { 288a00ce4e8SJustin Hibbits phandle_t cpus, cpunode; 2897a8d25c0SNathan Whitehorn int32_t ticks = -1; 290a00ce4e8SJustin Hibbits int res; 291a00ce4e8SJustin Hibbits char buf[8]; 2927a8d25c0SNathan Whitehorn 293a00ce4e8SJustin Hibbits cpus = OF_finddevice("/cpus"); 294*108117ccSOleksandr Tymoshenko if (cpus == -1) 295a00ce4e8SJustin Hibbits panic("CPU tree not found on Open Firmware\n"); 2967a8d25c0SNathan Whitehorn 297a00ce4e8SJustin Hibbits for (cpunode = OF_child(cpus); cpunode != 0; cpunode = OF_peer(cpunode)) { 298a00ce4e8SJustin Hibbits res = OF_getprop(cpunode, "device_type", buf, sizeof(buf)); 299a00ce4e8SJustin Hibbits if (res > 0 && strcmp(buf, "cpu") == 0) 300a00ce4e8SJustin Hibbits break; 301a00ce4e8SJustin Hibbits } 302a00ce4e8SJustin Hibbits if (cpunode <= 0) 303a00ce4e8SJustin Hibbits panic("CPU node not found on Open Firmware\n"); 304a00ce4e8SJustin Hibbits 305a00ce4e8SJustin Hibbits OF_getencprop(cpunode, "timebase-frequency", &ticks, sizeof(ticks)); 3067a8d25c0SNathan Whitehorn 3077a8d25c0SNathan Whitehorn if (ticks <= 0) 3087a8d25c0SNathan Whitehorn panic("Unable to determine timebase frequency!"); 3097a8d25c0SNathan Whitehorn 3107a8d25c0SNathan Whitehorn return (ticks); 3117a8d25c0SNathan Whitehorn } 3127a8d25c0SNathan Whitehorn 3137a8d25c0SNathan Whitehorn static int 31409f07b00SNathan Whitehorn chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 3157a8d25c0SNathan Whitehorn { 3167a8d25c0SNathan Whitehorn 317f0393bbfSWojciech Macek if (platform_cpuref_valid == 0) 318f0393bbfSWojciech Macek return (EINVAL); 3197a8d25c0SNathan Whitehorn 320f0393bbfSWojciech Macek cpuref->cr_cpuid = 0; 321f0393bbfSWojciech Macek cpuref->cr_hwref = platform_cpuref[0].cr_hwref; 3227a8d25c0SNathan Whitehorn 3237a8d25c0SNathan Whitehorn return (0); 3247a8d25c0SNathan Whitehorn } 3257a8d25c0SNathan Whitehorn 3267a8d25c0SNathan Whitehorn static int 3277a8d25c0SNathan Whitehorn chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 3287a8d25c0SNathan Whitehorn { 329f0393bbfSWojciech Macek int id; 3307a8d25c0SNathan Whitehorn 331f0393bbfSWojciech Macek if (platform_cpuref_valid == 0) 332f0393bbfSWojciech Macek return (EINVAL); 3337a8d25c0SNathan Whitehorn 334f0393bbfSWojciech Macek id = cpuref->cr_cpuid + 1; 335f0393bbfSWojciech Macek if (id >= platform_cpuref_cnt) 3367a8d25c0SNathan Whitehorn return (ENOENT); 33709f07b00SNathan Whitehorn 338f0393bbfSWojciech Macek cpuref->cr_cpuid = platform_cpuref[id].cr_cpuid; 339f0393bbfSWojciech Macek cpuref->cr_hwref = platform_cpuref[id].cr_hwref; 34009f07b00SNathan Whitehorn 34109f07b00SNathan Whitehorn return (0); 3427a8d25c0SNathan Whitehorn } 3437a8d25c0SNathan Whitehorn 3447a8d25c0SNathan Whitehorn static int 3457a8d25c0SNathan Whitehorn chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 3467a8d25c0SNathan Whitehorn { 3477a8d25c0SNathan Whitehorn 348f0393bbfSWojciech Macek cpuref->cr_cpuid = platform_cpuref[0].cr_cpuid; 349f0393bbfSWojciech Macek cpuref->cr_hwref = platform_cpuref[0].cr_hwref; 350f0393bbfSWojciech Macek return (0); 351f0393bbfSWojciech Macek } 3527a8d25c0SNathan Whitehorn 353f0393bbfSWojciech Macek static int 354f0393bbfSWojciech Macek chrp_cpuref_init(void) 355f0393bbfSWojciech Macek { 356f0393bbfSWojciech Macek phandle_t cpu, dev; 357f0393bbfSWojciech Macek char buf[32]; 358f0393bbfSWojciech Macek int a, res; 359f0393bbfSWojciech Macek cell_t interrupt_servers[32]; 360f0393bbfSWojciech Macek uint64_t bsp; 3617a8d25c0SNathan Whitehorn 362f0393bbfSWojciech Macek if (platform_cpuref_valid) 363f0393bbfSWojciech Macek return (0); 3647a8d25c0SNathan Whitehorn 365f0393bbfSWojciech Macek dev = OF_peer(0); 366f0393bbfSWojciech Macek dev = OF_child(dev); 367f0393bbfSWojciech Macek while (dev != 0) { 368f0393bbfSWojciech Macek res = OF_getprop(dev, "name", buf, sizeof(buf)); 369f0393bbfSWojciech Macek if (res > 0 && strcmp(buf, "cpus") == 0) 370f0393bbfSWojciech Macek break; 371f0393bbfSWojciech Macek dev = OF_peer(dev); 372f0393bbfSWojciech Macek } 373f0393bbfSWojciech Macek 374f0393bbfSWojciech Macek bsp = 0; 375f0393bbfSWojciech Macek for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) { 376f0393bbfSWojciech Macek res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 377f0393bbfSWojciech Macek if (res > 0 && strcmp(buf, "cpu") == 0) { 378f0393bbfSWojciech Macek res = OF_getproplen(cpu, "ibm,ppc-interrupt-server#s"); 379f0393bbfSWojciech Macek if (res > 0) { 380f0393bbfSWojciech Macek 381f0393bbfSWojciech Macek 382f0393bbfSWojciech Macek OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", 383f0393bbfSWojciech Macek interrupt_servers, res); 384f0393bbfSWojciech Macek 385f0393bbfSWojciech Macek for (a = 0; a < res/sizeof(cell_t); a++) { 386f0393bbfSWojciech Macek platform_cpuref[platform_cpuref_cnt].cr_hwref = interrupt_servers[a]; 387f0393bbfSWojciech Macek platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt; 388f0393bbfSWojciech Macek 389f0393bbfSWojciech Macek platform_cpuref_cnt++; 390f0393bbfSWojciech Macek } 391f0393bbfSWojciech Macek } 392f0393bbfSWojciech Macek } 393f0393bbfSWojciech Macek } 394f0393bbfSWojciech Macek 395f0393bbfSWojciech Macek platform_cpuref_valid = 1; 3967a8d25c0SNathan Whitehorn 3977a8d25c0SNathan Whitehorn return (0); 3987a8d25c0SNathan Whitehorn } 3997a8d25c0SNathan Whitehorn 400f0393bbfSWojciech Macek 4017a8d25c0SNathan Whitehorn #ifdef SMP 4027a8d25c0SNathan Whitehorn static int 4037a8d25c0SNathan Whitehorn chrp_smp_start_cpu(platform_t plat, struct pcpu *pc) 4047a8d25c0SNathan Whitehorn { 4057a8d25c0SNathan Whitehorn cell_t start_cpu; 4067a8d25c0SNathan Whitehorn int result, err, timeout; 4077a8d25c0SNathan Whitehorn 4087a8d25c0SNathan Whitehorn if (!rtas_exists()) { 4097a8d25c0SNathan Whitehorn printf("RTAS uninitialized: unable to start AP %d\n", 4107a8d25c0SNathan Whitehorn pc->pc_cpuid); 4117a8d25c0SNathan Whitehorn return (ENXIO); 4127a8d25c0SNathan Whitehorn } 4137a8d25c0SNathan Whitehorn 4147a8d25c0SNathan Whitehorn start_cpu = rtas_token_lookup("start-cpu"); 4157a8d25c0SNathan Whitehorn if (start_cpu == -1) { 4167a8d25c0SNathan Whitehorn printf("RTAS unknown method: unable to start AP %d\n", 4177a8d25c0SNathan Whitehorn pc->pc_cpuid); 4187a8d25c0SNathan Whitehorn return (ENXIO); 4197a8d25c0SNathan Whitehorn } 4207a8d25c0SNathan Whitehorn 4217a8d25c0SNathan Whitehorn ap_pcpu = pc; 4227a8d25c0SNathan Whitehorn powerpc_sync(); 4237a8d25c0SNathan Whitehorn 424f0393bbfSWojciech Macek result = rtas_call_method(start_cpu, 3, 1, pc->pc_hwref, EXC_RST, pc, 4257a8d25c0SNathan Whitehorn &err); 4267a8d25c0SNathan Whitehorn if (result < 0 || err != 0) { 4277a8d25c0SNathan Whitehorn printf("RTAS error (%d/%d): unable to start AP %d\n", 4287a8d25c0SNathan Whitehorn result, err, pc->pc_cpuid); 4297a8d25c0SNathan Whitehorn return (ENXIO); 4307a8d25c0SNathan Whitehorn } 4317a8d25c0SNathan Whitehorn 4327a8d25c0SNathan Whitehorn timeout = 10000; 4337a8d25c0SNathan Whitehorn while (!pc->pc_awake && timeout--) 4347a8d25c0SNathan Whitehorn DELAY(100); 4357a8d25c0SNathan Whitehorn 4367a8d25c0SNathan Whitehorn return ((pc->pc_awake) ? 0 : EBUSY); 4377a8d25c0SNathan Whitehorn } 4387a8d25c0SNathan Whitehorn 4397a8d25c0SNathan Whitehorn static struct cpu_group * 4407a8d25c0SNathan Whitehorn chrp_smp_topo(platform_t plat) 4417a8d25c0SNathan Whitehorn { 44209f07b00SNathan Whitehorn struct pcpu *pc, *last_pc; 44309f07b00SNathan Whitehorn int i, ncores, ncpus; 4447a8d25c0SNathan Whitehorn 44509f07b00SNathan Whitehorn ncores = ncpus = 0; 44609f07b00SNathan Whitehorn last_pc = NULL; 44709f07b00SNathan Whitehorn for (i = 0; i <= mp_maxid; i++) { 44809f07b00SNathan Whitehorn pc = pcpu_find(i); 44909f07b00SNathan Whitehorn if (pc == NULL) 450f9d6e0a5SNathan Whitehorn continue; 45109f07b00SNathan Whitehorn if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref) 45209f07b00SNathan Whitehorn ncores++; 45309f07b00SNathan Whitehorn last_pc = pc; 45409f07b00SNathan Whitehorn ncpus++; 455f9d6e0a5SNathan Whitehorn } 456f9d6e0a5SNathan Whitehorn 45709f07b00SNathan Whitehorn if (ncpus % ncores != 0) { 4587a8d25c0SNathan Whitehorn printf("WARNING: Irregular SMP topology. Performance may be " 45909f07b00SNathan Whitehorn "suboptimal (%d CPUS, %d cores)\n", ncpus, ncores); 4607a8d25c0SNathan Whitehorn return (smp_topo_none()); 4617a8d25c0SNathan Whitehorn } 4627a8d25c0SNathan Whitehorn 4637a8d25c0SNathan Whitehorn /* Don't do anything fancier for non-threaded SMP */ 46409f07b00SNathan Whitehorn if (ncpus == ncores) 4657a8d25c0SNathan Whitehorn return (smp_topo_none()); 4667a8d25c0SNathan Whitehorn 46709f07b00SNathan Whitehorn return (smp_topo_1level(CG_SHARE_L1, ncpus / ncores, CG_FLAG_SMT)); 4687a8d25c0SNathan Whitehorn } 4697a8d25c0SNathan Whitehorn #endif 4707a8d25c0SNathan Whitehorn 4717a8d25c0SNathan Whitehorn static void 4727a8d25c0SNathan Whitehorn chrp_reset(platform_t platform) 4737a8d25c0SNathan Whitehorn { 4747a8d25c0SNathan Whitehorn OF_reboot(); 4757a8d25c0SNathan Whitehorn } 4767a8d25c0SNathan Whitehorn 4777a8d25c0SNathan Whitehorn #ifdef __powerpc64__ 4787a8d25c0SNathan Whitehorn static void 4797a8d25c0SNathan Whitehorn phyp_cpu_idle(sbintime_t sbt) 4807a8d25c0SNathan Whitehorn { 481e21d69e9SNathan Whitehorn register_t msr; 482e21d69e9SNathan Whitehorn 483e21d69e9SNathan Whitehorn msr = mfmsr(); 484e21d69e9SNathan Whitehorn 485e21d69e9SNathan Whitehorn mtmsr(msr & ~PSL_EE); 486e21d69e9SNathan Whitehorn if (sched_runnable()) { 487e21d69e9SNathan Whitehorn mtmsr(msr); 488e21d69e9SNathan Whitehorn return; 489e21d69e9SNathan Whitehorn } 490e21d69e9SNathan Whitehorn 491e21d69e9SNathan Whitehorn phyp_hcall(H_CEDE); /* Re-enables interrupts internally */ 492e21d69e9SNathan Whitehorn mtmsr(msr); 4937a8d25c0SNathan Whitehorn } 4947a8d25c0SNathan Whitehorn 4957a8d25c0SNathan Whitehorn static void 4967a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform) 4977a8d25c0SNathan Whitehorn { 4987a8d25c0SNathan Whitehorn if (!(mfmsr() & PSL_HV)) { 499f1e48417SNathan Whitehorn /* Register VPA */ 500f0393bbfSWojciech Macek phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(hwref), 501f0393bbfSWojciech Macek splpar_vpa[PCPU_GET(hwref)]); 502f1e48417SNathan Whitehorn 5037a8d25c0SNathan Whitehorn /* Set interrupt priority */ 5047a8d25c0SNathan Whitehorn phyp_hcall(H_CPPR, 0xff); 5057a8d25c0SNathan Whitehorn } 5067a8d25c0SNathan Whitehorn } 5077a8d25c0SNathan Whitehorn #else 5087a8d25c0SNathan Whitehorn static void 5097a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform) 5107a8d25c0SNathan Whitehorn { 5117a8d25c0SNathan Whitehorn } 5127a8d25c0SNathan Whitehorn #endif 5137a8d25c0SNathan Whitehorn 514