]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/arm/mp_machdep.c
Upgrade to OpenSSH 6.8p1.
[FreeBSD/FreeBSD.git] / sys / arm / arm / mp_machdep.c
1 /*-
2  * Copyright (c) 2011 Semihalf.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/bus.h>
31 #include <sys/kernel.h>
32 #include <sys/lock.h>
33 #include <sys/mutex.h>
34 #include <sys/proc.h>
35 #include <sys/pcpu.h>
36 #include <sys/sched.h>
37 #include <sys/smp.h>
38 #include <sys/ktr.h>
39 #include <sys/malloc.h>
40
41 #include <vm/vm.h>
42 #include <vm/vm_extern.h>
43 #include <vm/vm_kern.h>
44 #include <vm/pmap.h>
45
46 #include <machine/armreg.h>
47 #include <machine/cpu.h>
48 #include <machine/cpufunc.h>
49 #include <machine/smp.h>
50 #include <machine/pcb.h>
51 #include <machine/pmap.h>
52 #include <machine/pte.h>
53 #include <machine/physmem.h>
54 #include <machine/intr.h>
55 #include <machine/vmparam.h>
56 #ifdef VFP
57 #include <machine/vfp.h>
58 #endif
59 #ifdef CPU_MV_PJ4B
60 #include <arm/mv/mvwin.h>
61 #include <dev/fdt/fdt_common.h>
62 #endif
63
64 #include "opt_smp.h"
65
66 extern struct pcpu __pcpu[];
67 /* used to hold the AP's until we are ready to release them */
68 struct mtx ap_boot_mtx;
69 struct pcb stoppcbs[MAXCPU];
70
71 /* # of Applications processors */
72 volatile int mp_naps;
73
74 /* Set to 1 once we're ready to let the APs out of the pen. */
75 volatile int aps_ready = 0;
76
77 #ifndef ARM_INTRNG
78 static int ipi_handler(void *arg);
79 #endif
80 void set_stackptrs(int cpu);
81
82 /* Temporary variables for init_secondary()  */
83 void *dpcpu[MAXCPU - 1];
84
85 /* Determine if we running MP machine */
86 int
87 cpu_mp_probe(void)
88 {
89         CPU_SETOF(0, &all_cpus);
90
91         return (platform_mp_probe());
92 }
93
94 /* Start Application Processor via platform specific function */
95 static int
96 check_ap(void)
97 {
98         uint32_t ms;
99
100         for (ms = 0; ms < 2000; ++ms) {
101                 if ((mp_naps + 1) == mp_ncpus)
102                         return (0);             /* success */
103                 else
104                         DELAY(1000);
105         }
106
107         return (-2);
108 }
109
110 extern unsigned char _end[];
111
112 /* Initialize and fire up non-boot processors */
113 void
114 cpu_mp_start(void)
115 {
116         int error, i;
117
118         mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
119
120         /* Reserve memory for application processors */
121         for(i = 0; i < (mp_ncpus - 1); i++)
122                 dpcpu[i] = (void *)kmem_malloc(kernel_arena, DPCPU_SIZE,
123                     M_WAITOK | M_ZERO);
124
125         cpu_idcache_wbinv_all();
126         cpu_l2cache_wbinv_all();
127         cpu_idcache_wbinv_all();
128
129         /* Initialize boot code and start up processors */
130         platform_mp_start_ap();
131
132         /*  Check if ap's started properly */
133         error = check_ap();
134         if (error)
135                 printf("WARNING: Some AP's failed to start\n");
136         else
137                 for (i = 1; i < mp_ncpus; i++)
138                         CPU_SET(i, &all_cpus);
139 }
140
141 /* Introduce rest of cores to the world */
142 void
143 cpu_mp_announce(void)
144 {
145
146 }
147
148 extern vm_paddr_t pmap_pa;
149 void
150 init_secondary(int cpu)
151 {
152         struct pcpu *pc;
153         uint32_t loop_counter;
154 #ifndef ARM_INTRNG
155         int start = 0, end = 0;
156 #endif
157 #ifdef ARM_NEW_PMAP
158         uint32_t actlr_mask, actlr_set;
159
160         pmap_set_tex();
161         cpuinfo_get_actlr_modifier(&actlr_mask, &actlr_set);
162         reinit_mmu(pmap_kern_ttb, actlr_mask, actlr_set);
163         cpu_setup();
164
165         /* Provide stack pointers for other processor modes. */
166         set_stackptrs(cpu);
167
168         enable_interrupts(PSR_A);
169 #else /* ARM_NEW_PMAP */
170         cpu_setup();
171         setttb(pmap_pa);
172         cpu_tlb_flushID();
173 #endif /* ARM_NEW_PMAP */
174         pc = &__pcpu[cpu];
175
176         /*
177          * pcpu_init() updates queue, so it should not be executed in parallel
178          * on several cores
179          */
180         while(mp_naps < (cpu - 1))
181                 ;
182
183         pcpu_init(pc, cpu, sizeof(struct pcpu));
184         dpcpu_init(dpcpu[cpu - 1], cpu);
185 #ifndef ARM_NEW_PMAP
186         /* Provide stack pointers for other processor modes. */
187         set_stackptrs(cpu);
188 #endif
189         /* Signal our startup to BSP */
190         atomic_add_rel_32(&mp_naps, 1);
191
192         /* Spin until the BSP releases the APs */
193         while (!atomic_load_acq_int(&aps_ready)) {
194 #if __ARM_ARCH >= 7
195                 __asm __volatile("wfe");
196 #endif
197         }
198
199         /* Initialize curthread */
200         KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
201         pc->pc_curthread = pc->pc_idlethread;
202         pc->pc_curpcb = pc->pc_idlethread->td_pcb;
203         set_curthread(pc->pc_idlethread);
204 #ifdef VFP
205         vfp_init();
206 #endif
207
208         mtx_lock_spin(&ap_boot_mtx);
209
210         atomic_add_rel_32(&smp_cpus, 1);
211
212         if (smp_cpus == mp_ncpus) {
213                 /* enable IPI's, tlb shootdown, freezes etc */
214                 atomic_store_rel_int(&smp_started, 1);
215         }
216
217         mtx_unlock_spin(&ap_boot_mtx);
218
219 #ifndef ARM_INTRNG
220         /* Enable ipi */
221 #ifdef IPI_IRQ_START
222         start = IPI_IRQ_START;
223 #ifdef IPI_IRQ_END
224         end = IPI_IRQ_END;
225 #else
226         end = IPI_IRQ_START;
227 #endif
228 #endif
229
230         for (int i = start; i <= end; i++)
231                 arm_unmask_irq(i);
232 #endif /* INTRNG */
233         enable_interrupts(PSR_I);
234
235         loop_counter = 0;
236         while (smp_started == 0) {
237                 DELAY(100);
238                 loop_counter++;
239                 if (loop_counter == 1000)
240                         CTR0(KTR_SMP, "AP still wait for smp_started");
241         }
242         /* Start per-CPU event timers. */
243         cpu_initclocks_ap();
244
245         CTR0(KTR_SMP, "go into scheduler");
246         platform_mp_init_secondary();
247
248         /* Enter the scheduler */
249         sched_throw(NULL);
250
251         panic("scheduler returned us to %s", __func__);
252         /* NOTREACHED */
253 }
254
255 #ifdef ARM_INTRNG
256 static void
257 ipi_rendezvous(void *dummy __unused)
258 {
259
260         CTR0(KTR_SMP, "IPI_RENDEZVOUS");
261         smp_rendezvous_action();
262 }
263
264 static void
265 ipi_ast(void *dummy __unused)
266 {
267
268         CTR0(KTR_SMP, "IPI_AST");
269 }
270
271 static void
272 ipi_stop(void *dummy __unused)
273 {
274         u_int cpu;
275
276         /*
277          * IPI_STOP_HARD is mapped to IPI_STOP.
278          */
279         CTR0(KTR_SMP, "IPI_STOP or IPI_STOP_HARD");
280
281         cpu = PCPU_GET(cpuid);
282         savectx(&stoppcbs[cpu]);
283
284         /*
285          * CPUs are stopped when entering the debugger and at
286          * system shutdown, both events which can precede a
287          * panic dump.  For the dump to be correct, all caches
288          * must be flushed and invalidated, but on ARM there's
289          * no way to broadcast a wbinv_all to other cores.
290          * Instead, we have each core do the local wbinv_all as
291          * part of stopping the core.  The core requesting the
292          * stop will do the l2 cache flush after all other cores
293          * have done their l1 flushes and stopped.
294          */
295         cpu_idcache_wbinv_all();
296
297         /* Indicate we are stopped */
298         CPU_SET_ATOMIC(cpu, &stopped_cpus);
299
300         /* Wait for restart */
301         while (!CPU_ISSET(cpu, &started_cpus))
302                 cpu_spinwait();
303
304         CPU_CLR_ATOMIC(cpu, &started_cpus);
305         CPU_CLR_ATOMIC(cpu, &stopped_cpus);
306         CTR0(KTR_SMP, "IPI_STOP (restart)");
307 }
308
309 static void
310 ipi_preempt(void *arg)
311 {
312         struct trapframe *oldframe;
313         struct thread *td;
314
315         critical_enter();
316         td = curthread;
317         td->td_intr_nesting_level++;
318         oldframe = td->td_intr_frame;
319         td->td_intr_frame = (struct trapframe *)arg;
320
321         CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__);
322         sched_preempt(td);
323
324         td->td_intr_frame = oldframe;
325         td->td_intr_nesting_level--;
326         critical_exit();
327 }
328
329 static void
330 ipi_hardclock(void *arg)
331 {
332         struct trapframe *oldframe;
333         struct thread *td;
334
335         critical_enter();
336         td = curthread;
337         td->td_intr_nesting_level++;
338         oldframe = td->td_intr_frame;
339         td->td_intr_frame = (struct trapframe *)arg;
340
341         CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__);
342         hardclockintr();
343
344         td->td_intr_frame = oldframe;
345         td->td_intr_nesting_level--;
346         critical_exit();
347 }
348
349 static void
350 ipi_tlb(void *dummy __unused)
351 {
352
353         CTR1(KTR_SMP, "%s: IPI_TLB", __func__);
354         cpufuncs.cf_tlb_flushID();
355 }
356 #else
357 static int
358 ipi_handler(void *arg)
359 {
360         u_int   cpu, ipi;
361
362         cpu = PCPU_GET(cpuid);
363
364         ipi = pic_ipi_read((int)arg);
365
366         while ((ipi != 0x3ff)) {
367                 switch (ipi) {
368                 case IPI_RENDEZVOUS:
369                         CTR0(KTR_SMP, "IPI_RENDEZVOUS");
370                         smp_rendezvous_action();
371                         break;
372
373                 case IPI_AST:
374                         CTR0(KTR_SMP, "IPI_AST");
375                         break;
376
377                 case IPI_STOP:
378                         /*
379                          * IPI_STOP_HARD is mapped to IPI_STOP so it is not
380                          * necessary to add it in the switch.
381                          */
382                         CTR0(KTR_SMP, "IPI_STOP or IPI_STOP_HARD");
383
384                         savectx(&stoppcbs[cpu]);
385
386                         /*
387                          * CPUs are stopped when entering the debugger and at
388                          * system shutdown, both events which can precede a
389                          * panic dump.  For the dump to be correct, all caches
390                          * must be flushed and invalidated, but on ARM there's
391                          * no way to broadcast a wbinv_all to other cores.
392                          * Instead, we have each core do the local wbinv_all as
393                          * part of stopping the core.  The core requesting the
394                          * stop will do the l2 cache flush after all other cores
395                          * have done their l1 flushes and stopped.
396                          */
397                         cpu_idcache_wbinv_all();
398
399                         /* Indicate we are stopped */
400                         CPU_SET_ATOMIC(cpu, &stopped_cpus);
401
402                         /* Wait for restart */
403                         while (!CPU_ISSET(cpu, &started_cpus))
404                                 cpu_spinwait();
405
406                         CPU_CLR_ATOMIC(cpu, &started_cpus);
407                         CPU_CLR_ATOMIC(cpu, &stopped_cpus);
408                         CTR0(KTR_SMP, "IPI_STOP (restart)");
409                         break;
410                 case IPI_PREEMPT:
411                         CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__);
412                         sched_preempt(curthread);
413                         break;
414                 case IPI_HARDCLOCK:
415                         CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__);
416                         hardclockintr();
417                         break;
418                 case IPI_TLB:
419                         CTR1(KTR_SMP, "%s: IPI_TLB", __func__);
420                         cpufuncs.cf_tlb_flushID();
421                         break;
422                 default:
423                         panic("Unknown IPI 0x%0x on cpu %d", ipi, curcpu);
424                 }
425
426                 pic_ipi_clear(ipi);
427                 ipi = pic_ipi_read(-1);
428         }
429
430         return (FILTER_HANDLED);
431 }
432 #endif
433
434 static void
435 release_aps(void *dummy __unused)
436 {
437         uint32_t loop_counter;
438 #ifndef ARM_INTRNG
439         int start = 0, end = 0;
440 #endif
441
442         if (mp_ncpus == 1)
443                 return;
444
445 #ifdef ARM_INTRNG
446         intr_ipi_set_handler(IPI_RENDEZVOUS, "rendezvous", ipi_rendezvous, NULL, 0);
447         intr_ipi_set_handler(IPI_AST, "ast", ipi_ast, NULL, 0);
448         intr_ipi_set_handler(IPI_STOP, "stop", ipi_stop, NULL, 0);
449         intr_ipi_set_handler(IPI_PREEMPT, "preempt", ipi_preempt, NULL, 0);
450         intr_ipi_set_handler(IPI_HARDCLOCK, "hardclock", ipi_hardclock, NULL, 0);
451         intr_ipi_set_handler(IPI_TLB, "tlb", ipi_tlb, NULL, 0);
452
453 #else
454 #ifdef IPI_IRQ_START
455         start = IPI_IRQ_START;
456 #ifdef IPI_IRQ_END
457         end = IPI_IRQ_END;
458 #else
459         end = IPI_IRQ_START;
460 #endif
461 #endif
462
463         for (int i = start; i <= end; i++) {
464                 /*
465                  * IPI handler
466                  */
467                 /*
468                  * Use 0xdeadbeef as the argument value for irq 0,
469                  * if we used 0, the intr code will give the trap frame
470                  * pointer instead.
471                  */
472                 arm_setup_irqhandler("ipi", ipi_handler, NULL, (void *)i, i,
473                     INTR_TYPE_MISC | INTR_EXCL, NULL);
474
475                 /* Enable ipi */
476                 arm_unmask_irq(i);
477         }
478 #endif
479         atomic_store_rel_int(&aps_ready, 1);
480         /* Wake the other threads up */
481 #if __ARM_ARCH >= 7
482         armv7_sev();
483 #endif
484
485         printf("Release APs\n");
486
487         for (loop_counter = 0; loop_counter < 2000; loop_counter++) {
488                 if (smp_started)
489                         return;
490                 DELAY(1000);
491         }
492         printf("AP's not started\n");
493 }
494
495 SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL);
496
497 struct cpu_group *
498 cpu_topo(void)
499 {
500
501         return (smp_topo_1level(CG_SHARE_L2, mp_ncpus, 0));
502 }
503
504 void
505 cpu_mp_setmaxid(void)
506 {
507
508         platform_mp_setmaxid();
509 }
510
511 /* Sending IPI */
512 void
513 ipi_all_but_self(u_int ipi)
514 {
515         cpuset_t other_cpus;
516
517         other_cpus = all_cpus;
518         CPU_CLR(PCPU_GET(cpuid), &other_cpus);
519         CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
520         platform_ipi_send(other_cpus, ipi);
521 }
522
523 void
524 ipi_cpu(int cpu, u_int ipi)
525 {
526         cpuset_t cpus;
527
528         CPU_ZERO(&cpus);
529         CPU_SET(cpu, &cpus);
530
531         CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x", __func__, cpu, ipi);
532         platform_ipi_send(cpus, ipi);
533 }
534
535 void
536 ipi_selected(cpuset_t cpus, u_int ipi)
537 {
538
539         CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
540         platform_ipi_send(cpus, ipi);
541 }
542
543 void
544 tlb_broadcast(int ipi)
545 {
546
547         if (smp_started)
548                 ipi_all_but_self(ipi);
549 }