intrng: Allow alternative IPI PICs to be registered and used

On RISC-V, the root PIC (whether the PLIC or, as will be the case in
future, the local interrupt controller) cannot send IPIs, relying on
another means to trigger the necessary software interrupts (firmware
calls), but there are upcoming standard devices that will be able to
inject them, so we can't just put the firmware calls in the root PIC
driver.

Thus, split out a new intr_ipi_dev from intr_irq_root_dev to use for
sending IPIs. New devices can be registered with a given priority up
until the first IPI is set up, when the best device seen so far gets
frozen as the IPI device to use.

Reviewed by:	mhorne
MFC after:	1 month
Differential Revision:	https://reviews.freebsd.org/D35899
This commit is contained in:
Jessica Clarke 2024-01-24 23:49:54 +00:00
parent fae8755f16
commit 103d39efe0
7 changed files with 78 additions and 8 deletions

View file

@ -232,6 +232,14 @@ gic_acpi_attach(device_t dev)
intr_pic_deregister(dev, xref);
goto cleanup;
}
#ifdef SMP
if (intr_ipi_pic_register(dev, 0) != 0) {
device_printf(dev, "could not register for IPIs\n");
goto cleanup;
}
#endif
/* If we have children probe and attach them */
if (arm_gic_add_children(dev)) {
bus_generic_probe(dev);

View file

@ -158,6 +158,13 @@ gic_fdt_attach(device_t dev)
intr_pic_deregister(dev, xref);
goto cleanup;
}
#ifdef SMP
if (intr_ipi_pic_register(dev, 0) != 0) {
device_printf(dev, "could not register for IPIs\n");
goto cleanup;
}
#endif
} else {
if (sc->base.gic_res[2] == NULL) {
device_printf(dev,

View file

@ -646,7 +646,17 @@ bcm_lintc_pic_attach(struct bcm_lintc_softc *sc)
if (pic == NULL)
return (ENXIO);
return (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);
if (error != 0)
return (error);
#ifdef SMP
error = intr_ipi_pic_register(sc->bls_dev, 0);
if (error != 0)
return (error);
#endif
return (0);
}
static int

View file

@ -351,6 +351,14 @@ gic_v3_acpi_attach(device_t dev)
goto error;
}
#ifdef SMP
err = intr_ipi_pic_register(dev, 0);
if (err != 0) {
device_printf(dev, "could not register for IPIs\n");
goto error;
}
#endif
/*
* Try to register the ITS driver to this GIC. The GIC will act as
* a bus in that case. Failure here will not affect the main GIC

View file

@ -166,6 +166,14 @@ gic_v3_fdt_attach(device_t dev)
goto error;
}
#ifdef SMP
err = intr_ipi_pic_register(dev, 0);
if (err != 0) {
device_printf(dev, "could not register for IPIs\n");
goto error;
}
#endif
/*
* Try to register ITS to this GIC.
* GIC will act as a bus in that case.

View file

@ -139,6 +139,10 @@ struct intr_ipi {
char ii_name[INTR_IPI_NAMELEN];
u_long *ii_count;
};
static device_t intr_ipi_dev;
static u_int intr_ipi_dev_priority;
static bool intr_ipi_dev_frozen;
#endif
static struct mtx pic_list_lock;
@ -380,7 +384,8 @@ intr_isrc_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf)
KASSERT(isrc != NULL, ("%s: no source", __func__));
isrc_increment_count(isrc);
if ((isrc->isrc_flags & INTR_ISRCF_IPI) == 0)
isrc_increment_count(isrc);
#ifdef INTR_SOLO
if (isrc->isrc_filter != NULL) {
@ -396,7 +401,8 @@ intr_isrc_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf)
return (0);
}
isrc_increment_straycount(isrc);
if ((isrc->isrc_flags & INTR_ISRCF_IPI) == 0)
isrc_increment_straycount(isrc);
return (EINVAL);
}
@ -1815,6 +1821,20 @@ intr_ipi_lookup(u_int ipi)
return (&ipi_sources[ipi]);
}
int
intr_ipi_pic_register(device_t dev, u_int priority)
{
if (intr_ipi_dev_frozen) {
device_printf(dev, "IPI device already frozen");
return (EBUSY);
}
if (intr_ipi_dev == NULL || priority > intr_ipi_dev_priority)
intr_ipi_dev = dev;
return (0);
}
/*
* Setup IPI handler on interrupt controller.
*
@ -1828,10 +1848,17 @@ intr_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
struct intr_ipi *ii;
int error;
KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
if (!intr_ipi_dev_frozen) {
if (intr_ipi_dev == NULL)
panic("%s: no IPI PIC attached", __func__);
intr_ipi_dev_frozen = true;
device_printf(intr_ipi_dev, "using for IPIs\n");
}
KASSERT(hand != NULL, ("%s: ipi %u no handler", __func__, ipi));
error = PIC_IPI_SETUP(intr_irq_root_dev, ipi, &isrc);
error = PIC_IPI_SETUP(intr_ipi_dev, ipi, &isrc);
if (error != 0)
return;
@ -1846,7 +1873,7 @@ intr_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
strlcpy(ii->ii_name, name, INTR_IPI_NAMELEN);
ii->ii_count = intr_ipi_setup_counters(name);
PIC_ENABLE_INTR(intr_irq_root_dev, isrc);
PIC_ENABLE_INTR(intr_ipi_dev, isrc);
}
void
@ -1854,7 +1881,8 @@ intr_ipi_send(cpuset_t cpus, u_int ipi)
{
struct intr_ipi *ii;
KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
KASSERT(intr_ipi_dev_frozen,
("%s: IPI device not yet frozen", __func__));
ii = intr_ipi_lookup(ipi);
if (ii->ii_count == NULL)
@ -1873,7 +1901,7 @@ intr_ipi_send(cpuset_t cpus, u_int ipi)
dsb(ishst);
#endif
PIC_IPI_SEND(intr_irq_root_dev, ii->ii_isrc, cpus, ipi);
PIC_IPI_SEND(intr_ipi_dev, ii->ii_isrc, cpus, ipi);
}
/*

View file

@ -156,6 +156,7 @@ extern u_int intr_nirq; /* number of IRQs on intrng platforms */
#ifdef SMP
typedef void intr_ipi_handler_t(void *);
int intr_ipi_pic_register(device_t dev, u_int priority);
void intr_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
void *arg);
void intr_ipi_send(cpuset_t cpus, u_int ipi);