diff --git a/sys/arm/arm/gic_acpi.c b/sys/arm/arm/gic_acpi.c --- a/sys/arm/arm/gic_acpi.c +++ b/sys/arm/arm/gic_acpi.c @@ -232,6 +232,14 @@ 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); 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 @@ -158,6 +158,13 @@ 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, 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 @@ -646,7 +646,17 @@ 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 diff --git a/sys/arm64/arm64/gic_v3_acpi.c b/sys/arm64/arm64/gic_v3_acpi.c --- a/sys/arm64/arm64/gic_v3_acpi.c +++ b/sys/arm64/arm64/gic_v3_acpi.c @@ -351,6 +351,14 @@ 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 diff --git a/sys/arm64/arm64/gic_v3_fdt.c b/sys/arm64/arm64/gic_v3_fdt.c --- a/sys/arm64/arm64/gic_v3_fdt.c +++ b/sys/arm64/arm64/gic_v3_fdt.c @@ -166,6 +166,14 @@ 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. 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 @@ -139,6 +139,10 @@ 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 @@ 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 @@ return (0); } - isrc_increment_straycount(isrc); + if ((isrc->isrc_flags & INTR_ISRCF_IPI) == 0) + isrc_increment_straycount(isrc); return (EINVAL); } @@ -1815,6 +1821,20 @@ 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 @@ 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 @@ 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 @@ { 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 @@ 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); } /* diff --git a/sys/sys/intr.h b/sys/sys/intr.h --- a/sys/sys/intr.h +++ b/sys/sys/intr.h @@ -156,6 +156,7 @@ #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);