xref: /freebsd/sys/arm/arm/mp_machdep.c (revision d93a896e)
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 "opt_ddb.h"
27 #include "opt_smp.h"
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/bus.h>
34 #include <sys/kernel.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <sys/proc.h>
38 #include <sys/pcpu.h>
39 #include <sys/sched.h>
40 #include <sys/smp.h>
41 #include <sys/ktr.h>
42 #include <sys/malloc.h>
43 
44 #include <vm/vm.h>
45 #include <vm/vm_extern.h>
46 #include <vm/vm_kern.h>
47 #include <vm/pmap.h>
48 
49 #include <machine/armreg.h>
50 #include <machine/cpu.h>
51 #include <machine/cpufunc.h>
52 #include <machine/debug_monitor.h>
53 #include <machine/smp.h>
54 #include <machine/pcb.h>
55 #include <machine/physmem.h>
56 #include <machine/intr.h>
57 #include <machine/vmparam.h>
58 #ifdef VFP
59 #include <machine/vfp.h>
60 #endif
61 #ifdef CPU_MV_PJ4B
62 #include <arm/mv/mvwin.h>
63 #endif
64 
65 extern struct pcpu __pcpu[];
66 /* used to hold the AP's until we are ready to release them */
67 struct mtx ap_boot_mtx;
68 struct pcb stoppcbs[MAXCPU];
69 
70 /* # of Applications processors */
71 volatile int mp_naps;
72 
73 /* Set to 1 once we're ready to let the APs out of the pen. */
74 volatile int aps_ready = 0;
75 
76 #ifndef INTRNG
77 static int ipi_handler(void *arg);
78 #endif
79 void set_stackptrs(int cpu);
80 
81 /* Temporary variables for init_secondary()  */
82 void *dpcpu[MAXCPU - 1];
83 
84 /* Determine if we running MP machine */
85 int
86 cpu_mp_probe(void)
87 {
88 
89 	KASSERT(mp_ncpus != 0, ("cpu_mp_probe: mp_ncpus is unset"));
90 
91 	CPU_SETOF(0, &all_cpus);
92 
93 	return (mp_ncpus > 1);
94 }
95 
96 /* Start Application Processor via platform specific function */
97 static int
98 check_ap(void)
99 {
100 	uint32_t ms;
101 
102 	for (ms = 0; ms < 2000; ++ms) {
103 		if ((mp_naps + 1) == mp_ncpus)
104 			return (0);		/* success */
105 		else
106 			DELAY(1000);
107 	}
108 
109 	return (-2);
110 }
111 
112 extern unsigned char _end[];
113 
114 /* Initialize and fire up non-boot processors */
115 void
116 cpu_mp_start(void)
117 {
118 	int error, i;
119 
120 	mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
121 
122 	/* Reserve memory for application processors */
123 	for(i = 0; i < (mp_ncpus - 1); i++)
124 		dpcpu[i] = (void *)kmem_malloc(kernel_arena, DPCPU_SIZE,
125 		    M_WAITOK | M_ZERO);
126 
127 	dcache_wbinv_poc_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 INTRNG
155 	int start = 0, end = 0;
156 #endif
157 
158 	pmap_set_tex();
159 	cpuinfo_reinit_mmu(pmap_kern_ttb);
160 	cpu_setup();
161 
162 	/* Provide stack pointers for other processor modes. */
163 	set_stackptrs(cpu);
164 
165 	enable_interrupts(PSR_A);
166 	pc = &__pcpu[cpu];
167 
168 	/*
169 	 * pcpu_init() updates queue, so it should not be executed in parallel
170 	 * on several cores
171 	 */
172 	while(mp_naps < (cpu - 1))
173 		;
174 
175 	pcpu_init(pc, cpu, sizeof(struct pcpu));
176 	dpcpu_init(dpcpu[cpu - 1], cpu);
177 #if __ARM_ARCH >= 6 && defined(DDB)
178 	dbg_monitor_init_secondary();
179 #endif
180 	/* Signal our startup to BSP */
181 	atomic_add_rel_32(&mp_naps, 1);
182 
183 	/* Spin until the BSP releases the APs */
184 	while (!atomic_load_acq_int(&aps_ready)) {
185 #if __ARM_ARCH >= 7
186 		__asm __volatile("wfe");
187 #endif
188 	}
189 
190 	/* Initialize curthread */
191 	KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
192 	pc->pc_curthread = pc->pc_idlethread;
193 	pc->pc_curpcb = pc->pc_idlethread->td_pcb;
194 	set_curthread(pc->pc_idlethread);
195 #ifdef VFP
196 	vfp_init();
197 #endif
198 
199 	/* Configure the interrupt controller */
200 	intr_pic_init_secondary();
201 
202 	mtx_lock_spin(&ap_boot_mtx);
203 
204 	atomic_add_rel_32(&smp_cpus, 1);
205 
206 	if (smp_cpus == mp_ncpus) {
207 		/* enable IPI's, tlb shootdown, freezes etc */
208 		atomic_store_rel_int(&smp_started, 1);
209 	}
210 
211 	mtx_unlock_spin(&ap_boot_mtx);
212 
213 #ifndef INTRNG
214 	/* Enable ipi */
215 #ifdef IPI_IRQ_START
216 	start = IPI_IRQ_START;
217 #ifdef IPI_IRQ_END
218 	end = IPI_IRQ_END;
219 #else
220 	end = IPI_IRQ_START;
221 #endif
222 #endif
223 
224 	for (int i = start; i <= end; i++)
225 		arm_unmask_irq(i);
226 #endif /* INTRNG */
227 	enable_interrupts(PSR_I);
228 
229 	loop_counter = 0;
230 	while (smp_started == 0) {
231 		DELAY(100);
232 		loop_counter++;
233 		if (loop_counter == 1000)
234 			CTR0(KTR_SMP, "AP still wait for smp_started");
235 	}
236 	/* Start per-CPU event timers. */
237 	cpu_initclocks_ap();
238 
239 	CTR0(KTR_SMP, "go into scheduler");
240 
241 	/* Enter the scheduler */
242 	sched_throw(NULL);
243 
244 	panic("scheduler returned us to %s", __func__);
245 	/* NOTREACHED */
246 }
247 
248 #ifdef INTRNG
249 static void
250 ipi_rendezvous(void *dummy __unused)
251 {
252 
253 	CTR0(KTR_SMP, "IPI_RENDEZVOUS");
254 	smp_rendezvous_action();
255 }
256 
257 static void
258 ipi_ast(void *dummy __unused)
259 {
260 
261 	CTR0(KTR_SMP, "IPI_AST");
262 }
263 
264 static void
265 ipi_stop(void *dummy __unused)
266 {
267 	u_int cpu;
268 
269 	/*
270 	 * IPI_STOP_HARD is mapped to IPI_STOP.
271 	 */
272 	CTR0(KTR_SMP, "IPI_STOP or IPI_STOP_HARD");
273 
274 	cpu = PCPU_GET(cpuid);
275 	savectx(&stoppcbs[cpu]);
276 
277 	/*
278 	 * CPUs are stopped when entering the debugger and at
279 	 * system shutdown, both events which can precede a
280 	 * panic dump.  For the dump to be correct, all caches
281 	 * must be flushed and invalidated, but on ARM there's
282 	 * no way to broadcast a wbinv_all to other cores.
283 	 * Instead, we have each core do the local wbinv_all as
284 	 * part of stopping the core.  The core requesting the
285 	 * stop will do the l2 cache flush after all other cores
286 	 * have done their l1 flushes and stopped.
287 	 */
288 	dcache_wbinv_poc_all();
289 
290 	/* Indicate we are stopped */
291 	CPU_SET_ATOMIC(cpu, &stopped_cpus);
292 
293 	/* Wait for restart */
294 	while (!CPU_ISSET(cpu, &started_cpus))
295 		cpu_spinwait();
296 
297 	CPU_CLR_ATOMIC(cpu, &started_cpus);
298 	CPU_CLR_ATOMIC(cpu, &stopped_cpus);
299 #ifdef DDB
300 	dbg_resume_dbreg();
301 #endif
302 	CTR0(KTR_SMP, "IPI_STOP (restart)");
303 }
304 
305 static void
306 ipi_preempt(void *arg)
307 {
308 	struct trapframe *oldframe;
309 	struct thread *td;
310 
311 	critical_enter();
312 	td = curthread;
313 	td->td_intr_nesting_level++;
314 	oldframe = td->td_intr_frame;
315 	td->td_intr_frame = (struct trapframe *)arg;
316 
317 	CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__);
318 	sched_preempt(td);
319 
320 	td->td_intr_frame = oldframe;
321 	td->td_intr_nesting_level--;
322 	critical_exit();
323 }
324 
325 static void
326 ipi_hardclock(void *arg)
327 {
328 	struct trapframe *oldframe;
329 	struct thread *td;
330 
331 	critical_enter();
332 	td = curthread;
333 	td->td_intr_nesting_level++;
334 	oldframe = td->td_intr_frame;
335 	td->td_intr_frame = (struct trapframe *)arg;
336 
337 	CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__);
338 	hardclockintr();
339 
340 	td->td_intr_frame = oldframe;
341 	td->td_intr_nesting_level--;
342 	critical_exit();
343 }
344 
345 #else
346 static int
347 ipi_handler(void *arg)
348 {
349 	u_int	cpu, ipi;
350 
351 	cpu = PCPU_GET(cpuid);
352 
353 	ipi = pic_ipi_read((int)arg);
354 
355 	while ((ipi != 0x3ff)) {
356 		switch (ipi) {
357 		case IPI_RENDEZVOUS:
358 			CTR0(KTR_SMP, "IPI_RENDEZVOUS");
359 			smp_rendezvous_action();
360 			break;
361 
362 		case IPI_AST:
363 			CTR0(KTR_SMP, "IPI_AST");
364 			break;
365 
366 		case IPI_STOP:
367 			/*
368 			 * IPI_STOP_HARD is mapped to IPI_STOP so it is not
369 			 * necessary to add it in the switch.
370 			 */
371 			CTR0(KTR_SMP, "IPI_STOP or IPI_STOP_HARD");
372 
373 			savectx(&stoppcbs[cpu]);
374 
375 			/*
376 			 * CPUs are stopped when entering the debugger and at
377 			 * system shutdown, both events which can precede a
378 			 * panic dump.  For the dump to be correct, all caches
379 			 * must be flushed and invalidated, but on ARM there's
380 			 * no way to broadcast a wbinv_all to other cores.
381 			 * Instead, we have each core do the local wbinv_all as
382 			 * part of stopping the core.  The core requesting the
383 			 * stop will do the l2 cache flush after all other cores
384 			 * have done their l1 flushes and stopped.
385 			 */
386 			dcache_wbinv_poc_all();
387 
388 			/* Indicate we are stopped */
389 			CPU_SET_ATOMIC(cpu, &stopped_cpus);
390 
391 			/* Wait for restart */
392 			while (!CPU_ISSET(cpu, &started_cpus))
393 				cpu_spinwait();
394 
395 			CPU_CLR_ATOMIC(cpu, &started_cpus);
396 			CPU_CLR_ATOMIC(cpu, &stopped_cpus);
397 #ifdef DDB
398 			dbg_resume_dbreg();
399 #endif
400 			CTR0(KTR_SMP, "IPI_STOP (restart)");
401 			break;
402 		case IPI_PREEMPT:
403 			CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__);
404 			sched_preempt(curthread);
405 			break;
406 		case IPI_HARDCLOCK:
407 			CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__);
408 			hardclockintr();
409 			break;
410 		default:
411 			panic("Unknown IPI 0x%0x on cpu %d", ipi, curcpu);
412 		}
413 
414 		pic_ipi_clear(ipi);
415 		ipi = pic_ipi_read(-1);
416 	}
417 
418 	return (FILTER_HANDLED);
419 }
420 #endif
421 
422 static void
423 release_aps(void *dummy __unused)
424 {
425 	uint32_t loop_counter;
426 #ifndef INTRNG
427 	int start = 0, end = 0;
428 #endif
429 
430 	if (mp_ncpus == 1)
431 		return;
432 
433 #ifdef INTRNG
434 	intr_pic_ipi_setup(IPI_RENDEZVOUS, "rendezvous", ipi_rendezvous, NULL);
435 	intr_pic_ipi_setup(IPI_AST, "ast", ipi_ast, NULL);
436 	intr_pic_ipi_setup(IPI_STOP, "stop", ipi_stop, NULL);
437 	intr_pic_ipi_setup(IPI_PREEMPT, "preempt", ipi_preempt, NULL);
438 	intr_pic_ipi_setup(IPI_HARDCLOCK, "hardclock", ipi_hardclock, NULL);
439 #else
440 #ifdef IPI_IRQ_START
441 	start = IPI_IRQ_START;
442 #ifdef IPI_IRQ_END
443 	end = IPI_IRQ_END;
444 #else
445 	end = IPI_IRQ_START;
446 #endif
447 #endif
448 
449 	for (int i = start; i <= end; i++) {
450 		/*
451 		 * IPI handler
452 		 */
453 		/*
454 		 * Use 0xdeadbeef as the argument value for irq 0,
455 		 * if we used 0, the intr code will give the trap frame
456 		 * pointer instead.
457 		 */
458 		arm_setup_irqhandler("ipi", ipi_handler, NULL, (void *)i, i,
459 		    INTR_TYPE_MISC | INTR_EXCL, NULL);
460 
461 		/* Enable ipi */
462 		arm_unmask_irq(i);
463 	}
464 #endif
465 	atomic_store_rel_int(&aps_ready, 1);
466 	/* Wake the other threads up */
467 	dsb();
468 	sev();
469 
470 	printf("Release APs\n");
471 
472 	for (loop_counter = 0; loop_counter < 2000; loop_counter++) {
473 		if (smp_started)
474 			return;
475 		DELAY(1000);
476 	}
477 	printf("AP's not started\n");
478 }
479 
480 SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL);
481 
482 struct cpu_group *
483 cpu_topo(void)
484 {
485 
486 	return (smp_topo_1level(CG_SHARE_L2, mp_ncpus, 0));
487 }
488 
489 void
490 cpu_mp_setmaxid(void)
491 {
492 
493 	platform_mp_setmaxid();
494 }
495 
496 /* Sending IPI */
497 void
498 ipi_all_but_self(u_int ipi)
499 {
500 	cpuset_t other_cpus;
501 
502 	other_cpus = all_cpus;
503 	CPU_CLR(PCPU_GET(cpuid), &other_cpus);
504 	CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
505 #ifdef INTRNG
506 	intr_ipi_send(other_cpus, ipi);
507 #else
508 	pic_ipi_send(other_cpus, ipi);
509 #endif
510 }
511 
512 void
513 ipi_cpu(int cpu, u_int ipi)
514 {
515 	cpuset_t cpus;
516 
517 	CPU_ZERO(&cpus);
518 	CPU_SET(cpu, &cpus);
519 
520 	CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x", __func__, cpu, ipi);
521 #ifdef INTRNG
522 	intr_ipi_send(cpus, ipi);
523 #else
524 	pic_ipi_send(cpus, ipi);
525 #endif
526 }
527 
528 void
529 ipi_selected(cpuset_t cpus, u_int ipi)
530 {
531 
532 	CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
533 #ifdef INTRNG
534 	intr_ipi_send(cpus, ipi);
535 #else
536 	pic_ipi_send(cpus, ipi);
537 #endif
538 }
539