Commit 1da4e2f4 authored by Paul Mackerras's avatar Paul Mackerras

KVM: PPC: Book3S HV: Don't let VCPU sleep if it has a doorbell pending

It is possible, through a narrow race condition, for a VCPU to exit
the guest with a H_CEDE hypercall while it has a doorbell interrupt
pending.  In this case, the H_CEDE should return immediately, but in
fact it puts the VCPU to sleep until some other interrupt becomes
pending or a prod is received (via another VCPU doing H_PROD).

This fixes it by checking the DPDES (Directed Privileged Doorbell
Exception Status) bit for the thread along with the other interrupt
pending bits.
Signed-off-by: default avatarPaul Mackerras <paulus@ozlabs.org>
parent 1bc3fe81
...@@ -675,6 +675,17 @@ static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu, ...@@ -675,6 +675,17 @@ static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu,
vcpu->arch.dtl.dirty = true; vcpu->arch.dtl.dirty = true;
} }
/* See if there is a doorbell interrupt pending for a vcpu */
static bool kvmppc_doorbell_pending(struct kvm_vcpu *vcpu)
{
int thr;
struct kvmppc_vcore *vc;
vc = vcpu->arch.vcore;
thr = vcpu->vcpu_id - vc->first_vcpuid;
return !!(vc->dpdes & (1 << thr));
}
static bool kvmppc_power8_compatible(struct kvm_vcpu *vcpu) static bool kvmppc_power8_compatible(struct kvm_vcpu *vcpu)
{ {
if (vcpu->arch.vcore->arch_compat >= PVR_ARCH_207) if (vcpu->arch.vcore->arch_compat >= PVR_ARCH_207)
...@@ -2672,6 +2683,15 @@ static void shrink_halt_poll_ns(struct kvmppc_vcore *vc) ...@@ -2672,6 +2683,15 @@ static void shrink_halt_poll_ns(struct kvmppc_vcore *vc)
vc->halt_poll_ns /= halt_poll_ns_shrink; vc->halt_poll_ns /= halt_poll_ns_shrink;
} }
static bool kvmppc_vcpu_woken(struct kvm_vcpu *vcpu)
{
if (vcpu->arch.pending_exceptions || vcpu->arch.prodded ||
kvmppc_doorbell_pending(vcpu))
return true;
return false;
}
/* /*
* Check to see if any of the runnable vcpus on the vcore have pending * Check to see if any of the runnable vcpus on the vcore have pending
* exceptions or are no longer ceded * exceptions or are no longer ceded
...@@ -2682,8 +2702,7 @@ static int kvmppc_vcore_check_block(struct kvmppc_vcore *vc) ...@@ -2682,8 +2702,7 @@ static int kvmppc_vcore_check_block(struct kvmppc_vcore *vc)
int i; int i;
for_each_runnable_thread(i, vcpu, vc) { for_each_runnable_thread(i, vcpu, vc) {
if (vcpu->arch.pending_exceptions || !vcpu->arch.ceded || if (!vcpu->arch.ceded || kvmppc_vcpu_woken(vcpu))
vcpu->arch.prodded)
return 1; return 1;
} }
...@@ -2869,7 +2888,7 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) ...@@ -2869,7 +2888,7 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
break; break;
n_ceded = 0; n_ceded = 0;
for_each_runnable_thread(i, v, vc) { for_each_runnable_thread(i, v, vc) {
if (!v->arch.pending_exceptions && !v->arch.prodded) if (!kvmppc_vcpu_woken(v))
n_ceded += v->arch.ceded; n_ceded += v->arch.ceded;
else else
v->arch.ceded = 0; v->arch.ceded = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment