xref: /freebsd/sys/powerpc/aim/mp_cpudep.c (revision cadd87749dc74a8e56ad741188d6740e121db7a4)
1 /*-
2  * Copyright (c) 2008 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34 #include <sys/pcpu.h>
35 #include <sys/proc.h>
36 #include <sys/smp.h>
37 
38 #include <machine/bat.h>
39 #include <machine/bus.h>
40 #include <machine/cpu.h>
41 #include <machine/hid.h>
42 #include <machine/intr_machdep.h>
43 #include <machine/pcb.h>
44 #include <machine/psl.h>
45 #include <machine/smp.h>
46 #include <machine/spr.h>
47 #include <machine/trap_aim.h>
48 
49 #include <dev/ofw/openfirm.h>
50 #include <machine/ofw_machdep.h>
51 
52 extern void *rstcode;
53 
54 void *ap_pcpu;
55 
56 static int
57 powerpc_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu)
58 {
59 	int cpuid, res;
60 
61 	cpuref->cr_hwref = cpu;
62 	res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
63 	if (res < 0)
64 		return (ENOENT);
65 
66 	cpuref->cr_cpuid = cpuid & 0xff;
67 	return (0);
68 }
69 
70 int
71 powerpc_smp_first_cpu(struct cpuref *cpuref)
72 {
73 	char buf[8];
74 	phandle_t cpu, dev, root;
75 	int res;
76 
77 	root = OF_peer(0);
78 
79 	dev = OF_child(root);
80 	while (dev != 0) {
81 		res = OF_getprop(dev, "name", buf, sizeof(buf));
82 		if (res > 0 && strcmp(buf, "cpus") == 0)
83 			break;
84 		dev = OF_peer(dev);
85 	}
86 	if (dev == 0)
87 		return (ENOENT);
88 
89 	cpu = OF_child(dev);
90 	while (cpu != 0) {
91 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
92 		if (res > 0 && strcmp(buf, "cpu") == 0)
93 			break;
94 		cpu = OF_peer(cpu);
95 	}
96 	if (cpu == 0)
97 		return (ENOENT);
98 
99 	return (powerpc_smp_fill_cpuref(cpuref, cpu));
100 }
101 
102 int
103 powerpc_smp_next_cpu(struct cpuref *cpuref)
104 {
105 	char buf[8];
106 	phandle_t cpu;
107 	int res;
108 
109 	cpu = OF_peer(cpuref->cr_hwref);
110 	while (cpu != 0) {
111 		res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
112 		if (res > 0 && strcmp(buf, "cpu") == 0)
113 			break;
114 		cpu = OF_peer(cpu);
115 	}
116 	if (cpu == 0)
117 		return (ENOENT);
118 
119 	return (powerpc_smp_fill_cpuref(cpuref, cpu));
120 }
121 
122 int
123 powerpc_smp_get_bsp(struct cpuref *cpuref)
124 {
125 	ihandle_t inst;
126 	phandle_t bsp, chosen;
127 	int res;
128 
129 	chosen = OF_finddevice("/chosen");
130 	if (chosen == 0)
131 		return (ENXIO);
132 
133 	res = OF_getprop(chosen, "cpu", &inst, sizeof(inst));
134 	if (res < 0)
135 		return (ENXIO);
136 
137 	bsp = OF_instance_to_package(inst);
138 	return (powerpc_smp_fill_cpuref(cpuref, bsp));
139 }
140 
141 uint32_t
142 cpudep_ap_bootstrap(volatile uint32_t *trcp)
143 {
144 	uint32_t hid, msr, sp;
145 
146 	trcp[0] = 0x2000;
147 	trcp[1] = (uint32_t)&cpudep_ap_bootstrap;
148 
149 	__asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu));
150 	__asm __volatile("sync");
151 
152 	trcp[0] = 0x2001;
153 	trcp[1] = (uint32_t)pcpup;
154 
155 	hid = mfspr(SPR_HID0);
156 	hid &= ~(HID0_ICE | HID0_DCE);
157 	hid &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
158 	mtspr(SPR_HID0, hid);
159 	isync();
160 
161 	trcp[0] = 0x2002;
162 	trcp[1] = hid;
163 
164 	hid |= HID0_ICFI | HID0_DCFI;
165 	hid |= HID0_ICE | HID0_DCE;
166 	mtspr(SPR_HID0, hid);
167 	isync();
168 
169 	trcp[0] = 0x2003;
170 	trcp[1] = hid;
171 
172 	msr = PSL_IR | PSL_DR | PSL_ME | PSL_RI;
173 	mtmsr(msr);
174 	isync();
175 
176 	trcp[0] = 0x2004;
177 	trcp[1] = msr;
178 
179 	hid |= HID0_NAP | HID0_DPM;
180 	mtspr(SPR_HID0, hid);
181 	isync();
182 
183 	trcp[0] = 0x2005;
184 	trcp[1] = hid;
185 
186 	pcpup->pc_curthread = pcpup->pc_idlethread;
187 	pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb;
188 	sp = pcpup->pc_curpcb->pcb_sp;
189 
190 	trcp[0] = 0x2006;
191 	trcp[1] = sp;
192 
193 	return (sp);
194 }
195 
196 int
197 powerpc_smp_start_cpu(struct pcpu *pc)
198 {
199 	phandle_t cpu;
200 	volatile uint32_t *trcp;
201 	volatile uint8_t *rstvec;
202 	uint32_t trace;
203 	int res, reset, timeout;
204 
205 	cpu = pc->pc_hwref;
206 	res = OF_getprop(cpu, "soft-reset", &reset, sizeof(reset));
207 	if (res < 0)
208 		return (ENXIO);
209 
210 	trcp = (uint32_t *)(EXC_RST + 4);
211 	trace = *trcp;
212 
213 	ap_pcpu = pc;
214 
215 	rstvec = (uint8_t *)(0x80000000 + reset);
216 
217 	*rstvec = 4;
218 	__asm __volatile("sync");
219 	DELAY(1);
220 	*rstvec = 0;
221 	__asm __volatile("sync");
222 
223 	timeout = 1000;
224 	while (!pc->pc_awake && timeout--)
225 		DELAY(100);
226 
227 	if (!pc->pc_awake)
228 		printf("XXX: timeout (trace=%x; data=%x)\n", trcp[0], trcp[1]);
229 
230 	return (0);
231 }
232