Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

irqchip/gic-v4.1: Disable vSGI upon (GIC CPUIF < v4.1) detection

GIC CPU interfaces versions predating GIC v4.1 were not built to
accommodate vINTID within the vSGI range; as reported in the GIC
specifications (8.2 "Changes to the CPU interface"), it is
CONSTRAINED UNPREDICTABLE to deliver a vSGI to a PE with
ID_AA64PFR0_EL1.GIC < b0011.

Check the GIC CPUIF version by reading the SYS_ID_AA64_PFR0_EL1.

Disable vSGIs if a CPUIF version < 4.1 is detected to prevent using
vSGIs on systems where they may misbehave.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20210317100719.3331-2-lorenzo.pieralisi@arm.com

authored by

Lorenzo Pieralisi and committed by
Marc Zyngier
46135d6f a6992bbe

+29 -4
+2 -2
arch/arm64/kvm/vgic/vgic-mmio-v3.c
··· 86 86 } 87 87 break; 88 88 case GICD_TYPER2: 89 - if (kvm_vgic_global_state.has_gicv4_1) 89 + if (kvm_vgic_global_state.has_gicv4_1 && gic_cpuif_has_vsgi()) 90 90 value = GICD_TYPER2_nASSGIcap; 91 91 break; 92 92 case GICD_IIDR: ··· 119 119 dist->enabled = val & GICD_CTLR_ENABLE_SS_G1; 120 120 121 121 /* Not a GICv4.1? No HW SGIs */ 122 - if (!kvm_vgic_global_state.has_gicv4_1) 122 + if (!kvm_vgic_global_state.has_gicv4_1 || !gic_cpuif_has_vsgi()) 123 123 val &= ~GICD_CTLR_nASSGIreq; 124 124 125 125 /* Dist stays enabled? nASSGIreq is RO */
+25 -2
drivers/irqchip/irq-gic-v4.c
··· 87 87 static const struct irq_domain_ops *vpe_domain_ops; 88 88 static const struct irq_domain_ops *sgi_domain_ops; 89 89 90 + #ifdef CONFIG_ARM64 91 + #include <asm/cpufeature.h> 92 + 93 + bool gic_cpuif_has_vsgi(void) 94 + { 95 + unsigned long fld, reg = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); 96 + 97 + fld = cpuid_feature_extract_unsigned_field(reg, ID_AA64PFR0_GIC_SHIFT); 98 + 99 + return fld >= 0x3; 100 + } 101 + #else 102 + bool gic_cpuif_has_vsgi(void) 103 + { 104 + return false; 105 + } 106 + #endif 107 + 90 108 static bool has_v4_1(void) 91 109 { 92 110 return !!sgi_domain_ops; 111 + } 112 + 113 + static bool has_v4_1_sgi(void) 114 + { 115 + return has_v4_1() && gic_cpuif_has_vsgi(); 93 116 } 94 117 95 118 static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx) ··· 120 97 char *name; 121 98 int sgi_base; 122 99 123 - if (!has_v4_1()) 100 + if (!has_v4_1_sgi()) 124 101 return 0; 125 102 126 103 name = kasprintf(GFP_KERNEL, "GICv4-sgi-%d", task_pid_nr(current)); ··· 205 182 { 206 183 int i; 207 184 208 - if (!has_v4_1()) 185 + if (!has_v4_1_sgi()) 209 186 return; 210 187 211 188 for (i = 0; i < vm->nr_vpes; i++) {
+2
include/linux/irqchip/arm-gic-v4.h
··· 145 145 const struct irq_domain_ops *vpe_ops, 146 146 const struct irq_domain_ops *sgi_ops); 147 147 148 + bool gic_cpuif_has_vsgi(void); 149 + 148 150 #endif