|
@@ -1471,20 +1471,86 @@ static struct kvm_s390_interrupt_info *get_io_int(struct kvm *kvm,
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+static struct kvm_s390_interrupt_info *get_top_io_int(struct kvm *kvm,
|
|
|
+ u64 isc_mask, u32 schid)
|
|
|
+{
|
|
|
+ struct kvm_s390_interrupt_info *inti = NULL;
|
|
|
+ int isc;
|
|
|
+
|
|
|
+ for (isc = 0; isc <= MAX_ISC && !inti; isc++) {
|
|
|
+ if (isc_mask & isc_to_isc_bits(isc))
|
|
|
+ inti = get_io_int(kvm, isc, schid);
|
|
|
+ }
|
|
|
+ return inti;
|
|
|
+}
|
|
|
+
|
|
|
+static int get_top_gisa_isc(struct kvm *kvm, u64 isc_mask, u32 schid)
|
|
|
+{
|
|
|
+ unsigned long active_mask;
|
|
|
+ int isc;
|
|
|
+
|
|
|
+ if (schid)
|
|
|
+ goto out;
|
|
|
+ if (!kvm->arch.gisa)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ active_mask = (isc_mask & kvm_s390_gisa_get_ipm(kvm->arch.gisa) << 24) << 32;
|
|
|
+ while (active_mask) {
|
|
|
+ isc = __fls(active_mask) ^ (BITS_PER_LONG - 1);
|
|
|
+ if (kvm_s390_gisa_tac_ipm_gisc(kvm->arch.gisa, isc))
|
|
|
+ return isc;
|
|
|
+ clear_bit_inv(isc, &active_mask);
|
|
|
+ }
|
|
|
+out:
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Dequeue and return an I/O interrupt matching any of the interruption
|
|
|
* subclasses as designated by the isc mask in cr6 and the schid (if != 0).
|
|
|
+ * Take into account the interrupts pending in the interrupt list and in GISA.
|
|
|
+ *
|
|
|
+ * Note that for a guest that does not enable I/O interrupts
|
|
|
+ * but relies on TPI, a flood of classic interrupts may starve
|
|
|
+ * out adapter interrupts on the same isc. Linux does not do
|
|
|
+ * that, and it is possible to work around the issue by configuring
|
|
|
+ * different iscs for classic and adapter interrupts in the guest,
|
|
|
+ * but we may want to revisit this in the future.
|
|
|
*/
|
|
|
struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
|
|
|
u64 isc_mask, u32 schid)
|
|
|
{
|
|
|
- struct kvm_s390_interrupt_info *inti = NULL;
|
|
|
+ struct kvm_s390_interrupt_info *inti, *tmp_inti;
|
|
|
int isc;
|
|
|
|
|
|
- for (isc = 0; isc <= MAX_ISC && !inti; isc++) {
|
|
|
- if (isc_mask & isc_to_isc_bits(isc))
|
|
|
- inti = get_io_int(kvm, isc, schid);
|
|
|
+ inti = get_top_io_int(kvm, isc_mask, schid);
|
|
|
+
|
|
|
+ isc = get_top_gisa_isc(kvm, isc_mask, schid);
|
|
|
+ if (isc < 0)
|
|
|
+ /* no AI in GISA */
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ if (!inti)
|
|
|
+ /* AI in GISA but no classical IO int */
|
|
|
+ goto gisa_out;
|
|
|
+
|
|
|
+ /* both types of interrupts present */
|
|
|
+ if (int_word_to_isc(inti->io.io_int_word) <= isc) {
|
|
|
+ /* classical IO int with higher priority */
|
|
|
+ kvm_s390_gisa_set_ipm_gisc(kvm->arch.gisa, isc);
|
|
|
+ goto out;
|
|
|
}
|
|
|
+gisa_out:
|
|
|
+ tmp_inti = kzalloc(sizeof(*inti), GFP_KERNEL);
|
|
|
+ if (tmp_inti) {
|
|
|
+ tmp_inti->type = KVM_S390_INT_IO(1, 0, 0, 0);
|
|
|
+ tmp_inti->io.io_int_word = isc_to_int_word(isc);
|
|
|
+ if (inti)
|
|
|
+ kvm_s390_reinject_io_int(kvm, inti);
|
|
|
+ inti = tmp_inti;
|
|
|
+ } else
|
|
|
+ kvm_s390_gisa_set_ipm_gisc(kvm->arch.gisa, isc);
|
|
|
+out:
|
|
|
return inti;
|
|
|
}
|
|
|
|