Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/arm/gic.c
Show First 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | |||||
static u_int sgi_first_unused = GIC_FIRST_SGI; | static u_int sgi_first_unused = GIC_FIRST_SGI; | ||||
#endif | #endif | ||||
#define GIC_INTR_ISRC(sc, irq) (&sc->gic_irqs[irq].gi_isrc) | #define GIC_INTR_ISRC(sc, irq) (&sc->gic_irqs[irq].gi_isrc) | ||||
static struct resource_spec arm_gic_spec[] = { | static struct resource_spec arm_gic_spec[] = { | ||||
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */ | { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */ | ||||
{ SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */ | { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */ | ||||
{ SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, /* Parent interrupt */ | { SYS_RES_MEMORY, 2, RF_ACTIVE | RF_OPTIONAL }, /* Virtual Interface Control */ | ||||
{ SYS_RES_MEMORY, 3, RF_ACTIVE | RF_OPTIONAL }, /* Virtual CPU interface */ | |||||
{ SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, /* vGIC maintenance interrupt or parent interrupt */ | |||||
{ -1, 0 } | { -1, 0 } | ||||
}; | }; | ||||
extern char hypmode_enabled[]; | |||||
#if defined(__arm__) && defined(INVARIANTS) | #if defined(__arm__) && defined(INVARIANTS) | ||||
static int gic_debug_spurious = 1; | static int gic_debug_spurious = 1; | ||||
#else | #else | ||||
static int gic_debug_spurious = 0; | static int gic_debug_spurious = 0; | ||||
#endif | #endif | ||||
TUNABLE_INT("hw.gic.debug_spurious", &gic_debug_spurious); | TUNABLE_INT("hw.gic.debug_spurious", &gic_debug_spurious); | ||||
static u_int arm_gic_map[MAXCPU]; | static u_int arm_gic_map[MAXCPU]; | ||||
static struct arm_gic_softc *gic_sc = NULL; | static struct arm_gic_softc *gic_sc = NULL; | ||||
#define gic_c_read_4(_sc, _reg) \ | #define gic_c_read_4(_sc, _reg) \ | ||||
bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg)) | bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg)) | ||||
#define gic_c_write_4(_sc, _reg, _val) \ | #define gic_c_write_4(_sc, _reg, _val) \ | ||||
bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val)) | bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val)) | ||||
#define gic_d_read_4(_sc, _reg) \ | #define gic_d_read_4(_sc, _reg) \ | ||||
bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg)) | bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg)) | ||||
#define gic_d_write_1(_sc, _reg, _val) \ | #define gic_d_write_1(_sc, _reg, _val) \ | ||||
bus_space_write_1((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val)) | bus_space_write_1((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val)) | ||||
#define gic_d_write_4(_sc, _reg, _val) \ | #define gic_d_write_4(_sc, _reg, _val) \ | ||||
bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val)) | bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val)) | ||||
#define gic_h_read_4(_sc, _reg) \ | |||||
bus_space_read_4((_sc)->gic_h_bst, (_sc)->gic_h_bsh, (_reg)) | |||||
#define gic_h_write_4(_sc, _reg, _val) \ | |||||
bus_space_write_4((_sc)->gic_h_bst, (_sc)->gic_h_bsh, (_reg), (_val)) | |||||
struct arm_gic_softc * | |||||
arm_gic_get_sc(void) | |||||
{ | |||||
return gic_sc; | |||||
} | |||||
uint32_t | |||||
arm_gic_get_lr_num(void) | |||||
{ | |||||
return (gic_h_read_4(gic_sc, GICH_VTR) & 0x3f) + 1; | |||||
} | |||||
static inline void | static inline void | ||||
gic_irq_unmask(struct arm_gic_softc *sc, u_int irq) | gic_irq_unmask(struct arm_gic_softc *sc, u_int irq) | ||||
{ | { | ||||
gic_d_write_4(sc, GICD_ISENABLER(irq), GICD_I_MASK(irq)); | gic_d_write_4(sc, GICD_ISENABLER(irq), GICD_I_MASK(irq)); | ||||
} | } | ||||
static inline void | static inline void | ||||
▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | arm_gic_attach(device_t dev) | ||||
sc->gic_dev = dev; | sc->gic_dev = dev; | ||||
gic_sc = sc; | gic_sc = sc; | ||||
/* Initialize mutex */ | /* Initialize mutex */ | ||||
mtx_init(&sc->mutex, "GIC lock", NULL, MTX_SPIN); | mtx_init(&sc->mutex, "GIC lock", NULL, MTX_SPIN); | ||||
/* Distributor Interface */ | /* Distributor Interface */ | ||||
sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]); | sc->gic_d_bst = rman_get_bustag(sc->gic_res[DISTRIBUTOR_RES_IDX]); | ||||
sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[0]); | sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[DISTRIBUTOR_RES_IDX]); | ||||
/* CPU Interface */ | /* CPU Interface */ | ||||
sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]); | sc->gic_c_bst = rman_get_bustag(sc->gic_res[CPU_INTERFACE_RES_IDX]); | ||||
sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]); | sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[CPU_INTERFACE_RES_IDX]); | ||||
/* Virtual Interface Control */ | |||||
if (sc->is_root) { | |||||
if (sc->gic_res[VIRT_INTERFACE_CONTROL_RES_IDX] == NULL) { | |||||
device_printf(dev, "Cannot find Virtual Interface Control Registers. Disabling Hyp-Mode...\n"); | |||||
hypmode_enabled[0] = -1; | |||||
} else { | |||||
sc->gic_h_bst = rman_get_bustag(sc->gic_res[VIRT_INTERFACE_CONTROL_RES_IDX]); | |||||
sc->gic_h_bsh = rman_get_bushandle(sc->gic_res[VIRT_INTERFACE_CONTROL_RES_IDX]); | |||||
} | |||||
} else { | |||||
hypmode_enabled[0] = -1; | |||||
} | |||||
/* Disable interrupt forwarding to the CPU interface */ | /* Disable interrupt forwarding to the CPU interface */ | ||||
gic_d_write_4(sc, GICD_CTLR, 0x00); | gic_d_write_4(sc, GICD_CTLR, 0x00); | ||||
/* Get the number of interrupts */ | /* Get the number of interrupts */ | ||||
sc->typer = gic_d_read_4(sc, GICD_TYPER); | sc->typer = gic_d_read_4(sc, GICD_TYPER); | ||||
nirqs = GICD_TYPER_I_NUM(sc->typer); | nirqs = GICD_TYPER_I_NUM(sc->typer); | ||||
if (arm_gic_register_isrcs(sc, nirqs)) { | if (arm_gic_register_isrcs(sc, nirqs)) { | ||||
▲ Show 20 Lines • Show All 162 Lines • ▼ Show 20 Lines | case GIC_IVAR_HW_REV: | ||||
return (0); | return (0); | ||||
case GIC_IVAR_BUS: | case GIC_IVAR_BUS: | ||||
KASSERT(sc->gic_bus != GIC_BUS_UNKNOWN, | KASSERT(sc->gic_bus != GIC_BUS_UNKNOWN, | ||||
("arm_gic_read_ivar: Unknown bus type")); | ("arm_gic_read_ivar: Unknown bus type")); | ||||
KASSERT(sc->gic_bus <= GIC_BUS_MAX, | KASSERT(sc->gic_bus <= GIC_BUS_MAX, | ||||
("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_VIRTUAL_INT_CTRL_RES: | |||||
*result = (uintptr_t)sc->gic_res[VIRT_INTERFACE_CONTROL_RES_IDX]; | |||||
return (0); | |||||
case GIC_IVAR_VIRTUAL_INT_CTRL_VADDR: | |||||
*result = (uintptr_t)rman_get_virtual(sc->gic_res[VIRT_INTERFACE_CONTROL_RES_IDX]); | |||||
return (0); | |||||
case GIC_IVAR_VIRTUAL_INT_CTRL_PADDR: | |||||
*result = (uintptr_t)rman_get_start(sc->gic_res[VIRT_INTERFACE_CONTROL_RES_IDX]); | |||||
return (0); | |||||
case GIC_IVAR_VIRTUAL_INT_CTRL_SIZE: | |||||
*result = rman_get_size(sc->gic_res[VIRT_INTERFACE_CONTROL_RES_IDX]); | |||||
return (0); | |||||
case GIC_IVAR_VIRTUAL_CPU_INT_PADDR: | |||||
*result = rman_get_start(sc->gic_res[VIRT_CPU_INTERFACE_RES_IDX]); | |||||
return (0); | |||||
case GIC_IVAR_VIRTUAL_CPU_INT_SIZE: | |||||
*result = rman_get_size(sc->gic_res[VIRT_CPU_INTERFACE_RES_IDX]); | |||||
return (0); | |||||
case GIC_IVAR_LR_NUM: | |||||
*result = (gic_h_read_4(gic_sc, GICH_VTR) & 0x3f) + 1; | |||||
return (0); | |||||
case GIC_IVAR_MAINTENANCE_INTR_RES: | |||||
if (sc->is_root) | |||||
*result = (uintptr_t)sc->gic_res[MAINTENANCE_INTR_RES_IDX]; | |||||
else | |||||
result = NULL; | |||||
return (0); | |||||
} | } | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
int | int | ||||
arm_gic_intr(void *arg) | arm_gic_intr(void *arg) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 456 Lines • ▼ Show 20 Lines | arm_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus, | ||||
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; | ||||
uint32_t val = 0, i; | uint32_t val = 0, i; | ||||
for (i = 0; i < MAXCPU; i++) | for (i = 0; i < MAXCPU; i++) | ||||
if (CPU_ISSET(i, &cpus)) | if (CPU_ISSET(i, &cpus)) | ||||
val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT; | val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT; | ||||
gic_d_write_4(sc, GICD_SGIR, val | gi->gi_irq); | gic_d_write_4(sc, GICD_SGIR(0), val | gi->gi_irq); | ||||
} | } | ||||
static int | static int | ||||
arm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp) | arm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp) | ||||
{ | { | ||||
struct intr_irqsrc *isrc; | struct intr_irqsrc *isrc; | ||||
struct arm_gic_softc *sc = device_get_softc(dev); | struct arm_gic_softc *sc = device_get_softc(dev); | ||||
▲ Show 20 Lines • Show All 266 Lines • Show Last 20 Lines |