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> 52fb3855e0SWojciech Macek 53fb3855e0SWojciech Macek #include "platform_if.h" 54fb3855e0SWojciech Macek #include "opal.h" 55fb3855e0SWojciech Macek 56fb3855e0SWojciech Macek #ifdef SMP 57fb3855e0SWojciech Macek extern void *ap_pcpu; 58fb3855e0SWojciech Macek #endif 59fb3855e0SWojciech Macek 60fb3855e0SWojciech Macek static int powernv_probe(platform_t); 61fb3855e0SWojciech Macek static int powernv_attach(platform_t); 62fb3855e0SWojciech Macek void powernv_mem_regions(platform_t, struct mem_region *phys, int *physsz, 63fb3855e0SWojciech Macek struct mem_region *avail, int *availsz); 64fb3855e0SWojciech Macek static u_long powernv_timebase_freq(platform_t, struct cpuref *cpuref); 65fb3855e0SWojciech Macek static int powernv_smp_first_cpu(platform_t, struct cpuref *cpuref); 66fb3855e0SWojciech Macek static int powernv_smp_next_cpu(platform_t, struct cpuref *cpuref); 67fb3855e0SWojciech Macek static int powernv_smp_get_bsp(platform_t, struct cpuref *cpuref); 68fb3855e0SWojciech Macek static void powernv_smp_ap_init(platform_t); 69fb3855e0SWojciech Macek #ifdef SMP 70fb3855e0SWojciech Macek static int powernv_smp_start_cpu(platform_t, struct pcpu *cpu); 71fb3855e0SWojciech Macek static struct cpu_group *powernv_smp_topo(platform_t plat); 72fb3855e0SWojciech Macek #endif 73fb3855e0SWojciech Macek static void powernv_reset(platform_t); 74*01d7bda7SWojciech Macek static void powernv_cpu_idle(sbintime_t sbt); 75fb3855e0SWojciech Macek 76fb3855e0SWojciech Macek static platform_method_t powernv_methods[] = { 77fb3855e0SWojciech Macek PLATFORMMETHOD(platform_probe, powernv_probe), 78fb3855e0SWojciech Macek PLATFORMMETHOD(platform_attach, powernv_attach), 79fb3855e0SWojciech Macek PLATFORMMETHOD(platform_mem_regions, powernv_mem_regions), 80fb3855e0SWojciech Macek PLATFORMMETHOD(platform_timebase_freq, powernv_timebase_freq), 81fb3855e0SWojciech Macek 82fb3855e0SWojciech Macek PLATFORMMETHOD(platform_smp_ap_init, powernv_smp_ap_init), 83fb3855e0SWojciech Macek PLATFORMMETHOD(platform_smp_first_cpu, powernv_smp_first_cpu), 84fb3855e0SWojciech Macek PLATFORMMETHOD(platform_smp_next_cpu, powernv_smp_next_cpu), 85fb3855e0SWojciech Macek PLATFORMMETHOD(platform_smp_get_bsp, powernv_smp_get_bsp), 86fb3855e0SWojciech Macek #ifdef SMP 87fb3855e0SWojciech Macek PLATFORMMETHOD(platform_smp_start_cpu, powernv_smp_start_cpu), 88fb3855e0SWojciech Macek PLATFORMMETHOD(platform_smp_topo, powernv_smp_topo), 89fb3855e0SWojciech Macek #endif 90fb3855e0SWojciech Macek 91fb3855e0SWojciech Macek PLATFORMMETHOD(platform_reset, powernv_reset), 92fb3855e0SWojciech Macek 93fb3855e0SWojciech Macek { 0, 0 } 94fb3855e0SWojciech Macek }; 95fb3855e0SWojciech Macek 96fb3855e0SWojciech Macek static platform_def_t powernv_platform = { 97fb3855e0SWojciech Macek "powernv", 98fb3855e0SWojciech Macek powernv_methods, 99fb3855e0SWojciech Macek 0 100fb3855e0SWojciech Macek }; 101fb3855e0SWojciech Macek 102fb3855e0SWojciech Macek PLATFORM_DEF(powernv_platform); 103fb3855e0SWojciech Macek 104fb3855e0SWojciech Macek static int 105fb3855e0SWojciech Macek powernv_probe(platform_t plat) 106fb3855e0SWojciech Macek { 107fb3855e0SWojciech Macek if (opal_check() == 0) 108fb3855e0SWojciech Macek return (BUS_PROBE_SPECIFIC); 109fb3855e0SWojciech Macek 110fb3855e0SWojciech Macek return (ENXIO); 111fb3855e0SWojciech Macek } 112fb3855e0SWojciech Macek 113fb3855e0SWojciech Macek static int 114fb3855e0SWojciech Macek powernv_attach(platform_t plat) 115fb3855e0SWojciech Macek { 116fb3855e0SWojciech Macek /* Ping OPAL again just to make sure */ 117fb3855e0SWojciech Macek opal_check(); 118fb3855e0SWojciech Macek 119*01d7bda7SWojciech Macek cpu_idle_hook = powernv_cpu_idle; 120*01d7bda7SWojciech Macek 121fb3855e0SWojciech Macek return (0); 122fb3855e0SWojciech Macek } 123fb3855e0SWojciech Macek 124fb3855e0SWojciech Macek void 125fb3855e0SWojciech Macek powernv_mem_regions(platform_t plat, struct mem_region *phys, int *physsz, 126fb3855e0SWojciech Macek struct mem_region *avail, int *availsz) 127fb3855e0SWojciech Macek { 128fb3855e0SWojciech Macek 129fb3855e0SWojciech Macek ofw_mem_regions(phys, physsz, avail, availsz); 130fb3855e0SWojciech Macek } 131fb3855e0SWojciech Macek 132fb3855e0SWojciech Macek static u_long 133fb3855e0SWojciech Macek powernv_timebase_freq(platform_t plat, struct cpuref *cpuref) 134fb3855e0SWojciech Macek { 135fb3855e0SWojciech Macek phandle_t phandle; 136fb3855e0SWojciech Macek int32_t ticks = -1; 137fb3855e0SWojciech Macek 138fb3855e0SWojciech Macek phandle = cpuref->cr_hwref; 139fb3855e0SWojciech Macek 140fb3855e0SWojciech Macek OF_getprop(phandle, "timebase-frequency", &ticks, sizeof(ticks)); 141fb3855e0SWojciech Macek 142fb3855e0SWojciech Macek if (ticks <= 0) 143fb3855e0SWojciech Macek panic("Unable to determine timebase frequency!"); 144fb3855e0SWojciech Macek 145fb3855e0SWojciech Macek return (ticks); 146fb3855e0SWojciech Macek } 147fb3855e0SWojciech Macek 148fb3855e0SWojciech Macek static int 149fb3855e0SWojciech Macek powernv_smp_first_cpu(platform_t plat, struct cpuref *cpuref) 150fb3855e0SWojciech Macek { 151fb3855e0SWojciech Macek char buf[8]; 152fb3855e0SWojciech Macek phandle_t cpu, dev, root; 153fb3855e0SWojciech Macek int res, cpuid; 154fb3855e0SWojciech Macek 155fb3855e0SWojciech Macek root = OF_peer(0); 156fb3855e0SWojciech Macek 157fb3855e0SWojciech Macek dev = OF_child(root); 158fb3855e0SWojciech Macek while (dev != 0) { 159fb3855e0SWojciech Macek res = OF_getprop(dev, "name", buf, sizeof(buf)); 160fb3855e0SWojciech Macek if (res > 0 && strcmp(buf, "cpus") == 0) 161fb3855e0SWojciech Macek break; 162fb3855e0SWojciech Macek dev = OF_peer(dev); 163fb3855e0SWojciech Macek } 164fb3855e0SWojciech Macek if (dev == 0) { 165fb3855e0SWojciech Macek /* 166fb3855e0SWojciech Macek * psim doesn't have a name property on the /cpus node, 167fb3855e0SWojciech Macek * but it can be found directly 168fb3855e0SWojciech Macek */ 169fb3855e0SWojciech Macek dev = OF_finddevice("/cpus"); 170fb3855e0SWojciech Macek if (dev == 0) 171fb3855e0SWojciech Macek return (ENOENT); 172fb3855e0SWojciech Macek } 173fb3855e0SWojciech Macek 174fb3855e0SWojciech Macek cpu = OF_child(dev); 175fb3855e0SWojciech Macek 176fb3855e0SWojciech Macek while (cpu != 0) { 177fb3855e0SWojciech Macek res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 178fb3855e0SWojciech Macek if (res > 0 && strcmp(buf, "cpu") == 0) 179fb3855e0SWojciech Macek break; 180fb3855e0SWojciech Macek cpu = OF_peer(cpu); 181fb3855e0SWojciech Macek } 182fb3855e0SWojciech Macek if (cpu == 0) 183fb3855e0SWojciech Macek return (ENOENT); 184fb3855e0SWojciech Macek 185fb3855e0SWojciech Macek cpuref->cr_hwref = cpu; 186fb3855e0SWojciech Macek res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid, 187fb3855e0SWojciech Macek sizeof(cpuid)); 188fb3855e0SWojciech Macek if (res <= 0) 189fb3855e0SWojciech Macek res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 190fb3855e0SWojciech Macek if (res <= 0) 191fb3855e0SWojciech Macek cpuid = 0; 192fb3855e0SWojciech Macek cpuref->cr_cpuid = cpuid; 193fb3855e0SWojciech Macek 194fb3855e0SWojciech Macek return (0); 195fb3855e0SWojciech Macek } 196fb3855e0SWojciech Macek 197fb3855e0SWojciech Macek static int 198fb3855e0SWojciech Macek powernv_smp_next_cpu(platform_t plat, struct cpuref *cpuref) 199fb3855e0SWojciech Macek { 200fb3855e0SWojciech Macek char buf[8]; 201fb3855e0SWojciech Macek phandle_t cpu; 202fb3855e0SWojciech Macek int i, res, cpuid; 203fb3855e0SWojciech Macek 204fb3855e0SWojciech Macek /* Check for whether it should be the next thread */ 205fb3855e0SWojciech Macek res = OF_getproplen(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s"); 206fb3855e0SWojciech Macek if (res > 0) { 207fb3855e0SWojciech Macek cell_t interrupt_servers[res/sizeof(cell_t)]; 208fb3855e0SWojciech Macek OF_getprop(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s", 209fb3855e0SWojciech Macek interrupt_servers, res); 210fb3855e0SWojciech Macek for (i = 0; i < res/sizeof(cell_t) - 1; i++) { 211fb3855e0SWojciech Macek if (interrupt_servers[i] == cpuref->cr_cpuid) { 212fb3855e0SWojciech Macek cpuref->cr_cpuid = interrupt_servers[i+1]; 213fb3855e0SWojciech Macek return (0); 214fb3855e0SWojciech Macek } 215fb3855e0SWojciech Macek } 216fb3855e0SWojciech Macek } 217fb3855e0SWojciech Macek 218fb3855e0SWojciech Macek /* Next CPU core/package */ 219fb3855e0SWojciech Macek cpu = OF_peer(cpuref->cr_hwref); 220fb3855e0SWojciech Macek while (cpu != 0) { 221fb3855e0SWojciech Macek res = OF_getprop(cpu, "device_type", buf, sizeof(buf)); 222fb3855e0SWojciech Macek if (res > 0 && strcmp(buf, "cpu") == 0) 223fb3855e0SWojciech Macek break; 224fb3855e0SWojciech Macek cpu = OF_peer(cpu); 225fb3855e0SWojciech Macek } 226fb3855e0SWojciech Macek if (cpu == 0) 227fb3855e0SWojciech Macek return (ENOENT); 228fb3855e0SWojciech Macek 229fb3855e0SWojciech Macek cpuref->cr_hwref = cpu; 230fb3855e0SWojciech Macek res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid, 231fb3855e0SWojciech Macek sizeof(cpuid)); 232fb3855e0SWojciech Macek if (res <= 0) 233fb3855e0SWojciech Macek res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid)); 234fb3855e0SWojciech Macek if (res <= 0) 235fb3855e0SWojciech Macek cpuid = 0; 236fb3855e0SWojciech Macek cpuref->cr_cpuid = cpuid; 237fb3855e0SWojciech Macek 238fb3855e0SWojciech Macek return (0); 239fb3855e0SWojciech Macek } 240fb3855e0SWojciech Macek 241fb3855e0SWojciech Macek static int 242fb3855e0SWojciech Macek powernv_smp_get_bsp(platform_t plat, struct cpuref *cpuref) 243fb3855e0SWojciech Macek { 244fb3855e0SWojciech Macek phandle_t chosen; 245fb3855e0SWojciech Macek int cpuid, res; 246fb3855e0SWojciech Macek struct cpuref i; 247fb3855e0SWojciech Macek 248fb3855e0SWojciech Macek chosen = OF_finddevice("/chosen"); 249fb3855e0SWojciech Macek if (chosen == 0) 250fb3855e0SWojciech Macek return (ENOENT); 251fb3855e0SWojciech Macek 252fb3855e0SWojciech Macek res = OF_getencprop(chosen, "fdtbootcpu", &cpuid, sizeof(cpuid)); 253fb3855e0SWojciech Macek if (res < 0) 254fb3855e0SWojciech Macek return (ENOENT); 255fb3855e0SWojciech Macek 256fb3855e0SWojciech Macek cpuref->cr_cpuid = cpuid; 257fb3855e0SWojciech Macek 258fb3855e0SWojciech Macek if (powernv_smp_first_cpu(plat, &i) != 0) 259fb3855e0SWojciech Macek return (ENOENT); 260fb3855e0SWojciech Macek cpuref->cr_hwref = i.cr_hwref; 261fb3855e0SWojciech Macek 262fb3855e0SWojciech Macek do { 263fb3855e0SWojciech Macek if (i.cr_cpuid == cpuid) { 264fb3855e0SWojciech Macek cpuref->cr_hwref = i.cr_hwref; 265fb3855e0SWojciech Macek break; 266fb3855e0SWojciech Macek } 267fb3855e0SWojciech Macek } while (powernv_smp_next_cpu(plat, &i) == 0); 268fb3855e0SWojciech Macek 269fb3855e0SWojciech Macek return (0); 270fb3855e0SWojciech Macek } 271fb3855e0SWojciech Macek 272fb3855e0SWojciech Macek #ifdef SMP 273fb3855e0SWojciech Macek static int 274fb3855e0SWojciech Macek powernv_smp_start_cpu(platform_t plat, struct pcpu *pc) 275fb3855e0SWojciech Macek { 276*01d7bda7SWojciech Macek int result; 277fb3855e0SWojciech Macek 278fb3855e0SWojciech Macek ap_pcpu = pc; 279fb3855e0SWojciech Macek powerpc_sync(); 280fb3855e0SWojciech Macek 281fb3855e0SWojciech Macek result = opal_call(OPAL_START_CPU, pc->pc_cpuid, EXC_RST); 282*01d7bda7SWojciech Macek if (result != OPAL_SUCCESS) { 283*01d7bda7SWojciech Macek printf("OPAL error (%d): unable to start AP %d\n", 284*01d7bda7SWojciech Macek result, pc->pc_cpuid); 285fb3855e0SWojciech Macek return (ENXIO); 286fb3855e0SWojciech Macek } 287fb3855e0SWojciech Macek 288*01d7bda7SWojciech Macek return (0); 289fb3855e0SWojciech Macek } 290fb3855e0SWojciech Macek 291fb3855e0SWojciech Macek static struct cpu_group * 292fb3855e0SWojciech Macek powernv_smp_topo(platform_t plat) 293fb3855e0SWojciech Macek { 294fb3855e0SWojciech Macek struct pcpu *pc, *last_pc; 295fb3855e0SWojciech Macek int i, ncores, ncpus; 296fb3855e0SWojciech Macek 297fb3855e0SWojciech Macek ncores = ncpus = 0; 298fb3855e0SWojciech Macek last_pc = NULL; 299fb3855e0SWojciech Macek for (i = 0; i <= mp_maxid; i++) { 300fb3855e0SWojciech Macek pc = pcpu_find(i); 301fb3855e0SWojciech Macek if (pc == NULL) 302fb3855e0SWojciech Macek continue; 303fb3855e0SWojciech Macek if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref) 304fb3855e0SWojciech Macek ncores++; 305fb3855e0SWojciech Macek last_pc = pc; 306fb3855e0SWojciech Macek ncpus++; 307fb3855e0SWojciech Macek } 308fb3855e0SWojciech Macek 309fb3855e0SWojciech Macek if (ncpus % ncores != 0) { 310fb3855e0SWojciech Macek printf("WARNING: Irregular SMP topology. Performance may be " 311fb3855e0SWojciech Macek "suboptimal (%d CPUS, %d cores)\n", ncpus, ncores); 312fb3855e0SWojciech Macek return (smp_topo_none()); 313fb3855e0SWojciech Macek } 314fb3855e0SWojciech Macek 315fb3855e0SWojciech Macek /* Don't do anything fancier for non-threaded SMP */ 316fb3855e0SWojciech Macek if (ncpus == ncores) 317fb3855e0SWojciech Macek return (smp_topo_none()); 318fb3855e0SWojciech Macek 319fb3855e0SWojciech Macek return (smp_topo_1level(CG_SHARE_L1, ncpus / ncores, CG_FLAG_SMT)); 320fb3855e0SWojciech Macek } 321fb3855e0SWojciech Macek #endif 322fb3855e0SWojciech Macek 323fb3855e0SWojciech Macek static void 324fb3855e0SWojciech Macek powernv_reset(platform_t platform) 325fb3855e0SWojciech Macek { 32632d1354aSWojciech Macek 32732d1354aSWojciech Macek opal_call(OPAL_CEC_REBOOT); 328fb3855e0SWojciech Macek } 329fb3855e0SWojciech Macek 330fb3855e0SWojciech Macek static void 331fb3855e0SWojciech Macek powernv_smp_ap_init(platform_t platform) 332fb3855e0SWojciech Macek { 333fb3855e0SWojciech Macek } 334fb3855e0SWojciech Macek 335*01d7bda7SWojciech Macek static void 336*01d7bda7SWojciech Macek powernv_cpu_idle(sbintime_t sbt) 337*01d7bda7SWojciech Macek { 338*01d7bda7SWojciech Macek } 339