KVM: s390: migration / injection of prog irq ilc
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>
Wed, 4 Nov 2015 15:33:33 +0000 (16:33 +0100)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Wed, 10 Feb 2016 12:12:50 +0000 (13:12 +0100)
We have to migrate the program irq ilc and someday we will have to
specify the ilc without KVM trying to autodetect the value.

Let's reuse one of the spare fields in our program irq that should
always be set to 0 by user space. Because we also want to make use
of 0 ilcs ("not available"), we need a validity indicator.

If no valid ilc is given, we try to autodetect the ilc via the current
icptcode and icptstatus + parameter and store the valid ilc in the
irq structure.

This has a nice effect: QEMU's making use of KVM_S390_IRQ /
KVM_S390_SET_IRQ_STATE / KVM_S390_GET_IRQ_STATE for migration will
directly migrate the ilc without any changes.

Please note that we use bit 0 as validity and bit 1,2 for the ilc, so
by applying the ilc mask we directly get the ilen which is usually what
we work with.

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
include/uapi/linux/kvm.h

index daa4fdbcc91c645ce3734bee81b41ee3abf236d5..e594a783002223d00716cc471b47038c77246896 100644 (file)
@@ -571,7 +571,7 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
        struct kvm_s390_pgm_info pgm_info;
        int rc = 0, nullifying = false;
-       u16 ilen = kvm_s390_get_ilen(vcpu);
+       u16 ilen;
 
        spin_lock(&li->lock);
        pgm_info = li->irq.pgm;
@@ -579,6 +579,7 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)
        memset(&li->irq.pgm, 0, sizeof(pgm_info));
        spin_unlock(&li->lock);
 
+       ilen = pgm_info.flags & KVM_S390_PGM_FLAGS_ILC_MASK;
        VCPU_EVENT(vcpu, 3, "deliver: program irq code 0x%x, ilen:%d",
                   pgm_info.code, ilen);
        vcpu->stat.deliver_program_int++;
@@ -1043,8 +1044,16 @@ 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);
 
+       if (!(irq->u.pgm.flags & KVM_S390_PGM_FLAGS_ILC_VALID)) {
+               /* auto detection if no valid ILC was given */
+               irq->u.pgm.flags &= ~KVM_S390_PGM_FLAGS_ILC_MASK;
+               irq->u.pgm.flags |= kvm_s390_get_ilen(vcpu);
+               irq->u.pgm.flags |= KVM_S390_PGM_FLAGS_ILC_VALID;
+       }
+
        if (irq->u.pgm.code == PGM_PER) {
                li->irq.pgm.code |= PGM_PER;
+               li->irq.pgm.flags = irq->u.pgm.flags;
                /* 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;
@@ -1053,6 +1062,7 @@ static int __inject_prog(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
        } else if (!(irq->u.pgm.code & PGM_PER)) {
                li->irq.pgm.code = (li->irq.pgm.code & PGM_PER) |
                                   irq->u.pgm.code;
+               li->irq.pgm.flags = irq->u.pgm.flags;
                /* 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;
index 9da905157ceeebcb5afbd9e73b8ac56195954929..4e20a40bb10f5578bac320db593c3a59cc5ed911 100644 (file)
@@ -541,7 +541,12 @@ struct kvm_s390_pgm_info {
        __u8 exc_access_id;
        __u8 per_access_id;
        __u8 op_access_id;
-       __u8 pad[3];
+#define KVM_S390_PGM_FLAGS_ILC_VALID   0x01
+#define KVM_S390_PGM_FLAGS_ILC_0       0x02
+#define KVM_S390_PGM_FLAGS_ILC_1       0x04
+#define KVM_S390_PGM_FLAGS_ILC_MASK    0x06
+       __u8 flags;
+       __u8 pad[2];
 };
 
 struct kvm_s390_prefix_info {