aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm/interrupt.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kvm/interrupt.c')
-rw-r--r--arch/s390/kvm/interrupt.c57
1 files changed, 42 insertions, 15 deletions
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 1ba917638bba..0ad1f7500abd 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -19,6 +19,7 @@
19#include <linux/bitmap.h> 19#include <linux/bitmap.h>
20#include <asm/asm-offsets.h> 20#include <asm/asm-offsets.h>
21#include <asm/uaccess.h> 21#include <asm/uaccess.h>
22#include <asm/sclp.h>
22#include "kvm-s390.h" 23#include "kvm-s390.h"
23#include "gaccess.h" 24#include "gaccess.h"
24#include "trace-s390.h" 25#include "trace-s390.h"
@@ -735,18 +736,17 @@ static int __must_check __deliver_floating_interrupt(struct kvm_vcpu *vcpu,
735 return rc; 736 return rc;
736} 737}
737 738
738/* Check whether SIGP interpretation facility has an external call pending */ 739/* Check whether an external call is pending (deliverable or not) */
739int kvm_s390_si_ext_call_pending(struct kvm_vcpu *vcpu) 740int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu)
740{ 741{
741 atomic_t *sigp_ctrl = &vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].ctrl; 742 struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
743 uint8_t sigp_ctrl = vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
742 744
743 if (!psw_extint_disabled(vcpu) && 745 if (!sclp_has_sigpif())
744 (vcpu->arch.sie_block->gcr[0] & 0x2000ul) && 746 return test_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs);
745 (atomic_read(sigp_ctrl) & SIGP_CTRL_C) &&
746 (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_ECALL_PEND))
747 return 1;
748 747
749 return 0; 748 return (sigp_ctrl & SIGP_CTRL_C) &&
749 (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_ECALL_PEND);
750} 750}
751 751
752int kvm_s390_vcpu_has_irq(struct kvm_vcpu *vcpu, int exclude_stop) 752int kvm_s390_vcpu_has_irq(struct kvm_vcpu *vcpu, int exclude_stop)
@@ -770,7 +770,10 @@ int kvm_s390_vcpu_has_irq(struct kvm_vcpu *vcpu, int exclude_stop)
770 if (!rc && kvm_cpu_has_pending_timer(vcpu)) 770 if (!rc && kvm_cpu_has_pending_timer(vcpu))
771 rc = 1; 771 rc = 1;
772 772
773 if (!rc && kvm_s390_si_ext_call_pending(vcpu)) 773 /* external call pending and deliverable */
774 if (!rc && kvm_s390_ext_call_pending(vcpu) &&
775 !psw_extint_disabled(vcpu) &&
776 (vcpu->arch.sie_block->gcr[0] & 0x2000ul))
774 rc = 1; 777 rc = 1;
775 778
776 if (!rc && !exclude_stop && kvm_s390_is_stop_irq_pending(vcpu)) 779 if (!rc && !exclude_stop && kvm_s390_is_stop_irq_pending(vcpu))
@@ -875,8 +878,7 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu)
875 878
876 /* clear pending external calls set by sigp interpretation facility */ 879 /* clear pending external calls set by sigp interpretation facility */
877 atomic_clear_mask(CPUSTAT_ECALL_PEND, li->cpuflags); 880 atomic_clear_mask(CPUSTAT_ECALL_PEND, li->cpuflags);
878 atomic_clear_mask(SIGP_CTRL_C, 881 vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl = 0;
879 &vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].ctrl);
880} 882}
881 883
882int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) 884int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
@@ -1000,18 +1002,43 @@ static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
1000 return 0; 1002 return 0;
1001} 1003}
1002 1004
1005static int __inject_extcall_sigpif(struct kvm_vcpu *vcpu, uint16_t src_id)
1006{
1007 unsigned char new_val, old_val;
1008 uint8_t *sigp_ctrl = &vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
1009
1010 new_val = SIGP_CTRL_C | (src_id & SIGP_CTRL_SCN_MASK);
1011 old_val = *sigp_ctrl & ~SIGP_CTRL_C;
1012 if (cmpxchg(sigp_ctrl, old_val, new_val) != old_val) {
1013 /* another external call is pending */
1014 return -EBUSY;
1015 }
1016 atomic_set_mask(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags);
1017 return 0;
1018}
1019
1003static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) 1020static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
1004{ 1021{
1005 struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 1022 struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
1006 struct kvm_s390_extcall_info *extcall = &li->irq.extcall; 1023 struct kvm_s390_extcall_info *extcall = &li->irq.extcall;
1024 uint16_t src_id = irq->u.extcall.code;
1007 1025
1008 VCPU_EVENT(vcpu, 3, "inject: external call source-cpu:%u", 1026 VCPU_EVENT(vcpu, 3, "inject: external call source-cpu:%u",
1009 irq->u.extcall.code); 1027 src_id);
1010 trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_EXTERNAL_CALL, 1028 trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_EXTERNAL_CALL,
1011 irq->u.extcall.code, 0, 2); 1029 src_id, 0, 2);
1012 1030
1031 /* sending vcpu invalid */
1032 if (src_id >= KVM_MAX_VCPUS ||
1033 kvm_get_vcpu(vcpu->kvm, src_id) == NULL)
1034 return -EINVAL;
1035
1036 if (sclp_has_sigpif())
1037 return __inject_extcall_sigpif(vcpu, src_id);
1038
1039 if (!test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs))
1040 return -EBUSY;
1013 *extcall = irq->u.extcall; 1041 *extcall = irq->u.extcall;
1014 set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs);
1015 atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); 1042 atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
1016 return 0; 1043 return 0;
1017} 1044}