Index: sys/arm/arm/gic.h =================================================================== --- sys/arm/arm/gic.h +++ sys/arm/arm/gic.h @@ -55,15 +55,18 @@ struct arm_gic_softc { device_t gic_dev; + bool is_root; #ifdef INTRNG 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,13 @@ 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 */ -#ifdef INTRNG - { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, /* Parent interrupt */ -#endif + { 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 } }; +extern char hypmode_enabled[]; #if defined(__arm__) && defined(INVARIANTS) static int gic_debug_spurious = 1; @@ -168,6 +169,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 +460,25 @@ 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->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 */ gic_d_write_4(sc, GICD_CTLR, 0x00); @@ -644,6 +674,32 @@ ("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: + if (sc->is_root) + *result = (uintptr_t)sc->gic_res[MAINTENANCE_INTR_RES_IDX]; + else + result = NULL; + return (0); } return (ENOENT); @@ -1105,7 +1161,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 @@ -136,12 +136,21 @@ { #ifdef INTRNG struct arm_gic_fdt_softc *sc = device_get_softc(dev); - phandle_t pxref; - intptr_t xref; + intptr_t xref = OF_xref_from_node(ofw_bus_get_node(dev)); + phandle_t pxref = ofw_bus_find_iparent(ofw_bus_get_node(dev)); #endif int err; + sc->base.is_root = false; #ifdef INTRNG + /* + * Controller is root if: + * - doesn't have interrupt parent + * - his interrupt parent is this controller + */ + if (pxref == 0 || xref == pxref) + sc->base.is_root = true; + sc->base.gic_bus = GIC_BUS_FDT; #endif @@ -150,8 +159,6 @@ return (err); #ifdef INTRNG - xref = OF_xref_from_node(ofw_bus_get_node(dev)); - /* * Now, when everything is initialized, it's right time to * register interrupt controller to interrupt framefork. @@ -161,13 +168,7 @@ goto cleanup; } - /* - * Controller is root if: - * - doesn't have interrupt parent - * - his interrupt parent is this controller - */ - pxref = ofw_bus_find_iparent(ofw_bus_get_node(dev)); - if (pxref == 0 || xref == pxref) { + if (sc->base.is_root) { if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc, GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) { device_printf(dev, "could not set PIC as a root\n"); @@ -175,13 +176,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 +215,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