1255643Snwhitehorn/*- 2255643Snwhitehorn * Copyright (c) 2008 Marcel Moolenaar 3255643Snwhitehorn * Copyright (c) 2009 Nathan Whitehorn 4255643Snwhitehorn * All rights reserved. 5255643Snwhitehorn * 6255643Snwhitehorn * Redistribution and use in source and binary forms, with or without 7255643Snwhitehorn * modification, are permitted provided that the following conditions 8255643Snwhitehorn * are met: 9255643Snwhitehorn * 10255643Snwhitehorn * 1. Redistributions of source code must retain the above copyright 11255643Snwhitehorn * notice, this list of conditions and the following disclaimer. 12255643Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 13255643Snwhitehorn * notice, this list of conditions and the following disclaimer in the 14255643Snwhitehorn * documentation and/or other materials provided with the distribution. 15255643Snwhitehorn * 16255643Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17255643Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18255643Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19255643Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20255643Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21255643Snwhitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22255643Snwhitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23255643Snwhitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24255643Snwhitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25255643Snwhitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26255643Snwhitehorn */ 27255643Snwhitehorn 28255643Snwhitehorn#include <sys/cdefs.h> 29255643Snwhitehorn__FBSDID("$FreeBSD: releng/10.3/sys/powerpc/pseries/platform_chrp.c 266020 2014-05-14 14:17:51Z ian $"); 30255643Snwhitehorn 31255643Snwhitehorn#include <sys/param.h> 32255643Snwhitehorn#include <sys/systm.h> 33255643Snwhitehorn#include <sys/kernel.h> 34255643Snwhitehorn#include <sys/bus.h> 35255643Snwhitehorn#include <sys/pcpu.h> 36255643Snwhitehorn#include <sys/proc.h> 37255643Snwhitehorn#include <sys/smp.h> 38255643Snwhitehorn#include <vm/vm.h> 39255643Snwhitehorn#include <vm/pmap.h> 40255643Snwhitehorn 41255643Snwhitehorn#include <machine/bus.h> 42255643Snwhitehorn#include <machine/cpu.h> 43255643Snwhitehorn#include <machine/hid.h> 44255643Snwhitehorn#include <machine/platformvar.h> 45255643Snwhitehorn#include <machine/pmap.h> 46255643Snwhitehorn#include <machine/rtas.h> 47255643Snwhitehorn#include <machine/smp.h> 48255643Snwhitehorn#include <machine/spr.h> 49265974Sian#include <machine/trap.h> 50255643Snwhitehorn 51255643Snwhitehorn#include <dev/ofw/openfirm.h> 52255643Snwhitehorn#include <machine/ofw_machdep.h> 53255643Snwhitehorn 54255643Snwhitehorn#include "platform_if.h" 55255643Snwhitehorn 56255643Snwhitehorn#ifdef SMP 57255643Snwhitehornextern void *ap_pcpu; 58255643Snwhitehorn#endif 59255643Snwhitehorn 60255643Snwhitehorn#ifdef __powerpc64__ 61255643Snwhitehornstatic uint8_t splpar_vpa[640] __aligned(64); 62255643Snwhitehorn#endif 63255643Snwhitehorn 64255643Snwhitehornstatic vm_offset_t realmaxaddr = VM_MAX_ADDRESS; 65255643Snwhitehorn 66255643Snwhitehornstatic int chrp_probe(platform_t); 67255643Snwhitehornstatic int chrp_attach(platform_t); 68266020Sianvoid chrp_mem_regions(platform_t, struct mem_region *phys, int *physsz, 69266020Sian struct mem_region *avail, int *availsz); 70255643Snwhitehornstatic vm_offset_t chrp_real_maxaddr(platform_t); 71255643Snwhitehornstatic u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref); 72255643Snwhitehornstatic int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref); 73255643Snwhitehornstatic int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref); 74255643Snwhitehornstatic int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref); 75255643Snwhitehornstatic void chrp_smp_ap_init(platform_t); 76255643Snwhitehorn#ifdef SMP 77255643Snwhitehornstatic int chrp_smp_start_cpu(platform_t, struct pcpu *cpu); 78255643Snwhitehornstatic struct cpu_group *chrp_smp_topo(platform_t plat); 79255643Snwhitehorn#endif 80255643Snwhitehornstatic void chrp_reset(platform_t); 81255643Snwhitehorn#ifdef __powerpc64__ 82255643Snwhitehorn#include "phyp-hvcall.h" 83255643Snwhitehornstatic void phyp_cpu_idle(sbintime_t sbt); 84255643Snwhitehorn#endif 85255643Snwhitehorn 86255643Snwhitehornstatic platform_method_t chrp_methods[] = { 87255643Snwhitehorn PLATFORMMETHOD(platform_probe, chrp_probe), 88255643Snwhitehorn PLATFORMMETHOD(platform_attach, chrp_attach), 89255643Snwhitehorn PLATFORMMETHOD(platform_mem_regions, chrp_mem_regions), 90255643Snwhitehorn PLATFORMMETHOD(platform_real_maxaddr, chrp_real_maxaddr), 91255643Snwhitehorn PLATFORMMETHOD(platform_timebase_freq, chrp_timebase_freq), 92255643Snwhitehorn 93255643Snwhitehorn PLATFORMMETHOD(platform_smp_ap_init, chrp_smp_ap_init), 94255643Snwhitehorn PLATFORMMETHOD(platform_smp_first_cpu, chrp_smp_first_cpu), 95255643Snwhitehorn PLATFORMMETHOD(platform_smp_next_cpu, chrp_smp_next_cpu), 96255643Snwhitehorn PLATFORMMETHOD(platform_smp_get_bsp, chrp_smp_get_bsp), 97255643Snwhitehorn#ifdef SMP 98255643Snwhitehorn PLATFORMMETHOD(platform_smp_start_cpu, chrp_smp_start_cpu), 99255643Snwhitehorn PLATFORMMETHOD(platform_smp_topo, chrp_smp_topo), 100255643Snwhitehorn#endif 101255643Snwhitehorn 102255643Snwhitehorn PLATFORMMETHOD(platform_reset, chrp_reset), 103255643Snwhitehorn 104255643Snwhitehorn { 0, 0 } 105255643Snwhitehorn}; 106255643Snwhitehorn 107255643Snwhitehornstatic platform_def_t chrp_platform = { 108255643Snwhitehorn "chrp", 109255643Snwhitehorn chrp_methods, 110255643Snwhitehorn 0 111255643Snwhitehorn}; 112255643Snwhitehorn 113255643SnwhitehornPLATFORM_DEF(chrp_platform); 114255643Snwhitehorn 115255643Snwhitehornstatic int 116255643Snwhitehornchrp_probe(platform_t plat) 117255643Snwhitehorn{ 118255643Snwhitehorn if (OF_finddevice("/memory") != -1 || OF_finddevice("/memory@0") != -1) 119255643Snwhitehorn return (BUS_PROBE_GENERIC); 120255643Snwhitehorn 121255643Snwhitehorn return (ENXIO); 122255643Snwhitehorn} 123255643Snwhitehorn 124255643Snwhitehornstatic int 125255643Snwhitehornchrp_attach(platform_t plat) 126255643Snwhitehorn{ 127255643Snwhitehorn#ifdef __powerpc64__ 128255643Snwhitehorn /* XXX: check for /rtas/ibm,hypertas-functions? */ 129255643Snwhitehorn if (!(mfmsr() & PSL_HV)) { 130255643Snwhitehorn struct mem_region *phys, *avail; 131255643Snwhitehorn int nphys, navail; 132255643Snwhitehorn mem_regions(&phys, &nphys, &avail, &navail); 133255643Snwhitehorn realmaxaddr = phys[0].mr_size; 134255643Snwhitehorn 135255643Snwhitehorn pmap_mmu_install("mmu_phyp", BUS_PROBE_SPECIFIC); 136255643Snwhitehorn cpu_idle_hook = phyp_cpu_idle; 137255643Snwhitehorn 138255643Snwhitehorn /* Set up important VPA fields */ 139255643Snwhitehorn bzero(splpar_vpa, sizeof(splpar_vpa)); 140255643Snwhitehorn splpar_vpa[4] = (uint8_t)((sizeof(splpar_vpa) >> 8) & 0xff); 141255643Snwhitehorn splpar_vpa[5] = (uint8_t)(sizeof(splpar_vpa) & 0xff); 142255643Snwhitehorn splpar_vpa[0xba] = 1; /* Maintain FPRs */ 143255643Snwhitehorn splpar_vpa[0xbb] = 1; /* Maintain PMCs */ 144255643Snwhitehorn splpar_vpa[0xfc] = 0xff; /* Maintain full SLB */ 145255643Snwhitehorn splpar_vpa[0xfd] = 0xff; 146255643Snwhitehorn splpar_vpa[0xff] = 1; /* Maintain Altivec */ 147255643Snwhitehorn mb(); 148255643Snwhitehorn 149255643Snwhitehorn /* Set up hypervisor CPU stuff */ 150255643Snwhitehorn chrp_smp_ap_init(plat); 151255643Snwhitehorn } 152255643Snwhitehorn#endif 153255643Snwhitehorn 154255910Snwhitehorn /* Some systems (e.g. QEMU) need Open Firmware to stand down */ 155255910Snwhitehorn ofw_quiesce(); 156255910Snwhitehorn 157255643Snwhitehorn return (0); 158255643Snwhitehorn} 159255643Snwhitehorn 160266020Sianstatic int 161266020Sianparse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem, 162266020Sian struct mem_region *ofavail) 163266020Sian{ 164266020Sian phandle_t phandle; 165266020Sian vm_offset_t base; 166266020Sian int i, idx, len, lasz, lmsz, res; 167266020Sian uint32_t lmb_size[2]; 168266020Sian unsigned long *dmem, flags; 169266020Sian 170266020Sian lmsz = *msz; 171266020Sian lasz = *asz; 172266020Sian 173266020Sian phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory"); 174266020Sian if (phandle == -1) 175266020Sian /* No drconf node, return. */ 176266020Sian return (0); 177266020Sian 178266020Sian res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size)); 179266020Sian if (res == -1) 180266020Sian return (0); 181266020Sian printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20); 182266020Sian 183266020Sian /* Parse the /ibm,dynamic-memory. 184266020Sian The first position gives the # of entries. The next two words 185266020Sian reflect the address of the memory block. The next four words are 186266020Sian the DRC index, reserved, list index and flags. 187266020Sian (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory) 188266020Sian 189266020Sian #el Addr DRC-idx res list-idx flags 190266020Sian ------------------------------------------------- 191266020Sian | 4 | 8 | 4 | 4 | 4 | 4 |.... 192266020Sian ------------------------------------------------- 193266020Sian */ 194266020Sian 195266020Sian len = OF_getproplen(phandle, "ibm,dynamic-memory"); 196266020Sian if (len > 0) { 197266020Sian 198266020Sian /* We have to use a variable length array on the stack 199266020Sian since we have very limited stack space. 200266020Sian */ 201266020Sian cell_t arr[len/sizeof(cell_t)]; 202266020Sian 203266020Sian res = OF_getprop(phandle, "ibm,dynamic-memory", &arr, 204266020Sian sizeof(arr)); 205266020Sian if (res == -1) 206266020Sian return (0); 207266020Sian 208266020Sian /* Number of elements */ 209266020Sian idx = arr[0]; 210266020Sian 211266020Sian /* First address. */ 212266020Sian dmem = (void*)&arr[1]; 213266020Sian 214266020Sian for (i = 0; i < idx; i++) { 215266020Sian base = *dmem; 216266020Sian dmem += 2; 217266020Sian flags = *dmem; 218266020Sian /* Use region only if available and not reserved. */ 219266020Sian if ((flags & 0x8) && !(flags & 0x80)) { 220266020Sian ofmem[lmsz].mr_start = base; 221266020Sian ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1]; 222266020Sian ofavail[lasz].mr_start = base; 223266020Sian ofavail[lasz].mr_size = (vm_size_t)lmb_size[1]; 224266020Sian lmsz++; 225266020Sian lasz++; 226266020Sian } 227266020Sian dmem++; 228266020Sian } 229266020Sian } 230266020Sian 231266020Sian *msz = lmsz; 232266020Sian *asz = lasz; 233266020Sian 234266020Sian return (1); 235266020Sian} 236266020Sian 237255643Snwhitehornvoid 238266020Sianchrp_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 239266020Sian struct mem_region *avail, int *availsz) 240255643Snwhitehorn{ 241266020Sian vm_offset_t maxphysaddr; 242266020Sian int i; 243266020Sian 244266020Sian ofw_mem_regions(phys, physsz, avail, availsz); 245266020Sian parse_drconf_memory(physsz, availsz, phys, avail); 246266020Sian 247266020Sian /* 248266020Sian * On some firmwares (SLOF), some memory may be marked available that 249266020Sian * doesn't actually exist. This manifests as an extension of the last 250266020Sian * available segment past the end of physical memory, so truncate that 251266020Sian * one. 252266020Sian */ 253266020Sian maxphysaddr = 0; 254266020Sian for (i = 0; i < *physsz; i++) 255266020Sian if (phys[i].mr_start + phys[i].mr_size > maxphysaddr) 256266020Sian maxphysaddr = phys[i].mr_start + phys[i].mr_size; 257266020Sian 258266020Sian for (i = 0; i < *availsz; i++) 259266020Sian if (avail[i].mr_start + avail[i].mr_size > maxphysaddr) 260266020Sian avail[i].mr_size = maxphysaddr - avail[i].mr_start; 261255643Snwhitehorn} 262255643Snwhitehorn 263255643Snwhitehornstatic vm_offset_t 264255643Snwhitehornchrp_real_maxaddr(platform_t plat) 265255643Snwhitehorn{ 266255643Snwhitehorn return (realmaxaddr); 267255643Snwhitehorn} 268255643Snwhitehorn 269255643Snwhitehornstatic u_long 270255643Snwhitehornchrp_timebase_freq(platform_t plat, struct cpuref *cpuref) 271255643Snwhitehorn{ 272255643Snwhitehorn phandle_t phandle; 273255643Snwhitehorn int32_t ticks = -1; 274255643Snwhitehorn 275255643Snwhitehorn phandle = cpuref->cr_hwref; 276255643Snwhitehorn 277255643Snwhitehorn OF_getprop(phandle, "timebase-frequency", &ticks, sizeof(ticks)); 278255643Snwhitehorn 279255643Snwhitehorn if (ticks <= 0) 280255643Snwhitehorn panic("Unable to determine timebase frequency!"); 281255643Snwhitehorn 282255643Snwhitehorn return (ticks); 283255643Snwhitehorn} 284255643Snwhitehorn 285255643Snwhitehornstatic int 286255643Snwhitehornchrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 287255643Snwhitehorn{ 288255643Snwhitehorn char buf[8]; 289255643Snwhitehorn phandle_t cpu, dev, root; 290255643Snwhitehorn int res, cpuid; 291255643Snwhitehorn 292255643Snwhitehorn root = OF_peer(0); 293255643Snwhitehorn 294255643Snwhitehorn dev = OF_child(root); 295255643Snwhitehorn while (dev != 0) { 296255643Snwhitehorn res = OF_getprop(dev, "name", buf, sizeof(buf)); 297255643Snwhitehorn if (res > 0 && strcmp(buf, "cpus") == 0) 298255643Snwhitehorn break; 299255643Snwhitehorn dev = OF_peer(dev); 300255643Snwhitehorn } 301255643Snwhitehorn if (dev == 0) { 302255643Snwhitehorn /* 303255643Snwhitehorn * psim doesn't have a name property on the /cpus node, 304255643Snwhitehorn * but it can be found directly 305255643Snwhitehorn */ 306255643Snwhitehorn dev = OF_finddevice("/cpus"); 307255643Snwhitehorn if (dev == 0) 308255643Snwhitehorn return (ENOENT); 309255643Snwhitehorn } 310255643Snwhitehorn 311255643Snwhitehorn cpu = OF_child(dev); 312255643Snwhitehorn 313255643Snwhitehorn while (cpu != 0) { 314255643Snwhitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 315255643Snwhitehorn if (res > 0 && strcmp(buf, "cpu") == 0) 316255643Snwhitehorn break; 317255643Snwhitehorn cpu = OF_peer(cpu); 318255643Snwhitehorn } 319255643Snwhitehorn if (cpu == 0) 320255643Snwhitehorn return (ENOENT); 321255643Snwhitehorn 322255643Snwhitehorn cpuref->cr_hwref = cpu; 323255643Snwhitehorn res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid, 324255643Snwhitehorn sizeof(cpuid)); 325255643Snwhitehorn if (res <= 0) 326255643Snwhitehorn res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 327255643Snwhitehorn if (res <= 0) 328255643Snwhitehorn cpuid = 0; 329255643Snwhitehorn cpuref->cr_cpuid = cpuid; 330255643Snwhitehorn 331255643Snwhitehorn return (0); 332255643Snwhitehorn} 333255643Snwhitehorn 334255643Snwhitehornstatic int 335255643Snwhitehornchrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 336255643Snwhitehorn{ 337255643Snwhitehorn char buf[8]; 338255643Snwhitehorn phandle_t cpu; 339255643Snwhitehorn int i, res, cpuid; 340255643Snwhitehorn 341255643Snwhitehorn /* Check for whether it should be the next thread */ 342255643Snwhitehorn res = OF_getproplen(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s"); 343255643Snwhitehorn if (res > 0) { 344255643Snwhitehorn cell_t interrupt_servers[res/sizeof(cell_t)]; 345255643Snwhitehorn OF_getprop(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s", 346255643Snwhitehorn interrupt_servers, res); 347255643Snwhitehorn for (i = 0; i < res/sizeof(cell_t) - 1; i++) { 348255643Snwhitehorn if (interrupt_servers[i] == cpuref->cr_cpuid) { 349255643Snwhitehorn cpuref->cr_cpuid = interrupt_servers[i+1]; 350255643Snwhitehorn return (0); 351255643Snwhitehorn } 352255643Snwhitehorn } 353255643Snwhitehorn } 354255643Snwhitehorn 355255643Snwhitehorn /* Next CPU core/package */ 356255643Snwhitehorn cpu = OF_peer(cpuref->cr_hwref); 357255643Snwhitehorn while (cpu != 0) { 358255643Snwhitehorn res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 359255643Snwhitehorn if (res > 0 && strcmp(buf, "cpu") == 0) 360255643Snwhitehorn break; 361255643Snwhitehorn cpu = OF_peer(cpu); 362255643Snwhitehorn } 363255643Snwhitehorn if (cpu == 0) 364255643Snwhitehorn return (ENOENT); 365255643Snwhitehorn 366255643Snwhitehorn cpuref->cr_hwref = cpu; 367255643Snwhitehorn res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid, 368255643Snwhitehorn sizeof(cpuid)); 369255643Snwhitehorn if (res <= 0) 370255643Snwhitehorn res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 371255643Snwhitehorn if (res <= 0) 372255643Snwhitehorn cpuid = 0; 373255643Snwhitehorn cpuref->cr_cpuid = cpuid; 374255643Snwhitehorn 375255643Snwhitehorn return (0); 376255643Snwhitehorn} 377255643Snwhitehorn 378255643Snwhitehornstatic int 379255643Snwhitehornchrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 380255643Snwhitehorn{ 381255643Snwhitehorn ihandle_t inst; 382255643Snwhitehorn phandle_t bsp, chosen; 383255643Snwhitehorn int res, cpuid; 384255643Snwhitehorn 385255643Snwhitehorn chosen = OF_finddevice("/chosen"); 386255643Snwhitehorn if (chosen == 0) 387255643Snwhitehorn return (ENXIO); 388255643Snwhitehorn 389255643Snwhitehorn res = OF_getprop(chosen, "cpu", &inst, sizeof(inst)); 390255643Snwhitehorn if (res < 0) 391255643Snwhitehorn return (ENXIO); 392255643Snwhitehorn 393255643Snwhitehorn bsp = OF_instance_to_package(inst); 394255643Snwhitehorn 395255643Snwhitehorn /* Pick the primary thread. Can it be any other? */ 396255643Snwhitehorn cpuref->cr_hwref = bsp; 397255643Snwhitehorn res = OF_getprop(bsp, "ibm,ppc-interrupt-server#s", &cpuid, 398255643Snwhitehorn sizeof(cpuid)); 399255643Snwhitehorn if (res <= 0) 400255643Snwhitehorn res = OF_getprop(bsp, "reg", &cpuid, sizeof(cpuid)); 401255643Snwhitehorn if (res <= 0) 402255643Snwhitehorn cpuid = 0; 403255643Snwhitehorn cpuref->cr_cpuid = cpuid; 404255643Snwhitehorn 405255643Snwhitehorn return (0); 406255643Snwhitehorn} 407255643Snwhitehorn 408255643Snwhitehorn#ifdef SMP 409255643Snwhitehornstatic int 410255643Snwhitehornchrp_smp_start_cpu(platform_t plat, struct pcpu *pc) 411255643Snwhitehorn{ 412255643Snwhitehorn cell_t start_cpu; 413255643Snwhitehorn int result, err, timeout; 414255643Snwhitehorn 415255643Snwhitehorn if (!rtas_exists()) { 416255643Snwhitehorn printf("RTAS uninitialized: unable to start AP %d\n", 417255643Snwhitehorn pc->pc_cpuid); 418255643Snwhitehorn return (ENXIO); 419255643Snwhitehorn } 420255643Snwhitehorn 421255643Snwhitehorn start_cpu = rtas_token_lookup("start-cpu"); 422255643Snwhitehorn if (start_cpu == -1) { 423255643Snwhitehorn printf("RTAS unknown method: unable to start AP %d\n", 424255643Snwhitehorn pc->pc_cpuid); 425255643Snwhitehorn return (ENXIO); 426255643Snwhitehorn } 427255643Snwhitehorn 428255643Snwhitehorn ap_pcpu = pc; 429255643Snwhitehorn powerpc_sync(); 430255643Snwhitehorn 431255643Snwhitehorn result = rtas_call_method(start_cpu, 3, 1, pc->pc_cpuid, EXC_RST, pc, 432255643Snwhitehorn &err); 433255643Snwhitehorn if (result < 0 || err != 0) { 434255643Snwhitehorn printf("RTAS error (%d/%d): unable to start AP %d\n", 435255643Snwhitehorn result, err, pc->pc_cpuid); 436255643Snwhitehorn return (ENXIO); 437255643Snwhitehorn } 438255643Snwhitehorn 439255643Snwhitehorn timeout = 10000; 440255643Snwhitehorn while (!pc->pc_awake && timeout--) 441255643Snwhitehorn DELAY(100); 442255643Snwhitehorn 443255643Snwhitehorn return ((pc->pc_awake) ? 0 : EBUSY); 444255643Snwhitehorn} 445255643Snwhitehorn 446255643Snwhitehornstatic struct cpu_group * 447255643Snwhitehornchrp_smp_topo(platform_t plat) 448255643Snwhitehorn{ 449255643Snwhitehorn struct pcpu *pc, *last_pc; 450255643Snwhitehorn int i, ncores, ncpus; 451255643Snwhitehorn 452255643Snwhitehorn ncores = ncpus = 0; 453255643Snwhitehorn last_pc = NULL; 454255643Snwhitehorn for (i = 0; i <= mp_maxid; i++) { 455255643Snwhitehorn pc = pcpu_find(i); 456255643Snwhitehorn if (pc == NULL) 457255643Snwhitehorn continue; 458255643Snwhitehorn if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref) 459255643Snwhitehorn ncores++; 460255643Snwhitehorn last_pc = pc; 461255643Snwhitehorn ncpus++; 462255643Snwhitehorn } 463255643Snwhitehorn 464255643Snwhitehorn if (ncpus % ncores != 0) { 465255643Snwhitehorn printf("WARNING: Irregular SMP topology. Performance may be " 466255643Snwhitehorn "suboptimal (%d CPUS, %d cores)\n", ncpus, ncores); 467255643Snwhitehorn return (smp_topo_none()); 468255643Snwhitehorn } 469255643Snwhitehorn 470255643Snwhitehorn /* Don't do anything fancier for non-threaded SMP */ 471255643Snwhitehorn if (ncpus == ncores) 472255643Snwhitehorn return (smp_topo_none()); 473255643Snwhitehorn 474255643Snwhitehorn return (smp_topo_1level(CG_SHARE_L1, ncpus / ncores, CG_FLAG_SMT)); 475255643Snwhitehorn} 476255643Snwhitehorn#endif 477255643Snwhitehorn 478255643Snwhitehornstatic void 479255643Snwhitehornchrp_reset(platform_t platform) 480255643Snwhitehorn{ 481255643Snwhitehorn OF_reboot(); 482255643Snwhitehorn} 483255643Snwhitehorn 484255643Snwhitehorn#ifdef __powerpc64__ 485255643Snwhitehornstatic void 486255643Snwhitehornphyp_cpu_idle(sbintime_t sbt) 487255643Snwhitehorn{ 488255643Snwhitehorn phyp_hcall(H_CEDE); 489255643Snwhitehorn} 490255643Snwhitehorn 491255643Snwhitehornstatic void 492255643Snwhitehornchrp_smp_ap_init(platform_t platform) 493255643Snwhitehorn{ 494255643Snwhitehorn if (!(mfmsr() & PSL_HV)) { 495255643Snwhitehorn /* Set interrupt priority */ 496255643Snwhitehorn phyp_hcall(H_CPPR, 0xff); 497255643Snwhitehorn 498255643Snwhitehorn /* Register VPA */ 499255643Snwhitehorn phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(cpuid), splpar_vpa); 500255643Snwhitehorn } 501255643Snwhitehorn} 502255643Snwhitehorn#else 503255643Snwhitehornstatic void 504255643Snwhitehornchrp_smp_ap_init(platform_t platform) 505255643Snwhitehorn{ 506255643Snwhitehorn} 507255643Snwhitehorn#endif 508255643Snwhitehorn 509