|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [RFC PATCH 08/19] arm/gic: Keep track of GIC features
On Mon, Feb 2, 2026 at 6:14 PM Mykyta Poturai <Mykyta_Poturai@xxxxxxxx> wrote:
>
> 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;
gicv4.has_vlpis indicates vLPI/direct-injection support, not the GIC
architecture revision. A GICv4 implementation may have no vLPIs (only
pLPIs), so gic_is_gicv4() can return a false negative. If the intent
is to check the arch version, please use GICD_PIDR2/GICR_PIDR2.ArchRev
(e.g. ArchRev==4).
> +}
> +#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;
> - }
> - }
nit: if we call the v4 capability update here we can avoid the extra
RD iteration and most of the diff
#ifdef CONFIG_GICV4
gicv4_update_lpi_properties()
#endif
> -
> - 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",
nit: maybe better to print correct version of GIC
the same applies to other prints
> + 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,
nit: the function updates more than vLPI properties (it also sets
has_direct_lpi),
so maybe rename it to include “lpi” rather than “vlpi”.
> + void __iomem *ptr)
> +{
> + uint64_t typer;
> +
> + typer = readq_relaxed(ptr + GICR_TYPER);
> + gicv4.has_vlpis &= !!(typer & GICR_TYPER_VLPIS);
Might be worth documenting that we treat these RD capabilities as global:
if any Redistributor lacks a feature, we disable it system-wide.
> + gicv4.has_rvpeid &= !!(typer & GICR_TYPER_RVPEID);
> + /* RVPEID implies some form of DirectLPI. */
> + gicv4.has_direct_lpi &= (!!(typer & GICR_TYPER_DirectLPIS) ||
It was not clear to me from the comment above why we use RVPEID here:
> + !!(typer & GICR_TYPER_RVPEID));
Looking at Arm IHI 0069H.b, the invalidate/sync registers are mandatory not
only when GICR_TYPER.Direct* is set, but also when GICR_CTLR.IR == 1, and
also whenever GICv4.1 is implemented. See 12.11.20 *GICR_INVLPIR*,
“Accessing the GICR_INVLPIR”.
RVPEID is a GICv4.1-only field, and it does not directly describe the
presence of the DirectLPI/invalidate registers. My understanding from the
GICR_VPENDBASER layout is that the v4.1 encoding uses a vPEID field, while
the v4.0 encoding uses a VPT physical address. If that interpretation is
correct, then RVPEID would always be set when GICv4.1 is present, which
makes the current check somewhat redundant (and it would be good to explain
that in the comment).
For reference, the GIC-700 / GIC-700AE TRMs describe RVPEID as indicating
whether GICR_VPENDBASER records the index (vPEID) into the vPE configuration
table (i.e. whether GICv4.1 support is present).
Given the above, I think it would be better to also include GICR_CTLR.IR
here (as the Linux kernel does), and add a short comment explaining the use
of RVPEID.
---
nit: we can just use gicv4.has_rvpeid here
> + 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;
nit: 'gicv4.has_vlpis = false' is redundant here since the condition
already has '!gicv4.has_vlpis'
> + gicv4.has_rvpeid = false;
> + }
> +
> + printk("GICv4: CPU%d: %sVLPI support, %sdirect LPI support,
> %sValid+Dirty support, %sRVPEID support\n",
nit: Xen may run on GICv3 even with CONFIG_GICV4 code enabled; please
avoid hardcoding "GICv4"
> + 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)
> +
nit: GICD_TYPER2 and related bit definitions are not used anywhere in this
series.
Best regards,
Mykola
> #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 |