|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [RFC PATCH 08/19] arm/gic: Keep track of GIC features
Different versions of GICv4 may support different features. Record them
and provide functions to check for their availability.
Signed-off-by: Mykyta Poturai <mykyta_poturai@xxxxxxxx>
---
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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |