KVM: s390: factor out reading of the guest TOD clock
[deliverable/linux.git] / arch / s390 / kvm / interrupt.c
index b277d50dcf76a409072832059438e2f10ca3bc63..373e32346d68d6c3ae270ca39b96b09fe66b0a6e 100644 (file)
@@ -51,11 +51,9 @@ static int psw_mchk_disabled(struct kvm_vcpu *vcpu)
 
 static int psw_interrupts_disabled(struct kvm_vcpu *vcpu)
 {
-       if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) ||
-           (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO) ||
-           (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT))
-               return 0;
-       return 1;
+       return psw_extint_disabled(vcpu) &&
+              psw_ioint_disabled(vcpu) &&
+              psw_mchk_disabled(vcpu);
 }
 
 static int ckc_interrupts_enabled(struct kvm_vcpu *vcpu)
@@ -71,13 +69,8 @@ static int ckc_interrupts_enabled(struct kvm_vcpu *vcpu)
 
 static int ckc_irq_pending(struct kvm_vcpu *vcpu)
 {
-       preempt_disable();
-       if (!(vcpu->arch.sie_block->ckc <
-             get_tod_clock_fast() + vcpu->arch.sie_block->epoch)) {
-               preempt_enable();
+       if (vcpu->arch.sie_block->ckc >= kvm_s390_get_tod_clock_fast(vcpu->kvm))
                return 0;
-       }
-       preempt_enable();
        return ckc_interrupts_enabled(vcpu);
 }
 
@@ -109,14 +102,10 @@ static inline u8 int_word_to_isc(u32 int_word)
        return (int_word & 0x38000000) >> 27;
 }
 
-static inline unsigned long pending_floating_irqs(struct kvm_vcpu *vcpu)
+static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu)
 {
-       return vcpu->kvm->arch.float_int.pending_irqs;
-}
-
-static inline unsigned long pending_local_irqs(struct kvm_vcpu *vcpu)
-{
-       return vcpu->arch.local_int.pending_irqs;
+       return vcpu->kvm->arch.float_int.pending_irqs |
+              vcpu->arch.local_int.pending_irqs;
 }
 
 static unsigned long disable_iscs(struct kvm_vcpu *vcpu,
@@ -135,8 +124,7 @@ static unsigned long deliverable_irqs(struct kvm_vcpu *vcpu)
 {
        unsigned long active_mask;
 
-       active_mask = pending_local_irqs(vcpu);
-       active_mask |= pending_floating_irqs(vcpu);
+       active_mask = pending_irqs(vcpu);
        if (!active_mask)
                return 0;
 
@@ -173,20 +161,20 @@ static unsigned long deliverable_irqs(struct kvm_vcpu *vcpu)
 
 static void __set_cpu_idle(struct kvm_vcpu *vcpu)
 {
-       atomic_set_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
+       atomic_or(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
        set_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask);
 }
 
 static void __unset_cpu_idle(struct kvm_vcpu *vcpu)
 {
-       atomic_clear_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
+       atomic_andnot(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags);
        clear_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask);
 }
 
 static void __reset_intercept_indicators(struct kvm_vcpu *vcpu)
 {
-       atomic_clear_mask(CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT,
-                         &vcpu->arch.sie_block->cpuflags);
+       atomic_andnot(CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT,
+                   &vcpu->arch.sie_block->cpuflags);
        vcpu->arch.sie_block->lctl = 0x0000;
        vcpu->arch.sie_block->ictl &= ~(ICTL_LPSW | ICTL_STCTL | ICTL_PINT);
 
@@ -199,12 +187,12 @@ static void __reset_intercept_indicators(struct kvm_vcpu *vcpu)
 
 static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag)
 {
-       atomic_set_mask(flag, &vcpu->arch.sie_block->cpuflags);
+       atomic_or(flag, &vcpu->arch.sie_block->cpuflags);
 }
 
 static void set_intercept_indicators_io(struct kvm_vcpu *vcpu)
 {
-       if (!(pending_floating_irqs(vcpu) & IRQ_PEND_IO_MASK))
+       if (!(pending_irqs(vcpu) & IRQ_PEND_IO_MASK))
                return;
        else if (psw_ioint_disabled(vcpu))
                __set_cpuflag(vcpu, CPUSTAT_IO_INT);
@@ -214,7 +202,7 @@ static void set_intercept_indicators_io(struct kvm_vcpu *vcpu)
 
 static void set_intercept_indicators_ext(struct kvm_vcpu *vcpu)
 {
-       if (!(pending_local_irqs(vcpu) & IRQ_PEND_EXT_MASK))
+       if (!(pending_irqs(vcpu) & IRQ_PEND_EXT_MASK))
                return;
        if (psw_extint_disabled(vcpu))
                __set_cpuflag(vcpu, CPUSTAT_EXT_INT);
@@ -224,7 +212,7 @@ static void set_intercept_indicators_ext(struct kvm_vcpu *vcpu)
 
 static void set_intercept_indicators_mchk(struct kvm_vcpu *vcpu)
 {
-       if (!(pending_local_irqs(vcpu) & IRQ_PEND_MCHK_MASK))
+       if (!(pending_irqs(vcpu) & IRQ_PEND_MCHK_MASK))
                return;
        if (psw_mchk_disabled(vcpu))
                vcpu->arch.sie_block->ictl |= ICTL_LPSW;
@@ -815,23 +803,21 @@ int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu)
 
 int kvm_s390_vcpu_has_irq(struct kvm_vcpu *vcpu, int exclude_stop)
 {
-       int rc;
+       if (deliverable_irqs(vcpu))
+               return 1;
 
-       rc = !!deliverable_irqs(vcpu);
-
-       if (!rc && kvm_cpu_has_pending_timer(vcpu))
-               rc = 1;
+       if (kvm_cpu_has_pending_timer(vcpu))
+               return 1;
 
        /* external call pending and deliverable */
-       if (!rc && kvm_s390_ext_call_pending(vcpu) &&
+       if (kvm_s390_ext_call_pending(vcpu) &&
            !psw_extint_disabled(vcpu) &&
            (vcpu->arch.sie_block->gcr[0] & 0x2000ul))
-               rc = 1;
-
-       if (!rc && !exclude_stop && kvm_s390_is_stop_irq_pending(vcpu))
-               rc = 1;
+               return 1;
 
-       return rc;
+       if (!exclude_stop && kvm_s390_is_stop_irq_pending(vcpu))
+               return 1;
+       return 0;
 }
 
 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
@@ -846,7 +832,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
        vcpu->stat.exit_wait_state++;
 
        /* fast path */
-       if (kvm_cpu_has_pending_timer(vcpu) || kvm_arch_vcpu_runnable(vcpu))
+       if (kvm_arch_vcpu_runnable(vcpu))
                return 0;
 
        if (psw_interrupts_disabled(vcpu)) {
@@ -860,9 +846,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
                goto no_timer;
        }
 
-       preempt_disable();
-       now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch;
-       preempt_enable();
+       now = kvm_s390_get_tod_clock_fast(vcpu->kvm);
        sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
 
        /* underflow */
@@ -901,9 +885,7 @@ enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer)
        u64 now, sltime;
 
        vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer);
-       preempt_disable();
-       now = get_tod_clock_fast() + vcpu->arch.sie_block->epoch;
-       preempt_enable();
+       now = kvm_s390_get_tod_clock_fast(vcpu->kvm);
        sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
 
        /*
@@ -928,7 +910,7 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu)
        spin_unlock(&li->lock);
 
        /* clear pending external calls set by sigp interpretation facility */
-       atomic_clear_mask(CPUSTAT_ECALL_PEND, li->cpuflags);
+       atomic_andnot(CPUSTAT_ECALL_PEND, li->cpuflags);
        vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl = 0;
 }
 
@@ -981,39 +963,30 @@ 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;
 }
 
