diff options
Diffstat (limited to 'arch/s390/kvm/interrupt.c')
-rw-r--r-- | arch/s390/kvm/interrupt.c | 123 |
1 files changed, 79 insertions, 44 deletions
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index aabf46f5f883..b04616b57a94 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c | |||
@@ -169,8 +169,15 @@ static int ckc_interrupts_enabled(struct kvm_vcpu *vcpu) | |||
169 | 169 | ||
170 | static int ckc_irq_pending(struct kvm_vcpu *vcpu) | 170 | static int ckc_irq_pending(struct kvm_vcpu *vcpu) |
171 | { | 171 | { |
172 | if (vcpu->arch.sie_block->ckc >= kvm_s390_get_tod_clock_fast(vcpu->kvm)) | 172 | const u64 now = kvm_s390_get_tod_clock_fast(vcpu->kvm); |
173 | const u64 ckc = vcpu->arch.sie_block->ckc; | ||
174 | |||
175 | if (vcpu->arch.sie_block->gcr[0] & 0x0020000000000000ul) { | ||
176 | if ((s64)ckc >= (s64)now) | ||
177 | return 0; | ||
178 | } else if (ckc >= now) { | ||
173 | return 0; | 179 | return 0; |
180 | } | ||
174 | return ckc_interrupts_enabled(vcpu); | 181 | return ckc_interrupts_enabled(vcpu); |
175 | } | 182 | } |
176 | 183 | ||
@@ -187,12 +194,6 @@ static int cpu_timer_irq_pending(struct kvm_vcpu *vcpu) | |||
187 | return kvm_s390_get_cpu_timer(vcpu) >> 63; | 194 | return kvm_s390_get_cpu_timer(vcpu) >> 63; |
188 | } | 195 | } |
189 | 196 | ||
190 | static inline int is_ioirq(unsigned long irq_type) | ||
191 | { | ||
192 | return ((irq_type >= IRQ_PEND_IO_ISC_7) && | ||
193 | (irq_type <= IRQ_PEND_IO_ISC_0)); | ||
194 | } | ||
195 | |||
196 | static uint64_t isc_to_isc_bits(int isc) | 197 | static uint64_t isc_to_isc_bits(int isc) |
197 | { | 198 | { |
198 | return (0x80 >> isc) << 24; | 199 | return (0x80 >> isc) << 24; |
@@ -236,10 +237,15 @@ static inline int kvm_s390_gisa_tac_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gis | |||
236 | return test_and_clear_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); | 237 | return test_and_clear_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa); |
237 | } | 238 | } |
238 | 239 | ||
239 | static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu) | 240 | static inline unsigned long pending_irqs_no_gisa(struct kvm_vcpu *vcpu) |
240 | { | 241 | { |
241 | return vcpu->kvm->arch.float_int.pending_irqs | | 242 | return vcpu->kvm->arch.float_int.pending_irqs | |
242 | vcpu->arch.local_int.pending_irqs | | 243 | vcpu->arch.local_int.pending_irqs; |
244 | } | ||
245 | |||
246 | static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu) | ||
247 | { | ||
248 | return pending_irqs_no_gisa(vcpu) | | ||
243 | kvm_s390_gisa_get_ipm(vcpu->kvm->arch.gisa) << IRQ_PEND_IO_ISC_7; | 249 | kvm_s390_gisa_get_ipm(vcpu->kvm->arch.gisa) << IRQ_PEND_IO_ISC_7; |
244 | } | 250 | } |
245 | 251 | ||
@@ -337,7 +343,7 @@ static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) | |||
337 | 343 | ||
338 | static void set_intercept_indicators_io(struct kvm_vcpu *vcpu) | 344 | static void set_intercept_indicators_io(struct kvm_vcpu *vcpu) |
339 | { | 345 | { |
340 | if (!(pending_irqs(vcpu) & IRQ_PEND_IO_MASK)) | 346 | if (!(pending_irqs_no_gisa(vcpu) & IRQ_PEND_IO_MASK)) |
341 | return; | 347 | return; |
342 | else if (psw_ioint_disabled(vcpu)) | 348 | else if (psw_ioint_disabled(vcpu)) |
343 | kvm_s390_set_cpuflags(vcpu, CPUSTAT_IO_INT); | 349 | kvm_s390_set_cpuflags(vcpu, CPUSTAT_IO_INT); |
@@ -1011,24 +1017,6 @@ out: | |||
1011 | return rc; | 1017 | return rc; |
1012 | } | 1018 | } |
1013 | 1019 | ||
1014 | typedef int (*deliver_irq_t)(struct kvm_vcpu *vcpu); | ||
1015 | |||
1016 | static const deliver_irq_t deliver_irq_funcs[] = { | ||
1017 | [IRQ_PEND_MCHK_EX] = __deliver_machine_check, | ||
1018 | [IRQ_PEND_MCHK_REP] = __deliver_machine_check, | ||
1019 | [IRQ_PEND_PROG] = __deliver_prog, | ||
1020 | [IRQ_PEND_EXT_EMERGENCY] = __deliver_emergency_signal, | ||
1021 | [IRQ_PEND_EXT_EXTERNAL] = __deliver_external_call, | ||
1022 | [IRQ_PEND_EXT_CLOCK_COMP] = __deliver_ckc, | ||
1023 | [IRQ_PEND_EXT_CPU_TIMER] = __deliver_cpu_timer, | ||
1024 | [IRQ_PEND_RESTART] = __deliver_restart, | ||
1025 | [IRQ_PEND_SET_PREFIX] = __deliver_set_prefix, | ||
1026 | [IRQ_PEND_PFAULT_INIT] = __deliver_pfault_init, | ||
1027 | [IRQ_PEND_EXT_SERVICE] = __deliver_service, | ||
1028 | [IRQ_PEND_PFAULT_DONE] = __deliver_pfault_done, | ||
1029 | [IRQ_PEND_VIRTIO] = __deliver_virtio, | ||
1030 | }; | ||
1031 | |||
1032 | /* Check whether an external call is pending (deliverable or not) */ | 1020 | /* Check whether an external call is pending (deliverable or not) */ |
1033 | int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu) | 1021 | int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu) |
1034 | { | 1022 | { |
@@ -1066,13 +1054,19 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) | |||
1066 | 1054 | ||
1067 | static u64 __calculate_sltime(struct kvm_vcpu *vcpu) | 1055 | static u64 __calculate_sltime(struct kvm_vcpu *vcpu) |
1068 | { | 1056 | { |
1069 | u64 now, cputm, sltime = 0; | 1057 | const u64 now = kvm_s390_get_tod_clock_fast(vcpu->kvm); |
1058 | const u64 ckc = vcpu->arch.sie_block->ckc; | ||
1059 | u64 cputm, sltime = 0; | ||
1070 | 1060 | ||
1071 | if (ckc_interrupts_enabled(vcpu)) { | 1061 | if (ckc_interrupts_enabled(vcpu)) { |
1072 | now = kvm_s390_get_tod_clock_fast(vcpu->kvm); | 1062 | if (vcpu->arch.sie_block->gcr[0] & 0x0020000000000000ul) { |
1073 | sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now); | 1063 | if ((s64)now < (s64)ckc) |
1074 | /* already expired or overflow? */ | 1064 | sltime = tod_to_ns((s64)ckc - (s64)now); |
1075 | if (!sltime || vcpu->arch.sie_block->ckc <= now) | 1065 | } else if (now < ckc) { |
1066 | sltime = tod_to_ns(ckc - now); | ||
1067 | } | ||
1068 | /* already expired */ | ||
1069 | if (!sltime) | ||
1076 | return 0; | 1070 | return 0; |
1077 | if (cpu_timer_interrupts_enabled(vcpu)) { | 1071 | if (cpu_timer_interrupts_enabled(vcpu)) { |
1078 | cputm = kvm_s390_get_cpu_timer(vcpu); | 1072 | cputm = kvm_s390_get_cpu_timer(vcpu); |
@@ -1192,7 +1186,6 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu) | |||
1192 | int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) | 1186 | int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) |
1193 | { | 1187 | { |
1194 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; | 1188 | struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; |
1195 | deliver_irq_t func; | ||
1196 | int rc = 0; | 1189 | int rc = 0; |
1197 | unsigned long irq_type; | 1190 | unsigned long irq_type; |
1198 | unsigned long irqs; | 1191 | unsigned long irqs; |
@@ -1212,16 +1205,57 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) | |||
1212 | while ((irqs = deliverable_irqs(vcpu)) && !rc) { | 1205 | while ((irqs = deliverable_irqs(vcpu)) && !rc) { |
1213 | /* bits are in the reverse order of interrupt priority */ | 1206 | /* bits are in the reverse order of interrupt priority */ |
1214 | irq_type = find_last_bit(&irqs, IRQ_PEND_COUNT); | 1207 | irq_type = find_last_bit(&irqs, IRQ_PEND_COUNT); |
1215 | if (is_ioirq(irq_type)) { | 1208 | switch (irq_type) { |
1209 | case IRQ_PEND_IO_ISC_0: | ||
1210 | case IRQ_PEND_IO_ISC_1: | ||
1211 | case IRQ_PEND_IO_ISC_2: | ||
1212 | case IRQ_PEND_IO_ISC_3: | ||
1213 | case IRQ_PEND_IO_ISC_4: | ||
1214 | case IRQ_PEND_IO_ISC_5: | ||
1215 | case IRQ_PEND_IO_ISC_6: | ||
1216 | case IRQ_PEND_IO_ISC_7: | ||
1216 | rc = __deliver_io(vcpu, irq_type); | 1217 | rc = __deliver_io(vcpu, irq_type); |
1217 | } else { | 1218 | break; |
1218 | func = deliver_irq_funcs[irq_type]; | 1219 | case IRQ_PEND_MCHK_EX: |
1219 | if (!func) { | 1220 | case IRQ_PEND_MCHK_REP: |
1220 | WARN_ON_ONCE(func == NULL); | 1221 | rc = __deliver_machine_check(vcpu); |
1221 | clear_bit(irq_type, &li->pending_irqs); | 1222 | break; |
1222 | continue; | 1223 | case IRQ_PEND_PROG: |
1223 | } | 1224 | rc = __deliver_prog(vcpu); |
1224 | rc = func(vcpu); | 1225 | break; |
1226 | case IRQ_PEND_EXT_EMERGENCY: | ||
1227 | rc = __deliver_emergency_signal(vcpu); | ||
1228 | break; | ||
1229 | case IRQ_PEND_EXT_EXTERNAL: | ||
1230 | rc = __deliver_external_call(vcpu); | ||
1231 | break; | ||
1232 | case IRQ_PEND_EXT_CLOCK_COMP: | ||
1233 | rc = __deliver_ckc(vcpu); | ||
1234 | break; | ||
1235 | case IRQ_PEND_EXT_CPU_TIMER: | ||
1236 | rc = __deliver_cpu_timer(vcpu); | ||
1237 | break; | ||
1238 | case IRQ_PEND_RESTART: | ||
1239 | rc = __deliver_restart(vcpu); | ||
1240 | break; | ||
1241 | case IRQ_PEND_SET_PREFIX: | ||
1242 | rc = __deliver_set_prefix(vcpu); | ||
1243 | break; | ||
1244 | case IRQ_PEND_PFAULT_INIT: | ||
1245 | rc = __deliver_pfault_init(vcpu); | ||
1246 | break; | ||
1247 | case IRQ_PEND_EXT_SERVICE: | ||
1248 | rc = __deliver_service(vcpu); | ||
1249 | break; | ||
1250 | case IRQ_PEND_PFAULT_DONE: | ||
1251 | rc = __deliver_pfault_done(vcpu); | ||
1252 | break; | ||
1253 | case IRQ_PEND_VIRTIO: | ||
1254 | rc = __deliver_virtio(vcpu); | ||
1255 | break; | ||
1256 | default: | ||
1257 | WARN_ONCE(1, "Unknown pending irq type %ld", irq_type); | ||
1258 | clear_bit(irq_type, &li->pending_irqs); | ||
1225 | } | 1259 | } |
1226 | } | 1260 | } |
1227 | 1261 | ||
@@ -1701,7 +1735,8 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type) | |||
1701 | kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_STOP_INT); | 1735 | kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_STOP_INT); |
1702 | break; | 1736 | break; |
1703 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: | 1737 | case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
1704 | kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_IO_INT); | 1738 | if (!(type & KVM_S390_INT_IO_AI_MASK && kvm->arch.gisa)) |
1739 | kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_IO_INT); | ||
1705 | break; | 1740 | break; |
1706 | default: | 1741 | default: |
1707 | kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_EXT_INT); | 1742 | kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_EXT_INT); |