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 pick Level has been picked for that). Signed-off-by: Sascha Bischoff --- arch/arm64/kvm/vgic/vgic-init.c | 41 +++++++++++++++++++++++------- include/linux/irqchip/arm-gic-v5.h | 2 ++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index b246cb6eae71b..51f4443cebcef 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; + + if (vgic_is_v5(vcpu->kvm)) + num_private_irqs = VGIC_V5_NR_PRIVATE_IRQS; + else + num_private_irqs = VGIC_NR_PRIVATE_IRQS; lockdep_assert_held(&vcpu->kvm->arch.config_lock); 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,39 @@ 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 = i | FIELD_PREP(GICV5_HWIRQ_TYPE, + GICV5_HWIRQ_TYPE_PPI); + + /* + * The only architected PPI that is Edge is + * the SW PPI. + */ + if (irq->intid == GICV5_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) { diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h index ff10d6c7be2ae..9607b36f021ee 100644 --- a/include/linux/irqchip/arm-gic-v5.h +++ b/include/linux/irqchip/arm-gic-v5.h @@ -13,6 +13,8 @@ #define GICV5_IPIS_PER_CPU MAX_IPI +#define GICV5_SW_PPI 0x20000003 + /* * INTID handling */ -- 2.34.1