1fb3855e0SWojciech Macek /*- 2fb3855e0SWojciech Macek * Copyright (c) 2015 Nathan Whitehorn 3fb3855e0SWojciech Macek * All rights reserved. 4fb3855e0SWojciech Macek * 5fb3855e0SWojciech Macek * Redistribution and use in source and binary forms, with or without 6fb3855e0SWojciech Macek * modification, are permitted provided that the following conditions 7fb3855e0SWojciech Macek * are met: 8fb3855e0SWojciech Macek * 9fb3855e0SWojciech Macek * 1. Redistributions of source code must retain the above copyright 10fb3855e0SWojciech Macek * notice, this list of conditions and the following disclaimer. 11fb3855e0SWojciech Macek * 2. Redistributions in binary form must reproduce the above copyright 12fb3855e0SWojciech Macek * notice, this list of conditions and the following disclaimer in the 13fb3855e0SWojciech Macek * documentation and/or other materials provided with the distribution. 14fb3855e0SWojciech Macek * 15fb3855e0SWojciech Macek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16fb3855e0SWojciech Macek * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17fb3855e0SWojciech Macek * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18fb3855e0SWojciech Macek * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19fb3855e0SWojciech Macek * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20fb3855e0SWojciech Macek * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21fb3855e0SWojciech Macek * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22fb3855e0SWojciech Macek * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23fb3855e0SWojciech Macek * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24fb3855e0SWojciech Macek * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25fb3855e0SWojciech Macek */ 26fb3855e0SWojciech Macek 27fb3855e0SWojciech Macek #include <sys/cdefs.h> 28fb3855e0SWojciech Macek __FBSDID("$FreeBSD$"); 29fb3855e0SWojciech Macek 30fb3855e0SWojciech Macek #include <sys/param.h> 31fb3855e0SWojciech Macek #include <sys/systm.h> 32fb3855e0SWojciech Macek #include <sys/kernel.h> 33fb3855e0SWojciech Macek #include <sys/bus.h> 34fb3855e0SWojciech Macek #include <sys/pcpu.h> 35fb3855e0SWojciech Macek #include <sys/proc.h> 36fb3855e0SWojciech Macek #include <sys/smp.h> 37fb3855e0SWojciech Macek #include <vm/vm.h> 38fb3855e0SWojciech Macek #include <vm/pmap.h> 39fb3855e0SWojciech Macek 40fb3855e0SWojciech Macek #include <machine/bus.h> 41fb3855e0SWojciech Macek #include <machine/cpu.h> 42fb3855e0SWojciech Macek #include <machine/hid.h> 43fb3855e0SWojciech Macek #include <machine/platformvar.h> 44fb3855e0SWojciech Macek #include <machine/pmap.h> 45fb3855e0SWojciech Macek #include <machine/rtas.h> 46fb3855e0SWojciech Macek #include <machine/smp.h> 47fb3855e0SWojciech Macek #include <machine/spr.h> 48fb3855e0SWojciech Macek #include <machine/trap.h> 49fb3855e0SWojciech Macek 50fb3855e0SWojciech Macek #include <dev/ofw/openfirm.h> 51fb3855e0SWojciech Macek #include <machine/ofw_machdep.h> 52*504d9b60SWojciech Macek #include <powerpc/aim/mmu_oea64.h> 53fb3855e0SWojciech Macek 54fb3855e0SWojciech Macek #include "platform_if.h" 55fb3855e0SWojciech Macek #include "opal.h" 56fb3855e0SWojciech Macek 57fb3855e0SWojciech Macek #ifdef SMP 58fb3855e0SWojciech Macek extern void *ap_pcpu; 59fb3855e0SWojciech Macek #endif 60fb3855e0SWojciech Macek 61fb3855e0SWojciech Macek static int powernv_probe(platform_t); 62fb3855e0SWojciech Macek static int powernv_attach(platform_t); 63fb3855e0SWojciech Macek void powernv_mem_regions(platform_t, struct mem_region *phys, int *physsz, 64fb3855e0SWojciech Macek struct mem_region *avail, int *availsz); 65fb3855e0SWojciech Macek static u_long powernv_timebase_freq(platform_t, struct cpuref *cpuref); 66fb3855e0SWojciech Macek static int powernv_smp_first_cpu(platform_t, struct cpuref *cpuref); 67fb3855e0SWojciech Macek static int powernv_smp_next_cpu(platform_t, struct cpuref *cpuref); 68fb3855e0SWojciech Macek static int powernv_smp_get_bsp(platform_t, struct cpuref *cpuref); 69fb3855e0SWojciech Macek static void powernv_smp_ap_init(platform_t); 70fb3855e0SWojciech Macek #ifdef SMP 71fb3855e0SWojciech Macek static int powernv_smp_start_cpu(platform_t, struct pcpu *cpu); 72fb3855e0SWojciech Macek static struct cpu_group *powernv_smp_topo(platform_t plat); 73fb3855e0SWojciech Macek #endif 74fb3855e0SWojciech Macek static void powernv_reset(platform_t); 7501d7bda7SWojciech Macek static void powernv_cpu_idle(sbintime_t sbt); 76fb3855e0SWojciech Macek 77fb3855e0SWojciech Macek static platform_method_t powernv_methods[] = { 78fb3855e0SWojciech Macek PLATFORMMETHOD(platform_probe, powernv_probe), 79fb3855e0SWojciech Macek PLATFORMMETHOD(platform_attach, powernv_attach), 80fb3855e0SWojciech Macek PLATFORMMETHOD(platform_mem_regions, powernv_mem_regions), 81fb3855e0SWojciech Macek PLATFORMMETHOD(platform_timebase_freq, powernv_timebase_freq), 82fb3855e0SWojciech Macek 83fb3855e0SWojciech Macek PLATFORMMETHOD(platform_smp_ap_init, powernv_smp_ap_init), 84fb3855e0SWojciech Macek PLATFORMMETHOD(platform_smp_first_cpu, powernv_smp_first_cpu), 85fb3855e0SWojciech Macek PLATFORMMETHOD(platform_smp_next_cpu, powernv_smp_next_cpu), 86fb3855e0SWojciech Macek PLATFORMMETHOD(platform_smp_get_bsp, powernv_smp_get_bsp), 87fb3855e0SWojciech Macek #ifdef SMP 88fb3855e0SWojciech Macek PLATFORMMETHOD(platform_smp_start_cpu, powernv_smp_start_cpu), 89fb3855e0SWojciech Macek PLATFORMMETHOD(platform_smp_topo, powernv_smp_topo), 90fb3855e0SWojciech Macek #endif 91fb3855e0SWojciech Macek 92fb3855e0SWojciech Macek PLATFORMMETHOD(platform_reset, powernv_reset), 93fb3855e0SWojciech Macek 94fb3855e0SWojciech Macek { 0, 0 } 95fb3855e0SWojciech Macek }; 96fb3855e0SWojciech Macek 97fb3855e0SWojciech Macek static platform_def_t powernv_platform = { 98fb3855e0SWojciech Macek "powernv", 99fb3855e0SWojciech Macek powernv_methods, 100fb3855e0SWojciech Macek 0 101fb3855e0SWojciech Macek }; 102fb3855e0SWojciech Macek 103fb3855e0SWojciech Macek PLATFORM_DEF(powernv_platform); 104fb3855e0SWojciech Macek 105*504d9b60SWojciech Macek static int powernv_boot_pir; 106*504d9b60SWojciech Macek 107fb3855e0SWojciech Macek static int 108fb3855e0SWojciech Macek powernv_probe(platform_t plat) 109fb3855e0SWojciech Macek { 110fb3855e0SWojciech Macek if (opal_check() == 0) 111fb3855e0SWojciech Macek return (BUS_PROBE_SPECIFIC); 112fb3855e0SWojciech Macek 113fb3855e0SWojciech Macek return (ENXIO); 114fb3855e0SWojciech Macek } 115fb3855e0SWojciech Macek 116fb3855e0SWojciech Macek static int 117fb3855e0SWojciech Macek powernv_attach(platform_t plat) 118fb3855e0SWojciech Macek { 119*504d9b60SWojciech Macek uint32_t nptlp, shift = 0, slb_encoding = 0; 120*504d9b60SWojciech Macek int32_t lp_size, lp_encoding; 121*504d9b60SWojciech Macek char buf[255]; 122*504d9b60SWojciech Macek pcell_t prop; 123*504d9b60SWojciech Macek phandle_t cpu; 124*504d9b60SWojciech Macek int res, len, node, idx; 125*504d9b60SWojciech Macek 126fb3855e0SWojciech Macek /* Ping OPAL again just to make sure */ 127fb3855e0SWojciech Macek opal_check(); 128fb3855e0SWojciech Macek 12901d7bda7SWojciech Macek cpu_idle_hook = powernv_cpu_idle; 130*504d9b60SWojciech Macek powernv_boot_pir = mfspr(SPR_PIR); 13101d7bda7SWojciech Macek 132*504d9b60SWojciech Macek /* Init CPU bits */ 133*504d9b60SWojciech Macek powernv_smp_ap_init(plat); 134c0248976SWojciech Macek 135*504d9b60SWojciech Macek /* Set SLB count from device tree */ 136*504d9b60SWojciech Macek cpu = OF_peer(0); 137*504d9b60SWojciech Macek cpu = OF_child(cpu); 138*504d9b60SWojciech Macek while (cpu != 0) { 139*504d9b60SWojciech Macek res = OF_getprop(cpu, "name", buf, sizeof(buf)); 140*504d9b60SWojciech Macek if (res > 0 && strcmp(buf, "cpus") == 0) 141*504d9b60SWojciech Macek break; 142*504d9b60SWojciech Macek cpu = OF_peer(cpu); 143*504d9b60SWojciech Macek } 144*504d9b60SWojciech Macek if (cpu == 0) 145*504d9b60SWojciech Macek goto out; 146*504d9b60SWojciech Macek 147*504d9b60SWojciech Macek cpu = OF_child(cpu); 148*504d9b60SWojciech Macek while (cpu != 0) { 149*504d9b60SWojciech Macek res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 150*504d9b60SWojciech Macek if (res > 0 && strcmp(buf, "cpu") == 0) 151*504d9b60SWojciech Macek break; 152*504d9b60SWojciech Macek cpu = OF_peer(cpu); 153*504d9b60SWojciech Macek } 154*504d9b60SWojciech Macek if (cpu == 0) 155*504d9b60SWojciech Macek goto out; 156*504d9b60SWojciech Macek 157*504d9b60SWojciech Macek res = OF_getencprop(cpu, "ibm,slb-size", &prop, sizeof(prop)); 158*504d9b60SWojciech Macek if (res > 0) 159*504d9b60SWojciech Macek n_slbs = prop; 160*504d9b60SWojciech Macek 161*504d9b60SWojciech Macek /* 162*504d9b60SWojciech Macek * Scan the large page size property for PAPR compatible machines. 163*504d9b60SWojciech Macek * See PAPR D.5 Changes to Section 5.1.4, 'CPU Node Properties' 164*504d9b60SWojciech Macek * for the encoding of the property. 165*504d9b60SWojciech Macek */ 166*504d9b60SWojciech Macek 167*504d9b60SWojciech Macek len = OF_getproplen(node, "ibm,segment-page-sizes"); 168*504d9b60SWojciech Macek if (len > 0) { 169*504d9b60SWojciech Macek /* 170*504d9b60SWojciech Macek * We have to use a variable length array on the stack 171*504d9b60SWojciech Macek * since we have very limited stack space. 172*504d9b60SWojciech Macek */ 173*504d9b60SWojciech Macek pcell_t arr[len/sizeof(cell_t)]; 174*504d9b60SWojciech Macek res = OF_getencprop(cpu, "ibm,segment-page-sizes", arr, 175*504d9b60SWojciech Macek sizeof(arr)); 176*504d9b60SWojciech Macek len /= 4; 177*504d9b60SWojciech Macek idx = 0; 178*504d9b60SWojciech Macek while (len > 0) { 179*504d9b60SWojciech Macek shift = arr[idx]; 180*504d9b60SWojciech Macek slb_encoding = arr[idx + 1]; 181*504d9b60SWojciech Macek nptlp = arr[idx + 2]; 182*504d9b60SWojciech Macek idx += 3; 183*504d9b60SWojciech Macek len -= 3; 184*504d9b60SWojciech Macek while (len > 0 && nptlp) { 185*504d9b60SWojciech Macek lp_size = arr[idx]; 186*504d9b60SWojciech Macek lp_encoding = arr[idx+1]; 187*504d9b60SWojciech Macek if (slb_encoding == SLBV_L && lp_encoding == 0) 188*504d9b60SWojciech Macek break; 189*504d9b60SWojciech Macek 190*504d9b60SWojciech Macek idx += 2; 191*504d9b60SWojciech Macek len -= 2; 192*504d9b60SWojciech Macek nptlp--; 193*504d9b60SWojciech Macek } 194*504d9b60SWojciech Macek if (nptlp && slb_encoding == SLBV_L && lp_encoding == 0) 195*504d9b60SWojciech Macek break; 196*504d9b60SWojciech Macek } 197*504d9b60SWojciech Macek 198*504d9b60SWojciech Macek if (len == 0) 199*504d9b60SWojciech Macek panic("Standard large pages (SLB[L] = 1, PTE[LP] = 0) " 200*504d9b60SWojciech Macek "not supported by this system."); 201*504d9b60SWojciech Macek 202*504d9b60SWojciech Macek moea64_large_page_shift = shift; 203*504d9b60SWojciech Macek moea64_large_page_size = 1ULL << lp_size; 204*504d9b60SWojciech Macek } 205*504d9b60SWojciech Macek 206*504d9b60SWojciech Macek out: 207fb3855e0SWojciech Macek return (0); 208fb3855e0SWojciech Macek } 209fb3855e0SWojciech Macek 210*504d9b60SWojciech Macek 211fb3855e0SWojciech Macek void 212fb3855e0SWojciech Macek powernv_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 213fb3855e0SWojciech Macek struct mem_region *avail, int *availsz) 214fb3855e0SWojciech Macek { 215fb3855e0SWojciech Macek 216fb3855e0SWojciech Macek ofw_mem_regions(phys, physsz, avail, availsz); 217fb3855e0SWojciech Macek } 218fb3855e0SWojciech Macek 219fb3855e0SWojciech Macek static u_long 220fb3855e0SWojciech Macek powernv_timebase_freq(platform_t plat, struct cpuref *cpuref) 221fb3855e0SWojciech Macek { 222fb3855e0SWojciech Macek phandle_t phandle; 223fb3855e0SWojciech Macek int32_t ticks = -1; 224fb3855e0SWojciech Macek 225fb3855e0SWojciech Macek phandle = cpuref->cr_hwref; 226fb3855e0SWojciech Macek 227*504d9b60SWojciech Macek OF_getencprop(phandle, "timebase-frequency", &ticks, sizeof(ticks)); 228fb3855e0SWojciech Macek 229fb3855e0SWojciech Macek if (ticks <= 0) 230fb3855e0SWojciech Macek panic("Unable to determine timebase frequency!"); 231fb3855e0SWojciech Macek 232fb3855e0SWojciech Macek return (ticks); 233fb3855e0SWojciech Macek } 234fb3855e0SWojciech Macek 235fb3855e0SWojciech Macek static int 236fb3855e0SWojciech Macek powernv_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 237fb3855e0SWojciech Macek { 238fb3855e0SWojciech Macek char buf[8]; 239fb3855e0SWojciech Macek phandle_t cpu, dev, root; 240fb3855e0SWojciech Macek int res, cpuid; 241fb3855e0SWojciech Macek 242fb3855e0SWojciech Macek root = OF_peer(0); 243fb3855e0SWojciech Macek 244fb3855e0SWojciech Macek dev = OF_child(root); 245fb3855e0SWojciech Macek while (dev != 0) { 246fb3855e0SWojciech Macek res = OF_getprop(dev, "name", buf, sizeof(buf)); 247fb3855e0SWojciech Macek if (res > 0 && strcmp(buf, "cpus") == 0) 248fb3855e0SWojciech Macek break; 249fb3855e0SWojciech Macek dev = OF_peer(dev); 250fb3855e0SWojciech Macek } 251fb3855e0SWojciech Macek if (dev == 0) { 252fb3855e0SWojciech Macek /* 253fb3855e0SWojciech Macek * psim doesn't have a name property on the /cpus node, 254fb3855e0SWojciech Macek * but it can be found directly 255fb3855e0SWojciech Macek */ 256fb3855e0SWojciech Macek dev = OF_finddevice("/cpus"); 257fb3855e0SWojciech Macek if (dev == 0) 258fb3855e0SWojciech Macek return (ENOENT); 259fb3855e0SWojciech Macek } 260fb3855e0SWojciech Macek 261fb3855e0SWojciech Macek cpu = OF_child(dev); 262fb3855e0SWojciech Macek 263fb3855e0SWojciech Macek while (cpu != 0) { 264fb3855e0SWojciech Macek res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 265fb3855e0SWojciech Macek if (res > 0 && strcmp(buf, "cpu") == 0) 266fb3855e0SWojciech Macek break; 267fb3855e0SWojciech Macek cpu = OF_peer(cpu); 268fb3855e0SWojciech Macek } 269fb3855e0SWojciech Macek if (cpu == 0) 270fb3855e0SWojciech Macek return (ENOENT); 271fb3855e0SWojciech Macek 272fb3855e0SWojciech Macek cpuref->cr_hwref = cpu; 273*504d9b60SWojciech Macek res = OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid, 274fb3855e0SWojciech Macek sizeof(cpuid)); 275fb3855e0SWojciech Macek if (res <= 0) 276*504d9b60SWojciech Macek res = OF_getencprop(cpu, "reg", &cpuid, sizeof(cpuid)); 277fb3855e0SWojciech Macek if (res <= 0) 278fb3855e0SWojciech Macek cpuid = 0; 279fb3855e0SWojciech Macek cpuref->cr_cpuid = cpuid; 280fb3855e0SWojciech Macek 281fb3855e0SWojciech Macek return (0); 282fb3855e0SWojciech Macek } 283fb3855e0SWojciech Macek 284fb3855e0SWojciech Macek static int 285fb3855e0SWojciech Macek powernv_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 286fb3855e0SWojciech Macek { 287fb3855e0SWojciech Macek char buf[8]; 288fb3855e0SWojciech Macek phandle_t cpu; 289fb3855e0SWojciech Macek int i, res, cpuid; 290fb3855e0SWojciech Macek 291fb3855e0SWojciech Macek /* Check for whether it should be the next thread */ 292fb3855e0SWojciech Macek res = OF_getproplen(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s"); 293fb3855e0SWojciech Macek if (res > 0) { 294fb3855e0SWojciech Macek cell_t interrupt_servers[res/sizeof(cell_t)]; 295*504d9b60SWojciech Macek OF_getencprop(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s", 296fb3855e0SWojciech Macek interrupt_servers, res); 297fb3855e0SWojciech Macek for (i = 0; i < res/sizeof(cell_t) - 1; i++) { 298fb3855e0SWojciech Macek if (interrupt_servers[i] == cpuref->cr_cpuid) { 299fb3855e0SWojciech Macek cpuref->cr_cpuid = interrupt_servers[i+1]; 300fb3855e0SWojciech Macek return (0); 301fb3855e0SWojciech Macek } 302fb3855e0SWojciech Macek } 303fb3855e0SWojciech Macek } 304fb3855e0SWojciech Macek 305fb3855e0SWojciech Macek /* Next CPU core/package */ 306fb3855e0SWojciech Macek cpu = OF_peer(cpuref->cr_hwref); 307fb3855e0SWojciech Macek while (cpu != 0) { 308fb3855e0SWojciech Macek res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 309fb3855e0SWojciech Macek if (res > 0 && strcmp(buf, "cpu") == 0) 310fb3855e0SWojciech Macek break; 311fb3855e0SWojciech Macek cpu = OF_peer(cpu); 312fb3855e0SWojciech Macek } 313fb3855e0SWojciech Macek if (cpu == 0) 314fb3855e0SWojciech Macek return (ENOENT); 315fb3855e0SWojciech Macek 316fb3855e0SWojciech Macek cpuref->cr_hwref = cpu; 317*504d9b60SWojciech Macek res = OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid, 318fb3855e0SWojciech Macek sizeof(cpuid)); 319fb3855e0SWojciech Macek if (res <= 0) 320*504d9b60SWojciech Macek res = OF_getencprop(cpu, "reg", &cpuid, sizeof(cpuid)); 321fb3855e0SWojciech Macek if (res <= 0) 322fb3855e0SWojciech Macek cpuid = 0; 323fb3855e0SWojciech Macek cpuref->cr_cpuid = cpuid; 324fb3855e0SWojciech Macek 325fb3855e0SWojciech Macek return (0); 326fb3855e0SWojciech Macek } 327fb3855e0SWojciech Macek 328fb3855e0SWojciech Macek static int 329fb3855e0SWojciech Macek powernv_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 330fb3855e0SWojciech Macek { 331fb3855e0SWojciech Macek phandle_t chosen; 332fb3855e0SWojciech Macek int cpuid, res; 333fb3855e0SWojciech Macek struct cpuref i; 334fb3855e0SWojciech Macek 335fb3855e0SWojciech Macek chosen = OF_finddevice("/chosen"); 336fb3855e0SWojciech Macek if (chosen == 0) 337fb3855e0SWojciech Macek return (ENOENT); 338fb3855e0SWojciech Macek 339fb3855e0SWojciech Macek res = OF_getencprop(chosen, "fdtbootcpu", &cpuid, sizeof(cpuid)); 340fb3855e0SWojciech Macek if (res < 0) 341fb3855e0SWojciech Macek return (ENOENT); 342fb3855e0SWojciech Macek 343*504d9b60SWojciech Macek /* XXX: FDT from kexec lies sometimes. PIR seems not to. */ 344*504d9b60SWojciech Macek if (cpuid == 0) 345*504d9b60SWojciech Macek cpuid = powernv_boot_pir; 346*504d9b60SWojciech Macek 347fb3855e0SWojciech Macek cpuref->cr_cpuid = cpuid; 348fb3855e0SWojciech Macek 349fb3855e0SWojciech Macek if (powernv_smp_first_cpu(plat, &i) != 0) 350fb3855e0SWojciech Macek return (ENOENT); 351fb3855e0SWojciech Macek cpuref->cr_hwref = i.cr_hwref; 352fb3855e0SWojciech Macek 353fb3855e0SWojciech Macek do { 354fb3855e0SWojciech Macek if (i.cr_cpuid == cpuid) { 355fb3855e0SWojciech Macek cpuref->cr_hwref = i.cr_hwref; 356fb3855e0SWojciech Macek break; 357fb3855e0SWojciech Macek } 358fb3855e0SWojciech Macek } while (powernv_smp_next_cpu(plat, &i) == 0); 359fb3855e0SWojciech Macek 360fb3855e0SWojciech Macek return (0); 361fb3855e0SWojciech Macek } 362fb3855e0SWojciech Macek 363fb3855e0SWojciech Macek #ifdef SMP 364fb3855e0SWojciech Macek static int 365fb3855e0SWojciech Macek powernv_smp_start_cpu(platform_t plat, struct pcpu *pc) 366fb3855e0SWojciech Macek { 36701d7bda7SWojciech Macek int result; 368fb3855e0SWojciech Macek 369fb3855e0SWojciech Macek ap_pcpu = pc; 370fb3855e0SWojciech Macek powerpc_sync(); 371fb3855e0SWojciech Macek 372fb3855e0SWojciech Macek result = opal_call(OPAL_START_CPU, pc->pc_cpuid, EXC_RST); 37301d7bda7SWojciech Macek if (result != OPAL_SUCCESS) { 37401d7bda7SWojciech Macek printf("OPAL error (%d): unable to start AP %d\n", 37501d7bda7SWojciech Macek result, pc->pc_cpuid); 376fb3855e0SWojciech Macek return (ENXIO); 377fb3855e0SWojciech Macek } 378fb3855e0SWojciech Macek 37901d7bda7SWojciech Macek return (0); 380fb3855e0SWojciech Macek } 381fb3855e0SWojciech Macek 382fb3855e0SWojciech Macek static struct cpu_group * 383fb3855e0SWojciech Macek powernv_smp_topo(platform_t plat) 384fb3855e0SWojciech Macek { 385fb3855e0SWojciech Macek struct pcpu *pc, *last_pc; 386fb3855e0SWojciech Macek int i, ncores, ncpus; 387fb3855e0SWojciech Macek 388fb3855e0SWojciech Macek ncores = ncpus = 0; 389fb3855e0SWojciech Macek last_pc = NULL; 390*504d9b60SWojciech Macek CPU_FOREACH(i) { 391fb3855e0SWojciech Macek pc = pcpu_find(i); 392fb3855e0SWojciech Macek if (pc == NULL) 393fb3855e0SWojciech Macek continue; 394fb3855e0SWojciech Macek if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref) 395fb3855e0SWojciech Macek ncores++; 396fb3855e0SWojciech Macek last_pc = pc; 397fb3855e0SWojciech Macek ncpus++; 398fb3855e0SWojciech Macek } 399fb3855e0SWojciech Macek 400fb3855e0SWojciech Macek if (ncpus % ncores != 0) { 401fb3855e0SWojciech Macek printf("WARNING: Irregular SMP topology. Performance may be " 402fb3855e0SWojciech Macek "suboptimal (%d CPUS, %d cores)\n", ncpus, ncores); 403fb3855e0SWojciech Macek return (smp_topo_none()); 404fb3855e0SWojciech Macek } 405fb3855e0SWojciech Macek 406fb3855e0SWojciech Macek /* Don't do anything fancier for non-threaded SMP */ 407fb3855e0SWojciech Macek if (ncpus == ncores) 408fb3855e0SWojciech Macek return (smp_topo_none()); 409fb3855e0SWojciech Macek 410*504d9b60SWojciech Macek #ifdef NOTYET /* smp_topo_1level() fails with non-consecutive CPU IDs */ 411fb3855e0SWojciech Macek return (smp_topo_1level(CG_SHARE_L1, ncpus / ncores, CG_FLAG_SMT)); 412*504d9b60SWojciech Macek #else 413*504d9b60SWojciech Macek return (smp_topo_none()); 414*504d9b60SWojciech Macek #endif 415fb3855e0SWojciech Macek } 416fb3855e0SWojciech Macek #endif 417fb3855e0SWojciech Macek 418fb3855e0SWojciech Macek static void 419fb3855e0SWojciech Macek powernv_reset(platform_t platform) 420fb3855e0SWojciech Macek { 42132d1354aSWojciech Macek 42232d1354aSWojciech Macek opal_call(OPAL_CEC_REBOOT); 423fb3855e0SWojciech Macek } 424fb3855e0SWojciech Macek 425fb3855e0SWojciech Macek static void 426fb3855e0SWojciech Macek powernv_smp_ap_init(platform_t platform) 427fb3855e0SWojciech Macek { 428*504d9b60SWojciech Macek 429*504d9b60SWojciech Macek /* Direct interrupts to SRR instead of HSRR and reset LPCR otherwise */ 430*504d9b60SWojciech Macek mtspr(SPR_LPCR, LPCR_LPES); 431fb3855e0SWojciech Macek } 432fb3855e0SWojciech Macek 43301d7bda7SWojciech Macek static void 43401d7bda7SWojciech Macek powernv_cpu_idle(sbintime_t sbt) 43501d7bda7SWojciech Macek { 43601d7bda7SWojciech Macek } 437