diff options
author | Christian Borntraeger <borntraeger@de.ibm.com> | 2016-11-22 03:29:38 -0500 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2016-11-22 13:32:35 -0500 |
commit | e1788bb995befed5831c99cee6527dfb080a46c0 (patch) | |
tree | 62cfe675eaef6a446b0c25724fcdee6be5257051 | |
parent | 31d8b8d41a7e3e8db081972a63ef1de276ef8ab4 (diff) |
KVM: s390: handle floating point registers in the run ioctl not in vcpu_put/load
Right now we switch the host fprs/vrs in kvm_arch_vcpu_load and switch
back in kvm_arch_vcpu_put. This process is already optimized
since commit 9977e886cbbc7 ("s390/kernel: lazy restore fpu registers")
avoiding double save/restores on schedule. We still reload the pointers
and test the guest fpc on each context switch, though.
We can minimize the cost of vcpu_load/put by doing the test in the
VCPU_RUN ioctl itself. As most VCPU threads almost never exit to
userspace in the common fast path, this allows to avoid this overhead
for the common case (eventfd driven I/O, all exits including sleep
handled in the kernel) - making kvm_arch_vcpu_load/put basically
disappear in perf top.
Also adapt the fpu get/set ioctls.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 45 |
1 files changed, 21 insertions, 24 deletions
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 4105e1ea8dda..bec71e902be3 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -1812,19 +1812,6 @@ __u64 kvm_s390_get_cpu_timer(struct kvm_vcpu *vcpu) | |||
1812 | 1812 | ||
1813 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | 1813 | void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) |
1814 | { | 1814 | { |
1815 | /* Save host register state */ | ||
1816 | save_fpu_regs(); | ||
1817 | vcpu->arch.host_fpregs.fpc = current->thread.fpu.fpc; | ||
1818 | vcpu->arch.host_fpregs.regs = current->thread.fpu.regs; | ||
1819 | |||
1820 | if (MACHINE_HAS_VX) | ||
1821 | current->thread.fpu.regs = vcpu->run->s.regs.vrs; | ||
1822 | else | ||
1823 | current->thread.fpu.regs = vcpu->run->s.regs.fprs; | ||
1824 | current->thread.fpu.fpc = vcpu->run->s.regs.fpc; | ||
1825 | if (test_fp_ctl(current->thread.fpu.fpc)) | ||
1826 | /* User space provided an invalid FPC, let's clear it */ | ||
1827 | current->thread.fpu.fpc = 0; | ||
1828 | 1815 | ||
1829 | gmap_enable(vcpu->arch.enabled_gmap); | 1816 | gmap_enable(vcpu->arch.enabled_gmap); |
1830 | atomic_or(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); | 1817 | atomic_or(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); |
@@ -1842,13 +1829,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) | |||
1842 | vcpu->arch.enabled_gmap = gmap_get_enabled(); | 1829 | vcpu->arch.enabled_gmap = gmap_get_enabled(); |
1843 | gmap_disable(vcpu->arch.enabled_gmap); | 1830 | gmap_disable(vcpu->arch.enabled_gmap); |
1844 | 1831 | ||
1845 | /* Save guest register state */ | ||
1846 | save_fpu_regs(); | ||
1847 | vcpu->run->s.regs.fpc = current->thread.fpu.fpc; | ||
1848 | |||
1849 | /* Restore host register state */ | ||
1850 | current->thread.fpu.fpc = vcpu->arch.host_fpregs.fpc; | ||
1851 | current->thread.fpu.regs = vcpu->arch.host_fpregs.regs; | ||
1852 | } | 1832 | } |
1853 | 1833 | ||
1854 | static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) | 1834 | static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) |
@@ -2251,11 +2231,9 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, | |||
2251 | 2231 | ||
2252 | int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | 2232 | int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) |
2253 | { | 2233 | { |
2254 | /* make sure the new values will be lazily loaded */ | ||
2255 | save_fpu_regs(); | ||
2256 | if (test_fp_ctl(fpu->fpc)) | 2234 | if (test_fp_ctl(fpu->fpc)) |
2257 | return -EINVAL; | 2235 | return -EINVAL; |
2258 | current->thread.fpu.fpc = fpu->fpc; | 2236 | vcpu->run->s.regs.fpc = fpu->fpc; |
2259 | if (MACHINE_HAS_VX) | 2237 | if (MACHINE_HAS_VX) |
2260 | convert_fp_to_vx((__vector128 *) vcpu->run->s.regs.vrs, | 2238 | convert_fp_to_vx((__vector128 *) vcpu->run->s.regs.vrs, |
2261 | (freg_t *) fpu->fprs); | 2239 | (freg_t *) fpu->fprs); |
@@ -2273,7 +2251,7 @@ int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | |||
2273 | (__vector128 *) vcpu->run->s.regs.vrs); | 2251 | (__vector128 *) vcpu->run->s.regs.vrs); |
2274 | else | 2252 | else |
2275 | memcpy(fpu->fprs, vcpu->run->s.regs.fprs, sizeof(fpu->fprs)); | 2253 | memcpy(fpu->fprs, vcpu->run->s.regs.fprs, sizeof(fpu->fprs)); |
2276 | fpu->fpc = current->thread.fpu.fpc; | 2254 | fpu->fpc = vcpu->run->s.regs.fpc; |
2277 | return 0; | 2255 | return 0; |
2278 | } | 2256 | } |
2279 | 2257 | ||
@@ -2736,6 +2714,18 @@ static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2736 | } | 2714 | } |
2737 | save_access_regs(vcpu->arch.host_acrs); | 2715 | save_access_regs(vcpu->arch.host_acrs); |
2738 | restore_access_regs(vcpu->run->s.regs.acrs); | 2716 | restore_access_regs(vcpu->run->s.regs.acrs); |
2717 | /* save host (userspace) fprs/vrs */ | ||
2718 | save_fpu_regs(); | ||
2719 | vcpu->arch.host_fpregs.fpc = current->thread.fpu.fpc; | ||
2720 | vcpu->arch.host_fpregs.regs = current->thread.fpu.regs; | ||
2721 | if (MACHINE_HAS_VX) | ||
2722 | current->thread.fpu.regs = vcpu->run->s.regs.vrs; | ||
2723 | else | ||
2724 | current->thread.fpu.regs = vcpu->run->s.regs.fprs; | ||
2725 | current->thread.fpu.fpc = vcpu->run->s.regs.fpc; | ||
2726 | if (test_fp_ctl(current->thread.fpu.fpc)) | ||
2727 | /* User space provided an invalid FPC, let's clear it */ | ||
2728 | current->thread.fpu.fpc = 0; | ||
2739 | 2729 | ||
2740 | kvm_run->kvm_dirty_regs = 0; | 2730 | kvm_run->kvm_dirty_regs = 0; |
2741 | } | 2731 | } |
@@ -2756,6 +2746,13 @@ static void store_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
2756 | kvm_run->s.regs.pfc = vcpu->arch.pfault_compare; | 2746 | kvm_run->s.regs.pfc = vcpu->arch.pfault_compare; |
2757 | save_access_regs(vcpu->run->s.regs.acrs); | 2747 | save_access_regs(vcpu->run->s.regs.acrs); |
2758 | restore_access_regs(vcpu->arch.host_acrs); | 2748 | restore_access_regs(vcpu->arch.host_acrs); |
2749 | /* Save guest register state */ | ||
2750 | save_fpu_regs(); | ||
2751 | vcpu->run->s.regs.fpc = current->thread.fpu.fpc; | ||
2752 | /* Restore will be done lazily at return */ | ||
2753 | current->thread.fpu.fpc = vcpu->arch.host_fpregs.fpc; | ||
2754 | current->thread.fpu.regs = vcpu->arch.host_fpregs.regs; | ||
2755 | |||
2759 | } | 2756 | } |
2760 | 2757 | ||
2761 | int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 2758 | int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |