xref: /freebsd/sys/powerpc/pseries/platform_chrp.c (revision 685dc743)
17a8d25c0SNathan Whitehorn /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
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>
31a6625592SBrandon Bergren #include <sys/endian.h>
327a8d25c0SNathan Whitehorn #include <sys/param.h>
337a8d25c0SNathan Whitehorn #include <sys/systm.h>
347a8d25c0SNathan Whitehorn #include <sys/kernel.h>
357a8d25c0SNathan Whitehorn #include <sys/bus.h>
367a8d25c0SNathan Whitehorn #include <sys/pcpu.h>
377a8d25c0SNathan Whitehorn #include <sys/proc.h>
38e21d69e9SNathan Whitehorn #include <sys/sched.h>
397a8d25c0SNathan Whitehorn #include <sys/smp.h>
407a8d25c0SNathan Whitehorn #include <vm/vm.h>
417a8d25c0SNathan Whitehorn #include <vm/pmap.h>
427a8d25c0SNathan Whitehorn 
437a8d25c0SNathan Whitehorn #include <machine/bus.h>
447a8d25c0SNathan Whitehorn #include <machine/cpu.h>
457a8d25c0SNathan Whitehorn #include <machine/hid.h>
467a8d25c0SNathan Whitehorn #include <machine/platformvar.h>
477a8d25c0SNathan Whitehorn #include <machine/rtas.h>
487a8d25c0SNathan Whitehorn #include <machine/smp.h>
497a8d25c0SNathan Whitehorn #include <machine/spr.h>
50258dbffeSNathan Whitehorn #include <machine/trap.h>
517a8d25c0SNathan Whitehorn 
527a8d25c0SNathan Whitehorn #include <dev/ofw/openfirm.h>
537a8d25c0SNathan Whitehorn #include <machine/ofw_machdep.h>
547a8d25c0SNathan Whitehorn 
557a8d25c0SNathan Whitehorn #include "platform_if.h"
567a8d25c0SNathan Whitehorn 
577a8d25c0SNathan Whitehorn #ifdef SMP
587a8d25c0SNathan Whitehorn extern void *ap_pcpu;
597a8d25c0SNathan Whitehorn #endif
607a8d25c0SNathan Whitehorn 
617a8d25c0SNathan Whitehorn #ifdef __powerpc64__
62f1e48417SNathan Whitehorn static uint8_t splpar_vpa[MAXCPU][640] __aligned(128); /* XXX: dpcpu */
637a8d25c0SNathan Whitehorn #endif
647a8d25c0SNathan Whitehorn 
657a8d25c0SNathan Whitehorn static vm_offset_t realmaxaddr = VM_MAX_ADDRESS;
667a8d25c0SNathan Whitehorn 
677a8d25c0SNathan Whitehorn static int chrp_probe(platform_t);
687a8d25c0SNathan Whitehorn static int chrp_attach(platform_t);
69c1cb22d7SNathan Whitehorn void chrp_mem_regions(platform_t, struct mem_region *phys, int *physsz,
70c1cb22d7SNathan Whitehorn     struct mem_region *avail, int *availsz);
717a8d25c0SNathan Whitehorn static vm_offset_t chrp_real_maxaddr(platform_t);
727a8d25c0SNathan Whitehorn static u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref);
737a8d25c0SNathan Whitehorn static int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref);
747a8d25c0SNathan Whitehorn static int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref);
757a8d25c0SNathan Whitehorn static int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref);
767a8d25c0SNathan Whitehorn static void chrp_smp_ap_init(platform_t);
77f0393bbfSWojciech Macek static int chrp_cpuref_init(void);
787a8d25c0SNathan Whitehorn #ifdef SMP
797a8d25c0SNathan Whitehorn static int chrp_smp_start_cpu(platform_t, struct pcpu *cpu);
80bba9cbe3SConrad Meyer static void chrp_smp_probe_threads(platform_t plat);
817a8d25c0SNathan Whitehorn static struct cpu_group *chrp_smp_topo(platform_t plat);
827a8d25c0SNathan Whitehorn #endif
837a8d25c0SNathan Whitehorn static void chrp_reset(platform_t);
847a8d25c0SNathan Whitehorn #ifdef __powerpc64__
857a8d25c0SNathan Whitehorn #include "phyp-hvcall.h"
867a8d25c0SNathan Whitehorn static void phyp_cpu_idle(sbintime_t sbt);
877a8d25c0SNathan Whitehorn #endif
887a8d25c0SNathan Whitehorn 
89f0393bbfSWojciech Macek static struct cpuref platform_cpuref[MAXCPU];
90f0393bbfSWojciech Macek static int platform_cpuref_cnt;
91f0393bbfSWojciech Macek static int platform_cpuref_valid;
92f0393bbfSWojciech Macek 
937a8d25c0SNathan Whitehorn static platform_method_t chrp_methods[] = {
947a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_probe, 		chrp_probe),
957a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_attach,		chrp_attach),
967a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_mem_regions,	chrp_mem_regions),
977a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_real_maxaddr,	chrp_real_maxaddr),
987a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_timebase_freq,	chrp_timebase_freq),
997a8d25c0SNathan Whitehorn 
1007a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_ap_init,	chrp_smp_ap_init),
1017a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_first_cpu,	chrp_smp_first_cpu),
1027a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_next_cpu,	chrp_smp_next_cpu),
1037a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_get_bsp,	chrp_smp_get_bsp),
1047a8d25c0SNathan Whitehorn #ifdef SMP
1057a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_start_cpu,	chrp_smp_start_cpu),
106bba9cbe3SConrad Meyer 	PLATFORMMETHOD(platform_smp_probe_threads,	chrp_smp_probe_threads),
1077a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_topo,	chrp_smp_topo),
1087a8d25c0SNathan Whitehorn #endif
1097a8d25c0SNathan Whitehorn 
1107a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_reset,		chrp_reset),
1117a8d25c0SNathan Whitehorn 	{ 0, 0 }
1127a8d25c0SNathan Whitehorn };
1137a8d25c0SNathan Whitehorn 
1147a8d25c0SNathan Whitehorn static platform_def_t chrp_platform = {
1157a8d25c0SNathan Whitehorn 	"chrp",
1167a8d25c0SNathan Whitehorn 	chrp_methods,
1177a8d25c0SNathan Whitehorn 	0
1187a8d25c0SNathan Whitehorn };
1197a8d25c0SNathan Whitehorn 
1207a8d25c0SNathan Whitehorn PLATFORM_DEF(chrp_platform);
1217a8d25c0SNathan Whitehorn 
1227a8d25c0SNathan Whitehorn static int
chrp_probe(platform_t plat)1237a8d25c0SNathan Whitehorn chrp_probe(platform_t plat)
1247a8d25c0SNathan Whitehorn {
1257a8d25c0SNathan Whitehorn 	if (OF_finddevice("/memory") != -1 || OF_finddevice("/memory@0") != -1)
1267a8d25c0SNathan Whitehorn 		return (BUS_PROBE_GENERIC);
1277a8d25c0SNathan Whitehorn 
1287a8d25c0SNathan Whitehorn 	return (ENXIO);
1297a8d25c0SNathan Whitehorn }
1307a8d25c0SNathan Whitehorn 
1317a8d25c0SNathan Whitehorn static int
chrp_attach(platform_t plat)1327a8d25c0SNathan Whitehorn chrp_attach(platform_t plat)
1337a8d25c0SNathan Whitehorn {
13435f29427SLeandro Lupori 	int quiesce;
13566fe9464SBjoern A. Zeeb #ifdef __powerpc64__
136f1e48417SNathan Whitehorn 	int i;
13735ef3951SBrandon Bergren #if BYTE_ORDER == LITTLE_ENDIAN
13835ef3951SBrandon Bergren 	int result;
13935ef3951SBrandon Bergren #endif
140f1e48417SNathan Whitehorn 
1417a8d25c0SNathan Whitehorn 	/* XXX: check for /rtas/ibm,hypertas-functions? */
1427a8d25c0SNathan Whitehorn 	if (!(mfmsr() & PSL_HV)) {
1437a8d25c0SNathan Whitehorn 		struct mem_region *phys, *avail;
1447a8d25c0SNathan Whitehorn 		int nphys, navail;
1458b55f9f8SLeandro Lupori 		vm_offset_t off;
1468b55f9f8SLeandro Lupori 
1477a8d25c0SNathan Whitehorn 		mem_regions(&phys, &nphys, &avail, &navail);
1488b55f9f8SLeandro Lupori 
1498b55f9f8SLeandro Lupori 		realmaxaddr = 0;
1508b55f9f8SLeandro Lupori 		for (i = 0; i < nphys; i++) {
1518b55f9f8SLeandro Lupori 			off = phys[i].mr_start + phys[i].mr_size;
1528b55f9f8SLeandro Lupori 			realmaxaddr = MAX(off, realmaxaddr);
1538b55f9f8SLeandro Lupori 		}
1547a8d25c0SNathan Whitehorn 
1555ae48eb9SJustin Hibbits 		if (!radix_mmu)
1567a8d25c0SNathan Whitehorn 			pmap_mmu_install("mmu_phyp", BUS_PROBE_SPECIFIC);
1577a8d25c0SNathan Whitehorn 		cpu_idle_hook = phyp_cpu_idle;
1587a8d25c0SNathan Whitehorn 
1597a8d25c0SNathan Whitehorn 		/* Set up important VPA fields */
160f1e48417SNathan Whitehorn 		for (i = 0; i < MAXCPU; i++) {
161f1e48417SNathan Whitehorn 			/* First two: VPA size */
162f1e48417SNathan Whitehorn 			splpar_vpa[i][4] =
163f1e48417SNathan Whitehorn 			    (uint8_t)((sizeof(splpar_vpa[i]) >> 8) & 0xff);
164f1e48417SNathan Whitehorn 			splpar_vpa[i][5] =
165f1e48417SNathan Whitehorn 			    (uint8_t)(sizeof(splpar_vpa[i]) & 0xff);
166f1e48417SNathan Whitehorn 			splpar_vpa[i][0xba] = 1;	/* Maintain FPRs */
167f1e48417SNathan Whitehorn 			splpar_vpa[i][0xbb] = 1;	/* Maintain PMCs */
168f1e48417SNathan Whitehorn 			splpar_vpa[i][0xfc] = 0xff;	/* Maintain full SLB */
169f1e48417SNathan Whitehorn 			splpar_vpa[i][0xfd] = 0xff;
170f1e48417SNathan Whitehorn 			splpar_vpa[i][0xff] = 1;	/* Maintain Altivec */
171f1e48417SNathan Whitehorn 		}
1727a8d25c0SNathan Whitehorn 		mb();
1737a8d25c0SNathan Whitehorn 
1747a8d25c0SNathan Whitehorn 		/* Set up hypervisor CPU stuff */
1757a8d25c0SNathan Whitehorn 		chrp_smp_ap_init(plat);
17635ef3951SBrandon Bergren 
17735ef3951SBrandon Bergren #if BYTE_ORDER == LITTLE_ENDIAN
17835ef3951SBrandon Bergren 		/*
17935ef3951SBrandon Bergren 		 * Ask the hypervisor to update the LPAR ILE bit.
18035ef3951SBrandon Bergren 		 *
18135ef3951SBrandon Bergren 		 * This involves all processors reentering the hypervisor
18235ef3951SBrandon Bergren 		 * so the change appears simultaneously in all processors.
18335ef3951SBrandon Bergren 		 * This can take a long time.
18435ef3951SBrandon Bergren 		 */
18535ef3951SBrandon Bergren 		for(;;) {
18635ef3951SBrandon Bergren 			result = phyp_hcall(H_SET_MODE, 1UL,
18735ef3951SBrandon Bergren 			    H_SET_MODE_RSRC_ILE, 0, 0);
18835ef3951SBrandon Bergren 			if (result == H_SUCCESS)
18935ef3951SBrandon Bergren 				break;
19035ef3951SBrandon Bergren 			DELAY(1000);
19135ef3951SBrandon Bergren 		}
19235ef3951SBrandon Bergren #endif
19335ef3951SBrandon Bergren 
1947a8d25c0SNathan Whitehorn 	}
1957a8d25c0SNathan Whitehorn #endif
196f0393bbfSWojciech Macek 	chrp_cpuref_init();
1977a8d25c0SNathan Whitehorn 
1989f706727SNathan Whitehorn 	/* Some systems (e.g. QEMU) need Open Firmware to stand down */
19935f29427SLeandro Lupori 	quiesce = 1;
20035f29427SLeandro Lupori 	TUNABLE_INT_FETCH("debug.quiesce_ofw", &quiesce);
20135f29427SLeandro Lupori 	if (quiesce)
2029f706727SNathan Whitehorn 		ofw_quiesce();
2039f706727SNathan Whitehorn 
2047a8d25c0SNathan Whitehorn 	return (0);
2057a8d25c0SNathan Whitehorn }
2067a8d25c0SNathan Whitehorn 
207c1cb22d7SNathan Whitehorn static int
parse_drconf_memory(struct mem_region * ofmem,int * msz,struct mem_region * ofavail,int * asz)208f5dfbe2fSAndreas Tobler parse_drconf_memory(struct mem_region *ofmem, int *msz,
209f5dfbe2fSAndreas Tobler 		    struct mem_region *ofavail, int *asz)
2107a8d25c0SNathan Whitehorn {
211c1cb22d7SNathan Whitehorn 	phandle_t phandle;
212c1cb22d7SNathan Whitehorn 	vm_offset_t base;
213c1cb22d7SNathan Whitehorn 	int i, idx, len, lasz, lmsz, res;
214f5dfbe2fSAndreas Tobler 	uint32_t flags, lmb_size[2];
215509142e1SNathan Whitehorn 	uint32_t *dmem;
216c1cb22d7SNathan Whitehorn 
217c1cb22d7SNathan Whitehorn 	lmsz = *msz;
218c1cb22d7SNathan Whitehorn 	lasz = *asz;
219c1cb22d7SNathan Whitehorn 
220c1cb22d7SNathan Whitehorn 	phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory");
221c1cb22d7SNathan Whitehorn 	if (phandle == -1)
222c1cb22d7SNathan Whitehorn 		/* No drconf node, return. */
223c1cb22d7SNathan Whitehorn 		return (0);
224c1cb22d7SNathan Whitehorn 
225509142e1SNathan Whitehorn 	res = OF_getencprop(phandle, "ibm,lmb-size", lmb_size,
226509142e1SNathan Whitehorn 	    sizeof(lmb_size));
227c1cb22d7SNathan Whitehorn 	if (res == -1)
228c1cb22d7SNathan Whitehorn 		return (0);
229c1cb22d7SNathan Whitehorn 	printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20);
230c1cb22d7SNathan Whitehorn 
231c1cb22d7SNathan Whitehorn 	/* Parse the /ibm,dynamic-memory.
232c1cb22d7SNathan Whitehorn 	   The first position gives the # of entries. The next two words
233c1cb22d7SNathan Whitehorn  	   reflect the address of the memory block. The next four words are
234c1cb22d7SNathan Whitehorn 	   the DRC index, reserved, list index and flags.
235c1cb22d7SNathan Whitehorn 	   (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory)
236c1cb22d7SNathan Whitehorn 
237c1cb22d7SNathan Whitehorn 	    #el  Addr   DRC-idx  res   list-idx  flags
238c1cb22d7SNathan Whitehorn 	   -------------------------------------------------
239c1cb22d7SNathan Whitehorn 	   | 4 |   8   |   4   |   4   |   4   |   4   |....
240c1cb22d7SNathan Whitehorn 	   -------------------------------------------------
241c1cb22d7SNathan Whitehorn 	*/
242c1cb22d7SNathan Whitehorn 
243c1cb22d7SNathan Whitehorn 	len = OF_getproplen(phandle, "ibm,dynamic-memory");
244c1cb22d7SNathan Whitehorn 	if (len > 0) {
245c1cb22d7SNathan Whitehorn 		/* We have to use a variable length array on the stack
246c1cb22d7SNathan Whitehorn 		   since we have very limited stack space.
247c1cb22d7SNathan Whitehorn 		*/
248c1cb22d7SNathan Whitehorn 		cell_t arr[len/sizeof(cell_t)];
249c1cb22d7SNathan Whitehorn 
250509142e1SNathan Whitehorn 		res = OF_getencprop(phandle, "ibm,dynamic-memory", arr,
251c1cb22d7SNathan Whitehorn 		    sizeof(arr));
252c1cb22d7SNathan Whitehorn 		if (res == -1)
253c1cb22d7SNathan Whitehorn 			return (0);
254c1cb22d7SNathan Whitehorn 
255c1cb22d7SNathan Whitehorn 		/* Number of elements */
256c1cb22d7SNathan Whitehorn 		idx = arr[0];
257c1cb22d7SNathan Whitehorn 
258f5dfbe2fSAndreas Tobler 		/* First address, in arr[1], arr[2]*/
259509142e1SNathan Whitehorn 		dmem = &arr[1];
260c1cb22d7SNathan Whitehorn 
261c1cb22d7SNathan Whitehorn 		for (i = 0; i < idx; i++) {
262509142e1SNathan Whitehorn 			base = ((uint64_t)dmem[0] << 32) + dmem[1];
263509142e1SNathan Whitehorn 			dmem += 4;
264509142e1SNathan Whitehorn 			flags = dmem[1];
265c1cb22d7SNathan Whitehorn 			/* Use region only if available and not reserved. */
266c1cb22d7SNathan Whitehorn 			if ((flags & 0x8) && !(flags & 0x80)) {
267c1cb22d7SNathan Whitehorn 				ofmem[lmsz].mr_start = base;
268c1cb22d7SNathan Whitehorn 				ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1];
269c1cb22d7SNathan Whitehorn 				ofavail[lasz].mr_start = base;
270c1cb22d7SNathan Whitehorn 				ofavail[lasz].mr_size = (vm_size_t)lmb_size[1];
271c1cb22d7SNathan Whitehorn 				lmsz++;
272c1cb22d7SNathan Whitehorn 				lasz++;
273c1cb22d7SNathan Whitehorn 			}
274509142e1SNathan Whitehorn 			dmem += 2;
275c1cb22d7SNathan Whitehorn 		}
276c1cb22d7SNathan Whitehorn 	}
277c1cb22d7SNathan Whitehorn 
278c1cb22d7SNathan Whitehorn 	*msz = lmsz;
279c1cb22d7SNathan Whitehorn 	*asz = lasz;
280c1cb22d7SNathan Whitehorn 
281c1cb22d7SNathan Whitehorn 	return (1);
282c1cb22d7SNathan Whitehorn }
283c1cb22d7SNathan Whitehorn 
284c1cb22d7SNathan Whitehorn void
chrp_mem_regions(platform_t plat,struct mem_region * phys,int * physsz,struct mem_region * avail,int * availsz)285c1cb22d7SNathan Whitehorn chrp_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
286c1cb22d7SNathan Whitehorn     struct mem_region *avail, int *availsz)
287c1cb22d7SNathan Whitehorn {
288c1cb22d7SNathan Whitehorn 	vm_offset_t maxphysaddr;
289c1cb22d7SNathan Whitehorn 	int i;
290c1cb22d7SNathan Whitehorn 
2917a8d25c0SNathan Whitehorn 	ofw_mem_regions(phys, physsz, avail, availsz);
292f5dfbe2fSAndreas Tobler 	parse_drconf_memory(phys, physsz, avail, availsz);
293c1cb22d7SNathan Whitehorn 
294c1cb22d7SNathan Whitehorn 	/*
295c1cb22d7SNathan Whitehorn 	 * On some firmwares (SLOF), some memory may be marked available that
296c1cb22d7SNathan Whitehorn 	 * doesn't actually exist. This manifests as an extension of the last
297c1cb22d7SNathan Whitehorn 	 * available segment past the end of physical memory, so truncate that
298c1cb22d7SNathan Whitehorn 	 * one.
299c1cb22d7SNathan Whitehorn 	 */
300c1cb22d7SNathan Whitehorn 	maxphysaddr = 0;
301c1cb22d7SNathan Whitehorn 	for (i = 0; i < *physsz; i++)
302c1cb22d7SNathan Whitehorn 		if (phys[i].mr_start + phys[i].mr_size > maxphysaddr)
303c1cb22d7SNathan Whitehorn 			maxphysaddr = phys[i].mr_start + phys[i].mr_size;
304c1cb22d7SNathan Whitehorn 
305c1cb22d7SNathan Whitehorn 	for (i = 0; i < *availsz; i++)
306c1cb22d7SNathan Whitehorn 		if (avail[i].mr_start + avail[i].mr_size > maxphysaddr)
307c1cb22d7SNathan Whitehorn 			avail[i].mr_size = maxphysaddr - avail[i].mr_start;
3087a8d25c0SNathan Whitehorn }
3097a8d25c0SNathan Whitehorn 
3107a8d25c0SNathan Whitehorn static vm_offset_t
chrp_real_maxaddr(platform_t plat)3117a8d25c0SNathan Whitehorn chrp_real_maxaddr(platform_t plat)
3127a8d25c0SNathan Whitehorn {
3137a8d25c0SNathan Whitehorn 	return (realmaxaddr);
3147a8d25c0SNathan Whitehorn }
3157a8d25c0SNathan Whitehorn 
3167a8d25c0SNathan Whitehorn static u_long
chrp_timebase_freq(platform_t plat,struct cpuref * cpuref)3177a8d25c0SNathan Whitehorn chrp_timebase_freq(platform_t plat, struct cpuref *cpuref)
3187a8d25c0SNathan Whitehorn {
319a00ce4e8SJustin Hibbits 	phandle_t cpus, cpunode;
3207a8d25c0SNathan Whitehorn 	int32_t ticks = -1;
321a00ce4e8SJustin Hibbits 	int res;
322a00ce4e8SJustin Hibbits 	char buf[8];
3237a8d25c0SNathan Whitehorn 
324a00ce4e8SJustin Hibbits 	cpus = OF_finddevice("/cpus");
325108117ccSOleksandr Tymoshenko 	if (cpus == -1)
326a00ce4e8SJustin Hibbits 		panic("CPU tree not found on Open Firmware\n");
3277a8d25c0SNathan Whitehorn 
328a00ce4e8SJustin Hibbits 	for (cpunode = OF_child(cpus); cpunode != 0; cpunode = OF_peer(cpunode)) {
329a00ce4e8SJustin Hibbits 		res = OF_getprop(cpunode, "device_type", buf, sizeof(buf));
330a00ce4e8SJustin Hibbits 		if (res > 0 && strcmp(buf, "cpu") == 0)
331a00ce4e8SJustin Hibbits 			break;
332a00ce4e8SJustin Hibbits 	}
333a00ce4e8SJustin Hibbits 	if (cpunode <= 0)
334a00ce4e8SJustin Hibbits 		panic("CPU node not found on Open Firmware\n");
335a00ce4e8SJustin Hibbits 
336a00ce4e8SJustin Hibbits 	OF_getencprop(cpunode, "timebase-frequency", &ticks, sizeof(ticks));
3377a8d25c0SNathan Whitehorn 
3387a8d25c0SNathan Whitehorn 	if (ticks <= 0)
3397a8d25c0SNathan Whitehorn 		panic("Unable to determine timebase frequency!");
3407a8d25c0SNathan Whitehorn 
3417a8d25c0SNathan Whitehorn 	return (ticks);
3427a8d25c0SNathan Whitehorn }
3437a8d25c0SNathan Whitehorn 
3447a8d25c0SNathan Whitehorn static int
chrp_smp_first_cpu(platform_t plat,struct cpuref * cpuref)34509f07b00SNathan Whitehorn chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
3467a8d25c0SNathan Whitehorn {
3477a8d25c0SNathan Whitehorn 
348f0393bbfSWojciech Macek 	if (platform_cpuref_valid == 0)
349f0393bbfSWojciech Macek 		return (EINVAL);
3507a8d25c0SNathan Whitehorn 
351f0393bbfSWojciech Macek 	cpuref->cr_cpuid = 0;
352f0393bbfSWojciech Macek 	cpuref->cr_hwref = platform_cpuref[0].cr_hwref;
3537a8d25c0SNathan Whitehorn 
3547a8d25c0SNathan Whitehorn 	return (0);
3557a8d25c0SNathan Whitehorn }
3567a8d25c0SNathan Whitehorn 
3577a8d25c0SNathan Whitehorn static int
chrp_smp_next_cpu(platform_t plat,struct cpuref * cpuref)3587a8d25c0SNathan Whitehorn chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
3597a8d25c0SNathan Whitehorn {
360f0393bbfSWojciech Macek 	int id;
3617a8d25c0SNathan Whitehorn 
362f0393bbfSWojciech Macek 	if (platform_cpuref_valid == 0)
363f0393bbfSWojciech Macek 		return (EINVAL);
3647a8d25c0SNathan Whitehorn 
365f0393bbfSWojciech Macek 	id = cpuref->cr_cpuid + 1;
366f0393bbfSWojciech Macek 	if (id >= platform_cpuref_cnt)
3677a8d25c0SNathan Whitehorn 		return (ENOENT);
36809f07b00SNathan Whitehorn 
369f0393bbfSWojciech Macek 	cpuref->cr_cpuid = platform_cpuref[id].cr_cpuid;
370f0393bbfSWojciech Macek 	cpuref->cr_hwref = platform_cpuref[id].cr_hwref;
37109f07b00SNathan Whitehorn 
37209f07b00SNathan Whitehorn 	return (0);
3737a8d25c0SNathan Whitehorn }
3747a8d25c0SNathan Whitehorn 
3757a8d25c0SNathan Whitehorn static int
chrp_smp_get_bsp(platform_t plat,struct cpuref * cpuref)3767a8d25c0SNathan Whitehorn chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
3777a8d25c0SNathan Whitehorn {
3787a8d25c0SNathan Whitehorn 
379f0393bbfSWojciech Macek 	cpuref->cr_cpuid = platform_cpuref[0].cr_cpuid;
380f0393bbfSWojciech Macek 	cpuref->cr_hwref = platform_cpuref[0].cr_hwref;
381f0393bbfSWojciech Macek 	return (0);
382f0393bbfSWojciech Macek }
3837a8d25c0SNathan Whitehorn 
384151c44e2SJustin Hibbits static void
get_cpu_reg(phandle_t cpu,cell_t * reg)385151c44e2SJustin Hibbits get_cpu_reg(phandle_t cpu, cell_t *reg)
386151c44e2SJustin Hibbits {
387151c44e2SJustin Hibbits 	int res;
388151c44e2SJustin Hibbits 
389151c44e2SJustin Hibbits 	res = OF_getproplen(cpu, "reg");
390151c44e2SJustin Hibbits 	if (res != sizeof(cell_t))
391151c44e2SJustin Hibbits 		panic("Unexpected length for CPU property reg on Open Firmware\n");
392151c44e2SJustin Hibbits 	OF_getencprop(cpu, "reg", reg, res);
393151c44e2SJustin Hibbits }
394151c44e2SJustin Hibbits 
395f0393bbfSWojciech Macek static int
chrp_cpuref_init(void)396f0393bbfSWojciech Macek chrp_cpuref_init(void)
397f0393bbfSWojciech Macek {
398151c44e2SJustin Hibbits 	phandle_t cpu, dev, chosen, pbsp;
399151c44e2SJustin Hibbits 	ihandle_t ibsp;
400f0393bbfSWojciech Macek 	char buf[32];
401151c44e2SJustin Hibbits 	int a, bsp, res, res2, tmp_cpuref_cnt;
402151c44e2SJustin Hibbits 	static struct cpuref tmp_cpuref[MAXCPU];
403151c44e2SJustin Hibbits 	cell_t interrupt_servers[32], addr_cells, size_cells, reg, bsp_reg;
4047a8d25c0SNathan Whitehorn 
405f0393bbfSWojciech Macek 	if (platform_cpuref_valid)
406f0393bbfSWojciech Macek 		return (0);
4077a8d25c0SNathan Whitehorn 
408f0393bbfSWojciech Macek 	dev = OF_peer(0);
409f0393bbfSWojciech Macek 	dev = OF_child(dev);
410f0393bbfSWojciech Macek 	while (dev != 0) {
411f0393bbfSWojciech Macek 		res = OF_getprop(dev, "name", buf, sizeof(buf));
412f0393bbfSWojciech Macek 		if (res > 0 && strcmp(buf, "cpus") == 0)
413f0393bbfSWojciech Macek 			break;
414f0393bbfSWojciech Macek 		dev = OF_peer(dev);
415f0393bbfSWojciech Macek 	}
416f0393bbfSWojciech Macek 
417151c44e2SJustin Hibbits 	/* Make sure that cpus reg property have 1 address cell and 0 size cells */
418151c44e2SJustin Hibbits 	res = OF_getproplen(dev, "#address-cells");
419151c44e2SJustin Hibbits 	res2 = OF_getproplen(dev, "#size-cells");
420151c44e2SJustin Hibbits 	if (res != res2 || res != sizeof(cell_t))
421151c44e2SJustin Hibbits 		panic("CPU properties #address-cells and #size-cells not found on Open Firmware\n");
422151c44e2SJustin Hibbits 	OF_getencprop(dev, "#address-cells", &addr_cells, sizeof(addr_cells));
423151c44e2SJustin Hibbits 	OF_getencprop(dev, "#size-cells", &size_cells, sizeof(size_cells));
424151c44e2SJustin Hibbits 	if (addr_cells != 1 || size_cells != 0)
425151c44e2SJustin Hibbits 		panic("Unexpected values for CPU properties #address-cells and #size-cells on Open Firmware\n");
426151c44e2SJustin Hibbits 
427151c44e2SJustin Hibbits 	/* Look for boot CPU in /chosen/cpu and /chosen/fdtbootcpu */
428151c44e2SJustin Hibbits 
429151c44e2SJustin Hibbits 	chosen = OF_finddevice("/chosen");
430151c44e2SJustin Hibbits 	if (chosen == -1)
431151c44e2SJustin Hibbits 		panic("Device /chosen not found on Open Firmware\n");
432151c44e2SJustin Hibbits 
433151c44e2SJustin Hibbits 	bsp_reg = -1;
434151c44e2SJustin Hibbits 
435151c44e2SJustin Hibbits 	/* /chosen/cpu */
436151c44e2SJustin Hibbits 	if (OF_getproplen(chosen, "cpu") == sizeof(ihandle_t)) {
437151c44e2SJustin Hibbits 		OF_getprop(chosen, "cpu", &ibsp, sizeof(ibsp));
438a6625592SBrandon Bergren 		pbsp = OF_instance_to_package(be32toh(ibsp));
439151c44e2SJustin Hibbits 		if (pbsp != -1)
440151c44e2SJustin Hibbits 			get_cpu_reg(pbsp, &bsp_reg);
441151c44e2SJustin Hibbits 	}
442151c44e2SJustin Hibbits 
443151c44e2SJustin Hibbits 	/* /chosen/fdtbootcpu */
444151c44e2SJustin Hibbits 	if (bsp_reg == -1) {
445151c44e2SJustin Hibbits 		if (OF_getproplen(chosen, "fdtbootcpu") == sizeof(cell_t))
446151c44e2SJustin Hibbits 			OF_getprop(chosen, "fdtbootcpu", &bsp_reg, sizeof(bsp_reg));
447151c44e2SJustin Hibbits 	}
448151c44e2SJustin Hibbits 
449151c44e2SJustin Hibbits 	if (bsp_reg == -1)
450151c44e2SJustin Hibbits 		panic("Boot CPU not found on Open Firmware\n");
451151c44e2SJustin Hibbits 
452151c44e2SJustin Hibbits 	bsp = -1;
453151c44e2SJustin Hibbits 	tmp_cpuref_cnt = 0;
454f0393bbfSWojciech Macek 	for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) {
455f0393bbfSWojciech Macek 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
456f0393bbfSWojciech Macek 		if (res > 0 && strcmp(buf, "cpu") == 0) {
457f0393bbfSWojciech Macek 			res = OF_getproplen(cpu, "ibm,ppc-interrupt-server#s");
458f0393bbfSWojciech Macek 			if (res > 0) {
459f0393bbfSWojciech Macek 				OF_getencprop(cpu, "ibm,ppc-interrupt-server#s",
460f0393bbfSWojciech Macek 				    interrupt_servers, res);
461f0393bbfSWojciech Macek 
462151c44e2SJustin Hibbits 				get_cpu_reg(cpu, &reg);
463151c44e2SJustin Hibbits 				if (reg == bsp_reg)
464151c44e2SJustin Hibbits 					bsp = tmp_cpuref_cnt;
465f0393bbfSWojciech Macek 
466151c44e2SJustin Hibbits 				for (a = 0; a < res/sizeof(cell_t); a++) {
467151c44e2SJustin Hibbits 					tmp_cpuref[tmp_cpuref_cnt].cr_hwref = interrupt_servers[a];
468151c44e2SJustin Hibbits 					tmp_cpuref[tmp_cpuref_cnt].cr_cpuid = tmp_cpuref_cnt;
469151c44e2SJustin Hibbits 					tmp_cpuref_cnt++;
470151c44e2SJustin Hibbits 				}
471151c44e2SJustin Hibbits 			}
472151c44e2SJustin Hibbits 		}
473151c44e2SJustin Hibbits 	}
474151c44e2SJustin Hibbits 
475151c44e2SJustin Hibbits 	if (bsp == -1)
476151c44e2SJustin Hibbits 		panic("Boot CPU not found\n");
477151c44e2SJustin Hibbits 
478151c44e2SJustin Hibbits 	/* Map IDs, so BSP has CPUID 0 regardless of hwref */
479151c44e2SJustin Hibbits 	for (a = bsp; a < tmp_cpuref_cnt; a++) {
480151c44e2SJustin Hibbits 		platform_cpuref[platform_cpuref_cnt].cr_hwref = tmp_cpuref[a].cr_hwref;
481151c44e2SJustin Hibbits 		platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt;
482f0393bbfSWojciech Macek 		platform_cpuref_cnt++;
483f0393bbfSWojciech Macek 	}
484151c44e2SJustin Hibbits 	for (a = 0; a < bsp; a++) {
485151c44e2SJustin Hibbits 		platform_cpuref[platform_cpuref_cnt].cr_hwref = tmp_cpuref[a].cr_hwref;
486151c44e2SJustin Hibbits 		platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt;
487151c44e2SJustin Hibbits 		platform_cpuref_cnt++;
488f0393bbfSWojciech Macek 	}
489f0393bbfSWojciech Macek 
490f0393bbfSWojciech Macek 	platform_cpuref_valid = 1;
4917a8d25c0SNathan Whitehorn 
4927a8d25c0SNathan Whitehorn 	return (0);
4937a8d25c0SNathan Whitehorn }
4947a8d25c0SNathan Whitehorn 
4957a8d25c0SNathan Whitehorn #ifdef SMP
4967a8d25c0SNathan Whitehorn static int
chrp_smp_start_cpu(platform_t plat,struct pcpu * pc)4977a8d25c0SNathan Whitehorn chrp_smp_start_cpu(platform_t plat, struct pcpu *pc)
4987a8d25c0SNathan Whitehorn {
4997a8d25c0SNathan Whitehorn 	cell_t start_cpu;
5007a8d25c0SNathan Whitehorn 	int result, err, timeout;
5017a8d25c0SNathan Whitehorn 
5027a8d25c0SNathan Whitehorn 	if (!rtas_exists()) {
5037a8d25c0SNathan Whitehorn 		printf("RTAS uninitialized: unable to start AP %d\n",
5047a8d25c0SNathan Whitehorn 		    pc->pc_cpuid);
5057a8d25c0SNathan Whitehorn 		return (ENXIO);
5067a8d25c0SNathan Whitehorn 	}
5077a8d25c0SNathan Whitehorn 
5087a8d25c0SNathan Whitehorn 	start_cpu = rtas_token_lookup("start-cpu");
5097a8d25c0SNathan Whitehorn 	if (start_cpu == -1) {
5107a8d25c0SNathan Whitehorn 		printf("RTAS unknown method: unable to start AP %d\n",
5117a8d25c0SNathan Whitehorn 		    pc->pc_cpuid);
5127a8d25c0SNathan Whitehorn 		return (ENXIO);
5137a8d25c0SNathan Whitehorn 	}
5147a8d25c0SNathan Whitehorn 
5157a8d25c0SNathan Whitehorn 	ap_pcpu = pc;
5167a8d25c0SNathan Whitehorn 	powerpc_sync();
5177a8d25c0SNathan Whitehorn 
518f0393bbfSWojciech Macek 	result = rtas_call_method(start_cpu, 3, 1, pc->pc_hwref, EXC_RST, pc,
5197a8d25c0SNathan Whitehorn 	    &err);
5207a8d25c0SNathan Whitehorn 	if (result < 0 || err != 0) {
5217a8d25c0SNathan Whitehorn 		printf("RTAS error (%d/%d): unable to start AP %d\n",
5227a8d25c0SNathan Whitehorn 		    result, err, pc->pc_cpuid);
5237a8d25c0SNathan Whitehorn 		return (ENXIO);
5247a8d25c0SNathan Whitehorn 	}
5257a8d25c0SNathan Whitehorn 
5267a8d25c0SNathan Whitehorn 	timeout = 10000;
5277a8d25c0SNathan Whitehorn 	while (!pc->pc_awake && timeout--)
5287a8d25c0SNathan Whitehorn 		DELAY(100);
5297a8d25c0SNathan Whitehorn 
5307a8d25c0SNathan Whitehorn 	return ((pc->pc_awake) ? 0 : EBUSY);
5317a8d25c0SNathan Whitehorn }
5327a8d25c0SNathan Whitehorn 
533bba9cbe3SConrad Meyer static void
chrp_smp_probe_threads(platform_t plat)534bba9cbe3SConrad Meyer chrp_smp_probe_threads(platform_t plat)
5357a8d25c0SNathan Whitehorn {
53609f07b00SNathan Whitehorn 	struct pcpu *pc, *last_pc;
537bba9cbe3SConrad Meyer 	int i, ncores;
5387a8d25c0SNathan Whitehorn 
539bba9cbe3SConrad Meyer 	ncores = 0;
54009f07b00SNathan Whitehorn 	last_pc = NULL;
54109f07b00SNathan Whitehorn 	for (i = 0; i <= mp_maxid; i++) {
54209f07b00SNathan Whitehorn 		pc = pcpu_find(i);
54309f07b00SNathan Whitehorn 		if (pc == NULL)
544f9d6e0a5SNathan Whitehorn 			continue;
54509f07b00SNathan Whitehorn 		if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref)
54609f07b00SNathan Whitehorn 			ncores++;
54709f07b00SNathan Whitehorn 		last_pc = pc;
548f9d6e0a5SNathan Whitehorn 	}
549f9d6e0a5SNathan Whitehorn 
5506b83069eSConrad Meyer 	mp_ncores = ncores;
551bba9cbe3SConrad Meyer 	if (mp_ncpus % ncores == 0)
552bba9cbe3SConrad Meyer 		smp_threads_per_core = mp_ncpus / ncores;
553bba9cbe3SConrad Meyer }
5546b83069eSConrad Meyer 
555bba9cbe3SConrad Meyer static struct cpu_group *
chrp_smp_topo(platform_t plat)556bba9cbe3SConrad Meyer chrp_smp_topo(platform_t plat)
557bba9cbe3SConrad Meyer {
558bba9cbe3SConrad Meyer 
559bba9cbe3SConrad Meyer 	if (mp_ncpus % mp_ncores != 0) {
5607a8d25c0SNathan Whitehorn 		printf("WARNING: Irregular SMP topology. Performance may be "
561bba9cbe3SConrad Meyer 		     "suboptimal (%d CPUS, %d cores)\n", mp_ncpus, mp_ncores);
5627a8d25c0SNathan Whitehorn 		return (smp_topo_none());
5637a8d25c0SNathan Whitehorn 	}
5647a8d25c0SNathan Whitehorn 
5657a8d25c0SNathan Whitehorn 	/* Don't do anything fancier for non-threaded SMP */
566bba9cbe3SConrad Meyer 	if (mp_ncpus == mp_ncores)
5677a8d25c0SNathan Whitehorn 		return (smp_topo_none());
5687a8d25c0SNathan Whitehorn 
569bba9cbe3SConrad Meyer 	return (smp_topo_1level(CG_SHARE_L1, smp_threads_per_core,
570bba9cbe3SConrad Meyer 	    CG_FLAG_SMT));
5717a8d25c0SNathan Whitehorn }
5727a8d25c0SNathan Whitehorn #endif
5737a8d25c0SNathan Whitehorn 
5747a8d25c0SNathan Whitehorn static void
chrp_reset(platform_t platform)5757a8d25c0SNathan Whitehorn chrp_reset(platform_t platform)
5767a8d25c0SNathan Whitehorn {
5777a8d25c0SNathan Whitehorn 	OF_reboot();
5787a8d25c0SNathan Whitehorn }
5797a8d25c0SNathan Whitehorn 
5807a8d25c0SNathan Whitehorn #ifdef __powerpc64__
5817a8d25c0SNathan Whitehorn static void
phyp_cpu_idle(sbintime_t sbt)5827a8d25c0SNathan Whitehorn phyp_cpu_idle(sbintime_t sbt)
5837a8d25c0SNathan Whitehorn {
584e21d69e9SNathan Whitehorn 	register_t msr;
585e21d69e9SNathan Whitehorn 
586e21d69e9SNathan Whitehorn 	msr = mfmsr();
587e21d69e9SNathan Whitehorn 
588e21d69e9SNathan Whitehorn 	mtmsr(msr & ~PSL_EE);
589e21d69e9SNathan Whitehorn 	if (sched_runnable()) {
590e21d69e9SNathan Whitehorn 		mtmsr(msr);
591e21d69e9SNathan Whitehorn 		return;
592e21d69e9SNathan Whitehorn 	}
593e21d69e9SNathan Whitehorn 
594e21d69e9SNathan Whitehorn 	phyp_hcall(H_CEDE); /* Re-enables interrupts internally */
595e21d69e9SNathan Whitehorn 	mtmsr(msr);
5967a8d25c0SNathan Whitehorn }
5977a8d25c0SNathan Whitehorn 
5987a8d25c0SNathan Whitehorn static void
chrp_smp_ap_init(platform_t platform)5997a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform)
6007a8d25c0SNathan Whitehorn {
6017a8d25c0SNathan Whitehorn 	if (!(mfmsr() & PSL_HV)) {
602f1e48417SNathan Whitehorn 		/* Register VPA */
603f0393bbfSWojciech Macek 		phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(hwref),
604f0393bbfSWojciech Macek 		    splpar_vpa[PCPU_GET(hwref)]);
605f1e48417SNathan Whitehorn 
6067a8d25c0SNathan Whitehorn 		/* Set interrupt priority */
6077a8d25c0SNathan Whitehorn 		phyp_hcall(H_CPPR, 0xff);
6087a8d25c0SNathan Whitehorn 	}
6097a8d25c0SNathan Whitehorn }
6107a8d25c0SNathan Whitehorn #else
6117a8d25c0SNathan Whitehorn static void
chrp_smp_ap_init(platform_t platform)6127a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform)
6137a8d25c0SNathan Whitehorn {
6147a8d25c0SNathan Whitehorn }
6157a8d25c0SNathan Whitehorn #endif
616