]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/s390/kvm/kvm-s390.c
KVM: s390: Introduce new structures
[karo-tx-linux.git] / arch / s390 / kvm / kvm-s390.c
index 8fe2f1c722dcabe22b3b3731bdce5e22092703db..c2683529b25c97dab521490896f0645105342a12 100644 (file)
@@ -283,6 +283,8 @@ static void kvm_s390_sync_dirty_log(struct kvm *kvm,
 }
 
 /* Section: vm related */
+static void sca_del_vcpu(struct kvm_vcpu *vcpu);
+
 /*
  * Get (and clear) the dirty memory log for a memory slot.
  */
@@ -342,12 +344,16 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
                r = 0;
                break;
        case KVM_CAP_S390_VECTOR_REGISTERS:
-               if (MACHINE_HAS_VX) {
+               mutex_lock(&kvm->lock);
+               if (atomic_read(&kvm->online_vcpus)) {
+                       r = -EBUSY;
+               } else if (MACHINE_HAS_VX) {
                        set_kvm_facility(kvm->arch.model.fac->mask, 129);
                        set_kvm_facility(kvm->arch.model.fac->list, 129);
                        r = 0;
                } else
                        r = -EINVAL;
+               mutex_unlock(&kvm->lock);
                VM_EVENT(kvm, 3, "ENABLE: CAP_S390_VECTOR_REGISTERS %s",
                         r ? "(not available)" : "(success)");
                break;
@@ -1094,14 +1100,15 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 
        rc = -ENOMEM;
 
-       kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL);
+       kvm->arch.sca = (struct bsca_block *) get_zeroed_page(GFP_KERNEL);
        if (!kvm->arch.sca)
                goto out_err;
        spin_lock(&kvm_lock);
        sca_offset += 16;
-       if (sca_offset + sizeof(struct sca_block) > PAGE_SIZE)
+       if (sca_offset + sizeof(struct bsca_block) > PAGE_SIZE)
                sca_offset = 0;
-       kvm->arch.sca = (struct sca_block *) ((char *) kvm->arch.sca + sca_offset);
+       kvm->arch.sca = (struct bsca_block *)
+                       ((char *) kvm->arch.sca + sca_offset);
        spin_unlock(&kvm_lock);
 
        sprintf(debug_name, "kvm-%u", current->pid);
@@ -1184,13 +1191,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
        trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id);
        kvm_s390_clear_local_irqs(vcpu);
        kvm_clear_async_pf_completion_queue(vcpu);
-       if (!kvm_is_ucontrol(vcpu->kvm)) {
-               clear_bit(63 - vcpu->vcpu_id,
-                         (unsigned long *) &vcpu->kvm->arch.sca->mcn);
-               if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
-                   (__u64) vcpu->arch.sie_block)
-                       vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
-       }
+       if (!kvm_is_ucontrol(vcpu->kvm))
+               sca_del_vcpu(vcpu);
        smp_mb();
 
        if (kvm_is_ucontrol(vcpu->kvm))
@@ -1245,6 +1247,32 @@ static int __kvm_ucontrol_vcpu_init(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+static void sca_del_vcpu(struct kvm_vcpu *vcpu)
+{
+       struct bsca_block *sca = vcpu->kvm->arch.sca;
+
+       clear_bit_inv(vcpu->vcpu_id, (unsigned long *) &sca->mcn);
+       if (sca->cpu[vcpu->vcpu_id].sda == (__u64) vcpu->arch.sie_block)
+               sca->cpu[vcpu->vcpu_id].sda = 0;
+}
+
+static void sca_add_vcpu(struct kvm_vcpu *vcpu, struct kvm *kvm,
+                       unsigned int id)
+{
+       struct bsca_block *sca = kvm->arch.sca;
+
+       if (!sca->cpu[id].sda)
+               sca->cpu[id].sda = (__u64) vcpu->arch.sie_block;
+       vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32);
+       vcpu->arch.sie_block->scaol = (__u32)(__u64)sca;
+       set_bit_inv(id, (unsigned long *) &sca->mcn);
+}
+
+static int sca_can_add_vcpu(struct kvm *kvm, unsigned int id)
+{
+       return id < KVM_MAX_VCPUS;
+}
+
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
        vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
@@ -1461,7 +1489,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
        struct sie_page *sie_page;
        int rc = -EINVAL;
 
