diff options
| -rw-r--r-- | arch/powerpc/kvm/Kconfig | 1 | ||||
| -rw-r--r-- | arch/powerpc/kvm/book3s_hv.c | 39 | ||||
| -rw-r--r-- | arch/powerpc/kvm/booke.c | 1 | ||||
| -rw-r--r-- | arch/powerpc/kvm/powerpc.c | 37 |
4 files changed, 55 insertions, 23 deletions
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index 9a0d1c1aca6c..b6bc2fc86dca 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig @@ -22,6 +22,7 @@ config KVM select KVM_COMMON select KVM_VFIO select HAVE_KVM_IRQ_BYPASS + select VIRT_XFER_TO_GUEST_WORK config KVM_BOOK3S_HANDLER bool diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 61dbeea317f3..3cfe9a7be9c6 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -3853,7 +3853,8 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) */ local_irq_disable(); hard_irq_disable(); - if (lazy_irq_pending() || need_resched() || + xfer_to_guest_mode_prepare(); + if (lazy_irq_pending() || xfer_to_guest_mode_work_pending() || recheck_signals_and_mmu(&core_info)) { local_irq_enable(); vc->vcore_state = VCORE_INACTIVE; @@ -4824,10 +4825,16 @@ static int kvmppc_run_vcpu(struct kvm_vcpu *vcpu) vc->runner = vcpu; if (n_ceded == vc->n_runnable) { kvmppc_vcore_blocked(vc); - } else if (need_resched()) { + } else if (__xfer_to_guest_mode_work_pending()) { kvmppc_vcore_preempt(vc); - /* Let something else run */ - cond_resched_lock(&vc->lock); + /* + * Let something else run. The raw helper is used as + * signal exits are accounted by this path already; + * it may schedule(), so drop the vcore lock. + */ + spin_unlock(&vc->lock); + xfer_to_guest_mode_handle_work(); + spin_lock(&vc->lock); if (vc->vcore_state == VCORE_PREEMPT) kvmppc_vcore_end_preempt(vc); } else { @@ -4895,12 +4902,16 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, run->exit_reason = KVM_EXIT_FAIL_ENTRY; run->fail_entry.hardware_entry_failure_reason = 0; vcpu->arch.ret = r; - return r; + goto done; } } - if (need_resched()) - cond_resched(); + r = kvm_xfer_to_guest_mode_handle_work(vcpu); + if (r) { + /* -EINTR: signal pending, exit to userspace (KVM_EXIT_INTR) */ + vcpu->arch.ret = r; + goto done; + } kvmppc_update_vpas(vcpu); @@ -4914,9 +4925,13 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, vcpu->arch.state = KVMPPC_VCPU_RUNNABLE; - if (signal_pending(current)) - goto sigpend; - if (need_resched() || !kvm->arch.mmu_ready) + xfer_to_guest_mode_prepare(); + + /* + * IRQs are disabled here, so on pending work bail to the outer loop, + * which handles it via kvm_xfer_to_guest_mode_handle_work() above. + */ + if (xfer_to_guest_mode_work_pending() || !kvm->arch.mmu_ready) goto out; vcpu->cpu = pcpu; @@ -5068,10 +5083,6 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, return vcpu->arch.ret; - sigpend: - vcpu->stat.signal_exits++; - run->exit_reason = KVM_EXIT_INTR; - vcpu->arch.ret = -EINTR; out: vcpu->cpu = -1; vcpu->arch.thread_cpu = -1; diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index f3ddb24ece74..5fba199dfdd6 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -722,6 +722,7 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu) if (vcpu->arch.shared->msr & MSR_WE) { local_irq_enable(); kvm_vcpu_halt(vcpu); + local_irq_disable(); hard_irq_disable(); kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS); diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 00302399fc37..be5e48ae0c6c 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -81,23 +81,41 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) int r; WARN_ON(irqs_disabled()); + /* + * local_irq_disable() first: on 32-bit, hard_irq_disable() alone is a + * raw MSR[EE] clear that bypasses the lockdep/irq-tracing state, and + * the xfer_to_guest_mode helpers assert IRQs are seen as disabled. + */ + local_irq_disable(); hard_irq_disable(); while (true) { - if (need_resched()) { + xfer_to_guest_mode_prepare(); + + if (xfer_to_guest_mode_work_pending()) { + /* + * The helper must run with IRQs enabled and may + * schedule(). On a pending signal it returns -EINTR + * with run->exit_reason and vcpu->stat.signal_exits + * already set, so just return to userspace. + */ local_irq_enable(); - cond_resched(); + r = kvm_xfer_to_guest_mode_handle_work(vcpu); + local_irq_disable(); hard_irq_disable(); + if (r) { + /* + * The generic helper does not set the exit + * type; record it for the E500 + * CONFIG_KVM_EXIT_TIMING histogram (a no-op + * otherwise). + */ + kvmppc_set_exit_type(vcpu, SIGNAL_EXITS); + break; + } continue; } - if (signal_pending(current)) { - kvmppc_account_exit(vcpu, SIGNAL_EXITS); - vcpu->run->exit_reason = KVM_EXIT_INTR; - r = -EINTR; - break; - } - vcpu->mode = IN_GUEST_MODE; /* @@ -116,6 +134,7 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) local_irq_enable(); trace_kvm_check_requests(vcpu); r = kvmppc_core_check_requests(vcpu); + local_irq_disable(); hard_irq_disable(); if (r > 0) continue; |
