]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/mp_machdep.c
Merge ^/head r294961 through r295350.
[FreeBSD/FreeBSD.git] / sys / arm64 / arm64 / mp_machdep.c
1 /*-
2  * Copyright (c) 2015 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Andrew Turner under
6  * sponsorship from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30
31 #include "opt_kstack_pages.h"
32 #include "opt_platform.h"
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/bus.h>
40 #include <sys/cpu.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/module.h>
44 #include <sys/mutex.h>
45 #include <sys/proc.h>
46 #include <sys/sched.h>
47 #include <sys/smp.h>
48
49 #include <vm/vm.h>
50 #include <vm/pmap.h>
51 #include <vm/vm_extern.h>
52 #include <vm/vm_kern.h>
53
54 #include <machine/debug_monitor.h>
55 #include <machine/intr.h>
56 #include <machine/smp.h>
57 #ifdef VFP
58 #include <machine/vfp.h>
59 #endif
60
61 #ifdef FDT
62 #include <dev/ofw/openfirm.h>
63 #include <dev/ofw/ofw_cpu.h>
64 #endif
65
66 #include <dev/psci/psci.h>
67
68 boolean_t ofw_cpu_reg(phandle_t node, u_int, cell_t *);
69
70 extern struct pcpu __pcpu[];
71
72 static enum {
73         CPUS_UNKNOWN,
74 #ifdef FDT
75         CPUS_FDT,
76 #endif
77 } cpu_enum_method;
78
79 static device_identify_t arm64_cpu_identify;
80 static device_probe_t arm64_cpu_probe;
81 static device_attach_t arm64_cpu_attach;
82
83 static int ipi_handler(void *arg);
84
85 struct mtx ap_boot_mtx;
86 struct pcb stoppcbs[MAXCPU];
87
88 #ifdef INVARIANTS
89 static uint32_t cpu_reg[MAXCPU][2];
90 #endif
91 static device_t cpu_list[MAXCPU];
92
93 void mpentry(unsigned long cpuid);
94 void init_secondary(uint64_t);
95
96 uint8_t secondary_stacks[MAXCPU - 1][PAGE_SIZE * KSTACK_PAGES] __aligned(16);
97
98 /* Set to 1 once we're ready to let the APs out of the pen. */
99 volatile int aps_ready = 0;
100
101 /* Temporary variables for init_secondary()  */
102 void *dpcpu[MAXCPU - 1];
103
104 static device_method_t arm64_cpu_methods[] = {
105         /* Device interface */
106         DEVMETHOD(device_identify,      arm64_cpu_identify),
107         DEVMETHOD(device_probe,         arm64_cpu_probe),
108         DEVMETHOD(device_attach,        arm64_cpu_attach),
109
110         DEVMETHOD_END
111 };
112
113 static devclass_t arm64_cpu_devclass;
114 static driver_t arm64_cpu_driver = {
115         "arm64_cpu",
116         arm64_cpu_methods,
117         0
118 };
119
120 DRIVER_MODULE(arm64_cpu, cpu, arm64_cpu_driver, arm64_cpu_devclass, 0, 0);
121
122 static void
123 arm64_cpu_identify(driver_t *driver, device_t parent)
124 {
125
126         if (device_find_child(parent, "arm64_cpu", -1) != NULL)
127                 return;
128         if (BUS_ADD_CHILD(parent, 0, "arm64_cpu", -1) == NULL)
129                 device_printf(parent, "add child failed\n");
130 }
131
132 static int
133 arm64_cpu_probe(device_t dev)
134 {
135         u_int cpuid;
136
137         cpuid = device_get_unit(dev);
138         if (cpuid >= MAXCPU || cpuid > mp_maxid)
139                 return (EINVAL);
140
141         device_quiet(dev);
142         return (0);
143 }
144
145 static int
146 arm64_cpu_attach(device_t dev)
147 {
148         const uint32_t *reg;
149         size_t reg_size;
150         u_int cpuid;
151         int i;
152
153         cpuid = device_get_unit(dev);
154
155         if (cpuid >= MAXCPU || cpuid > mp_maxid)
156                 return (EINVAL);
157         KASSERT(cpu_list[cpuid] == NULL, ("Already have cpu %u", cpuid));
158
159         reg = cpu_get_cpuid(dev, &reg_size);
160         if (reg == NULL)
161                 return (EINVAL);
162
163         if (bootverbose) {
164                 device_printf(dev, "register <");
165                 for (i = 0; i < reg_size; i++)
166                         printf("%s%x", (i == 0) ? "" : " ", reg[i]);
167                 printf(">\n");
168         }
169
170         /* Set the device to start it later */
171         cpu_list[cpuid] = dev;
172
173         return (0);
174 }
175
176 static void
177 release_aps(void *dummy __unused)
178 {
179         int cpu, i;
180
181         /* Setup the IPI handler */
182         for (i = 0; i < COUNT_IPI; i++)
183                 arm_setup_ipihandler(ipi_handler, i);
184
185         atomic_store_rel_int(&aps_ready, 1);
186         /* Wake up the other CPUs */
187         __asm __volatile("sev");
188
189         printf("Release APs\n");
190
191         for (i = 0; i < 2000; i++) {
192                 if (smp_started) {
193                         for (cpu = 0; cpu <= mp_maxid; cpu++) {
194                                 if (CPU_ABSENT(cpu))
195                                         continue;
196                                 print_cpu_features(cpu);
197                         }
198                         return;
199                 }
200                 DELAY(1000);
201         }
202
203         printf("APs not started\n");
204 }
205 SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL);
206
207 void
208 init_secondary(uint64_t cpu)
209 {
210         struct pcpu *pcpup;
211         int i;
212
213         pcpup = &__pcpu[cpu];
214         /*
215          * Set the pcpu pointer with a backup in tpidr_el1 to be
216          * loaded when entering the kernel from userland.
217          */
218         __asm __volatile(
219             "mov x18, %0 \n"
220             "msr tpidr_el1, %0" :: "r"(pcpup));
221
222         /* Spin until the BSP releases the APs */
223         while (!aps_ready)
224                 __asm __volatile("wfe");
225
226         /* Initialize curthread */
227         KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
228         pcpup->pc_curthread = pcpup->pc_idlethread;
229         pcpup->pc_curpcb = pcpup->pc_idlethread->td_pcb;
230
231         /*
232          * Identify current CPU. This is necessary to setup
233          * affinity registers and to provide support for
234          * runtime chip identification.
235          */
236         identify_cpu();
237
238         /* Configure the interrupt controller */
239         arm_init_secondary();
240
241         for (i = 0; i < COUNT_IPI; i++)
242                 arm_unmask_ipi(i);
243
244         /* Start per-CPU event timers. */
245         cpu_initclocks_ap();
246
247 #ifdef VFP
248         vfp_init();
249 #endif
250
251         dbg_monitor_init();
252
253         /* Enable interrupts */
254         intr_enable();
255
256         mtx_lock_spin(&ap_boot_mtx);
257
258         atomic_add_rel_32(&smp_cpus, 1);
259
260         if (smp_cpus == mp_ncpus) {
261                 /* enable IPI's, tlb shootdown, freezes etc */
262                 atomic_store_rel_int(&smp_started, 1);
263         }
264
265         mtx_unlock_spin(&ap_boot_mtx);
266
267         /* Enter the scheduler */
268         sched_throw(NULL);
269
270         panic("scheduler returned us to init_secondary");
271         /* NOTREACHED */
272 }
273
274 static int
275 ipi_handler(void *arg)
276 {
277         u_int cpu, ipi;
278
279         arg = (void *)((uintptr_t)arg & ~(1 << 16));
280         KASSERT((uintptr_t)arg < COUNT_IPI,
281             ("Invalid IPI %ju", (uintptr_t)arg));
282
283         cpu = PCPU_GET(cpuid);
284         ipi = (uintptr_t)arg;
285
286         switch(ipi) {
287         case IPI_AST:
288                 CTR0(KTR_SMP, "IPI_AST");
289                 break;
290         case IPI_PREEMPT:
291                 CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__);
292                 sched_preempt(curthread);
293                 break;
294         case IPI_RENDEZVOUS:
295                 CTR0(KTR_SMP, "IPI_RENDEZVOUS");
296                 smp_rendezvous_action();
297                 break;
298         case IPI_STOP:
299         case IPI_STOP_HARD:
300                 CTR0(KTR_SMP, (ipi == IPI_STOP) ? "IPI_STOP" : "IPI_STOP_HARD");
301                 savectx(&stoppcbs[cpu]);
302
303                 /* Indicate we are stopped */
304                 CPU_SET_ATOMIC(cpu, &stopped_cpus);
305
306                 /* Wait for restart */
307                 while (!CPU_ISSET(cpu, &started_cpus))
308                         cpu_spinwait();
309
310                 CPU_CLR_ATOMIC(cpu, &started_cpus);
311                 CPU_CLR_ATOMIC(cpu, &stopped_cpus);
312                 CTR0(KTR_SMP, "IPI_STOP (restart)");
313                 break;
314         case IPI_HARDCLOCK:
315                 CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__);
316                 hardclockintr();
317                 break;
318         default:
319                 panic("Unknown IPI %#0x on cpu %d", ipi, curcpu);
320         }
321
322         return (FILTER_HANDLED);
323 }
324
325 struct cpu_group *
326 cpu_topo(void)
327 {
328
329         return (smp_topo_none());
330 }
331
332 /* Determine if we running MP machine */
333 int
334 cpu_mp_probe(void)
335 {
336
337         /* ARM64TODO: Read the u bit of mpidr_el1 to determine this */
338         return (1);
339 }
340
341 #ifdef FDT
342 static boolean_t
343 cpu_init_fdt(u_int id, phandle_t node, u_int addr_size, pcell_t *reg)
344 {
345         uint64_t target_cpu;
346         struct pcpu *pcpup;
347         vm_paddr_t pa;
348         int err;
349
350         /* Check we are able to start this cpu */
351         if (id > mp_maxid)
352                 return (0);
353
354         KASSERT(id < MAXCPU, ("Too mant CPUs"));
355
356         KASSERT(addr_size == 1 || addr_size == 2, ("Invalid register size"));
357 #ifdef INVARIANTS
358         cpu_reg[id][0] = reg[0];
359         if (addr_size == 2)
360                 cpu_reg[id][1] = reg[1];
361 #endif
362
363         /* We are already running on cpu 0 */
364         if (id == 0)
365                 return (1);
366
367
368         pcpup = &__pcpu[id];
369         pcpu_init(pcpup, id, sizeof(struct pcpu));
370
371         dpcpu[id - 1] = (void *)kmem_malloc(kernel_arena, DPCPU_SIZE,
372             M_WAITOK | M_ZERO);
373         dpcpu_init(dpcpu[id - 1], id);
374
375         target_cpu = reg[0];
376         if (addr_size == 2) {
377                 target_cpu <<= 32;
378                 target_cpu |= reg[1];
379         }
380
381         printf("Starting CPU %u (%lx)\n", id, target_cpu);
382         pa = pmap_extract(kernel_pmap, (vm_offset_t)mpentry);
383
384         err = psci_cpu_on(target_cpu, pa, id);
385         if (err != PSCI_RETVAL_SUCCESS) {
386                 /* Panic here if INVARIANTS are enabled */
387                 KASSERT(0, ("Failed to start CPU %u (%lx)\n", id, target_cpu));
388
389                 pcpu_destroy(pcpup);
390                 kmem_free(kernel_arena, (vm_offset_t)dpcpu[id - 1], DPCPU_SIZE);
391                 dpcpu[id - 1] = NULL;
392                 /* Notify the user that the CPU failed to start */
393                 printf("Failed to start CPU %u (%lx)\n", id, target_cpu);
394         } else
395                 CPU_SET(id, &all_cpus);
396
397         return (1);
398 }
399 #endif
400
401 /* Initialize and fire up non-boot processors */
402 void
403 cpu_mp_start(void)
404 {
405
406         mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
407
408         CPU_SET(0, &all_cpus);
409
410         switch(cpu_enum_method) {
411 #ifdef FDT
412         case CPUS_FDT:
413                 ofw_cpu_early_foreach(cpu_init_fdt, true);
414                 break;
415 #endif
416         case CPUS_UNKNOWN:
417                 break;
418         }
419 }
420
421 /* Introduce rest of cores to the world */
422 void
423 cpu_mp_announce(void)
424 {
425 }
426
427 void
428 cpu_mp_setmaxid(void)
429 {
430 #ifdef FDT
431         int cores;
432
433         cores = ofw_cpu_early_foreach(NULL, false);
434         if (cores > 0) {
435                 cores = MIN(cores, MAXCPU);
436                 if (bootverbose)
437                         printf("Found %d CPUs in the device tree\n", cores);
438                 mp_ncpus = cores;
439                 mp_maxid = cores - 1;
440                 cpu_enum_method = CPUS_FDT;
441                 return;
442         }
443 #endif
444
445         if (bootverbose)
446                 printf("No CPU data, limiting to 1 core\n");
447         mp_ncpus = 1;
448         mp_maxid = 0;
449 }