Different versions of GICv4 may support different features. Record them and provide functions to check for their availability.
Signed-off-by: Mykyta Poturai <[email protected]> --- xen/arch/arm/gic-v3.c | 175 ++++++++++++++++++++----- xen/arch/arm/include/asm/gic.h | 2 + xen/arch/arm/include/asm/gic_v3_defs.h | 9 ++ xen/arch/arm/include/asm/vgic.h | 9 ++ 4 files changed, 162 insertions(+), 33 deletions(-) diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 9b8b87078b..14852d18c2 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -100,6 +100,38 @@ static struct { static struct gic_info gicv3_info; +#ifdef CONFIG_GICV4 +/* Global state */ +static struct { + bool has_vlpis; + bool has_direct_lpi; + bool has_vpend_valid_dirty; + bool has_rvpeid; +} gicv4 = { .has_vlpis = true, .has_direct_lpi = true, + .has_vpend_valid_dirty = true, .has_rvpeid = true, }; + + +bool gic_support_directLPI(void) +{ + return gicv4.has_direct_lpi; +} + +bool gic_support_vptValidDirty(void) +{ + return gicv4.has_vpend_valid_dirty; +} + +bool gic_has_v4_1_extension(void) +{ + return gicv4.has_rvpeid; +} + +bool gic_is_gicv4(void) +{ + return gicv4.has_vlpis; +} +#endif + /* per-cpu re-distributor base */ static DEFINE_PER_CPU(void __iomem*, rbase); @@ -914,7 +946,8 @@ static bool gicv3_enable_lpis(void) return true; } -static int __init gicv3_populate_rdist(void) +static int __init gic_iterate_rdists(int (*fn)(struct rdist_region *, + void __iomem *)) { int i; uint32_t aff; @@ -958,40 +991,16 @@ static int __init gicv3_populate_rdist(void) if ( (typer >> 32) == aff ) { + int ret; + this_cpu(rbase) = ptr; - if ( typer & GICR_TYPER_PLPIS ) - { - paddr_t rdist_addr; - unsigned int procnum; - int ret; - - /* - * The ITS refers to redistributors either by their physical - * address or by their ID. Which one to use is an ITS - * choice. So determine those two values here (which we - * can do only here in GICv3 code) and tell the - * ITS code about it, so it can use them later to be able - * to address those redistributors accordingly. - */ - rdist_addr = gicv3.rdist_regions[i].base; - rdist_addr += ptr - gicv3.rdist_regions[i].map_base; - procnum = (typer & GICR_TYPER_PROC_NUM_MASK); - procnum >>= GICR_TYPER_PROC_NUM_SHIFT; - - gicv3_set_redist_address(rdist_addr, procnum); - - ret = gicv3_lpi_init_rdist(ptr); - if ( ret && ret != -ENODEV ) - { - printk("GICv3: CPU%d: Cannot initialize LPIs: %u\n", - smp_processor_id(), ret); - break; - } - } - - printk("GICv3: CPU%d: Found redistributor in region %d @%p\n", - smp_processor_id(), i, ptr); + ret = fn(gicv3.rdist_regions + i, ptr); + if ( ret ) + return ret; + + printk("GICv3: CPU%d: Found redistributor @%p\n", + smp_processor_id(), ptr); return 0; } @@ -1010,11 +1019,107 @@ static int __init gicv3_populate_rdist(void) } while ( !(typer & GICR_TYPER_LAST) ); } + return -ENODEV; +} + +static int __init __gicv3_populate_rdist(struct rdist_region *region, + void __iomem *ptr) +{ + uint64_t typer; + + typer = readq_relaxed(ptr + GICR_TYPER); + if ( typer & GICR_TYPER_PLPIS ) + { + paddr_t rdist_addr; + unsigned int procnum; + int ret; + + /* + * The ITS refers to redistributors either by their physical + * address or by their ID. Which one to use is an ITS + * choice. So determine those two values here (which we + * can do only here in GICv3 code) and tell the + * ITS code about it, so it can use them later to be able + * to address those redistributors accordingly. + */ + rdist_addr = region->base; + rdist_addr += ptr - region->map_base; + procnum = (typer & GICR_TYPER_PROC_NUM_MASK); + procnum >>= GICR_TYPER_PROC_NUM_SHIFT; + + gicv3_set_redist_address(rdist_addr, procnum); + + ret = gicv3_lpi_init_rdist(ptr); + if ( ret && ret != -ENODEV ) + { + printk("GICv3: CPU%d: Cannot initialize LPIs: %d\n", + smp_processor_id(), ret); + printk("%s %d\n", __func__, __LINE__); + return ret; + } + } + + return 0; +} + +static int __init gicv3_populate_rdist(void) +{ + int ret = gic_iterate_rdists(__gicv3_populate_rdist); + if ( ret == 0) + return 0; + dprintk(XENLOG_ERR, "GICv3: CPU%d: mpidr 0x%"PRIregister" has no re-distributor!\n", smp_processor_id(), cpu_logical_map(smp_processor_id())); + return -ENODEV; +} + +#ifdef CONFIG_GICV4 +static int __init __gicv4_update_vlpi_properties(struct rdist_region *region, + void __iomem *ptr) +{ + uint64_t typer; + + typer = readq_relaxed(ptr + GICR_TYPER); + gicv4.has_vlpis &= !!(typer & GICR_TYPER_VLPIS); + gicv4.has_rvpeid &= !!(typer & GICR_TYPER_RVPEID); + /* RVPEID implies some form of DirectLPI. */ + gicv4.has_direct_lpi &= (!!(typer & GICR_TYPER_DirectLPIS) || + !!(typer & GICR_TYPER_RVPEID)); + gicv4.has_vpend_valid_dirty &= !!(typer & GICR_TYPER_DIRTY); + + /* Detect non-sensical configurations */ + if ( gicv4.has_rvpeid && !gicv4.has_vlpis ) + { + gicv4.has_direct_lpi = false; + gicv4.has_vlpis = false; + gicv4.has_rvpeid = false; + } + + printk("GICv4: CPU%d: %sVLPI support, %sdirect LPI support, %sValid+Dirty support, %sRVPEID support\n", + smp_processor_id(), !!(typer & GICR_TYPER_VLPIS) ? "" : "no ", + (!!(typer & GICR_TYPER_DirectLPIS) || + !!(typer & GICR_TYPER_RVPEID)) ? "" : "no ", + !!(typer & GICR_TYPER_DIRTY) ? "" : "no ", + !!(typer & GICR_TYPER_RVPEID) ? "" : "no "); + + return 0; +} + +static int __init gicv4_update_vlpi_properties(void) +{ + int ret = gic_iterate_rdists(__gicv4_update_vlpi_properties); + + if ( ret == 0 ) + return 0; return -ENODEV; } +#else +static int __init gicv4_update_vlpi_properties(void) +{ + return 0; +} +#endif static int gicv3_cpu_init(void) { @@ -1024,6 +1129,10 @@ static int gicv3_cpu_init(void) if ( gicv3_populate_rdist() ) return -ENODEV; + ret = gicv4_update_vlpi_properties(); + if ( ret ) + return ret; + if ( gicv3_enable_redist() ) return -ENODEV; diff --git a/xen/arch/arm/include/asm/gic.h b/xen/arch/arm/include/asm/gic.h index 8e713aa477..afb1cc3751 100644 --- a/xen/arch/arm/include/asm/gic.h +++ b/xen/arch/arm/include/asm/gic.h @@ -235,6 +235,8 @@ enum gic_version { GIC_INVALID = 0, /* the default until explicitly set up */ GIC_V2, GIC_V3, + GIC_V4, + GIC_V4_1, }; DECLARE_PER_CPU(uint64_t, lr_mask); diff --git a/xen/arch/arm/include/asm/gic_v3_defs.h b/xen/arch/arm/include/asm/gic_v3_defs.h index c373b94d19..3a7d18ef59 100644 --- a/xen/arch/arm/include/asm/gic_v3_defs.h +++ b/xen/arch/arm/include/asm/gic_v3_defs.h @@ -93,6 +93,12 @@ #define GICD_TYPE_LPIS (1U << 17) +#define GICD_TYPER2 0x000c + +#define GICD_TYPER2_VIL (1U << 7) +#define GICD_TYPER2_VID GENMASK(4, 0) +#define GICD_TYPER2_nASSGIcap (1U << 8) + #define GICD_CTLR_RWP (1UL << 31) #define GICD_CTLR_ARE_NS (1U << 4) #define GICD_CTLR_ENABLE_G1A (1U << 1) @@ -149,7 +155,10 @@ #define GICR_TYPER_PLPIS (1U << 0) #define GICR_TYPER_VLPIS (1U << 1) +#define GICR_TYPER_DIRTY (1U << 2) +#define GICR_TYPER_DirectLPIS (1U << 3) #define GICR_TYPER_LAST (1U << 4) +#define GICR_TYPER_RVPEID (1U << 7) #define GICR_TYPER_PROC_NUM_SHIFT 8 #define GICR_TYPER_PROC_NUM_MASK (0xffff << GICR_TYPER_PROC_NUM_SHIFT) diff --git a/xen/arch/arm/include/asm/vgic.h b/xen/arch/arm/include/asm/vgic.h index 360f8a968e..f12d736808 100644 --- a/xen/arch/arm/include/asm/vgic.h +++ b/xen/arch/arm/include/asm/vgic.h @@ -405,6 +405,15 @@ extern bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int ir extern void vgic_check_inflight_irqs_pending(struct vcpu *v, unsigned int rank, uint32_t r); +/* GICV4 functions */ +#ifdef CONFIG_GICV4 +bool gic_support_vptValidDirty(void); +bool gic_is_gicv4(void); +#else +#define gic_support_vptValidDirty() (false) +#define gic_is_gicv4() (false) +#endif + #endif /* !CONFIG_NEW_VGIC */ /*** Common VGIC functions used by Xen arch code ****/ -- 2.51.2
