KVM: s390: correctly handle injection of pgm irqs and per events
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>
Mon, 4 May 2015 10:38:48 +0000 (12:38 +0200)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Tue, 13 Oct 2015 13:50:34 +0000 (15:50 +0200)
PER events can always co-exist with other program interrupts.

For now, we always overwrite all program interrupt parameters when
injecting any type of program interrupt.

Let's handle that correctly by only overwriting the relevant portion of
the program interrupt parameters. Therefore we can now inject PER events
and ordinary program interrupts concurrently, resulting in no loss of
program interrupts. This will especially by helpful when manually detecting
PER events later - as both types might be triggered during one SIE exit.

Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
arch/s390/kvm/interrupt.c

index f603bacf6ac95d613f740bb8ca41e5a5339cd40b..a8be542b9cb087cee8739d9d239de1fbfb10525d 100644 (file)
@@ -972,7 +972,26 @@ static int __inject_prog(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
        trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_PROGRAM_INT,
                                   irq->u.pgm.code, 0);
 
-       li->irq.pgm = irq->u.pgm;
+       if (irq->u.pgm.code == PGM_PER) {
+               li->irq.pgm.code |= PGM_PER;
+               /* only modify PER related information */
+               li->irq.pgm.per_address = irq->u.pgm.per_address;
+               li->irq.pgm.per_code = irq->u.pgm.per_code;
+               li->irq.pgm.per_atmid = irq->u.pgm.per_atmid;
+               li->irq.pgm.per_access_id = irq->u.pgm.per_access_id;
+       } else if (!(irq->u.pgm.code & PGM_PER)) {
+               li->irq.pgm.code = (li->irq.pgm.code & PGM_PER) |
+                                  irq->u.pgm.code;
+               /* only modify non-PER information */
+               li->irq.pgm.trans_exc_code = irq->u.pgm.trans_exc_code;
+               li->irq.pgm.mon_code = irq->u.pgm.mon_code;
+               li->irq.pgm.data_exc_code = irq->u.pgm.data_exc_code;
+               li->irq.pgm.mon_class_nr = irq->u.pgm.mon_class_nr;
+               li->irq.pgm.exc_access_id = irq->u.pgm.exc_access_id;
+               li->irq.pgm.op_access_id = irq->u.pgm.op_access_id;
+       } else {
+               li->irq.pgm = irq->u.pgm;
+       }
        set_bit(IRQ_PEND_PROG, &li->pending_irqs);
        return 0;
 }