Changeset View
Changeset View
Standalone View
Standalone View
head/sys/arm/arm/gic.c
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/cpuset.h> | #include <sys/cpuset.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#ifdef INTRNG | #ifdef INTRNG | ||||
#include <sys/sched.h> | #include <sys/sched.h> | ||||
#endif | #endif | ||||
#include <vm/vm.h> | |||||
#include <vm/pmap.h> | |||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/intr.h> | #include <machine/intr.h> | ||||
#include <machine/smp.h> | #include <machine/smp.h> | ||||
#include <dev/fdt/fdt_common.h> | #include <dev/fdt/fdt_common.h> | ||||
#include <dev/ofw/openfirm.h> | #include <dev/ofw/openfirm.h> | ||||
#include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
#include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
#ifdef INTRNG | #ifdef INTRNG | ||||
#include "pic_if.h" | #include "pic_if.h" | ||||
#include "msi_if.h" | |||||
#endif | #endif | ||||
#define GIC_DEBUG_SPURIOUS | #define GIC_DEBUG_SPURIOUS | ||||
/* We are using GICv2 register naming */ | /* We are using GICv2 register naming */ | ||||
/* Distributor Registers */ | /* Distributor Registers */ | ||||
#define GICD_CTLR 0x000 /* v1 ICDDCR */ | #define GICD_CTLR 0x000 /* v1 ICDDCR */ | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
#ifdef INTRNG | #ifdef INTRNG | ||||
struct gic_irqsrc { | struct gic_irqsrc { | ||||
struct intr_irqsrc gi_isrc; | struct intr_irqsrc gi_isrc; | ||||
uint32_t gi_irq; | uint32_t gi_irq; | ||||
enum intr_polarity gi_pol; | enum intr_polarity gi_pol; | ||||
enum intr_trigger gi_trig; | enum intr_trigger gi_trig; | ||||
#define GI_FLAG_EARLY_EOI (1 << 0) | #define GI_FLAG_EARLY_EOI (1 << 0) | ||||
#define GI_FLAG_MSI (1 << 1) /* This interrupt source should only */ | |||||
/* be used for MSI/MSI-X interrupts */ | |||||
#define GI_FLAG_MSI_USED (1 << 2) /* This irq is already allocated */ | |||||
/* for a MSI/MSI-X interrupt */ | |||||
u_int gi_flags; | u_int gi_flags; | ||||
}; | }; | ||||
static u_int gic_irq_cpu; | static u_int gic_irq_cpu; | ||||
static int arm_gic_intr(void *); | static int arm_gic_intr(void *); | ||||
static int arm_gic_bind_intr(device_t dev, struct intr_irqsrc *isrc); | static int arm_gic_bind_intr(device_t dev, struct intr_irqsrc *isrc); | ||||
#ifdef SMP | #ifdef SMP | ||||
▲ Show 20 Lines • Show All 423 Lines • ▼ Show 20 Lines | if (cdev == NULL) { | ||||
free(dinfo, M_DEVBUF); | free(dinfo, M_DEVBUF); | ||||
continue; | continue; | ||||
} | } | ||||
device_set_ivars(cdev, dinfo); | device_set_ivars(cdev, dinfo); | ||||
} | } | ||||
return (true); | return (true); | ||||
} | } | ||||
static void | |||||
arm_gic_reserve_msi_range(device_t dev, u_int start, u_int count) | |||||
{ | |||||
struct arm_gic_softc *sc; | |||||
int i; | |||||
sc = device_get_softc(dev); | |||||
KASSERT((start + count) < sc->nirqs, | |||||
("%s: Trying to allocate too many MSI IRQs: %d + %d > %d", __func__, | |||||
start, count, sc->nirqs)); | |||||
for (i = 0; i < count; i++) { | |||||
KASSERT(sc->gic_irqs[start + i].gi_isrc.isrc_handlers == 0, | |||||
("%s: MSI interrupt %d already has a handler", __func__, | |||||
count + i)); | |||||
KASSERT(sc->gic_irqs[start + i].gi_pol == INTR_POLARITY_CONFORM, | |||||
("%s: MSI interrupt %d already has a polarity", __func__, | |||||
count + i)); | |||||
KASSERT(sc->gic_irqs[start + i].gi_trig == INTR_TRIGGER_CONFORM, | |||||
("%s: MSI interrupt %d already has a trigger", __func__, | |||||
count + i)); | |||||
sc->gic_irqs[start + i].gi_pol = INTR_POLARITY_HIGH; | |||||
sc->gic_irqs[start + i].gi_trig = INTR_TRIGGER_EDGE; | |||||
sc->gic_irqs[start + i].gi_flags |= GI_FLAG_MSI; | |||||
} | |||||
} | |||||
#endif | #endif | ||||
static int | static int | ||||
arm_gic_attach(device_t dev) | arm_gic_attach(device_t dev) | ||||
{ | { | ||||
struct arm_gic_softc *sc; | struct arm_gic_softc *sc; | ||||
int i; | int i; | ||||
uint32_t icciidr, mask, nirqs; | uint32_t icciidr, mask, nirqs; | ||||
▲ Show 20 Lines • Show All 440 Lines • ▼ Show 20 Lines | #endif | ||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
switch (data->type) { | switch (data->type) { | ||||
#ifdef FDT | #ifdef FDT | ||||
case INTR_MAP_DATA_FDT: | case INTR_MAP_DATA_FDT: | ||||
daf = (struct intr_map_data_fdt *)data; | daf = (struct intr_map_data_fdt *)data; | ||||
if (gic_map_fdt(dev, daf->ncells, daf->cells, &irq, &pol, | if (gic_map_fdt(dev, daf->ncells, daf->cells, &irq, &pol, | ||||
&trig) != 0) | &trig) != 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
KASSERT(irq >= sc->nirqs || | |||||
(sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI) == 0, | |||||
("%s: Attempting to map a MSI interrupt from FDT", | |||||
__func__)); | |||||
break; | break; | ||||
#endif | #endif | ||||
default: | default: | ||||
return (ENOTSUP); | return (ENOTSUP); | ||||
} | } | ||||
if (irq >= sc->nirqs) | if (irq >= sc->nirqs) | ||||
return (EINVAL); | return (EINVAL); | ||||
Show All 33 Lines | arm_gic_setup_intr(device_t dev, struct intr_irqsrc *isrc, | ||||
struct resource *res, struct intr_map_data *data) | struct resource *res, struct intr_map_data *data) | ||||
{ | { | ||||
struct arm_gic_softc *sc = device_get_softc(dev); | struct arm_gic_softc *sc = device_get_softc(dev); | ||||
struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; | struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; | ||||
u_int irq; | u_int irq; | ||||
enum intr_trigger trig; | enum intr_trigger trig; | ||||
enum intr_polarity pol; | enum intr_polarity pol; | ||||
if (data == NULL) | if ((gi->gi_flags & GI_FLAG_MSI) == GI_FLAG_MSI) { | ||||
return (ENOTSUP); | irq = gi->gi_irq; | ||||
pol = gi->gi_pol; | |||||
trig = gi->gi_trig; | |||||
KASSERT(pol == INTR_POLARITY_HIGH, | |||||
("%s: MSI interrupts must be active-high", __func__)); | |||||
KASSERT(trig == INTR_TRIGGER_EDGE, | |||||
("%s: MSI interrupts must be edge triggered", __func__)); | |||||
} else if (data != NULL) { | |||||
/* Get config for resource. */ | /* Get config for resource. */ | ||||
if (gic_map_intr(dev, data, &irq, &pol, &trig)) | if (gic_map_intr(dev, data, &irq, &pol, &trig)) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (gi->gi_irq != irq) | if (gi->gi_irq != irq) | ||||
return (EINVAL); | return (EINVAL); | ||||
} else | |||||
return (ENOTSUP); | |||||
/* Compare config if this is not first setup. */ | /* Compare config if this is not first setup. */ | ||||
if (isrc->isrc_handlers != 0) { | if (isrc->isrc_handlers != 0) { | ||||
if ((pol != INTR_POLARITY_CONFORM && pol != gi->gi_pol) || | if ((pol != INTR_POLARITY_CONFORM && pol != gi->gi_pol) || | ||||
(trig != INTR_TRIGGER_CONFORM && trig != gi->gi_trig)) | (trig != INTR_TRIGGER_CONFORM && trig != gi->gi_trig)) | ||||
return (EINVAL); | return (EINVAL); | ||||
else | else | ||||
return (0); | return (0); | ||||
} | } | ||||
/* For MSI/MSI-X we should have already configured these */ | |||||
if ((gi->gi_flags & GI_FLAG_MSI) == 0) { | |||||
if (pol == INTR_POLARITY_CONFORM) | if (pol == INTR_POLARITY_CONFORM) | ||||
pol = INTR_POLARITY_LOW; /* just pick some */ | pol = INTR_POLARITY_LOW; /* just pick some */ | ||||
if (trig == INTR_TRIGGER_CONFORM) | if (trig == INTR_TRIGGER_CONFORM) | ||||
trig = INTR_TRIGGER_EDGE; /* just pick some */ | trig = INTR_TRIGGER_EDGE; /* just pick some */ | ||||
gi->gi_pol = pol; | gi->gi_pol = pol; | ||||
gi->gi_trig = trig; | gi->gi_trig = trig; | ||||
/* Edge triggered interrupts need an early EOI sent */ | /* Edge triggered interrupts need an early EOI sent */ | ||||
if (gi->gi_pol == INTR_TRIGGER_EDGE) | if (gi->gi_pol == INTR_TRIGGER_EDGE) | ||||
gi->gi_flags |= GI_FLAG_EARLY_EOI; | gi->gi_flags |= GI_FLAG_EARLY_EOI; | ||||
} | |||||
/* | /* | ||||
* XXX - In case that per CPU interrupt is going to be enabled in time | * XXX - In case that per CPU interrupt is going to be enabled in time | ||||
* when SMP is already started, we need some IPI call which | * when SMP is already started, we need some IPI call which | ||||
* enables it on others CPUs. Further, it's more complicated as | * enables it on others CPUs. Further, it's more complicated as | ||||
* pic_enable_source() and pic_disable_source() should act on | * pic_enable_source() and pic_disable_source() should act on | ||||
* per CPU basis only. Thus, it should be solved here somehow. | * per CPU basis only. Thus, it should be solved here somehow. | ||||
*/ | */ | ||||
if (isrc->isrc_flags & INTR_ISRCF_PPI) | if (isrc->isrc_flags & INTR_ISRCF_PPI) | ||||
CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); | CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); | ||||
gic_config(sc, gi->gi_irq, trig, pol); | gic_config(sc, gi->gi_irq, gi->gi_trig, gi->gi_pol); | ||||
arm_gic_bind_intr(dev, isrc); | arm_gic_bind_intr(dev, isrc); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
arm_gic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, | arm_gic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, | ||||
struct resource *res, struct intr_map_data *data) | struct resource *res, struct intr_map_data *data) | ||||
{ | { | ||||
struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; | struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; | ||||
if (isrc->isrc_handlers == 0) { | if (isrc->isrc_handlers == 0 && (gi->gi_flags & GI_FLAG_MSI) == 0) { | ||||
gi->gi_pol = INTR_POLARITY_CONFORM; | gi->gi_pol = INTR_POLARITY_CONFORM; | ||||
gi->gi_trig = INTR_TRIGGER_CONFORM; | gi->gi_trig = INTR_TRIGGER_CONFORM; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
arm_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc) | arm_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc) | ||||
▲ Show 20 Lines • Show All 367 Lines • ▼ Show 20 Lines | |||||
#define MSI_TYPER_SPI_COUNT(x) (((x) >> 0) & 0x3ff) | #define MSI_TYPER_SPI_COUNT(x) (((x) >> 0) & 0x3ff) | ||||
#define GICv2M_MSI_SETSPI_NS 0x040 | #define GICv2M_MSI_SETSPI_NS 0x040 | ||||
#define GICV2M_MSI_IIDR 0xFCC | #define GICV2M_MSI_IIDR 0xFCC | ||||
struct arm_gicv2m_softc { | struct arm_gicv2m_softc { | ||||
struct resource *sc_mem; | struct resource *sc_mem; | ||||
struct mtx sc_mutex; | struct mtx sc_mutex; | ||||
u_int sc_spi_start; | u_int sc_spi_start; | ||||
u_int sc_spi_end; | |||||
u_int sc_spi_count; | u_int sc_spi_count; | ||||
u_int sc_spi_offset; | |||||
}; | }; | ||||
static struct ofw_compat_data gicv2m_compat_data[] = { | static struct ofw_compat_data gicv2m_compat_data[] = { | ||||
{"arm,gic-v2m-frame", true}, | {"arm,gic-v2m-frame", true}, | ||||
{NULL, false} | {NULL, false} | ||||
}; | }; | ||||
static int | static int | ||||
Show All 9 Lines | arm_gicv2m_probe(device_t dev) | ||||
device_set_desc(dev, "ARM Generic Interrupt Controller MSI/MSIX"); | device_set_desc(dev, "ARM Generic Interrupt Controller MSI/MSIX"); | ||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
static int | static int | ||||
arm_gicv2m_attach(device_t dev) | arm_gicv2m_attach(device_t dev) | ||||
{ | { | ||||
struct arm_gicv2m_softc *sc; | struct arm_gicv2m_softc *sc; | ||||
struct arm_gic_softc *psc; | |||||
uint32_t typer; | uint32_t typer; | ||||
int rid; | int rid; | ||||
psc = device_get_softc(device_get_parent(dev)); | |||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
rid = 0; | rid = 0; | ||||
sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, | sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, | ||||
RF_ACTIVE); | RF_ACTIVE); | ||||
if (sc->sc_mem == NULL) { | if (sc->sc_mem == NULL) { | ||||
device_printf(dev, "Unable to allocate resources\n"); | device_printf(dev, "Unable to allocate resources\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
typer = bus_read_4(sc->sc_mem, GICV2M_MSI_TYPER); | typer = bus_read_4(sc->sc_mem, GICV2M_MSI_TYPER); | ||||
sc->sc_spi_start = MSI_TYPER_SPI_BASE(typer); | sc->sc_spi_start = MSI_TYPER_SPI_BASE(typer); | ||||
sc->sc_spi_count = MSI_TYPER_SPI_COUNT(typer); | sc->sc_spi_count = MSI_TYPER_SPI_COUNT(typer); | ||||
sc->sc_spi_end = sc->sc_spi_start + sc->sc_spi_count; | |||||
/* Reserve these interrupts for MSI/MSI-X use */ | |||||
arm_gic_reserve_msi_range(device_get_parent(dev), sc->sc_spi_start, | |||||
sc->sc_spi_count); | |||||
mtx_init(&sc->sc_mutex, "GICv2m lock", "", MTX_DEF); | mtx_init(&sc->sc_mutex, "GICv2m lock", "", MTX_DEF); | ||||
intr_msi_register(dev, gic_xref(dev)); | |||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev, "using spi %u to %u\n", sc->sc_spi_start, | device_printf(dev, "using spi %u to %u\n", sc->sc_spi_start, | ||||
sc->sc_spi_start + sc->sc_spi_count - 1); | sc->sc_spi_start + sc->sc_spi_count - 1); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | |||||
arm_gicv2m_alloc_msi(device_t dev, device_t child, int count, int maxcount, | |||||
device_t *pic, struct intr_irqsrc **srcs) | |||||
{ | |||||
struct arm_gic_softc *psc; | |||||
struct arm_gicv2m_softc *sc; | |||||
int i, irq, end_irq; | |||||
bool found; | |||||
KASSERT(powerof2(count), ("%s: bad count", __func__)); | |||||
KASSERT(powerof2(maxcount), ("%s: bad maxcount", __func__)); | |||||
psc = device_get_softc(device_get_parent(dev)); | |||||
sc = device_get_softc(dev); | |||||
mtx_lock(&sc->sc_mutex); | |||||
found = false; | |||||
for (irq = sc->sc_spi_start; irq < sc->sc_spi_end && !found; irq++) { | |||||
/* Start on an aligned interrupt */ | |||||
if ((irq & (maxcount - 1)) != 0) | |||||
continue; | |||||
/* Assume we found a valid range until shown otherwise */ | |||||
found = true; | |||||
/* Check this range is valid */ | |||||
for (end_irq = irq; end_irq != irq + count - 1; end_irq++) { | |||||
/* No free interrupts */ | |||||
if (end_irq == sc->sc_spi_end) { | |||||
found = false; | |||||
break; | |||||
} | |||||
KASSERT((psc->gic_irqs[irq].gi_flags & GI_FLAG_MSI)!= 0, | |||||
("%s: Non-MSI interrupt found", __func__)); | |||||
/* This is already used */ | |||||
if ((psc->gic_irqs[irq].gi_flags & GI_FLAG_MSI_USED) == | |||||
GI_FLAG_MSI_USED) { | |||||
found = false; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
/* Not enough interrupts were found */ | |||||
if (!found || irq == sc->sc_spi_end) { | |||||
mtx_unlock(&sc->sc_mutex); | |||||
return (ENXIO); | |||||
} | |||||
for (i = 0; i < count; i++) { | |||||
/* Mark the interrupt as used */ | |||||
psc->gic_irqs[irq + i].gi_flags |= GI_FLAG_MSI_USED; | |||||
} | |||||
mtx_unlock(&sc->sc_mutex); | |||||
for (i = 0; i < count; i++) | |||||
srcs[i] = (struct intr_irqsrc *)&psc->gic_irqs[irq + i]; | |||||
*pic = device_get_parent(dev); | |||||
return (0); | |||||
} | |||||
static int | |||||
arm_gicv2m_release_msi(device_t dev, device_t child, int count, | |||||
struct intr_irqsrc **isrc) | |||||
{ | |||||
struct arm_gicv2m_softc *sc; | |||||
struct gic_irqsrc *gi; | |||||
int i; | |||||
sc = device_get_softc(dev); | |||||
mtx_lock(&sc->sc_mutex); | |||||
for (i = 0; i < count; i++) { | |||||
gi = (struct gic_irqsrc *)isrc; | |||||
KASSERT((gi->gi_flags & GI_FLAG_MSI_USED) == GI_FLAG_MSI_USED, | |||||
("%s: Trying to release an unused MSI-X interrupt", | |||||
__func__)); | |||||
gi->gi_flags &= ~GI_FLAG_MSI_USED; | |||||
mtx_unlock(&sc->sc_mutex); | |||||
} | |||||
return (0); | |||||
} | |||||
static int | |||||
arm_gicv2m_alloc_msix(device_t dev, device_t child, device_t *pic, | |||||
struct intr_irqsrc **isrcp) | |||||
{ | |||||
struct arm_gicv2m_softc *sc; | |||||
struct arm_gic_softc *psc; | |||||
int irq; | |||||
psc = device_get_softc(device_get_parent(dev)); | |||||
sc = device_get_softc(dev); | |||||
mtx_lock(&sc->sc_mutex); | |||||
/* Find an unused interrupt */ | |||||
for (irq = sc->sc_spi_start; irq < sc->sc_spi_end; irq++) { | |||||
KASSERT((psc->gic_irqs[irq].gi_flags & GI_FLAG_MSI) != 0, | |||||
("%s: Non-MSI interrupt found", __func__)); | |||||
if ((psc->gic_irqs[irq].gi_flags & GI_FLAG_MSI_USED) == 0) | |||||
break; | |||||
} | |||||
/* No free interrupt was found */ | |||||
if (irq == sc->sc_spi_end) { | |||||
mtx_unlock(&sc->sc_mutex); | |||||
return (ENXIO); | |||||
} | |||||
/* Mark the interrupt as used */ | |||||
psc->gic_irqs[irq].gi_flags |= GI_FLAG_MSI_USED; | |||||
mtx_unlock(&sc->sc_mutex); | |||||
*isrcp = (struct intr_irqsrc *)&psc->gic_irqs[irq]; | |||||
*pic = device_get_parent(dev); | |||||
return (0); | |||||
} | |||||
static int | |||||
arm_gicv2m_release_msix(device_t dev, device_t child, struct intr_irqsrc *isrc) | |||||
{ | |||||
struct arm_gicv2m_softc *sc; | |||||
struct gic_irqsrc *gi; | |||||
sc = device_get_softc(dev); | |||||
gi = (struct gic_irqsrc *)isrc; | |||||
KASSERT((gi->gi_flags & GI_FLAG_MSI_USED) == GI_FLAG_MSI_USED, | |||||
("%s: Trying to release an unused MSI-X interrupt", __func__)); | |||||
mtx_lock(&sc->sc_mutex); | |||||
gi->gi_flags &= ~GI_FLAG_MSI_USED; | |||||
mtx_unlock(&sc->sc_mutex); | |||||
return (0); | |||||
} | |||||
static int | |||||
arm_gicv2m_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc, | |||||
uint64_t *addr, uint32_t *data) | |||||
{ | |||||
struct arm_gicv2m_softc *sc = device_get_softc(dev); | |||||
struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; | |||||
*addr = vtophys(rman_get_virtual(sc->sc_mem)) + GICv2M_MSI_SETSPI_NS; | |||||
*data = gi->gi_irq; | |||||
return (0); | |||||
} | |||||
static device_method_t arm_gicv2m_methods[] = { | static device_method_t arm_gicv2m_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_probe, arm_gicv2m_probe), | DEVMETHOD(device_probe, arm_gicv2m_probe), | ||||
DEVMETHOD(device_attach, arm_gicv2m_attach), | DEVMETHOD(device_attach, arm_gicv2m_attach), | ||||
/* MSI/MSI-X */ | |||||
DEVMETHOD(msi_alloc_msi, arm_gicv2m_alloc_msi), | |||||
DEVMETHOD(msi_release_msi, arm_gicv2m_release_msi), | |||||
DEVMETHOD(msi_alloc_msix, arm_gicv2m_alloc_msix), | |||||
DEVMETHOD(msi_release_msix, arm_gicv2m_release_msix), | |||||
DEVMETHOD(msi_map_msi, arm_gicv2m_map_msi), | |||||
/* End */ | /* End */ | ||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
DEFINE_CLASS_0(gicv2m, arm_gicv2m_driver, arm_gicv2m_methods, | DEFINE_CLASS_0(gicv2m, arm_gicv2m_driver, arm_gicv2m_methods, | ||||
sizeof(struct arm_gicv2m_softc)); | sizeof(struct arm_gicv2m_softc)); | ||||
static devclass_t arm_gicv2m_devclass; | static devclass_t arm_gicv2m_devclass; | ||||
EARLY_DRIVER_MODULE(gicv2m, gic, arm_gicv2m_driver, | EARLY_DRIVER_MODULE(gicv2m, gic, arm_gicv2m_driver, | ||||
arm_gicv2m_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); | arm_gicv2m_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); | ||||
#endif | #endif |