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