xref: /freebsd/sys/powerpc/pseries/platform_chrp.c (revision 108117cc22335234f817584a42704258209ca78c)
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 
337a8d25c0SNathan Whitehorn #include <sys/param.h>
347a8d25c0SNathan Whitehorn #include <sys/systm.h>
357a8d25c0SNathan Whitehorn #include <sys/kernel.h>
367a8d25c0SNathan Whitehorn #include <sys/bus.h>
377a8d25c0SNathan Whitehorn #include <sys/pcpu.h>
387a8d25c0SNathan Whitehorn #include <sys/proc.h>
39e21d69e9SNathan Whitehorn #include <sys/sched.h>
407a8d25c0SNathan Whitehorn #include <sys/smp.h>
417a8d25c0SNathan Whitehorn #include <vm/vm.h>
427a8d25c0SNathan Whitehorn #include <vm/pmap.h>
437a8d25c0SNathan Whitehorn 
447a8d25c0SNathan Whitehorn #include <machine/bus.h>
457a8d25c0SNathan Whitehorn #include <machine/cpu.h>
467a8d25c0SNathan Whitehorn #include <machine/hid.h>
477a8d25c0SNathan Whitehorn #include <machine/platformvar.h>
487a8d25c0SNathan Whitehorn #include <machine/rtas.h>
497a8d25c0SNathan Whitehorn #include <machine/smp.h>
507a8d25c0SNathan Whitehorn #include <machine/spr.h>
51258dbffeSNathan Whitehorn #include <machine/trap.h>
527a8d25c0SNathan Whitehorn 
537a8d25c0SNathan Whitehorn #include <dev/ofw/openfirm.h>
547a8d25c0SNathan Whitehorn #include <machine/ofw_machdep.h>
557a8d25c0SNathan Whitehorn 
567a8d25c0SNathan Whitehorn #include "platform_if.h"
577a8d25c0SNathan Whitehorn 
587a8d25c0SNathan Whitehorn #ifdef SMP
597a8d25c0SNathan Whitehorn extern void *ap_pcpu;
607a8d25c0SNathan Whitehorn #endif
617a8d25c0SNathan Whitehorn 
627a8d25c0SNathan Whitehorn #ifdef __powerpc64__
63f1e48417SNathan Whitehorn static uint8_t splpar_vpa[MAXCPU][640] __aligned(128); /* XXX: dpcpu */
647a8d25c0SNathan Whitehorn #endif
657a8d25c0SNathan Whitehorn 
667a8d25c0SNathan Whitehorn static vm_offset_t realmaxaddr = VM_MAX_ADDRESS;
677a8d25c0SNathan Whitehorn 
687a8d25c0SNathan Whitehorn static int chrp_probe(platform_t);
697a8d25c0SNathan Whitehorn static int chrp_attach(platform_t);
70c1cb22d7SNathan Whitehorn void chrp_mem_regions(platform_t, struct mem_region *phys, int *physsz,
71c1cb22d7SNathan Whitehorn     struct mem_region *avail, int *availsz);
727a8d25c0SNathan Whitehorn static vm_offset_t chrp_real_maxaddr(platform_t);
737a8d25c0SNathan Whitehorn static u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref);
747a8d25c0SNathan Whitehorn static int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref);
757a8d25c0SNathan Whitehorn static int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref);
767a8d25c0SNathan Whitehorn static int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref);
777a8d25c0SNathan Whitehorn static void chrp_smp_ap_init(platform_t);
78f0393bbfSWojciech Macek static int chrp_cpuref_init(void);
797a8d25c0SNathan Whitehorn #ifdef SMP
807a8d25c0SNathan Whitehorn static int chrp_smp_start_cpu(platform_t, struct pcpu *cpu);
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),
1067a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_smp_topo,	chrp_smp_topo),
1077a8d25c0SNathan Whitehorn #endif
1087a8d25c0SNathan Whitehorn 
1097a8d25c0SNathan Whitehorn 	PLATFORMMETHOD(platform_reset,		chrp_reset),
1107a8d25c0SNathan Whitehorn 
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
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
1327a8d25c0SNathan Whitehorn chrp_attach(platform_t plat)
1337a8d25c0SNathan Whitehorn {
13466fe9464SBjoern A. Zeeb #ifdef __powerpc64__
135f1e48417SNathan Whitehorn 	int i;
136f1e48417SNathan Whitehorn 
1377a8d25c0SNathan Whitehorn 	/* XXX: check for /rtas/ibm,hypertas-functions? */
1387a8d25c0SNathan Whitehorn 	if (!(mfmsr() & PSL_HV)) {
1397a8d25c0SNathan Whitehorn 		struct mem_region *phys, *avail;
1407a8d25c0SNathan Whitehorn 		int nphys, navail;
1417a8d25c0SNathan Whitehorn 		mem_regions(&phys, &nphys, &avail, &navail);
1427a8d25c0SNathan Whitehorn 		realmaxaddr = phys[0].mr_size;
1437a8d25c0SNathan Whitehorn 
1447a8d25c0SNathan Whitehorn 		pmap_mmu_install("mmu_phyp", BUS_PROBE_SPECIFIC);
1457a8d25c0SNathan Whitehorn 		cpu_idle_hook = phyp_cpu_idle;
1467a8d25c0SNathan Whitehorn 
1477a8d25c0SNathan Whitehorn 		/* Set up important VPA fields */
148f1e48417SNathan Whitehorn 		for (i = 0; i < MAXCPU; i++) {
149f1e48417SNathan Whitehorn 			bzero(splpar_vpa[i], sizeof(splpar_vpa));
150f1e48417SNathan Whitehorn 			/* First two: VPA size */
151f1e48417SNathan Whitehorn 			splpar_vpa[i][4] =
152f1e48417SNathan Whitehorn 			    (uint8_t)((sizeof(splpar_vpa[i]) >> 8) & 0xff);
153f1e48417SNathan Whitehorn 			splpar_vpa[i][5] =
154f1e48417SNathan Whitehorn 			    (uint8_t)(sizeof(splpar_vpa[i]) & 0xff);
155f1e48417SNathan Whitehorn 			splpar_vpa[i][0xba] = 1;	/* Maintain FPRs */
156f1e48417SNathan Whitehorn 			splpar_vpa[i][0xbb] = 1;	/* Maintain PMCs */
157f1e48417SNathan Whitehorn 			splpar_vpa[i][0xfc] = 0xff;	/* Maintain full SLB */
158f1e48417SNathan Whitehorn 			splpar_vpa[i][0xfd] = 0xff;
159f1e48417SNathan Whitehorn 			splpar_vpa[i][0xff] = 1;	/* Maintain Altivec */
160f1e48417SNathan Whitehorn 		}
1617a8d25c0SNathan Whitehorn 		mb();
1627a8d25c0SNathan Whitehorn 
1637a8d25c0SNathan Whitehorn 		/* Set up hypervisor CPU stuff */
1647a8d25c0SNathan Whitehorn 		chrp_smp_ap_init(plat);
1657a8d25c0SNathan Whitehorn 	}
1667a8d25c0SNathan Whitehorn #endif
167f0393bbfSWojciech Macek 	chrp_cpuref_init();
1687a8d25c0SNathan Whitehorn 
1699f706727SNathan Whitehorn 	/* Some systems (e.g. QEMU) need Open Firmware to stand down */
1709f706727SNathan Whitehorn 	ofw_quiesce();
1719f706727SNathan Whitehorn 
1727a8d25c0SNathan Whitehorn 	return (0);
1737a8d25c0SNathan Whitehorn }
1747a8d25c0SNathan Whitehorn 
175c1cb22d7SNathan Whitehorn static int
176f5dfbe2fSAndreas Tobler parse_drconf_memory(struct mem_region *ofmem, int *msz,
177f5dfbe2fSAndreas Tobler 		    struct mem_region *ofavail, int *asz)
1787a8d25c0SNathan Whitehorn {
179c1cb22d7SNathan Whitehorn 	phandle_t phandle;
180c1cb22d7SNathan Whitehorn 	vm_offset_t base;
181c1cb22d7SNathan Whitehorn 	int i, idx, len, lasz, lmsz, res;
182f5dfbe2fSAndreas Tobler 	uint32_t flags, lmb_size[2];
183509142e1SNathan Whitehorn 	uint32_t *dmem;
184c1cb22d7SNathan Whitehorn 
185c1cb22d7SNathan Whitehorn 	lmsz = *msz;
186c1cb22d7SNathan Whitehorn 	lasz = *asz;
187c1cb22d7SNathan Whitehorn 
188c1cb22d7SNathan Whitehorn 	phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory");
189c1cb22d7SNathan Whitehorn 	if (phandle == -1)
190c1cb22d7SNathan Whitehorn 		/* No drconf node, return. */
191c1cb22d7SNathan Whitehorn 		return (0);
192c1cb22d7SNathan Whitehorn 
193509142e1SNathan Whitehorn 	res = OF_getencprop(phandle, "ibm,lmb-size", lmb_size,
194509142e1SNathan Whitehorn 	    sizeof(lmb_size));
195c1cb22d7SNathan Whitehorn 	if (res == -1)
196c1cb22d7SNathan Whitehorn 		return (0);
197c1cb22d7SNathan Whitehorn 	printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20);
198c1cb22d7SNathan Whitehorn 
199c1cb22d7SNathan Whitehorn 	/* Parse the /ibm,dynamic-memory.
200c1cb22d7SNathan Whitehorn 	   The first position gives the # of entries. The next two words
201c1cb22d7SNathan Whitehorn  	   reflect the address of the memory block. The next four words are
202c1cb22d7SNathan Whitehorn 	   the DRC index, reserved, list index and flags.
203c1cb22d7SNathan Whitehorn 	   (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory)
204c1cb22d7SNathan Whitehorn 
205c1cb22d7SNathan Whitehorn 	    #el  Addr   DRC-idx  res   list-idx  flags
206c1cb22d7SNathan Whitehorn 	   -------------------------------------------------
207c1cb22d7SNathan Whitehorn 	   | 4 |   8   |   4   |   4   |   4   |   4   |....
208c1cb22d7SNathan Whitehorn 	   -------------------------------------------------
209c1cb22d7SNathan Whitehorn 	*/
210c1cb22d7SNathan Whitehorn 
211c1cb22d7SNathan Whitehorn 	len = OF_getproplen(phandle, "ibm,dynamic-memory");
212c1cb22d7SNathan Whitehorn 	if (len > 0) {
213c1cb22d7SNathan Whitehorn 
214c1cb22d7SNathan Whitehorn 		/* We have to use a variable length array on the stack
215c1cb22d7SNathan Whitehorn 		   since we have very limited stack space.
216c1cb22d7SNathan Whitehorn 		*/
217c1cb22d7SNathan Whitehorn 		cell_t arr[len/sizeof(cell_t)];
218c1cb22d7SNathan Whitehorn 
219509142e1SNathan Whitehorn 		res = OF_getencprop(phandle, "ibm,dynamic-memory", arr,
220c1cb22d7SNathan Whitehorn 		    sizeof(arr));
221c1cb22d7SNathan Whitehorn 		if (res == -1)
222c1cb22d7SNathan Whitehorn 			return (0);
223c1cb22d7SNathan Whitehorn 
224c1cb22d7SNathan Whitehorn 		/* Number of elements */
225c1cb22d7SNathan Whitehorn 		idx = arr[0];
226c1cb22d7SNathan Whitehorn 
227f5dfbe2fSAndreas Tobler 		/* First address, in arr[1], arr[2]*/
228509142e1SNathan Whitehorn 		dmem = &arr[1];
229c1cb22d7SNathan Whitehorn 
230c1cb22d7SNathan Whitehorn 		for (i = 0; i < idx; i++) {
231509142e1SNathan Whitehorn 			base = ((uint64_t)dmem[0] << 32) + dmem[1];
232509142e1SNathan Whitehorn 			dmem += 4;
233509142e1SNathan Whitehorn 			flags = dmem[1];
234c1cb22d7SNathan Whitehorn 			/* Use region only if available and not reserved. */
235c1cb22d7SNathan Whitehorn 			if ((flags & 0x8) && !(flags & 0x80)) {
236c1cb22d7SNathan Whitehorn 				ofmem[lmsz].mr_start = base;
237c1cb22d7SNathan Whitehorn 				ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1];
238c1cb22d7SNathan Whitehorn 				ofavail[lasz].mr_start = base;
239c1cb22d7SNathan Whitehorn 				ofavail[lasz].mr_size = (vm_size_t)lmb_size[1];
240c1cb22d7SNathan Whitehorn 				lmsz++;
241c1cb22d7SNathan Whitehorn 				lasz++;
242c1cb22d7SNathan Whitehorn 			}
243509142e1SNathan Whitehorn 			dmem += 2;
244c1cb22d7SNathan Whitehorn 		}
245c1cb22d7SNathan Whitehorn 	}
246c1cb22d7SNathan Whitehorn 
247c1cb22d7SNathan Whitehorn 	*msz = lmsz;
248c1cb22d7SNathan Whitehorn 	*asz = lasz;
249c1cb22d7SNathan Whitehorn 
250c1cb22d7SNathan Whitehorn 	return (1);
251c1cb22d7SNathan Whitehorn }
252c1cb22d7SNathan Whitehorn 
253c1cb22d7SNathan Whitehorn void
254c1cb22d7SNathan Whitehorn chrp_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
255c1cb22d7SNathan Whitehorn     struct mem_region *avail, int *availsz)
256c1cb22d7SNathan Whitehorn {
257c1cb22d7SNathan Whitehorn 	vm_offset_t maxphysaddr;
258c1cb22d7SNathan Whitehorn 	int i;
259c1cb22d7SNathan Whitehorn 
2607a8d25c0SNathan Whitehorn 	ofw_mem_regions(phys, physsz, avail, availsz);
261f5dfbe2fSAndreas Tobler 	parse_drconf_memory(phys, physsz, avail, availsz);
262c1cb22d7SNathan Whitehorn 
263c1cb22d7SNathan Whitehorn 	/*
264c1cb22d7SNathan Whitehorn 	 * On some firmwares (SLOF), some memory may be marked available that
265c1cb22d7SNathan Whitehorn 	 * doesn't actually exist. This manifests as an extension of the last
266c1cb22d7SNathan Whitehorn 	 * available segment past the end of physical memory, so truncate that
267c1cb22d7SNathan Whitehorn 	 * one.
268c1cb22d7SNathan Whitehorn 	 */
269c1cb22d7SNathan Whitehorn 	maxphysaddr = 0;
270c1cb22d7SNathan Whitehorn 	for (i = 0; i < *physsz; i++)
271c1cb22d7SNathan Whitehorn 		if (phys[i].mr_start + phys[i].mr_size > maxphysaddr)
272c1cb22d7SNathan Whitehorn 			maxphysaddr = phys[i].mr_start + phys[i].mr_size;
273c1cb22d7SNathan Whitehorn 
274c1cb22d7SNathan Whitehorn 	for (i = 0; i < *availsz; i++)
275c1cb22d7SNathan Whitehorn 		if (avail[i].mr_start + avail[i].mr_size > maxphysaddr)
276c1cb22d7SNathan Whitehorn 			avail[i].mr_size = maxphysaddr - avail[i].mr_start;
2777a8d25c0SNathan Whitehorn }
2787a8d25c0SNathan Whitehorn 
2797a8d25c0SNathan Whitehorn static vm_offset_t
2807a8d25c0SNathan Whitehorn chrp_real_maxaddr(platform_t plat)
2817a8d25c0SNathan Whitehorn {
2827a8d25c0SNathan Whitehorn 	return (realmaxaddr);
2837a8d25c0SNathan Whitehorn }
2847a8d25c0SNathan Whitehorn 
2857a8d25c0SNathan Whitehorn static u_long
2867a8d25c0SNathan Whitehorn chrp_timebase_freq(platform_t plat, struct cpuref *cpuref)
2877a8d25c0SNathan Whitehorn {
288a00ce4e8SJustin Hibbits 	phandle_t cpus, cpunode;
2897a8d25c0SNathan Whitehorn 	int32_t ticks = -1;
290a00ce4e8SJustin Hibbits 	int res;
291a00ce4e8SJustin Hibbits 	char buf[8];
2927a8d25c0SNathan Whitehorn 
293a00ce4e8SJustin Hibbits 	cpus = OF_finddevice("/cpus");
294*108117ccSOleksandr Tymoshenko 	if (cpus == -1)
295a00ce4e8SJustin Hibbits 		panic("CPU tree not found on Open Firmware\n");
2967a8d25c0SNathan Whitehorn 
297a00ce4e8SJustin Hibbits 	for (cpunode = OF_child(cpus); cpunode != 0; cpunode = OF_peer(cpunode)) {
298a00ce4e8SJustin Hibbits 		res = OF_getprop(cpunode, "device_type", buf, sizeof(buf));
299a00ce4e8SJustin Hibbits 		if (res > 0 && strcmp(buf, "cpu") == 0)
300a00ce4e8SJustin Hibbits 			break;
301a00ce4e8SJustin Hibbits 	}
302a00ce4e8SJustin Hibbits 	if (cpunode <= 0)
303a00ce4e8SJustin Hibbits 		panic("CPU node not found on Open Firmware\n");
304a00ce4e8SJustin Hibbits 
305a00ce4e8SJustin Hibbits 	OF_getencprop(cpunode, "timebase-frequency", &ticks, sizeof(ticks));
3067a8d25c0SNathan Whitehorn 
3077a8d25c0SNathan Whitehorn 	if (ticks <= 0)
3087a8d25c0SNathan Whitehorn 		panic("Unable to determine timebase frequency!");
3097a8d25c0SNathan Whitehorn 
3107a8d25c0SNathan Whitehorn 	return (ticks);
3117a8d25c0SNathan Whitehorn }
3127a8d25c0SNathan Whitehorn 
3137a8d25c0SNathan Whitehorn static int
31409f07b00SNathan Whitehorn chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
3157a8d25c0SNathan Whitehorn {
3167a8d25c0SNathan Whitehorn 
317f0393bbfSWojciech Macek 	if (platform_cpuref_valid == 0)
318f0393bbfSWojciech Macek 		return (EINVAL);
3197a8d25c0SNathan Whitehorn 
320f0393bbfSWojciech Macek 	cpuref->cr_cpuid = 0;
321f0393bbfSWojciech Macek 	cpuref->cr_hwref = platform_cpuref[0].cr_hwref;
3227a8d25c0SNathan Whitehorn 
3237a8d25c0SNathan Whitehorn 	return (0);
3247a8d25c0SNathan Whitehorn }
3257a8d25c0SNathan Whitehorn 
3267a8d25c0SNathan Whitehorn static int
3277a8d25c0SNathan Whitehorn chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
3287a8d25c0SNathan Whitehorn {
329f0393bbfSWojciech Macek 	int id;
3307a8d25c0SNathan Whitehorn 
331f0393bbfSWojciech Macek 	if (platform_cpuref_valid == 0)
332f0393bbfSWojciech Macek 		return (EINVAL);
3337a8d25c0SNathan Whitehorn 
334f0393bbfSWojciech Macek 	id = cpuref->cr_cpuid + 1;
335f0393bbfSWojciech Macek 	if (id >= platform_cpuref_cnt)
3367a8d25c0SNathan Whitehorn 		return (ENOENT);
33709f07b00SNathan Whitehorn 
338f0393bbfSWojciech Macek 	cpuref->cr_cpuid = platform_cpuref[id].cr_cpuid;
339f0393bbfSWojciech Macek 	cpuref->cr_hwref = platform_cpuref[id].cr_hwref;
34009f07b00SNathan Whitehorn 
34109f07b00SNathan Whitehorn 	return (0);
3427a8d25c0SNathan Whitehorn }
3437a8d25c0SNathan Whitehorn 
3447a8d25c0SNathan Whitehorn static int
3457a8d25c0SNathan Whitehorn chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
3467a8d25c0SNathan Whitehorn {
3477a8d25c0SNathan Whitehorn 
348f0393bbfSWojciech Macek 	cpuref->cr_cpuid = platform_cpuref[0].cr_cpuid;
349f0393bbfSWojciech Macek 	cpuref->cr_hwref = platform_cpuref[0].cr_hwref;
350f0393bbfSWojciech Macek 	return (0);
351f0393bbfSWojciech Macek }
3527a8d25c0SNathan Whitehorn 
353f0393bbfSWojciech Macek static int
354f0393bbfSWojciech Macek chrp_cpuref_init(void)
355f0393bbfSWojciech Macek {
356f0393bbfSWojciech Macek 	phandle_t cpu, dev;
357f0393bbfSWojciech Macek 	char buf[32];
358f0393bbfSWojciech Macek 	int a, res;
359f0393bbfSWojciech Macek 	cell_t interrupt_servers[32];
360f0393bbfSWojciech Macek 	uint64_t bsp;
3617a8d25c0SNathan Whitehorn 
362f0393bbfSWojciech Macek 	if (platform_cpuref_valid)
363f0393bbfSWojciech Macek 		return (0);
3647a8d25c0SNathan Whitehorn 
365f0393bbfSWojciech Macek 	dev = OF_peer(0);
366f0393bbfSWojciech Macek 	dev = OF_child(dev);
367f0393bbfSWojciech Macek 	while (dev != 0) {
368f0393bbfSWojciech Macek 		res = OF_getprop(dev, "name", buf, sizeof(buf));
369f0393bbfSWojciech Macek 		if (res > 0 && strcmp(buf, "cpus") == 0)
370f0393bbfSWojciech Macek 			break;
371f0393bbfSWojciech Macek 		dev = OF_peer(dev);
372f0393bbfSWojciech Macek 	}
373f0393bbfSWojciech Macek 
374f0393bbfSWojciech Macek 	bsp = 0;
375f0393bbfSWojciech Macek 	for (cpu = OF_child(dev); cpu != 0; cpu = OF_peer(cpu)) {
376f0393bbfSWojciech Macek 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
377f0393bbfSWojciech Macek 		if (res > 0 && strcmp(buf, "cpu") == 0) {
378f0393bbfSWojciech Macek 			res = OF_getproplen(cpu, "ibm,ppc-interrupt-server#s");
379f0393bbfSWojciech Macek 			if (res > 0) {
380f0393bbfSWojciech Macek 
381f0393bbfSWojciech Macek 
382f0393bbfSWojciech Macek 				OF_getencprop(cpu, "ibm,ppc-interrupt-server#s",
383f0393bbfSWojciech Macek 				    interrupt_servers, res);
384f0393bbfSWojciech Macek 
385f0393bbfSWojciech Macek 				for (a = 0; a < res/sizeof(cell_t); a++) {
386f0393bbfSWojciech Macek 					platform_cpuref[platform_cpuref_cnt].cr_hwref = interrupt_servers[a];
387f0393bbfSWojciech Macek 					platform_cpuref[platform_cpuref_cnt].cr_cpuid = platform_cpuref_cnt;
388f0393bbfSWojciech Macek 
389f0393bbfSWojciech Macek 					platform_cpuref_cnt++;
390f0393bbfSWojciech Macek 				}
391f0393bbfSWojciech Macek 			}
392f0393bbfSWojciech Macek 		}
393f0393bbfSWojciech Macek 	}
394f0393bbfSWojciech Macek 
395f0393bbfSWojciech Macek 	platform_cpuref_valid = 1;
3967a8d25c0SNathan Whitehorn 
3977a8d25c0SNathan Whitehorn 	return (0);
3987a8d25c0SNathan Whitehorn }
3997a8d25c0SNathan Whitehorn 
400f0393bbfSWojciech Macek 
4017a8d25c0SNathan Whitehorn #ifdef SMP
4027a8d25c0SNathan Whitehorn static int
4037a8d25c0SNathan Whitehorn chrp_smp_start_cpu(platform_t plat, struct pcpu *pc)
4047a8d25c0SNathan Whitehorn {
4057a8d25c0SNathan Whitehorn 	cell_t start_cpu;
4067a8d25c0SNathan Whitehorn 	int result, err, timeout;
4077a8d25c0SNathan Whitehorn 
4087a8d25c0SNathan Whitehorn 	if (!rtas_exists()) {
4097a8d25c0SNathan Whitehorn 		printf("RTAS uninitialized: unable to start AP %d\n",
4107a8d25c0SNathan Whitehorn 		    pc->pc_cpuid);
4117a8d25c0SNathan Whitehorn 		return (ENXIO);
4127a8d25c0SNathan Whitehorn 	}
4137a8d25c0SNathan Whitehorn 
4147a8d25c0SNathan Whitehorn 	start_cpu = rtas_token_lookup("start-cpu");
4157a8d25c0SNathan Whitehorn 	if (start_cpu == -1) {
4167a8d25c0SNathan Whitehorn 		printf("RTAS unknown method: unable to start AP %d\n",
4177a8d25c0SNathan Whitehorn 		    pc->pc_cpuid);
4187a8d25c0SNathan Whitehorn 		return (ENXIO);
4197a8d25c0SNathan Whitehorn 	}
4207a8d25c0SNathan Whitehorn 
4217a8d25c0SNathan Whitehorn 	ap_pcpu = pc;
4227a8d25c0SNathan Whitehorn 	powerpc_sync();
4237a8d25c0SNathan Whitehorn 
424f0393bbfSWojciech Macek 	result = rtas_call_method(start_cpu, 3, 1, pc->pc_hwref, EXC_RST, pc,
4257a8d25c0SNathan Whitehorn 	    &err);
4267a8d25c0SNathan Whitehorn 	if (result < 0 || err != 0) {
4277a8d25c0SNathan Whitehorn 		printf("RTAS error (%d/%d): unable to start AP %d\n",
4287a8d25c0SNathan Whitehorn 		    result, err, pc->pc_cpuid);
4297a8d25c0SNathan Whitehorn 		return (ENXIO);
4307a8d25c0SNathan Whitehorn 	}
4317a8d25c0SNathan Whitehorn 
4327a8d25c0SNathan Whitehorn 	timeout = 10000;
4337a8d25c0SNathan Whitehorn 	while (!pc->pc_awake && timeout--)
4347a8d25c0SNathan Whitehorn 		DELAY(100);
4357a8d25c0SNathan Whitehorn 
4367a8d25c0SNathan Whitehorn 	return ((pc->pc_awake) ? 0 : EBUSY);
4377a8d25c0SNathan Whitehorn }
4387a8d25c0SNathan Whitehorn 
4397a8d25c0SNathan Whitehorn static struct cpu_group *
4407a8d25c0SNathan Whitehorn chrp_smp_topo(platform_t plat)
4417a8d25c0SNathan Whitehorn {
44209f07b00SNathan Whitehorn 	struct pcpu *pc, *last_pc;
44309f07b00SNathan Whitehorn 	int i, ncores, ncpus;
4447a8d25c0SNathan Whitehorn 
44509f07b00SNathan Whitehorn 	ncores = ncpus = 0;
44609f07b00SNathan Whitehorn 	last_pc = NULL;
44709f07b00SNathan Whitehorn 	for (i = 0; i <= mp_maxid; i++) {
44809f07b00SNathan Whitehorn 		pc = pcpu_find(i);
44909f07b00SNathan Whitehorn 		if (pc == NULL)
450f9d6e0a5SNathan Whitehorn 			continue;
45109f07b00SNathan Whitehorn 		if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref)
45209f07b00SNathan Whitehorn 			ncores++;
45309f07b00SNathan Whitehorn 		last_pc = pc;
45409f07b00SNathan Whitehorn 		ncpus++;
455f9d6e0a5SNathan Whitehorn 	}
456f9d6e0a5SNathan Whitehorn 
45709f07b00SNathan Whitehorn 	if (ncpus % ncores != 0) {
4587a8d25c0SNathan Whitehorn 		printf("WARNING: Irregular SMP topology. Performance may be "
45909f07b00SNathan Whitehorn 		     "suboptimal (%d CPUS, %d cores)\n", ncpus, ncores);
4607a8d25c0SNathan Whitehorn 		return (smp_topo_none());
4617a8d25c0SNathan Whitehorn 	}
4627a8d25c0SNathan Whitehorn 
4637a8d25c0SNathan Whitehorn 	/* Don't do anything fancier for non-threaded SMP */
46409f07b00SNathan Whitehorn 	if (ncpus == ncores)
4657a8d25c0SNathan Whitehorn 		return (smp_topo_none());
4667a8d25c0SNathan Whitehorn 
46709f07b00SNathan Whitehorn 	return (smp_topo_1level(CG_SHARE_L1, ncpus / ncores, CG_FLAG_SMT));
4687a8d25c0SNathan Whitehorn }
4697a8d25c0SNathan Whitehorn #endif
4707a8d25c0SNathan Whitehorn 
4717a8d25c0SNathan Whitehorn static void
4727a8d25c0SNathan Whitehorn chrp_reset(platform_t platform)
4737a8d25c0SNathan Whitehorn {
4747a8d25c0SNathan Whitehorn 	OF_reboot();
4757a8d25c0SNathan Whitehorn }
4767a8d25c0SNathan Whitehorn 
4777a8d25c0SNathan Whitehorn #ifdef __powerpc64__
4787a8d25c0SNathan Whitehorn static void
4797a8d25c0SNathan Whitehorn phyp_cpu_idle(sbintime_t sbt)
4807a8d25c0SNathan Whitehorn {
481e21d69e9SNathan Whitehorn 	register_t msr;
482e21d69e9SNathan Whitehorn 
483e21d69e9SNathan Whitehorn 	msr = mfmsr();
484e21d69e9SNathan Whitehorn 
485e21d69e9SNathan Whitehorn 	mtmsr(msr & ~PSL_EE);
486e21d69e9SNathan Whitehorn 	if (sched_runnable()) {
487e21d69e9SNathan Whitehorn 		mtmsr(msr);
488e21d69e9SNathan Whitehorn 		return;
489e21d69e9SNathan Whitehorn 	}
490e21d69e9SNathan Whitehorn 
491e21d69e9SNathan Whitehorn 	phyp_hcall(H_CEDE); /* Re-enables interrupts internally */
492e21d69e9SNathan Whitehorn 	mtmsr(msr);
4937a8d25c0SNathan Whitehorn }
4947a8d25c0SNathan Whitehorn 
4957a8d25c0SNathan Whitehorn static void
4967a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform)
4977a8d25c0SNathan Whitehorn {
4987a8d25c0SNathan Whitehorn 	if (!(mfmsr() & PSL_HV)) {
499f1e48417SNathan Whitehorn 		/* Register VPA */
500f0393bbfSWojciech Macek 		phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(hwref),
501f0393bbfSWojciech Macek 		    splpar_vpa[PCPU_GET(hwref)]);
502f1e48417SNathan Whitehorn 
5037a8d25c0SNathan Whitehorn 		/* Set interrupt priority */
5047a8d25c0SNathan Whitehorn 		phyp_hcall(H_CPPR, 0xff);
5057a8d25c0SNathan Whitehorn 	}
5067a8d25c0SNathan Whitehorn }
5077a8d25c0SNathan Whitehorn #else
5087a8d25c0SNathan Whitehorn static void
5097a8d25c0SNathan Whitehorn chrp_smp_ap_init(platform_t platform)
5107a8d25c0SNathan Whitehorn {
5117a8d25c0SNathan Whitehorn }
5127a8d25c0SNathan Whitehorn #endif
5137a8d25c0SNathan Whitehorn 
514