]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/malta/malta_mp.c
Merge libc++ trunk r338150, and resolve conflicts.
[FreeBSD/FreeBSD.git] / sys / mips / malta / malta_mp.c
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 MALTA_MAXCPU    2
52 #define VPECONF0_VPA    (1 << 0)
53 #define MVPCONTROL_VPC  (1 << 1)
54 #define TCSTATUS_A      (1 << 13)
55
56 unsigned malta_ap_boot = ~0;
57
58 #define C_SW0           (1 << 8)
59 #define C_SW1           (1 << 9)
60 #define C_IRQ0          (1 << 10)
61 #define C_IRQ1          (1 << 11)
62 #define C_IRQ2          (1 << 12)
63 #define C_IRQ3          (1 << 13)
64 #define C_IRQ4          (1 << 14)
65 #define C_IRQ5          (1 << 15)
66
67 static inline void
68 evpe(void)
69 {
70         __asm __volatile(
71         "       .set push                       \n"
72         "       .set noreorder                  \n"
73         "       .set noat                       \n"
74         "       .set mips32r2                   \n"
75         "       .word   0x41600021      # evpe  \n"
76         "       ehb                             \n"
77         "       .set pop                        \n");
78 }
79
80 static inline void
81 ehb(void)
82 {
83         __asm __volatile(
84         "       .set mips32r2   \n"
85         "       ehb             \n"
86         "       .set mips0      \n");
87 }
88
89 #define mttc0(rd, sel, val)                                             \
90 ({                                                                      \
91         __asm __volatile(                                               \
92         "       .set push                                       \n"     \
93         "       .set mips32r2                                   \n"     \
94         "       .set noat                                       \n"     \
95         "       move    $1, %0                                  \n"     \
96         "       .word 0x41810000 | (" #rd " << 11) | " #sel "   \n"     \
97         "       .set pop                                        \n"     \
98         :: "r" (val));                                                  \
99 })
100
101 #define mftc0(rt, sel)                                                  \
102 ({                                                                      \
103         unsigned long __res;                                            \
104         __asm __volatile(                                               \
105         "       .set push                                       \n"     \
106         "       .set mips32r2                                   \n"     \
107         "       .set noat                                       \n"     \
108         "       .word 0x41000800 | (" #rt " << 16) | " #sel "   \n"     \
109         "       move    %0, $1                                  \n"     \
110         "       .set pop                                        \n"     \
111         : "=r" (__res));                                                \
112          __res;                                                         \
113 })
114
115 #define write_c0_register32(reg, sel, val)                              \
116 ({                                                                      \
117         __asm __volatile(                                               \
118         "       .set push                                       \n"     \
119         "       .set mips32                                     \n"     \
120         "       mtc0    %0, $%1, %2                             \n"     \
121         "       .set pop                                        \n"     \
122         :: "r" (val), "i" (reg), "i" (sel));                            \
123 })
124
125 #define read_c0_register32(reg, sel)                                    \
126 ({                                                                      \
127         uint32_t __retval;                                              \
128         __asm __volatile(                                               \
129         "       .set push                                       \n"     \
130         "       .set mips32                                     \n"     \
131         "       mfc0    %0, $%1, %2                             \n"     \
132         "       .set pop                                        \n"     \
133         : "=r" (__retval) : "i" (reg), "i" (sel));                      \
134         __retval;                                                       \
135 })
136
137 static void
138 set_thread_context(int cpuid)
139 {
140         uint32_t reg;
141
142         reg = read_c0_register32(1, 1);
143         reg &= ~(0xff);
144         reg |= cpuid;
145         write_c0_register32(1, 1, reg);
146
147         ehb();
148 }
149
150 void
151 platform_ipi_send(int cpuid)
152 {
153         uint32_t reg;
154
155         set_thread_context(cpuid);
156
157         /* Set cause */
158         reg = mftc0(13, 0);
159         reg |= (C_SW1);
160         mttc0(13, 0, reg);
161 }
162
163 void
164 platform_ipi_clear(void)
165 {
166         uint32_t reg;
167
168         reg = mips_rd_cause();
169         reg &= ~(C_SW1);
170         mips_wr_cause(reg);
171 }
172
173 int
174 platform_ipi_hardintr_num(void)
175 {
176
177         return (-1);
178 }
179
180 int
181 platform_ipi_softintr_num(void)
182 {
183
184         return (1);
185 }
186
187 void
188 platform_init_ap(int cpuid)
189 {
190         uint32_t clock_int_mask;
191         uint32_t ipi_intr_mask;
192
193         /*
194          * Clear any pending IPIs.
195          */
196         platform_ipi_clear();
197
198         /*
199          * Unmask the clock and ipi interrupts.
200          */
201         ipi_intr_mask = soft_int_mask(platform_ipi_softintr_num());
202         clock_int_mask = hard_int_mask(5);
203         set_intr_mask(ipi_intr_mask | clock_int_mask);
204
205         mips_wbflush();
206 }
207
208 void
209 platform_cpu_mask(cpuset_t *mask)
210 {
211         uint32_t i, m;
212
213         CPU_ZERO(mask);
214         for (i = 0, m = 1 ; i < MALTA_MAXCPU; i++, m <<= 1)
215                 CPU_SET(i, mask);
216 }
217
218 struct cpu_group *
219 platform_smp_topo(void)
220 {
221
222         return (smp_topo_none());
223 }
224
225 int
226 platform_start_ap(int cpuid)
227 {
228         uint32_t reg;
229         int timeout;
230
231         /* Enter into configuration */
232         reg = read_c0_register32(0, 1);
233         reg |= (MVPCONTROL_VPC);
234         write_c0_register32(0, 1, reg);
235
236         set_thread_context(cpuid);
237
238         /*
239          * Hint: how to set entry point.
240          * reg = 0x80000000;
241          * mttc0(2, 3, reg);
242          */
243
244         /* Enable thread */
245         reg = mftc0(2, 1);
246         reg |= (TCSTATUS_A);
247         mttc0(2, 1, reg);
248
249         /* Unhalt CPU core */
250         mttc0(2, 4, 0);
251
252         /* Activate VPE */
253         reg = mftc0(1, 2);
254         reg |= (VPECONF0_VPA);
255         mttc0(1, 2, reg);
256
257         /* Out of configuration */
258         reg = read_c0_register32(0, 1);
259         reg &= ~(MVPCONTROL_VPC);
260         write_c0_register32(0, 1, reg);
261
262         evpe();
263
264         if (atomic_cmpset_32(&malta_ap_boot, ~0, cpuid) == 0)
265                 return (-1);
266
267         printf("Waiting for cpu%d to start\n", cpuid);
268
269         timeout = 100;
270         do {
271                 DELAY(1000);
272                 if (atomic_cmpset_32(&malta_ap_boot, 0, ~0) != 0) {
273                         printf("CPU %d started\n", cpuid);
274                         return (0);
275                 }
276         } while (timeout--);
277
278         printf("CPU %d failed to start\n", cpuid);
279
280         return (0);
281 }