aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>2014-10-14 09:29:30 -0400
committerChristian Borntraeger <borntraeger@de.ibm.com>2015-01-23 07:25:36 -0500
commitea5f496925755bc5e13adbdcfcb841bc2848913b (patch)
treedd36477016aef39db6ab17926f0ff488b79ebd5b
parentd614be05c8b73033fa141c2f4559c117578b9171 (diff)
KVM: s390: only one external call may be pending at a time
Only one external call may be pending at a vcpu at a time. For this reason, we have to detect whether the SIGP externcal call interpretation facility is available. If so, all external calls have to be injected using this mechanism. SIGP EXTERNAL CALL orders have to return whether another external call is already pending. This check was missing until now. SIGP SENSE hasn't returned yet in all conditions whether an external call was pending. If a SIGP EXTERNAL CALL irq is to be injected and one is already pending, -EBUSY is returned. Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r--arch/s390/include/asm/kvm_host.h8
-rw-r--r--arch/s390/kvm/intercept.c8
-rw-r--r--arch/s390/kvm/interrupt.c57
-rw-r--r--arch/s390/kvm/kvm-s390.c4
-rw-r--r--arch/s390/kvm/kvm-s390.h2
-rw-r--r--arch/s390/kvm/sigp.c17
6 files changed, 68 insertions, 28 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 02e42480609d..4de479e47f71 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -35,11 +35,13 @@
35#define KVM_NR_IRQCHIPS 1 35#define KVM_NR_IRQCHIPS 1
36#define KVM_IRQCHIP_NUM_PINS 4096 36#define KVM_IRQCHIP_NUM_PINS 4096
37 37
38#define SIGP_CTRL_C 0x00800000 38#define SIGP_CTRL_C 0x80
39#define SIGP_CTRL_SCN_MASK 0x3f
39 40
40struct sca_entry { 41struct sca_entry {
41 atomic_t ctrl; 42 __u8 reserved0;
42 __u32 reserved; 43 __u8 sigp_ctrl;
44 __u16 reserved[3];
43 __u64 sda; 45 __u64 sda;
44 __u64 reserved2[2]; 46 __u64 reserved2[2];
45} __attribute__((packed)); 47} __attribute__((packed));
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 897669454fb0..7c868a991411 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -288,11 +288,13 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu)
288 irq.type = KVM_S390_INT_CPU_TIMER; 288 irq.type = KVM_S390_INT_CPU_TIMER;
289 break; 289 break;
290 case EXT_IRQ_EXTERNAL_CALL: 290 case EXT_IRQ_EXTERNAL_CALL:
291 if (kvm_s390_si_ext_call_pending(vcpu))
292 return 0;
293 irq.type = KVM_S390_INT_EXTERNAL_CALL; 291 irq.type = KVM_S390_INT_EXTERNAL_CALL;
294 irq.u.extcall.code = vcpu->arch.sie_block->extcpuaddr; 292 irq.u.extcall.code = vcpu->arch.sie_block->extcpuaddr;
295 break; 293 rc = kvm_s390_inject_vcpu(vcpu, &irq);
294 /* ignore if another external call is already pending */
295 if (rc == -EBUSY)
296 return 0;
297 return rc;
296 default: 298 default:
297 return -EOPNOTSUPP; 299 return -EOPNOTSUPP;
298 } 300 }
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}
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 6a5ed333628c..9bdc9f927e82 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -723,9 +723,11 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
723 vcpu->arch.sie_block->ecb |= 0x10; 723 vcpu->arch.sie_block->ecb |= 0x10;
724 724
725 vcpu->arch.sie_block->ecb2 = 8; 725 vcpu->arch.sie_block->ecb2 = 8;
726 vcpu->arch.sie_block->eca = 0xD1002000U; 726 vcpu->arch.sie_block->eca = 0xC1002000U;
727 if (sclp_has_siif()) 727 if (sclp_has_siif())
728 vcpu->arch.sie_block->eca |= 1; 728 vcpu->arch.sie_block->eca |= 1;
729 if (sclp_has_sigpif())
730 vcpu->arch.sie_block->eca |= 0x10000000U;
729 vcpu->arch.sie_block->fac = (int) (long) vfacilities; 731 vcpu->arch.sie_block->fac = (int) (long) vfacilities;
730 vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE | 732 vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE |
731 ICTL_TPROT; 733 ICTL_TPROT;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 2becffef6b61..c22dce8a7536 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -231,7 +231,7 @@ int s390int_to_s390irq(struct kvm_s390_interrupt *s390int,
231int kvm_s390_vcpu_has_irq(struct kvm_vcpu *vcpu, int exclude_stop); 231int kvm_s390_vcpu_has_irq(struct kvm_vcpu *vcpu, int exclude_stop);
232int psw_extint_disabled(struct kvm_vcpu *vcpu); 232int psw_extint_disabled(struct kvm_vcpu *vcpu);
233void kvm_s390_destroy_adapters(struct kvm *kvm); 233void kvm_s390_destroy_adapters(struct kvm *kvm);
234int kvm_s390_si_ext_call_pending(struct kvm_vcpu *vcpu); 234int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu);
235extern struct kvm_device_ops kvm_flic_ops; 235extern struct kvm_device_ops kvm_flic_ops;
236int kvm_s390_is_stop_irq_pending(struct kvm_vcpu *vcpu); 236int kvm_s390_is_stop_irq_pending(struct kvm_vcpu *vcpu);
237void kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu); 237void kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index 8ae449576574..1524be9120ad 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -26,15 +26,17 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
26 struct kvm_s390_local_interrupt *li; 26 struct kvm_s390_local_interrupt *li;
27 int cpuflags; 27 int cpuflags;
28 int rc; 28 int rc;
29 int ext_call_pending;
29 30
30 li = &dst_vcpu->arch.local_int; 31 li = &dst_vcpu->arch.local_int;
31 32
32 cpuflags = atomic_read(li->cpuflags); 33 cpuflags = atomic_read(li->cpuflags);
33 if (!(cpuflags & (CPUSTAT_ECALL_PEND | CPUSTAT_STOPPED))) 34 ext_call_pending = kvm_s390_ext_call_pending(dst_vcpu);
35 if (!(cpuflags & CPUSTAT_STOPPED) && !ext_call_pending)
34 rc = SIGP_CC_ORDER_CODE_ACCEPTED; 36 rc = SIGP_CC_ORDER_CODE_ACCEPTED;
35 else { 37 else {
36 *reg &= 0xffffffff00000000UL; 38 *reg &= 0xffffffff00000000UL;
37 if (cpuflags & CPUSTAT_ECALL_PEND) 39 if (ext_call_pending)
38 *reg |= SIGP_STATUS_EXT_CALL_PENDING; 40 *reg |= SIGP_STATUS_EXT_CALL_PENDING;
39 if (cpuflags & CPUSTAT_STOPPED) 41 if (cpuflags & CPUSTAT_STOPPED)
40 *reg |= SIGP_STATUS_STOPPED; 42 *reg |= SIGP_STATUS_STOPPED;
@@ -96,7 +98,7 @@ static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu,
96} 98}
97 99
98static int __sigp_external_call(struct kvm_vcpu *vcpu, 100static int __sigp_external_call(struct kvm_vcpu *vcpu,
99 struct kvm_vcpu *dst_vcpu) 101 struct kvm_vcpu *dst_vcpu, u64 *reg)
100{ 102{
101 struct kvm_s390_irq irq = { 103 struct kvm_s390_irq irq = {
102 .type = KVM_S390_INT_EXTERNAL_CALL, 104 .type = KVM_S390_INT_EXTERNAL_CALL,
@@ -105,9 +107,14 @@ static int __sigp_external_call(struct kvm_vcpu *vcpu,
105 int rc; 107 int rc;
106 108
107 rc = kvm_s390_inject_vcpu(dst_vcpu, &irq); 109 rc = kvm_s390_inject_vcpu(dst_vcpu, &irq);
108 if (!rc) 110 if (rc == -EBUSY) {
111 *reg &= 0xffffffff00000000UL;
112 *reg |= SIGP_STATUS_EXT_CALL_PENDING;
113 return SIGP_CC_STATUS_STORED;
114 } else if (rc == 0) {
109 VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", 115 VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x",
110 dst_vcpu->vcpu_id); 116 dst_vcpu->vcpu_id);
117 }
111 118
112 return rc ? rc : SIGP_CC_ORDER_CODE_ACCEPTED; 119 return rc ? rc : SIGP_CC_ORDER_CODE_ACCEPTED;
113} 120}
@@ -303,7 +310,7 @@ static int handle_sigp_dst(struct kvm_vcpu *vcpu, u8 order_code,
303 break; 310 break;
304 case SIGP_EXTERNAL_CALL: 311 case SIGP_EXTERNAL_CALL:
305 vcpu->stat.instruction_sigp_external_call++; 312 vcpu->stat.instruction_sigp_external_call++;
306 rc = __sigp_external_call(vcpu, dst_vcpu); 313 rc = __sigp_external_call(vcpu, dst_vcpu, status_reg);
307 break; 314 break;
308 case SIGP_EMERGENCY_SIGNAL: 315 case SIGP_EMERGENCY_SIGNAL:
309 vcpu->stat.instruction_sigp_emergency++; 316 vcpu->stat.instruction_sigp_emergency++;