aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2014-01-21 16:45:05 +1100
committerEli Qiao <taget@linux.vnet.ibm.com>2014-01-22 10:26:26 +0800
commit6b49cdc53603dc9e85a26b3f821a1cdfd0ef444d (patch)
treef6905c81b65f3ff7328dadd165b7aa4cc09760ac
parentd0da4a50fa32a8cb006befd50ec7b147885e0b0e (diff)
downloadpowerkvm-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.c77
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.)