diff options
Diffstat (limited to 'arch/s390/kvm/interrupt.c')
-rw-r--r-- | arch/s390/kvm/interrupt.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 84efc2ba6a90..5a80af740d3e 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c | |||
@@ -977,6 +977,11 @@ no_timer: | |||
977 | 977 | ||
978 | void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu) | 978 | void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu) |
979 | { | 979 | { |
980 | /* | ||
981 | * We cannot move this into the if, as the CPU might be already | ||
982 | * in kvm_vcpu_block without having the waitqueue set (polling) | ||
983 | */ | ||
984 | vcpu->valid_wakeup = true; | ||
980 | if (swait_active(&vcpu->wq)) { | 985 | if (swait_active(&vcpu->wq)) { |
981 | /* | 986 | /* |
982 | * The vcpu gave up the cpu voluntarily, mark it as a good | 987 | * The vcpu gave up the cpu voluntarily, mark it as a good |
@@ -2034,6 +2039,27 @@ static int modify_io_adapter(struct kvm_device *dev, | |||
2034 | return ret; | 2039 | return ret; |
2035 | } | 2040 | } |
2036 | 2041 | ||
2042 | static int clear_io_irq(struct kvm *kvm, struct kvm_device_attr *attr) | ||
2043 | |||
2044 | { | ||
2045 | const u64 isc_mask = 0xffUL << 24; /* all iscs set */ | ||
2046 | u32 schid; | ||
2047 | |||
2048 | if (attr->flags) | ||
2049 | return -EINVAL; | ||
2050 | if (attr->attr != sizeof(schid)) | ||
2051 | return -EINVAL; | ||
2052 | if (copy_from_user(&schid, (void __user *) attr->addr, sizeof(schid))) | ||
2053 | return -EFAULT; | ||
2054 | kfree(kvm_s390_get_io_int(kvm, isc_mask, schid)); | ||
2055 | /* | ||
2056 | * If userspace is conforming to the architecture, we can have at most | ||
2057 | * one pending I/O interrupt per subchannel, so this is effectively a | ||
2058 | * clear all. | ||
2059 | */ | ||
2060 | return 0; | ||
2061 | } | ||
2062 | |||
2037 | static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) | 2063 | static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) |
2038 | { | 2064 | { |
2039 | int r = 0; | 2065 | int r = 0; |
@@ -2067,6 +2093,9 @@ static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) | |||
2067 | case KVM_DEV_FLIC_ADAPTER_MODIFY: | 2093 | case KVM_DEV_FLIC_ADAPTER_MODIFY: |
2068 | r = modify_io_adapter(dev, attr); | 2094 | r = modify_io_adapter(dev, attr); |
2069 | break; | 2095 | break; |
2096 | case KVM_DEV_FLIC_CLEAR_IO_IRQ: | ||
2097 | r = clear_io_irq(dev->kvm, attr); | ||
2098 | break; | ||
2070 | default: | 2099 | default: |
2071 | r = -EINVAL; | 2100 | r = -EINVAL; |
2072 | } | 2101 | } |
@@ -2074,6 +2103,23 @@ static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) | |||
2074 | return r; | 2103 | return r; |
2075 | } | 2104 | } |
2076 | 2105 | ||
2106 | static int flic_has_attr(struct kvm_device *dev, | ||
2107 | struct kvm_device_attr *attr) | ||
2108 | { | ||
2109 | switch (attr->group) { | ||
2110 | case KVM_DEV_FLIC_GET_ALL_IRQS: | ||
2111 | case KVM_DEV_FLIC_ENQUEUE: | ||
2112 | case KVM_DEV_FLIC_CLEAR_IRQS: | ||
2113 | case KVM_DEV_FLIC_APF_ENABLE: | ||
2114 | case KVM_DEV_FLIC_APF_DISABLE_WAIT: | ||
2115 | case KVM_DEV_FLIC_ADAPTER_REGISTER: | ||
2116 | case KVM_DEV_FLIC_ADAPTER_MODIFY: | ||
2117 | case KVM_DEV_FLIC_CLEAR_IO_IRQ: | ||
2118 | return 0; | ||
2119 | } | ||
2120 | return -ENXIO; | ||
2121 | } | ||
2122 | |||
2077 | static int flic_create(struct kvm_device *dev, u32 type) | 2123 | static int flic_create(struct kvm_device *dev, u32 type) |
2078 | { | 2124 | { |
2079 | if (!dev) | 2125 | if (!dev) |
@@ -2095,6 +2141,7 @@ struct kvm_device_ops kvm_flic_ops = { | |||
2095 | .name = "kvm-flic", | 2141 | .name = "kvm-flic", |
2096 | .get_attr = flic_get_attr, | 2142 | .get_attr = flic_get_attr, |
2097 | .set_attr = flic_set_attr, | 2143 | .set_attr = flic_set_attr, |
2144 | .has_attr = flic_has_attr, | ||
2098 | .create = flic_create, | 2145 | .create = flic_create, |
2099 | .destroy = flic_destroy, | 2146 | .destroy = flic_destroy, |
2100 | }; | 2147 | }; |