]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
irqchip/gic-v5: Populate struct gic_kvm_info
authorSascha Bischoff <Sascha.Bischoff@arm.com>
Fri, 27 Jun 2025 10:09:01 +0000 (10:09 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Tue, 8 Jul 2025 21:41:06 +0000 (14:41 -0700)
Populate the gic_kvm_info struct based on support for
FEAT_GCIE_LEGACY.  The struct is used by KVM to probe for a compatible
GIC.

Co-authored-by: Timothy Hayes <timothy.hayes@arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes@arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
Reviewed-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
Link: https://lore.kernel.org/r/20250627100847.1022515-3-sascha.bischoff@arm.com
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
drivers/irqchip/irq-gic-v5.c
include/linux/irqchip/arm-vgic-info.h

index 0e4789818131d9f4cf14025d2df97dcb6d946b0b..4bd224f359a78da165b9adca2b79df47674ed36b 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/irqchip.h>
 #include <linux/irqchip/arm-gic-v5.h>
+#include <linux/irqchip/arm-vgic-info.h>
 
 #include <asm/cpufeature.h>
 #include <asm/exception.h>
@@ -1058,6 +1059,36 @@ static void gicv5_set_cpuif_idbits(void)
        }
 }
 
+#ifdef CONFIG_KVM
+static struct gic_kvm_info gic_v5_kvm_info __initdata;
+
+static bool __init gicv5_cpuif_has_gcie_legacy(void)
+{
+       u64 idr0 = read_sysreg_s(SYS_ICC_IDR0_EL1);
+       return !!FIELD_GET(ICC_IDR0_EL1_GCIE_LEGACY, idr0);
+}
+
+static void __init gic_of_setup_kvm_info(struct device_node *node)
+{
+       gic_v5_kvm_info.type = GIC_V5;
+       gic_v5_kvm_info.has_gcie_v3_compat = gicv5_cpuif_has_gcie_legacy();
+
+       /* GIC Virtual CPU interface maintenance interrupt */
+       gic_v5_kvm_info.no_maint_irq_mask = false;
+       gic_v5_kvm_info.maint_irq = irq_of_parse_and_map(node, 0);
+       if (!gic_v5_kvm_info.maint_irq) {
+               pr_warn("cannot find GICv5 virtual CPU interface maintenance interrupt\n");
+               return;
+       }
+
+       vgic_set_kvm_info(&gic_v5_kvm_info);
+}
+#else
+static inline void __init gic_of_setup_kvm_info(struct device_node *node)
+{
+}
+#endif // CONFIG_KVM
+
 static int __init gicv5_of_init(struct device_node *node, struct device_node *parent)
 {
        int ret = gicv5_irs_of_probe(node);
@@ -1090,6 +1121,8 @@ static int __init gicv5_of_init(struct device_node *node, struct device_node *pa
 
        gicv5_irs_its_probe();
 
+       gic_of_setup_kvm_info(node);
+
        return 0;
 
 out_int:
index a75b2c7de69d09262946ab4aade39b46c5be6098..ca1713fac6e3bcee29a2dba4fa5c20636e287321 100644 (file)
@@ -15,6 +15,8 @@ enum gic_type {
        GIC_V2,
        /* Full GICv3, optionally with v2 compat */
        GIC_V3,
+       /* Full GICv5, optionally with v3 compat */
+       GIC_V5,
 };
 
 struct gic_kvm_info {
@@ -34,6 +36,8 @@ struct gic_kvm_info {
        bool            has_v4_1;
        /* Deactivation impared, subpar stuff */
        bool            no_hw_deactivation;
+       /* v3 compat support (GICv5 hosts, only) */
+       bool            has_gcie_v3_compat;
 };
 
 #ifdef CONFIG_KVM