aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm/arm/vgic/vgic.c
diff options
context:
space:
mode:
authorShih-Wei Li <shihwei@cs.columbia.edu>2016-10-19 18:12:34 +0000
committerChristoffer Dall <cdall@linaro.org>2017-04-09 07:45:31 -0700
commitf6769581e90ba2535b3e587fe15b74f6cbc4aaab (patch)
tree947613a9b9ca8970e457000fd47769e2a6c60894 /virt/kvm/arm/vgic/vgic.c
parentKVM: arm/arm64: vgic: Defer touching GICH_VMCR to vcpu_load/put (diff)
downloadlinux-dev-f6769581e90ba2535b3e587fe15b74f6cbc4aaab.tar.xz
linux-dev-f6769581e90ba2535b3e587fe15b74f6cbc4aaab.zip
KVM: arm/arm64: vgic: Avoid flushing vgic state when there's no pending IRQ
We do not need to flush vgic states in each world switch unless there is pending IRQ queued to the vgic's ap list. We can thus reduce the overhead by not grabbing the spinlock and not making the extra function call to vgic_flush_lr_state. Note: list_empty is a single atomic read (uses READ_ONCE) and can therefore check if a list is empty or not without the need to take the spinlock protecting the list. Reviewed-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Shih-Wei Li <shihwei@cs.columbia.edu> Signed-off-by: Christoffer Dall <cdall@linaro.org>
Diffstat (limited to '')
-rw-r--r--virt/kvm/arm/vgic/vgic.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 2ac0def57424..104329139f24 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -637,12 +637,17 @@ next:
/* Sync back the hardware VGIC state into our emulation after a guest's run. */
void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
if (unlikely(!vgic_initialized(vcpu->kvm)))
return;
vgic_process_maintenance_interrupt(vcpu);
vgic_fold_lr_state(vcpu);
vgic_prune_ap_list(vcpu);
+
+ /* Make sure we can fast-path in flush_hwstate */
+ vgic_cpu->used_lrs = 0;
}
/* Flush our emulation state into the GIC hardware before entering the guest. */
@@ -651,6 +656,18 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
if (unlikely(!vgic_initialized(vcpu->kvm)))
return;
+ /*
+ * If there are no virtual interrupts active or pending for this
+ * VCPU, then there is no work to do and we can bail out without
+ * taking any lock. There is a potential race with someone injecting
+ * interrupts to the VCPU, but it is a benign race as the VCPU will
+ * either observe the new interrupt before or after doing this check,
+ * and introducing additional synchronization mechanism doesn't change
+ * this.
+ */
+ if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
+ return;
+
spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
vgic_flush_lr_state(vcpu);
spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);