aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorChristian Ehrhardt <ehrhardt@linux.vnet.ibm.com>2011-10-18 06:27:15 -0400
committerAvi Kivity <avi@redhat.com>2011-10-30 06:24:05 -0400
commit7697e71f72b45a1bd0abe70918c383100fcc8514 (patch)
treeafad6ff9dcd00a031de31b9cd34d2ae09484586a /arch/s390
parent7eef87dc99e419b1cc051e4417c37e4744d7b661 (diff)
KVM: s390: implement sigp external call
Implement sigp external call, which might be required for guests that issue an external call instead of an emergency signal for IPI. This fixes an issue with "KVM: unknown SIGP: 0x02" when booting such an SMP guest. Signed-off-by: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/include/asm/kvm_host.h7
-rw-r--r--arch/s390/kvm/interrupt.c30
-rw-r--r--arch/s390/kvm/kvm-s390.c2
-rw-r--r--arch/s390/kvm/sigp.c45
4 files changed, 83 insertions, 1 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 00ff00dfb24c..1ca5de07ac36 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -119,6 +119,7 @@ struct kvm_vcpu_stat {
119 u32 instruction_lctlg; 119 u32 instruction_lctlg;
120 u32 exit_program_interruption; 120 u32 exit_program_interruption;
121 u32 exit_instr_and_program; 121 u32 exit_instr_and_program;
122 u32 deliver_external_call;
122 u32 deliver_emergency_signal; 123 u32 deliver_emergency_signal;
123 u32 deliver_service_signal; 124 u32 deliver_service_signal;
124 u32 deliver_virtio_interrupt; 125 u32 deliver_virtio_interrupt;
@@ -138,6 +139,7 @@ struct kvm_vcpu_stat {
138 u32 instruction_stfl; 139 u32 instruction_stfl;
139 u32 instruction_tprot; 140 u32 instruction_tprot;
140 u32 instruction_sigp_sense; 141 u32 instruction_sigp_sense;
142 u32 instruction_sigp_external_call;
141 u32 instruction_sigp_emergency; 143 u32 instruction_sigp_emergency;
142 u32 instruction_sigp_stop; 144 u32 instruction_sigp_stop;
143 u32 instruction_sigp_arch; 145 u32 instruction_sigp_arch;
@@ -174,6 +176,10 @@ struct kvm_s390_prefix_info {
174 __u32 address; 176 __u32 address;
175}; 177};
176 178
179struct kvm_s390_extcall_info {
180 __u16 code;
181};
182
177struct kvm_s390_emerg_info { 183struct kvm_s390_emerg_info {
178 __u16 code; 184 __u16 code;
179}; 185};
@@ -186,6 +192,7 @@ struct kvm_s390_interrupt_info {
186 struct kvm_s390_ext_info ext; 192 struct kvm_s390_ext_info ext;
187 struct kvm_s390_pgm_info pgm; 193 struct kvm_s390_pgm_info pgm;
188 struct kvm_s390_emerg_info emerg; 194 struct kvm_s390_emerg_info emerg;
195 struct kvm_s390_extcall_info extcall;
189 struct kvm_s390_prefix_info prefix; 196 struct kvm_s390_prefix_info prefix;
190 }; 197 };
191}; 198};
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index c9aeb4b4d0b8..87c16705b381 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -38,6 +38,11 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
38 struct kvm_s390_interrupt_info *inti) 38 struct kvm_s390_interrupt_info *inti)
39{ 39{
40 switch (inti->type) { 40 switch (inti->type) {
41 case KVM_S390_INT_EXTERNAL_CALL:
42 if (psw_extint_disabled(vcpu))
43 return 0;
44 if (vcpu->arch.sie_block->gcr[0] & 0x2000ul)
45 return 1;
41 case KVM_S390_INT_EMERGENCY: 46 case KVM_S390_INT_EMERGENCY:
42 if (psw_extint_disabled(vcpu)) 47 if (psw_extint_disabled(vcpu))
43 return 0; 48 return 0;
@@ -98,6 +103,7 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
98 struct kvm_s390_interrupt_info *inti) 103 struct kvm_s390_interrupt_info *inti)
99{ 104{
100 switch (inti->type) { 105 switch (inti->type) {
106 case KVM_S390_INT_EXTERNAL_CALL:
101 case KVM_S390_INT_EMERGENCY: 107 case KVM_S390_INT_EMERGENCY:
102 case KVM_S390_INT_SERVICE: 108 case KVM_S390_INT_SERVICE:
103 case KVM_S390_INT_VIRTIO: 109 case KVM_S390_INT_VIRTIO:
@@ -143,6 +149,28 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
143 exception = 1; 149 exception = 1;
144 break; 150 break;
145 151
152 case KVM_S390_INT_EXTERNAL_CALL:
153 VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call");
154 vcpu->stat.deliver_external_call++;
155 rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1202);
156 if (rc == -EFAULT)
157 exception = 1;
158
159 rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, inti->extcall.code);
160 if (rc == -EFAULT)
161 exception = 1;
162
163 rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW,
164 &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
165 if (rc == -EFAULT)
166 exception = 1;
167
168 rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw,
169 __LC_EXT_NEW_PSW, sizeof(psw_t));
170 if (rc == -EFAULT)
171 exception = 1;
172 break;
173
146 case KVM_S390_INT_SERVICE: 174 case KVM_S390_INT_SERVICE:
147 VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", 175 VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x",
148 inti->ext.ext_params); 176 inti->ext.ext_params);
@@ -522,6 +550,7 @@ int kvm_s390_inject_vm(struct kvm *kvm,
522 break; 550 break;
523 case KVM_S390_PROGRAM_INT: 551 case KVM_S390_PROGRAM_INT:
524 case KVM_S390_SIGP_STOP: 552 case KVM_S390_SIGP_STOP:
553 case KVM_S390_INT_EXTERNAL_CALL:
525 case KVM_S390_INT_EMERGENCY: 554 case KVM_S390_INT_EMERGENCY:
526 default: 555 default:
527 kfree(inti); 556 kfree(inti);
@@ -581,6 +610,7 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
581 break; 610 break;
582 case KVM_S390_SIGP_STOP: 611 case KVM_S390_SIGP_STOP:
583 case KVM_S390_RESTART: 612 case KVM_S390_RESTART:
613 case KVM_S390_INT_EXTERNAL_CALL:
584 case KVM_S390_INT_EMERGENCY: 614 case KVM_S390_INT_EMERGENCY:
585 VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); 615 VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
586 inti->type = s390int->type; 616 inti->type = s390int->type;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 29635678b5ec..9610ba41b974 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -46,6 +46,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
46 { "instruction_lctlg", VCPU_STAT(instruction_lctlg) }, 46 { "instruction_lctlg", VCPU_STAT(instruction_lctlg) },
47 { "instruction_lctl", VCPU_STAT(instruction_lctl) }, 47 { "instruction_lctl", VCPU_STAT(instruction_lctl) },
48 { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) }, 48 { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) },
49 { "deliver_external_call", VCPU_STAT(deliver_external_call) },
49 { "deliver_service_signal", VCPU_STAT(deliver_service_signal) }, 50 { "deliver_service_signal", VCPU_STAT(deliver_service_signal) },
50 { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) }, 51 { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) },
51 { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) }, 52 { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) },
@@ -64,6 +65,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
64 { "instruction_stfl", VCPU_STAT(instruction_stfl) }, 65 { "instruction_stfl", VCPU_STAT(instruction_stfl) },
65 { "instruction_tprot", VCPU_STAT(instruction_tprot) }, 66 { "instruction_tprot", VCPU_STAT(instruction_tprot) },
66 { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) }, 67 { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) },
68 { "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) },
67 { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) }, 69 { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) },
68 { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) }, 70 { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) },
69 { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) }, 71 { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) },
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index d6a50c1fb2e6..f815118835f3 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -87,6 +87,7 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
87 return -ENOMEM; 87 return -ENOMEM;
88 88
89 inti->type = KVM_S390_INT_EMERGENCY; 89 inti->type = KVM_S390_INT_EMERGENCY;
90 inti->emerg.code = vcpu->vcpu_id;
90 91
91 spin_lock(&fi->lock); 92 spin_lock(&fi->lock);
92 li = fi->local_int[cpu_addr]; 93 li = fi->local_int[cpu_addr];
@@ -103,9 +104,47 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
103 wake_up_interruptible(&li->wq); 104 wake_up_interruptible(&li->wq);
104 spin_unlock_bh(&li->lock); 105 spin_unlock_bh(&li->lock);
105 rc = 0; /* order accepted */ 106 rc = 0; /* order accepted */
107 VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
108unlock:
109 spin_unlock(&fi->lock);
110 return rc;
111}
112
113static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
114{
115 struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
116 struct kvm_s390_local_interrupt *li;
117 struct kvm_s390_interrupt_info *inti;
118 int rc;
119
120 if (cpu_addr >= KVM_MAX_VCPUS)
121 return 3; /* not operational */
122
123 inti = kzalloc(sizeof(*inti), GFP_KERNEL);
124 if (!inti)
125 return -ENOMEM;
126
127 inti->type = KVM_S390_INT_EXTERNAL_CALL;
128 inti->extcall.code = vcpu->vcpu_id;
129
130 spin_lock(&fi->lock);
131 li = fi->local_int[cpu_addr];
132 if (li == NULL) {
133 rc = 3; /* not operational */
134 kfree(inti);
135 goto unlock;
136 }
137 spin_lock_bh(&li->lock);
138 list_add_tail(&inti->list, &li->list);
139 atomic_set(&li->active, 1);
140 atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
141 if (waitqueue_active(&li->wq))
142 wake_up_interruptible(&li->wq);
143 spin_unlock_bh(&li->lock);
144 rc = 0; /* order accepted */
145 VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", cpu_addr);
106unlock: 146unlock:
107 spin_unlock(&fi->lock); 147 spin_unlock(&fi->lock);
108 VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
109 return rc; 148 return rc;
110} 149}
111 150
@@ -267,6 +306,10 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
267 rc = __sigp_sense(vcpu, cpu_addr, 306 rc = __sigp_sense(vcpu, cpu_addr,
268 &vcpu->arch.guest_gprs[r1]); 307 &vcpu->arch.guest_gprs[r1]);
269 break; 308 break;
309 case SIGP_EXTERNAL_CALL:
310 vcpu->stat.instruction_sigp_external_call++;
311 rc = __sigp_external_call(vcpu, cpu_addr);
312 break;
270 case SIGP_EMERGENCY: 313 case SIGP_EMERGENCY:
271 vcpu->stat.instruction_sigp_emergency++; 314 vcpu->stat.instruction_sigp_emergency++;
272 rc = __sigp_emergency(vcpu, cpu_addr); 315 rc = __sigp_emergency(vcpu, cpu_addr);