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