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