1255643Snwhitehorn/*-
2255643Snwhitehorn * Copyright (c) 2008 Marcel Moolenaar
3255643Snwhitehorn * Copyright (c) 2009 Nathan Whitehorn
4255643Snwhitehorn * All rights reserved.
5255643Snwhitehorn *
6255643Snwhitehorn * Redistribution and use in source and binary forms, with or without
7255643Snwhitehorn * modification, are permitted provided that the following conditions
8255643Snwhitehorn * are met:
9255643Snwhitehorn *
10255643Snwhitehorn * 1. Redistributions of source code must retain the above copyright
11255643Snwhitehorn *    notice, this list of conditions and the following disclaimer.
12255643Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
13255643Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
14255643Snwhitehorn *    documentation and/or other materials provided with the distribution.
15255643Snwhitehorn *
16255643Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17255643Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18255643Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19255643Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20255643Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21255643Snwhitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22255643Snwhitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23255643Snwhitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24255643Snwhitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25255643Snwhitehorn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26255643Snwhitehorn */
27255643Snwhitehorn
28255643Snwhitehorn#include <sys/cdefs.h>
29255643Snwhitehorn__FBSDID("$FreeBSD: releng/10.3/sys/powerpc/pseries/platform_chrp.c 266020 2014-05-14 14:17:51Z ian $");
30255643Snwhitehorn
31255643Snwhitehorn#include <sys/param.h>
32255643Snwhitehorn#include <sys/systm.h>
33255643Snwhitehorn#include <sys/kernel.h>
34255643Snwhitehorn#include <sys/bus.h>
35255643Snwhitehorn#include <sys/pcpu.h>
36255643Snwhitehorn#include <sys/proc.h>
37255643Snwhitehorn#include <sys/smp.h>
38255643Snwhitehorn#include <vm/vm.h>
39255643Snwhitehorn#include <vm/pmap.h>
40255643Snwhitehorn
41255643Snwhitehorn#include <machine/bus.h>
42255643Snwhitehorn#include <machine/cpu.h>
43255643Snwhitehorn#include <machine/hid.h>
44255643Snwhitehorn#include <machine/platformvar.h>
45255643Snwhitehorn#include <machine/pmap.h>
46255643Snwhitehorn#include <machine/rtas.h>
47255643Snwhitehorn#include <machine/smp.h>
48255643Snwhitehorn#include <machine/spr.h>
49265974Sian#include <machine/trap.h>
50255643Snwhitehorn
51255643Snwhitehorn#include <dev/ofw/openfirm.h>
52255643Snwhitehorn#include <machine/ofw_machdep.h>
53255643Snwhitehorn
54255643Snwhitehorn#include "platform_if.h"
55255643Snwhitehorn
56255643Snwhitehorn#ifdef SMP
57255643Snwhitehornextern void *ap_pcpu;
58255643Snwhitehorn#endif
59255643Snwhitehorn
60255643Snwhitehorn#ifdef __powerpc64__
61255643Snwhitehornstatic uint8_t splpar_vpa[640] __aligned(64);
62255643Snwhitehorn#endif
63255643Snwhitehorn
64255643Snwhitehornstatic vm_offset_t realmaxaddr = VM_MAX_ADDRESS;
65255643Snwhitehorn
66255643Snwhitehornstatic int chrp_probe(platform_t);
67255643Snwhitehornstatic int chrp_attach(platform_t);
68266020Sianvoid chrp_mem_regions(platform_t, struct mem_region *phys, int *physsz,
69266020Sian    struct mem_region *avail, int *availsz);
70255643Snwhitehornstatic vm_offset_t chrp_real_maxaddr(platform_t);
71255643Snwhitehornstatic u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref);
72255643Snwhitehornstatic int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref);
73255643Snwhitehornstatic int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref);
74255643Snwhitehornstatic int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref);
75255643Snwhitehornstatic void chrp_smp_ap_init(platform_t);
76255643Snwhitehorn#ifdef SMP
77255643Snwhitehornstatic int chrp_smp_start_cpu(platform_t, struct pcpu *cpu);
78255643Snwhitehornstatic struct cpu_group *chrp_smp_topo(platform_t plat);
79255643Snwhitehorn#endif
80255643Snwhitehornstatic void chrp_reset(platform_t);
81255643Snwhitehorn#ifdef __powerpc64__
82255643Snwhitehorn#include "phyp-hvcall.h"
83255643Snwhitehornstatic void phyp_cpu_idle(sbintime_t sbt);
84255643Snwhitehorn#endif
85255643Snwhitehorn
86255643Snwhitehornstatic platform_method_t chrp_methods[] = {
87255643Snwhitehorn	PLATFORMMETHOD(platform_probe, 		chrp_probe),
88255643Snwhitehorn	PLATFORMMETHOD(platform_attach,		chrp_attach),
89255643Snwhitehorn	PLATFORMMETHOD(platform_mem_regions,	chrp_mem_regions),
90255643Snwhitehorn	PLATFORMMETHOD(platform_real_maxaddr,	chrp_real_maxaddr),
91255643Snwhitehorn	PLATFORMMETHOD(platform_timebase_freq,	chrp_timebase_freq),
92255643Snwhitehorn
93255643Snwhitehorn	PLATFORMMETHOD(platform_smp_ap_init,	chrp_smp_ap_init),
94255643Snwhitehorn	PLATFORMMETHOD(platform_smp_first_cpu,	chrp_smp_first_cpu),
95255643Snwhitehorn	PLATFORMMETHOD(platform_smp_next_cpu,	chrp_smp_next_cpu),
96255643Snwhitehorn	PLATFORMMETHOD(platform_smp_get_bsp,	chrp_smp_get_bsp),
97255643Snwhitehorn#ifdef SMP
98255643Snwhitehorn	PLATFORMMETHOD(platform_smp_start_cpu,	chrp_smp_start_cpu),
99255643Snwhitehorn	PLATFORMMETHOD(platform_smp_topo,	chrp_smp_topo),
100255643Snwhitehorn#endif
101255643Snwhitehorn
102255643Snwhitehorn	PLATFORMMETHOD(platform_reset,		chrp_reset),
103255643Snwhitehorn
104255643Snwhitehorn	{ 0, 0 }
105255643Snwhitehorn};
106255643Snwhitehorn
107255643Snwhitehornstatic platform_def_t chrp_platform = {
108255643Snwhitehorn	"chrp",
109255643Snwhitehorn	chrp_methods,
110255643Snwhitehorn	0
111255643Snwhitehorn};
112255643Snwhitehorn
113255643SnwhitehornPLATFORM_DEF(chrp_platform);
114255643Snwhitehorn
115255643Snwhitehornstatic int
116255643Snwhitehornchrp_probe(platform_t plat)
117255643Snwhitehorn{
118255643Snwhitehorn	if (OF_finddevice("/memory") != -1 || OF_finddevice("/memory@0") != -1)
119255643Snwhitehorn		return (BUS_PROBE_GENERIC);
120255643Snwhitehorn
121255643Snwhitehorn	return (ENXIO);
122255643Snwhitehorn}
123255643Snwhitehorn
124255643Snwhitehornstatic int
125255643Snwhitehornchrp_attach(platform_t plat)
126255643Snwhitehorn{
127255643Snwhitehorn#ifdef __powerpc64__
128255643Snwhitehorn	/* XXX: check for /rtas/ibm,hypertas-functions? */
129255643Snwhitehorn	if (!(mfmsr() & PSL_HV)) {
130255643Snwhitehorn		struct mem_region *phys, *avail;
131255643Snwhitehorn		int nphys, navail;
132255643Snwhitehorn		mem_regions(&phys, &nphys, &avail, &navail);
133255643Snwhitehorn		realmaxaddr = phys[0].mr_size;
134255643Snwhitehorn
135255643Snwhitehorn		pmap_mmu_install("mmu_phyp", BUS_PROBE_SPECIFIC);
136255643Snwhitehorn		cpu_idle_hook = phyp_cpu_idle;
137255643Snwhitehorn
138255643Snwhitehorn		/* Set up important VPA fields */
139255643Snwhitehorn		bzero(splpar_vpa, sizeof(splpar_vpa));
140255643Snwhitehorn		splpar_vpa[4] = (uint8_t)((sizeof(splpar_vpa) >> 8) & 0xff);
141255643Snwhitehorn		splpar_vpa[5] = (uint8_t)(sizeof(splpar_vpa) & 0xff);
142255643Snwhitehorn		splpar_vpa[0xba] = 1;			/* Maintain FPRs */
143255643Snwhitehorn		splpar_vpa[0xbb] = 1;			/* Maintain PMCs */
144255643Snwhitehorn		splpar_vpa[0xfc] = 0xff;		/* Maintain full SLB */
145255643Snwhitehorn		splpar_vpa[0xfd] = 0xff;
146255643Snwhitehorn		splpar_vpa[0xff] = 1;			/* Maintain Altivec */
147255643Snwhitehorn		mb();
148255643Snwhitehorn
149255643Snwhitehorn		/* Set up hypervisor CPU stuff */
150255643Snwhitehorn		chrp_smp_ap_init(plat);
151255643Snwhitehorn	}
152255643Snwhitehorn#endif
153255643Snwhitehorn
154255910Snwhitehorn	/* Some systems (e.g. QEMU) need Open Firmware to stand down */
155255910Snwhitehorn	ofw_quiesce();
156255910Snwhitehorn
157255643Snwhitehorn	return (0);
158255643Snwhitehorn}
159255643Snwhitehorn
160266020Sianstatic int
161266020Sianparse_drconf_memory(int *msz, int *asz, struct mem_region *ofmem,
162266020Sian		    struct mem_region *ofavail)
163266020Sian{
164266020Sian	phandle_t phandle;
165266020Sian	vm_offset_t base;
166266020Sian	int i, idx, len, lasz, lmsz, res;
167266020Sian	uint32_t lmb_size[2];
168266020Sian	unsigned long *dmem, flags;
169266020Sian
170266020Sian	lmsz = *msz;
171266020Sian	lasz = *asz;
172266020Sian
173266020Sian	phandle = OF_finddevice("/ibm,dynamic-reconfiguration-memory");
174266020Sian	if (phandle == -1)
175266020Sian		/* No drconf node, return. */
176266020Sian		return (0);
177266020Sian
178266020Sian	res = OF_getprop(phandle, "ibm,lmb-size", lmb_size, sizeof(lmb_size));
179266020Sian	if (res == -1)
180266020Sian		return (0);
181266020Sian	printf("Logical Memory Block size: %d MB\n", lmb_size[1] >> 20);
182266020Sian
183266020Sian	/* Parse the /ibm,dynamic-memory.
184266020Sian	   The first position gives the # of entries. The next two words
185266020Sian 	   reflect the address of the memory block. The next four words are
186266020Sian	   the DRC index, reserved, list index and flags.
187266020Sian	   (see PAPR C.6.6.2 ibm,dynamic-reconfiguration-memory)
188266020Sian
189266020Sian	    #el  Addr   DRC-idx  res   list-idx  flags
190266020Sian	   -------------------------------------------------
191266020Sian	   | 4 |   8   |   4   |   4   |   4   |   4   |....
192266020Sian	   -------------------------------------------------
193266020Sian	*/
194266020Sian
195266020Sian	len = OF_getproplen(phandle, "ibm,dynamic-memory");
196266020Sian	if (len > 0) {
197266020Sian
198266020Sian		/* We have to use a variable length array on the stack
199266020Sian		   since we have very limited stack space.
200266020Sian		*/
201266020Sian		cell_t arr[len/sizeof(cell_t)];
202266020Sian
203266020Sian		res = OF_getprop(phandle, "ibm,dynamic-memory", &arr,
204266020Sian				 sizeof(arr));
205266020Sian		if (res == -1)
206266020Sian			return (0);
207266020Sian
208266020Sian		/* Number of elements */
209266020Sian		idx = arr[0];
210266020Sian
211266020Sian		/* First address. */
212266020Sian		dmem = (void*)&arr[1];
213266020Sian
214266020Sian		for (i = 0; i < idx; i++) {
215266020Sian			base = *dmem;
216266020Sian			dmem += 2;
217266020Sian			flags = *dmem;
218266020Sian			/* Use region only if available and not reserved. */
219266020Sian			if ((flags & 0x8) && !(flags & 0x80)) {
220266020Sian				ofmem[lmsz].mr_start = base;
221266020Sian				ofmem[lmsz].mr_size = (vm_size_t)lmb_size[1];
222266020Sian				ofavail[lasz].mr_start = base;
223266020Sian				ofavail[lasz].mr_size = (vm_size_t)lmb_size[1];
224266020Sian				lmsz++;
225266020Sian				lasz++;
226266020Sian			}
227266020Sian			dmem++;
228266020Sian		}
229266020Sian	}
230266020Sian
231266020Sian	*msz = lmsz;
232266020Sian	*asz = lasz;
233266020Sian
234266020Sian	return (1);
235266020Sian}
236266020Sian
237255643Snwhitehornvoid
238266020Sianchrp_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
239266020Sian    struct mem_region *avail, int *availsz)
240255643Snwhitehorn{
241266020Sian	vm_offset_t maxphysaddr;
242266020Sian	int i;
243266020Sian
244266020Sian	ofw_mem_regions(phys, physsz, avail, availsz);
245266020Sian	parse_drconf_memory(physsz, availsz, phys, avail);
246266020Sian
247266020Sian	/*
248266020Sian	 * On some firmwares (SLOF), some memory may be marked available that
249266020Sian	 * doesn't actually exist. This manifests as an extension of the last
250266020Sian	 * available segment past the end of physical memory, so truncate that
251266020Sian	 * one.
252266020Sian	 */
253266020Sian	maxphysaddr = 0;
254266020Sian	for (i = 0; i < *physsz; i++)
255266020Sian		if (phys[i].mr_start + phys[i].mr_size > maxphysaddr)
256266020Sian			maxphysaddr = phys[i].mr_start + phys[i].mr_size;
257266020Sian
258266020Sian	for (i = 0; i < *availsz; i++)
259266020Sian		if (avail[i].mr_start + avail[i].mr_size > maxphysaddr)
260266020Sian			avail[i].mr_size = maxphysaddr - avail[i].mr_start;
261255643Snwhitehorn}
262255643Snwhitehorn
263255643Snwhitehornstatic vm_offset_t
264255643Snwhitehornchrp_real_maxaddr(platform_t plat)
265255643Snwhitehorn{
266255643Snwhitehorn	return (realmaxaddr);
267255643Snwhitehorn}
268255643Snwhitehorn
269255643Snwhitehornstatic u_long
270255643Snwhitehornchrp_timebase_freq(platform_t plat, struct cpuref *cpuref)
271255643Snwhitehorn{
272255643Snwhitehorn	phandle_t phandle;
273255643Snwhitehorn	int32_t ticks = -1;
274255643Snwhitehorn
275255643Snwhitehorn	phandle = cpuref->cr_hwref;
276255643Snwhitehorn
277255643Snwhitehorn	OF_getprop(phandle, "timebase-frequency", &ticks, sizeof(ticks));
278255643Snwhitehorn
279255643Snwhitehorn	if (ticks <= 0)
280255643Snwhitehorn		panic("Unable to determine timebase frequency!");
281255643Snwhitehorn
282255643Snwhitehorn	return (ticks);
283255643Snwhitehorn}
284255643Snwhitehorn
285255643Snwhitehornstatic int
286255643Snwhitehornchrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
287255643Snwhitehorn{
288255643Snwhitehorn	char buf[8];
289255643Snwhitehorn	phandle_t cpu, dev, root;
290255643Snwhitehorn	int res, cpuid;
291255643Snwhitehorn
292255643Snwhitehorn	root = OF_peer(0);
293255643Snwhitehorn
294255643Snwhitehorn	dev = OF_child(root);
295255643Snwhitehorn	while (dev != 0) {
296255643Snwhitehorn		res = OF_getprop(dev, "name", buf, sizeof(buf));
297255643Snwhitehorn		if (res > 0 && strcmp(buf, "cpus") == 0)
298255643Snwhitehorn			break;
299255643Snwhitehorn		dev = OF_peer(dev);
300255643Snwhitehorn	}
301255643Snwhitehorn	if (dev == 0) {
302255643Snwhitehorn		/*
303255643Snwhitehorn		 * psim doesn't have a name property on the /cpus node,
304255643Snwhitehorn		 * but it can be found directly
305255643Snwhitehorn		 */
306255643Snwhitehorn		dev = OF_finddevice("/cpus");
307255643Snwhitehorn		if (dev == 0)
308255643Snwhitehorn			return (ENOENT);
309255643Snwhitehorn	}
310255643Snwhitehorn
311255643Snwhitehorn	cpu = OF_child(dev);
312255643Snwhitehorn
313255643Snwhitehorn	while (cpu != 0) {
314255643Snwhitehorn		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
315255643Snwhitehorn		if (res > 0 && strcmp(buf, "cpu") == 0)
316255643Snwhitehorn			break;
317255643Snwhitehorn		cpu = OF_peer(cpu);
318255643Snwhitehorn	}
319255643Snwhitehorn	if (cpu == 0)
320255643Snwhitehorn		return (ENOENT);
321255643Snwhitehorn
322255643Snwhitehorn	cpuref->cr_hwref = cpu;
323255643Snwhitehorn	res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid,
324255643Snwhitehorn	    sizeof(cpuid));
325255643Snwhitehorn	if (res <= 0)
326255643Snwhitehorn		res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
327255643Snwhitehorn	if (res <= 0)
328255643Snwhitehorn		cpuid = 0;
329255643Snwhitehorn	cpuref->cr_cpuid = cpuid;
330255643Snwhitehorn
331255643Snwhitehorn	return (0);
332255643Snwhitehorn}
333255643Snwhitehorn
334255643Snwhitehornstatic int
335255643Snwhitehornchrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
336255643Snwhitehorn{
337255643Snwhitehorn	char buf[8];
338255643Snwhitehorn	phandle_t cpu;
339255643Snwhitehorn	int i, res, cpuid;
340255643Snwhitehorn
341255643Snwhitehorn	/* Check for whether it should be the next thread */
342255643Snwhitehorn	res = OF_getproplen(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s");
343255643Snwhitehorn	if (res > 0) {
344255643Snwhitehorn		cell_t interrupt_servers[res/sizeof(cell_t)];
345255643Snwhitehorn		OF_getprop(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s",
346255643Snwhitehorn		    interrupt_servers, res);
347255643Snwhitehorn		for (i = 0; i < res/sizeof(cell_t) - 1; i++) {
348255643Snwhitehorn			if (interrupt_servers[i] == cpuref->cr_cpuid) {
349255643Snwhitehorn				cpuref->cr_cpuid = interrupt_servers[i+1];
350255643Snwhitehorn				return (0);
351255643Snwhitehorn			}
352255643Snwhitehorn		}
353255643Snwhitehorn	}
354255643Snwhitehorn
355255643Snwhitehorn	/* Next CPU core/package */
356255643Snwhitehorn	cpu = OF_peer(cpuref->cr_hwref);
357255643Snwhitehorn	while (cpu != 0) {
358255643Snwhitehorn		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
359255643Snwhitehorn		if (res > 0 && strcmp(buf, "cpu") == 0)
360255643Snwhitehorn			break;
361255643Snwhitehorn		cpu = OF_peer(cpu);
362255643Snwhitehorn	}
363255643Snwhitehorn	if (cpu == 0)
364255643Snwhitehorn		return (ENOENT);
365255643Snwhitehorn
366255643Snwhitehorn	cpuref->cr_hwref = cpu;
367255643Snwhitehorn	res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid,
368255643Snwhitehorn	    sizeof(cpuid));
369255643Snwhitehorn	if (res <= 0)
370255643Snwhitehorn		res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
371255643Snwhitehorn	if (res <= 0)
372255643Snwhitehorn		cpuid = 0;
373255643Snwhitehorn	cpuref->cr_cpuid = cpuid;
374255643Snwhitehorn
375255643Snwhitehorn	return (0);
376255643Snwhitehorn}
377255643Snwhitehorn
378255643Snwhitehornstatic int
379255643Snwhitehornchrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
380255643Snwhitehorn{
381255643Snwhitehorn	ihandle_t inst;
382255643Snwhitehorn	phandle_t bsp, chosen;
383255643Snwhitehorn	int res, cpuid;
384255643Snwhitehorn
385255643Snwhitehorn	chosen = OF_finddevice("/chosen");
386255643Snwhitehorn	if (chosen == 0)
387255643Snwhitehorn		return (ENXIO);
388255643Snwhitehorn
389255643Snwhitehorn	res = OF_getprop(chosen, "cpu", &inst, sizeof(inst));
390255643Snwhitehorn	if (res < 0)
391255643Snwhitehorn		return (ENXIO);
392255643Snwhitehorn
393255643Snwhitehorn	bsp = OF_instance_to_package(inst);
394255643Snwhitehorn
395255643Snwhitehorn	/* Pick the primary thread. Can it be any other? */
396255643Snwhitehorn	cpuref->cr_hwref = bsp;
397255643Snwhitehorn	res = OF_getprop(bsp, "ibm,ppc-interrupt-server#s", &cpuid,
398255643Snwhitehorn	    sizeof(cpuid));
399255643Snwhitehorn	if (res <= 0)
400255643Snwhitehorn		res = OF_getprop(bsp, "reg", &cpuid, sizeof(cpuid));
401255643Snwhitehorn	if (res <= 0)
402255643Snwhitehorn		cpuid = 0;
403255643Snwhitehorn	cpuref->cr_cpuid = cpuid;
404255643Snwhitehorn
405255643Snwhitehorn	return (0);
406255643Snwhitehorn}
407255643Snwhitehorn
408255643Snwhitehorn#ifdef SMP
409255643Snwhitehornstatic int
410255643Snwhitehornchrp_smp_start_cpu(platform_t plat, struct pcpu *pc)
411255643Snwhitehorn{
412255643Snwhitehorn	cell_t start_cpu;
413255643Snwhitehorn	int result, err, timeout;
414255643Snwhitehorn
415255643Snwhitehorn	if (!rtas_exists()) {
416255643Snwhitehorn		printf("RTAS uninitialized: unable to start AP %d\n",
417255643Snwhitehorn		    pc->pc_cpuid);
418255643Snwhitehorn		return (ENXIO);
419255643Snwhitehorn	}
420255643Snwhitehorn
421255643Snwhitehorn	start_cpu = rtas_token_lookup("start-cpu");
422255643Snwhitehorn	if (start_cpu == -1) {
423255643Snwhitehorn		printf("RTAS unknown method: unable to start AP %d\n",
424255643Snwhitehorn		    pc->pc_cpuid);
425255643Snwhitehorn		return (ENXIO);
426255643Snwhitehorn	}
427255643Snwhitehorn
428255643Snwhitehorn	ap_pcpu = pc;
429255643Snwhitehorn	powerpc_sync();
430255643Snwhitehorn
431255643Snwhitehorn	result = rtas_call_method(start_cpu, 3, 1, pc->pc_cpuid, EXC_RST, pc,
432255643Snwhitehorn	    &err);
433255643Snwhitehorn	if (result < 0 || err != 0) {
434255643Snwhitehorn		printf("RTAS error (%d/%d): unable to start AP %d\n",
435255643Snwhitehorn		    result, err, pc->pc_cpuid);
436255643Snwhitehorn		return (ENXIO);
437255643Snwhitehorn	}
438255643Snwhitehorn
439255643Snwhitehorn	timeout = 10000;
440255643Snwhitehorn	while (!pc->pc_awake && timeout--)
441255643Snwhitehorn		DELAY(100);
442255643Snwhitehorn
443255643Snwhitehorn	return ((pc->pc_awake) ? 0 : EBUSY);
444255643Snwhitehorn}
445255643Snwhitehorn
446255643Snwhitehornstatic struct cpu_group *
447255643Snwhitehornchrp_smp_topo(platform_t plat)
448255643Snwhitehorn{
449255643Snwhitehorn	struct pcpu *pc, *last_pc;
450255643Snwhitehorn	int i, ncores, ncpus;
451255643Snwhitehorn
452255643Snwhitehorn	ncores = ncpus = 0;
453255643Snwhitehorn	last_pc = NULL;
454255643Snwhitehorn	for (i = 0; i <= mp_maxid; i++) {
455255643Snwhitehorn		pc = pcpu_find(i);
456255643Snwhitehorn		if (pc == NULL)
457255643Snwhitehorn			continue;
458255643Snwhitehorn		if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref)
459255643Snwhitehorn			ncores++;
460255643Snwhitehorn		last_pc = pc;
461255643Snwhitehorn		ncpus++;
462255643Snwhitehorn	}
463255643Snwhitehorn
464255643Snwhitehorn	if (ncpus % ncores != 0) {
465255643Snwhitehorn		printf("WARNING: Irregular SMP topology. Performance may be "
466255643Snwhitehorn		     "suboptimal (%d CPUS, %d cores)\n", ncpus, ncores);
467255643Snwhitehorn		return (smp_topo_none());
468255643Snwhitehorn	}
469255643Snwhitehorn
470255643Snwhitehorn	/* Don't do anything fancier for non-threaded SMP */
471255643Snwhitehorn	if (ncpus == ncores)
472255643Snwhitehorn		return (smp_topo_none());
473255643Snwhitehorn
474255643Snwhitehorn	return (smp_topo_1level(CG_SHARE_L1, ncpus / ncores, CG_FLAG_SMT));
475255643Snwhitehorn}
476255643Snwhitehorn#endif
477255643Snwhitehorn
478255643Snwhitehornstatic void
479255643Snwhitehornchrp_reset(platform_t platform)
480255643Snwhitehorn{
481255643Snwhitehorn	OF_reboot();
482255643Snwhitehorn}
483255643Snwhitehorn
484255643Snwhitehorn#ifdef __powerpc64__
485255643Snwhitehornstatic void
486255643Snwhitehornphyp_cpu_idle(sbintime_t sbt)
487255643Snwhitehorn{
488255643Snwhitehorn	phyp_hcall(H_CEDE);
489255643Snwhitehorn}
490255643Snwhitehorn
491255643Snwhitehornstatic void
492255643Snwhitehornchrp_smp_ap_init(platform_t platform)
493255643Snwhitehorn{
494255643Snwhitehorn	if (!(mfmsr() & PSL_HV)) {
495255643Snwhitehorn		/* Set interrupt priority */
496255643Snwhitehorn		phyp_hcall(H_CPPR, 0xff);
497255643Snwhitehorn
498255643Snwhitehorn		/* Register VPA */
499255643Snwhitehorn		phyp_hcall(H_REGISTER_VPA, 1UL, PCPU_GET(cpuid), splpar_vpa);
500255643Snwhitehorn	}
501255643Snwhitehorn}
502255643Snwhitehorn#else
503255643Snwhitehornstatic void
504255643Snwhitehornchrp_smp_ap_init(platform_t platform)
505255643Snwhitehorn{
506255643Snwhitehorn}
507255643Snwhitehorn#endif
508255643Snwhitehorn
509