]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/mp_machdep.c
MFH
[FreeBSD/FreeBSD.git] / sys / arm64 / arm64 / mp_machdep.c
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_acpi.h"
32 #include "opt_ddb.h"
33 #include "opt_kstack_pages.h"
34 #include "opt_platform.h"
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/bus.h>
42 #include <sys/cpu.h>
43 #include <sys/csan.h>
44 #include <sys/kernel.h>
45 #include <sys/ktr.h>
46 #include <sys/malloc.h>
47 #include <sys/module.h>
48 #include <sys/mutex.h>
49 #include <sys/pcpu.h>
50 #include <sys/proc.h>
51 #include <sys/sched.h>
52 #include <sys/smp.h>
53
54 #include <vm/vm.h>
55 #include <vm/pmap.h>
56 #include <vm/vm_extern.h>
57 #include <vm/vm_kern.h>
58 #include <vm/vm_map.h>
59
60 #include <machine/machdep.h>
61 #include <machine/debug_monitor.h>
62 #include <machine/intr.h>
63 #include <machine/smp.h>
64 #ifdef VFP
65 #include <machine/vfp.h>
66 #endif
67
68 #ifdef DEV_ACPI
69 #include <contrib/dev/acpica/include/acpi.h>
70 #include <dev/acpica/acpivar.h>
71 #endif
72
73 #ifdef FDT
74 #include <dev/ofw/openfirm.h>
75 #include <dev/ofw/ofw_bus.h>
76 #include <dev/ofw/ofw_bus_subr.h>
77 #include <dev/ofw/ofw_cpu.h>
78 #endif
79
80 #include <dev/psci/psci.h>
81
82 #include "pic_if.h"
83
84 #define MP_QUIRK_CPULIST        0x01    /* The list of cpus may be wrong, */
85                                         /* don't panic if one fails to start */
86 static uint32_t mp_quirks;
87
88 #ifdef FDT
89 static struct {
90         const char *compat;
91         uint32_t quirks;
92 } fdt_quirks[] = {
93         { "arm,foundation-aarch64",     MP_QUIRK_CPULIST },
94         { "arm,fvp-base",               MP_QUIRK_CPULIST },
95         /* This is incorrect in some DTS files */
96         { "arm,vfp-base",               MP_QUIRK_CPULIST },
97         { NULL, 0 },
98 };
99 #endif
100
101 typedef void intr_ipi_send_t(void *, cpuset_t, u_int);
102 typedef void intr_ipi_handler_t(void *);
103
104 #define INTR_IPI_NAMELEN        (MAXCOMLEN + 1)
105 struct intr_ipi {
106         intr_ipi_handler_t *    ii_handler;
107         void *                  ii_handler_arg;
108         intr_ipi_send_t *       ii_send;
109         void *                  ii_send_arg;
110         char                    ii_name[INTR_IPI_NAMELEN];
111         u_long *                ii_count;
112 };
113
114 static struct intr_ipi ipi_sources[INTR_IPI_COUNT];
115
116 static struct intr_ipi *intr_ipi_lookup(u_int);
117 static void intr_pic_ipi_setup(u_int, const char *, intr_ipi_handler_t *,
118     void *);
119
120 static void ipi_ast(void *);
121 static void ipi_hardclock(void *);
122 static void ipi_preempt(void *);
123 static void ipi_rendezvous(void *);
124 static void ipi_stop(void *);
125
126 struct pcb stoppcbs[MAXCPU];
127
128 /*
129  * Not all systems boot from the first CPU in the device tree. To work around
130  * this we need to find which CPU we have booted from so when we later
131  * enable the secondary CPUs we skip this one.
132  */
133 static int cpu0 = -1;
134
135 void mpentry(unsigned long cpuid);
136 void init_secondary(uint64_t);
137
138 /* Synchronize AP startup. */
139 static struct mtx ap_boot_mtx;
140
141 /* Stacks for AP initialization, discarded once idle threads are started. */
142 void *bootstack;
143 static void *bootstacks[MAXCPU];
144
145 /* Count of started APs, used to synchronize access to bootstack. */
146 static volatile int aps_started;
147
148 /* Set to 1 once we're ready to let the APs out of the pen. */
149 static volatile int aps_ready;
150
151 /* Temporary variables for init_secondary()  */
152 void *dpcpu[MAXCPU - 1];
153
154 static void
155 release_aps(void *dummy __unused)
156 {
157         int i, started;
158
159         /* Only release CPUs if they exist */
160         if (mp_ncpus == 1)
161                 return;
162
163         intr_pic_ipi_setup(IPI_AST, "ast", ipi_ast, NULL);
164         intr_pic_ipi_setup(IPI_PREEMPT, "preempt", ipi_preempt, NULL);
165         intr_pic_ipi_setup(IPI_RENDEZVOUS, "rendezvous", ipi_rendezvous, NULL);
166         intr_pic_ipi_setup(IPI_STOP, "stop", ipi_stop, NULL);
167         intr_pic_ipi_setup(IPI_STOP_HARD, "stop hard", ipi_stop, NULL);
168         intr_pic_ipi_setup(IPI_HARDCLOCK, "hardclock", ipi_hardclock, NULL);
169
170         atomic_store_rel_int(&aps_ready, 1);
171         /* Wake up the other CPUs */
172         __asm __volatile(
173             "dsb ishst  \n"
174             "sev        \n"
175             ::: "memory");
176
177         printf("Release APs...");
178
179         started = 0;
180         for (i = 0; i < 2000; i++) {
181                 if (smp_started) {
182                         printf("done\n");
183                         return;
184                 }
185                 /*
186                  * Don't time out while we are making progress. Some large
187                  * systems can take a while to start all CPUs.
188                  */
189                 if (smp_cpus > started) {
190                         i = 0;
191                         started = smp_cpus;
192                 }
193                 DELAY(1000);
194         }
195
196         printf("APs not started\n");
197 }
198 SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL);
199
200 void
201 init_secondary(uint64_t cpu)
202 {
203         struct pcpu *pcpup;
204         pmap_t pmap0;
205
206         pcpup = &__pcpu[cpu];
207         /*
208          * Set the pcpu pointer with a backup in tpidr_el1 to be
209          * loaded when entering the kernel from userland.
210          */
211         __asm __volatile(
212             "mov x18, %0 \n"
213             "msr tpidr_el1, %0" :: "r"(pcpup));
214
215         /*
216          * Identify current CPU. This is necessary to setup
217          * affinity registers and to provide support for
218          * runtime chip identification.
219          *
220          * We need this before signalling the CPU is ready to
221          * let the boot CPU use the results.
222          */
223         identify_cpu(cpu);
224
225         /* Ensure the stores in identify_cpu have completed */
226         atomic_thread_fence_acq_rel();
227
228         /* Signal the BSP and spin until it has released all APs. */
229         atomic_add_int(&aps_started, 1);
230         while (!atomic_load_int(&aps_ready))
231                 __asm __volatile("wfe");
232
233         pcpup->pc_midr = get_midr();
234
235         /* Initialize curthread */
236         KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
237         pcpup->pc_curthread = pcpup->pc_idlethread;
238
239         /* Initialize curpmap to match TTBR0's current setting. */
240         pmap0 = vmspace_pmap(&vmspace0);
241         KASSERT(pmap_to_ttbr0(pmap0) == READ_SPECIALREG(ttbr0_el1),
242             ("pmap0 doesn't match cpu %ld's ttbr0", cpu));
243         pcpup->pc_curpmap = pmap0;
244
245         install_cpu_errata();
246
247         intr_pic_init_secondary();
248
249         /* Start per-CPU event timers. */
250         cpu_initclocks_ap();
251
252 #ifdef VFP
253         vfp_init();
254 #endif
255
256         dbg_init();
257         pan_enable();
258
259         mtx_lock_spin(&ap_boot_mtx);
260         atomic_add_rel_32(&smp_cpus, 1);
261         if (smp_cpus == mp_ncpus) {
262                 /* enable IPI's, tlb shootdown, freezes etc */
263                 atomic_store_rel_int(&smp_started, 1);
264         }
265         mtx_unlock_spin(&ap_boot_mtx);
266
267         kcsan_cpu_init(cpu);
268
269         /*
270          * Assert that smp_after_idle_runnable condition is reasonable.
271          */
272         MPASS(PCPU_GET(curpcb) == NULL);
273
274         /* Enter the scheduler */
275         sched_throw(NULL);
276
277         panic("scheduler returned us to init_secondary");
278         /* NOTREACHED */
279 }
280
281 static void
282 smp_after_idle_runnable(void *arg __unused)
283 {
284         struct pcpu *pc;
285         int cpu;
286
287         for (cpu = 1; cpu < mp_ncpus; cpu++) {
288                 if (bootstacks[cpu] != NULL) {
289                         pc = pcpu_find(cpu);
290                         while (atomic_load_ptr(&pc->pc_curpcb) == NULL)
291                                 cpu_spinwait();
292                         kmem_free((vm_offset_t)bootstacks[cpu], PAGE_SIZE);
293                 }
294         }
295 }
296 SYSINIT(smp_after_idle_runnable, SI_SUB_SMP, SI_ORDER_ANY,
297     smp_after_idle_runnable, NULL);
298
299 /*
300  *  Send IPI thru interrupt controller.
301  */
302 static void
303 pic_ipi_send(void *arg, cpuset_t cpus, u_int ipi)
304 {
305
306         KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
307
308         /*
309          * Ensure that this CPU's stores will be visible to IPI
310          * recipients before starting to send the interrupts.
311          */
312         dsb(ishst);
313
314         PIC_IPI_SEND(intr_irq_root_dev, arg, cpus, ipi);
315 }
316
317 /*
318  *  Setup IPI handler on interrupt controller.
319  *
320  *  Not SMP coherent.
321  */
322 static void
323 intr_pic_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
324     void *arg)
325 {
326         struct intr_irqsrc *isrc;
327         struct intr_ipi *ii;
328         int error;
329
330         KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
331         KASSERT(hand != NULL, ("%s: ipi %u no handler", __func__, ipi));
332
333         error = PIC_IPI_SETUP(intr_irq_root_dev, ipi, &isrc);
334         if (error != 0)
335                 return;
336
337         isrc->isrc_handlers++;
338
339         ii = intr_ipi_lookup(ipi);
340         KASSERT(ii->ii_count == NULL, ("%s: ipi %u reused", __func__, ipi));
341
342         ii->ii_handler = hand;
343         ii->ii_handler_arg = arg;
344         ii->ii_send = pic_ipi_send;
345         ii->ii_send_arg = isrc;
346         strlcpy(ii->ii_name, name, INTR_IPI_NAMELEN);
347         ii->ii_count = intr_ipi_setup_counters(name);
348 }
349
350 static void
351 intr_ipi_send(cpuset_t cpus, u_int ipi)
352 {
353         struct intr_ipi *ii;
354
355         ii = intr_ipi_lookup(ipi);
356         if (ii->ii_count == NULL)
357                 panic("%s: not setup IPI %u", __func__, ipi);
358
359         ii->ii_send(ii->ii_send_arg, cpus, ipi);
360 }
361
362 static void
363 ipi_ast(void *dummy __unused)
364 {
365
366         CTR0(KTR_SMP, "IPI_AST");
367 }
368
369 static void
370 ipi_hardclock(void *dummy __unused)
371 {
372
373         CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__);
374         hardclockintr();
375 }
376
377 static void
378 ipi_preempt(void *dummy __unused)
379 {
380         CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__);
381         sched_preempt(curthread);
382 }
383
384 static void
385 ipi_rendezvous(void *dummy __unused)
386 {
387
388         CTR0(KTR_SMP, "IPI_RENDEZVOUS");
389         smp_rendezvous_action();
390 }
391
392 static void
393 ipi_stop(void *dummy __unused)
394 {
395         u_int cpu;
396
397         CTR0(KTR_SMP, "IPI_STOP");
398
399         cpu = PCPU_GET(cpuid);
400         savectx(&stoppcbs[cpu]);
401
402         /* Indicate we are stopped */
403         CPU_SET_ATOMIC(cpu, &stopped_cpus);
404
405         /* Wait for restart */
406         while (!CPU_ISSET(cpu, &started_cpus))
407                 cpu_spinwait();
408
409 #ifdef DDB
410         dbg_register_sync(NULL);
411 #endif
412
413         CPU_CLR_ATOMIC(cpu, &started_cpus);
414         CPU_CLR_ATOMIC(cpu, &stopped_cpus);
415         CTR0(KTR_SMP, "IPI_STOP (restart)");
416 }
417
418 struct cpu_group *
419 cpu_topo(void)
420 {
421
422         return (smp_topo_none());
423 }
424
425 /* Determine if we running MP machine */
426 int
427 cpu_mp_probe(void)
428 {
429
430         /* ARM64TODO: Read the u bit of mpidr_el1 to determine this */
431         return (1);
432 }
433
434 static bool
435 start_cpu(u_int id, uint64_t target_cpu)
436 {
437         struct pcpu *pcpup;
438         vm_paddr_t pa;
439         u_int cpuid;
440         int err, naps;
441
442         /* Check we are able to start this cpu */
443         if (id > mp_maxid)
444                 return (false);
445
446         KASSERT(id < MAXCPU, ("Too many CPUs"));
447
448         /* We are already running on cpu 0 */
449         if (id == cpu0)
450                 return (true);
451
452         /*
453          * Rotate the CPU IDs to put the boot CPU as CPU 0. We keep the other
454          * CPUs ordered as they are likely grouped into clusters so it can be
455          * useful to keep that property, e.g. for the GICv3 driver to send
456          * an IPI to all CPUs in the cluster.
457          */
458         cpuid = id;
459         if (cpuid < cpu0)
460                 cpuid += mp_maxid + 1;
461         cpuid -= cpu0;
462
463         pcpup = &__pcpu[cpuid];
464         pcpu_init(pcpup, cpuid, sizeof(struct pcpu));
465
466         dpcpu[cpuid - 1] = (void *)kmem_malloc(DPCPU_SIZE, M_WAITOK | M_ZERO);
467         dpcpu_init(dpcpu[cpuid - 1], cpuid);
468
469         bootstacks[cpuid] = (void *)kmem_malloc(PAGE_SIZE, M_WAITOK | M_ZERO);
470
471         naps = atomic_load_int(&aps_started);
472         bootstack = (char *)bootstacks[cpuid] + PAGE_SIZE;
473
474         printf("Starting CPU %u (%lx)\n", cpuid, target_cpu);
475         pa = pmap_extract(kernel_pmap, (vm_offset_t)mpentry);
476         err = psci_cpu_on(target_cpu, pa, cpuid);
477         if (err != PSCI_RETVAL_SUCCESS) {
478                 /*
479                  * Panic here if INVARIANTS are enabled and PSCI failed to
480                  * start the requested CPU.  psci_cpu_on() returns PSCI_MISSING
481                  * to indicate we are unable to use it to start the given CPU.
482                  */
483                 KASSERT(err == PSCI_MISSING ||
484                     (mp_quirks & MP_QUIRK_CPULIST) == MP_QUIRK_CPULIST,
485                     ("Failed to start CPU %u (%lx), error %d\n",
486                     id, target_cpu, err));
487
488                 pcpu_destroy(pcpup);
489                 kmem_free((vm_offset_t)dpcpu[cpuid - 1], DPCPU_SIZE);
490                 dpcpu[cpuid - 1] = NULL;
491                 kmem_free((vm_offset_t)bootstacks[cpuid], PAGE_SIZE);
492                 bootstacks[cpuid] = NULL;
493                 mp_ncpus--;
494
495                 /* Notify the user that the CPU failed to start */
496                 printf("Failed to start CPU %u (%lx), error %d\n",
497                     id, target_cpu, err);
498         } else {
499                 /* Wait for the AP to switch to its boot stack. */
500                 while (atomic_load_int(&aps_started) < naps + 1)
501                         cpu_spinwait();
502                 CPU_SET(cpuid, &all_cpus);
503         }
504
505         return (true);
506 }
507
508 #ifdef DEV_ACPI
509 static void
510 madt_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
511 {
512         ACPI_MADT_GENERIC_INTERRUPT *intr;
513         u_int *cpuid;
514         u_int id;
515
516         switch(entry->Type) {
517         case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
518                 intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry;
519                 cpuid = arg;
520                 id = *cpuid;
521                 start_cpu(id, intr->ArmMpidr);
522                 __pcpu[id].pc_acpi_id = intr->Uid;
523                 (*cpuid)++;
524                 break;
525         default:
526                 break;
527         }
528 }
529
530 static void
531 cpu_init_acpi(void)
532 {
533         ACPI_TABLE_MADT *madt;
534         vm_paddr_t physaddr;
535         u_int cpuid;
536
537         physaddr = acpi_find_table(ACPI_SIG_MADT);
538         if (physaddr == 0)
539                 return;
540
541         madt = acpi_map_table(physaddr, ACPI_SIG_MADT);
542         if (madt == NULL) {
543                 printf("Unable to map the MADT, not starting APs\n");
544                 return;
545         }
546
547         cpuid = 0;
548         acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
549             madt_handler, &cpuid);
550
551         acpi_unmap_table(madt);
552
553 #if MAXMEMDOM > 1
554         acpi_pxm_set_cpu_locality();
555 #endif
556 }
557 #endif
558
559 #ifdef FDT
560 static boolean_t
561 cpu_init_fdt(u_int id, phandle_t node, u_int addr_size, pcell_t *reg)
562 {
563         uint64_t target_cpu;
564         int domain;
565
566         target_cpu = reg[0];
567         if (addr_size == 2) {
568                 target_cpu <<= 32;
569                 target_cpu |= reg[1];
570         }
571
572         if (!start_cpu(id, target_cpu))
573                 return (FALSE);
574
575         /* Try to read the numa node of this cpu */
576         if (vm_ndomains == 1 ||
577             OF_getencprop(node, "numa-node-id", &domain, sizeof(domain)) <= 0)
578                 domain = 0;
579         __pcpu[id].pc_domain = domain;
580         if (domain < MAXMEMDOM)
581                 CPU_SET(id, &cpuset_domain[domain]);
582
583         return (TRUE);
584 }
585 #endif
586
587 /* Initialize and fire up non-boot processors */
588 void
589 cpu_mp_start(void)
590 {
591 #ifdef FDT
592         phandle_t node;
593         int i;
594 #endif
595
596         mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
597
598         CPU_SET(0, &all_cpus);
599
600         switch(arm64_bus_method) {
601 #ifdef DEV_ACPI
602         case ARM64_BUS_ACPI:
603                 mp_quirks = MP_QUIRK_CPULIST;
604                 KASSERT(cpu0 >= 0, ("Current CPU was not found"));
605                 cpu_init_acpi();
606                 break;
607 #endif
608 #ifdef FDT
609         case ARM64_BUS_FDT:
610                 node = OF_peer(0);
611                 for (i = 0; fdt_quirks[i].compat != NULL; i++) {
612                         if (ofw_bus_node_is_compatible(node,
613                             fdt_quirks[i].compat) != 0) {
614                                 mp_quirks = fdt_quirks[i].quirks;
615                         }
616                 }
617                 KASSERT(cpu0 >= 0, ("Current CPU was not found"));
618                 ofw_cpu_early_foreach(cpu_init_fdt, true);
619                 break;
620 #endif
621         default:
622                 break;
623         }
624 }
625
626 /* Introduce rest of cores to the world */
627 void
628 cpu_mp_announce(void)
629 {
630 }
631
632 #ifdef DEV_ACPI
633 static void
634 cpu_count_acpi_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
635 {
636         ACPI_MADT_GENERIC_INTERRUPT *intr;
637         u_int *cores = arg;
638         uint64_t mpidr_reg;
639
640         switch(entry->Type) {
641         case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
642                 intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry;
643                 if (cpu0 < 0) {
644                         mpidr_reg = READ_SPECIALREG(mpidr_el1);
645                         if ((mpidr_reg & 0xff00fffffful) == intr->ArmMpidr)
646                                 cpu0 = *cores;
647                 }
648                 (*cores)++;
649                 break;
650         default:
651                 break;
652         }
653 }
654
655 static u_int
656 cpu_count_acpi(void)
657 {
658         ACPI_TABLE_MADT *madt;
659         vm_paddr_t physaddr;
660         u_int cores;
661
662         physaddr = acpi_find_table(ACPI_SIG_MADT);
663         if (physaddr == 0)
664                 return (0);
665
666         madt = acpi_map_table(physaddr, ACPI_SIG_MADT);
667         if (madt == NULL) {
668                 printf("Unable to map the MADT, not starting APs\n");
669                 return (0);
670         }
671
672         cores = 0;
673         acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
674             cpu_count_acpi_handler, &cores);
675
676         acpi_unmap_table(madt);
677
678         return (cores);
679 }
680 #endif
681
682 #ifdef FDT
683 static boolean_t
684 cpu_find_cpu0_fdt(u_int id, phandle_t node, u_int addr_size, pcell_t *reg)
685 {
686         uint64_t mpidr_fdt, mpidr_reg;
687
688         if (cpu0 < 0) {
689                 mpidr_fdt = reg[0];
690                 if (addr_size == 2) {
691                         mpidr_fdt <<= 32;
692                         mpidr_fdt |= reg[1];
693                 }
694
695                 mpidr_reg = READ_SPECIALREG(mpidr_el1);
696
697                 if ((mpidr_reg & 0xff00fffffful) == mpidr_fdt)
698                         cpu0 = id;
699         }
700
701         return (TRUE);
702 }
703 #endif
704
705 void
706 cpu_mp_setmaxid(void)
707 {
708         int cores;
709
710         mp_ncpus = 1;
711         mp_maxid = 0;
712
713         switch(arm64_bus_method) {
714 #ifdef DEV_ACPI
715         case ARM64_BUS_ACPI:
716                 cores = cpu_count_acpi();
717                 if (cores > 0) {
718                         cores = MIN(cores, MAXCPU);
719                         if (bootverbose)
720                                 printf("Found %d CPUs in the ACPI tables\n",
721                                     cores);
722                         mp_ncpus = cores;
723                         mp_maxid = cores - 1;
724                 }
725                 break;
726 #endif
727 #ifdef FDT
728         case ARM64_BUS_FDT:
729                 cores = ofw_cpu_early_foreach(cpu_find_cpu0_fdt, false);
730                 if (cores > 0) {
731                         cores = MIN(cores, MAXCPU);
732                         if (bootverbose)
733                                 printf("Found %d CPUs in the device tree\n",
734                                     cores);
735                         mp_ncpus = cores;
736                         mp_maxid = cores - 1;
737                 }
738                 break;
739 #endif
740         default:
741                 if (bootverbose)
742                         printf("No CPU data, limiting to 1 core\n");
743                 break;
744         }
745
746         if (TUNABLE_INT_FETCH("hw.ncpu", &cores)) {
747                 if (cores > 0 && cores < mp_ncpus) {
748                         mp_ncpus = cores;
749                         mp_maxid = cores - 1;
750                 }
751         }
752 }
753
754 /*
755  *  Lookup IPI source.
756  */
757 static struct intr_ipi *
758 intr_ipi_lookup(u_int ipi)
759 {
760
761         if (ipi >= INTR_IPI_COUNT)
762                 panic("%s: no such IPI %u", __func__, ipi);
763
764         return (&ipi_sources[ipi]);
765 }
766
767 /*
768  *  interrupt controller dispatch function for IPIs. It should
769  *  be called straight from the interrupt controller, when associated
770  *  interrupt source is learned. Or from anybody who has an interrupt
771  *  source mapped.
772  */
773 void
774 intr_ipi_dispatch(u_int ipi, struct trapframe *tf)
775 {
776         void *arg;
777         struct intr_ipi *ii;
778
779         ii = intr_ipi_lookup(ipi);
780         if (ii->ii_count == NULL)
781                 panic("%s: not setup IPI %u", __func__, ipi);
782
783         intr_ipi_increment_count(ii->ii_count, PCPU_GET(cpuid));
784
785         /*
786          * Supply ipi filter with trapframe argument
787          * if none is registered.
788          */
789         arg = ii->ii_handler_arg != NULL ? ii->ii_handler_arg : tf;
790         ii->ii_handler(arg);
791 }
792
793 #ifdef notyet
794 /*
795  *  Map IPI into interrupt controller.
796  *
797  *  Not SMP coherent.
798  */
799 static int
800 ipi_map(struct intr_irqsrc *isrc, u_int ipi)
801 {
802         boolean_t is_percpu;
803         int error;
804
805         if (ipi >= INTR_IPI_COUNT)
806                 panic("%s: no such IPI %u", __func__, ipi);
807
808         KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
809
810         isrc->isrc_type = INTR_ISRCT_NAMESPACE;
811         isrc->isrc_nspc_type = INTR_IRQ_NSPC_IPI;
812         isrc->isrc_nspc_num = ipi_next_num;
813
814         error = PIC_REGISTER(intr_irq_root_dev, isrc, &is_percpu);
815         if (error == 0) {
816                 isrc->isrc_dev = intr_irq_root_dev;
817                 ipi_next_num++;
818         }
819         return (error);
820 }
821
822 /*
823  *  Setup IPI handler to interrupt source.
824  *
825  *  Note that there could be more ways how to send and receive IPIs
826  *  on a platform like fast interrupts for example. In that case,
827  *  one can call this function with ASIF_NOALLOC flag set and then
828  *  call intr_ipi_dispatch() when appropriate.
829  *
830  *  Not SMP coherent.
831  */
832 int
833 intr_ipi_set_handler(u_int ipi, const char *name, intr_ipi_filter_t *filter,
834     void *arg, u_int flags)
835 {
836         struct intr_irqsrc *isrc;
837         int error;
838
839         if (filter == NULL)
840                 return(EINVAL);
841
842         isrc = intr_ipi_lookup(ipi);
843         if (isrc->isrc_ipifilter != NULL)
844                 return (EEXIST);
845
846         if ((flags & AISHF_NOALLOC) == 0) {
847                 error = ipi_map(isrc, ipi);
848                 if (error != 0)
849                         return (error);
850         }
851
852         isrc->isrc_ipifilter = filter;
853         isrc->isrc_arg = arg;
854         isrc->isrc_handlers = 1;
855         isrc->isrc_count = intr_ipi_setup_counters(name);
856         isrc->isrc_index = 0; /* it should not be used in IPI case */
857
858         if (isrc->isrc_dev != NULL) {
859                 PIC_ENABLE_INTR(isrc->isrc_dev, isrc);
860                 PIC_ENABLE_SOURCE(isrc->isrc_dev, isrc);
861         }
862         return (0);
863 }
864 #endif
865
866 /* Sending IPI */
867 void
868 ipi_all_but_self(u_int ipi)
869 {
870         cpuset_t cpus;
871
872         cpus = all_cpus;
873         CPU_CLR(PCPU_GET(cpuid), &cpus);
874         CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
875         intr_ipi_send(cpus, ipi);
876 }
877
878 void
879 ipi_cpu(int cpu, u_int ipi)
880 {
881         cpuset_t cpus;
882
883         CPU_ZERO(&cpus);
884         CPU_SET(cpu, &cpus);
885
886         CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x", __func__, cpu, ipi);
887         intr_ipi_send(cpus, ipi);
888 }
889
890 void
891 ipi_selected(cpuset_t cpus, u_int ipi)
892 {
893
894         CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
895         intr_ipi_send(cpus, ipi);
896 }