1 /*-
2 * Copyright (c) 2016 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
5 * Portions of this software were developed by SRI International and the
6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract
7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Portions of this software were developed by the University of Cambridge
10 * Computer Laboratory as part of the CTSRD Project, with support from the
11 * UK Higher Education Innovation Fund (HEIF).
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * $FreeBSD$
35 */
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 #include <sys/param.h>
41 #include <sys/conf.h>
42 #include <sys/kernel.h>
43 #include <sys/smp.h>
44 #include <sys/systm.h>
45
46 #include <machine/cpufunc.h>
47 #include <machine/hwfunc.h>
48 #include <machine/md_var.h>
49 #include <machine/smp.h>
50
51 #define VPECONF0_VPA (1 << 0)
52 #define MVPCONTROL_VPC (1 << 1)
53 #define MVPCONF0_PVPE_SHIFT 10
54 #define MVPCONF0_PVPE_MASK (0xf << MVPCONF0_PVPE_SHIFT)
55 #define TCSTATUS_A (1 << 13)
56
57 unsigned malta_ap_boot = ~0;
58
59 #define C_SW0 (1 << 8)
60 #define C_SW1 (1 << 9)
61 #define C_IRQ0 (1 << 10)
62 #define C_IRQ1 (1 << 11)
63 #define C_IRQ2 (1 << 12)
64 #define C_IRQ3 (1 << 13)
65 #define C_IRQ4 (1 << 14)
66 #define C_IRQ5 (1 << 15)
67
68 static inline void
69 evpe(void)
70 {
71 __asm __volatile(
72 " .set push \n"
73 " .set noreorder \n"
74 " .set noat \n"
75 " .set mips32r2 \n"
76 " .word 0x41600021 # evpe \n"
77 " ehb \n"
78 " .set pop \n");
79 }
80
81 static inline void
82 ehb(void)
83 {
84 __asm __volatile(
85 " .set mips32r2 \n"
86 " ehb \n"
87 " .set mips0 \n");
88 }
89
90 #define mttc0(rd, sel, val) \
91 ({ \
92 __asm __volatile( \
93 " .set push \n" \
94 " .set mips32r2 \n" \
95 " .set noat \n" \
96 " move $1, %0 \n" \
97 " .word 0x41810000 | (" #rd " << 11) | " #sel " \n" \
98 " .set pop \n" \
99 :: "r" (val)); \
100 })
101
102 #define mftc0(rt, sel) \
103 ({ \
104 unsigned long __res; \
105 __asm __volatile( \
106 " .set push \n" \
107 " .set mips32r2 \n" \
108 " .set noat \n" \
109 " .word 0x41000800 | (" #rt " << 16) | " #sel " \n" \
110 " move %0, $1 \n" \
111 " .set pop \n" \
112 : "=r" (__res)); \
113 __res; \
114 })
115
116 #define write_c0_register32(reg, sel, val) \
117 ({ \
118 __asm __volatile( \
119 " .set push \n" \
120 " .set mips32 \n" \
121 " mtc0 %0, $%1, %2 \n" \
122 " .set pop \n" \
123 :: "r" (val), "i" (reg), "i" (sel)); \
124 })
125
126 #define read_c0_register32(reg, sel) \
127 ({ \
128 uint32_t __retval; \
129 __asm __volatile( \
130 " .set push \n" \
131 " .set mips32 \n" \
132 " mfc0 %0, $%1, %2 \n" \
133 " .set pop \n" \
134 : "=r" (__retval) : "i" (reg), "i" (sel)); \
135 __retval; \
136 })
137
138 static void
139 set_thread_context(int cpuid)
140 {
141 uint32_t reg;
142
143 reg = read_c0_register32(1, 1);
144 reg &= ~(0xff);
145 reg |= cpuid;
146 write_c0_register32(1, 1, reg);
147
148 ehb();
149 }
150
151 void
152 platform_ipi_send(int cpuid)
153 {
154 uint32_t reg;
155
156 set_thread_context(cpuid);
157
158 /* Set cause */
159 reg = mftc0(13, 0);
160 reg |= (C_SW1);
161 mttc0(13, 0, reg);
162 }
163
164 void
165 platform_ipi_clear(void)
166 {
167 uint32_t reg;
168
169 reg = mips_rd_cause();
170 reg &= ~(C_SW1);
171 mips_wr_cause(reg);
172 }
173
174 int
175 platform_ipi_hardintr_num(void)
176 {
177
178 return (-1);
179 }
180
181 int
182 platform_ipi_softintr_num(void)
183 {
184
185 return (1);
186 }
187
188 void
189 platform_init_ap(int cpuid)
190 {
191 uint32_t clock_int_mask;
192 uint32_t ipi_intr_mask;
193
194 /*
195 * Clear any pending IPIs.
196 */
197 platform_ipi_clear();
198
199 /*
200 * Unmask the clock and ipi interrupts.
201 */
202 ipi_intr_mask = soft_int_mask(platform_ipi_softintr_num());
203 clock_int_mask = hard_int_mask(5);
204 set_intr_mask(ipi_intr_mask | clock_int_mask);
205
206 mips_wbflush();
207 }
208
209 void
210 platform_cpu_mask(cpuset_t *mask)
211 {
212 uint32_t i, ncpus, reg;
213
214 reg = mftc0(0, 2);
215 ncpus = ((reg & MVPCONF0_PVPE_MASK) >> MVPCONF0_PVPE_SHIFT) + 1;
216
217 CPU_ZERO(mask);
218 for (i = 0; i < ncpus; i++)
219 CPU_SET(i, mask);
220 }
221
222 struct cpu_group *
223 platform_smp_topo(void)
224 {
225
226 return (smp_topo_none());
227 }
228
229 int
230 platform_start_ap(int cpuid)
231 {
232 uint32_t reg;
233 int timeout;
234
235 /* Enter into configuration */
236 reg = read_c0_register32(0, 1);
237 reg |= (MVPCONTROL_VPC);
238 write_c0_register32(0, 1, reg);
239
240 set_thread_context(cpuid);
241
242 /*
243 * Hint: how to set entry point.
244 * reg = 0x80000000;
245 * mttc0(2, 3, reg);
246 */
247
248 /* Enable thread */
249 reg = mftc0(2, 1);
250 reg |= (TCSTATUS_A);
251 mttc0(2, 1, reg);
252
253 /* Unhalt CPU core */
254 mttc0(2, 4, 0);
255
256 /* Activate VPE */
257 reg = mftc0(1, 2);
258 reg |= (VPECONF0_VPA);
259 mttc0(1, 2, reg);
260
261 /* Out of configuration */
262 reg = read_c0_register32(0, 1);
263 reg &= ~(MVPCONTROL_VPC);
264 write_c0_register32(0, 1, reg);
265
266 evpe();
267
268 if (atomic_cmpset_32(&malta_ap_boot, ~0, cpuid) == 0)
269 return (-1);
270
271 printf("Waiting for cpu%d to start\n", cpuid);
272
273 timeout = 100;
274 do {
275 DELAY(1000);
276 if (atomic_cmpset_32(&malta_ap_boot, 0, ~0) != 0) {
277 printf("CPU %d started\n", cpuid);
278 return (0);
279 }
280 } while (timeout--);
281
282 printf("CPU %d failed to start\n", cpuid);
283
284 return (0);
285 }
Cache object: fbf59654d0fbf99ce92a21ac6b4ab3a9
|