xref: /freebsd/sys/powerpc/pseries/platform_chrp.c (revision e21d69e9a781e4a525ceaef02e8888a6f097dddd)
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>
37*e21d69e9SNathan Whitehorn #include <sys/sched.h>
387a8d25c0SNathan Whitehorn #include <sys/smp.h>
397a8d25c0SNathan Whitehorn #include <vm/vm.h>
407a8d25c0SNathan Whitehorn #include <vm/pmap.h>
417a8d25c0SNathan Whitehorn 
427a8d25c0SNathan Whitehorn #include <machine/bus.h>
437a8d25c0SNathan Whitehorn #include <machine/cpu.h>
447a8d25c0SNathan Whitehorn #include <machine/hid.h>
457a8d25c0SNathan Whitehorn #include <machine/platformvar.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__
61f1e48417SNathan Whitehorn static uint8_t splpar_vpa[MAXCPU][640] __aligned(128); /* XXX: dpcpu */
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);
68c1cb22d7SNathan Whitehorn void chrp_mem_regions(platform_t, struct mem_region *phys, int *physsz,
69c1cb22d7SNathan 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 {
12766fe9464SBjoern A. Zeeb #ifdef __powerpc64__
128f1e48417SNathan Whitehorn 	int i;
129f1e48417SNathan Whitehorn 
1307a8d25c0SNathan Whitehorn 	/* XXX: check for /rtas/ibm,hypertas-functions? */
1317a8d25c0SNathan Whitehorn 	if (!(mfmsr() & PSL_HV)) {
1327a8d25c0SNathan Whitehorn 		struct mem_region *phys, *avail;
1337a8d25c0SNathan Whitehorn 		int nphys, navail;
1347a8d25c0SNathan Whitehorn 		mem_regions(&phys, &nphys, &avail, &navail);
1357a8d25c0SNathan Whitehorn 		realmaxaddr = phys[0].mr_size;
1367a8d25c0SNathan Whitehorn 
1377a8d25c0SNathan Whitehorn 		pmap_mmu_install("mmu_phyp", BUS_PROBE_SPECIFIC);
1387a8d25c0SNathan Whitehorn 		cpu_idle_hook = phyp_cpu_idle;
1397a8d25c0SNathan Whitehorn 
1407a8d25c0SNathan Whitehorn 		/* Set up important VPA fields */
141f1e48417SNathan Whitehorn 		for (i = 0; i < MAXCPU; i++) {
142f1e48417SNathan Whitehorn 			bzero(splpar_vpa[i], sizeof(splpar_vpa));
143f1e48417SNathan Whitehorn 			/* First two: VPA size */
144f1e48417SNathan Whitehorn 			splpar_vpa[i][4] =
145f1e48417SNathan Whitehorn 			    (uint8_t)((sizeof(splpar_vpa[i]) >> 8) & 0xff);
146f1e48417SNathan Whitehorn 			splpar_vpa[i][5] =
147f1e48417SNathan Whitehorn 			    (uint8_t)(sizeof(splpar_vpa[i]) & 0xff);
148f1e48417SNathan Whitehorn 			splpar_vpa[i][0xba] = 1;	/* Maintain FPRs */
149f1e48417SNathan Whitehorn 			splpar_vpa[i][0xbb] = 1;	/* Maintain PMCs */
150f1e48417SNathan Whitehorn 			splpar_vpa[i][0xfc] = 0xff;	/* Maintain full SLB */
151f1e48417SNathan Whitehorn 			splpar_vpa[i][0xfd] = 0xff;
152f1e48417SNathan Whitehorn 			splpar_vpa[i][0xff] = 1;	/* Maintain Altivec */
153f1e48417SNathan Whitehorn 		}
1547a8d25c0SNathan Whitehorn 		mb();
1557a8d25c0SNathan Whitehorn 
1567a8d25c0SNathan Whitehorn 		/* Set up hypervisor CPU stuff */
1577a8d25c0SNathan Whitehorn 		chrp_smp_ap_init(plat);
1587a8d25c0SNathan Whitehorn 	}
1597a8d25c0SNathan Whitehorn #endif
1607a8d25c0SNathan Whitehorn 
1619f706727SNathan Whitehorn 	/* Some systems (e.g. QEMU) need Open Firmware to stand down */
1629f706727SNathan Whitehorn 	ofw_quiesce();
1639f706727SNathan Whitehorn 
1647a8d25c0SNathan Whitehorn 	return (0);
1657a8d25c0SNathan Whitehorn }
1667a8d25c0SNathan Whitehorn 
167c1cb22d7SNathan Whitehorn static int
168f5dfbe2fSAndreas Tobler parse_drconf_memory(struct mem_region *ofmem, int *msz,
169f5dfbe2fSAndreas Tobler 		    struct mem_region *ofavail, int *asz)
1707a8d25c0SNathan Whitehorn {
171c1cb22d7SNathan Whitehorn 	phandle_t phandle;
172c1cb22d7SNathan Whitehorn 	vm_offset_t base;
173c1cb22d7SNathan Whitehorn 	int i, idx, len, lasz, lmsz, res;
174f5dfbe2fSAndreas Tobler 	uint32_t flags, lmb_size[2];
175509142e1SNathan Whitehorn 	uint32_t *dmem;
176c1cb22d7SNathan Whitehorn 
177c1cb22d7SNathan Whitehorn 	lmsz = *msz;
178c1cb22d7SNathan Whitehorn 	lasz = *asz;
179c1cb22d7SNathan Whitehorn 
180c1cb22d7SNathan Whitehorn 	phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory");
181c1cb22d7SNathan Whitehorn 	if (phandle == -1)
182c1cb22d7SNathan Whitehorn 		/* No drconf node, return. */
183c1cb22d7SNathan Whitehorn 		return (0);
184c1cb22d7SNathan Whitehorn 
185509142e1SNathan Whitehorn 	res = OF_getencprop(phandle, "ibm,lmb-size", lmb_size,
186509142e1SNathan Whitehorn 	    sizeof(lmb_size));
187c1cb22d7SNathan Whitehorn 	if (res == -1)
188c1cb22d7SNathan Whitehorn 		return (0);
189c1cb22d7SNathan Whitehorn 	printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20);
190c1cb22d7SNathan Whitehorn 
191c1cb22d7SNathan Whitehorn 	/* Parse the /ibm,dynamic-memory.
192c1cb22d7SNathan Whitehorn 	   The first position gives the # of entries. The next two words
193c1cb22d7SNathan Whitehorn  	   reflect the address of the memory block. The next four words are
194c1cb22d7SNathan Whitehorn 	   the DRC index, reserved, list index and flags.
195c1cb22d7SNathan Whitehorn 	   (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory)
196c1cb22d7SNathan Whitehorn 
197c1cb22d7SNathan Whitehorn 	    #el  Addr   DRC-idx  res   list-idx  flags
198c1cb22d7SNathan Whitehorn 	   -------------------------------------------------
199c1cb22d7SNathan Whitehorn 	   | 4 |   8   |   4   |   4   |   4   |   4   |....
200c1cb22d7SNathan Whitehorn 	   -------------------------------------------------
201c1cb22d7SNathan Whitehorn 	*/
202c1cb22d7SNathan Whitehorn 
203c1cb22d7SNathan Whitehorn 	len = OF_getproplen(phandle, "ibm,dynamic-memory");
204c1cb22d7SNathan Whitehorn 	if (len > 0) {
205c1cb22d7SNathan Whitehorn 
206c1cb22d7SNathan Whitehorn 		/* We have to use a variable length array on the stack
207c1cb22d7SNathan Whitehorn 		   since we have very limited stack space.
208c1cb22d7SNathan Whitehorn 		*/
209c1cb22d7SNathan Whitehorn 		cell_t arr[len/sizeof(cell_t)];
210c1cb22d7SNathan Whitehorn 
211509142e1SNathan Whitehorn 		res = OF_getencprop(phandle, "ibm,dynamic-memory", arr,
212c1cb22d7SNathan Whitehorn 		    sizeof(arr));
213c1cb22d7SNathan Whitehorn 		if (res == -1)
214c1cb22d7SNathan Whitehorn 			return (0);
215c1cb22d7SNathan Whitehorn 
216c1cb22d7SNathan Whitehorn 		/* Number of elements */
217c1cb22d7SNathan Whitehorn 		idx = arr[0];
218c1cb22d7SNathan Whitehorn 
219f5dfbe2fSAndreas Tobler 		/* First address, in arr[1], arr[2]*/
220509142e1SNathan Whitehorn 		dmem = &arr[1];
221c1cb22d7SNathan Whitehorn 
222c1cb22d7SNathan Whitehorn 		for (i = 0; i < idx; i++) {
223509142e1SNathan Whitehorn 			base = ((uint64_t)dmem[0] << 32) + dmem[1];
224509142e1SNathan Whitehorn 			dmem += 4;
225509142e1SNathan Whitehorn 			flags = dmem[1];
226c1cb22d7SNathan Whitehorn 			/* Use region only if available and not reserved. */
227c1cb22d7SNathan Whitehorn 			if ((flags & 0x8) && !(flags & 0x80)) {
228c1cb22d7SNathan Whitehorn 				ofmem[lmsz].mr_start = base;
229c1cb22d7SNathan Whitehorn 				ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1];
230c1cb22d7SNathan Whitehorn 				ofavail[lasz].mr_start = base;
231c1cb22d7SNathan Whitehorn 				ofavail[lasz].mr_size = (vm_size_t)lmb_size[1];
232c1cb22d7SNathan Whitehorn 				lmsz++;
233c1cb22d7SNathan Whitehorn 				lasz++;
234c1cb22d7SNathan Whitehorn 			}
235509142e1SNathan Whitehorn 			dmem += 2;
236c1cb22d7SNathan Whitehorn 		}
237c1cb22d7SNathan Whitehorn 	}
238c1cb22d7SNathan Whitehorn 
239c1cb22d7SNathan Whitehorn 	*msz = lmsz;
240c1cb22d7SNathan Whitehorn 	*asz = lasz;
241c1cb22d7SNathan Whitehorn 
242c1cb22d7SNathan Whitehorn 	return (1);
243c1cb22d7SNathan Whitehorn }
244c1cb22d7SNathan Whitehorn 
245c1cb22d7SNathan Whitehorn void
246c1cb22d7SNathan Whitehorn chrp_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
247c1cb22d7SNathan Whitehorn     struct mem_region *avail, int *availsz)
248c1cb22d7SNathan Whitehorn {
249c1cb22d7SNathan Whitehorn 	vm_offset_t maxphysaddr;
250c1cb22d7SNathan Whitehorn 	int i;
251c1cb22d7SNathan Whitehorn 
2527a8d25c0SNathan Whitehorn 	ofw_mem_regions(phys, physsz, avail, availsz);
253f5dfbe2fSAndreas Tobler 	parse_drconf_memory(phys, physsz, avail, availsz);
254c1cb22d7SNathan Whitehorn 
255c1cb22d7SNathan Whitehorn 	/*
256c1cb22d7SNathan Whitehorn 	 * On some firmwares (SLOF), some memory may be marked available that
257c1cb22d7SNathan Whitehorn 	 * doesn't actually exist. This manifests as an extension of the last
258c1cb22d7SNathan Whitehorn 	 * available segment past the end of physical memory, so truncate that
259c1cb22d7SNathan Whitehorn 	 * one.
260c1cb22d7SNathan Whitehorn 	 */
261c1cb22d7SNathan Whitehorn 	maxphysaddr = 0;
262c1cb22d7SNathan Whitehorn 	for (i = 0; i < *physsz; i++)
263c1cb22d7SNathan Whitehorn 		if (phys[i].mr_start + phys[i].mr_size > maxphysaddr)
264c1cb22d7SNathan Whitehorn 			maxphysaddr = phys[i].mr_start + phys[i].mr_size;
265c1cb22d7SNathan Whitehorn 
266c1cb22d7SNathan Whitehorn 	for (i = 0; i < *availsz; i++)
267c1cb22d7SNathan Whitehorn 		if (avail[i].mr_start + avail[i].mr_size > maxphysaddr)
268c1cb22d7SNathan Whitehorn 			avail[i].mr_size = maxphysaddr - avail[i].mr_start;
2697a8d25c0SNathan Whitehorn }
2707a8d25c0SNathan Whitehorn 
2717a8d25c0SNathan Whitehorn static vm_offset_t
2727a8d25c0SNathan Whitehorn chrp_real_maxaddr(platform_t plat)
2737a8d25c0SNathan Whitehorn {
2747a8d25c0SNathan Whitehorn 	return (realmaxaddr);
2757a8d25c0SNathan Whitehorn }
2767a8d25c0SNathan Whitehorn 
2777a8d25c0SNathan Whitehorn static u_long
2787a8d25c0SNathan Whitehorn chrp_timebase_freq(platform_t plat, struct cpuref *cpuref)
2797a8d25c0SNathan Whitehorn {
2807a8d25c0SNathan Whitehorn 	phandle_t phandle;
2817a8d25c0SNathan Whitehorn 	int32_t ticks = -1;
2827a8d25c0SNathan Whitehorn 
2837a8d25c0SNathan Whitehorn 	phandle = cpuref->cr_hwref;
2847a8d25c0SNathan Whitehorn 
285509142e1SNathan Whitehorn 	OF_getencprop(phandle, "timebase-frequency", &ticks, sizeof(ticks));
2867a8d25c0SNathan Whitehorn 
2877a8d25c0SNathan Whitehorn 	if (ticks <= 0)
2887a8d25c0SNathan Whitehorn 		panic("Unable to determine timebase frequency!");
2897a8d25c0SNathan Whitehorn 
2907a8d25c0SNathan Whitehorn 	return (ticks);
2917a8d25c0SNathan Whitehorn }
2927a8d25c0SNathan Whitehorn 
2937a8d25c0SNathan Whitehorn static int
2947a8d25c0SNathan Whitehorn chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
2957a8d25c0SNathan Whitehorn {
2967a8d25c0SNathan Whitehorn 	char buf[8];
2977a8d25c0SNathan Whitehorn 	phandle_t cpu, dev, root;
2987a8d25c0SNathan Whitehorn 	int res, cpuid;
2997a8d25c0SNathan Whitehorn 
3007a8d25c0SNathan Whitehorn 	root = OF_peer(0);
3017a8d25c0SNathan Whitehorn 
3027a8d25c0SNathan Whitehorn 	dev = OF_child(root);
3037a8d25c0SNathan Whitehorn 	while (dev != 0) {
3047a8d25c0SNathan Whitehorn 		res = OF_getprop(dev, "name", buf, sizeof(buf));
3057a8d25c0SNathan Whitehorn 		if (res > 0 && strcmp(buf, "cpus") == 0)
3067a8d25c0SNathan Whitehorn 			break;
3077a8d25c0SNathan Whitehorn 		dev = OF_peer(dev);
3087a8d25c0SNathan Whitehorn 	}
3097a8d25c0SNathan Whitehorn 	if (dev == 0) {
3107a8d25c0SNathan Whitehorn 		/*
3117a8d25c0SNathan Whitehorn 		 * psim doesn't have a name property on the /cpus node,
3127a8d25c0SNathan Whitehorn 		 * but it can be found directly
3137a8d25c0SNathan Whitehorn 		 */
3147a8d25c0SNathan Whitehorn 		dev = OF_finddevice("/cpus");
3157a8d25c0SNathan Whitehorn 		if (dev == 0)
3167a8d25c0SNathan Whitehorn 			return (ENOENT);
3177a8d25c0SNathan Whitehorn 	}
3187a8d25c0SNathan Whitehorn 
3197a8d25c0SNathan Whitehorn 	cpu = OF_child(dev);
3207a8d25c0SNathan Whitehorn 
3217a8d25c0SNathan Whitehorn 	while (cpu != 0) {
3227a8d25c0SNathan Whitehorn 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
3237a8d25c0SNathan Whitehorn 		if (res > 0 && strcmp(buf, "cpu") == 0)
3247a8d25c0SNathan Whitehorn 			break;
3257a8d25c0SNathan Whitehorn 		cpu = OF_peer(cpu);
3267a8d25c0SNathan Whitehorn 	}
3277a8d25c0SNathan Whitehorn 	if (cpu == 0)
3287a8d25c0SNathan Whitehorn 		return (ENOENT);
3297a8d25c0SNathan Whitehorn 
3307a8d25c0SNathan Whitehorn 	cpuref->cr_hwref = cpu;
331509142e1SNathan Whitehorn 	res = OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid,
3327a8d25c0SNathan Whitehorn 	    sizeof(cpuid));
3337a8d25c0SNathan Whitehorn 	if (res <= 0)
334509142e1SNathan Whitehorn 		res = OF_getencprop(cpu, "reg", &cpuid, sizeof(cpuid));
3357a8d25c0SNathan Whitehorn 	if (res <= 0)
3367a8d25c0SNathan Whitehorn 		cpuid = 0;
3377a8d25c0SNathan Whitehorn 	cpuref->cr_cpuid = cpuid;
3387a8d25c0SNathan Whitehorn 
3397a8d25c0SNathan Whitehorn 	return (0);
3407a8d25c0SNathan Whitehorn }
3417a8d25c0SNathan Whitehorn 
3427a8d25c0SNathan Whitehorn static int
3437a8d25c0SNathan Whitehorn chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
3447a8d25c0SNathan Whitehorn {
3457a8d25c0SNathan Whitehorn 	char buf[8];
3467a8d25c0SNathan Whitehorn 	phandle_t cpu;
3477a8d25c0SNathan Whitehorn 	int i, res, cpuid;
3487a8d25c0SNathan Whitehorn 
3497a8d25c0SNathan Whitehorn 	/* Check for whether it should be the next thread */
3507a8d25c0SNathan Whitehorn 	res = OF_getproplen(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s");
3517a8d25c0SNathan Whitehorn 	if (res > 0) {
3527a8d25c0SNathan Whitehorn 		cell_t interrupt_servers[res/sizeof(cell_t)];
353509142e1SNathan Whitehorn 		OF_getencprop(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s",
3547a8d25c0SNathan Whitehorn 		    interrupt_servers, res);
3557a8d25c0SNathan Whitehorn 		for (i = 0; i < res/sizeof(cell_t) - 1; i++) {
3567a8d25c0SNathan Whitehorn 			if (interrupt_servers[i] == cpuref->cr_cpuid) {
3577a8d25c0SNathan Whitehorn 				cpuref->cr_cpuid = interrupt_servers[i+1];
3587a8d25c0SNathan Whitehorn 				return (0);
3597a8d25c0SNathan Whitehorn 			}
3607a8d25c0SNathan Whitehorn 		}
3617a8d25c0SNathan Whitehorn 	}
3627a8d25c0SNathan Whitehorn 
3637a8d25c0SNathan Whitehorn 	/* Next CPU core/package */
3647a8d25c0SNathan Whitehorn 	cpu = OF_peer(cpuref->cr_hwref);
3657a8d25c0SNathan Whitehorn 	while (cpu != 0) {
3667a8d25c0SNathan Whitehorn 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
3677a8d25c0SNathan Whitehorn 		if (res > 0 && strcmp(buf, "cpu") == 0)
3687a8d25c0SNathan Whitehorn 			break;
3697a8d25c0SNathan Whitehorn 		cpu = OF_peer(cpu);
3707a8d25c0SNathan Whitehorn 	}
3717a8d25c0SNathan Whitehorn 	if (cpu == 0)
3727a8d25c0SNathan Whitehorn 		return (ENOENT);
3737a8d25c0SNathan Whitehorn 
3747a8d25c0SNathan Whitehorn 	cpuref->cr_hwref = cpu;
375509142e1SNathan Whitehorn 	res = OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid,
3767a8d25c0SNathan Whitehorn 	    sizeof(cpuid));
3777a8d25c0SNathan Whitehorn 	if (res <= 0)
378509142e1SNathan Whitehorn 		res = OF_getencprop(cpu, "reg", &cpuid, sizeof(cpuid));
3797a8d25c0SNathan Whitehorn 	if (res <= 0)
3807a8d25c0SNathan Whitehorn 		cpuid = 0;
3817a8d25c0SNathan Whitehorn 	cpuref->cr_cpuid = cpuid;
3827a8d25c0SNathan Whitehorn 
3837a8d25c0SNathan Whitehorn 	return (0);
3847a8d25c0SNathan Whitehorn }
3857a8d25c0SNathan Whitehorn 
3867a8d25c0SNathan Whitehorn static int
3877a8d25c0SNathan Whitehorn chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
3887a8d25c0SNathan Whitehorn {
3897a8d25c0SNathan Whitehorn 	ihandle_t inst;
3907a8d25c0SNathan Whitehorn 	phandle_t bsp, chosen;
3917a8d25c0SNathan Whitehorn 	int res, cpuid;
3927a8d25c0SNathan Whitehorn 
3937a8d25c0SNathan Whitehorn 	chosen = OF_finddevice("/chosen");
3947a8d25c0SNathan Whitehorn 	if (chosen == 0)
3957a8d25c0SNathan Whitehorn 		return (ENXIO);
3967a8d25c0SNathan Whitehorn 
397509142e1SNathan Whitehorn 	res = OF_getencprop(chosen, "cpu", &inst, sizeof(inst));
3987a8d25c0SNathan Whitehorn 	if (res < 0)
3997a8d25c0SNathan Whitehorn 		return (ENXIO);
4007a8d25c0SNathan Whitehorn 
4017a8d25c0SNathan Whitehorn 	bsp = OF_instance_to_package(inst);
4027a8d25c0SNathan Whitehorn 
4037a8d25c0SNathan Whitehorn 	/* Pick the primary thread. Can it be any other? */
4047a8d25c0SNathan Whitehorn 	cpuref->cr_hwref = bsp;
405509142e1SNathan Whitehorn 	res = OF_getencprop(bsp, "ibm,ppc-interrupt-server#s", &cpuid,
4067a8d25c0SNathan Whitehorn 	    sizeof(cpuid));
4077a8d25c0SNathan Whitehorn 	if (res <= 0)
408509142e1SNathan Whitehorn 		res = OF_getencprop(bsp, "reg", &cpuid, sizeof(cpuid));
4097a8d25c0SNathan Whitehorn 	if (res <= 0)
4107a8d25c0SNathan Whitehorn 		cpuid = 0;
4117a8d25c0SNathan Whitehorn 	cpuref->cr_cpuid = cpuid;
4127a8d25c0SNathan Whitehorn 
4137a8d25c0SNathan Whitehorn 	return (0);
4147a8d25c0SNathan Whitehorn }
4157a8d25c0SNathan Whitehorn 
4167a8d25c0SNathan Whitehorn #ifdef SMP
4177a8d25c0SNathan Whitehorn static int
4187a8d25c0SNathan Whitehorn chrp_smp_start_cpu(platform_t plat, struct pcpu *pc)
4197a8d25c0SNathan Whitehorn {
4207a8d25c0SNathan Whitehorn 	cell_t start_cpu;
4217a8d25c0SNathan Whitehorn 	int result, err, timeout;
4227a8d25c0SNathan Whitehorn 
4237a8d25c0SNathan Whitehorn 	if (!rtas_exists()) {
4247a8d25c0SNathan Whitehorn 		printf("RTAS uninitialized: unable to start AP %d\n",
4257a8d25c0SNathan Whitehorn 		    pc->pc_cpuid);
4267a8d25c0SNathan Whitehorn 		return (ENXIO);
4277a8d25c0SNathan Whitehorn 	}
4287a8d25c0SNathan Whitehorn 
4297a8d25c0SNathan Whitehorn 	start_cpu = rtas_token_lookup("start-cpu");
4307a8d25c0SNathan Whitehorn 	if (start_cpu == -1) {
4317a8d25c0SNathan Whitehorn 		printf("RTAS unknown method: unable to start AP %d\n",
4327a8d25c0SNathan Whitehorn 		    pc->pc_cpuid);
4337a8d25c0SNathan Whitehorn 		return (ENXIO);
4347a8d25c0SNathan Whitehorn 	}
4357a8d25c0SNathan Whitehorn 
4367a8d25c0SNathan Whitehorn 	ap_pcpu = pc;
4377a8d25c0SNathan Whitehorn 	powerpc_sync();
4387a8d25c0SNathan Whitehorn 
4397a8d25c0SNathan Whitehorn 	result = rtas_call_method(start_cpu, 3, 1, pc->pc_cpuid, EXC_RST, pc,
4407a8d25c0SNathan Whitehorn 	    &err);
4417a8d25c0SNathan Whitehorn 	if (result < 0 || err != 0) {
4427a8d25c0SNathan Whitehorn 		printf("RTAS error (%d/%d): unable to start AP %d\n",
4437a8d25c0SNathan Whitehorn 		    result, err, pc->pc_cpuid);
4447a8d25c0SNathan Whitehorn 		return (ENXIO);
4457a8d25c0SNathan Whitehorn 	}
4467a8d25c0SNathan Whitehorn 
4477a8d25c0SNathan Whitehorn 	timeout = 10000;
4487a8d25c0SNathan Whitehorn 	while (!pc->pc_awake && timeout--)
4497a8d25c0SNathan Whitehorn 		DELAY(100);
4507a8d25c0SNathan Whitehorn 
4517a8d25c0SNathan Whitehorn 	return ((pc->pc_awake) ? 0 : EBUSY);
4527a8d25c0SNathan Whitehorn }
4537a8d25c0SNathan Whitehorn 
4547a8d25c0SNathan Whitehorn static struct cpu_group *
4557a8d25c0SNathan Whitehorn chrp_smp_topo(platform_t plat)
4567a8d25c0SNathan Whitehorn {
4577a8d25c0SNathan Whitehorn 	struct pcpu *pc, *last_pc;
4587a8d25c0SNathan Whitehorn 	int i, ncores, ncpus;
4597a8d25c0SNathan Whitehorn 
4607a8d25c0SNathan Whitehorn 	ncores = ncpus = 0;
4617a8d25c0SNathan Whitehorn 	last_pc = NULL;
4627a8d25c0SNathan Whitehorn 	for (i = 0; i <= mp_maxid; i++) {
4637a8d25c0SNathan Whitehorn 		pc = pcpu_find(i);
4647a8d25c0SNathan Whitehorn 		if (pc == NULL)
4657a8d25c0SNathan Whitehorn 			continue;
4667a8d25c0SNathan Whitehorn 		if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref)
4677a8d25c0SNathan Whitehorn 			ncores++;
4687a8d25c0SNathan Whitehorn 		last_pc = pc;
4697a8d25c0SNathan Whitehorn 		ncpus++;
4707a8d25c0SNathan Whitehorn 	}
4717a8d25c0SNathan Whitehorn 
4727a8d25c0SNathan Whitehorn 	if (ncpus % ncores != 0) {
4737a8d25c0SNathan Whitehorn 		printf("WARNING: Irregular SMP topology. Performance may be "
4747a8d25c0SNathan Whitehorn 		     "suboptimal (%d CPUS, %d cores)\n", ncpus, ncores);
4757a8d25c0SNathan Whitehorn 		return (smp_topo_none());
4767a8d25c0SNathan Whitehorn 	}
4777a8d25c0SNathan Whitehorn 
4787a8d25c0SNathan Whitehorn 	/* Don't do anything fancier for non-threaded SMP */
4797a8d25c0SNathan Whitehorn 	if (ncpus == ncores)
4807a8d25c0SNathan Whitehorn 		return (smp_topo_none());
4817a8d25c0SNathan Whitehorn 
4827a8d25c0SNathan Whitehorn 	return (smp_topo_1level(CG_SHARE_L1, ncpus / ncores, CG_FLAG_SMT));
4837a8d25c0SNathan Whitehorn }
4847a8d25c0SNathan Whitehorn #endif
4857a8d25c0SNathan Whitehorn 
4867a8d25c0SNathan Whitehorn static void
4877a8d25c0SNathan Whitehorn chrp_reset(platform_t platform)
4887a8d25c0SNathan Whitehorn {
4897a8d25c0SNathan Whitehorn 	OF_reboot();
4907a8d25c0SNathan Whitehorn }
4917a8d25c0SNathan Whitehorn 
4927a8d25c0SNathan Whitehorn #ifdef __powerpc64__
4937a8d25c0SNathan Whitehorn static void
4947a8d25c0SNathan Whitehorn phyp_cpu_idle(sbintime_t sbt)
4957a8d25c0SNathan Whitehorn {
496*e21d69e9SNathan Whitehorn 	register_t msr;
497*e21d69e9SNathan Whitehorn 
498*e21d69e9SNathan Whitehorn 	msr = mfmsr();
499*e21d69e9SNathan Whitehorn 
500*e21d69e9SNathan Whitehorn 	mtmsr(msr & ~PSL_EE);
501*e21d69e9SNathan Whitehorn 	if (sched_runnable()) {
502*e21d69e9SNathan Whitehorn 		mtmsr(msr);
503*e21d69e9SNathan Whitehorn 		return;
504*e21d69e9SNathan Whitehorn 	}
505*e21d69e9SNathan Whitehorn 
506*e21d69e9SNathan Whitehorn 	phyp_hcall(H_CEDE); /* Re-enables interrupts internally */
507*e21d69e9SNathan Whitehorn 	mtmsr(msr);
5087a8d25c0SNathan Whitehorn }
5097a8d25c0SNathan Whitehorn 
5107a8d25c0SNathan Whitehorn static void
5117a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform)
5127a8d25c0SNathan Whitehorn {
5137a8d25c0SNathan Whitehorn 	if (!(mfmsr() & PSL_HV)) {
514f1e48417SNathan Whitehorn 		/* Register VPA */
515f1e48417SNathan Whitehorn 		phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(cpuid),
516f1e48417SNathan Whitehorn 		    splpar_vpa[PCPU_GET(cpuid)]);
517f1e48417SNathan Whitehorn 
5187a8d25c0SNathan Whitehorn 		/* Set interrupt priority */
5197a8d25c0SNathan Whitehorn 		phyp_hcall(H_CPPR, 0xff);
5207a8d25c0SNathan Whitehorn 	}
5217a8d25c0SNathan Whitehorn }
5227a8d25c0SNathan Whitehorn #else
5237a8d25c0SNathan Whitehorn static void
5247a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform)
5257a8d25c0SNathan Whitehorn {
5267a8d25c0SNathan Whitehorn }
5277a8d25c0SNathan Whitehorn #endif
5287a8d25c0SNathan Whitehorn 
529