Index: sys/arm/arm/gic.h =================================================================== --- sys/arm/arm/gic.h +++ sys/arm/arm/gic.h @@ -59,11 +59,13 @@ void * gic_intrhand; struct gic_irqsrc * gic_irqs; #endif - struct resource * gic_res[3]; + struct resource * gic_res[6]; bus_space_tag_t gic_c_bst; bus_space_tag_t gic_d_bst; bus_space_handle_t gic_c_bsh; bus_space_handle_t gic_d_bsh; + bus_space_tag_t gic_h_bst; + bus_space_handle_t gic_h_bsh; uint8_t ver; struct mtx mutex; uint32_t nirqs; Index: sys/arm/arm/gic.c =================================================================== --- sys/arm/arm/gic.c +++ sys/arm/arm/gic.c @@ -139,12 +139,16 @@ static struct resource_spec arm_gic_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */ { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */ + { 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 */ #ifdef INTRNG - { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, /* Parent interrupt */ + { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, /* Parent interrupt */ #endif { -1, 0 } }; +extern char hypmode_enabled[]; #if defined(__arm__) && defined(INVARIANTS) static int gic_debug_spurious = 1; @@ -168,6 +172,22 @@ #define gic_d_write_4(_sc, _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; +} + #ifndef INTRNG static int gic_config_irq(int irq, enum intr_trigger trig, enum intr_polarity pol); @@ -443,12 +463,23 @@ mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN); /* Distributor Interface */ - sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]); - sc->gic_d_bsh = rman_get_bushandle(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[DISTRIBUTOR_RES_IDX]); /* CPU Interface */ - sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]); - sc->gic_c_bsh = rman_get_bushandle(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[CPU_INTERFACE_RES_IDX]); + + /* Virtual Interface Control */ + 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]); + } + /* Disable interrupt forwarding to the CPU interface */ gic_d_write_4(sc, GICD_CTLR, 0x00); @@ -644,6 +675,29 @@ ("arm_gic_read_ivar: Invalid bus type %u", sc->gic_bus)); *result = sc->gic_bus; 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 = (unsigned int)rman_get_virtual(sc->gic_res[VIRT_INTERFACE_CONTROL_RES_IDX]); + return (0); + case GIC_IVAR_VIRTUAL_INT_CTRL_PADDR: + *result = (unsigned int)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]); + 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: + *result = (uintptr_t)sc->gic_res[MAINTENANCE_INTR_RES_IDX]; + return (0); } return (ENOENT); @@ -1105,7 +1159,7 @@ if (CPU_ISSET(i, &cpus)) 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 Index: sys/arm/arm/gic_common.h =================================================================== --- sys/arm/arm/gic_common.h +++ sys/arm/arm/gic_common.h @@ -32,8 +32,25 @@ #ifndef _GIC_COMMON_H_ #define _GIC_COMMON_H_ -#define GIC_IVAR_HW_REV 500 -#define GIC_IVAR_BUS 501 +#ifndef __ASSEMBLER__ + +#define DISTRIBUTOR_RES_IDX 0 +#define CPU_INTERFACE_RES_IDX 1 +#define VIRT_INTERFACE_CONTROL_RES_IDX 2 +#define VIRT_CPU_INTERFACE_RES_IDX 3 +#define MAINTENANCE_INTR_RES_IDX 4 +#define INTRNG_RES_IDX 5 + +#define GIC_IVAR_HW_REV 500 +#define GIC_IVAR_BUS 501 +#define GIC_IVAR_VIRTUAL_INT_CTRL_RES 502 +#define GIC_IVAR_VIRTUAL_INT_CTRL_VADDR 503 +#define GIC_IVAR_VIRTUAL_INT_CTRL_PADDR 505 +#define GIC_IVAR_VIRTUAL_INT_CTRL_SIZE 504 +#define GIC_IVAR_VIRTUAL_CPU_INT_PADDR 506 +#define GIC_IVAR_VIRTUAL_CPU_INT_SIZE 507 +#define GIC_IVAR_LR_NUM 508 +#define GIC_IVAR_MAINTENANCE_INTR_RES 509 /* GIC_IVAR_BUS values */ #define GIC_BUS_UNKNOWN 0 @@ -43,6 +60,19 @@ __BUS_ACCESSOR(gic, hw_rev, GIC, HW_REV, u_int); __BUS_ACCESSOR(gic, bus, GIC, BUS, u_int); +__BUS_ACCESSOR(gic, virtual_int_ctrl_res, GIC, VIRTUAL_INT_CTRL_RES, struct resource *); +__BUS_ACCESSOR(gic, virtual_int_ctrl_vaddr, GIC, VIRTUAL_INT_CTRL_VADDR, uint64_t); +__BUS_ACCESSOR(gic, virtual_int_ctrl_paddr, GIC, VIRTUAL_INT_CTRL_PADDR, uint64_t); +__BUS_ACCESSOR(gic, virtual_int_ctrl_size, GIC, VIRTUAL_INT_CTRL_SIZE, uint32_t); +__BUS_ACCESSOR(gic, virtual_cpu_int_paddr, GIC, VIRTUAL_CPU_INT_PADDR, uint32_t); +__BUS_ACCESSOR(gic, virtual_cpu_int_size, GIC, VIRTUAL_CPU_INT_SIZE, uint32_t); +__BUS_ACCESSOR(gic, lr_num, GIC, LR_NUM, uint32_t); +__BUS_ACCESSOR(gic, maintenance_intr_res, GIC, MAINTENANCE_INTR_RES, struct resource *); + +struct arm_gic_softc *arm_gic_get_sc(void); +uint32_t arm_gic_get_lr_num(void); + +#endif /*__ASSEMBLER__ */ /* Common register values */ #define GICD_CTLR 0x0000 /* v1 ICDDCR */ @@ -73,6 +103,7 @@ #define GICD_ICENABLER(n) (0x0180 + (((n) >> 5) * 4)) /* v1 ICDICER */ #define GICD_ISPENDR(n) (0x0200 + (((n) >> 5) * 4)) /* v1 ICDISPR */ #define GICD_ICPENDR(n) (0x0280 + (((n) >> 5) * 4)) /* v1 ICDICPR */ +#define GICD_ISACTIVER(n) (0x0300 + (((n) >> 5) * 4)) /* v1 ICDABR */ #define GICD_ICACTIVER(n) (0x0380 + (((n) >> 5) * 4)) /* v1 ICDABR */ #define GICD_IPRIORITYR(n) (0x0400 + (((n) >> 2) * 4)) /* v1 ICDIPR */ #define GICD_I_PER_IPRIORITYn 4 @@ -87,7 +118,33 @@ #define GICD_ICFGR_TRIG_LVL (0 << 1) #define GICD_ICFGR_TRIG_EDGE (1 << 1) #define GICD_ICFGR_TRIG_MASK 0x2 -#define GICD_SGIR 0x0F00 /* v1 ICDSGIR */ +#define GICD_SGIR(n) (0x0F00 + ((n) * 4)) /* v1 ICDSGIR */ #define GICD_SGI_TARGET_SHIFT 16 +/* GIC Hypervisor specific registers */ +#define GICH_HCR 0x0 +#define GICH_VTR 0x4 +#define GICH_VMCR 0x8 +#define GICH_MISR 0x10 +#define GICH_EISR0 0x20 +#define GICH_EISR1 0x24 +#define GICH_ELSR0 0x30 +#define GICH_ELSR1 0x34 +#define GICH_APR 0xF0 +#define GICH_LR0 0x100 + +#define GICH_HCR_EN (1 << 0) +#define GICH_HCR_UIE (1 << 1) + +#define GICH_LR_VIRTID (0x3FF << 0) +#define GICH_LR_PHYSID_CPUID_SHIFT 10 +#define GICH_LR_PHYSID_CPUID (7 << GICH_LR_PHYSID_CPUID_SHIFT) +#define GICH_LR_STATE (3 << 28) +#define GICH_LR_PENDING (1 << 28) +#define GICH_LR_ACTIVE (1 << 29) +#define GICH_LR_EOI (1 << 19) + +#define GICH_MISR_EOI (1 << 0) +#define GICH_MISR_U (1 << 1) + #endif /* _GIC_COMMON_H_ */ Index: sys/arm/arm/gic_fdt.c =================================================================== --- sys/arm/arm/gic_fdt.c +++ sys/arm/arm/gic_fdt.c @@ -175,13 +175,13 @@ goto cleanup; } } else { - if (sc->base.gic_res[2] == NULL) { + if (sc->base.gic_res[INTRNG_RES_IDX] == NULL) { device_printf(dev, "not root PIC must have defined interrupt\n"); intr_pic_deregister(dev, xref); goto cleanup; } - if (bus_setup_intr(dev, sc->base.gic_res[2], INTR_TYPE_CLK, + if (bus_setup_intr(dev, sc->base.gic_res[INTRNG_RES_IDX], INTR_TYPE_CLK, arm_gic_intr, NULL, sc, &sc->base.gic_intrhand)) { device_printf(dev, "could not setup irq handler\n"); intr_pic_deregister(dev, xref); @@ -214,9 +214,8 @@ struct arm_gic_devinfo *di; di = device_get_ivars(child); - KASSERT(di != NULL, ("gic_fdt_get_resource_list: No devinfo")); - return (&di->rl); + return di ? (&di->rl) : (NULL); } static int