Merge tag 'kvm-s390-next-5.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / arch / s390 / kvm / kvm-s390.c
index 9cba1e5d033bd1ec967b22729a44847e46ed1f7f..d7ff30e45589935890ad1c1f67c0f36eaa4d480e 100644 (file)
@@ -529,6 +529,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_S390_CMMA_MIGRATION:
        case KVM_CAP_S390_AIS:
        case KVM_CAP_S390_AIS_MIGRATION:
+       case KVM_CAP_S390_VCPU_RESETS:
                r = 1;
                break;
        case KVM_CAP_S390_HPAGE_1M:
@@ -2700,11 +2701,6 @@ static int sca_can_add_vcpu(struct kvm *kvm, unsigned int id)
        return rc == 0 && id < KVM_S390_ESCA_CPU_SLOTS;
 }
 
-int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
-{
-       return 0;
-}
-
 /* needs disabled preemption to protect from TOD sync and vcpu_load/put */
 static void __start_cpu_timer_accounting(struct kvm_vcpu *vcpu)
 {
@@ -2813,35 +2809,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 
 }
 
-static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
-{
-       /* this equals initial cpu reset in pop, but we don't switch to ESA */
-       vcpu->arch.sie_block->gpsw.mask = 0UL;
-       vcpu->arch.sie_block->gpsw.addr = 0UL;
-       kvm_s390_set_prefix(vcpu, 0);
-       kvm_s390_set_cpu_timer(vcpu, 0);
-       vcpu->arch.sie_block->ckc       = 0UL;
-       vcpu->arch.sie_block->todpr     = 0;
-       memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64));
-       vcpu->arch.sie_block->gcr[0]  = CR0_UNUSED_56 |
-                                       CR0_INTERRUPT_KEY_SUBMASK |
-                                       CR0_MEASUREMENT_ALERT_SUBMASK;
-       vcpu->arch.sie_block->gcr[14] = CR14_UNUSED_32 |
-                                       CR14_UNUSED_33 |
-                                       CR14_EXTERNAL_DAMAGE_SUBMASK;
-       /* make sure the new fpc will be lazily loaded */
-       save_fpu_regs();
-       current->thread.fpu.fpc = 0;
-       vcpu->arch.sie_block->gbea = 1;
-       vcpu->arch.sie_block->pp = 0;
-       vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
-       vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
-       kvm_clear_async_pf_completion_queue(vcpu);
-       if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
-               kvm_s390_vcpu_stop(vcpu);
-       kvm_s390_clear_local_irqs(vcpu);
-}
-
 void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
 {
        mutex_lock(&vcpu->kvm->lock);
@@ -2931,7 +2898,7 @@ static void kvm_s390_vcpu_setup_model(struct kvm_vcpu *vcpu)
                vcpu->arch.sie_block->fac = (u32)(u64) model->fac_list;
 }
 
-int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
+static int kvm_s390_vcpu_setup(struct kvm_vcpu *vcpu)
 {
        int rc = 0;
 
@@ -3070,8 +3037,14 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
                 vcpu->vcpu_id, vcpu, vcpu->arch.sie_block);
        trace_kvm_s390_create_vcpu(vcpu->vcpu_id, vcpu, vcpu->arch.sie_block);
 
+       rc = kvm_s390_vcpu_setup(vcpu);
+       if (rc)
+               goto out_ucontrol_uninit;
        return 0;
 
+out_ucontrol_uninit:
+       if (kvm_is_ucontrol(vcpu->kvm))
+               gmap_remove(vcpu->arch.gmap);
 out_free_sie_block:
        free_page((unsigned long)(vcpu->arch.sie_block));
        return rc;
@@ -3278,10 +3251,53 @@ static int kvm_arch_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu,
        return r;
 }
 
-static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
+static void kvm_arch_vcpu_ioctl_normal_reset(struct kvm_vcpu *vcpu)
 {
-       kvm_s390_vcpu_initial_reset(vcpu);
-       return 0;
+       vcpu->arch.sie_block->gpsw.mask &= ~PSW_MASK_RI;
+       vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
+       memset(vcpu->run->s.regs.riccb, 0, sizeof(vcpu->run->s.regs.riccb));
+
+       kvm_clear_async_pf_completion_queue(vcpu);
+       if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
+               kvm_s390_vcpu_stop(vcpu);
+       kvm_s390_clear_local_irqs(vcpu);
+}
+
+static void kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
+{
+       /* Initial reset is a superset of the normal reset */
+       kvm_arch_vcpu_ioctl_normal_reset(vcpu);
+
+       /* this equals initial cpu reset in pop, but we don't switch to ESA */
+       vcpu->arch.sie_block->gpsw.mask = 0;
+       vcpu->arch.sie_block->gpsw.addr = 0;
+       kvm_s390_set_prefix(vcpu, 0);
+       kvm_s390_set_cpu_timer(vcpu, 0);
+       vcpu->arch.sie_block->ckc = 0;
+       vcpu->arch.sie_block->todpr = 0;
+       memset(vcpu->arch.sie_block->gcr, 0, sizeof(vcpu->arch.sie_block->gcr));
+       vcpu->arch.sie_block->gcr[0] = CR0_INITIAL_MASK;
+       vcpu->arch.sie_block->gcr[14] = CR14_INITIAL_MASK;
+       vcpu->run->s.regs.fpc = 0;
+       vcpu->arch.sie_block->gbea = 1;
+       vcpu->arch.sie_block->pp = 0;
+       vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
+}
+
+static void kvm_arch_vcpu_ioctl_clear_reset(struct kvm_vcpu *vcpu)
+{
+       struct kvm_sync_regs *regs = &vcpu->run->s.regs;
+
+       /* Clear reset is a superset of the initial reset */
+       kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+
+       memset(&regs->gprs, 0, sizeof(regs->gprs));
+       memset(&regs->vrs, 0, sizeof(regs->vrs));
+       memset(&regs->acrs, 0, sizeof(regs->acrs));
+       memset(&regs->gscb, 0, sizeof(regs->gscb));
+
+       regs->etoken = 0;
+       regs->etoken_extension = 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
@@ -4342,7 +4358,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
        switch (ioctl) {
        case KVM_S390_STORE_STATUS:
                idx = srcu_read_lock(&vcpu->kvm->srcu);
-               r = kvm_s390_vcpu_store_status(vcpu, arg);
+               r = kvm_s390_store_status_unloaded(vcpu, arg);
                srcu_read_unlock(&vcpu->kvm->srcu, idx);
                break;
        case KVM_S390_SET_INITIAL_PSW: {
@@ -4354,8 +4370,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
                break;
        }
+       case KVM_S390_CLEAR_RESET:
+               r = 0;
+               kvm_arch_vcpu_ioctl_clear_reset(vcpu);
+               break;
        case KVM_S390_INITIAL_RESET:
-               r = kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+               r = 0;
+               kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+               break;
+       case KVM_S390_NORMAL_RESET:
+               r = 0;
+               kvm_arch_vcpu_ioctl_normal_reset(vcpu);
                break;
        case KVM_SET_ONE_REG:
        case KVM_GET_ONE_REG: {