xref: /f-stack/freebsd/mips/malta/malta_mp.c (revision 22ce4aff)
1 /*-
2  * Copyright (c) 2016 Ruslan Bukin <[email protected]>
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
evpe(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
ehb(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
set_thread_context(int cpuid)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
platform_ipi_send(int cpuid)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
platform_ipi_clear(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
platform_ipi_hardintr_num(void)175 platform_ipi_hardintr_num(void)
176 {
177 
178 	return (-1);
179 }
180 
181 int
platform_ipi_softintr_num(void)182 platform_ipi_softintr_num(void)
183 {
184 
185 	return (1);
186 }
187 
188 void
platform_init_ap(int cpuid)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
platform_cpu_mask(cpuset_t * mask)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 *
platform_smp_topo(void)223 platform_smp_topo(void)
224 {
225 
226 	return (smp_topo_none());
227 }
228 
229 int
platform_start_ap(int cpuid)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 }
286