Re: [PATCH v5 19/23] KVM: arm64: GICv4.1: Allow SGIs to switch between HW and SW interrupts

From: Auger Eric
Date: Thu Mar 19 2020 - 12:16:54 EST


Hi Marc,

On 3/4/20 9:33 PM, Marc Zyngier wrote:
> In order to let a guest buy in the new, active-less SGIs, we
> need to be able to switch between the two modes.
>
> Handle this by stopping all guest activity, transfer the state
> from one mode to the other, and resume the guest. Nothing calls
> this code so far, but a later patch will plug it into the MMIO
> emulation.
>
> Signed-off-by: Marc Zyngier <maz@xxxxxxxxxx>
> ---
> include/kvm/arm_vgic.h | 3 ++
> virt/kvm/arm/vgic/vgic-v4.c | 94 +++++++++++++++++++++++++++++++++++++
> virt/kvm/arm/vgic/vgic.h | 1 +
> 3 files changed, 98 insertions(+)
>
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 63457908c9c4..69f4164d6477 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -231,6 +231,9 @@ struct vgic_dist {
> /* distributor enabled */
> bool enabled;
>
> + /* Wants SGIs without active state */
> + bool nassgireq;
> +
> struct vgic_irq *spis;
>
> struct vgic_io_device dist_iodev;
> diff --git a/virt/kvm/arm/vgic/vgic-v4.c b/virt/kvm/arm/vgic/vgic-v4.c
> index c2fcde104ea2..a65dc1c85363 100644
> --- a/virt/kvm/arm/vgic/vgic-v4.c
> +++ b/virt/kvm/arm/vgic/vgic-v4.c
> @@ -97,6 +97,100 @@ static irqreturn_t vgic_v4_doorbell_handler(int irq, void *info)
> return IRQ_HANDLED;
> }
>
> +static void vgic_v4_sync_sgi_config(struct its_vpe *vpe, struct vgic_irq *irq)
> +{
> + vpe->sgi_config[irq->intid].enabled = irq->enabled;
> + vpe->sgi_config[irq->intid].group = irq->group;
> + vpe->sgi_config[irq->intid].priority = irq->priority;
> +}
> +
> +static void vgic_v4_enable_vsgis(struct kvm_vcpu *vcpu)
> +{
> + struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
> + int i;
> +
> + /*
> + * With GICv4.1, every virtual SGI can be directly injected. So
> + * let's pretend that they are HW interrupts, tied to a host
> + * IRQ. The SGI code will do its magic.
> + */
> + for (i = 0; i < VGIC_NR_SGIS; i++) {
> + struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, i);
> + struct irq_desc *desc;
> + int ret;
Is is safe without holding the irq->irq_lock?
> +
> + if (irq->hw) {
> + vgic_put_irq(vcpu->kvm, irq);
> + continue;
> + }
> +
> + irq->hw = true;
> + irq->host_irq = irq_find_mapping(vpe->sgi_domain, i);
> +
> + /* Transfer the full irq state to the vPE */
> + vgic_v4_sync_sgi_config(vpe, irq);
> + desc = irq_to_desc(irq->host_irq);
> + ret = irq_domain_activate_irq(irq_desc_get_irq_data(desc),
> + false);
> + if (!WARN_ON(ret)) {
> + /* Transfer pending state */
> + ret = irq_set_irqchip_state(irq->host_irq,
> + IRQCHIP_STATE_PENDING,
> + irq->pending_latch);
> + WARN_ON(ret);
> + irq->pending_latch = false;
> + }
> +
> + vgic_put_irq(vcpu->kvm, irq);
> + }
> +}
> +
> +static void vgic_v4_disable_vsgis(struct kvm_vcpu *vcpu)
> +{
> + int i;
> +
> + for (i = 0; i < VGIC_NR_SGIS; i++) {
> + struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, i);
> + struct irq_desc *desc;
> + int ret;
> +
> + if (!irq->hw) {
> + vgic_put_irq(vcpu->kvm, irq);
> + continue;
> + }
> +
> + irq->hw = false;
> + ret = irq_get_irqchip_state(irq->host_irq,
> + IRQCHIP_STATE_PENDING,
> + &irq->pending_latch);
> + WARN_ON(ret);
> +
> + desc = irq_to_desc(irq->host_irq);
> + irq_domain_deactivate_irq(irq_desc_get_irq_data(desc));
> +
> + vgic_put_irq(vcpu->kvm, irq);
> + }
> +}
> +
> +/* Must be called with the kvm lock held */
> +void vgic_v4_configure_vsgis(struct kvm *kvm)
> +{
> + struct vgic_dist *dist = &kvm->arch.vgic;
> + struct kvm_vcpu *vcpu;
> + int i;
> +
> + kvm_arm_halt_guest(kvm);
> +
> + kvm_for_each_vcpu(i, vcpu, kvm) {
> + if (dist->nassgireq)
> + vgic_v4_enable_vsgis(vcpu);
> + else
> + vgic_v4_disable_vsgis(vcpu);
> + }
> +
> + kvm_arm_resume_guest(kvm);
> +}
> +
> /**
> * vgic_v4_init - Initialize the GICv4 data structures
> * @kvm: Pointer to the VM being initialized
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index c7fefd6b1c80..769e4802645e 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -316,5 +316,6 @@ void vgic_its_invalidate_cache(struct kvm *kvm);
> bool vgic_supports_direct_msis(struct kvm *kvm);
> int vgic_v4_init(struct kvm *kvm);
> void vgic_v4_teardown(struct kvm *kvm);
> +void vgic_v4_configure_vsgis(struct kvm *kvm);
>
> #endif
>
Thanks

Eric