mp_machdep.c revision 319202
1/*-
2 * Copyright (c) 2015-2016 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: stable/11/sys/arm64/arm64/mp_machdep.c 319202 2017-05-30 12:26:36Z andrew $");
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#include "pic_if.h"
69
70typedef void intr_ipi_send_t(void *, cpuset_t, u_int);
71typedef void intr_ipi_handler_t(void *);
72
73#define INTR_IPI_NAMELEN	(MAXCOMLEN + 1)
74struct intr_ipi {
75	intr_ipi_handler_t *	ii_handler;
76	void *			ii_handler_arg;
77	intr_ipi_send_t *	ii_send;
78	void *			ii_send_arg;
79	char			ii_name[INTR_IPI_NAMELEN];
80	u_long *		ii_count;
81};
82
83static struct intr_ipi ipi_sources[INTR_IPI_COUNT];
84
85static struct intr_ipi *intr_ipi_lookup(u_int);
86static void intr_pic_ipi_setup(u_int, const char *, intr_ipi_handler_t *,
87    void *);
88
89boolean_t ofw_cpu_reg(phandle_t node, u_int, cell_t *);
90
91extern struct pcpu __pcpu[];
92
93static enum {
94	CPUS_UNKNOWN,
95#ifdef FDT
96	CPUS_FDT,
97#endif
98} cpu_enum_method;
99
100static device_identify_t arm64_cpu_identify;
101static device_probe_t arm64_cpu_probe;
102static device_attach_t arm64_cpu_attach;
103
104static void ipi_ast(void *);
105static void ipi_hardclock(void *);
106static void ipi_preempt(void *);
107static void ipi_rendezvous(void *);
108static void ipi_stop(void *);
109
110static int ipi_handler(void *arg);
111
112struct mtx ap_boot_mtx;
113struct pcb stoppcbs[MAXCPU];
114
115static device_t cpu_list[MAXCPU];
116
117/*
118 * Not all systems boot from the first CPU in the device tree. To work around
119 * this we need to find which CPU we have booted from so when we later
120 * enable the secondary CPUs we skip this one.
121 */
122static int cpu0 = -1;
123
124void mpentry(unsigned long cpuid);
125void init_secondary(uint64_t);
126
127uint8_t secondary_stacks[MAXCPU - 1][PAGE_SIZE * KSTACK_PAGES] __aligned(16);
128
129/* Set to 1 once we're ready to let the APs out of the pen. */
130volatile int aps_ready = 0;
131
132/* Temporary variables for init_secondary()  */
133void *dpcpu[MAXCPU - 1];
134
135static device_method_t arm64_cpu_methods[] = {
136	/* Device interface */
137	DEVMETHOD(device_identify,	arm64_cpu_identify),
138	DEVMETHOD(device_probe,		arm64_cpu_probe),
139	DEVMETHOD(device_attach,	arm64_cpu_attach),
140
141	DEVMETHOD_END
142};
143
144static devclass_t arm64_cpu_devclass;
145static driver_t arm64_cpu_driver = {
146	"arm64_cpu",
147	arm64_cpu_methods,
148	0
149};
150
151DRIVER_MODULE(arm64_cpu, cpu, arm64_cpu_driver, arm64_cpu_devclass, 0, 0);
152
153static void
154arm64_cpu_identify(driver_t *driver, device_t parent)
155{
156
157	if (device_find_child(parent, "arm64_cpu", -1) != NULL)
158		return;
159	if (BUS_ADD_CHILD(parent, 0, "arm64_cpu", -1) == NULL)
160		device_printf(parent, "add child failed\n");
161}
162
163static int
164arm64_cpu_probe(device_t dev)
165{
166	u_int cpuid;
167
168	cpuid = device_get_unit(dev);
169	if (cpuid >= MAXCPU || cpuid > mp_maxid)
170		return (EINVAL);
171
172	device_quiet(dev);
173	return (0);
174}
175
176static int
177arm64_cpu_attach(device_t dev)
178{
179	const uint32_t *reg;
180	size_t reg_size;
181	u_int cpuid;
182	int i;
183
184	cpuid = device_get_unit(dev);
185
186	if (cpuid >= MAXCPU || cpuid > mp_maxid)
187		return (EINVAL);
188	KASSERT(cpu_list[cpuid] == NULL, ("Already have cpu %u", cpuid));
189
190	reg = cpu_get_cpuid(dev, &reg_size);
191	if (reg == NULL)
192		return (EINVAL);
193
194	if (bootverbose) {
195		device_printf(dev, "register <");
196		for (i = 0; i < reg_size; i++)
197			printf("%s%x", (i == 0) ? "" : " ", reg[i]);
198		printf(">\n");
199	}
200
201	/* Set the device to start it later */
202	cpu_list[cpuid] = dev;
203
204	return (0);
205}
206
207static void
208release_aps(void *dummy __unused)
209{
210	int cpu, i;
211
212	intr_pic_ipi_setup(IPI_AST, "ast", ipi_ast, NULL);
213	intr_pic_ipi_setup(IPI_PREEMPT, "preempt", ipi_preempt, NULL);
214	intr_pic_ipi_setup(IPI_RENDEZVOUS, "rendezvous", ipi_rendezvous, NULL);
215	intr_pic_ipi_setup(IPI_STOP, "stop", ipi_stop, NULL);
216	intr_pic_ipi_setup(IPI_STOP_HARD, "stop hard", ipi_stop, NULL);
217	intr_pic_ipi_setup(IPI_HARDCLOCK, "hardclock", ipi_hardclock, NULL);
218
219	atomic_store_rel_int(&aps_ready, 1);
220	/* Wake up the other CPUs */
221	__asm __volatile("sev");
222
223	printf("Release APs\n");
224
225	for (i = 0; i < 2000; i++) {
226		if (smp_started) {
227			for (cpu = 0; cpu <= mp_maxid; cpu++) {
228				if (CPU_ABSENT(cpu))
229					continue;
230				print_cpu_features(cpu);
231			}
232			return;
233		}
234		DELAY(1000);
235	}
236
237	printf("APs not started\n");
238}
239SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL);
240
241void
242init_secondary(uint64_t cpu)
243{
244	struct pcpu *pcpup;
245
246	pcpup = &__pcpu[cpu];
247	/*
248	 * Set the pcpu pointer with a backup in tpidr_el1 to be
249	 * loaded when entering the kernel from userland.
250	 */
251	__asm __volatile(
252	    "mov x18, %0 \n"
253	    "msr tpidr_el1, %0" :: "r"(pcpup));
254
255	/* Spin until the BSP releases the APs */
256	while (!aps_ready)
257		__asm __volatile("wfe");
258
259	/* Initialize curthread */
260	KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
261	pcpup->pc_curthread = pcpup->pc_idlethread;
262	pcpup->pc_curpcb = pcpup->pc_idlethread->td_pcb;
263
264	/*
265	 * Identify current CPU. This is necessary to setup
266	 * affinity registers and to provide support for
267	 * runtime chip identification.
268	 */
269	identify_cpu();
270
271	intr_pic_init_secondary();
272
273	/* Start per-CPU event timers. */
274	cpu_initclocks_ap();
275
276#ifdef VFP
277	vfp_init();
278#endif
279
280	dbg_monitor_init();
281	pan_enable();
282
283	/* Enable interrupts */
284	intr_enable();
285
286	mtx_lock_spin(&ap_boot_mtx);
287
288	atomic_add_rel_32(&smp_cpus, 1);
289
290	if (smp_cpus == mp_ncpus) {
291		/* enable IPI's, tlb shootdown, freezes etc */
292		atomic_store_rel_int(&smp_started, 1);
293	}
294
295	mtx_unlock_spin(&ap_boot_mtx);
296
297	/* Enter the scheduler */
298	sched_throw(NULL);
299
300	panic("scheduler returned us to init_secondary");
301	/* NOTREACHED */
302}
303
304/*
305 *  Send IPI thru interrupt controller.
306 */
307static void
308pic_ipi_send(void *arg, cpuset_t cpus, u_int ipi)
309{
310
311	KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
312	PIC_IPI_SEND(intr_irq_root_dev, arg, cpus, ipi);
313}
314
315/*
316 *  Setup IPI handler on interrupt controller.
317 *
318 *  Not SMP coherent.
319 */
320static void
321intr_pic_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
322    void *arg)
323{
324	struct intr_irqsrc *isrc;
325	struct intr_ipi *ii;
326	int error;
327
328	KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
329	KASSERT(hand != NULL, ("%s: ipi %u no handler", __func__, ipi));
330
331	error = PIC_IPI_SETUP(intr_irq_root_dev, ipi, &isrc);
332	if (error != 0)
333		return;
334
335	isrc->isrc_handlers++;
336
337	ii = intr_ipi_lookup(ipi);
338	KASSERT(ii->ii_count == NULL, ("%s: ipi %u reused", __func__, ipi));
339
340	ii->ii_handler = hand;
341	ii->ii_handler_arg = arg;
342	ii->ii_send = pic_ipi_send;
343	ii->ii_send_arg = isrc;
344	strlcpy(ii->ii_name, name, INTR_IPI_NAMELEN);
345	ii->ii_count = intr_ipi_setup_counters(name);
346}
347
348static void
349intr_ipi_send(cpuset_t cpus, u_int ipi)
350{
351	struct intr_ipi *ii;
352
353	ii = intr_ipi_lookup(ipi);
354	if (ii->ii_count == NULL)
355		panic("%s: not setup IPI %u", __func__, ipi);
356
357	ii->ii_send(ii->ii_send_arg, cpus, ipi);
358}
359
360static void
361ipi_ast(void *dummy __unused)
362{
363
364	CTR0(KTR_SMP, "IPI_AST");
365}
366
367static void
368ipi_hardclock(void *dummy __unused)
369{
370
371	CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__);
372	hardclockintr();
373}
374
375static void
376ipi_preempt(void *dummy __unused)
377{
378	CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__);
379	sched_preempt(curthread);
380}
381
382static void
383ipi_rendezvous(void *dummy __unused)
384{
385
386	CTR0(KTR_SMP, "IPI_RENDEZVOUS");
387	smp_rendezvous_action();
388}
389
390static void
391ipi_stop(void *dummy __unused)
392{
393	u_int cpu;
394
395	CTR0(KTR_SMP, "IPI_STOP");
396
397	cpu = PCPU_GET(cpuid);
398	savectx(&stoppcbs[cpu]);
399
400	/* Indicate we are stopped */
401	CPU_SET_ATOMIC(cpu, &stopped_cpus);
402
403	/* Wait for restart */
404	while (!CPU_ISSET(cpu, &started_cpus))
405		cpu_spinwait();
406
407	CPU_CLR_ATOMIC(cpu, &started_cpus);
408	CPU_CLR_ATOMIC(cpu, &stopped_cpus);
409	CTR0(KTR_SMP, "IPI_STOP (restart)");
410}
411
412struct cpu_group *
413cpu_topo(void)
414{
415
416	return (smp_topo_none());
417}
418
419/* Determine if we running MP machine */
420int
421cpu_mp_probe(void)
422{
423
424	/* ARM64TODO: Read the u bit of mpidr_el1 to determine this */
425	return (1);
426}
427
428#ifdef FDT
429static boolean_t
430cpu_init_fdt(u_int id, phandle_t node, u_int addr_size, pcell_t *reg)
431{
432	uint64_t target_cpu;
433	struct pcpu *pcpup;
434	vm_paddr_t pa;
435	u_int cpuid;
436	int err;
437
438	/* Check we are able to start this cpu */
439	if (id > mp_maxid)
440		return (0);
441
442	KASSERT(id < MAXCPU, ("Too many CPUs"));
443
444	/* We are already running on cpu 0 */
445	if (id == cpu0)
446		return (1);
447
448	/*
449	 * Rotate the CPU IDs to put the boot CPU as CPU 0. We keep the other
450	 * CPUs ordered as the are likely grouped into clusters so it can be
451	 * useful to keep that property, e.g. for the GICv3 driver to send
452	 * an IPI to all CPUs in the cluster.
453	 */
454	cpuid = id;
455	if (cpuid < cpu0)
456		cpuid += mp_maxid + 1;
457	cpuid -= cpu0;
458
459	pcpup = &__pcpu[cpuid];
460	pcpu_init(pcpup, cpuid, sizeof(struct pcpu));
461
462	dpcpu[cpuid - 1] = (void *)kmem_malloc(kernel_arena, DPCPU_SIZE,
463	    M_WAITOK | M_ZERO);
464	dpcpu_init(dpcpu[cpuid - 1], cpuid);
465
466	target_cpu = reg[0];
467	if (addr_size == 2) {
468		target_cpu <<= 32;
469		target_cpu |= reg[1];
470	}
471
472	printf("Starting CPU %u (%lx)\n", cpuid, target_cpu);
473	pa = pmap_extract(kernel_pmap, (vm_offset_t)mpentry);
474
475	err = psci_cpu_on(target_cpu, pa, cpuid);
476	if (err != PSCI_RETVAL_SUCCESS) {
477		/* Panic here if INVARIANTS are enabled */
478		KASSERT(0, ("Failed to start CPU %u (%lx)\n", id,
479		    target_cpu));
480
481		pcpu_destroy(pcpup);
482		kmem_free(kernel_arena, (vm_offset_t)dpcpu[cpuid - 1],
483		    DPCPU_SIZE);
484		dpcpu[cpuid - 1] = NULL;
485		/* Notify the user that the CPU failed to start */
486		printf("Failed to start CPU %u (%lx)\n", id, target_cpu);
487	} else
488		CPU_SET(cpuid, &all_cpus);
489
490	return (1);
491}
492#endif
493
494/* Initialize and fire up non-boot processors */
495void
496cpu_mp_start(void)
497{
498
499	mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
500
501	CPU_SET(0, &all_cpus);
502
503	switch(cpu_enum_method) {
504#ifdef FDT
505	case CPUS_FDT:
506		KASSERT(cpu0 >= 0, ("Current CPU was not found"));
507		ofw_cpu_early_foreach(cpu_init_fdt, true);
508		break;
509#endif
510	case CPUS_UNKNOWN:
511		break;
512	}
513}
514
515/* Introduce rest of cores to the world */
516void
517cpu_mp_announce(void)
518{
519}
520
521static boolean_t
522cpu_find_cpu0_fdt(u_int id, phandle_t node, u_int addr_size, pcell_t *reg)
523{
524	uint64_t mpidr_fdt, mpidr_reg;
525
526	if (cpu0 < 0) {
527		mpidr_fdt = reg[0];
528		if (addr_size == 2) {
529			mpidr_fdt <<= 32;
530			mpidr_fdt |= reg[1];
531		}
532
533		mpidr_reg = READ_SPECIALREG(mpidr_el1);
534
535		if ((mpidr_reg & 0xff00fffffful) == mpidr_fdt)
536			cpu0 = id;
537	}
538
539	return (TRUE);
540}
541
542void
543cpu_mp_setmaxid(void)
544{
545#ifdef FDT
546	int cores;
547
548	cores = ofw_cpu_early_foreach(cpu_find_cpu0_fdt, false);
549	if (cores > 0) {
550		cores = MIN(cores, MAXCPU);
551		if (bootverbose)
552			printf("Found %d CPUs in the device tree\n", cores);
553		mp_ncpus = cores;
554		mp_maxid = cores - 1;
555		cpu_enum_method = CPUS_FDT;
556		return;
557	}
558#endif
559
560	if (bootverbose)
561		printf("No CPU data, limiting to 1 core\n");
562	mp_ncpus = 1;
563	mp_maxid = 0;
564}
565
566/*
567 *  Lookup IPI source.
568 */
569static struct intr_ipi *
570intr_ipi_lookup(u_int ipi)
571{
572
573	if (ipi >= INTR_IPI_COUNT)
574		panic("%s: no such IPI %u", __func__, ipi);
575
576	return (&ipi_sources[ipi]);
577}
578
579/*
580 *  interrupt controller dispatch function for IPIs. It should
581 *  be called straight from the interrupt controller, when associated
582 *  interrupt source is learned. Or from anybody who has an interrupt
583 *  source mapped.
584 */
585void
586intr_ipi_dispatch(u_int ipi, struct trapframe *tf)
587{
588	void *arg;
589	struct intr_ipi *ii;
590
591	ii = intr_ipi_lookup(ipi);
592	if (ii->ii_count == NULL)
593		panic("%s: not setup IPI %u", __func__, ipi);
594
595	intr_ipi_increment_count(ii->ii_count, PCPU_GET(cpuid));
596
597	/*
598	 * Supply ipi filter with trapframe argument
599	 * if none is registered.
600	 */
601	arg = ii->ii_handler_arg != NULL ? ii->ii_handler_arg : tf;
602	ii->ii_handler(arg);
603}
604
605#ifdef notyet
606/*
607 *  Map IPI into interrupt controller.
608 *
609 *  Not SMP coherent.
610 */
611static int
612ipi_map(struct intr_irqsrc *isrc, u_int ipi)
613{
614	boolean_t is_percpu;
615	int error;
616
617	if (ipi >= INTR_IPI_COUNT)
618		panic("%s: no such IPI %u", __func__, ipi);
619
620	KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
621
622	isrc->isrc_type = INTR_ISRCT_NAMESPACE;
623	isrc->isrc_nspc_type = INTR_IRQ_NSPC_IPI;
624	isrc->isrc_nspc_num = ipi_next_num;
625
626	error = PIC_REGISTER(intr_irq_root_dev, isrc, &is_percpu);
627	if (error == 0) {
628		isrc->isrc_dev = intr_irq_root_dev;
629		ipi_next_num++;
630	}
631	return (error);
632}
633
634/*
635 *  Setup IPI handler to interrupt source.
636 *
637 *  Note that there could be more ways how to send and receive IPIs
638 *  on a platform like fast interrupts for example. In that case,
639 *  one can call this function with ASIF_NOALLOC flag set and then
640 *  call intr_ipi_dispatch() when appropriate.
641 *
642 *  Not SMP coherent.
643 */
644int
645intr_ipi_set_handler(u_int ipi, const char *name, intr_ipi_filter_t *filter,
646    void *arg, u_int flags)
647{
648	struct intr_irqsrc *isrc;
649	int error;
650
651	if (filter == NULL)
652		return(EINVAL);
653
654	isrc = intr_ipi_lookup(ipi);
655	if (isrc->isrc_ipifilter != NULL)
656		return (EEXIST);
657
658	if ((flags & AISHF_NOALLOC) == 0) {
659		error = ipi_map(isrc, ipi);
660		if (error != 0)
661			return (error);
662	}
663
664	isrc->isrc_ipifilter = filter;
665	isrc->isrc_arg = arg;
666	isrc->isrc_handlers = 1;
667	isrc->isrc_count = intr_ipi_setup_counters(name);
668	isrc->isrc_index = 0; /* it should not be used in IPI case */
669
670	if (isrc->isrc_dev != NULL) {
671		PIC_ENABLE_INTR(isrc->isrc_dev, isrc);
672		PIC_ENABLE_SOURCE(isrc->isrc_dev, isrc);
673	}
674	return (0);
675}
676#endif
677
678/* Sending IPI */
679void
680ipi_all_but_self(u_int ipi)
681{
682	cpuset_t cpus;
683
684	cpus = all_cpus;
685	CPU_CLR(PCPU_GET(cpuid), &cpus);
686	CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
687	intr_ipi_send(cpus, ipi);
688}
689
690void
691ipi_cpu(int cpu, u_int ipi)
692{
693	cpuset_t cpus;
694
695	CPU_ZERO(&cpus);
696	CPU_SET(cpu, &cpus);
697
698	CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x", __func__, cpu, ipi);
699	intr_ipi_send(cpus, ipi);
700}
701
702void
703ipi_selected(cpuset_t cpus, u_int ipi)
704{
705
706	CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
707	intr_ipi_send(cpus, ipi);
708}
709