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