]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - arch/s390/kvm/interrupt.c
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[mirror_ubuntu-artful-kernel.git] / arch / s390 / kvm / interrupt.c
index 2d120fef7d90d915e33d7f19cb0ba39e9a6a264e..a619ddae610da2c0fabaf66a9a123d1572b51f9c 100644 (file)
@@ -251,8 +251,13 @@ static unsigned long deliverable_irqs(struct kvm_vcpu *vcpu)
                __clear_bit(IRQ_PEND_EXT_SERVICE, &active_mask);
        if (psw_mchk_disabled(vcpu))
                active_mask &= ~IRQ_PEND_MCHK_MASK;
+       /*
+        * Check both floating and local interrupt's cr14 because
+        * bit IRQ_PEND_MCHK_REP could be set in both cases.
+        */
        if (!(vcpu->arch.sie_block->gcr[14] &
-             vcpu->kvm->arch.float_int.mchk.cr14))
+          (vcpu->kvm->arch.float_int.mchk.cr14 |
+          vcpu->arch.local_int.irq.mchk.cr14)))
                __clear_bit(IRQ_PEND_MCHK_REP, &active_mask);
 
        /*
@@ -1876,6 +1881,28 @@ out:
        return ret < 0 ? ret : n;
 }
 
+static int flic_ais_mode_get_all(struct kvm *kvm, struct kvm_device_attr *attr)
+{
+       struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int;
+       struct kvm_s390_ais_all ais;
+
+       if (attr->attr < sizeof(ais))
+               return -EINVAL;
+
+       if (!test_kvm_facility(kvm, 72))
+               return -ENOTSUPP;
+
+       mutex_lock(&fi->ais_lock);
+       ais.simm = fi->simm;
+       ais.nimm = fi->nimm;
+       mutex_unlock(&fi->ais_lock);
+
+       if (copy_to_user((void __user *)attr->addr, &ais, sizeof(ais)))
+               return -EFAULT;
+
+       return 0;
+}
+
 static int flic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
 {
        int r;
@@ -1885,6 +1912,9 @@ static int flic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
                r = get_all_floating_irqs(dev->kvm, (u8 __user *) attr->addr,
                                          attr->attr);
                break;
+       case KVM_DEV_FLIC_AISM_ALL:
+               r = flic_ais_mode_get_all(dev->kvm, attr);
+               break;
        default:
                r = -EINVAL;
        }
@@ -2235,6 +2265,25 @@ static int flic_inject_airq(struct kvm *kvm, struct kvm_device_attr *attr)
        return kvm_s390_inject_airq(kvm, adapter);
 }
 
+static int flic_ais_mode_set_all(struct kvm *kvm, struct kvm_device_attr *attr)
+{
+       struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int;
+       struct kvm_s390_ais_all ais;
+
+       if (!test_kvm_facility(kvm, 72))
+               return -ENOTSUPP;
+
+       if (copy_from_user(&ais, (void __user *)attr->addr, sizeof(ais)))
+               return -EFAULT;
+
+       mutex_lock(&fi->ais_lock);
+       fi->simm = ais.simm;
+       fi->nimm = ais.nimm;
+       mutex_unlock(&fi->ais_lock);
+
+       return 0;
+}
+
 static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
 {
        int r = 0;
@@ -2277,6 +2326,9 @@ static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
        case KVM_DEV_FLIC_AIRQ_INJECT:
                r = flic_inject_airq(dev->kvm, attr);
                break;
+       case KVM_DEV_FLIC_AISM_ALL:
+               r = flic_ais_mode_set_all(dev->kvm, attr);
+               break;
        default:
                r = -EINVAL;
        }
@@ -2298,6 +2350,7 @@ static int flic_has_attr(struct kvm_device *dev,
        case KVM_DEV_FLIC_CLEAR_IO_IRQ:
        case KVM_DEV_FLIC_AISM:
        case KVM_DEV_FLIC_AIRQ_INJECT:
+       case KVM_DEV_FLIC_AISM_ALL:
                return 0;
        }
        return -ENXIO;
@@ -2415,6 +2468,42 @@ static int set_adapter_int(struct kvm_kernel_irq_routing_entry *e,
        return ret;
 }
 
+/*
+ * Inject the machine check to the guest.
+ */
+void kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu,
+                                    struct mcck_volatile_info *mcck_info)
+{
+       struct kvm_s390_interrupt_info inti;
+       struct kvm_s390_irq irq;
+       struct kvm_s390_mchk_info *mchk;
+       union mci mci;
+       __u64 cr14 = 0;         /* upper bits are not used */
+
+       mci.val = mcck_info->mcic;
+       if (mci.sr)
+               cr14 |= MCCK_CR14_RECOVERY_SUB_MASK;
+       if (mci.dg)
+               cr14 |= MCCK_CR14_DEGRAD_SUB_MASK;
+       if (mci.w)
+               cr14 |= MCCK_CR14_WARN_SUB_MASK;
+
+       mchk = mci.ck ? &inti.mchk : &irq.u.mchk;
+       mchk->cr14 = cr14;
+       mchk->mcic = mcck_info->mcic;
+       mchk->ext_damage_code = mcck_info->ext_damage_code;
+       mchk->failing_storage_address = mcck_info->failing_storage_address;
+       if (mci.ck) {
+               /* Inject the floating machine check */
+               inti.type = KVM_S390_MCHK;
+               WARN_ON_ONCE(__inject_vm(vcpu->kvm, &inti));
+       } else {
+               /* Inject the machine check to specified vcpu */
+               irq.type = KVM_S390_MCHK;
+               WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &irq));
+       }
+}
+
 int kvm_set_routing_entry(struct kvm *kvm,
                          struct kvm_kernel_irq_routing_entry *e,
                          const struct kvm_irq_routing_entry *ue)