diff options
author | Paul Mackerras <paulus@samba.org> | 2014-01-21 16:45:05 +1100 |
---|---|---|
committer | Eli Qiao <taget@linux.vnet.ibm.com> | 2014-01-22 10:26:26 +0800 |
commit | 6b49cdc53603dc9e85a26b3f821a1cdfd0ef444d (patch) | |
tree | f6905c81b65f3ff7328dadd165b7aa4cc09760ac | |
parent | d0da4a50fa32a8cb006befd50ec7b147885e0b0e (diff) | |
download | powerkvm-6b49cdc53603dc9e85a26b3f821a1cdfd0ef444d.tar.gz |
KVM: PPC: Book3S HV: Send some subcommands of H_SET_MODE to userspace
This removes the code that handles the H_SET_MODE_RESOURCE_LE and
H_SET_MODE_RESOURCE_ADDR_TRANS_MODE subfunctions of the H_SET_MODE
hypercall from the kernel. Instead we now return H_TOO_HARD which
causes the hypercall to be sent up to userspace to be handled there.
In addition we now also send any other subfunction which we don't
recognize to userspace.
The reason for doing these two subfunctions in userspace is that they
need to modify LPCR across all vcpus of the guest. Modifying LPCR in
the kernel like this introduces a race between the kernel's
modification and any modification that userspace might be doing on
another vcpu. Therefore it's better to let userspace do all the
modifications, so it can do any necessary synchronization itself.
This also adds code to make sure that the MSR_LE bit in intr_msr
(the MSR value we set when synthesizing an interrupt for the guest)
is in sync with the ILE bit in the virtual core's LPCR value. This
is necessary for implementing the LE subfunction of H_SET_MODE in
userspace.
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/kvm/book3s_hv.c | 77 |
1 files changed, 24 insertions, 53 deletions
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 03b96f6621b2c..449ffac626c2d 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -565,10 +565,6 @@ static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags, unsigned long resource, unsigned long value1, unsigned long value2) { - struct kvm *kvm = vcpu->kvm; - struct kvm_vcpu *v; - int n; - switch (resource) { case H_SET_MODE_RESOURCE_SET_CIABR: if (!kvmppc_power8_compatible(vcpu)) @@ -591,56 +587,8 @@ static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags, vcpu->arch.dawr = value1; vcpu->arch.dawrx = value2; return H_SUCCESS; - case H_SET_MODE_RESOURCE_ADDR_TRANS_MODE: - if (!kvmppc_power8_compatible(vcpu)) - return H_P2; - if (value1) - return H_P3; - if (value2) - return H_P4; - switch (mflags) { - case 0: - case 2: - case 3: - mutex_lock(&kvm->lock); - kvmppc_update_lpcr(kvm, mflags << LPCR_AIL_SH, - LPCR_AIL); - mutex_unlock(&kvm->lock); - kick_all_cpus_sync(); - return H_SUCCESS; - default: - return H_UNSUPPORTED_FLAG_START; - } - case H_SET_MODE_RESOURCE_LE: - if (value1) - return H_P3; - if (value2) - return H_P4; - - switch (mflags) { - case 0: - mutex_lock(&kvm->lock); - kvmppc_update_lpcr(kvm, 0, LPCR_ILE); - kvm_for_each_vcpu(n, v, kvm) - v->arch.intr_msr &= ~MSR_LE; - mutex_unlock(&kvm->lock); - kick_all_cpus_sync(); - return H_SUCCESS; - - case 1: - mutex_lock(&kvm->lock); - kvmppc_update_lpcr(kvm, LPCR_ILE, LPCR_ILE); - kvm_for_each_vcpu(n, v, kvm) - v->arch.intr_msr |= MSR_LE; - mutex_unlock(&kvm->lock); - kick_all_cpus_sync(); - return H_SUCCESS; - - default: - return H_UNSUPPORTED_FLAG_START; - } default: - return H_P2; + return H_TOO_HARD; } } @@ -714,6 +662,8 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) kvmppc_get_gpr(vcpu, 5), kvmppc_get_gpr(vcpu, 6), kvmppc_get_gpr(vcpu, 7)); + if (ret == H_TOO_HARD) + return RESUME_HOST; break; case H_XIRR: @@ -915,6 +865,27 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr) spin_lock(&vc->lock); /* + * If ILE (interrupt little-endian) has changed, update the + * MSR_LE bit in the intr_msr for each vcpu in this vcore. + */ + if ((new_lpcr & LPCR_ILE) != (vc->lpcr & LPCR_ILE)) { + struct kvm *kvm = vcpu->kvm; + struct kvm_vcpu *vcpu; + int i; + + mutex_lock(&kvm->lock); + kvm_for_each_vcpu(i, vcpu, kvm) { + if (vcpu->arch.vcore != vc) + continue; + if (new_lpcr & LPCR_ILE) + vcpu->arch.intr_msr |= MSR_LE; + else + vcpu->arch.intr_msr &= ~MSR_LE; + } + mutex_unlock(&kvm->lock); + } + + /* * Userspace can only modify DPFD (default prefetch depth), * ILE (interrupt little-endian) and TC (translation control). * On POWER8 userspace can also modify AIL (alt. interrupt loc.) |