2 * Copyright (c) 2012-2014 Jakub Wojciech Klama <jceel@FreeBSD.org>.
3 * Copyright (c) 2015 Svatopluk Kraus
4 * Copyright (c) 2015 Michal Meloun
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
35 * New-style Interrupt Framework
37 * TODO: - to support IPI (PPI) enabling on other CPUs if already started
38 * - to complete things for removable PICs
42 #include "opt_platform.h"
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/syslog.h>
48 #include <sys/malloc.h>
50 #include <sys/queue.h>
52 #include <sys/interrupt.h>
54 #include <sys/cpuset.h>
55 #include <sys/sched.h>
57 #include <machine/atomic.h>
58 #include <machine/intr.h>
59 #include <machine/cpu.h>
60 #include <machine/smp.h>
61 #include <machine/stdarg.h>
63 #include <dev/ofw/openfirm.h>
64 #include <dev/ofw/ofw_bus.h>
65 #include <dev/ofw/ofw_bus_subr.h>
67 #include <dev/fdt/fdt_common.h>
75 #define INTRNAME_LEN (2*MAXCOMLEN + 1)
78 #define debugf(fmt, args...) do { printf("%s(): ", __func__); \
79 printf(fmt,##args); } while (0)
81 #define debugf(fmt, args...)
84 MALLOC_DECLARE(M_INTRNG);
85 MALLOC_DEFINE(M_INTRNG, "intr", "intr interrupt handling");
87 /* Main interrupt handler called from assembler -> 'hidden' for C code. */
88 void intr_irq_handler(struct trapframe *tf);
90 /* Root interrupt controller stuff. */
91 static struct intr_irqsrc *irq_root_isrc;
92 static device_t irq_root_dev;
93 static intr_irq_filter_t *irq_root_filter;
94 static void *irq_root_arg;
95 static u_int irq_root_ipicount;
97 /* Interrupt controller definition. */
99 SLIST_ENTRY(intr_pic) pic_next;
100 intptr_t pic_xref; /* hardware identification */
104 static struct mtx pic_list_lock;
105 static SLIST_HEAD(, intr_pic) pic_list;
107 static struct intr_pic *pic_lookup(device_t dev, intptr_t xref);
109 /* Interrupt source definition. */
110 static struct mtx isrc_table_lock;
111 static struct intr_irqsrc *irq_sources[NIRQ];
114 #define IRQ_INVALID nitems(irq_sources)
117 static boolean_t irq_assign_cpu = FALSE;
119 static struct intr_irqsrc ipi_sources[INTR_IPI_COUNT];
120 static u_int ipi_next_num;
124 * - 2 counters for each I/O interrupt.
125 * - MAXCPU counters for each IPI counters for SMP.
128 #define INTRCNT_COUNT (NIRQ * 2 + INTR_IPI_COUNT * MAXCPU)
130 #define INTRCNT_COUNT (NIRQ * 2)
133 /* Data for MI statistics reporting. */
134 u_long intrcnt[INTRCNT_COUNT];
135 char intrnames[INTRCNT_COUNT * INTRNAME_LEN];
136 size_t sintrcnt = sizeof(intrcnt);
137 size_t sintrnames = sizeof(intrnames);
138 static u_int intrcnt_index;
141 * Interrupt framework initialization routine.
144 intr_irq_init(void *dummy __unused)
147 SLIST_INIT(&pic_list);
148 mtx_init(&pic_list_lock, "intr pic list", NULL, MTX_DEF);
149 mtx_init(&isrc_table_lock, "intr isrc table", NULL, MTX_DEF);
151 SYSINIT(intr_irq_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_irq_init, NULL);
154 intrcnt_setname(const char *name, int index)
157 snprintf(intrnames + INTRNAME_LEN * index, INTRNAME_LEN, "%-*s",
158 INTRNAME_LEN - 1, name);
162 * Update name for interrupt source with interrupt event.
165 intrcnt_updatename(struct intr_irqsrc *isrc)
168 /* QQQ: What about stray counter name? */
169 mtx_assert(&isrc_table_lock, MA_OWNED);
170 intrcnt_setname(isrc->isrc_event->ie_fullname, isrc->isrc_index);
174 * Virtualization for interrupt source interrupt counter increment.
177 isrc_increment_count(struct intr_irqsrc *isrc)
181 * XXX - It should be atomic for PPI interrupts. It was proven that
182 * the lost is measurable easily for timer PPI interrupts.
184 isrc->isrc_count[0]++;
185 /*atomic_add_long(&isrc->isrc_count[0], 1);*/
189 * Virtualization for interrupt source interrupt stray counter increment.
192 isrc_increment_straycount(struct intr_irqsrc *isrc)
195 isrc->isrc_count[1]++;
199 * Virtualization for interrupt source interrupt name update.
202 isrc_update_name(struct intr_irqsrc *isrc, const char *name)
204 char str[INTRNAME_LEN];
206 mtx_assert(&isrc_table_lock, MA_OWNED);
209 snprintf(str, INTRNAME_LEN, "%s: %s", isrc->isrc_name, name);
210 intrcnt_setname(str, isrc->isrc_index);
211 snprintf(str, INTRNAME_LEN, "stray %s: %s", isrc->isrc_name,
213 intrcnt_setname(str, isrc->isrc_index + 1);
215 snprintf(str, INTRNAME_LEN, "%s:", isrc->isrc_name);
216 intrcnt_setname(str, isrc->isrc_index);
217 snprintf(str, INTRNAME_LEN, "stray %s:", isrc->isrc_name);
218 intrcnt_setname(str, isrc->isrc_index + 1);
223 * Virtualization for interrupt source interrupt counters setup.
226 isrc_setup_counters(struct intr_irqsrc *isrc)
231 * XXX - it does not work well with removable controllers and
232 * interrupt sources !!!
234 index = atomic_fetchadd_int(&intrcnt_index, 2);
235 isrc->isrc_index = index;
236 isrc->isrc_count = &intrcnt[index];
237 isrc_update_name(isrc, NULL);
242 * Virtualization for interrupt source IPI counter increment.
245 isrc_increment_ipi_count(struct intr_irqsrc *isrc, u_int cpu)
248 isrc->isrc_count[cpu]++;
252 * Virtualization for interrupt source IPI counters setup.
255 isrc_setup_ipi_counters(struct intr_irqsrc *isrc, const char *name)
258 char str[INTRNAME_LEN];
260 index = atomic_fetchadd_int(&intrcnt_index, MAXCPU);
261 isrc->isrc_index = index;
262 isrc->isrc_count = &intrcnt[index];
264 for (i = 0; i < MAXCPU; i++) {
266 * We do not expect any race in IPI case here,
267 * so locking is not needed.
269 snprintf(str, INTRNAME_LEN, "cpu%d:%s", i, name);
270 intrcnt_setname(str, index + i);
276 * Main interrupt dispatch handler. It's called straight
277 * from the assembler, where CPU interrupt is served.
280 intr_irq_handler(struct trapframe *tf)
282 struct trapframe * oldframe;
285 KASSERT(irq_root_filter != NULL, ("%s: no filter", __func__));
287 PCPU_INC(cnt.v_intr);
290 oldframe = td->td_intr_frame;
291 td->td_intr_frame = tf;
292 irq_root_filter(irq_root_arg);
293 td->td_intr_frame = oldframe;
298 * interrupt controller dispatch function for interrupts. It should
299 * be called straight from the interrupt controller, when associated interrupt
303 intr_irq_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf)
306 KASSERT(isrc != NULL, ("%s: no source", __func__));
308 isrc_increment_count(isrc);
311 if (isrc->isrc_filter != NULL) {
313 error = isrc->isrc_filter(isrc->isrc_arg, tf);
314 PIC_POST_FILTER(isrc->isrc_dev, isrc);
315 if (error == FILTER_HANDLED)
319 if (isrc->isrc_event != NULL) {
320 if (intr_event_handle(isrc->isrc_event, tf) == 0)
324 isrc_increment_straycount(isrc);
325 PIC_DISABLE_SOURCE(isrc->isrc_dev, isrc);
327 device_printf(isrc->isrc_dev, "stray irq <%s> disabled",
332 * Allocate interrupt source.
334 static struct intr_irqsrc *
335 isrc_alloc(u_int type, u_int extsize)
337 struct intr_irqsrc *isrc;
339 isrc = malloc(sizeof(*isrc) + extsize, M_INTRNG, M_WAITOK | M_ZERO);
340 isrc->isrc_irq = IRQ_INVALID; /* just to be safe */
341 isrc->isrc_type = type;
342 isrc->isrc_nspc_type = INTR_IRQ_NSPC_NONE;
343 isrc->isrc_trig = INTR_TRIGGER_CONFORM;
344 isrc->isrc_pol = INTR_POLARITY_CONFORM;
345 CPU_ZERO(&isrc->isrc_cpu);
350 * Free interrupt source.
353 isrc_free(struct intr_irqsrc *isrc)
356 free(isrc, M_INTRNG);
360 intr_irq_set_name(struct intr_irqsrc *isrc, const char *fmt, ...)
365 vsnprintf(isrc->isrc_name, INTR_ISRC_NAMELEN, fmt, ap);
370 * Alloc unique interrupt number (resource handle) for interrupt source.
372 * There could be various strategies how to allocate free interrupt number
373 * (resource handle) for new interrupt source.
375 * 1. Handles are always allocated forward, so handles are not recycled
376 * immediately. However, if only one free handle left which is reused
380 isrc_alloc_irq_locked(struct intr_irqsrc *isrc)
384 mtx_assert(&isrc_table_lock, MA_OWNED);
386 maxirqs = nitems(irq_sources);
387 if (irq_next_free >= maxirqs)
390 for (irq = irq_next_free; irq < maxirqs; irq++) {
391 if (irq_sources[irq] == NULL)
394 for (irq = 0; irq < irq_next_free; irq++) {
395 if (irq_sources[irq] == NULL)
399 irq_next_free = maxirqs;
403 isrc->isrc_irq = irq;
404 irq_sources[irq] = isrc;
406 intr_irq_set_name(isrc, "irq%u", irq);
407 isrc_setup_counters(isrc);
409 irq_next_free = irq + 1;
410 if (irq_next_free >= maxirqs)
416 * Free unique interrupt number (resource handle) from interrupt source.
419 isrc_free_irq(struct intr_irqsrc *isrc)
423 mtx_assert(&isrc_table_lock, MA_NOTOWNED);
425 maxirqs = nitems(irq_sources);
426 if (isrc->isrc_irq >= maxirqs)
429 mtx_lock(&isrc_table_lock);
430 if (irq_sources[isrc->isrc_irq] != isrc) {
431 mtx_unlock(&isrc_table_lock);
435 irq_sources[isrc->isrc_irq] = NULL;
436 isrc->isrc_irq = IRQ_INVALID; /* just to be safe */
437 mtx_unlock(&isrc_table_lock);
443 * Lookup interrupt source by interrupt number (resource handle).
445 static struct intr_irqsrc *
446 isrc_lookup(u_int irq)
449 if (irq < nitems(irq_sources))
450 return (irq_sources[irq]);
455 * Lookup interrupt source by namespace description.
457 static struct intr_irqsrc *
458 isrc_namespace_lookup(device_t dev, uint16_t type, uint16_t num)
461 struct intr_irqsrc *isrc;
463 mtx_assert(&isrc_table_lock, MA_OWNED);
465 for (irq = 0; irq < nitems(irq_sources); irq++) {
466 isrc = irq_sources[irq];
467 if (isrc != NULL && isrc->isrc_dev == dev &&
468 isrc->isrc_nspc_type == type && isrc->isrc_nspc_num == num)
475 * Map interrupt source according to namespace into framework. If such mapping
476 * does not exist, create it. Return unique interrupt number (resource handle)
477 * associated with mapped interrupt source.
480 intr_namespace_map_irq(device_t dev, uint16_t type, uint16_t num)
482 struct intr_irqsrc *isrc, *new_isrc;
485 new_isrc = isrc_alloc(INTR_ISRCT_NAMESPACE, 0);
487 mtx_lock(&isrc_table_lock);
488 isrc = isrc_namespace_lookup(dev, type, num);
490 mtx_unlock(&isrc_table_lock);
492 return (isrc->isrc_irq); /* already mapped */
495 error = isrc_alloc_irq_locked(new_isrc);
497 mtx_unlock(&isrc_table_lock);
499 return (IRQ_INVALID); /* no space left */
502 new_isrc->isrc_dev = dev;
503 new_isrc->isrc_nspc_type = type;
504 new_isrc->isrc_nspc_num = num;
505 mtx_unlock(&isrc_table_lock);
507 return (new_isrc->isrc_irq);
512 * Lookup interrupt source by FDT description.
514 static struct intr_irqsrc *
515 isrc_fdt_lookup(intptr_t xref, pcell_t *cells, u_int ncells)
518 struct intr_irqsrc *isrc;
520 mtx_assert(&isrc_table_lock, MA_OWNED);
522 cellsize = ncells * sizeof(*cells);
523 for (irq = 0; irq < nitems(irq_sources); irq++) {
524 isrc = irq_sources[irq];
525 if (isrc != NULL && isrc->isrc_type == INTR_ISRCT_FDT &&
526 isrc->isrc_xref == xref && isrc->isrc_ncells == ncells &&
527 memcmp(isrc->isrc_cells, cells, cellsize) == 0)
534 * Map interrupt source according to FDT data into framework. If such mapping
535 * does not exist, create it. Return unique interrupt number (resource handle)
536 * associated with mapped interrupt source.
539 intr_fdt_map_irq(phandle_t node, pcell_t *cells, u_int ncells)
541 struct intr_irqsrc *isrc, *new_isrc;
546 xref = (intptr_t)node; /* It's so simple for now. */
548 cellsize = ncells * sizeof(*cells);
549 new_isrc = isrc_alloc(INTR_ISRCT_FDT, cellsize);
551 mtx_lock(&isrc_table_lock);
552 isrc = isrc_fdt_lookup(xref, cells, ncells);
554 mtx_unlock(&isrc_table_lock);
556 return (isrc->isrc_irq); /* already mapped */
559 error = isrc_alloc_irq_locked(new_isrc);
561 mtx_unlock(&isrc_table_lock);
563 return (IRQ_INVALID); /* no space left */
566 new_isrc->isrc_xref = xref;
567 new_isrc->isrc_ncells = ncells;
568 memcpy(new_isrc->isrc_cells, cells, cellsize);
569 mtx_unlock(&isrc_table_lock);
571 return (new_isrc->isrc_irq);
576 * Register interrupt source into interrupt controller.
579 isrc_register(struct intr_irqsrc *isrc)
581 struct intr_pic *pic;
585 if (isrc->isrc_flags & INTR_ISRCF_REGISTERED)
588 if (isrc->isrc_dev == NULL) {
589 pic = pic_lookup(NULL, isrc->isrc_xref);
590 if (pic == NULL || pic->pic_dev == NULL)
592 isrc->isrc_dev = pic->pic_dev;
595 error = PIC_REGISTER(isrc->isrc_dev, isrc, &is_percpu);
599 mtx_lock(&isrc_table_lock);
600 isrc->isrc_flags |= INTR_ISRCF_REGISTERED;
602 isrc->isrc_flags |= INTR_ISRCF_PERCPU;
603 isrc_update_name(isrc, NULL);
604 mtx_unlock(&isrc_table_lock);
610 * Setup filter into interrupt source.
613 iscr_setup_filter(struct intr_irqsrc *isrc, const char *name,
614 intr_irq_filter_t *filter, void *arg, void **cookiep)
620 mtx_lock(&isrc_table_lock);
622 * Make sure that we do not mix the two ways
623 * how we handle interrupt sources.
625 if (isrc->isrc_filter != NULL || isrc->isrc_event != NULL) {
626 mtx_unlock(&isrc_table_lock);
629 isrc->isrc_filter = filter;
630 isrc->isrc_arg = arg;
631 isrc_update_name(isrc, name);
632 mtx_unlock(&isrc_table_lock);
640 * Interrupt source pre_ithread method for MI interrupt framework.
643 intr_isrc_pre_ithread(void *arg)
645 struct intr_irqsrc *isrc = arg;
647 PIC_PRE_ITHREAD(isrc->isrc_dev, isrc);
651 * Interrupt source post_ithread method for MI interrupt framework.
654 intr_isrc_post_ithread(void *arg)
656 struct intr_irqsrc *isrc = arg;
658 PIC_POST_ITHREAD(isrc->isrc_dev, isrc);
662 * Interrupt source post_filter method for MI interrupt framework.
665 intr_isrc_post_filter(void *arg)
667 struct intr_irqsrc *isrc = arg;
669 PIC_POST_FILTER(isrc->isrc_dev, isrc);
673 * Interrupt source assign_cpu method for MI interrupt framework.
676 intr_isrc_assign_cpu(void *arg, int cpu)
679 struct intr_irqsrc *isrc = arg;
682 if (isrc->isrc_dev != irq_root_dev)
685 mtx_lock(&isrc_table_lock);
687 CPU_ZERO(&isrc->isrc_cpu);
688 isrc->isrc_flags &= ~INTR_ISRCF_BOUND;
690 CPU_SETOF(cpu, &isrc->isrc_cpu);
691 isrc->isrc_flags |= INTR_ISRCF_BOUND;
695 * In NOCPU case, it's up to PIC to either leave ISRC on same CPU or
696 * re-balance it to another CPU or enable it on more CPUs. However,
697 * PIC is expected to change isrc_cpu appropriately to keep us well
698 * informed if the call is successfull.
700 if (irq_assign_cpu) {
701 error = PIC_BIND(isrc->isrc_dev, isrc);
703 CPU_ZERO(&isrc->isrc_cpu);
704 mtx_unlock(&isrc_table_lock);
708 mtx_unlock(&isrc_table_lock);
716 * Create interrupt event for interrupt source.
719 isrc_event_create(struct intr_irqsrc *isrc)
721 struct intr_event *ie;
724 error = intr_event_create(&ie, isrc, 0, isrc->isrc_irq,
725 intr_isrc_pre_ithread, intr_isrc_post_ithread, intr_isrc_post_filter,
726 intr_isrc_assign_cpu, "%s:", isrc->isrc_name);
730 mtx_lock(&isrc_table_lock);
732 * Make sure that we do not mix the two ways
733 * how we handle interrupt sources. Let contested event wins.
735 if (isrc->isrc_filter != NULL || isrc->isrc_event != NULL) {
736 mtx_unlock(&isrc_table_lock);
737 intr_event_destroy(ie);
738 return (isrc->isrc_event != NULL ? EBUSY : 0);
740 isrc->isrc_event = ie;
741 mtx_unlock(&isrc_table_lock);
747 * Destroy interrupt event for interrupt source.
750 isrc_event_destroy(struct intr_irqsrc *isrc)
752 struct intr_event *ie;
754 mtx_lock(&isrc_table_lock);
755 ie = isrc->isrc_event;
756 isrc->isrc_event = NULL;
757 mtx_unlock(&isrc_table_lock);
760 intr_event_destroy(ie);
764 * Add handler to interrupt source.
767 isrc_add_handler(struct intr_irqsrc *isrc, const char *name,
768 driver_filter_t filter, driver_intr_t handler, void *arg,
769 enum intr_type flags, void **cookiep)
773 if (isrc->isrc_event == NULL) {
774 error = isrc_event_create(isrc);
779 error = intr_event_add_handler(isrc->isrc_event, name, filter, handler,
780 arg, intr_priority(flags), flags, cookiep);
782 mtx_lock(&isrc_table_lock);
783 intrcnt_updatename(isrc);
784 mtx_unlock(&isrc_table_lock);
791 * Lookup interrupt controller locked.
793 static struct intr_pic *
794 pic_lookup_locked(device_t dev, intptr_t xref)
796 struct intr_pic *pic;
798 mtx_assert(&pic_list_lock, MA_OWNED);
800 SLIST_FOREACH(pic, &pic_list, pic_next) {
801 if (pic->pic_xref != xref)
803 if (pic->pic_xref != 0 || pic->pic_dev == dev)
810 * Lookup interrupt controller.
812 static struct intr_pic *
813 pic_lookup(device_t dev, intptr_t xref)
815 struct intr_pic *pic;
817 mtx_lock(&pic_list_lock);
818 pic = pic_lookup_locked(dev, xref);
819 mtx_unlock(&pic_list_lock);
825 * Create interrupt controller.
827 static struct intr_pic *
828 pic_create(device_t dev, intptr_t xref)
830 struct intr_pic *pic;
832 mtx_lock(&pic_list_lock);
833 pic = pic_lookup_locked(dev, xref);
835 mtx_unlock(&pic_list_lock);
838 pic = malloc(sizeof(*pic), M_INTRNG, M_NOWAIT | M_ZERO);
839 pic->pic_xref = xref;
841 SLIST_INSERT_HEAD(&pic_list, pic, pic_next);
842 mtx_unlock(&pic_list_lock);
848 * Destroy interrupt controller.
851 pic_destroy(device_t dev, intptr_t xref)
853 struct intr_pic *pic;
855 mtx_lock(&pic_list_lock);
856 pic = pic_lookup_locked(dev, xref);
858 mtx_unlock(&pic_list_lock);
861 SLIST_REMOVE(&pic_list, pic, intr_pic, pic_next);
862 mtx_unlock(&pic_list_lock);
868 * Register interrupt controller.
871 intr_pic_register(device_t dev, intptr_t xref)
873 struct intr_pic *pic;
875 pic = pic_create(dev, xref);
878 if (pic->pic_dev != dev)
879 return (EINVAL); /* XXX it could be many things. */
881 debugf("PIC %p registered for %s <xref %x>\n", pic,
882 device_get_nameunit(dev), xref);
887 * Unregister interrupt controller.
890 intr_pic_unregister(device_t dev, intptr_t xref)
893 panic("%s: not implemented", __func__);
897 * Mark interrupt controller (itself) as a root one.
899 * Note that only an interrupt controller can really know its position
900 * in interrupt controller's tree. So root PIC must claim itself as a root.
902 * In FDT case, according to ePAPR approved version 1.1 from 08 April 2011,
904 * "The root of the interrupt tree is determined when traversal
905 * of the interrupt tree reaches an interrupt controller node without
906 * an interrupts property and thus no explicit interrupt parent."
909 intr_pic_claim_root(device_t dev, intptr_t xref, intr_irq_filter_t *filter,
910 void *arg, u_int ipicount)
915 if (pic_lookup(dev, xref) == NULL) {
916 device_printf(dev, "not registered\n");
919 if (filter == NULL) {
920 device_printf(dev, "filter missing\n");
925 * Only one interrupt controllers could be on the root for now.
926 * Note that we further suppose that there is not threaded interrupt
927 * routine (handler) on the root. See intr_irq_handler().
929 if (irq_root_dev != NULL) {
930 device_printf(dev, "another root already set\n");
934 rootirq = intr_namespace_map_irq(device_get_parent(dev), 0, 0);
935 if (rootirq == IRQ_INVALID) {
936 device_printf(dev, "failed to map an irq for the root pic\n");
940 /* Create the isrc. */
941 irq_root_isrc = isrc_lookup(rootirq);
943 /* XXX "register" with the PIC. We are the "pic" here, so fake it. */
944 irq_root_isrc->isrc_flags |= INTR_ISRCF_REGISTERED;
946 error = intr_irq_add_handler(device_get_parent(dev),
947 (void*)filter, NULL, arg, rootirq, INTR_TYPE_CLK, NULL);
949 device_printf(dev, "failed to install root pic handler\n");
953 irq_root_filter = filter;
955 irq_root_ipicount = ipicount;
957 debugf("irq root set to %s\n", device_get_nameunit(dev));
962 intr_irq_add_handler(device_t dev, driver_filter_t filt, driver_intr_t hand,
963 void *arg, u_int irq, int flags, void **cookiep)
966 struct intr_irqsrc *isrc;
969 name = device_get_nameunit(dev);
973 * Standard handling is done thru MI interrupt framework. However,
974 * some interrupts could request solely own special handling. This
975 * non standard handling can be used for interrupt controllers without
976 * handler (filter only), so in case that interrupt controllers are
977 * chained, MI interrupt framework is called only in leaf controller.
979 * Note that root interrupt controller routine is served as well,
980 * however in intr_irq_handler(), i.e. main system dispatch routine.
982 if (flags & INTR_SOLO && hand != NULL) {
983 debugf("irq %u cannot solo on %s\n", irq, name);
988 isrc = isrc_lookup(irq);
990 debugf("irq %u without source on %s\n", irq, name);
994 error = isrc_register(isrc);
996 debugf("irq %u map error %d on %s\n", irq, error, name);
1001 if (flags & INTR_SOLO) {
1002 error = iscr_setup_filter(isrc, name, (intr_irq_filter_t *)filt,
1004 debugf("irq %u setup filter error %d on %s\n", irq, error,
1009 error = isrc_add_handler(isrc, name, filt, hand, arg, flags,
1011 debugf("irq %u add handler error %d on %s\n", irq, error, name);
1016 mtx_lock(&isrc_table_lock);
1017 isrc->isrc_handlers++;
1018 if (isrc->isrc_handlers == 1) {
1019 PIC_ENABLE_INTR(isrc->isrc_dev, isrc);
1020 PIC_ENABLE_SOURCE(isrc->isrc_dev, isrc);
1022 mtx_unlock(&isrc_table_lock);
1027 intr_irq_remove_handler(device_t dev, u_int irq, void *cookie)
1029 struct intr_irqsrc *isrc;
1032 isrc = isrc_lookup(irq);
1033 if (isrc == NULL || isrc->isrc_handlers == 0)
1036 if (isrc->isrc_filter != NULL) {
1040 mtx_lock(&isrc_table_lock);
1041 isrc->isrc_filter = NULL;
1042 isrc->isrc_arg = NULL;
1043 isrc->isrc_handlers = 0;
1044 PIC_DISABLE_SOURCE(isrc->isrc_dev, isrc);
1045 PIC_DISABLE_INTR(isrc->isrc_dev, isrc);
1046 isrc_update_name(isrc, NULL);
1047 mtx_unlock(&isrc_table_lock);
1051 if (isrc != intr_handler_source(cookie))
1054 error = intr_event_remove_handler(cookie);
1056 mtx_lock(&isrc_table_lock);
1057 isrc->isrc_handlers--;
1058 if (isrc->isrc_handlers == 0) {
1059 PIC_DISABLE_SOURCE(isrc->isrc_dev, isrc);
1060 PIC_DISABLE_INTR(isrc->isrc_dev, isrc);
1062 intrcnt_updatename(isrc);
1063 mtx_unlock(&isrc_table_lock);
1069 intr_irq_config(u_int irq, enum intr_trigger trig, enum intr_polarity pol)
1071 struct intr_irqsrc *isrc;
1073 isrc = isrc_lookup(irq);
1077 if (isrc->isrc_handlers != 0)
1078 return (EBUSY); /* interrrupt is enabled (active) */
1081 * Once an interrupt is enabled, we do not change its configuration.
1082 * A controller PIC_ENABLE_INTR() method is called when an interrupt
1083 * is going to be enabled. In this method, a controller should setup
1084 * the interrupt according to saved configuration parameters.
1086 isrc->isrc_trig = trig;
1087 isrc->isrc_pol = pol;
1093 intr_irq_describe(u_int irq, void *cookie, const char *descr)
1095 struct intr_irqsrc *isrc;
1098 isrc = isrc_lookup(irq);
1099 if (isrc == NULL || isrc->isrc_handlers == 0)
1102 if (isrc->isrc_filter != NULL) {
1106 mtx_lock(&isrc_table_lock);
1107 isrc_update_name(isrc, descr);
1108 mtx_unlock(&isrc_table_lock);
1112 error = intr_event_describe_handler(isrc->isrc_event, cookie, descr);
1114 mtx_lock(&isrc_table_lock);
1115 intrcnt_updatename(isrc);
1116 mtx_unlock(&isrc_table_lock);
1123 intr_irq_bind(u_int irq, int cpu)
1125 struct intr_irqsrc *isrc;
1127 isrc = isrc_lookup(irq);
1128 if (isrc == NULL || isrc->isrc_handlers == 0)
1131 if (isrc->isrc_filter != NULL)
1132 return (intr_isrc_assign_cpu(isrc, cpu));
1134 return (intr_event_bind(isrc->isrc_event, cpu));
1138 * Return the CPU that the next interrupt source should use.
1139 * For now just returns the next CPU according to round-robin.
1142 intr_irq_next_cpu(u_int last_cpu, cpuset_t *cpumask)
1145 if (!irq_assign_cpu || mp_ncpus == 1)
1146 return (PCPU_GET(cpuid));
1150 if (last_cpu > mp_maxid)
1152 } while (!CPU_ISSET(last_cpu, cpumask));
1157 * Distribute all the interrupt sources among the available
1158 * CPUs once the AP's have been launched.
1161 intr_irq_shuffle(void *arg __unused)
1163 struct intr_irqsrc *isrc;
1169 mtx_lock(&isrc_table_lock);
1170 irq_assign_cpu = TRUE;
1171 for (i = 0; i < NIRQ; i++) {
1172 isrc = irq_sources[i];
1173 if (isrc == NULL || isrc->isrc_handlers == 0 ||
1174 isrc->isrc_flags & INTR_ISRCF_PERCPU)
1177 if (isrc->isrc_event != NULL &&
1178 isrc->isrc_flags & INTR_ISRCF_BOUND &&
1179 isrc->isrc_event->ie_cpu != CPU_FFS(&isrc->isrc_cpu) - 1)
1180 panic("%s: CPU inconsistency", __func__);
1182 if ((isrc->isrc_flags & INTR_ISRCF_BOUND) == 0)
1183 CPU_ZERO(&isrc->isrc_cpu); /* start again */
1186 * We are in wicked position here if the following call fails
1187 * for bound ISRC. The best thing we can do is to clear
1188 * isrc_cpu so inconsistency with ie_cpu will be detectable.
1190 if (PIC_BIND(isrc->isrc_dev, isrc) != 0)
1191 CPU_ZERO(&isrc->isrc_cpu);
1193 mtx_unlock(&isrc_table_lock);
1195 SYSINIT(intr_irq_shuffle, SI_SUB_SMP, SI_ORDER_SECOND, intr_irq_shuffle, NULL);
1199 intr_irq_next_cpu(u_int current_cpu, cpuset_t *cpumask)
1202 return (PCPU_GET(cpuid));
1206 void dosoftints(void);
1214 * Lookup IPI source.
1216 static struct intr_irqsrc *
1217 intr_ipi_lookup(u_int ipi)
1220 if (ipi >= INTR_IPI_COUNT)
1221 panic("%s: no such IPI %u", __func__, ipi);
1223 return (&ipi_sources[ipi]);
1227 * interrupt controller dispatch function for IPIs. It should
1228 * be called straight from the interrupt controller, when associated
1229 * interrupt source is learned. Or from anybody who has an interrupt
1233 intr_ipi_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf)
1237 KASSERT(isrc != NULL, ("%s: no source", __func__));
1239 isrc_increment_ipi_count(isrc, PCPU_GET(cpuid));
1242 * Supply ipi filter with trapframe argument
1243 * if none is registered.
1245 arg = isrc->isrc_arg != NULL ? isrc->isrc_arg : tf;
1246 isrc->isrc_ipifilter(arg);
1250 * Map IPI into interrupt controller.
1255 ipi_map(struct intr_irqsrc *isrc, u_int ipi)
1257 boolean_t is_percpu;
1260 if (ipi >= INTR_IPI_COUNT)
1261 panic("%s: no such IPI %u", __func__, ipi);
1263 KASSERT(irq_root_dev != NULL, ("%s: no root attached", __func__));
1265 isrc->isrc_type = INTR_ISRCT_NAMESPACE;
1266 isrc->isrc_nspc_type = INTR_IRQ_NSPC_IPI;
1267 isrc->isrc_nspc_num = ipi_next_num;
1269 error = PIC_REGISTER(irq_root_dev, isrc, &is_percpu);
1271 debugf("ipi %u mapped to %u on %s - error %d\n", ipi, ipi_next_num,
1272 device_get_nameunit(irq_root_dev), error);
1275 isrc->isrc_dev = irq_root_dev;
1282 * Setup IPI handler to interrupt source.
1284 * Note that there could be more ways how to send and receive IPIs
1285 * on a platform like fast interrupts for example. In that case,
1286 * one can call this function with ASIF_NOALLOC flag set and then
1287 * call intr_ipi_dispatch() when appropriate.
1292 intr_ipi_set_handler(u_int ipi, const char *name, intr_ipi_filter_t *filter,
1293 void *arg, u_int flags)
1295 struct intr_irqsrc *isrc;
1301 isrc = intr_ipi_lookup(ipi);
1302 if (isrc->isrc_ipifilter != NULL)
1305 if ((flags & AISHF_NOALLOC) == 0) {
1306 error = ipi_map(isrc, ipi);
1311 isrc->isrc_ipifilter = filter;
1312 isrc->isrc_arg = arg;
1313 isrc->isrc_handlers = 1;
1314 isrc_setup_ipi_counters(isrc, name);
1316 if (isrc->isrc_dev != NULL) {
1317 mtx_lock(&isrc_table_lock);
1318 PIC_ENABLE_INTR(isrc->isrc_dev, isrc);
1319 PIC_ENABLE_SOURCE(isrc->isrc_dev, isrc);
1320 mtx_unlock(&isrc_table_lock);
1326 * Send IPI thru interrupt controller.
1329 pic_ipi_send(cpuset_t cpus, u_int ipi)
1331 struct intr_irqsrc *isrc;
1333 isrc = intr_ipi_lookup(ipi);
1335 KASSERT(irq_root_dev != NULL, ("%s: no root attached", __func__));
1336 PIC_IPI_SEND(irq_root_dev, isrc, cpus);
1340 * Init interrupt controller on another CPU.
1343 intr_pic_init_secondary(void)
1347 * QQQ: Only root PIC is aware of other CPUs ???
1349 KASSERT(irq_root_dev != NULL, ("%s: no root attached", __func__));
1351 //mtx_lock(&isrc_table_lock);
1352 PIC_INIT_SECONDARY(irq_root_dev);
1353 //mtx_unlock(&isrc_table_lock);
1358 DB_SHOW_COMMAND(irqs, db_show_irqs)
1361 struct intr_irqsrc *isrc;
1364 for (i = 0; i <= mp_maxid; i++) {
1370 for (ipisum = 0, ipi = 0; ipi < INTR_IPI_COUNT; ipi++) {
1371 isrc = intr_ipi_lookup(ipi);
1372 if (isrc->isrc_count != NULL)
1373 ipisum += isrc->isrc_count[i];
1375 printf ("cpu%u: total %u ipis %u\n", i,
1376 pc->pc_cnt.v_intr, ipisum);
1382 for (irqsum = 0, i = 0; i < NIRQ; i++) {
1383 isrc = irq_sources[i];
1387 db_printf("irq%-3u <%s>: cpu %02lx%s cnt %lu\n", i,
1388 isrc->isrc_name, isrc->isrc_cpu.__bits[0],
1389 isrc->isrc_flags & INTR_ISRCF_BOUND ? " (bound)" : "",
1390 isrc->isrc_count[0]);
1391 irqsum += isrc->isrc_count[0];
1393 db_printf("irq total %u\n", irqsum);