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