Merge branch 'akpm' (patches from Andrew)
[deliverable/linux.git] / arch / s390 / kvm / interrupt.c
index 84efc2ba6a90555de35f6c3b78a47ab455b3beb6..24524c0f3ef88b2987c7bc1d54d924e811428286 100644 (file)
@@ -28,9 +28,6 @@
 #include "gaccess.h"
 #include "trace-s390.h"
 
-#define IOINT_SCHID_MASK 0x0000ffff
-#define IOINT_SSID_MASK 0x00030000
-#define IOINT_CSSID_MASK 0x03fc0000
 #define PFAULT_INIT 0x0600
 #define PFAULT_DONE 0x0680
 #define VIRTIO_PARAM 0x0d00
@@ -821,7 +818,14 @@ static int __must_check __deliver_io(struct kvm_vcpu *vcpu,
                                        struct kvm_s390_interrupt_info,
                                        list);
        if (inti) {
-               VCPU_EVENT(vcpu, 4, "deliver: I/O 0x%llx", inti->type);
+               if (inti->type & KVM_S390_INT_IO_AI_MASK)
+                       VCPU_EVENT(vcpu, 4, "%s", "deliver: I/O (AI)");
+               else
+                       VCPU_EVENT(vcpu, 4, "deliver: I/O %x ss %x schid %04x",
+                       inti->io.subchannel_id >> 8,
+                       inti->io.subchannel_id >> 1 & 0x3,
+                       inti->io.subchannel_nr);
+
                vcpu->stat.deliver_io_int++;
                trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
                                inti->type,
@@ -977,6 +981,11 @@ no_timer:
 
 void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu)
 {
+       /*
+        * We cannot move this into the if, as the CPU might be already
+        * in kvm_vcpu_block without having the waitqueue set (polling)
+        */
+       vcpu->valid_wakeup = true;
        if (swait_active(&vcpu->wq)) {
                /*
                 * The vcpu gave up the cpu voluntarily, mark it as a good
@@ -986,6 +995,11 @@ void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu)
                swake_up(&vcpu->wq);
                vcpu->stat.halt_wakeup++;
        }
+       /*
+        * The VCPU might not be sleeping but is executing the VSIE. Let's
+        * kick it, so it leaves the SIE to process the request.
+        */
+       kvm_s390_vsie_kick(vcpu);
 }
 
 enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer)
@@ -1410,6 +1424,13 @@ static int __inject_io(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
        }
        fi->counters[FIRQ_CNTR_IO] += 1;
 
+       if (inti->type & KVM_S390_INT_IO_AI_MASK)
+               VM_EVENT(kvm, 4, "%s", "inject: I/O (AI)");
+       else
+               VM_EVENT(kvm, 4, "inject: I/O %x ss %x schid %04x",
+                       inti->io.subchannel_id >> 8,
+                       inti->io.subchannel_id >> 1 & 0x3,
+                       inti->io.subchannel_nr);
        isc = int_word_to_isc(inti->io.io_int_word);
        list = &fi->lists[FIRQ_LIST_IO_ISC_0 + isc];
        list_add_tail(&inti->list, list);
@@ -1526,13 +1547,6 @@ int kvm_s390_inject_vm(struct kvm *kvm,
                inti->mchk.mcic = s390int->parm64;
                break;
        case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
-               if (inti->type & KVM_S390_INT_IO_AI_MASK)
-                       VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)");
-               else
-                       VM_EVENT(kvm, 5, "inject: I/O css %x ss %x schid %04x",
-                                s390int->type & IOINT_CSSID_MASK,
-                                s390int->type & IOINT_SSID_MASK,
-                                s390int->type & IOINT_SCHID_MASK);
                inti->io.subchannel_id = s390int->parm >> 16;
                inti->io.subchannel_nr = s390int->parm & 0x0000ffffu;
                inti->io.io_int_parm = s390int->parm64 >> 32;
@@ -2034,6 +2048,27 @@ static int modify_io_adapter(struct kvm_device *dev,
        return ret;
 }
 
+static int clear_io_irq(struct kvm *kvm, struct kvm_device_attr *attr)
+
+{
+       const u64 isc_mask = 0xffUL << 24; /* all iscs set */
+       u32 schid;
+
+       if (attr->flags)
+               return -EINVAL;
+       if (attr->attr != sizeof(schid))
+               return -EINVAL;
+       if (copy_from_user(&schid, (void __user *) attr->addr, sizeof(schid)))
+               return -EFAULT;
+       kfree(kvm_s390_get_io_int(kvm, isc_mask, schid));
+       /*
+        * If userspace is conforming to the architecture, we can have at most
+        * one pending I/O interrupt per subchannel, so this is effectively a
+        * clear all.
+        */
+       return 0;
+}
+
 static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
 {
        int r = 0;
@@ -2067,6 +2102,9 @@ static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
        case KVM_DEV_FLIC_ADAPTER_MODIFY:
                r = modify_io_adapter(dev, attr);
                break;
+       case KVM_DEV_FLIC_CLEAR_IO_IRQ:
+               r = clear_io_irq(dev->kvm, attr);
+               break;
        default:
                r = -EINVAL;
        }
@@ -2074,6 +2112,23 @@ static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
        return r;
 }
 
+static int flic_has_attr(struct kvm_device *dev,
+                            struct kvm_device_attr *attr)
+{
+       switch (attr->group) {
+       case KVM_DEV_FLIC_GET_ALL_IRQS:
+       case KVM_DEV_FLIC_ENQUEUE:
+       case KVM_DEV_FLIC_CLEAR_IRQS:
+       case KVM_DEV_FLIC_APF_ENABLE:
+       case KVM_DEV_FLIC_APF_DISABLE_WAIT:
+       case KVM_DEV_FLIC_ADAPTER_REGISTER:
+       case KVM_DEV_FLIC_ADAPTER_MODIFY:
+       case KVM_DEV_FLIC_CLEAR_IO_IRQ:
+               return 0;
+       }
+       return -ENXIO;
+}
+
 static int flic_create(struct kvm_device *dev, u32 type)
 {
        if (!dev)
@@ -2095,6 +2150,7 @@ struct kvm_device_ops kvm_flic_ops = {
        .name = "kvm-flic",
        .get_attr = flic_get_attr,
        .set_attr = flic_set_attr,
+       .has_attr = flic_has_attr,
        .create = flic_create,
        .destroy = flic_destroy,
 };
@@ -2190,7 +2246,8 @@ static int set_adapter_int(struct kvm_kernel_irq_routing_entry *e,
        return ret;
 }
 
-int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
+int kvm_set_routing_entry(struct kvm *kvm,
+                         struct kvm_kernel_irq_routing_entry *e,
                          const struct kvm_irq_routing_entry *ue)
 {
        int ret;
This page took 0.03969 seconds and 5 git commands to generate.