diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2017-12-18 06:57:43 -0500 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2017-12-18 06:57:43 -0500 |
commit | 43aabca38aa9668eee3c3c1206207034614c0901 (patch) | |
tree | 03029d7ed46fc14ffc598b75ac1536faef26a0d1 | |
parent | e39d200fa5bf5b94a0948db0dae44c1b73b84a56 (diff) | |
parent | 0eb7c33cadf6b2f1a94e58ded8b0eb89b4eba382 (diff) |
Merge tag 'kvm-arm-fixes-for-v4.15-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/ARM Fixes for v4.15, Round 2
Fixes:
- A bug in our handling of SPE state for non-vhe systems
- A bug that causes hyp unmapping to go off limits and crash the system on
shutdown
- Three timer fixes that were introduced as part of the timer optimizations
for v4.15
-rw-r--r-- | arch/arm64/kvm/hyp/debug-sr.c | 3 | ||||
-rw-r--r-- | include/kvm/arm_arch_timer.h | 2 | ||||
-rw-r--r-- | virt/kvm/arm/arch_timer.c | 40 | ||||
-rw-r--r-- | virt/kvm/arm/arm.c | 2 | ||||
-rw-r--r-- | virt/kvm/arm/mmu.c | 10 |
5 files changed, 33 insertions, 24 deletions
diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c index 321c9c05dd9e..f4363d40e2cd 100644 --- a/arch/arm64/kvm/hyp/debug-sr.c +++ b/arch/arm64/kvm/hyp/debug-sr.c | |||
@@ -74,6 +74,9 @@ static void __hyp_text __debug_save_spe_nvhe(u64 *pmscr_el1) | |||
74 | { | 74 | { |
75 | u64 reg; | 75 | u64 reg; |
76 | 76 | ||
77 | /* Clear pmscr in case of early return */ | ||
78 | *pmscr_el1 = 0; | ||
79 | |||
77 | /* SPE present on this CPU? */ | 80 | /* SPE present on this CPU? */ |
78 | if (!cpuid_feature_extract_unsigned_field(read_sysreg(id_aa64dfr0_el1), | 81 | if (!cpuid_feature_extract_unsigned_field(read_sysreg(id_aa64dfr0_el1), |
79 | ID_AA64DFR0_PMSVER_SHIFT)) | 82 | ID_AA64DFR0_PMSVER_SHIFT)) |
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h index 6e45608b2399..9da6ce22803f 100644 --- a/include/kvm/arm_arch_timer.h +++ b/include/kvm/arm_arch_timer.h | |||
@@ -62,7 +62,7 @@ struct arch_timer_cpu { | |||
62 | bool enabled; | 62 | bool enabled; |
63 | }; | 63 | }; |
64 | 64 | ||
65 | int kvm_timer_hyp_init(void); | 65 | int kvm_timer_hyp_init(bool); |
66 | int kvm_timer_enable(struct kvm_vcpu *vcpu); | 66 | int kvm_timer_enable(struct kvm_vcpu *vcpu); |
67 | int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu); | 67 | int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu); |
68 | void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu); | 68 | void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu); |
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index f9555b1e7f15..cc29a8148328 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c | |||
@@ -92,16 +92,23 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id) | |||
92 | { | 92 | { |
93 | struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id; | 93 | struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id; |
94 | struct arch_timer_context *vtimer; | 94 | struct arch_timer_context *vtimer; |
95 | u32 cnt_ctl; | ||
95 | 96 | ||
96 | if (!vcpu) { | 97 | /* |
97 | pr_warn_once("Spurious arch timer IRQ on non-VCPU thread\n"); | 98 | * We may see a timer interrupt after vcpu_put() has been called which |
98 | return IRQ_NONE; | 99 | * sets the CPU's vcpu pointer to NULL, because even though the timer |
99 | } | 100 | * has been disabled in vtimer_save_state(), the hardware interrupt |
100 | vtimer = vcpu_vtimer(vcpu); | 101 | * signal may not have been retired from the interrupt controller yet. |
102 | */ | ||
103 | if (!vcpu) | ||
104 | return IRQ_HANDLED; | ||
101 | 105 | ||
106 | vtimer = vcpu_vtimer(vcpu); | ||
102 | if (!vtimer->irq.level) { | 107 | if (!vtimer->irq.level) { |
103 | vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl); | 108 | cnt_ctl = read_sysreg_el0(cntv_ctl); |
104 | if (kvm_timer_irq_can_fire(vtimer)) | 109 | cnt_ctl &= ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_STAT | |
110 | ARCH_TIMER_CTRL_IT_MASK; | ||
111 | if (cnt_ctl == (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_STAT)) | ||
105 | kvm_timer_update_irq(vcpu, true, vtimer); | 112 | kvm_timer_update_irq(vcpu, true, vtimer); |
106 | } | 113 | } |
107 | 114 | ||
@@ -355,6 +362,7 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu) | |||
355 | 362 | ||
356 | /* Disable the virtual timer */ | 363 | /* Disable the virtual timer */ |
357 | write_sysreg_el0(0, cntv_ctl); | 364 | write_sysreg_el0(0, cntv_ctl); |
365 | isb(); | ||
358 | 366 | ||
359 | vtimer->loaded = false; | 367 | vtimer->loaded = false; |
360 | out: | 368 | out: |
@@ -720,7 +728,7 @@ static int kvm_timer_dying_cpu(unsigned int cpu) | |||
720 | return 0; | 728 | return 0; |
721 | } | 729 | } |
722 | 730 | ||
723 | int kvm_timer_hyp_init(void) | 731 | int kvm_timer_hyp_init(bool has_gic) |
724 | { | 732 | { |
725 | struct arch_timer_kvm_info *info; | 733 | struct arch_timer_kvm_info *info; |
726 | int err; | 734 | int err; |
@@ -756,10 +764,13 @@ int kvm_timer_hyp_init(void) | |||
756 | return err; | 764 | return err; |
757 | } | 765 | } |
758 | 766 | ||
759 | err = irq_set_vcpu_affinity(host_vtimer_irq, kvm_get_running_vcpus()); | 767 | if (has_gic) { |
760 | if (err) { | 768 | err = irq_set_vcpu_affinity(host_vtimer_irq, |
761 | kvm_err("kvm_arch_timer: error setting vcpu affinity\n"); | 769 | kvm_get_running_vcpus()); |
762 | goto out_free_irq; | 770 | if (err) { |
771 | kvm_err("kvm_arch_timer: error setting vcpu affinity\n"); | ||
772 | goto out_free_irq; | ||
773 | } | ||
763 | } | 774 | } |
764 | 775 | ||
765 | kvm_info("virtual timer IRQ%d\n", host_vtimer_irq); | 776 | kvm_info("virtual timer IRQ%d\n", host_vtimer_irq); |
@@ -835,10 +846,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu) | |||
835 | no_vgic: | 846 | no_vgic: |
836 | preempt_disable(); | 847 | preempt_disable(); |
837 | timer->enabled = 1; | 848 | timer->enabled = 1; |
838 | if (!irqchip_in_kernel(vcpu->kvm)) | 849 | kvm_timer_vcpu_load(vcpu); |
839 | kvm_timer_vcpu_load_user(vcpu); | ||
840 | else | ||
841 | kvm_timer_vcpu_load_vgic(vcpu); | ||
842 | preempt_enable(); | 850 | preempt_enable(); |
843 | 851 | ||
844 | return 0; | 852 | return 0; |
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 6b60c98a6e22..2e43f9d42bd5 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c | |||
@@ -1326,7 +1326,7 @@ static int init_subsystems(void) | |||
1326 | /* | 1326 | /* |
1327 | * Init HYP architected timer support | 1327 | * Init HYP architected timer support |
1328 | */ | 1328 | */ |
1329 | err = kvm_timer_hyp_init(); | 1329 | err = kvm_timer_hyp_init(vgic_present); |
1330 | if (err) | 1330 | if (err) |
1331 | goto out; | 1331 | goto out; |
1332 | 1332 | ||
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index b36945d49986..b4b69c2d1012 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c | |||
@@ -509,8 +509,6 @@ static void unmap_hyp_range(pgd_t *pgdp, phys_addr_t start, u64 size) | |||
509 | */ | 509 | */ |
510 | void free_hyp_pgds(void) | 510 | void free_hyp_pgds(void) |
511 | { | 511 | { |
512 | unsigned long addr; | ||
513 | |||
514 | mutex_lock(&kvm_hyp_pgd_mutex); | 512 | mutex_lock(&kvm_hyp_pgd_mutex); |
515 | 513 | ||
516 | if (boot_hyp_pgd) { | 514 | if (boot_hyp_pgd) { |
@@ -521,10 +519,10 @@ void free_hyp_pgds(void) | |||
521 | 519 | ||
522 | if (hyp_pgd) { | 520 | if (hyp_pgd) { |
523 | unmap_hyp_range(hyp_pgd, hyp_idmap_start, PAGE_SIZE); | 521 | unmap_hyp_range(hyp_pgd, hyp_idmap_start, PAGE_SIZE); |
524 | for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE) | 522 | unmap_hyp_range(hyp_pgd, kern_hyp_va(PAGE_OFFSET), |
525 | unmap_hyp_range(hyp_pgd, kern_hyp_va(addr), PGDIR_SIZE); | 523 | (uintptr_t)high_memory - PAGE_OFFSET); |
526 | for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE) | 524 | unmap_hyp_range(hyp_pgd, kern_hyp_va(VMALLOC_START), |
527 | unmap_hyp_range(hyp_pgd, kern_hyp_va(addr), PGDIR_SIZE); | 525 | VMALLOC_END - VMALLOC_START); |
528 | 526 | ||
529 | free_pages((unsigned long)hyp_pgd, hyp_pgd_order); | 527 | free_pages((unsigned long)hyp_pgd, hyp_pgd_order); |
530 | hyp_pgd = NULL; | 528 | hyp_pgd = NULL; |