Initialise the private interrupts (PPIs, only) for GICv5. This means that a GICv5-style intid is generated (which encodes the PPI type in the top bits) instead of the 0-based index that is used for older GICs. Additionally, set all of the GICv5 PPIs to use Level for the handling mode, with the exception of the SW_PPI which uses Edge. This matches the architecturally-defined set in the GICv5 specification (the CTIIRQ handling mode is IMPDEF, so Level has been picked for that). Signed-off-by: Sascha Bischoff Reviewed-by: Jonathan Cameron --- arch/arm64/kvm/vgic/vgic-init.c | 39 +++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index 653364299154e..973bbbe56062c 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -263,13 +263,19 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type) { struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; int i; + u32 num_private_irqs; lockdep_assert_held(&vcpu->kvm->arch.config_lock); + if (vgic_is_v5(vcpu->kvm)) + num_private_irqs = VGIC_V5_NR_PRIVATE_IRQS; + else + num_private_irqs = VGIC_NR_PRIVATE_IRQS; + if (vgic_cpu->private_irqs) return 0; - vgic_cpu->private_irqs = kcalloc(VGIC_NR_PRIVATE_IRQS, + vgic_cpu->private_irqs = kcalloc(num_private_irqs, sizeof(struct vgic_irq), GFP_KERNEL_ACCOUNT); @@ -280,22 +286,37 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type) * Enable and configure all SGIs to be edge-triggered and * configure all PPIs as level-triggered. */ - for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) { + for (i = 0; i < num_private_irqs; i++) { struct vgic_irq *irq = &vgic_cpu->private_irqs[i]; INIT_LIST_HEAD(&irq->ap_list); raw_spin_lock_init(&irq->irq_lock); - irq->intid = i; irq->vcpu = NULL; irq->target_vcpu = vcpu; refcount_set(&irq->refcount, 0); - if (vgic_irq_is_sgi(i)) { - /* SGIs */ - irq->enabled = 1; - irq->config = VGIC_CONFIG_EDGE; + if (!vgic_is_v5(vcpu->kvm)) { + irq->intid = i; + if (vgic_irq_is_sgi(i)) { + /* SGIs */ + irq->enabled = 1; + irq->config = VGIC_CONFIG_EDGE; + } else { + /* PPIs */ + irq->config = VGIC_CONFIG_LEVEL; + } } else { - /* PPIs */ - irq->config = VGIC_CONFIG_LEVEL; + irq->intid = FIELD_PREP(GICV5_HWIRQ_ID, i) | + FIELD_PREP(GICV5_HWIRQ_TYPE, + GICV5_HWIRQ_TYPE_PPI); + + /* The only Edge architected PPI is the SW_PPI */ + if (i == GICV5_ARCH_PPI_SW_PPI) + irq->config = VGIC_CONFIG_EDGE; + else + irq->config = VGIC_CONFIG_LEVEL; + + /* Register the GICv5-specific PPI ops */ + vgic_v5_set_ppi_ops(irq); } switch (type) { -- 2.34.1