diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2019-08-09 10:53:50 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2019-08-09 10:53:50 -0400 |
commit | a738b5e75b4c13be3485c82eb62c30047aa9f164 (patch) | |
tree | f47fca53ee79938be283e13cf5d48def68f9dad2 /virt/kvm/arm | |
parent | 0e1c438c44dd9cde56effb44c5f1cfeda72e108d (diff) | |
parent | 16e604a437c89751dc626c9e90cf88ba93c5be64 (diff) |
Merge tag 'kvmarm-fixes-for-5.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/arm fixes for 5.3, take #2
- Fix our system register reset so that we stop writing
non-sensical values to them, and track which registers
get reset instead.
- Sync VMCR back from the GIC on WFI so that KVM has an
exact vue of PMR.
- Reevaluate state of HW-mapped, level triggered interrupts
on enable.
Diffstat (limited to 'virt/kvm/arm')
-rw-r--r-- | virt/kvm/arm/arm.c | 11 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-mmio.c | 16 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-v2.c | 9 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-v3.c | 7 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic.c | 11 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic.h | 2 |
6 files changed, 54 insertions, 2 deletions
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 3f7bea930acf..35a069815baf 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c | |||
@@ -318,6 +318,17 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) | |||
318 | 318 | ||
319 | void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) | 319 | void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) |
320 | { | 320 | { |
321 | /* | ||
322 | * If we're about to block (most likely because we've just hit a | ||
323 | * WFI), we need to sync back the state of the GIC CPU interface | ||
324 | * so that we have the lastest PMR and group enables. This ensures | ||
325 | * that kvm_arch_vcpu_runnable has up-to-date data to decide | ||
326 | * whether we have pending interrupts. | ||
327 | */ | ||
328 | preempt_disable(); | ||
329 | kvm_vgic_vmcr_sync(vcpu); | ||
330 | preempt_enable(); | ||
331 | |||
321 | kvm_vgic_v4_enable_doorbell(vcpu); | 332 | kvm_vgic_v4_enable_doorbell(vcpu); |
322 | } | 333 | } |
323 | 334 | ||
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c index 3ba7278fb533..44efc2ff863f 100644 --- a/virt/kvm/arm/vgic/vgic-mmio.c +++ b/virt/kvm/arm/vgic/vgic-mmio.c | |||
@@ -113,6 +113,22 @@ void vgic_mmio_write_senable(struct kvm_vcpu *vcpu, | |||
113 | struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); | 113 | struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); |
114 | 114 | ||
115 | raw_spin_lock_irqsave(&irq->irq_lock, flags); | 115 | raw_spin_lock_irqsave(&irq->irq_lock, flags); |
116 | if (vgic_irq_is_mapped_level(irq)) { | ||
117 | bool was_high = irq->line_level; | ||
118 | |||
119 | /* | ||
120 | * We need to update the state of the interrupt because | ||
121 | * the guest might have changed the state of the device | ||
122 | * while the interrupt was disabled at the VGIC level. | ||
123 | */ | ||
124 | irq->line_level = vgic_get_phys_line_level(irq); | ||
125 | /* | ||
126 | * Deactivate the physical interrupt so the GIC will let | ||
127 | * us know when it is asserted again. | ||
128 | */ | ||
129 | if (!irq->active && was_high && !irq->line_level) | ||
130 | vgic_irq_set_phys_active(irq, false); | ||
131 | } | ||
116 | irq->enabled = true; | 132 | irq->enabled = true; |
117 | vgic_queue_irq_unlock(vcpu->kvm, irq, flags); | 133 | vgic_queue_irq_unlock(vcpu->kvm, irq, flags); |
118 | 134 | ||
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c index 6dd5ad706c92..96aab77d0471 100644 --- a/virt/kvm/arm/vgic/vgic-v2.c +++ b/virt/kvm/arm/vgic/vgic-v2.c | |||
@@ -484,10 +484,17 @@ void vgic_v2_load(struct kvm_vcpu *vcpu) | |||
484 | kvm_vgic_global_state.vctrl_base + GICH_APR); | 484 | kvm_vgic_global_state.vctrl_base + GICH_APR); |
485 | } | 485 | } |
486 | 486 | ||
487 | void vgic_v2_put(struct kvm_vcpu *vcpu) | 487 | void vgic_v2_vmcr_sync(struct kvm_vcpu *vcpu) |
488 | { | 488 | { |
489 | struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; | 489 | struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; |
490 | 490 | ||
491 | cpu_if->vgic_vmcr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VMCR); | 491 | cpu_if->vgic_vmcr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VMCR); |
492 | } | ||
493 | |||
494 | void vgic_v2_put(struct kvm_vcpu *vcpu) | ||
495 | { | ||
496 | struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; | ||
497 | |||
498 | vgic_v2_vmcr_sync(vcpu); | ||
492 | cpu_if->vgic_apr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_APR); | 499 | cpu_if->vgic_apr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_APR); |
493 | } | 500 | } |
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c index c2c9ce009f63..0c653a1e5215 100644 --- a/virt/kvm/arm/vgic/vgic-v3.c +++ b/virt/kvm/arm/vgic/vgic-v3.c | |||
@@ -662,12 +662,17 @@ void vgic_v3_load(struct kvm_vcpu *vcpu) | |||
662 | __vgic_v3_activate_traps(vcpu); | 662 | __vgic_v3_activate_traps(vcpu); |
663 | } | 663 | } |
664 | 664 | ||
665 | void vgic_v3_put(struct kvm_vcpu *vcpu) | 665 | void vgic_v3_vmcr_sync(struct kvm_vcpu *vcpu) |
666 | { | 666 | { |
667 | struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; | 667 | struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; |
668 | 668 | ||
669 | if (likely(cpu_if->vgic_sre)) | 669 | if (likely(cpu_if->vgic_sre)) |
670 | cpu_if->vgic_vmcr = kvm_call_hyp_ret(__vgic_v3_read_vmcr); | 670 | cpu_if->vgic_vmcr = kvm_call_hyp_ret(__vgic_v3_read_vmcr); |
671 | } | ||
672 | |||
673 | void vgic_v3_put(struct kvm_vcpu *vcpu) | ||
674 | { | ||
675 | vgic_v3_vmcr_sync(vcpu); | ||
671 | 676 | ||
672 | kvm_call_hyp(__vgic_v3_save_aprs, vcpu); | 677 | kvm_call_hyp(__vgic_v3_save_aprs, vcpu); |
673 | 678 | ||
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c index 04786c8ec77e..13d4b38a94ec 100644 --- a/virt/kvm/arm/vgic/vgic.c +++ b/virt/kvm/arm/vgic/vgic.c | |||
@@ -919,6 +919,17 @@ void kvm_vgic_put(struct kvm_vcpu *vcpu) | |||
919 | vgic_v3_put(vcpu); | 919 | vgic_v3_put(vcpu); |
920 | } | 920 | } |
921 | 921 | ||
922 | void kvm_vgic_vmcr_sync(struct kvm_vcpu *vcpu) | ||
923 | { | ||
924 | if (unlikely(!irqchip_in_kernel(vcpu->kvm))) | ||
925 | return; | ||
926 | |||
927 | if (kvm_vgic_global_state.type == VGIC_V2) | ||
928 | vgic_v2_vmcr_sync(vcpu); | ||
929 | else | ||
930 | vgic_v3_vmcr_sync(vcpu); | ||
931 | } | ||
932 | |||
922 | int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu) | 933 | int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu) |
923 | { | 934 | { |
924 | struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; | 935 | struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; |
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h index 3b7525deec80..797e05004d80 100644 --- a/virt/kvm/arm/vgic/vgic.h +++ b/virt/kvm/arm/vgic/vgic.h | |||
@@ -193,6 +193,7 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address, | |||
193 | void vgic_v2_init_lrs(void); | 193 | void vgic_v2_init_lrs(void); |
194 | void vgic_v2_load(struct kvm_vcpu *vcpu); | 194 | void vgic_v2_load(struct kvm_vcpu *vcpu); |
195 | void vgic_v2_put(struct kvm_vcpu *vcpu); | 195 | void vgic_v2_put(struct kvm_vcpu *vcpu); |
196 | void vgic_v2_vmcr_sync(struct kvm_vcpu *vcpu); | ||
196 | 197 | ||
197 | void vgic_v2_save_state(struct kvm_vcpu *vcpu); | 198 | void vgic_v2_save_state(struct kvm_vcpu *vcpu); |
198 | void vgic_v2_restore_state(struct kvm_vcpu *vcpu); | 199 | void vgic_v2_restore_state(struct kvm_vcpu *vcpu); |
@@ -223,6 +224,7 @@ bool vgic_v3_check_base(struct kvm *kvm); | |||
223 | 224 | ||
224 | void vgic_v3_load(struct kvm_vcpu *vcpu); | 225 | void vgic_v3_load(struct kvm_vcpu *vcpu); |
225 | void vgic_v3_put(struct kvm_vcpu *vcpu); | 226 | void vgic_v3_put(struct kvm_vcpu *vcpu); |
227 | void vgic_v3_vmcr_sync(struct kvm_vcpu *vcpu); | ||
226 | 228 | ||
227 | bool vgic_has_its(struct kvm *kvm); | 229 | bool vgic_has_its(struct kvm *kvm); |
228 | int kvm_vgic_register_its_device(void); | 230 | int kvm_vgic_register_its_device(void); |