Add a gic interface to allocate MSI interrupts
The previous update to handle the gicv2m as a child of the gicv3 driver assumed there was only a single gicv2m child. On some hardware there are multiple children. Support this by removing the mbi ivars and adding a new interface to handle MSI allocation in a given range. Tested by: mw, trasz Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D32224
This commit is contained in:
parent
3d2533f5c2
commit
18c2139495
@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <arm/arm/gic.h>
|
#include <arm/arm/gic.h>
|
||||||
#include <arm/arm/gic_common.h>
|
#include <arm/arm/gic_common.h>
|
||||||
|
|
||||||
|
#include "gic_if.h"
|
||||||
#include "pic_if.h"
|
#include "pic_if.h"
|
||||||
#include "msi_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));
|
("arm_gic_read_ivar: Invalid bus type %u", sc->gic_bus));
|
||||||
*result = sc->gic_bus;
|
*result = sc->gic_bus;
|
||||||
return (0);
|
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);
|
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_HW_REV:
|
||||||
case GIC_IVAR_BUS:
|
case GIC_IVAR_BUS:
|
||||||
return (EINVAL);
|
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);
|
return (ENOENT);
|
||||||
@ -1044,8 +1013,8 @@ arm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
arm_gic_alloc_msi(device_t dev, device_t child, int count, int maxcount,
|
arm_gic_alloc_msi(device_t dev, u_int mbi_start, u_int mbi_count, int count,
|
||||||
device_t *pic, struct intr_irqsrc **srcs)
|
int maxcount, struct intr_irqsrc **isrc)
|
||||||
{
|
{
|
||||||
struct arm_gic_softc *sc;
|
struct arm_gic_softc *sc;
|
||||||
int i, irq, end_irq;
|
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);
|
mtx_lock_spin(&sc->mutex);
|
||||||
|
|
||||||
found = false;
|
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 */
|
/* Start on an aligned interrupt */
|
||||||
if ((irq & (maxcount - 1)) != 0)
|
if ((irq & (maxcount - 1)) != 0)
|
||||||
continue;
|
continue;
|
||||||
@ -1070,7 +1039,7 @@ arm_gic_alloc_msi(device_t dev, device_t child, int count, int maxcount,
|
|||||||
/* Check this range is valid */
|
/* Check this range is valid */
|
||||||
for (end_irq = irq; end_irq != irq + count; end_irq++) {
|
for (end_irq = irq; end_irq != irq + count; end_irq++) {
|
||||||
/* No free interrupts */
|
/* No free interrupts */
|
||||||
if (end_irq == sc->sc_spi_end) {
|
if (end_irq == mbi_start + mbi_count) {
|
||||||
found = false;
|
found = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1090,7 +1059,7 @@ arm_gic_alloc_msi(device_t dev, device_t child, int count, int maxcount,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Not enough interrupts were found */
|
/* Not enough interrupts were found */
|
||||||
if (!found || irq == sc->sc_spi_end) {
|
if (!found || irq == mbi_start + mbi_count) {
|
||||||
mtx_unlock_spin(&sc->mutex);
|
mtx_unlock_spin(&sc->mutex);
|
||||||
return (ENXIO);
|
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);
|
mtx_unlock_spin(&sc->mutex);
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
srcs[i] = (struct intr_irqsrc *)&sc->gic_irqs[irq + i];
|
isrc[i] = (struct intr_irqsrc *)&sc->gic_irqs[irq + i];
|
||||||
*pic = dev;
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
arm_gic_release_msi(device_t dev, device_t child, int count,
|
arm_gic_release_msi(device_t dev, int count, struct intr_irqsrc **isrc)
|
||||||
struct intr_irqsrc **isrc)
|
|
||||||
{
|
{
|
||||||
struct arm_gic_softc *sc;
|
struct arm_gic_softc *sc;
|
||||||
struct gic_irqsrc *gi;
|
struct gic_irqsrc *gi;
|
||||||
@ -1134,8 +1101,8 @@ arm_gic_release_msi(device_t dev, device_t child, int count,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
arm_gic_alloc_msix(device_t dev, device_t child, device_t *pic,
|
arm_gic_alloc_msix(device_t dev, u_int mbi_start, u_int mbi_count,
|
||||||
struct intr_irqsrc **isrcp)
|
struct intr_irqsrc **isrc)
|
||||||
{
|
{
|
||||||
struct arm_gic_softc *sc;
|
struct arm_gic_softc *sc;
|
||||||
int irq;
|
int irq;
|
||||||
@ -1144,14 +1111,14 @@ arm_gic_alloc_msix(device_t dev, device_t child, device_t *pic,
|
|||||||
|
|
||||||
mtx_lock_spin(&sc->mutex);
|
mtx_lock_spin(&sc->mutex);
|
||||||
/* Find an unused interrupt */
|
/* 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,
|
KASSERT((sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI) != 0,
|
||||||
("%s: Non-MSI interrupt found", __func__));
|
("%s: Non-MSI interrupt found", __func__));
|
||||||
if ((sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI_USED) == 0)
|
if ((sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI_USED) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* No free interrupt was found */
|
/* No free interrupt was found */
|
||||||
if (irq == sc->sc_spi_end) {
|
if (irq == mbi_start + mbi_count) {
|
||||||
mtx_unlock_spin(&sc->mutex);
|
mtx_unlock_spin(&sc->mutex);
|
||||||
return (ENXIO);
|
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;
|
sc->gic_irqs[irq].gi_flags |= GI_FLAG_MSI_USED;
|
||||||
mtx_unlock_spin(&sc->mutex);
|
mtx_unlock_spin(&sc->mutex);
|
||||||
|
|
||||||
*isrcp = (struct intr_irqsrc *)&sc->gic_irqs[irq];
|
*isrc = (struct intr_irqsrc *)&sc->gic_irqs[irq];
|
||||||
*pic = dev;
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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 arm_gic_softc *sc;
|
||||||
struct gic_irqsrc *gi;
|
struct gic_irqsrc *gi;
|
||||||
@ -1211,11 +1177,12 @@ static device_method_t arm_gic_methods[] = {
|
|||||||
DEVMETHOD(pic_ipi_setup, arm_gic_ipi_setup),
|
DEVMETHOD(pic_ipi_setup, arm_gic_ipi_setup),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* MSI/MSI-X */
|
/* GIC */
|
||||||
DEVMETHOD(msi_alloc_msi, arm_gic_alloc_msi),
|
DEVMETHOD(gic_reserve_msi_range, arm_gic_reserve_msi_range),
|
||||||
DEVMETHOD(msi_release_msi, arm_gic_release_msi),
|
DEVMETHOD(gic_alloc_msi, arm_gic_alloc_msi),
|
||||||
DEVMETHOD(msi_alloc_msix, arm_gic_alloc_msix),
|
DEVMETHOD(gic_release_msi, arm_gic_release_msi),
|
||||||
DEVMETHOD(msi_release_msix, arm_gic_release_msix),
|
DEVMETHOD(gic_alloc_msix, arm_gic_alloc_msix),
|
||||||
|
DEVMETHOD(gic_release_msix, arm_gic_release_msix),
|
||||||
|
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
@ -1238,7 +1205,6 @@ arm_gicv2m_attach(device_t dev)
|
|||||||
{
|
{
|
||||||
struct arm_gicv2m_softc *sc;
|
struct arm_gicv2m_softc *sc;
|
||||||
uint32_t typer;
|
uint32_t typer;
|
||||||
u_int spi_start, spi_count;
|
|
||||||
int rid;
|
int rid;
|
||||||
|
|
||||||
sc = device_get_softc(dev);
|
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);
|
typer = bus_read_4(sc->sc_mem, GICV2M_MSI_TYPER);
|
||||||
spi_start = MSI_TYPER_SPI_BASE(typer);
|
sc->sc_spi_start = MSI_TYPER_SPI_BASE(typer);
|
||||||
spi_count = MSI_TYPER_SPI_COUNT(typer);
|
sc->sc_spi_count = MSI_TYPER_SPI_COUNT(typer);
|
||||||
gic_set_mbi_start(dev, spi_start);
|
|
||||||
gic_set_mbi_count(dev, spi_count);
|
/* 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);
|
intr_msi_register(dev, sc->sc_xref);
|
||||||
|
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
device_printf(dev, "using spi %u to %u\n", spi_start,
|
device_printf(dev, "using spi %u to %u\n", sc->sc_spi_start,
|
||||||
spi_start + spi_count - 1);
|
sc->sc_spi_start + sc->sc_spi_count - 1);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -1270,28 +1238,47 @@ static int
|
|||||||
arm_gicv2m_alloc_msi(device_t dev, device_t child, int count, int maxcount,
|
arm_gicv2m_alloc_msi(device_t dev, device_t child, int count, int maxcount,
|
||||||
device_t *pic, struct intr_irqsrc **srcs)
|
device_t *pic, struct intr_irqsrc **srcs)
|
||||||
{
|
{
|
||||||
return (MSI_ALLOC_MSI(device_get_parent(dev), child, count, maxcount,
|
struct arm_gicv2m_softc *sc;
|
||||||
pic, srcs));
|
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
|
static int
|
||||||
arm_gicv2m_release_msi(device_t dev, device_t child, int count,
|
arm_gicv2m_release_msi(device_t dev, device_t child, int count,
|
||||||
struct intr_irqsrc **isrc)
|
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
|
static int
|
||||||
arm_gicv2m_alloc_msix(device_t dev, device_t child, device_t *pic,
|
arm_gicv2m_alloc_msix(device_t dev, device_t child, device_t *pic,
|
||||||
struct intr_irqsrc **isrcp)
|
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
|
static int
|
||||||
arm_gicv2m_release_msix(device_t dev, device_t child, struct intr_irqsrc *isrc)
|
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
|
static int
|
||||||
|
@ -63,10 +63,6 @@ struct arm_gic_softc {
|
|||||||
|
|
||||||
int nranges;
|
int nranges;
|
||||||
struct arm_gic_range * ranges;
|
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);
|
DECLARE_CLASS(arm_gic_driver);
|
||||||
@ -74,6 +70,8 @@ DECLARE_CLASS(arm_gic_driver);
|
|||||||
struct arm_gicv2m_softc {
|
struct arm_gicv2m_softc {
|
||||||
struct resource *sc_mem;
|
struct resource *sc_mem;
|
||||||
uintptr_t sc_xref;
|
uintptr_t sc_xref;
|
||||||
|
u_int sc_spi_start;
|
||||||
|
u_int sc_spi_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_CLASS(arm_gicv2m_driver);
|
DECLARE_CLASS(arm_gicv2m_driver);
|
||||||
|
@ -33,8 +33,6 @@
|
|||||||
|
|
||||||
#define GIC_IVAR_HW_REV 500
|
#define GIC_IVAR_HW_REV 500
|
||||||
#define GIC_IVAR_BUS 501
|
#define GIC_IVAR_BUS 501
|
||||||
#define GIC_IVAR_MBI_START 510
|
|
||||||
#define GIC_IVAR_MBI_COUNT 511
|
|
||||||
|
|
||||||
/* GIC_IVAR_BUS values */
|
/* GIC_IVAR_BUS values */
|
||||||
#define GIC_BUS_UNKNOWN 0
|
#define GIC_BUS_UNKNOWN 0
|
||||||
@ -44,8 +42,6 @@
|
|||||||
|
|
||||||
__BUS_ACCESSOR(gic, hw_rev, GIC, HW_REV, u_int);
|
__BUS_ACCESSOR(gic, hw_rev, GIC, HW_REV, u_int);
|
||||||
__BUS_ACCESSOR(gic, bus, GIC, BUS, 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 */
|
/* Software Generated Interrupts */
|
||||||
#define GIC_FIRST_SGI 0 /* Irqs 0-15 are SGIs/IPIs. */
|
#define GIC_FIRST_SGI 0 /* Irqs 0-15 are SGIs/IPIs. */
|
||||||
|
39
sys/arm/arm/gic_if.m
Normal file
39
sys/arm/arm/gic_if.m
Normal file
@ -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;
|
||||||
|
};
|
@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <dev/acpica/acpivar.h>
|
#include <dev/acpica/acpivar.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "gic_if.h"
|
||||||
#include "pic_if.h"
|
#include "pic_if.h"
|
||||||
#include "msi_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;
|
static pic_ipi_setup_t gic_v3_ipi_setup;
|
||||||
#endif
|
#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_alloc_msi_t gic_v3_alloc_msi;
|
||||||
static msi_release_msi_t gic_v3_release_msi;
|
static msi_release_msi_t gic_v3_release_msi;
|
||||||
static msi_alloc_msix_t gic_v3_alloc_msix;
|
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_release_msix, gic_v3_release_msix),
|
||||||
DEVMETHOD(msi_map_msi, gic_v3_map_msi),
|
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 */
|
/* End */
|
||||||
DEVMETHOD_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));
|
("gic_v3_read_ivar: Invalid bus type %u", sc->gic_bus));
|
||||||
*result = sc->gic_bus;
|
*result = sc->gic_bus;
|
||||||
return (0);
|
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);
|
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_HW_REV:
|
||||||
case GIC_IVAR_BUS:
|
case GIC_IVAR_BUS:
|
||||||
return (EINVAL);
|
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);
|
return (ENOENT);
|
||||||
@ -1385,8 +1369,8 @@ gic_v3_redist_init(struct gic_v3_softc *sc)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gic_v3_alloc_msi(device_t dev, device_t child, int count, int maxcount,
|
gic_v3_gic_alloc_msi(device_t dev, u_int mbi_start, u_int mbi_count,
|
||||||
device_t *pic, struct intr_irqsrc **srcs)
|
int count, int maxcount, struct intr_irqsrc **isrc)
|
||||||
{
|
{
|
||||||
struct gic_v3_softc *sc;
|
struct gic_v3_softc *sc;
|
||||||
int i, irq, end_irq;
|
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);
|
mtx_lock(&sc->gic_mbi_mtx);
|
||||||
|
|
||||||
found = false;
|
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 */
|
/* Start on an aligned interrupt */
|
||||||
if ((irq & (maxcount - 1)) != 0)
|
if ((irq & (maxcount - 1)) != 0)
|
||||||
continue;
|
continue;
|
||||||
@ -1411,7 +1395,7 @@ gic_v3_alloc_msi(device_t dev, device_t child, int count, int maxcount,
|
|||||||
/* Check this range is valid */
|
/* Check this range is valid */
|
||||||
for (end_irq = irq; end_irq != irq + count; end_irq++) {
|
for (end_irq = irq; end_irq != irq + count; end_irq++) {
|
||||||
/* No free interrupts */
|
/* No free interrupts */
|
||||||
if (end_irq == sc->gic_mbi_end) {
|
if (end_irq == mbi_start + mbi_count) {
|
||||||
found = false;
|
found = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1431,7 +1415,7 @@ gic_v3_alloc_msi(device_t dev, device_t child, int count, int maxcount,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Not enough interrupts were found */
|
/* 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);
|
mtx_unlock(&sc->gic_mbi_mtx);
|
||||||
return (ENXIO);
|
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);
|
mtx_unlock(&sc->gic_mbi_mtx);
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
srcs[i] = (struct intr_irqsrc *)&sc->gic_irqs[irq + i];
|
isrc[i] = (struct intr_irqsrc *)&sc->gic_irqs[irq + i];
|
||||||
*pic = dev;
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gic_v3_release_msi(device_t dev, device_t child, int count,
|
gic_v3_gic_release_msi(device_t dev, int count, struct intr_irqsrc **isrc)
|
||||||
struct intr_irqsrc **isrc)
|
|
||||||
{
|
{
|
||||||
struct gic_v3_softc *sc;
|
struct gic_v3_softc *sc;
|
||||||
struct gic_v3_irqsrc *gi;
|
struct gic_v3_irqsrc *gi;
|
||||||
@ -1475,7 +1457,7 @@ gic_v3_release_msi(device_t dev, device_t child, int count,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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 intr_irqsrc **isrcp)
|
||||||
{
|
{
|
||||||
struct gic_v3_softc *sc;
|
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);
|
mtx_lock(&sc->gic_mbi_mtx);
|
||||||
/* Find an unused interrupt */
|
/* 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,
|
KASSERT((sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI) != 0,
|
||||||
("%s: Non-MSI interrupt found", __func__));
|
("%s: Non-MSI interrupt found", __func__));
|
||||||
if ((sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI_USED) == 0)
|
if ((sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI_USED) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* No free interrupt was found */
|
/* No free interrupt was found */
|
||||||
if (irq == sc->gic_mbi_end) {
|
if (irq == mbi_start + mbi_count) {
|
||||||
mtx_unlock(&sc->gic_mbi_mtx);
|
mtx_unlock(&sc->gic_mbi_mtx);
|
||||||
return (ENXIO);
|
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);
|
mtx_unlock(&sc->gic_mbi_mtx);
|
||||||
|
|
||||||
*isrcp = (struct intr_irqsrc *)&sc->gic_irqs[irq];
|
*isrcp = (struct intr_irqsrc *)&sc->gic_irqs[irq];
|
||||||
*pic = dev;
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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_softc *sc;
|
||||||
struct gic_v3_irqsrc *gi;
|
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);
|
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
|
static int
|
||||||
gic_v3_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,
|
gic_v3_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,
|
||||||
uint64_t *addr, uint32_t *data)
|
uint64_t *addr, uint32_t *data)
|
||||||
|
@ -32,6 +32,7 @@ arm/arm/gdb_machdep.c optional gdb
|
|||||||
arm/arm/generic_timer.c optional generic_timer
|
arm/arm/generic_timer.c optional generic_timer
|
||||||
arm/arm/gic.c optional gic
|
arm/arm/gic.c optional gic
|
||||||
arm/arm/gic_fdt.c optional gic fdt
|
arm/arm/gic_fdt.c optional gic fdt
|
||||||
|
arm/arm/gic_if.m optional gic
|
||||||
arm/arm/identcpu-v6.c standard
|
arm/arm/identcpu-v6.c standard
|
||||||
arm/arm/in_cksum.c optional inet | inet6
|
arm/arm/in_cksum.c optional inet | inet6
|
||||||
arm/arm/in_cksum_arm.S optional inet | inet6
|
arm/arm/in_cksum_arm.S optional inet | inet6
|
||||||
|
@ -20,6 +20,7 @@ arm/arm/generic_timer.c standard
|
|||||||
arm/arm/gic.c standard
|
arm/arm/gic.c standard
|
||||||
arm/arm/gic_acpi.c optional acpi
|
arm/arm/gic_acpi.c optional acpi
|
||||||
arm/arm/gic_fdt.c optional fdt
|
arm/arm/gic_fdt.c optional fdt
|
||||||
|
arm/arm/gic_if.m standard
|
||||||
arm/arm/pmu.c standard
|
arm/arm/pmu.c standard
|
||||||
arm/arm/pmu_fdt.c optional fdt
|
arm/arm/pmu_fdt.c optional fdt
|
||||||
arm64/acpica/acpi_iort.c optional acpi
|
arm64/acpica/acpi_iort.c optional acpi
|
||||||
|
Loading…
Reference in New Issue
Block a user