xref: /freebsd/sys/powerpc/pseries/platform_chrp.c (revision 35ef3951)
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 
33a6625592SBrandon Bergren #include <sys/endian.h>
347a8d25c0SNathan Whitehorn #include <sys/param.h>
357a8d25c0SNathan Whitehorn #include <sys/systm.h>
367a8d25c0SNathan Whitehorn #include <sys/kernel.h>
377a8d25c0SNathan Whitehorn #include <sys/bus.h>
387a8d25c0SNathan Whitehorn #include <sys/pcpu.h>
397a8d25c0SNathan Whitehorn #include <sys/proc.h>
40e21d69e9SNathan Whitehorn #include <sys/sched.h>
417a8d25c0SNathan Whitehorn #include <sys/smp.h>
427a8d25c0SNathan Whitehorn #include <vm/vm.h>
437a8d25c0SNathan Whitehorn #include <vm/pmap.h>
447a8d25c0SNathan Whitehorn 
457a8d25c0SNathan Whitehorn #include <machine/bus.h>
467a8d25c0SNathan Whitehorn #include <machine/cpu.h>
477a8d25c0SNathan Whitehorn #include <machine/hid.h>
487a8d25c0SNathan Whitehorn #include <machine/platformvar.h>
497a8d25c0SNathan Whitehorn #include <machine/rtas.h>
507a8d25c0SNathan Whitehorn #include <machine/smp.h>
517a8d25c0SNathan Whitehorn #include <machine/spr.h>
52258dbffeSNathan Whitehorn #include <machine/trap.h>
537a8d25c0SNathan Whitehorn 
547a8d25c0SNathan Whitehorn #include <dev/ofw/openfirm.h>
557a8d25c0SNathan Whitehorn #include <machine/ofw_machdep.h>
567a8d25c0SNathan Whitehorn 
577a8d25c0SNathan Whitehorn #include "platform_if.h"
587a8d25c0SNathan Whitehorn 
597a8d25c0SNathan Whitehorn #ifdef SMP
607a8d25c0SNathan Whitehorn extern void *ap_pcpu;
617a8d25c0SNathan Whitehorn #endif
627a8d25c0SNathan Whitehorn 
637a8d25c0SNathan Whitehorn #ifdef __powerpc64__
64f1e48417SNathan Whitehorn static uint8_t splpar_vpa[MAXCPU][640] __aligned(128); /* XXX: dpcpu */
657a8d25c0SNathan Whitehorn #endif
667a8d25c0SNathan Whitehorn 
677a8d25c0SNathan Whitehorn static vm_offset_t realmaxaddr = VM_MAX_ADDRESS;
687a8d25c0SNathan Whitehorn 
697a8d25c0SNathan Whitehorn static int chrp_probe(platform_t);
707a8d25c0SNathan Whitehorn static int chrp_attach(platform_t);
71c1cb22d7SNathan Whitehorn void chrp_mem_regions(platform_t, struct mem_region *phys, int *physsz,
72c1cb22d7SNathan Whitehorn     struct mem_region *avail, int *availsz);
737a8d25c0SNathan Whitehorn static vm_offset_t chrp_real_maxaddr(platform_t);
747a8d25c0SNathan Whitehorn static u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref);
757a8d25c0SNathan Whitehorn static int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref);
767a8d25c0SNathan Whitehorn static int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref);
777a8d25c0SNathan Whitehorn static int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref);
787a8d25c0SNathan Whitehorn static void chrp_smp_ap_init(platform_t);
79f0393bbfSWojciech Macek static int chrp_cpuref_init(void);
807a8d25c0SNathan Whitehorn #ifdef SMP
817a8d25c0SNathan Whitehorn static int chrp_smp_start_cpu(platform_t, struct pcpu *cpu);
82bba9cbe3SConrad Meyer static void chrp_smp_probe_threads(platform_t plat);
837a8d25c0SNathan Whitehorn static struct cpu_group *chrp_smp_topo(platform_t plat);
847a8d25c0SNathan Whitehorn #endif
857a8d25c0SNathan Whitehorn static void chrp_reset(platform_t);
867a8d25c0SNathan Whitehorn #ifdef __powerpc64__
877a8d25c0SNathan Whitehorn #include "phyp-hvcall.h"
887a8d25c0SNathan Whitehorn static void phyp_cpu_idle(sbintime_t sbt);
897a8d25c0SNathan Whitehorn #endif
907a8d25c0SNathan Whitehorn 
91f0393bbfSWojciech Macek static struct cpuref platform_cpuref[MAXCPU];
92f0393bbfSWojciech Macek static int platform_cpuref_cnt;
93f0393bbfSWojciech Macek static int platform_cpuref_valid;
94f0393bbfSWojciech Macek 
957a8d25c0SNathan Whitehorn static platform_method_t chrp_methods[] = {
967a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_probe, 		chrp_probe),
977a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_attach,		chrp_attach),
987a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_mem_regions,	chrp_mem_regions),
997a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_real_maxaddr,	chrp_real_maxaddr),
1007a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_timebase_freq,	chrp_timebase_freq),
1017a8d25c0SNathan Whitehorn 
1027a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_ap_init,	chrp_smp_ap_init),
1037a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_first_cpu,	chrp_smp_first_cpu),
1047a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_next_cpu,	chrp_smp_next_cpu),
1057a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_get_bsp,	chrp_smp_get_bsp),
1067a8d25c0SNathan Whitehorn #ifdef SMP
1077a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_start_cpu,	chrp_smp_start_cpu),
108bba9cbe3SConrad Meyer 	PLATFORMMETHOD(platform_smp_probe_threads,	chrp_smp_probe_threads),
1097a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_topo,	chrp_smp_topo),
1107a8d25c0SNathan Whitehorn #endif
1117a8d25c0SNathan Whitehorn 
1127a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_reset,		chrp_reset),
1137a8d25c0SNathan Whitehorn 	{ 0, 0 }
1147a8d25c0SNathan Whitehorn };
1157a8d25c0SNathan Whitehorn 
1167a8d25c0SNathan Whitehorn static platform_def_t chrp_platform = {
1177a8d25c0SNathan Whitehorn 	"chrp",
1187a8d25c0SNathan Whitehorn 	chrp_methods,
1197a8d25c0SNathan Whitehorn 	0
1207a8d25c0SNathan Whitehorn };
1217a8d25c0SNathan Whitehorn 
1227a8d25c0SNathan Whitehorn PLATFORM_DEF(chrp_platform);
1237a8d25c0SNathan Whitehorn 
1247a8d25c0SNathan Whitehorn static int
1257a8d25c0SNathan Whitehorn chrp_probe(platform_t plat)
1267a8d25c0SNathan Whitehorn {
1277a8d25c0SNathan Whitehorn 	if (OF_finddevice("/memory") != -1 || OF_finddevice("/memory@0") != -1)
1287a8d25c0SNathan Whitehorn 		return (BUS_PROBE_GENERIC);
1297a8d25c0SNathan Whitehorn 
1307a8d25c0SNathan Whitehorn 	return (ENXIO);
1317a8d25c0SNathan Whitehorn }
1327a8d25c0SNathan Whitehorn 
1337a8d25c0SNathan Whitehorn static int
1347a8d25c0SNathan Whitehorn chrp_attach(platform_t plat)
1357a8d25c0SNathan Whitehorn {
13635f29427SLeandro Lupori 	int quiesce;
13766fe9464SBjoern A. Zeeb #ifdef __powerpc64__
138f1e48417SNathan Whitehorn 	int i;
13935ef3951SBrandon Bergren #if BYTE_ORDER == LITTLE_ENDIAN
14035ef3951SBrandon Bergren 	int result;
14135ef3951SBrandon Bergren #endif
142f1e48417SNathan Whitehorn 
1437a8d25c0SNathan Whitehorn 	/* XXX: check for /rtas/ibm,hypertas-functions? */
1447a8d25c0SNathan Whitehorn 	if (!(mfmsr() & PSL_HV)) {
1457a8d25c0SNathan Whitehorn 		struct mem_region *phys, *avail;
1467a8d25c0SNathan Whitehorn 		int nphys, navail;
1478b55f9f8SLeandro Lupori 		vm_offset_t off;
1488b55f9f8SLeandro Lupori 
1497a8d25c0SNathan Whitehorn 		mem_regions(&phys, &nphys, &avail, &navail);
1508b55f9f8SLeandro Lupori 
1518b55f9f8SLeandro Lupori 		realmaxaddr = 0;
1528b55f9f8SLeandro Lupori 		for (i = 0; i < nphys; i++) {
1538b55f9f8SLeandro Lupori 			off = phys[i].mr_start + phys[i].mr_size;
1548b55f9f8SLeandro Lupori 			realmaxaddr = MAX(off, realmaxaddr);
1558b55f9f8SLeandro Lupori 		}
1567a8d25c0SNathan Whitehorn 
1577a8d25c0SNathan Whitehorn 		pmap_mmu_install("mmu_phyp", BUS_PROBE_SPECIFIC);
1587a8d25c0SNathan Whitehorn 		cpu_idle_hook = phyp_cpu_idle;
1597a8d25c0SNathan Whitehorn 
1607a8d25c0SNathan Whitehorn 		/* Set up important VPA fields */
161f1e48417SNathan Whitehorn 		for (i = 0; i < MAXCPU; i++) {
162f1e48417SNathan Whitehorn 			/* First two: VPA size */
163f1e48417SNathan Whitehorn 			splpar_vpa[i][4] =
164f1e48417SNathan Whitehorn 			    (uint8_t)((sizeof(splpar_vpa[i]) >> 8) & 0xff);
165f1e48417SNathan Whitehorn 			splpar_vpa[i][5] =
166f1e48417SNathan Whitehorn 			    (uint8_t)(sizeof(splpar_vpa[i]) & 0xff);
167f1e48417SNathan Whitehorn 			splpar_vpa[i][0xba] = 1;	/* Maintain FPRs */
168f1e48417SNathan Whitehorn 			splpar_vpa[i][0xbb] = 1;	/* Maintain PMCs */
169f1e48417SNathan Whitehorn 			splpar_vpa[i][0xfc] = 0xff;	/* Maintain full SLB */
170f1e48417SNathan Whitehorn 			splpar_vpa[i][0xfd] = 0xff;
171f1e48417SNathan Whitehorn 			splpar_vpa[i][0xff] = 1;	/* Maintain Altivec */
172f1e48417SNathan Whitehorn 		}
1737a8d25c0SNathan Whitehorn 		mb();
1747a8d25c0SNathan Whitehorn 
1757a8d25c0SNathan Whitehorn 		/* Set up hypervisor CPU stuff */
1767a8d25c0SNathan Whitehorn 		chrp_smp_ap_init(plat);
17735ef3951SBrandon Bergren 
17835ef3951SBrandon Bergren #if BYTE_ORDER == LITTLE_ENDIAN
17935ef3951SBrandon Bergren 		/*
18035ef3951SBrandon Bergren 		 * Ask the hypervisor to update the LPAR ILE bit.
18135ef3951SBrandon Bergren 		 *
18235ef3951SBrandon Bergren 		 * This involves all processors reentering the hypervisor
18335ef3951SBrandon Bergren 		 * so the change appears simultaneously in all processors.
18435ef3951SBrandon Bergren 		 * This can take a long time.
18535ef3951SBrandon Bergren 		 */
18635ef3951SBrandon Bergren 		for(;;) {
18735ef3951SBrandon Bergren 			result = phyp_hcall(H_SET_MODE, 1UL,
18835ef3951SBrandon Bergren 			    H_SET_MODE_RSRC_ILE, 0, 0);
18935ef3951SBrandon Bergren 			if (result == H_SUCCESS)
19035ef3951SBrandon Bergren 				break;
19135ef3951SBrandon Bergren 			DELAY(1000);
19235ef3951SBrandon Bergren 		}
19335ef3951SBrandon Bergren #endif
19435ef3951SBrandon Bergren 
1957a8d25c0SNathan Whitehorn 	}
1967a8d25c0SNathan Whitehorn #endif
197f0393bbfSWojciech Macek 	chrp_cpuref_init();
1987a8d25c0SNathan Whitehorn 
1999f706727SNathan Whitehorn 	/* Some systems (e.g. QEMU) need Open Firmware to stand down */
20035f29427SLeandro Lupori 	quiesce = 1;
20135f29427SLeandro Lupori 	TUNABLE_INT_FETCH("debug.quiesce_ofw", &quiesce);
20235f29427SLeandro Lupori 	if (quiesce)
2039f706727SNathan Whitehorn 		ofw_quiesce();
2049f706727SNathan Whitehorn 
2057a8d25c0SNathan Whitehorn 	return (0);
2067a8d25c0SNathan Whitehorn }
2077a8d25c0SNathan Whitehorn 
208c1cb22d7SNathan Whitehorn static int
209f5dfbe2fSAndreas Tobler parse_drconf_memory(struct mem_region *ofmem, int *msz,
210f5dfbe2fSAndreas Tobler 		    struct mem_region *ofavail, int *asz)
2117a8d25c0SNathan Whitehorn {
212c1cb22d7SNathan Whitehorn 	phandle_t phandle;
213c1cb22d7SNathan Whitehorn 	vm_offset_t base;
214c1cb22d7SNathan Whitehorn 	int i, idx, len, lasz, lmsz, res;
215f5dfbe2fSAndreas Tobler 	uint32_t flags, lmb_size[2];
216509142e1SNathan Whitehorn 	uint32_t *dmem;
217c1cb22d7SNathan Whitehorn 
218c1cb22d7SNathan Whitehorn 	lmsz = *msz;
219c1cb22d7SNathan Whitehorn 	lasz = *asz;
220c1cb22d7SNathan Whitehorn 
221c1cb22d7SNathan Whitehorn 	phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory");
222c1cb22d7SNathan Whitehorn 	if (phandle == -1)
223c1cb22d7SNathan Whitehorn 		/* No drconf node, return. */
224c1cb22d7SNathan Whitehorn 		return (0);
225c1cb22d7SNathan Whitehorn 
226509142e1SNathan Whitehorn 	res = OF_getencprop(phandle, "ibm,lmb-size", lmb_size,
227509142e1SNathan Whitehorn 	    sizeof(lmb_size));
228c1cb22d7SNathan Whitehorn 	if (res == -1)
229c1cb22d7SNathan Whitehorn 		return (0);
230c1cb22d7SNathan Whitehorn 	printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20);
231c1cb22d7SNathan Whitehorn 
232c1cb22d7SNathan Whitehorn 	/* Parse the /ibm,dynamic-memory.
233c1cb22d7SNathan Whitehorn 	   The first position gives the # of entries. The next two words
234c1cb22d7SNathan Whitehorn  	   reflect the address of the memory block. The next four words are
235c1cb22d7SNathan Whitehorn 	   the DRC index, reserved, list index and flags.
236c1cb22d7SNathan Whitehorn 	   (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory)
237c1cb22d7SNathan Whitehorn 
238c1cb22d7SNathan Whitehorn 	    #el  Addr   DRC-idx  res   list-idx  flags
239c1cb22d7SNathan Whitehorn 	   -------------------------------------------------
240c1cb22d7SNathan Whitehorn 	   | 4 |   8   |   4   |   4   |   4   |   4   |....
241c1cb22d7SNathan Whitehorn 	   -------------------------------------------------
242c1cb22d7SNathan Whitehorn 	*/
243c1cb22d7SNathan Whitehorn 
244c1cb22d7SNathan Whitehorn 	len = OF_getproplen(phandle, "ibm,dynamic-memory");
245c1cb22d7SNathan Whitehorn 	if (len > 0) {
246c1cb22d7SNathan Whitehorn 		/* We have to use a variable length array on the stack
247c1cb22d7SNathan Whitehorn 		   since we have very limited stack space.
248c1cb22d7SNathan Whitehorn 		*/
249c1cb22d7SNathan Whitehorn 		cell_t arr[len/sizeof(cell_t)];
250c1cb22d7SNathan Whitehorn 
251509142e1SNathan Whitehorn 		res = OF_getencprop(phandle, "ibm,dynamic-memory", arr,
252c1cb22d7SNathan Whitehorn 		    sizeof(arr));
253c1cb22d7SNathan Whitehorn 		if (res == -1)
254c1cb22d7SNathan Whitehorn 			return (0);
255c1cb22d7SNathan Whitehorn 
256c1cb22d7SNathan Whitehorn 		/* Number of elements */
257c1cb22d7SNathan Whitehorn 		idx = arr[0];
258c1cb22d7SNathan Whitehorn 
259f5dfbe2fSAndreas Tobler 		/* First address, in arr[1], arr[2]*/
260509142e1SNathan Whitehorn 		dmem = &arr[1];
261c1cb22d7SNathan Whitehorn 
262c1cb22d7SNathan Whitehorn 		for (i = 0; i < idx; i++) {
263509142e1SNathan Whitehorn 			base = ((uint64_t)dmem[0] << 32) + dmem[1];
264509142e1SNathan Whitehorn 			dmem += 4;
265509142e1SNathan Whitehorn 			flags = dmem[1];
266c1cb22d7SNathan Whitehorn 			/* Use region only if available and not reserved. */
267c1cb22d7SNathan Whitehorn 			if ((flags & 0x8) && !(flags & 0x80)) {
268c1cb22d7SNathan Whitehorn 				ofmem[lmsz].mr_start = base;
269c1cb22d7SNathan Whitehorn 				ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1];
270c1cb22d7SNathan Whitehorn 				ofavail[lasz].mr_start = base;
271c1cb22d7SNathan Whitehorn 				ofavail[lasz].mr_size = (vm_size_t)lmb_size[1];
272c1cb22d7SNathan Whitehorn 				lmsz++;
273c1cb22d7SNathan Whitehorn 				lasz++;
274c1cb22d7SNathan Whitehorn 			}
275509142e1SNathan Whitehorn 			dmem += 2;
276c1cb22d7SNathan Whitehorn 		}
277c1cb22d7SNathan Whitehorn 	}
278c1cb22d7SNathan Whitehorn 
279c1cb22d7SNathan Whitehorn 	*msz = lmsz;
280c1cb22d7SNathan Whitehorn 	*asz = lasz;
281c1cb22d7SNathan Whitehorn 
282c1cb22d7SNathan Whitehorn 	return (1);
283c1cb22d7SNathan Whitehorn }
284c1cb22d7SNathan Whitehorn 
285c1cb22d7SNathan Whitehorn void
286c1cb22d7SNathan Whitehorn chrp_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
287c1cb22d7SNathan Whitehorn     struct mem_region *avail, int *availsz)
288c1cb22d7SNathan Whitehorn {
289c1cb22d7SNathan Whitehorn 	vm_offset_t maxphysaddr;
290c1cb22d7SNathan Whitehorn 	int i;
291c1cb22d7SNathan Whitehorn 
2927a8d25c0SNathan Whitehorn 	ofw_mem_regions(phys, physsz, avail, availsz);
293f5dfbe2fSAndreas Tobler 	parse_drconf_memory(phys, physsz, avail, availsz);
294c1cb22d7SNathan Whitehorn 
295c1cb22d7SNathan Whitehorn 	/*
296c1cb22d7SNathan Whitehorn 	 * On some firmwares (SLOF), some memory may be marked available that
297c1cb22d7SNathan Whitehorn 	 * doesn't actually exist. This manifests as an extension of the last
298c1cb22d7SNathan Whitehorn 	 * available segment past the end of physical memory, so truncate that
299c1cb22d7SNathan Whitehorn 	 * one.
300c1cb22d7SNathan Whitehorn 	 */
301c1cb22d7SNathan Whitehorn 	maxphysaddr = 0;
302c1cb22d7SNathan Whitehorn 	for (i = 0; i < *physsz; i++)
303c1cb22d7SNathan Whitehorn 		if (phys[i].mr_start + phys[i].mr_size > maxphysaddr)
304c1cb22d7SNathan Whitehorn 			maxphysaddr = phys[i].mr_start + phys[i].mr_size;
305c1cb22d7SNathan Whitehorn 
306c1cb22d7SNathan Whitehorn 	for (i = 0; i < *availsz; i++)
307c1cb22d7SNathan Whitehorn 		if (avail[i].mr_start + avail[i].mr_size > maxphysaddr)
308c1cb22d7SNathan Whitehorn 			avail[i].mr_size = maxphysaddr - avail[i].mr_start;
3097a8d25c0SNathan Whitehorn }
3107a8d25c0SNathan Whitehorn 
3117a8d25c0SNathan Whitehorn static vm_offset_t
3127a8d25c0SNathan Whitehorn chrp_real_maxaddr(platform_t plat)
3137a8d25c0SNathan Whitehorn {
3147a8d25c0SNathan Whitehorn 	return (realmaxaddr);
3157a8d25c0SNathan Whitehorn }
3167a8d25c0SNathan Whitehorn 
3177a8d25c0SNathan Whitehorn static u_long
3187a8d25c0SNathan Whitehorn chrp_timebase_freq(platform_t plat, struct cpuref *cpuref)
3197a8d25c0SNathan Whitehorn {
320a00ce4e8SJustin Hibbits 	phandle_t cpus, cpunode;
3217a8d25c0SNathan Whitehorn 	int32_t ticks = -1;
322a00ce4e8SJustin Hibbits 	int res;
323a00ce4e8SJustin Hibbits 	char buf[8];
3247a8d25c0SNathan Whitehorn 
325a00ce4e8SJustin Hibbits 	cpus = OF_finddevice("/cpus");
326108117ccSOleksandr Tymoshenko 	if (cpus == -1)
327a00ce4e8SJustin Hibbits 		panic("CPU tree not found on Open Firmware\n");
3287a8d25c0SNathan Whitehorn 
329a00ce4e8SJustin Hibbits 	for (cpunode = OF_child(cpus); cpunode != 0; cpunode = OF_peer(cpunode)) {
330a00ce4e8SJustin Hibbits 		res = OF_getprop(cpunode, "device_type", buf, sizeof(buf));
331a00ce4e8SJustin Hibbits 		if (res > 0 && strcmp(buf, "cpu") == 0)
332a00ce4e8SJustin Hibbits 			break;
333a00ce4e8SJustin Hibbits 	}
334a00ce4e8SJustin Hibbits 	if (cpunode <= 0)
335a00ce4e8SJustin Hibbits 		panic("CPU node not found on Open Firmware\n");
336a00ce4e8SJustin Hibbits 
337a00ce4e8SJustin Hibbits 	OF_getencprop(cpunode, "timebase-frequency", &ticks, sizeof(ticks));
3387a8d25c0SNathan Whitehorn 
3397a8d25c0SNathan Whitehorn 	if (ticks <= 0)
3407a8d25c0SNathan Whitehorn 		panic("Unable to determine timebase frequency!");
3417a8d25c0SNathan Whitehorn 
3427a8d25c0SNathan Whitehorn 	return (ticks);
3437a8d25c0SNathan Whitehorn }
3447a8d25c0SNathan Whitehorn 
3457a8d25c0SNathan Whitehorn static int
34609f07b00SNathan Whitehorn chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
3477a8d25c0SNathan Whitehorn {
3487a8d25c0SNathan Whitehorn 
349f0393bbfSWojciech Macek 	if (platform_cpuref_valid == 0)
350f0393bbfSWojciech Macek 		return (EINVAL);
3517a8d25c0SNathan Whitehorn 
352f0393bbfSWojciech Macek 	cpuref->cr_cpuid = 0;
353f0393bbfSWojciech Macek 	cpuref->cr_hwref = platform_cpuref[0].cr_hwref;
3547a8d25c0SNathan Whitehorn 
3557a8d25c0SNathan Whitehorn 	return (0);
3567a8d25c0SNathan Whitehorn }
3577a8d25c0SNathan Whitehorn 
3587a8d25c0SNathan Whitehorn static int
3597a8d25c0SNathan Whitehorn chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
3607a8d25c0SNathan Whitehorn {
361f0393bbfSWojciech Macek 	int id;
3627a8d25c0SNathan Whitehorn 
363f0393bbfSWojciech Macek 	if (platform_cpuref_valid == 0)
364f0393bbfSWojciech Macek 		return (EINVAL);
3657a8d25c0SNathan Whitehorn 
366f0393bbfSWojciech Macek 	id = cpuref->cr_cpuid + 1;
367f0393bbfSWojciech Macek 	if (id >= platform_cpuref_cnt)
3687a8d25c0SNathan Whitehorn 		return (ENOENT);
36909f07b00SNathan Whitehorn 
370f0393bbfSWojciech Macek 	cpuref->cr_cpuid = platform_cpuref[id].cr_cpuid;
371f0393bbfSWojciech Macek 	cpuref->cr_hwref = platform_cpuref[id].cr_hwref;
37209f07b00SNathan Whitehorn 
37309f07b00SNathan Whitehorn 	return (0);
3747a8d25c0SNathan Whitehorn }
3757a8d25c0SNathan Whitehorn 
3767a8d25c0SNathan Whitehorn static int
3777a8d25c0SNathan Whitehorn chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
3787a8d25c0SNathan Whitehorn {
3797a8d25c0SNathan Whitehorn 
380f0393bbfSWojciech Macek 	cpuref->cr_cpuid = platform_cpuref[0].cr_cpuid;
381f0393bbfSWojciech Macek 	cpuref->cr_hwref = platform_cpuref[0].cr_hwref;
382f0393bbfSWojciech Macek 	return (0);
383f0393bbfSWojciech Macek }
3847a8d25c0SNathan Whitehorn 
385151c44e2SJustin Hibbits static void
386151c44e2SJustin Hibbits get_cpu_reg(phandle_t cpu, cell_t *reg)
387151c44e2SJustin Hibbits {
388151c44e2SJustin Hibbits 	int res;
389151c44e2SJustin Hibbits 
390151c44e2SJustin Hibbits 	res = OF_getproplen(cpu, "reg");
391151c44e2SJustin Hibbits 	if (res != sizeof(cell_t))
392151c44e2SJustin Hibbits 		panic("Unexpected length for CPU property reg on Open Firmware\n");
393151c44e2SJustin Hibbits 	OF_getencprop(cpu, "reg", reg, res);
394151c44e2SJustin Hibbits }
395151c44e2SJustin Hibbits 
396f0393bbfSWojciech Macek static int
397f0393bbfSWojciech Macek chrp_cpuref_init(void)
398f0393bbfSWojciech Macek {
399151c44e2SJustin Hibbits 	phandle_t cpu, dev, chosen, pbsp;
400151c44e2SJustin Hibbits 	ihandle_t ibsp;
401f0393bbfSWojciech Macek 	char buf[32];
402151c44e2SJustin Hibbits 	int a, bsp, res, res2, tmp_cpuref_cnt;
403151c44e2SJustin Hibbits 	static struct cpuref tmp_cpuref[MAXCPU];
404151c44e2SJustin Hibbits 	cell_t interrupt_servers[32], addr_cells, size_cells, reg, bsp_reg;
4057a8d25c0SNathan Whitehorn 
406f0393bbfSWojciech Macek 	if (platform_cpuref_valid)
407f0393bbfSWojciech Macek 		return (0);
4087a8d25c0SNathan Whitehorn 
409f0393bbfSWojciech Macek 	dev = OF_peer(0);
410f0393bbfSWojciech Macek 	dev = OF_child(dev);
411f0393bbfSWojciech Macek 	while (dev != 0) {
412f0393bbfSWojciech Macek 		res = OF_getprop(dev, "name", buf, sizeof(buf));
413f0393bbfSWojciech Macek 		if (res > 0 && strcmp(buf, "cpus") == 0)
414f0393bbfSWojciech Macek 			break;
415f0393bbfSWojciech Macek 		dev = OF_peer(dev);
416f0393bbfSWojciech Macek 	}
417f0393bbfSWojciech Macek 
418151c44e2SJustin Hibbits 	/* Make sure that cpus reg property have 1 address cell and 0 size cells */
419151c44e2SJustin Hibbits 	res = OF_getproplen(dev, "#address-cells");
420151c44e2SJustin Hibbits 	res2 = OF_getproplen(dev, "#size-cells");
421151c44e2SJustin Hibbits 	if (res != res2 || res != sizeof(cell_t))
422151c44e2SJustin Hibbits 		panic("CPU properties #address-cells and #size-cells not found on Open Firmware\n");
423151c44e2SJustin Hibbits 	OF_getencprop(dev, "#address-cells", &addr_cells, sizeof(addr_cells));
424151c44e2SJustin Hibbits 	OF_getencprop(dev, "#size-cells", &size_cells, sizeof(size_cells));
425151c44e2SJustin Hibbits 	if (addr_cells != 1 || size_cells != 0)
426151c44e2SJustin Hibbits 		panic("Unexpected values for CPU properties #address-cells and #size-cells on Open Firmware\n");
427151c44e2SJustin Hibbits 
428151c44e2SJustin Hibbits 	/* Look for boot CPU in /chosen/cpu and /chosen/fdtbootcpu */
429151c44e2SJustin Hibbits 
430151c44e2SJustin Hibbits 	chosen = OF_finddevice("/chosen");
431151c44e2SJustin Hibbits 	if (chosen == -1)
432151c44e2SJustin Hibbits 		panic("Device /chosen not found on Open Firmware\n");
433151c44e2SJustin Hibbits 
434151c44e2SJustin Hibbits 	bsp_reg = -1;
435151c44e2SJustin Hibbits 
436151c44e2SJustin Hibbits 	/* /chosen/cpu */
437151c44e2SJustin Hibbits 	if (OF_getproplen(chosen, "cpu") == sizeof(ihandle_t)) {
438151c44e2SJustin Hibbits 		OF_getprop(chosen, "cpu", &ibsp, sizeof(ibsp));
439a6625592SBrandon Bergren 		pbsp = OF_instance_to_package(be32toh(ibsp));
440151c44e2SJustin Hibbits 		if (pbsp != -1)
441151c44e2SJustin Hibbits 			get_cpu_reg(pbsp, &bsp_reg);
442151c44e2SJustin Hibbits 	}
443151c44e2SJustin Hibbits 
444151c44e2SJustin Hibbits 	/* /chosen/fdtbootcpu */
445151c44e2SJustin Hibbits 	if (bsp_reg == -1) {
446151c44e2SJustin Hibbits 		if (OF_getproplen(chosen, "fdtbootcpu") == sizeof(cell_t))
447151c44e2SJustin Hibbits 			OF_getprop(chosen, "fdtbootcpu", &bsp_reg, sizeof(bsp_reg));
448151c44e2SJustin Hibbits 	}
449151c44e2SJustin Hibbits 
450151c44e2SJustin Hibbits 	if (bsp_reg == -1)
451151c44e2SJustin Hibbits 		panic("Boot CPU not found on Open Firmware\n");
452151c44e2SJustin Hibbits 
453151c44e2SJustin Hibbits 	bsp = -1;
454151c44e2SJustin Hibbits 	tmp_cpuref_cnt = 0;
455f0393bbfSWojciech Macek 	for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) {
456f0393bbfSWojciech Macek 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
457f0393bbfSWojciech Macek 		if (res > 0 && strcmp(buf, "cpu") == 0) {
458f0393bbfSWojciech Macek 			res = OF_getproplen(cpu, "ibm,ppc-interrupt-server#s");
459f0393bbfSWojciech Macek 			if (res > 0) {
460f0393bbfSWojciech Macek 				OF_getencprop(cpu, "ibm,ppc-interrupt-server#s",
461f0393bbfSWojciech Macek 				    interrupt_servers, res);
462f0393bbfSWojciech Macek 
463151c44e2SJustin Hibbits 				get_cpu_reg(cpu, &reg);
464151c44e2SJustin Hibbits 				if (reg == bsp_reg)
465151c44e2SJustin Hibbits 					bsp = tmp_cpuref_cnt;
466f0393bbfSWojciech Macek 
467151c44e2SJustin Hibbits 				for (a = 0; a < res/sizeof(cell_t); a++) {
468151c44e2SJustin Hibbits 					tmp_cpuref[tmp_cpuref_cnt].cr_hwref = interrupt_servers[a];
469151c44e2SJustin Hibbits 					tmp_cpuref[tmp_cpuref_cnt].cr_cpuid = tmp_cpuref_cnt;
470151c44e2SJustin Hibbits 					tmp_cpuref_cnt++;
471151c44e2SJustin Hibbits 				}
472151c44e2SJustin Hibbits 			}
473151c44e2SJustin Hibbits 		}
474151c44e2SJustin Hibbits 	}
475151c44e2SJustin Hibbits 
476151c44e2SJustin Hibbits 	if (bsp == -1)
477151c44e2SJustin Hibbits 		panic("Boot CPU not found\n");
478151c44e2SJustin Hibbits 
479151c44e2SJustin Hibbits 	/* Map IDs, so BSP has CPUID 0 regardless of hwref */
480151c44e2SJustin Hibbits 	for (a = bsp; a < tmp_cpuref_cnt; a++) {
481151c44e2SJustin Hibbits 		platform_cpuref[platform_cpuref_cnt].cr_hwref = tmp_cpuref[a].cr_hwref;
482151c44e2SJustin Hibbits 		platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt;
483f0393bbfSWojciech Macek 		platform_cpuref_cnt++;
484f0393bbfSWojciech Macek 	}
485151c44e2SJustin Hibbits 	for (a = 0; a < bsp; a++) {
486151c44e2SJustin Hibbits 		platform_cpuref[platform_cpuref_cnt].cr_hwref = tmp_cpuref[a].cr_hwref;
487151c44e2SJustin Hibbits 		platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt;
488151c44e2SJustin Hibbits 		platform_cpuref_cnt++;
489f0393bbfSWojciech Macek 	}
490f0393bbfSWojciech Macek 
491f0393bbfSWojciech Macek 	platform_cpuref_valid = 1;
4927a8d25c0SNathan Whitehorn 
4937a8d25c0SNathan Whitehorn 	return (0);
4947a8d25c0SNathan Whitehorn }
4957a8d25c0SNathan Whitehorn 
4967a8d25c0SNathan Whitehorn #ifdef SMP
4977a8d25c0SNathan Whitehorn static int
4987a8d25c0SNathan Whitehorn chrp_smp_start_cpu(platform_t plat, struct pcpu *pc)
4997a8d25c0SNathan Whitehorn {
5007a8d25c0SNathan Whitehorn 	cell_t start_cpu;
5017a8d25c0SNathan Whitehorn 	int result, err, timeout;
5027a8d25c0SNathan Whitehorn 
5037a8d25c0SNathan Whitehorn 	if (!rtas_exists()) {
5047a8d25c0SNathan Whitehorn 		printf("RTAS uninitialized: unable to start AP %d\n",
5057a8d25c0SNathan Whitehorn 		    pc->pc_cpuid);
5067a8d25c0SNathan Whitehorn 		return (ENXIO);
5077a8d25c0SNathan Whitehorn 	}
5087a8d25c0SNathan Whitehorn 
5097a8d25c0SNathan Whitehorn 	start_cpu = rtas_token_lookup("start-cpu");
5107a8d25c0SNathan Whitehorn 	if (start_cpu == -1) {
5117a8d25c0SNathan Whitehorn 		printf("RTAS unknown method: unable to start AP %d\n",
5127a8d25c0SNathan Whitehorn 		    pc->pc_cpuid);
5137a8d25c0SNathan Whitehorn 		return (ENXIO);
5147a8d25c0SNathan Whitehorn 	}
5157a8d25c0SNathan Whitehorn 
5167a8d25c0SNathan Whitehorn 	ap_pcpu = pc;
5177a8d25c0SNathan Whitehorn 	powerpc_sync();
5187a8d25c0SNathan Whitehorn 
519f0393bbfSWojciech Macek 	result = rtas_call_method(start_cpu, 3, 1, pc->pc_hwref, EXC_RST, pc,
5207a8d25c0SNathan Whitehorn 	    &err);
5217a8d25c0SNathan Whitehorn 	if (result < 0 || err != 0) {
5227a8d25c0SNathan Whitehorn 		printf("RTAS error (%d/%d): unable to start AP %d\n",
5237a8d25c0SNathan Whitehorn 		    result, err, pc->pc_cpuid);
5247a8d25c0SNathan Whitehorn 		return (ENXIO);
5257a8d25c0SNathan Whitehorn 	}
5267a8d25c0SNathan Whitehorn 
5277a8d25c0SNathan Whitehorn 	timeout = 10000;
5287a8d25c0SNathan Whitehorn 	while (!pc->pc_awake && timeout--)
5297a8d25c0SNathan Whitehorn 		DELAY(100);
5307a8d25c0SNathan Whitehorn 
5317a8d25c0SNathan Whitehorn 	return ((pc->pc_awake) ? 0 : EBUSY);
5327a8d25c0SNathan Whitehorn }
5337a8d25c0SNathan Whitehorn 
534bba9cbe3SConrad Meyer static void
535bba9cbe3SConrad Meyer chrp_smp_probe_threads(platform_t plat)
5367a8d25c0SNathan Whitehorn {
53709f07b00SNathan Whitehorn 	struct pcpu *pc, *last_pc;
538bba9cbe3SConrad Meyer 	int i, ncores;
5397a8d25c0SNathan Whitehorn 
540bba9cbe3SConrad Meyer 	ncores = 0;
54109f07b00SNathan Whitehorn 	last_pc = NULL;
54209f07b00SNathan Whitehorn 	for (i = 0; i <= mp_maxid; i++) {
54309f07b00SNathan Whitehorn 		pc = pcpu_find(i);
54409f07b00SNathan Whitehorn 		if (pc == NULL)
545f9d6e0a5SNathan Whitehorn 			continue;
54609f07b00SNathan Whitehorn 		if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref)
54709f07b00SNathan Whitehorn 			ncores++;
54809f07b00SNathan Whitehorn 		last_pc = pc;
549f9d6e0a5SNathan Whitehorn 	}
550f9d6e0a5SNathan Whitehorn 
5516b83069eSConrad Meyer 	mp_ncores = ncores;
552bba9cbe3SConrad Meyer 	if (mp_ncpus % ncores == 0)
553bba9cbe3SConrad Meyer 		smp_threads_per_core = mp_ncpus / ncores;
554bba9cbe3SConrad Meyer }
5556b83069eSConrad Meyer 
556bba9cbe3SConrad Meyer static struct cpu_group *
557bba9cbe3SConrad Meyer chrp_smp_topo(platform_t plat)
558bba9cbe3SConrad Meyer {
559bba9cbe3SConrad Meyer 
560bba9cbe3SConrad Meyer 	if (mp_ncpus % mp_ncores != 0) {
5617a8d25c0SNathan Whitehorn 		printf("WARNING: Irregular SMP topology. Performance may be "
562bba9cbe3SConrad Meyer 		     "suboptimal (%d CPUS, %d cores)\n", mp_ncpus, mp_ncores);
5637a8d25c0SNathan Whitehorn 		return (smp_topo_none());
5647a8d25c0SNathan Whitehorn 	}
5657a8d25c0SNathan Whitehorn 
5667a8d25c0SNathan Whitehorn 	/* Don't do anything fancier for non-threaded SMP */
567bba9cbe3SConrad Meyer 	if (mp_ncpus == mp_ncores)
5687a8d25c0SNathan Whitehorn 		return (smp_topo_none());
5697a8d25c0SNathan Whitehorn 
570bba9cbe3SConrad Meyer 	return (smp_topo_1level(CG_SHARE_L1, smp_threads_per_core,
571bba9cbe3SConrad Meyer 	    CG_FLAG_SMT));
5727a8d25c0SNathan Whitehorn }
5737a8d25c0SNathan Whitehorn #endif
5747a8d25c0SNathan Whitehorn 
5757a8d25c0SNathan Whitehorn static void
5767a8d25c0SNathan Whitehorn chrp_reset(platform_t platform)
5777a8d25c0SNathan Whitehorn {
5787a8d25c0SNathan Whitehorn 	OF_reboot();
5797a8d25c0SNathan Whitehorn }
5807a8d25c0SNathan Whitehorn 
5817a8d25c0SNathan Whitehorn #ifdef __powerpc64__
5827a8d25c0SNathan Whitehorn static void
5837a8d25c0SNathan Whitehorn phyp_cpu_idle(sbintime_t sbt)
5847a8d25c0SNathan Whitehorn {
585e21d69e9SNathan Whitehorn 	register_t msr;
586e21d69e9SNathan Whitehorn 
587e21d69e9SNathan Whitehorn 	msr = mfmsr();
588e21d69e9SNathan Whitehorn 
589e21d69e9SNathan Whitehorn 	mtmsr(msr & ~PSL_EE);
590e21d69e9SNathan Whitehorn 	if (sched_runnable()) {
591e21d69e9SNathan Whitehorn 		mtmsr(msr);
592e21d69e9SNathan Whitehorn 		return;
593e21d69e9SNathan Whitehorn 	}
594e21d69e9SNathan Whitehorn 
595e21d69e9SNathan Whitehorn 	phyp_hcall(H_CEDE); /* Re-enables interrupts internally */
596e21d69e9SNathan Whitehorn 	mtmsr(msr);
5977a8d25c0SNathan Whitehorn }
5987a8d25c0SNathan Whitehorn 
5997a8d25c0SNathan Whitehorn static void
6007a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform)
6017a8d25c0SNathan Whitehorn {
6027a8d25c0SNathan Whitehorn 	if (!(mfmsr() & PSL_HV)) {
603f1e48417SNathan Whitehorn 		/* Register VPA */
604f0393bbfSWojciech Macek 		phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(hwref),
605f0393bbfSWojciech Macek 		    splpar_vpa[PCPU_GET(hwref)]);
606f1e48417SNathan Whitehorn 
6077a8d25c0SNathan Whitehorn 		/* Set interrupt priority */
6087a8d25c0SNathan Whitehorn 		phyp_hcall(H_CPPR, 0xff);
6097a8d25c0SNathan Whitehorn 	}
6107a8d25c0SNathan Whitehorn }
6117a8d25c0SNathan Whitehorn #else
6127a8d25c0SNathan Whitehorn static void
6137a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform)
6147a8d25c0SNathan Whitehorn {
6157a8d25c0SNathan Whitehorn }
6167a8d25c0SNathan Whitehorn #endif
617