Commit 46135d6f authored by Lorenzo Pieralisi's avatar Lorenzo Pieralisi Committed by Marc Zyngier

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: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20210317100719.3331-2-lorenzo.pieralisi@arm.com
parent a6992bbe
...@@ -86,7 +86,7 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu, ...@@ -86,7 +86,7 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
} }
break; break;
case GICD_TYPER2: case GICD_TYPER2:
if (kvm_vgic_global_state.has_gicv4_1) if (kvm_vgic_global_state.has_gicv4_1 && gic_cpuif_has_vsgi())
value = GICD_TYPER2_nASSGIcap; value = GICD_TYPER2_nASSGIcap;
break; break;
case GICD_IIDR: case GICD_IIDR:
...@@ -119,7 +119,7 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu, ...@@ -119,7 +119,7 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
dist->enabled = val & GICD_CTLR_ENABLE_SS_G1; dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
/* Not a GICv4.1? No HW SGIs */ /* Not a GICv4.1? No HW SGIs */
if (!kvm_vgic_global_state.has_gicv4_1) if (!kvm_vgic_global_state.has_gicv4_1 || !gic_cpuif_has_vsgi())
val &= ~GICD_CTLR_nASSGIreq; val &= ~GICD_CTLR_nASSGIreq;
/* Dist stays enabled? nASSGIreq is RO */ /* Dist stays enabled? nASSGIreq is RO */
......
...@@ -87,17 +87,40 @@ static struct irq_domain *gic_domain; ...@@ -87,17 +87,40 @@ static struct irq_domain *gic_domain;
static const struct irq_domain_ops *vpe_domain_ops; static const struct irq_domain_ops *vpe_domain_ops;
static const struct irq_domain_ops *sgi_domain_ops; static const struct irq_domain_ops *sgi_domain_ops;
#ifdef CONFIG_ARM64
#include <asm/cpufeature.h>
bool gic_cpuif_has_vsgi(void)
{
unsigned long fld, reg = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
fld = cpuid_feature_extract_unsigned_field(reg, ID_AA64PFR0_GIC_SHIFT);
return fld >= 0x3;
}
#else
bool gic_cpuif_has_vsgi(void)
{
return false;
}
#endif
static bool has_v4_1(void) static bool has_v4_1(void)
{ {
return !!sgi_domain_ops; return !!sgi_domain_ops;
} }
static bool has_v4_1_sgi(void)
{
return has_v4_1() && gic_cpuif_has_vsgi();
}
static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx) static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx)
{ {
char *name; char *name;
int sgi_base; int sgi_base;
if (!has_v4_1()) if (!has_v4_1_sgi())
return 0; return 0;
name = kasprintf(GFP_KERNEL, "GICv4-sgi-%d", task_pid_nr(current)); name = kasprintf(GFP_KERNEL, "GICv4-sgi-%d", task_pid_nr(current));
...@@ -182,7 +205,7 @@ static void its_free_sgi_irqs(struct its_vm *vm) ...@@ -182,7 +205,7 @@ static void its_free_sgi_irqs(struct its_vm *vm)
{ {
int i; int i;
if (!has_v4_1()) if (!has_v4_1_sgi())
return; return;
for (i = 0; i < vm->nr_vpes; i++) { for (i = 0; i < vm->nr_vpes; i++) {
......
...@@ -145,4 +145,6 @@ int its_init_v4(struct irq_domain *domain, ...@@ -145,4 +145,6 @@ int its_init_v4(struct irq_domain *domain,
const struct irq_domain_ops *vpe_ops, const struct irq_domain_ops *vpe_ops,
const struct irq_domain_ops *sgi_ops); const struct irq_domain_ops *sgi_ops);
bool gic_cpuif_has_vsgi(void);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment