]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/malta/malta_mp.c
bhyvectl(8): Normalize the man page date
[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 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 }