diff --git a/sys/arm/arm/gic.c b/sys/arm/arm/gic.c index 89db4e324600..f281f29125b6 100644 --- a/sys/arm/arm/gic.c +++ b/sys/arm/arm/gic.c @@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include "gic_if.h" #include "pic_if.h" #include "msi_if.h" @@ -501,12 +502,6 @@ arm_gic_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) ("arm_gic_read_ivar: Invalid bus type %u", sc->gic_bus)); *result = sc->gic_bus; return (0); - case GIC_IVAR_MBI_START: - *result = sc->sc_spi_start; - return (0); - case GIC_IVAR_MBI_COUNT: - *result = sc->sc_spi_count; - return (0); } return (ENOENT); @@ -523,32 +518,6 @@ arm_gic_write_ivar(device_t dev, device_t child, int which, uintptr_t value) case GIC_IVAR_HW_REV: case GIC_IVAR_BUS: return (EINVAL); - case GIC_IVAR_MBI_START: - /* - * GIC_IVAR_MBI_START must be set once and first. This allows - * us to reserve the registers when GIC_IVAR_MBI_COUNT is set. - */ - MPASS(sc->sc_spi_start == 0); - MPASS(sc->sc_spi_count == 0); - MPASS(value >= GIC_FIRST_SPI); - MPASS(value < sc->nirqs); - - sc->sc_spi_start = value; - return (0); - case GIC_IVAR_MBI_COUNT: - MPASS(sc->sc_spi_start != 0); - MPASS(sc->sc_spi_count == 0); - - sc->sc_spi_count = value; - sc->sc_spi_end = sc->sc_spi_start + sc->sc_spi_count; - - MPASS(sc->sc_spi_end <= sc->nirqs); - - /* Reserve these interrupts for MSI/MSI-X use */ - arm_gic_reserve_msi_range(dev, sc->sc_spi_start, - sc->sc_spi_count); - - return (0); } return (ENOENT); @@ -1044,8 +1013,8 @@ arm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp) #endif static int -arm_gic_alloc_msi(device_t dev, device_t child, int count, int maxcount, - device_t *pic, struct intr_irqsrc **srcs) +arm_gic_alloc_msi(device_t dev, u_int mbi_start, u_int mbi_count, int count, + int maxcount, struct intr_irqsrc **isrc) { struct arm_gic_softc *sc; int i, irq, end_irq; @@ -1059,7 +1028,7 @@ arm_gic_alloc_msi(device_t dev, device_t child, int count, int maxcount, mtx_lock_spin(&sc->mutex); found = false; - for (irq = sc->sc_spi_start; irq < sc->sc_spi_end; irq++) { + for (irq = mbi_start; irq < mbi_start + mbi_count; irq++) { /* Start on an aligned interrupt */ if ((irq & (maxcount - 1)) != 0) continue; @@ -1070,7 +1039,7 @@ arm_gic_alloc_msi(device_t dev, device_t child, int count, int maxcount, /* Check this range is valid */ for (end_irq = irq; end_irq != irq + count; end_irq++) { /* No free interrupts */ - if (end_irq == sc->sc_spi_end) { + if (end_irq == mbi_start + mbi_count) { found = false; break; } @@ -1090,7 +1059,7 @@ arm_gic_alloc_msi(device_t dev, device_t child, int count, int maxcount, } /* Not enough interrupts were found */ - if (!found || irq == sc->sc_spi_end) { + if (!found || irq == mbi_start + mbi_count) { mtx_unlock_spin(&sc->mutex); return (ENXIO); } @@ -1102,15 +1071,13 @@ arm_gic_alloc_msi(device_t dev, device_t child, int count, int maxcount, mtx_unlock_spin(&sc->mutex); for (i = 0; i < count; i++) - srcs[i] = (struct intr_irqsrc *)&sc->gic_irqs[irq + i]; - *pic = dev; + isrc[i] = (struct intr_irqsrc *)&sc->gic_irqs[irq + i]; return (0); } static int -arm_gic_release_msi(device_t dev, device_t child, int count, - struct intr_irqsrc **isrc) +arm_gic_release_msi(device_t dev, int count, struct intr_irqsrc **isrc) { struct arm_gic_softc *sc; struct gic_irqsrc *gi; @@ -1134,8 +1101,8 @@ arm_gic_release_msi(device_t dev, device_t child, int count, } static int -arm_gic_alloc_msix(device_t dev, device_t child, device_t *pic, - struct intr_irqsrc **isrcp) +arm_gic_alloc_msix(device_t dev, u_int mbi_start, u_int mbi_count, + struct intr_irqsrc **isrc) { struct arm_gic_softc *sc; int irq; @@ -1144,14 +1111,14 @@ arm_gic_alloc_msix(device_t dev, device_t child, device_t *pic, mtx_lock_spin(&sc->mutex); /* Find an unused interrupt */ - for (irq = sc->sc_spi_start; irq < sc->sc_spi_end; irq++) { + for (irq = mbi_start; irq < mbi_start + mbi_count; irq++) { KASSERT((sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI) != 0, ("%s: Non-MSI interrupt found", __func__)); if ((sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI_USED) == 0) break; } /* No free interrupt was found */ - if (irq == sc->sc_spi_end) { + if (irq == mbi_start + mbi_count) { mtx_unlock_spin(&sc->mutex); return (ENXIO); } @@ -1160,14 +1127,13 @@ arm_gic_alloc_msix(device_t dev, device_t child, device_t *pic, sc->gic_irqs[irq].gi_flags |= GI_FLAG_MSI_USED; mtx_unlock_spin(&sc->mutex); - *isrcp = (struct intr_irqsrc *)&sc->gic_irqs[irq]; - *pic = dev; + *isrc = (struct intr_irqsrc *)&sc->gic_irqs[irq]; return (0); } static int -arm_gic_release_msix(device_t dev, device_t child, struct intr_irqsrc *isrc) +arm_gic_release_msix(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc; struct gic_irqsrc *gi; @@ -1211,11 +1177,12 @@ static device_method_t arm_gic_methods[] = { DEVMETHOD(pic_ipi_setup, arm_gic_ipi_setup), #endif - /* MSI/MSI-X */ - DEVMETHOD(msi_alloc_msi, arm_gic_alloc_msi), - DEVMETHOD(msi_release_msi, arm_gic_release_msi), - DEVMETHOD(msi_alloc_msix, arm_gic_alloc_msix), - DEVMETHOD(msi_release_msix, arm_gic_release_msix), + /* GIC */ + DEVMETHOD(gic_reserve_msi_range, arm_gic_reserve_msi_range), + DEVMETHOD(gic_alloc_msi, arm_gic_alloc_msi), + DEVMETHOD(gic_release_msi, arm_gic_release_msi), + DEVMETHOD(gic_alloc_msix, arm_gic_alloc_msix), + DEVMETHOD(gic_release_msix, arm_gic_release_msix), { 0, 0 } }; @@ -1238,7 +1205,6 @@ arm_gicv2m_attach(device_t dev) { struct arm_gicv2m_softc *sc; uint32_t typer; - u_int spi_start, spi_count; int rid; sc = device_get_softc(dev); @@ -1252,16 +1218,18 @@ arm_gicv2m_attach(device_t dev) } typer = bus_read_4(sc->sc_mem, GICV2M_MSI_TYPER); - spi_start = MSI_TYPER_SPI_BASE(typer); - spi_count = MSI_TYPER_SPI_COUNT(typer); - gic_set_mbi_start(dev, spi_start); - gic_set_mbi_count(dev, spi_count); + sc->sc_spi_start = MSI_TYPER_SPI_BASE(typer); + sc->sc_spi_count = MSI_TYPER_SPI_COUNT(typer); + + /* Reserve these interrupts for MSI/MSI-X use */ + GIC_RESERVE_MSI_RANGE(device_get_parent(dev), sc->sc_spi_start, + sc->sc_spi_count); intr_msi_register(dev, sc->sc_xref); if (bootverbose) - device_printf(dev, "using spi %u to %u\n", spi_start, - spi_start + spi_count - 1); + device_printf(dev, "using spi %u to %u\n", sc->sc_spi_start, + sc->sc_spi_start + sc->sc_spi_count - 1); return (0); } @@ -1270,28 +1238,47 @@ static int arm_gicv2m_alloc_msi(device_t dev, device_t child, int count, int maxcount, device_t *pic, struct intr_irqsrc **srcs) { - return (MSI_ALLOC_MSI(device_get_parent(dev), child, count, maxcount, - pic, srcs)); + struct arm_gicv2m_softc *sc; + int error; + + sc = device_get_softc(dev); + error = GIC_ALLOC_MSI(device_get_parent(dev), sc->sc_spi_start, + sc->sc_spi_count, count, maxcount, srcs); + if (error != 0) + return (error); + + *pic = dev; + return (0); } static int arm_gicv2m_release_msi(device_t dev, device_t child, int count, struct intr_irqsrc **isrc) { - return (MSI_RELEASE_MSI(device_get_parent(dev), child, count, isrc)); + return (GIC_RELEASE_MSI(device_get_parent(dev), count, isrc)); } static int arm_gicv2m_alloc_msix(device_t dev, device_t child, device_t *pic, struct intr_irqsrc **isrcp) { - return (MSI_ALLOC_MSIX(device_get_parent(dev), child, pic, isrcp)); + struct arm_gicv2m_softc *sc; + int error; + + sc = device_get_softc(dev); + error = GIC_ALLOC_MSIX(device_get_parent(dev), sc->sc_spi_start, + sc->sc_spi_count, isrcp); + if (error != 0) + return (error); + + *pic = dev; + return (0); } static int arm_gicv2m_release_msix(device_t dev, device_t child, struct intr_irqsrc *isrc) { - return (MSI_RELEASE_MSIX(device_get_parent(dev), child, isrc)); + return (GIC_RELEASE_MSIX(device_get_parent(dev), isrc)); } static int diff --git a/sys/arm/arm/gic.h b/sys/arm/arm/gic.h index 55f7f0cc5e44..ce0c8a6187e1 100644 --- a/sys/arm/arm/gic.h +++ b/sys/arm/arm/gic.h @@ -63,10 +63,6 @@ struct arm_gic_softc { int nranges; struct arm_gic_range * ranges; - - u_int sc_spi_start; - u_int sc_spi_end; - u_int sc_spi_count; }; DECLARE_CLASS(arm_gic_driver); @@ -74,6 +70,8 @@ DECLARE_CLASS(arm_gic_driver); struct arm_gicv2m_softc { struct resource *sc_mem; uintptr_t sc_xref; + u_int sc_spi_start; + u_int sc_spi_count; }; DECLARE_CLASS(arm_gicv2m_driver); diff --git a/sys/arm/arm/gic_common.h b/sys/arm/arm/gic_common.h index 52827d03e600..9e8fb19300ca 100644 --- a/sys/arm/arm/gic_common.h +++ b/sys/arm/arm/gic_common.h @@ -33,8 +33,6 @@ #define GIC_IVAR_HW_REV 500 #define GIC_IVAR_BUS 501 -#define GIC_IVAR_MBI_START 510 -#define GIC_IVAR_MBI_COUNT 511 /* GIC_IVAR_BUS values */ #define GIC_BUS_UNKNOWN 0 @@ -44,8 +42,6 @@ __BUS_ACCESSOR(gic, hw_rev, GIC, HW_REV, u_int); __BUS_ACCESSOR(gic, bus, GIC, BUS, u_int); -__BUS_ACCESSOR(gic, mbi_start, GIC, MBI_START, u_int); -__BUS_ACCESSOR(gic, mbi_count, GIC, MBI_COUNT, u_int); /* Software Generated Interrupts */ #define GIC_FIRST_SGI 0 /* Irqs 0-15 are SGIs/IPIs. */ diff --git a/sys/arm/arm/gic_if.m b/sys/arm/arm/gic_if.m new file mode 100644 index 000000000000..b9bef7db1a80 --- /dev/null +++ b/sys/arm/arm/gic_if.m @@ -0,0 +1,39 @@ + +INTERFACE gic; + +HEADER { + struct intr_irqsrc; +}; + +METHOD void reserve_msi_range { + device_t dev; + u_int mbi_start; + u_int mbi_count; +}; + +METHOD int alloc_msi { + device_t dev; + u_int mbi_start; + u_int mbi_count; + int count; + int maxcount; + struct intr_irqsrc **isrc; +}; + +METHOD int release_msi { + device_t dev; + int count; + struct intr_irqsrc **isrc; +}; + +METHOD int alloc_msix { + device_t dev; + u_int mbi_start; + u_int mbi_count; + struct intr_irqsrc **isrc; +}; + +METHOD int release_msix { + device_t dev; + struct intr_irqsrc *isrc; +}; diff --git a/sys/arm64/arm64/gic_v3.c b/sys/arm64/arm64/gic_v3.c index 23e1b3632fb8..7d9160f8ae17 100644 --- a/sys/arm64/arm64/gic_v3.c +++ b/sys/arm64/arm64/gic_v3.c @@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$"); #include #endif +#include "gic_if.h" #include "pic_if.h" #include "msi_if.h" @@ -95,6 +96,12 @@ static pic_ipi_send_t gic_v3_ipi_send; static pic_ipi_setup_t gic_v3_ipi_setup; #endif +static gic_reserve_msi_range_t gic_v3_reserve_msi_range; +static gic_alloc_msi_t gic_v3_gic_alloc_msi; +static gic_release_msi_t gic_v3_gic_release_msi; +static gic_alloc_msix_t gic_v3_gic_alloc_msix; +static gic_release_msix_t gic_v3_gic_release_msix; + static msi_alloc_msi_t gic_v3_alloc_msi; static msi_release_msi_t gic_v3_release_msi; static msi_alloc_msix_t gic_v3_alloc_msix; @@ -139,6 +146,13 @@ static device_method_t gic_v3_methods[] = { DEVMETHOD(msi_release_msix, gic_v3_release_msix), DEVMETHOD(msi_map_msi, gic_v3_map_msi), + /* GIC */ + DEVMETHOD(gic_reserve_msi_range, gic_v3_reserve_msi_range), + DEVMETHOD(gic_alloc_msi, gic_v3_gic_alloc_msi), + DEVMETHOD(gic_release_msi, gic_v3_gic_release_msi), + DEVMETHOD(gic_alloc_msix, gic_v3_gic_alloc_msix), + DEVMETHOD(gic_release_msix, gic_v3_gic_release_msix), + /* End */ DEVMETHOD_END }; @@ -467,12 +481,6 @@ gic_v3_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) ("gic_v3_read_ivar: Invalid bus type %u", sc->gic_bus)); *result = sc->gic_bus; return (0); - case GIC_IVAR_MBI_START: - *result = sc->gic_mbi_start; - return (0); - case GIC_IVAR_MBI_COUNT: - *result = sc->gic_mbi_end - sc->gic_mbi_start; - return (0); } return (ENOENT); @@ -491,30 +499,6 @@ gic_v3_write_ivar(device_t dev, device_t child, int which, uintptr_t value) case GIC_IVAR_HW_REV: case GIC_IVAR_BUS: return (EINVAL); - case GIC_IVAR_MBI_START: - /* - * GIC_IVAR_MBI_START must be set once and first. This allows - * us to reserve the registers when GIC_IVAR_MBI_COUNT is set. - */ - MPASS(sc->gic_mbi_start == 0); - MPASS(sc->gic_mbi_end == 0); - MPASS(value >= GIC_FIRST_SPI); - MPASS(value < sc->gic_nirqs); - - sc->gic_mbi_start = value; - return (0); - case GIC_IVAR_MBI_COUNT: - MPASS(sc->gic_mbi_start != 0); - MPASS(sc->gic_mbi_end == 0); - - sc->gic_mbi_end = value - sc->gic_mbi_start; - - MPASS(sc->gic_mbi_end <= sc->gic_nirqs); - - /* Reserve these interrupts for MSI/MSI-X use */ - gic_v3_reserve_msi_range(dev, sc->gic_mbi_start, value); - - return (0); } return (ENOENT); @@ -1385,8 +1369,8 @@ gic_v3_redist_init(struct gic_v3_softc *sc) */ static int -gic_v3_alloc_msi(device_t dev, device_t child, int count, int maxcount, - device_t *pic, struct intr_irqsrc **srcs) +gic_v3_gic_alloc_msi(device_t dev, u_int mbi_start, u_int mbi_count, + int count, int maxcount, struct intr_irqsrc **isrc) { struct gic_v3_softc *sc; int i, irq, end_irq; @@ -1400,7 +1384,7 @@ gic_v3_alloc_msi(device_t dev, device_t child, int count, int maxcount, mtx_lock(&sc->gic_mbi_mtx); found = false; - for (irq = sc->gic_mbi_start; irq < sc->gic_mbi_end; irq++) { + for (irq = mbi_start; irq < mbi_start + mbi_count; irq++) { /* Start on an aligned interrupt */ if ((irq & (maxcount - 1)) != 0) continue; @@ -1411,7 +1395,7 @@ gic_v3_alloc_msi(device_t dev, device_t child, int count, int maxcount, /* Check this range is valid */ for (end_irq = irq; end_irq != irq + count; end_irq++) { /* No free interrupts */ - if (end_irq == sc->gic_mbi_end) { + if (end_irq == mbi_start + mbi_count) { found = false; break; } @@ -1431,7 +1415,7 @@ gic_v3_alloc_msi(device_t dev, device_t child, int count, int maxcount, } /* Not enough interrupts were found */ - if (!found || irq == sc->gic_mbi_end) { + if (!found || irq == mbi_start + mbi_count) { mtx_unlock(&sc->gic_mbi_mtx); return (ENXIO); } @@ -1443,15 +1427,13 @@ gic_v3_alloc_msi(device_t dev, device_t child, int count, int maxcount, mtx_unlock(&sc->gic_mbi_mtx); for (i = 0; i < count; i++) - srcs[i] = (struct intr_irqsrc *)&sc->gic_irqs[irq + i]; - *pic = dev; + isrc[i] = (struct intr_irqsrc *)&sc->gic_irqs[irq + i]; return (0); } static int -gic_v3_release_msi(device_t dev, device_t child, int count, - struct intr_irqsrc **isrc) +gic_v3_gic_release_msi(device_t dev, int count, struct intr_irqsrc **isrc) { struct gic_v3_softc *sc; struct gic_v3_irqsrc *gi; @@ -1475,7 +1457,7 @@ gic_v3_release_msi(device_t dev, device_t child, int count, } static int -gic_v3_alloc_msix(device_t dev, device_t child, device_t *pic, +gic_v3_gic_alloc_msix(device_t dev, u_int mbi_start, u_int mbi_count, struct intr_irqsrc **isrcp) { struct gic_v3_softc *sc; @@ -1485,14 +1467,14 @@ gic_v3_alloc_msix(device_t dev, device_t child, device_t *pic, mtx_lock(&sc->gic_mbi_mtx); /* Find an unused interrupt */ - for (irq = sc->gic_mbi_start; irq < sc->gic_mbi_end; irq++) { + for (irq = mbi_start; irq < mbi_start + mbi_count; irq++) { KASSERT((sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI) != 0, ("%s: Non-MSI interrupt found", __func__)); if ((sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI_USED) == 0) break; } /* No free interrupt was found */ - if (irq == sc->gic_mbi_end) { + if (irq == mbi_start + mbi_count) { mtx_unlock(&sc->gic_mbi_mtx); return (ENXIO); } @@ -1502,13 +1484,12 @@ gic_v3_alloc_msix(device_t dev, device_t child, device_t *pic, mtx_unlock(&sc->gic_mbi_mtx); *isrcp = (struct intr_irqsrc *)&sc->gic_irqs[irq]; - *pic = dev; return (0); } static int -gic_v3_release_msix(device_t dev, device_t child, struct intr_irqsrc *isrc) +gic_v3_gic_release_msix(device_t dev, struct intr_irqsrc *isrc) { struct gic_v3_softc *sc; struct gic_v3_irqsrc *gi; @@ -1526,6 +1507,54 @@ gic_v3_release_msix(device_t dev, device_t child, struct intr_irqsrc *isrc) return (0); } +static int +gic_v3_alloc_msi(device_t dev, device_t child, int count, int maxcount, + device_t *pic, struct intr_irqsrc **isrc) +{ + struct gic_v3_softc *sc; + int error; + + sc = device_get_softc(dev); + error = gic_v3_gic_alloc_msi(dev, sc->gic_mbi_start, + sc->gic_mbi_end - sc->gic_mbi_start, count, maxcount, isrc); + if (error != 0) + return (error); + + *pic = dev; + return (0); +} + +static int +gic_v3_release_msi(device_t dev, device_t child, int count, + struct intr_irqsrc **isrc) +{ + return (gic_v3_gic_release_msi(dev, count, isrc)); +} + +static int +gic_v3_alloc_msix(device_t dev, device_t child, device_t *pic, + struct intr_irqsrc **isrc) +{ + struct gic_v3_softc *sc; + int error; + + sc = device_get_softc(dev); + error = gic_v3_gic_alloc_msix(dev, sc->gic_mbi_start, + sc->gic_mbi_end - sc->gic_mbi_start, isrc); + if (error != 0) + return (error); + + *pic = dev; + + return (0); +} + +static int +gic_v3_release_msix(device_t dev, device_t child, struct intr_irqsrc *isrc) +{ + return (gic_v3_gic_release_msix(dev, isrc)); +} + static int gic_v3_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc, uint64_t *addr, uint32_t *data) diff --git a/sys/conf/files.arm b/sys/conf/files.arm index 86e75ef4a2a4..76f62eb2e14e 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -32,6 +32,7 @@ arm/arm/gdb_machdep.c optional gdb arm/arm/generic_timer.c optional generic_timer arm/arm/gic.c optional gic arm/arm/gic_fdt.c optional gic fdt +arm/arm/gic_if.m optional gic arm/arm/identcpu-v6.c standard arm/arm/in_cksum.c optional inet | inet6 arm/arm/in_cksum_arm.S optional inet | inet6 diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index 9dd071b97e37..dcd9711ea7da 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -20,6 +20,7 @@ arm/arm/generic_timer.c standard arm/arm/gic.c standard arm/arm/gic_acpi.c optional acpi arm/arm/gic_fdt.c optional fdt +arm/arm/gic_if.m standard arm/arm/pmu.c standard arm/arm/pmu_fdt.c optional fdt arm64/acpica/acpi_iort.c optional acpi