xref: /freebsd/sys/powerpc/powernv/platform_powernv.c (revision 504d9b6029cce76e39ca66526d3ddbccc6443620)
1fb3855e0SWojciech Macek /*-
2fb3855e0SWojciech Macek  * Copyright (c) 2015 Nathan Whitehorn
3fb3855e0SWojciech Macek  * All rights reserved.
4fb3855e0SWojciech Macek  *
5fb3855e0SWojciech Macek  * Redistribution and use in source and binary forms, with or without
6fb3855e0SWojciech Macek  * modification, are permitted provided that the following conditions
7fb3855e0SWojciech Macek  * are met:
8fb3855e0SWojciech Macek  *
9fb3855e0SWojciech Macek  * 1. Redistributions of source code must retain the above copyright
10fb3855e0SWojciech Macek  *    notice, this list of conditions and the following disclaimer.
11fb3855e0SWojciech Macek  * 2. Redistributions in binary form must reproduce the above copyright
12fb3855e0SWojciech Macek  *    notice, this list of conditions and the following disclaimer in the
13fb3855e0SWojciech Macek  *    documentation and/or other materials provided with the distribution.
14fb3855e0SWojciech Macek  *
15fb3855e0SWojciech Macek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16fb3855e0SWojciech Macek  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17fb3855e0SWojciech Macek  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18fb3855e0SWojciech Macek  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19fb3855e0SWojciech Macek  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20fb3855e0SWojciech Macek  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21fb3855e0SWojciech Macek  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22fb3855e0SWojciech Macek  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23fb3855e0SWojciech Macek  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24fb3855e0SWojciech Macek  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25fb3855e0SWojciech Macek  */
26fb3855e0SWojciech Macek 
27fb3855e0SWojciech Macek #include <sys/cdefs.h>
28fb3855e0SWojciech Macek __FBSDID("$FreeBSD$");
29fb3855e0SWojciech Macek 
30fb3855e0SWojciech Macek #include <sys/param.h>
31fb3855e0SWojciech Macek #include <sys/systm.h>
32fb3855e0SWojciech Macek #include <sys/kernel.h>
33fb3855e0SWojciech Macek #include <sys/bus.h>
34fb3855e0SWojciech Macek #include <sys/pcpu.h>
35fb3855e0SWojciech Macek #include <sys/proc.h>
36fb3855e0SWojciech Macek #include <sys/smp.h>
37fb3855e0SWojciech Macek #include <vm/vm.h>
38fb3855e0SWojciech Macek #include <vm/pmap.h>
39fb3855e0SWojciech Macek 
40fb3855e0SWojciech Macek #include <machine/bus.h>
41fb3855e0SWojciech Macek #include <machine/cpu.h>
42fb3855e0SWojciech Macek #include <machine/hid.h>
43fb3855e0SWojciech Macek #include <machine/platformvar.h>
44fb3855e0SWojciech Macek #include <machine/pmap.h>
45fb3855e0SWojciech Macek #include <machine/rtas.h>
46fb3855e0SWojciech Macek #include <machine/smp.h>
47fb3855e0SWojciech Macek #include <machine/spr.h>
48fb3855e0SWojciech Macek #include <machine/trap.h>
49fb3855e0SWojciech Macek 
50fb3855e0SWojciech Macek #include <dev/ofw/openfirm.h>
51fb3855e0SWojciech Macek #include <machine/ofw_machdep.h>
52*504d9b60SWojciech Macek #include <powerpc/aim/mmu_oea64.h>
53fb3855e0SWojciech Macek 
54fb3855e0SWojciech Macek #include "platform_if.h"
55fb3855e0SWojciech Macek #include "opal.h"
56fb3855e0SWojciech Macek 
57fb3855e0SWojciech Macek #ifdef SMP
58fb3855e0SWojciech Macek extern void *ap_pcpu;
59fb3855e0SWojciech Macek #endif
60fb3855e0SWojciech Macek 
61fb3855e0SWojciech Macek static int powernv_probe(platform_t);
62fb3855e0SWojciech Macek static int powernv_attach(platform_t);
63fb3855e0SWojciech Macek void powernv_mem_regions(platform_t, struct mem_region *phys, int *physsz,
64fb3855e0SWojciech Macek     struct mem_region *avail, int *availsz);
65fb3855e0SWojciech Macek static u_long powernv_timebase_freq(platform_t, struct cpuref *cpuref);
66fb3855e0SWojciech Macek static int powernv_smp_first_cpu(platform_t, struct cpuref *cpuref);
67fb3855e0SWojciech Macek static int powernv_smp_next_cpu(platform_t, struct cpuref *cpuref);
68fb3855e0SWojciech Macek static int powernv_smp_get_bsp(platform_t, struct cpuref *cpuref);
69fb3855e0SWojciech Macek static void powernv_smp_ap_init(platform_t);
70fb3855e0SWojciech Macek #ifdef SMP
71fb3855e0SWojciech Macek static int powernv_smp_start_cpu(platform_t, struct pcpu *cpu);
72fb3855e0SWojciech Macek static struct cpu_group *powernv_smp_topo(platform_t plat);
73fb3855e0SWojciech Macek #endif
74fb3855e0SWojciech Macek static void powernv_reset(platform_t);
7501d7bda7SWojciech Macek static void powernv_cpu_idle(sbintime_t sbt);
76fb3855e0SWojciech Macek 
77fb3855e0SWojciech Macek static platform_method_t powernv_methods[] = {
78fb3855e0SWojciech Macek 	PLATFORMMETHOD(platform_probe, 		powernv_probe),
79fb3855e0SWojciech Macek 	PLATFORMMETHOD(platform_attach,		powernv_attach),
80fb3855e0SWojciech Macek 	PLATFORMMETHOD(platform_mem_regions,	powernv_mem_regions),
81fb3855e0SWojciech Macek 	PLATFORMMETHOD(platform_timebase_freq,	powernv_timebase_freq),
82fb3855e0SWojciech Macek 
83fb3855e0SWojciech Macek 	PLATFORMMETHOD(platform_smp_ap_init,	powernv_smp_ap_init),
84fb3855e0SWojciech Macek 	PLATFORMMETHOD(platform_smp_first_cpu,	powernv_smp_first_cpu),
85fb3855e0SWojciech Macek 	PLATFORMMETHOD(platform_smp_next_cpu,	powernv_smp_next_cpu),
86fb3855e0SWojciech Macek 	PLATFORMMETHOD(platform_smp_get_bsp,	powernv_smp_get_bsp),
87fb3855e0SWojciech Macek #ifdef SMP
88fb3855e0SWojciech Macek 	PLATFORMMETHOD(platform_smp_start_cpu,	powernv_smp_start_cpu),
89fb3855e0SWojciech Macek 	PLATFORMMETHOD(platform_smp_topo,	powernv_smp_topo),
90fb3855e0SWojciech Macek #endif
91fb3855e0SWojciech Macek 
92fb3855e0SWojciech Macek 	PLATFORMMETHOD(platform_reset,		powernv_reset),
93fb3855e0SWojciech Macek 
94fb3855e0SWojciech Macek 	{ 0, 0 }
95fb3855e0SWojciech Macek };
96fb3855e0SWojciech Macek 
97fb3855e0SWojciech Macek static platform_def_t powernv_platform = {
98fb3855e0SWojciech Macek 	"powernv",
99fb3855e0SWojciech Macek 	powernv_methods,
100fb3855e0SWojciech Macek 	0
101fb3855e0SWojciech Macek };
102fb3855e0SWojciech Macek 
103fb3855e0SWojciech Macek PLATFORM_DEF(powernv_platform);
104fb3855e0SWojciech Macek 
105*504d9b60SWojciech Macek static int powernv_boot_pir;
106*504d9b60SWojciech Macek 
107fb3855e0SWojciech Macek static int
108fb3855e0SWojciech Macek powernv_probe(platform_t plat)
109fb3855e0SWojciech Macek {
110fb3855e0SWojciech Macek 	if (opal_check() == 0)
111fb3855e0SWojciech Macek 		return (BUS_PROBE_SPECIFIC);
112fb3855e0SWojciech Macek 
113fb3855e0SWojciech Macek 	return (ENXIO);
114fb3855e0SWojciech Macek }
115fb3855e0SWojciech Macek 
116fb3855e0SWojciech Macek static int
117fb3855e0SWojciech Macek powernv_attach(platform_t plat)
118fb3855e0SWojciech Macek {
119*504d9b60SWojciech Macek 	uint32_t nptlp, shift = 0, slb_encoding = 0;
120*504d9b60SWojciech Macek 	int32_t lp_size, lp_encoding;
121*504d9b60SWojciech Macek 	char buf[255];
122*504d9b60SWojciech Macek 	pcell_t prop;
123*504d9b60SWojciech Macek 	phandle_t cpu;
124*504d9b60SWojciech Macek 	int res, len, node, idx;
125*504d9b60SWojciech Macek 
126fb3855e0SWojciech Macek 	/* Ping OPAL again just to make sure */
127fb3855e0SWojciech Macek 	opal_check();
128fb3855e0SWojciech Macek 
12901d7bda7SWojciech Macek 	cpu_idle_hook = powernv_cpu_idle;
130*504d9b60SWojciech Macek 	powernv_boot_pir = mfspr(SPR_PIR);
13101d7bda7SWojciech Macek 
132*504d9b60SWojciech Macek 	/* Init CPU bits */
133*504d9b60SWojciech Macek 	powernv_smp_ap_init(plat);
134c0248976SWojciech Macek 
135*504d9b60SWojciech Macek 	/* Set SLB count from device tree */
136*504d9b60SWojciech Macek 	cpu = OF_peer(0);
137*504d9b60SWojciech Macek 	cpu = OF_child(cpu);
138*504d9b60SWojciech Macek 	while (cpu != 0) {
139*504d9b60SWojciech Macek 		res = OF_getprop(cpu, "name", buf, sizeof(buf));
140*504d9b60SWojciech Macek 		if (res > 0 && strcmp(buf, "cpus") == 0)
141*504d9b60SWojciech Macek 			break;
142*504d9b60SWojciech Macek 		cpu = OF_peer(cpu);
143*504d9b60SWojciech Macek 	}
144*504d9b60SWojciech Macek 	if (cpu == 0)
145*504d9b60SWojciech Macek 		goto out;
146*504d9b60SWojciech Macek 
147*504d9b60SWojciech Macek 	cpu = OF_child(cpu);
148*504d9b60SWojciech Macek 	while (cpu != 0) {
149*504d9b60SWojciech Macek 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
150*504d9b60SWojciech Macek 		if (res > 0 && strcmp(buf, "cpu") == 0)
151*504d9b60SWojciech Macek 			break;
152*504d9b60SWojciech Macek 		cpu = OF_peer(cpu);
153*504d9b60SWojciech Macek 	}
154*504d9b60SWojciech Macek 	if (cpu == 0)
155*504d9b60SWojciech Macek 		goto out;
156*504d9b60SWojciech Macek 
157*504d9b60SWojciech Macek 	res = OF_getencprop(cpu, "ibm,slb-size", &prop, sizeof(prop));
158*504d9b60SWojciech Macek 	if (res > 0)
159*504d9b60SWojciech Macek 		n_slbs = prop;
160*504d9b60SWojciech Macek 
161*504d9b60SWojciech Macek 	/*
162*504d9b60SWojciech Macek 	 * Scan the large page size property for PAPR compatible machines.
163*504d9b60SWojciech Macek 	 * See PAPR D.5 Changes to Section 5.1.4, 'CPU Node Properties'
164*504d9b60SWojciech Macek 	 * for the encoding of the property.
165*504d9b60SWojciech Macek 	 */
166*504d9b60SWojciech Macek 
167*504d9b60SWojciech Macek 	len = OF_getproplen(node, "ibm,segment-page-sizes");
168*504d9b60SWojciech Macek 	if (len > 0) {
169*504d9b60SWojciech Macek 		/*
170*504d9b60SWojciech Macek 		 * We have to use a variable length array on the stack
171*504d9b60SWojciech Macek 		 * since we have very limited stack space.
172*504d9b60SWojciech Macek 		 */
173*504d9b60SWojciech Macek 		pcell_t arr[len/sizeof(cell_t)];
174*504d9b60SWojciech Macek 		res = OF_getencprop(cpu, "ibm,segment-page-sizes", arr,
175*504d9b60SWojciech Macek 		    sizeof(arr));
176*504d9b60SWojciech Macek 		len /= 4;
177*504d9b60SWojciech Macek 		idx = 0;
178*504d9b60SWojciech Macek 		while (len > 0) {
179*504d9b60SWojciech Macek 			shift = arr[idx];
180*504d9b60SWojciech Macek 			slb_encoding = arr[idx + 1];
181*504d9b60SWojciech Macek 			nptlp = arr[idx + 2];
182*504d9b60SWojciech Macek 			idx += 3;
183*504d9b60SWojciech Macek 			len -= 3;
184*504d9b60SWojciech Macek 			while (len > 0 && nptlp) {
185*504d9b60SWojciech Macek 				lp_size = arr[idx];
186*504d9b60SWojciech Macek 				lp_encoding = arr[idx+1];
187*504d9b60SWojciech Macek 				if (slb_encoding == SLBV_L && lp_encoding == 0)
188*504d9b60SWojciech Macek 					break;
189*504d9b60SWojciech Macek 
190*504d9b60SWojciech Macek 				idx += 2;
191*504d9b60SWojciech Macek 				len -= 2;
192*504d9b60SWojciech Macek 				nptlp--;
193*504d9b60SWojciech Macek 			}
194*504d9b60SWojciech Macek 			if (nptlp && slb_encoding == SLBV_L && lp_encoding == 0)
195*504d9b60SWojciech Macek 				break;
196*504d9b60SWojciech Macek 		}
197*504d9b60SWojciech Macek 
198*504d9b60SWojciech Macek 		if (len == 0)
199*504d9b60SWojciech Macek 			panic("Standard large pages (SLB[L] = 1, PTE[LP] = 0) "
200*504d9b60SWojciech Macek 			    "not supported by this system.");
201*504d9b60SWojciech Macek 
202*504d9b60SWojciech Macek 		moea64_large_page_shift = shift;
203*504d9b60SWojciech Macek 		moea64_large_page_size = 1ULL << lp_size;
204*504d9b60SWojciech Macek 	}
205*504d9b60SWojciech Macek 
206*504d9b60SWojciech Macek out:
207fb3855e0SWojciech Macek 	return (0);
208fb3855e0SWojciech Macek }
209fb3855e0SWojciech Macek 
210*504d9b60SWojciech Macek 
211fb3855e0SWojciech Macek void
212fb3855e0SWojciech Macek powernv_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
213fb3855e0SWojciech Macek     struct mem_region *avail, int *availsz)
214fb3855e0SWojciech Macek {
215fb3855e0SWojciech Macek 
216fb3855e0SWojciech Macek 	ofw_mem_regions(phys, physsz, avail, availsz);
217fb3855e0SWojciech Macek }
218fb3855e0SWojciech Macek 
219fb3855e0SWojciech Macek static u_long
220fb3855e0SWojciech Macek powernv_timebase_freq(platform_t plat, struct cpuref *cpuref)
221fb3855e0SWojciech Macek {
222fb3855e0SWojciech Macek 	phandle_t phandle;
223fb3855e0SWojciech Macek 	int32_t ticks = -1;
224fb3855e0SWojciech Macek 
225fb3855e0SWojciech Macek 	phandle = cpuref->cr_hwref;
226fb3855e0SWojciech Macek 
227*504d9b60SWojciech Macek 	OF_getencprop(phandle, "timebase-frequency", &ticks, sizeof(ticks));
228fb3855e0SWojciech Macek 
229fb3855e0SWojciech Macek 	if (ticks <= 0)
230fb3855e0SWojciech Macek 		panic("Unable to determine timebase frequency!");
231fb3855e0SWojciech Macek 
232fb3855e0SWojciech Macek 	return (ticks);
233fb3855e0SWojciech Macek }
234fb3855e0SWojciech Macek 
235fb3855e0SWojciech Macek static int
236fb3855e0SWojciech Macek powernv_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
237fb3855e0SWojciech Macek {
238fb3855e0SWojciech Macek 	char buf[8];
239fb3855e0SWojciech Macek 	phandle_t cpu, dev, root;
240fb3855e0SWojciech Macek 	int res, cpuid;
241fb3855e0SWojciech Macek 
242fb3855e0SWojciech Macek 	root = OF_peer(0);
243fb3855e0SWojciech Macek 
244fb3855e0SWojciech Macek 	dev = OF_child(root);
245fb3855e0SWojciech Macek 	while (dev != 0) {
246fb3855e0SWojciech Macek 		res = OF_getprop(dev, "name", buf, sizeof(buf));
247fb3855e0SWojciech Macek 		if (res > 0 && strcmp(buf, "cpus") == 0)
248fb3855e0SWojciech Macek 			break;
249fb3855e0SWojciech Macek 		dev = OF_peer(dev);
250fb3855e0SWojciech Macek 	}
251fb3855e0SWojciech Macek 	if (dev == 0) {
252fb3855e0SWojciech Macek 		/*
253fb3855e0SWojciech Macek 		 * psim doesn't have a name property on the /cpus node,
254fb3855e0SWojciech Macek 		 * but it can be found directly
255fb3855e0SWojciech Macek 		 */
256fb3855e0SWojciech Macek 		dev = OF_finddevice("/cpus");
257fb3855e0SWojciech Macek 		if (dev == 0)
258fb3855e0SWojciech Macek 			return (ENOENT);
259fb3855e0SWojciech Macek 	}
260fb3855e0SWojciech Macek 
261fb3855e0SWojciech Macek 	cpu = OF_child(dev);
262fb3855e0SWojciech Macek 
263fb3855e0SWojciech Macek 	while (cpu != 0) {
264fb3855e0SWojciech Macek 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
265fb3855e0SWojciech Macek 		if (res > 0 && strcmp(buf, "cpu") == 0)
266fb3855e0SWojciech Macek 			break;
267fb3855e0SWojciech Macek 		cpu = OF_peer(cpu);
268fb3855e0SWojciech Macek 	}
269fb3855e0SWojciech Macek 	if (cpu == 0)
270fb3855e0SWojciech Macek 		return (ENOENT);
271fb3855e0SWojciech Macek 
272fb3855e0SWojciech Macek 	cpuref->cr_hwref = cpu;
273*504d9b60SWojciech Macek 	res = OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid,
274fb3855e0SWojciech Macek 	    sizeof(cpuid));
275fb3855e0SWojciech Macek 	if (res <= 0)
276*504d9b60SWojciech Macek 		res = OF_getencprop(cpu, "reg", &cpuid, sizeof(cpuid));
277fb3855e0SWojciech Macek 	if (res <= 0)
278fb3855e0SWojciech Macek 		cpuid = 0;
279fb3855e0SWojciech Macek 	cpuref->cr_cpuid = cpuid;
280fb3855e0SWojciech Macek 
281fb3855e0SWojciech Macek 	return (0);
282fb3855e0SWojciech Macek }
283fb3855e0SWojciech Macek 
284fb3855e0SWojciech Macek static int
285fb3855e0SWojciech Macek powernv_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
286fb3855e0SWojciech Macek {
287fb3855e0SWojciech Macek 	char buf[8];
288fb3855e0SWojciech Macek 	phandle_t cpu;
289fb3855e0SWojciech Macek 	int i, res, cpuid;
290fb3855e0SWojciech Macek 
291fb3855e0SWojciech Macek 	/* Check for whether it should be the next thread */
292fb3855e0SWojciech Macek 	res = OF_getproplen(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s");
293fb3855e0SWojciech Macek 	if (res > 0) {
294fb3855e0SWojciech Macek 		cell_t interrupt_servers[res/sizeof(cell_t)];
295*504d9b60SWojciech Macek 		OF_getencprop(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s",
296fb3855e0SWojciech Macek 		    interrupt_servers, res);
297fb3855e0SWojciech Macek 		for (i = 0; i < res/sizeof(cell_t) - 1; i++) {
298fb3855e0SWojciech Macek 			if (interrupt_servers[i] == cpuref->cr_cpuid) {
299fb3855e0SWojciech Macek 				cpuref->cr_cpuid = interrupt_servers[i+1];
300fb3855e0SWojciech Macek 				return (0);
301fb3855e0SWojciech Macek 			}
302fb3855e0SWojciech Macek 		}
303fb3855e0SWojciech Macek 	}
304fb3855e0SWojciech Macek 
305fb3855e0SWojciech Macek 	/* Next CPU core/package */
306fb3855e0SWojciech Macek 	cpu = OF_peer(cpuref->cr_hwref);
307fb3855e0SWojciech Macek 	while (cpu != 0) {
308fb3855e0SWojciech Macek 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
309fb3855e0SWojciech Macek 		if (res > 0 && strcmp(buf, "cpu") == 0)
310fb3855e0SWojciech Macek 			break;
311fb3855e0SWojciech Macek 		cpu = OF_peer(cpu);
312fb3855e0SWojciech Macek 	}
313fb3855e0SWojciech Macek 	if (cpu == 0)
314fb3855e0SWojciech Macek 		return (ENOENT);
315fb3855e0SWojciech Macek 
316fb3855e0SWojciech Macek 	cpuref->cr_hwref = cpu;
317*504d9b60SWojciech Macek 	res = OF_getencprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid,
318fb3855e0SWojciech Macek 	    sizeof(cpuid));
319fb3855e0SWojciech Macek 	if (res <= 0)
320*504d9b60SWojciech Macek 		res = OF_getencprop(cpu, "reg", &cpuid, sizeof(cpuid));
321fb3855e0SWojciech Macek 	if (res <= 0)
322fb3855e0SWojciech Macek 		cpuid = 0;
323fb3855e0SWojciech Macek 	cpuref->cr_cpuid = cpuid;
324fb3855e0SWojciech Macek 
325fb3855e0SWojciech Macek 	return (0);
326fb3855e0SWojciech Macek }
327fb3855e0SWojciech Macek 
328fb3855e0SWojciech Macek static int
329fb3855e0SWojciech Macek powernv_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
330fb3855e0SWojciech Macek {
331fb3855e0SWojciech Macek 	phandle_t chosen;
332fb3855e0SWojciech Macek 	int cpuid, res;
333fb3855e0SWojciech Macek 	struct cpuref i;
334fb3855e0SWojciech Macek 
335fb3855e0SWojciech Macek 	chosen = OF_finddevice("/chosen");
336fb3855e0SWojciech Macek 	if (chosen == 0)
337fb3855e0SWojciech Macek 		return (ENOENT);
338fb3855e0SWojciech Macek 
339fb3855e0SWojciech Macek 	res = OF_getencprop(chosen, "fdtbootcpu", &cpuid, sizeof(cpuid));
340fb3855e0SWojciech Macek 	if (res < 0)
341fb3855e0SWojciech Macek 		return (ENOENT);
342fb3855e0SWojciech Macek 
343*504d9b60SWojciech Macek 	/* XXX: FDT from kexec lies sometimes. PIR seems not to. */
344*504d9b60SWojciech Macek 	if (cpuid == 0)
345*504d9b60SWojciech Macek 		cpuid = powernv_boot_pir;
346*504d9b60SWojciech Macek 
347fb3855e0SWojciech Macek 	cpuref->cr_cpuid = cpuid;
348fb3855e0SWojciech Macek 
349fb3855e0SWojciech Macek 	if (powernv_smp_first_cpu(plat, &i) != 0)
350fb3855e0SWojciech Macek 		return (ENOENT);
351fb3855e0SWojciech Macek 	cpuref->cr_hwref = i.cr_hwref;
352fb3855e0SWojciech Macek 
353fb3855e0SWojciech Macek 	do {
354fb3855e0SWojciech Macek 		if (i.cr_cpuid == cpuid) {
355fb3855e0SWojciech Macek 			cpuref->cr_hwref = i.cr_hwref;
356fb3855e0SWojciech Macek 			break;
357fb3855e0SWojciech Macek 		}
358fb3855e0SWojciech Macek 	} while (powernv_smp_next_cpu(plat, &i) == 0);
359fb3855e0SWojciech Macek 
360fb3855e0SWojciech Macek 	return (0);
361fb3855e0SWojciech Macek }
362fb3855e0SWojciech Macek 
363fb3855e0SWojciech Macek #ifdef SMP
364fb3855e0SWojciech Macek static int
365fb3855e0SWojciech Macek powernv_smp_start_cpu(platform_t plat, struct pcpu *pc)
366fb3855e0SWojciech Macek {
36701d7bda7SWojciech Macek 	int result;
368fb3855e0SWojciech Macek 
369fb3855e0SWojciech Macek 	ap_pcpu = pc;
370fb3855e0SWojciech Macek 	powerpc_sync();
371fb3855e0SWojciech Macek 
372fb3855e0SWojciech Macek 	result = opal_call(OPAL_START_CPU, pc->pc_cpuid, EXC_RST);
37301d7bda7SWojciech Macek 	if (result != OPAL_SUCCESS) {
37401d7bda7SWojciech Macek 		printf("OPAL error (%d): unable to start AP %d\n",
37501d7bda7SWojciech Macek 		    result, pc->pc_cpuid);
376fb3855e0SWojciech Macek 		return (ENXIO);
377fb3855e0SWojciech Macek 	}
378fb3855e0SWojciech Macek 
37901d7bda7SWojciech Macek 	return (0);
380fb3855e0SWojciech Macek }
381fb3855e0SWojciech Macek 
382fb3855e0SWojciech Macek static struct cpu_group *
383fb3855e0SWojciech Macek powernv_smp_topo(platform_t plat)
384fb3855e0SWojciech Macek {
385fb3855e0SWojciech Macek 	struct pcpu *pc, *last_pc;
386fb3855e0SWojciech Macek 	int i, ncores, ncpus;
387fb3855e0SWojciech Macek 
388fb3855e0SWojciech Macek 	ncores = ncpus = 0;
389fb3855e0SWojciech Macek 	last_pc = NULL;
390*504d9b60SWojciech Macek 	CPU_FOREACH(i) {
391fb3855e0SWojciech Macek 		pc = pcpu_find(i);
392fb3855e0SWojciech Macek 		if (pc == NULL)
393fb3855e0SWojciech Macek 			continue;
394fb3855e0SWojciech Macek 		if (last_pc == NULL || pc->pc_hwref != last_pc->pc_hwref)
395fb3855e0SWojciech Macek 			ncores++;
396fb3855e0SWojciech Macek 		last_pc = pc;
397fb3855e0SWojciech Macek 		ncpus++;
398fb3855e0SWojciech Macek 	}
399fb3855e0SWojciech Macek 
400fb3855e0SWojciech Macek 	if (ncpus % ncores != 0) {
401fb3855e0SWojciech Macek 		printf("WARNING: Irregular SMP topology. Performance may be "
402fb3855e0SWojciech Macek 		     "suboptimal (%d CPUS, %d cores)\n", ncpus, ncores);
403fb3855e0SWojciech Macek 		return (smp_topo_none());
404fb3855e0SWojciech Macek 	}
405fb3855e0SWojciech Macek 
406fb3855e0SWojciech Macek 	/* Don't do anything fancier for non-threaded SMP */
407fb3855e0SWojciech Macek 	if (ncpus == ncores)
408fb3855e0SWojciech Macek 		return (smp_topo_none());
409fb3855e0SWojciech Macek 
410*504d9b60SWojciech Macek #ifdef NOTYET /* smp_topo_1level() fails with non-consecutive CPU IDs */
411fb3855e0SWojciech Macek 	return (smp_topo_1level(CG_SHARE_L1, ncpus / ncores, CG_FLAG_SMT));
412*504d9b60SWojciech Macek #else
413*504d9b60SWojciech Macek 	return (smp_topo_none());
414*504d9b60SWojciech Macek #endif
415fb3855e0SWojciech Macek }
416fb3855e0SWojciech Macek #endif
417fb3855e0SWojciech Macek 
418fb3855e0SWojciech Macek static void
419fb3855e0SWojciech Macek powernv_reset(platform_t platform)
420fb3855e0SWojciech Macek {
42132d1354aSWojciech Macek 
42232d1354aSWojciech Macek 	opal_call(OPAL_CEC_REBOOT);
423fb3855e0SWojciech Macek }
424fb3855e0SWojciech Macek 
425fb3855e0SWojciech Macek static void
426fb3855e0SWojciech Macek powernv_smp_ap_init(platform_t platform)
427fb3855e0SWojciech Macek {
428*504d9b60SWojciech Macek 
429*504d9b60SWojciech Macek 	/* Direct interrupts to SRR instead of HSRR and reset LPCR otherwise */
430*504d9b60SWojciech Macek 	mtspr(SPR_LPCR, LPCR_LPES);
431fb3855e0SWojciech Macek }
432fb3855e0SWojciech Macek 
43301d7bda7SWojciech Macek static void
43401d7bda7SWojciech Macek powernv_cpu_idle(sbintime_t sbt)
43501d7bda7SWojciech Macek {
43601d7bda7SWojciech Macek }
437