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 @@ -79,15 +79,15 @@ /* Distributor Registers */ /* CPU Registers */ -#define GICC_CTLR 0x0000 /* v1 ICCICR */ -#define GICC_PMR 0x0004 /* v1 ICCPMR */ -#define GICC_BPR 0x0008 /* v1 ICCBPR */ -#define GICC_IAR 0x000C /* v1 ICCIAR */ -#define GICC_EOIR 0x0010 /* v1 ICCEOIR */ -#define GICC_RPR 0x0014 /* v1 ICCRPR */ -#define GICC_HPPIR 0x0018 /* v1 ICCHPIR */ -#define GICC_ABPR 0x001C /* v1 ICCABPR */ -#define GICC_IIDR 0x00FC /* v1 ICCIIDR*/ +#define GICC_CTLR 0x0000 /* v1 ICCICR */ +#define GICC_PMR 0x0004 /* v1 ICCPMR */ +#define GICC_BPR 0x0008 /* v1 ICCBPR */ +#define GICC_IAR 0x000C /* v1 ICCIAR */ +#define GICC_EOIR 0x0010 /* v1 ICCEOIR */ +#define GICC_RPR 0x0014 /* v1 ICCRPR */ +#define GICC_HPPIR 0x0018 /* v1 ICCHPIR */ +#define GICC_ABPR 0x001C /* v1 ICCABPR */ +#define GICC_IIDR 0x00FC /* v1 ICCIIDR*/ /* TYPER Registers */ #define GICD_TYPER_SECURITYEXT 0x400 @@ -105,10 +105,10 @@ uint32_t gi_irq; enum intr_polarity gi_pol; enum intr_trigger gi_trig; -#define GI_FLAG_EARLY_EOI (1 << 0) -#define GI_FLAG_MSI (1 << 1) /* This interrupt source should only */ +#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 */ +#define GI_FLAG_MSI_USED (1 << 2) /* This irq is already allocated */ /* for a MSI/MSI-X interrupt */ u_int gi_flags; }; @@ -121,7 +121,7 @@ static u_int sgi_first_unused = GIC_FIRST_SGI; #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) #else /* !INTRNG */ static struct ofw_compat_data compat_data[] = { {"arm,gic", true}, /* Non-standard, used in FreeBSD dts. */ @@ -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,22 @@ 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 +674,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 = (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]); + 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 +1158,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 @@ -1373,8 +1426,8 @@ */ #define GICV2M_MSI_TYPER 0x008 -#define MSI_TYPER_SPI_BASE(x) (((x) >> 16) & 0x3ff) -#define MSI_TYPER_SPI_COUNT(x) (((x) >> 0) & 0x3ff) +#define MSI_TYPER_SPI_BASE(x) (((x) >> 16) & 0x3ff) +#define MSI_TYPER_SPI_COUNT(x) (((x) >> 0) & 0x3ff) #define GICv2M_MSI_SETSPI_NS 0x040 #define GICV2M_MSI_IIDR 0xFCC 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,51 +60,91 @@ __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 */ #define GICD_TYPER 0x0004 /* v1 ICDICTR */ -#define GICD_TYPER_I_NUM(n) ((((n) & 0x1F) + 1) * 32) +#define GICD_TYPER_I_NUM(n) ((((n) & 0x1F) + 1) * 32) #define GICD_IIDR 0x0008 /* v1 ICDIIDR */ -#define GICD_IIDR_PROD_SHIFT 24 -#define GICD_IIDR_PROD_MASK 0xff000000 -#define GICD_IIDR_PROD(x) \ +#define GICD_IIDR_PROD_SHIFT 24 +#define GICD_IIDR_PROD_MASK 0xff000000 +#define GICD_IIDR_PROD(x) \ (((x) & GICD_IIDR_PROD_MASK) >> GICD_IIDR_PROD_SHIFT) -#define GICD_IIDR_VAR_SHIFT 16 -#define GICD_IIDR_VAR_MASK 0x000f0000 -#define GICD_IIDR_VAR(x) \ +#define GICD_IIDR_VAR_SHIFT 16 +#define GICD_IIDR_VAR_MASK 0x000f0000 +#define GICD_IIDR_VAR(x) \ (((x) & GICD_IIDR_VAR_MASK) >> GICD_IIDR_VAR_SHIFT) -#define GICD_IIDR_REV_SHIFT 12 -#define GICD_IIDR_REV_MASK 0x0000f000 -#define GICD_IIDR_REV(x) \ +#define GICD_IIDR_REV_SHIFT 12 +#define GICD_IIDR_REV_MASK 0x0000f000 +#define GICD_IIDR_REV(x) \ (((x) & GICD_IIDR_REV_MASK) >> GICD_IIDR_REV_SHIFT) -#define GICD_IIDR_IMPL_SHIFT 0 -#define GICD_IIDR_IMPL_MASK 0x00000fff -#define GICD_IIDR_IMPL(x) \ +#define GICD_IIDR_IMPL_SHIFT 0 +#define GICD_IIDR_IMPL_MASK 0x00000fff +#define GICD_IIDR_IMPL(x) \ (((x) & GICD_IIDR_IMPL_MASK) >> GICD_IIDR_IMPL_SHIFT) #define GICD_IGROUPR(n) (0x0080 + (((n) >> 5) * 4)) /* v1 ICDISER */ -#define GICD_I_PER_IGROUPRn 32 +#define GICD_I_PER_IGROUPRn 32 #define GICD_ISENABLER(n) (0x0100 + (((n) >> 5) * 4)) /* v1 ICDISER */ -#define GICD_I_MASK(n) (1ul << ((n) & 0x1f)) -#define GICD_I_PER_ISENABLERn 32 +#define GICD_I_MASK(n) (1ul << ((n) & 0x1f)) +#define GICD_I_PER_ISENABLERn 32 #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 +#define GICD_I_PER_IPRIORITYn 4 #define GICD_ITARGETSR(n) (0x0800 + (((n) >> 2) * 4)) /* v1 ICDIPTR */ #define GICD_ICFGR(n) (0x0C00 + (((n) >> 4) * 4)) /* v1 ICDICFR */ -#define GICD_I_PER_ICFGRn 16 +#define GICD_I_PER_ICFGRn 16 /* First bit is a polarity bit (0 - low, 1 - high) */ -#define GICD_ICFGR_POL_LOW (0 << 0) -#define GICD_ICFGR_POL_HIGH (1 << 0) -#define GICD_ICFGR_POL_MASK 0x1 +#define GICD_ICFGR_POL_LOW (0 << 0) +#define GICD_ICFGR_POL_HIGH (1 << 0) +#define GICD_ICFGR_POL_MASK 0x1 /* Second bit is a trigger bit (0 - level, 1 - edge) */ -#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_SGI_TARGET_SHIFT 16 +#define GICD_ICFGR_TRIG_LVL (0 << 1) +#define GICD_ICFGR_TRIG_EDGE (1 << 1) +#define GICD_ICFGR_TRIG_MASK 0x2 +#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