diff --git a/sys/arm/allwinner/a10/a10_intc.c b/sys/arm/allwinner/a10/a10_intc.c --- a/sys/arm/allwinner/a10/a10_intc.c +++ b/sys/arm/allwinner/a10/a10_intc.c @@ -180,11 +180,13 @@ } static int -a10_intr(void *arg) +a10_intr(void *arg, uint32_t type __diagused) { struct a10_aintc_softc *sc = arg; u_int irq; + MPASS(type == INTR_TYPE_IRQ); + irq = a10_pending_irq(sc); if (irq == -1 || irq > A10_INTR_MAX_NIRQS) { device_printf(sc->sc_dev, "Spurious interrupt %d\n", irq); diff --git a/sys/arm/arm/gic.h b/sys/arm/arm/gic.h --- a/sys/arm/arm/gic.h +++ b/sys/arm/arm/gic.h @@ -78,6 +78,7 @@ int arm_gic_attach(device_t); int arm_gic_detach(device_t); int arm_gicv2m_attach(device_t); -int arm_gic_intr(void *); +int arm_gic_intr_handler(void *); +int arm_gic_intr(void *, uint32_t type); #endif /* _ARM_GIC_H_ */ diff --git a/sys/arm/arm/gic.c b/sys/arm/arm/gic.c --- a/sys/arm/arm/gic.c +++ b/sys/arm/arm/gic.c @@ -532,7 +532,15 @@ } int -arm_gic_intr(void *arg) +arm_gic_intr(void *arg, uint32_t type __diagused) +{ + MPASS(type == INTR_TYPE_IRQ); + + return (arm_gic_intr_handler(arg)); +} + +int +arm_gic_intr_handler(void *arg) { struct arm_gic_softc *sc = arg; struct gic_irqsrc *gi; diff --git a/sys/arm/arm/gic_fdt.c b/sys/arm/arm/gic_fdt.c --- a/sys/arm/arm/gic_fdt.c +++ b/sys/arm/arm/gic_fdt.c @@ -168,7 +168,7 @@ goto cleanup; } if (bus_setup_intr(dev, sc->base.gic_res[2], INTR_TYPE_CLK, - arm_gic_intr, NULL, sc, &sc->base.gic_intrhand)) { + arm_gic_intr_handler, NULL, sc, &sc->base.gic_intrhand)) { device_printf(dev, "could not setup irq handler\n"); intr_pic_deregister(dev, xref); goto cleanup; diff --git a/sys/arm/broadcom/bcm2835/bcm2835_intr.c b/sys/arm/broadcom/bcm2835/bcm2835_intr.c --- a/sys/arm/broadcom/bcm2835/bcm2835_intr.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_intr.c @@ -210,7 +210,7 @@ } static int -bcm2835_intc_intr(void *arg) +bcm2835_intc_intr_handler(void *arg) { int irq, num; struct bcm_intc_softc *sc = arg; @@ -233,6 +233,14 @@ return (FILTER_HANDLED); } +static int +bcm2835_intc_intr(void *arg, uint32_t type __diagused) +{ + MPASS(type == INTR_TYPE_IRQ); + + return (bcm2835_intc_intr_handler(arg)); +} + static void bcm_intc_enable_intr(device_t dev, struct intr_irqsrc *isrc) { @@ -412,7 +420,7 @@ } } else { if (bus_setup_intr(dev, sc->intc_irq_res, INTR_TYPE_CLK, - bcm2835_intc_intr, NULL, sc, &sc->intc_irq_hdl)) { + bcm2835_intc_intr_handler, NULL, sc, &sc->intc_irq_hdl)) { /* XXX clean up */ device_printf(dev, "could not setup irq handler\n"); return (ENXIO); diff --git a/sys/arm/broadcom/bcm2835/bcm2836.c b/sys/arm/broadcom/bcm2835/bcm2836.c --- a/sys/arm/broadcom/bcm2835/bcm2836.c +++ b/sys/arm/broadcom/bcm2835/bcm2836.c @@ -384,13 +384,15 @@ } static int -bcm_lintc_intr(void *arg) +bcm_lintc_intr(void *arg, uint32_t type __diagused) { struct bcm_lintc_softc *sc; u_int cpu; uint32_t num, reg; struct trapframe *tf; + MPASS(type == INTR_TYPE_IRQ); + sc = arg; cpu = PCPU_GET(cpuid); tf = curthread->td_intr_frame; diff --git a/sys/arm/freescale/imx/tzic.c b/sys/arm/freescale/imx/tzic.c --- a/sys/arm/freescale/imx/tzic.c +++ b/sys/arm/freescale/imx/tzic.c @@ -101,12 +101,14 @@ } static int -tzic_intr(void *arg) +tzic_intr(void *arg, uint32_t type __diagused) { struct tzic_softc *sc = arg; int b, i, irq; uint32_t pending; + MPASS(type == INTR_TYPE_IRQ); + /* Get active interrupt */ for (i = 0; i < TZIC_NIRQS / 32; ++i) { pending = tzic_read_4(sc, TZIC_PND(i)); diff --git a/sys/arm/ti/aintc.c b/sys/arm/ti/aintc.c --- a/sys/arm/ti/aintc.c +++ b/sys/arm/ti/aintc.c @@ -117,11 +117,13 @@ } static int -ti_aintc_intr(void *arg) +ti_aintc_intr(void *arg, uint32_t type __diagused) { uint32_t irq; struct ti_aintc_softc *sc = arg; + MPASS(type == INTR_TYPE_IRQ); + /* Get active interrupt */ irq = aintc_read_4(sc, INTC_SIR_IRQ); if ((irq & INTC_SIR_SPURIOUS_MASK) != 0) { diff --git a/sys/arm64/arm64/exception.S b/sys/arm64/arm64/exception.S --- a/sys/arm64/arm64/exception.S +++ b/sys/arm64/arm64/exception.S @@ -27,6 +27,7 @@ #include #include +#include #include "assym.inc" .text @@ -167,7 +168,7 @@ .macro do_ast mrs x19, daif /* Make sure the IRQs are enabled before calling ast() */ - bic x19, x19, #PSR_I + bic x19, x19, #(PSR_I | PSR_F) 1: /* * Mask interrupts while checking the ast pending flag @@ -210,6 +211,15 @@ ERET END(handle_el1h_irq) +ENTRY(handle_el1h_fiq) + save_registers 1 + mov x0, sp + mov x1, #INTR_TYPE_FIQ + bl intr_irq_handler_type + restore_registers 1 + ERET +END(handle_el1h_irq) + ENTRY(handle_el0_sync) save_registers 0 ldr x0, [x18, #PC_CURTHREAD] @@ -230,6 +240,16 @@ ERET END(handle_el0_irq) +ENTRY(handle_el0_fiq) + save_registers 0 + mov x0, sp + mov x1, #INTR_TYPE_FIQ + bl intr_irq_handler_type + do_ast + restore_registers 0 + ERET +END(handle_el0_fiq) + ENTRY(handle_serror) save_registers 0 mov x0, sp @@ -268,16 +288,16 @@ vector el1h_sync 1 /* Synchronous EL1h */ vector el1h_irq 1 /* IRQ EL1h */ - vempty 1 /* FIQ EL1h */ + vector el1h_fiq 1 /* FIQ EL1h */ vector serror 1 /* Error EL1h */ vector el0_sync 0 /* Synchronous 64-bit EL0 */ vector el0_irq 0 /* IRQ 64-bit EL0 */ - vempty 0 /* FIQ 64-bit EL0 */ + vector el0_fiq 0 /* FIQ 64-bit EL0 */ vector serror 0 /* Error 64-bit EL0 */ vector el0_sync 0 /* Synchronous 32-bit EL0 */ vector el0_irq 0 /* IRQ 32-bit EL0 */ - vempty 0 /* FIQ 32-bit EL0 */ + vector el0_fiq 0 /* FIQ 32-bit EL0 */ vector serror 0 /* Error 32-bit EL0 */ diff --git a/sys/arm64/arm64/gic_v3.c b/sys/arm64/arm64/gic_v3.c --- a/sys/arm64/arm64/gic_v3.c +++ b/sys/arm64/arm64/gic_v3.c @@ -589,7 +589,7 @@ } int -arm_gic_v3_intr(void *arg) +arm_gic_v3_intr(void *arg, uint32_t type __diagused) { struct gic_v3_softc *sc = arg; struct gic_v3_irqsrc *gi; @@ -597,6 +597,8 @@ uint64_t active_irq; struct trapframe *tf; + /* No FIQs here yet */ + MPASS(type == INTR_TYPE_IRQ); pic = sc->gic_pic; while (1) { diff --git a/sys/arm64/arm64/gic_v3_var.h b/sys/arm64/arm64/gic_v3_var.h --- a/sys/arm64/arm64/gic_v3_var.h +++ b/sys/arm64/arm64/gic_v3_var.h @@ -109,7 +109,7 @@ /* Device methods */ int gic_v3_attach(device_t dev); int gic_v3_detach(device_t dev); -int arm_gic_v3_intr(void *); +int arm_gic_v3_intr(void *, uint32_t type); uint32_t gic_r_read_4(device_t, bus_size_t); uint64_t gic_r_read_8(device_t, bus_size_t); diff --git a/sys/arm64/include/armreg.h b/sys/arm64/include/armreg.h --- a/sys/arm64/include/armreg.h +++ b/sys/arm64/include/armreg.h @@ -196,7 +196,7 @@ #define DAIF_I (1 << 1) #define DAIF_F (1 << 0) #define DAIF_ALL (DAIF_D | DAIF_A | DAIF_I | DAIF_F) -#define DAIF_INTR (DAIF_I) /* All exceptions that pass */ +#define DAIF_INTR (DAIF_I | DAIF_F) /* All exceptions that pass */ /* through the intr framework */ /* DBGBCR_EL1 - Debug Breakpoint Control Registers */ @@ -2058,7 +2058,7 @@ #define PSR_D 0x00000200UL #define PSR_DAIF (PSR_D | PSR_A | PSR_I | PSR_F) /* The default DAIF mask. These bits are valid in spsr_el1 and daif */ -#define PSR_DAIF_DEFAULT (PSR_F) +#define PSR_DAIF_DEFAULT (0) #define PSR_IL 0x00100000UL #define PSR_SS 0x00200000UL #define PSR_V 0x10000000UL diff --git a/sys/arm64/include/intr.h b/sys/arm64/include/intr.h --- a/sys/arm64/include/intr.h +++ b/sys/arm64/include/intr.h @@ -27,16 +27,18 @@ #ifndef _MACHINE_INTR_H_ #define _MACHINE_INTR_H_ +/* + * We basically only want to expose some interrupt types that must be kept in + * sync between assembly and C here. + */ +#ifndef LOCORE + #ifdef FDT #include #endif #include -#ifndef NIRQ -#define NIRQ 16384 /* XXX - It should be an option. */ -#endif - static inline void arm_irq_memory_barrier(uintptr_t irq) { @@ -46,10 +48,19 @@ void intr_ipi_dispatch(u_int); #endif +#endif /* LOCORE */ + +#ifndef NIRQ +#define NIRQ 16384 /* XXX - It should be an option. */ +#endif + #ifdef DEV_ACPI #define ACPI_INTR_XREF 1 #define ACPI_MSI_XREF 2 #define ACPI_GPIO_XREF 3 #endif +/* Platform interrupt types */ +#define INTR_TYPE_FIQ 0x0001 + #endif /* _MACHINE_INTR_H */ diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c --- a/sys/kern/subr_intr.c +++ b/sys/kern/subr_intr.c @@ -94,6 +94,7 @@ MALLOC_DEFINE(M_INTRNG, "intr", "intr interrupt handling"); /* Main interrupt handler called from assembler -> 'hidden' for C code. */ +void intr_irq_handler_type(struct trapframe *tf, uint32_t type); void intr_irq_handler(struct trapframe *tf); /* Root interrupt controller stuff. */ @@ -101,6 +102,7 @@ static intr_irq_filter_t *irq_root_filter; static void *irq_root_arg; static u_int irq_root_ipicount; +static uint32_t irq_root_typemask; struct intr_pic_child { SLIST_ENTRY(intr_pic_child) pc_next; @@ -337,12 +339,23 @@ * from the assembler, where CPU interrupt is served. */ void -intr_irq_handler(struct trapframe *tf) +intr_irq_handler_type(struct trapframe *tf, uint32_t type) { struct trapframe * oldframe; struct thread * td; KASSERT(irq_root_filter != NULL, ("%s: no filter", __func__)); + KASSERT((irq_root_typemask & type) != 0, + ("%s: unknown irq type (%x)", __func__, type)); + + /* + * We could allow this possibility, but it doesn't make sense at the + * moment so we should defend against it early on. Root filter + * implementations should be more carefully considered if we start to + * allow multiple types firing at once for some reason. + */ + KASSERT((type & ~(1 << (ffs(type) - 1))) == 0, + ("%s: multiple irq types specified (%x)", __func__, type)); kasan_mark(tf, sizeof(*tf), sizeof(*tf), 0); @@ -351,7 +364,7 @@ td = curthread; oldframe = td->td_intr_frame; td->td_intr_frame = tf; - irq_root_filter(irq_root_arg); + irq_root_filter(irq_root_arg, type); td->td_intr_frame = oldframe; critical_exit(); #ifdef HWPMC_HOOKS @@ -361,6 +374,12 @@ #endif } +void +intr_irq_handler(struct trapframe *tf) +{ + intr_irq_handler_type(tf, INTR_TYPE_IRQ); +} + int intr_child_irq_handler(struct intr_pic *parent, uintptr_t irq) { @@ -883,8 +902,8 @@ * an interrupts property and thus no explicit interrupt parent." */ int -intr_pic_claim_root(device_t dev, intptr_t xref, intr_irq_filter_t *filter, - void *arg, u_int ipicount) +intr_pic_claim_root_type(device_t dev, intptr_t xref, intr_irq_filter_t *filter, + void *arg, u_int ipicount, uint32_t typemask) { struct intr_pic *pic; @@ -903,6 +922,11 @@ return (EINVAL); } + if (typemask == 0) { + device_printf(dev, "typemask must be specified\n"); + return (EINVAL); + } + /* * Only one interrupt controllers could be on the root for now. * Note that we further suppose that there is not threaded interrupt @@ -917,11 +941,21 @@ irq_root_filter = filter; irq_root_arg = arg; irq_root_ipicount = ipicount; + irq_root_typemask = typemask; debugf("irq root set to %s\n", device_get_nameunit(dev)); return (0); } +int +intr_pic_claim_root(device_t dev, intptr_t xref, intr_irq_filter_t *filter, + void *arg, u_int ipicount) +{ + + return (intr_pic_claim_root_type(dev, xref, filter, arg, ipicount, + INTR_TYPE_IRQ)); +} + /* * Add a handler to manage a sub range of a parents interrupts. */ diff --git a/sys/riscv/riscv/plic.c b/sys/riscv/riscv/plic.c --- a/sys/riscv/riscv/plic.c +++ b/sys/riscv/riscv/plic.c @@ -157,13 +157,15 @@ } static int -plic_intr(void *arg) +plic_intr(void *arg, uint32_t type __diagused) { struct plic_softc *sc; struct trapframe *tf; uint32_t pending; uint32_t cpu; + MPASS(type == INTR_TYPE_IRQ); + sc = arg; cpu = PCPU_GET(cpuid); diff --git a/sys/sys/intr.h b/sys/sys/intr.h --- a/sys/sys/intr.h +++ b/sys/sys/intr.h @@ -63,14 +63,20 @@ #ifdef notyet #define INTR_SOLO INTR_MD1 -typedef int intr_irq_filter_t(void *arg, struct trapframe *tf); +typedef int intr_irq_filter_t(void *arg, uint32_t type, struct trapframe *tf); #else -typedef int intr_irq_filter_t(void *arg); +typedef int intr_irq_filter_t(void *arg, uint32_t type); #endif typedef int intr_child_irq_filter_t(void *arg, uintptr_t irq); #define INTR_ISRC_NAMELEN (MAXCOMLEN + 1) +/* + * For INTR types, the top bit is reserved for INTRNG usage. Every bit below it + * may be used for a platform type (e.g., FIQs). + */ +#define INTR_TYPE_IRQ 0x80000000U /* IRQs */ + #define INTR_ISRCF_IPI 0x01 /* IPI interrupt */ #define INTR_ISRCF_PPI 0x02 /* PPI interrupt */ #define INTR_ISRCF_BOUND 0x04 /* bound to a CPU */ @@ -110,6 +116,8 @@ struct intr_pic *intr_pic_register(device_t, intptr_t); int intr_pic_deregister(device_t, intptr_t); +int intr_pic_claim_root_type(device_t, intptr_t, intr_irq_filter_t *, void *, + u_int, uint32_t); int intr_pic_claim_root(device_t, intptr_t, intr_irq_filter_t *, void *, u_int); int intr_pic_add_handler(device_t, struct intr_pic *, intr_child_irq_filter_t *, void *, uintptr_t, uintptr_t);