-int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
-{
-       struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
-       struct kvm_s390_irq irq;
-
-       spin_lock(&li->lock);
-       irq.u.pgm.code = code;
-       __inject_prog(vcpu, &irq);
-       BUG_ON(waitqueue_active(li->wq));
-       spin_unlock(&li->lock);
-       return 0;
-}
-
-int kvm_s390_inject_prog_irq(struct kvm_vcpu *vcpu,
-                            struct kvm_s390_pgm_info *pgm_info)
-{
-       struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
-       struct kvm_s390_irq irq;
-       int rc;
-
-       spin_lock(&li->lock);
-       irq.u.pgm = *pgm_info;
-       rc = __inject_prog(vcpu, &irq);
-       BUG_ON(waitqueue_active(li->wq));
-       spin_unlock(&li->lock);
-       return rc;
-}
-
 static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
 {
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
@@ -1026,7 +999,7 @@ static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
 
        li->irq.ext = irq->u.ext;
        set_bit(IRQ_PEND_PFAULT_INIT, &li->pending_irqs);
-       atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+       atomic_or(CPUSTAT_EXT_INT, li->cpuflags);
        return 0;
 }
 
@@ -1041,7 +1014,7 @@ static int __inject_extcall_sigpif(struct kvm_vcpu *vcpu, uint16_t src_id)
                /* another external call is pending */
                return -EBUSY;
        }
-       atomic_set_mask(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags);
+       atomic_or(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags);
        return 0;
 }
 
@@ -1067,7 +1040,7 @@ static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
        if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs))
                return -EBUSY;
        *extcall = irq->u.extcall;
-       atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+       atomic_or(CPUSTAT_EXT_INT, li->cpuflags);
        return 0;
 }
 
@@ -1139,7 +1112,7 @@ static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
 
        set_bit(irq->u.emerg.code, li->sigp_emerg_pending);
        set_bit(IRQ_PEND_EXT_EMERGENCY, &li->pending_irqs);
-       atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+       atomic_or(CPUSTAT_EXT_INT, li->cpuflags);
        return 0;
 }
 
@@ -1183,7 +1156,7 @@ static int __inject_ckc(struct kvm_vcpu *vcpu)
                                   0, 0);
 
        set_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs);
-       atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+       atomic_or(CPUSTAT_EXT_INT, li->cpuflags);
        return 0;
 }
 
@@ -1196,7 +1169,7 @@ static int __inject_cpu_timer(struct kvm_vcpu *vcpu)
                                   0, 0);
 
        set_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs);
-       atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+       atomic_or(CPUSTAT_EXT_INT, li->cpuflags);
        return 0;
 }
 
@@ -1375,13 +1348,13 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type)
        spin_lock(&li->lock);
        switch (type) {
        case KVM_S390_MCHK:
-               atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
+               atomic_or(CPUSTAT_STOP_INT, li->cpuflags);
                break;
        case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
-               atomic_set_mask(CPUSTAT_IO_INT, li->cpuflags);
+               atomic_or(CPUSTAT_IO_INT, li->cpuflags);
                break;
        default:
-               atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
+               atomic_or(CPUSTAT_EXT_INT, li->cpuflags);
                break;
        }
        spin_unlock(&li->lock);
@@ -1390,12 +1363,9 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type)
 
 static int __inject_vm(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
 {
-       struct kvm_s390_float_interrupt *fi;
        u64 type = READ_ONCE(inti->type);
        int rc;
 
-       fi = &kvm->arch.float_int;
-
        switch (type) {
        case KVM_S390_MCHK:
                rc = __inject_float_mchk(kvm, inti);
This page took 0.033671 seconds and 5 git commands to generate.