mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 08:43:19 -04:00
intrng: Add support for multiple interrupt roots
Different types of interrupts may require using different exception vectors so this commit adds support multiple interrupt roots to handle these cases. Archs may opt-in to multiple interrupt roots by defining INTR_ROOT_NUM as the number of roots in their intr.h. Based off https://reviews.freebsd.org/D40161. Signed-off-by: Ayrton Munoz <a.munoz3327@gmail.com> Co-authored-by: Kyle Evans <kevans@FreeBSD.org> Co-authored-by: Andrew Turner <andrew@FreeBSD.org> Reviewed-by: imp,mmel,mhorne Pull-Request: https://github.com/freebsd/freebsd-src/pull/1363
This commit is contained in:
parent
a305f44d14
commit
85918beb38
21 changed files with 104 additions and 45 deletions
|
|
@ -236,7 +236,7 @@ a10_intr_pic_attach(struct a10_aintc_softc *sc)
|
|||
if (pic == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
return (intr_pic_claim_root(sc->sc_dev, xref, a10_intr, sc));
|
||||
return (intr_pic_claim_root(sc->sc_dev, xref, a10_intr, sc, INTR_ROOT_IRQ));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@
|
|||
|
||||
#include "assym.inc"
|
||||
|
||||
#include <sys/intr.h>
|
||||
|
||||
#include <machine/asm.h>
|
||||
#include <machine/armreg.h>
|
||||
#include <machine/asmacros.h>
|
||||
|
|
@ -308,7 +310,8 @@ ASENTRY_NP(irq_entry)
|
|||
PUSHFRAMEINSVC /* mode stack, build trapframe there. */
|
||||
adr lr, exception_exit /* Return from handler via standard */
|
||||
mov r0, sp /* exception exit routine. Pass the */
|
||||
b _C_LABEL(intr_irq_handler)/* trapframe to the handler. */
|
||||
mov r1, #INTR_ROOT_IRQ /* trapframe and PIC root to the handler. */
|
||||
b _C_LABEL(intr_irq_handler)
|
||||
END(irq_entry)
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ gic_cpu_mask(struct arm_gic_softc *sc)
|
|||
|
||||
#ifdef SMP
|
||||
static void
|
||||
arm_gic_init_secondary(device_t dev)
|
||||
arm_gic_init_secondary(device_t dev, uint32_t rootnum)
|
||||
{
|
||||
struct arm_gic_softc *sc = device_get_softc(dev);
|
||||
u_int irq, cpu;
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ gic_acpi_attach(device_t dev)
|
|||
/*
|
||||
* Controller is root:
|
||||
*/
|
||||
if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc) != 0) {
|
||||
if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc, INTR_ROOT_IRQ) != 0) {
|
||||
device_printf(dev, "could not set PIC as a root\n");
|
||||
intr_pic_deregister(dev, xref);
|
||||
goto cleanup;
|
||||
|
|
|
|||
|
|
@ -153,7 +153,8 @@ gic_fdt_attach(device_t dev)
|
|||
*/
|
||||
pxref = ofw_bus_find_iparent(ofw_bus_get_node(dev));
|
||||
if (pxref == 0 || xref == pxref) {
|
||||
if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc) != 0) {
|
||||
if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc, INTR_ROOT_IRQ)
|
||||
!= 0) {
|
||||
device_printf(dev, "could not set PIC as a root\n");
|
||||
intr_pic_deregister(dev, xref);
|
||||
goto cleanup;
|
||||
|
|
|
|||
|
|
@ -405,7 +405,8 @@ bcm_intc_attach(device_t dev)
|
|||
sc->intc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
|
||||
RF_ACTIVE);
|
||||
if (sc->intc_irq_res == NULL) {
|
||||
if (intr_pic_claim_root(dev, xref, bcm2835_intc_intr, sc) != 0) {
|
||||
if (intr_pic_claim_root(dev, xref, bcm2835_intc_intr, sc, INTR_ROOT_IRQ)
|
||||
!= 0) {
|
||||
/* XXX clean up */
|
||||
device_printf(dev, "could not set PIC as a root\n");
|
||||
return (ENXIO);
|
||||
|
|
|
|||
|
|
@ -538,7 +538,7 @@ bcm_lintc_init_pmu_on_ap(struct bcm_lintc_softc *sc, u_int cpu)
|
|||
}
|
||||
|
||||
static void
|
||||
bcm_lintc_init_secondary(device_t dev)
|
||||
bcm_lintc_init_secondary(device_t dev, uint32_t rootnum)
|
||||
{
|
||||
u_int cpu;
|
||||
struct bcm_lintc_softc *sc;
|
||||
|
|
@ -646,7 +646,8 @@ bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
|
|||
if (pic == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
error = intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc);
|
||||
error = intr_pic_claim_root(sc->bls_dev, xref, bcm_lintc_intr, sc,
|
||||
INTR_ROOT_IRQ);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
|
|
|
|||
|
|
@ -230,7 +230,8 @@ ti_aintc_pic_attach(struct ti_aintc_softc *sc)
|
|||
if (pic == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
return (intr_pic_claim_root(sc->sc_dev, xref, ti_aintc_intr, sc));
|
||||
return (intr_pic_claim_root(sc->sc_dev, xref, ti_aintc_intr, sc,
|
||||
INTR_ROOT_IRQ));
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/elf_common.h>
|
||||
#include <sys/intr.h>
|
||||
|
||||
#include <machine/asm.h>
|
||||
#include <machine/armreg.h>
|
||||
|
|
@ -232,6 +233,7 @@ ENTRY(handle_el1h_irq)
|
|||
save_registers 1
|
||||
KMSAN_ENTER
|
||||
mov x0, sp
|
||||
mov x1, #INTR_ROOT_IRQ
|
||||
bl intr_irq_handler
|
||||
KMSAN_LEAVE
|
||||
restore_registers 1
|
||||
|
|
@ -266,6 +268,7 @@ ENTRY(handle_el0_irq)
|
|||
save_registers 0
|
||||
KMSAN_ENTER
|
||||
mov x0, sp
|
||||
mov x1, #INTR_ROOT_IRQ
|
||||
bl intr_irq_handler
|
||||
do_ast
|
||||
KMSAN_LEAVE
|
||||
|
|
|
|||
|
|
@ -1093,7 +1093,7 @@ gic_v3_bind_intr(device_t dev, struct intr_irqsrc *isrc)
|
|||
|
||||
#ifdef SMP
|
||||
static void
|
||||
gic_v3_init_secondary(device_t dev)
|
||||
gic_v3_init_secondary(device_t dev, uint32_t rootnum)
|
||||
{
|
||||
struct gic_v3_setup_periph_args pargs;
|
||||
device_t child;
|
||||
|
|
@ -1140,7 +1140,7 @@ gic_v3_init_secondary(device_t dev)
|
|||
|
||||
for (i = 0; i < sc->gic_nchildren; i++) {
|
||||
child = sc->gic_children[i];
|
||||
PIC_INIT_SECONDARY(child);
|
||||
PIC_INIT_SECONDARY(child, rootnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -345,8 +345,9 @@ gic_v3_acpi_attach(device_t dev)
|
|||
}
|
||||
}
|
||||
|
||||
if (intr_pic_claim_root(dev, ACPI_INTR_XREF, arm_gic_v3_intr, sc)
|
||||
!= 0) {
|
||||
err = intr_pic_claim_root(dev, ACPI_INTR_XREF, arm_gic_v3_intr, sc,
|
||||
INTR_ROOT_IRQ);
|
||||
if (err != 0) {
|
||||
err = ENXIO;
|
||||
goto error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,7 +161,8 @@ gic_v3_fdt_attach(device_t dev)
|
|||
/* Register xref */
|
||||
OF_device_register_xref(xref, dev);
|
||||
|
||||
if (intr_pic_claim_root(dev, xref, arm_gic_v3_intr, sc) != 0) {
|
||||
err = intr_pic_claim_root(dev, xref, arm_gic_v3_intr, sc, INTR_ROOT_IRQ);
|
||||
if (err != 0) {
|
||||
err = ENXIO;
|
||||
goto error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1284,7 +1284,7 @@ gicv3_its_setup_intr(device_t dev, struct intr_irqsrc *isrc,
|
|||
|
||||
#ifdef SMP
|
||||
static void
|
||||
gicv3_its_init_secondary(device_t dev)
|
||||
gicv3_its_init_secondary(device_t dev, uint32_t rootnum)
|
||||
{
|
||||
struct gicv3_its_softc *sc;
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ CODE {
|
|||
}
|
||||
|
||||
static void
|
||||
null_pic_init_secondary(device_t dev)
|
||||
null_pic_init_secondary(device_t dev, uint32_t rootnum)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -157,6 +157,7 @@ METHOD void pre_ithread {
|
|||
|
||||
METHOD void init_secondary {
|
||||
device_t dev;
|
||||
uint32_t rootnum;
|
||||
} DEFAULT null_pic_init_secondary;
|
||||
|
||||
METHOD void ipi_send {
|
||||
|
|
|
|||
|
|
@ -89,6 +89,15 @@
|
|||
|
||||
#define INTRNAME_LEN (2*MAXCOMLEN + 1)
|
||||
|
||||
/*
|
||||
* Archs may define multiple roots with INTR_ROOT_NUM to support different kinds
|
||||
* of interrupts (e.g. arm64 FIQs which use a different exception vector than
|
||||
* IRQs).
|
||||
*/
|
||||
#if !defined(INTR_ROOT_NUM)
|
||||
#define INTR_ROOT_NUM 1
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debugf(fmt, args...) do { printf("%s(): ", __func__); \
|
||||
printf(fmt,##args); } while (0)
|
||||
|
|
@ -99,13 +108,14 @@
|
|||
MALLOC_DECLARE(M_INTRNG);
|
||||
MALLOC_DEFINE(M_INTRNG, "intr", "intr interrupt handling");
|
||||
|
||||
/* Main interrupt handler called from assembler -> 'hidden' for C code. */
|
||||
void intr_irq_handler(struct trapframe *tf);
|
||||
|
||||
/* Root interrupt controller stuff. */
|
||||
device_t intr_irq_root_dev;
|
||||
static intr_irq_filter_t *irq_root_filter;
|
||||
static void *irq_root_arg;
|
||||
struct intr_irq_root {
|
||||
device_t dev;
|
||||
intr_irq_filter_t *filter;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static struct intr_irq_root intr_irq_roots[INTR_ROOT_NUM];
|
||||
|
||||
struct intr_pic_child {
|
||||
SLIST_ENTRY(intr_pic_child) pc_next;
|
||||
|
|
@ -327,12 +337,17 @@ isrc_release_counters(struct intr_irqsrc *isrc)
|
|||
* from the assembler, where CPU interrupt is served.
|
||||
*/
|
||||
void
|
||||
intr_irq_handler(struct trapframe *tf)
|
||||
intr_irq_handler(struct trapframe *tf, uint32_t rootnum)
|
||||
{
|
||||
struct trapframe * oldframe;
|
||||
struct thread * td;
|
||||
struct intr_irq_root *root;
|
||||
|
||||
KASSERT(irq_root_filter != NULL, ("%s: no filter", __func__));
|
||||
KASSERT(rootnum < INTR_ROOT_NUM,
|
||||
("%s: invalid interrupt root %d", __func__, rootnum));
|
||||
|
||||
root = &intr_irq_roots[rootnum];
|
||||
KASSERT(root->filter != NULL, ("%s: no filter", __func__));
|
||||
|
||||
kasan_mark(tf, sizeof(*tf), sizeof(*tf), 0);
|
||||
kmsan_mark(tf, sizeof(*tf), KMSAN_STATE_INITED);
|
||||
|
|
@ -342,7 +357,7 @@ intr_irq_handler(struct trapframe *tf)
|
|||
td = curthread;
|
||||
oldframe = td->td_intr_frame;
|
||||
td->td_intr_frame = tf;
|
||||
irq_root_filter(irq_root_arg);
|
||||
(root->filter)(root->arg);
|
||||
td->td_intr_frame = oldframe;
|
||||
critical_exit();
|
||||
#ifdef HWPMC_HOOKS
|
||||
|
|
@ -479,6 +494,14 @@ isrc_free_irq(struct intr_irqsrc *isrc)
|
|||
return (0);
|
||||
}
|
||||
|
||||
device_t
|
||||
intr_irq_root_device(uint32_t rootnum)
|
||||
{
|
||||
KASSERT(rootnum < INTR_ROOT_NUM,
|
||||
("%s: invalid interrupt root %d", __func__, rootnum));
|
||||
return (intr_irq_roots[rootnum].dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize interrupt source and register it into global interrupt table.
|
||||
*/
|
||||
|
|
@ -877,9 +900,10 @@ intr_pic_deregister(device_t dev, intptr_t xref)
|
|||
*/
|
||||
int
|
||||
intr_pic_claim_root(device_t dev, intptr_t xref, intr_irq_filter_t *filter,
|
||||
void *arg)
|
||||
void *arg, uint32_t rootnum)
|
||||
{
|
||||
struct intr_pic *pic;
|
||||
struct intr_irq_root *root;
|
||||
|
||||
pic = pic_lookup(dev, xref, FLAG_PIC);
|
||||
if (pic == NULL) {
|
||||
|
|
@ -901,14 +925,17 @@ intr_pic_claim_root(device_t dev, intptr_t xref, intr_irq_filter_t *filter,
|
|||
* Note that we further suppose that there is not threaded interrupt
|
||||
* routine (handler) on the root. See intr_irq_handler().
|
||||
*/
|
||||
if (intr_irq_root_dev != NULL) {
|
||||
KASSERT(rootnum < INTR_ROOT_NUM,
|
||||
("%s: invalid interrupt root %d", __func__, rootnum));
|
||||
root = &intr_irq_roots[rootnum];
|
||||
if (root->dev != NULL) {
|
||||
device_printf(dev, "another root already set\n");
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
intr_irq_root_dev = dev;
|
||||
irq_root_filter = filter;
|
||||
irq_root_arg = arg;
|
||||
root->dev = dev;
|
||||
root->filter = filter;
|
||||
root->arg = arg;
|
||||
|
||||
debugf("irq root set to %s\n", device_get_nameunit(dev));
|
||||
return (0);
|
||||
|
|
@ -1552,14 +1579,19 @@ dosoftints(void)
|
|||
void
|
||||
intr_pic_init_secondary(void)
|
||||
{
|
||||
device_t dev;
|
||||
uint32_t rootnum;
|
||||
|
||||
/*
|
||||
* QQQ: Only root PIC is aware of other CPUs ???
|
||||
* QQQ: Only root PICs are aware of other CPUs ???
|
||||
*/
|
||||
KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
|
||||
|
||||
//mtx_lock(&isrc_table_lock);
|
||||
PIC_INIT_SECONDARY(intr_irq_root_dev);
|
||||
for (rootnum = 0; rootnum < INTR_ROOT_NUM; rootnum++) {
|
||||
dev = intr_irq_roots[rootnum].dev;
|
||||
if (dev != NULL) {
|
||||
PIC_INIT_SECONDARY(dev, rootnum);
|
||||
}
|
||||
}
|
||||
//mtx_unlock(&isrc_table_lock);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -321,6 +321,7 @@ aplic_setup_direct_mode(device_t dev)
|
|||
int error = ENXIO;
|
||||
u_int irq;
|
||||
int cpu, hartid, rid, i, nintr, idc;
|
||||
device_t rootdev;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
node = ofw_bus_get_node(dev);
|
||||
|
|
@ -407,7 +408,8 @@ aplic_setup_direct_mode(device_t dev)
|
|||
APLIC_IDC_ITHRESHOLD_DISABLE);
|
||||
}
|
||||
|
||||
iparent = OF_xref_from_node(ofw_bus_get_node(intr_irq_root_dev));
|
||||
rootdev = intr_irq_root_device(INTR_ROOT_IRQ);
|
||||
iparent = OF_xref_from_node(ofw_bus_get_node(rootdev));
|
||||
cell = IRQ_EXTERNAL_SUPERVISOR;
|
||||
irq = ofw_bus_map_intr(dev, iparent, 1, &cell);
|
||||
error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ intc_attach(device_t dev)
|
|||
if (pic == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
return (intr_pic_claim_root(sc->dev, xref, intc_intr, sc));
|
||||
return (intr_pic_claim_root(sc->dev, xref, intc_intr, sc, INTR_ROOT_IRQ));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -241,7 +241,7 @@ intc_setup_intr(device_t dev, struct intr_irqsrc *isrc,
|
|||
|
||||
#ifdef SMP
|
||||
static void
|
||||
intc_init_secondary(device_t dev)
|
||||
intc_init_secondary(device_t dev, uint32_t rootnum)
|
||||
{
|
||||
struct intc_softc *sc;
|
||||
struct intr_irqsrc *isrc;
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ sbi_ipi_attach(device_t dev)
|
|||
int irq, rid, error;
|
||||
phandle_t iparent;
|
||||
pcell_t cell;
|
||||
device_t rootdev;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->dev = dev;
|
||||
|
|
@ -155,7 +156,8 @@ sbi_ipi_attach(device_t dev)
|
|||
return (ENXIO);
|
||||
}
|
||||
|
||||
iparent = OF_xref_from_node(ofw_bus_get_node(intr_irq_root_dev));
|
||||
rootdev = intr_irq_root_device(INTR_ROOT_IRQ);
|
||||
iparent = OF_xref_from_node(ofw_bus_get_node(rootdev));
|
||||
cell = IRQ_SOFTWARE_SUPERVISOR;
|
||||
irq = ofw_bus_map_intr(dev, iparent, 1, &cell);
|
||||
error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ riscv_timer_attach(device_t dev)
|
|||
int irq, rid, error;
|
||||
phandle_t iparent;
|
||||
pcell_t cell;
|
||||
device_t rootdev;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
if (riscv_timer_sc != NULL)
|
||||
|
|
@ -211,7 +212,8 @@ riscv_timer_attach(device_t dev)
|
|||
|
||||
riscv_timer_sc = sc;
|
||||
|
||||
iparent = OF_xref_from_node(ofw_bus_get_node(intr_irq_root_dev));
|
||||
rootdev = intr_irq_root_device(INTR_ROOT_IRQ);
|
||||
iparent = OF_xref_from_node(ofw_bus_get_node(rootdev));
|
||||
cell = IRQ_TIMER_SUPERVISOR;
|
||||
irq = ofw_bus_map_intr(dev, iparent, 1, &cell);
|
||||
error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1);
|
||||
|
|
|
|||
|
|
@ -74,8 +74,6 @@
|
|||
#include <ddb/db_sym.h>
|
||||
#endif
|
||||
|
||||
void intr_irq_handler(struct trapframe *tf);
|
||||
|
||||
int (*dtrace_invop_jump_addr)(struct trapframe *);
|
||||
|
||||
/* Called from exception.S */
|
||||
|
|
@ -319,7 +317,7 @@ do_trap_supervisor(struct trapframe *frame)
|
|||
exception = frame->tf_scause & SCAUSE_CODE;
|
||||
if ((frame->tf_scause & SCAUSE_INTR) != 0) {
|
||||
/* Interrupt */
|
||||
intr_irq_handler(frame);
|
||||
intr_irq_handler(frame, INTR_ROOT_IRQ);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -400,7 +398,7 @@ do_trap_user(struct trapframe *frame)
|
|||
exception = frame->tf_scause & SCAUSE_CODE;
|
||||
if ((frame->tf_scause & SCAUSE_INTR) != 0) {
|
||||
/* Interrupt */
|
||||
intr_irq_handler(frame);
|
||||
intr_irq_handler(frame, INTR_ROOT_IRQ);
|
||||
return;
|
||||
}
|
||||
intr_enable();
|
||||
|
|
|
|||
|
|
@ -33,10 +33,15 @@
|
|||
#error Need INTRNG for this file
|
||||
#endif
|
||||
|
||||
#ifndef LOCORE
|
||||
#include <sys/systm.h>
|
||||
#endif
|
||||
|
||||
#define INTR_IRQ_INVALID 0xFFFFFFFF
|
||||
|
||||
#define INTR_ROOT_IRQ 0
|
||||
|
||||
#ifndef LOCORE
|
||||
enum intr_map_data_type {
|
||||
INTR_MAP_DATA_ACPI = 0,
|
||||
INTR_MAP_DATA_FDT,
|
||||
|
|
@ -110,12 +115,13 @@ u_int intr_irq_next_cpu(u_int current_cpu, cpuset_t *cpumask);
|
|||
|
||||
struct intr_pic *intr_pic_register(device_t, intptr_t);
|
||||
int intr_pic_deregister(device_t, intptr_t);
|
||||
int intr_pic_claim_root(device_t, intptr_t, intr_irq_filter_t *, void *);
|
||||
int intr_pic_claim_root(device_t, intptr_t, intr_irq_filter_t *, void *,
|
||||
uint32_t);
|
||||
int intr_pic_add_handler(device_t, struct intr_pic *,
|
||||
intr_child_irq_filter_t *, void *, uintptr_t, uintptr_t);
|
||||
bool intr_is_per_cpu(struct resource *);
|
||||
|
||||
extern device_t intr_irq_root_dev;
|
||||
device_t intr_irq_root_device(uint32_t);
|
||||
|
||||
/* Intr interface for BUS. */
|
||||
|
||||
|
|
@ -163,4 +169,8 @@ void intr_ipi_send(cpuset_t cpus, u_int ipi);
|
|||
void intr_ipi_dispatch(u_int ipi);
|
||||
#endif
|
||||
|
||||
/* Main interrupt handler called from asm on most archs except riscv. */
|
||||
void intr_irq_handler(struct trapframe *tf, uint32_t rootnum);
|
||||
|
||||
#endif /* !LOCORE */
|
||||
#endif /* _SYS_INTR_H */
|
||||
|
|
|
|||
Loading…
Reference in a new issue