Skip to content

Commit

Permalink
KVM: s390: make kvm_s390_get_io_int() aware of GISA
Browse files Browse the repository at this point in the history
The function returns a pending I/O interrupt with the highest
priority defined by its ISC.

Together with AIV activation, pending adapter interrupts are
managed by the GISA IPM. Thus kvm_s390_get_io_int() needs to
inspect the IPM as well when the interrupt with the highest
priority has to be identified.

In case classic and adapter interrupts with the same ISC are
pending, the classic interrupt will be returned first.

Signed-off-by: Michael Mueller <[email protected]>
Reviewed-by: Halil Pasic <[email protected]>
Reviewed-by: Christian Borntraeger <[email protected]>
Reviewed-by: Cornelia Huck <[email protected]>
Signed-off-by: Christian Borntraeger <[email protected]>
  • Loading branch information
mimu001 authored and borntraeger committed Jan 26, 2018
1 parent 24160af commit 4b35f65
Showing 1 changed file with 70 additions and 4 deletions.
74 changes: 70 additions & 4 deletions arch/s390/kvm/interrupt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit 4b35f65

Please sign in to comment.