There are times when the default behaviour of vgic_queue_irq_unlock is undesirable. This is because some GICs, such a GICv5 which is the main driver for this change, handle the majority of the interrupt lifecycle in hardware. In this case, there is no need for a per-VCPU AP list as the interrupt can be made pending directly. This is done either via the ICH_PPI_x_EL2 registers for PPIs, or with the VDPEND system instruction for SPIs and LPIs. The queue_irq_unlock function is made overridable using a new function pointer in struct irq_ops. In kvm_vgic_inject_irq, vgic_queue_irq_unlock is overridden if the function pointer is non-null. Additionally, a new function is added via a function pointer - set_pending_state. The intent is for this to be used to directly set the pending state in hardware. Both of these new irq_ops are unused in this change - it is purely providing the infrastructure itself. The subsequent PPI injection changes provide a demonstration of their usage. Signed-off-by: Sascha Bischoff --- arch/arm64/kvm/vgic/vgic.c | 11 +++++++++++ include/kvm/arm_vgic.h | 15 +++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index d88570bb2f9f0..ac8cb0270e1e4 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -404,6 +404,13 @@ bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq, lockdep_assert_held(&irq->irq_lock); + /* + * If we have the queue_irq_unlock irq_op, we want to override + * the default behaviour. Call that, and return early. + */ + if (irq->ops && irq->ops->queue_irq_unlock) + return irq->ops->queue_irq_unlock(kvm, irq, flags); + retry: vcpu = vgic_target_oracle(irq); if (irq->vcpu || !vcpu) { @@ -547,7 +554,11 @@ int kvm_vgic_inject_irq(struct kvm *kvm, struct kvm_vcpu *vcpu, else irq->pending_latch = true; + if (irq->ops && irq->ops->set_pending_state) + WARN_ON_ONCE(!irq->ops->set_pending_state(vcpu, irq)); + vgic_queue_irq_unlock(kvm, irq, flags); + vgic_put_irq(kvm, irq); return 0; diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 17cd0295b135f..500709bd62c8d 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -171,6 +171,8 @@ enum vgic_irq_config { VGIC_CONFIG_LEVEL }; +struct vgic_irq; + /* * Per-irq ops overriding some common behavious. * @@ -189,6 +191,19 @@ struct irq_ops { * peaking into the physical GIC. */ bool (*get_input_level)(int vintid); + + /* + * Function pointer to directly set the pending state for interrupts + * that don't need to be enqueued on AP lists (for example, GICv5 PPIs). + */ + bool (*set_pending_state)(struct kvm_vcpu *vcpu, struct vgic_irq *irq); + + /* + * Function pointer to override the queuing of an IRQ. + */ + bool (*queue_irq_unlock)(struct kvm *kvm, struct vgic_irq *irq, + unsigned long flags) __releases(&irq->irq_lock); + }; struct vgic_irq { -- 2.34.1