]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/s390/kvm/interrupt.c
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetoot...
[karo-tx-linux.git] / arch / s390 / kvm / interrupt.c
index 24524c0f3ef88b2987c7bc1d54d924e811428286..be4db07f70d385af8f8b1230943eb8cbbd747d0a 100644 (file)
@@ -24,6 +24,8 @@
 #include <asm/sclp.h>
 #include <asm/isc.h>
 #include <asm/gmap.h>
+#include <asm/switch_to.h>
+#include <asm/nmi.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
 #include "trace-s390.h"
@@ -40,6 +42,7 @@ static int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id)
        if (!(atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_ECALL_PEND))
                return 0;
 
+       BUG_ON(!kvm_s390_use_sca_entries());
        read_lock(&vcpu->kvm->arch.sca_lock);
        if (vcpu->kvm->arch.use_esca) {
                struct esca_block *sca = vcpu->kvm->arch.sca;
@@ -68,6 +71,7 @@ static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id)
 {
        int expect, rc;
 
+       BUG_ON(!kvm_s390_use_sca_entries());
        read_lock(&vcpu->kvm->arch.sca_lock);
        if (vcpu->kvm->arch.use_esca) {
                struct esca_block *sca = vcpu->kvm->arch.sca;
@@ -109,6 +113,8 @@ static void sca_clear_ext_call(struct kvm_vcpu *vcpu)
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
        int rc, expect;
 
+       if (!kvm_s390_use_sca_entries())
+               return;
        atomic_andnot(CPUSTAT_ECALL_PEND, li->cpuflags);
        read_lock(&vcpu->kvm->arch.sca_lock);
        if (vcpu->kvm->arch.use_esca) {
@@ -400,12 +406,78 @@ static int __must_check __deliver_pfault_init(struct kvm_vcpu *vcpu)
        return rc ? -EFAULT : 0;
 }
 
+static int __write_machine_check(struct kvm_vcpu *vcpu,
+                                struct kvm_s390_mchk_info *mchk)
+{
+       unsigned long ext_sa_addr;
+       freg_t fprs[NUM_FPRS];
+       union mci mci;
+       int rc;
+
+       mci.val = mchk->mcic;
+       /* take care of lazy register loading via vcpu load/put */
+       save_fpu_regs();
+       save_access_regs(vcpu->run->s.regs.acrs);
+
+       /* Extended save area */
+       rc = read_guest_lc(vcpu, __LC_VX_SAVE_AREA_ADDR, &ext_sa_addr,
+                           sizeof(unsigned long));
+       /* Only bits 0-53 are used for address formation */
+       ext_sa_addr &= ~0x3ffUL;
+       if (!rc && mci.vr && ext_sa_addr && test_kvm_facility(vcpu->kvm, 129)) {
+               if (write_guest_abs(vcpu, ext_sa_addr, vcpu->run->s.regs.vrs,
+                                   512))
+                       mci.vr = 0;
+       } else {
+               mci.vr = 0;
+       }
+
+       /* General interruption information */
+       rc |= put_guest_lc(vcpu, 1, (u8 __user *) __LC_AR_MODE_ID);
+       rc |= write_guest_lc(vcpu, __LC_MCK_OLD_PSW,
+                            &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+       rc |= read_guest_lc(vcpu, __LC_MCK_NEW_PSW,
+                           &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
+       rc |= put_guest_lc(vcpu, mci.val, (u64 __user *) __LC_MCCK_CODE);
+
+       /* Register-save areas */
+       if (MACHINE_HAS_VX) {
+               convert_vx_to_fp(fprs, (__vector128 *) vcpu->run->s.regs.vrs);
+               rc |= write_guest_lc(vcpu, __LC_FPREGS_SAVE_AREA, fprs, 128);
+       } else {
+               rc |= write_guest_lc(vcpu, __LC_FPREGS_SAVE_AREA,
+                                    vcpu->run->s.regs.fprs, 128);
+       }
+       rc |= write_guest_lc(vcpu, __LC_GPREGS_SAVE_AREA,
+                            vcpu->run->s.regs.gprs, 128);
+       rc |= put_guest_lc(vcpu, current->thread.fpu.fpc,
+                          (u32 __user *) __LC_FP_CREG_SAVE_AREA);
+       rc |= put_guest_lc(vcpu, vcpu->arch.sie_block->todpr,
+                          (u32 __user *) __LC_TOD_PROGREG_SAVE_AREA);
+       rc |= put_guest_lc(vcpu, kvm_s390_get_cpu_timer(vcpu),
+                          (u64 __user *) __LC_CPU_TIMER_SAVE_AREA);
+       rc |= put_guest_lc(vcpu, vcpu->arch.sie_block->ckc >> 8,
+                          (u64 __user *) __LC_CLOCK_COMP_SAVE_AREA);
+       rc |= write_guest_lc(vcpu, __LC_AREGS_SAVE_AREA,
+                            &vcpu->run->s.regs.acrs, 64);
+       rc |= write_guest_lc(vcpu, __LC_CREGS_SAVE_AREA,
+                            &vcpu->arch.sie_block->gcr, 128);
+
+       /* Extended interruption information */
+       rc |= put_guest_lc(vcpu, mchk->ext_damage_code,
+                          (u32 __user *) __LC_EXT_DAMAGE_CODE);
+       rc |= put_guest_lc(vcpu, mchk->failing_storage_address,
+                          (u64 __user *) __LC_MCCK_FAIL_STOR_ADDR);
+       rc |= write_guest_lc(vcpu, __LC_PSW_SAVE_AREA, &mchk->fixed_logout,
+                            sizeof(mchk->fixed_logout));
+       return rc ? -EFAULT : 0;
+}
+
 static int __must_check __deliver_machine_check(struct kvm_vcpu *vcpu)
 {
        struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
        struct kvm_s390_mchk_info mchk = {};
-       unsigned long adtl_status_addr;
        int deliver = 0;
        int rc = 0;
 
@@ -446,29 +518,9 @@ static int __must_check __deliver_machine_check(struct kvm_vcpu *vcpu)
                trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
                                                 KVM_S390_MCHK,
                                                 mchk.cr14, mchk.mcic);
-
-               rc  = kvm_s390_vcpu_store_status(vcpu,
-                                                KVM_S390_STORE_STATUS_PREFIXED);
-               rc |= read_guest_lc(vcpu, __LC_VX_SAVE_AREA_ADDR,
-                                   &adtl_status_addr,
-                                   sizeof(unsigned long));
-               rc |= kvm_s390_vcpu_store_adtl_status(vcpu,
-                                                     adtl_status_addr);
-               rc |= put_guest_lc(vcpu, mchk.mcic,
-                                  (u64 __user *) __LC_MCCK_CODE);
-               rc |= put_guest_lc(vcpu, mchk.failing_storage_address,
-                                  (u64 __user *) __LC_MCCK_FAIL_STOR_ADDR);
-               rc |= write_guest_lc(vcpu, __LC_PSW_SAVE_AREA,
-                                    &mchk.fixed_logout,
-                                    sizeof(mchk.fixed_logout));
-               rc |= write_guest_lc(vcpu, __LC_MCK_OLD_PSW,
-                                    &vcpu->arch.sie_block->gpsw,
-                                    sizeof(psw_t));
-               rc |= read_guest_lc(vcpu, __LC_MCK_NEW_PSW,
-                                   &vcpu->arch.sie_block->gpsw,
-                                   sizeof(psw_t));
+               rc = __write_machine_check(vcpu, &mchk);
        }
-       return rc ? -EFAULT : 0;
+       return rc;
 }
 
 static int __must_check __deliver_restart(struct kvm_vcpu *vcpu)