-       if (id >= KVM_MAX_VCPUS)
+       if (!sca_can_add_vcpu(kvm, id))
                goto out;
 
        rc = -ENOMEM;
@@ -1483,13 +1511,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
                        WARN_ON_ONCE(1);
                        goto out_free_cpu;
                }
-               if (!kvm->arch.sca->cpu[id].sda)
-                       kvm->arch.sca->cpu[id].sda =
-                               (__u64) vcpu->arch.sie_block;
-               vcpu->arch.sie_block->scaoh =
-                       (__u32)(((__u64)kvm->arch.sca) >> 32);
-               vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
-               set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
+               sca_add_vcpu(vcpu, kvm, id);
        }
 
        spin_lock_init(&vcpu->arch.local_int.lock);
@@ -2067,8 +2089,6 @@ static int vcpu_post_run_fault_in_sie(struct kvm_vcpu *vcpu)
 
 static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
 {
-       int rc = -1;
-
        VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
                   vcpu->arch.sie_block->icptcode);
        trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode);
@@ -2076,40 +2096,35 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
        if (guestdbg_enabled(vcpu))
                kvm_s390_restore_guest_per_regs(vcpu);
 
-       if (exit_reason >= 0) {
-               rc = 0;
+       memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16);
+
+       if (vcpu->arch.sie_block->icptcode > 0) {
+               int rc = kvm_handle_sie_intercept(vcpu);
+
+               if (rc != -EOPNOTSUPP)
+                       return rc;
+               vcpu->run->exit_reason = KVM_EXIT_S390_SIEIC;
+               vcpu->run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode;
+               vcpu->run->s390_sieic.ipa = vcpu->arch.sie_block->ipa;
+               vcpu->run->s390_sieic.ipb = vcpu->arch.sie_block->ipb;
+               return -EREMOTE;
+       } else if (exit_reason != -EFAULT) {
+               vcpu->stat.exit_null++;
+               return 0;
        } else if (kvm_is_ucontrol(vcpu->kvm)) {
                vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL;
                vcpu->run->s390_ucontrol.trans_exc_code =
                                                current->thread.gmap_addr;
                vcpu->run->s390_ucontrol.pgm_code = 0x10;
-               rc = -EREMOTE;
-
+               return -EREMOTE;
        } else if (current->thread.gmap_pfault) {
                trace_kvm_s390_major_guest_pfault(vcpu);
                current->thread.gmap_pfault = 0;
-               if (kvm_arch_setup_async_pf(vcpu)) {
-                       rc = 0;
-               } else {
-                       gpa_t gpa = current->thread.gmap_addr;
-                       rc = kvm_arch_fault_in_page(vcpu, gpa, 1);
-               }
-       }
-
-       if (rc == -1)
-               rc = vcpu_post_run_fault_in_sie(vcpu);
-
-       memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16);
-
-       if (rc == 0) {
-               if (kvm_is_ucontrol(vcpu->kvm))
-                       /* Don't exit for host interrupts. */
-                       rc = vcpu->arch.sie_block->icptcode ? -EOPNOTSUPP : 0;
-               else
-                       rc = kvm_handle_sie_intercept(vcpu);
+               if (kvm_arch_setup_async_pf(vcpu))
+                       return 0;
+               return kvm_arch_fault_in_page(vcpu, current->thread.gmap_addr, 1);
        }
-
-       return rc;
+       return vcpu_post_run_fault_in_sie(vcpu);
 }
 
 static int __vcpu_run(struct kvm_vcpu *vcpu)
@@ -2229,18 +2244,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                rc = 0;
        }
 
-       if (rc == -EOPNOTSUPP) {
-               /* intercept cannot be handled in-kernel, prepare kvm-run */
-               kvm_run->exit_reason         = KVM_EXIT_S390_SIEIC;
-               kvm_run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode;
-               kvm_run->s390_sieic.ipa      = vcpu->arch.sie_block->ipa;
-               kvm_run->s390_sieic.ipb      = vcpu->arch.sie_block->ipb;
-               rc = 0;
-       }
-
        if (rc == -EREMOTE) {
-               /* intercept was handled, but userspace support is needed
-                * kvm_run has been prepared by the handler */
+               /* userspace support is needed, kvm_run has been prepared */
                rc = 0;
        }