aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2012-12-20 09:32:12 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2013-01-07 16:53:43 -0500
commitfa6b7fe9928d50444c29b29c8563746c6b0c6299 (patch)
tree0be284cf322eb82eefdb3df2743740e5578ba5c4
parentd6712df95bcfea597fc3ea2405ec13e8b69a7b8c (diff)
KVM: s390: Add support for channel I/O instructions.
Add a new capability, KVM_CAP_S390_CSS_SUPPORT, which will pass intercepts for channel I/O instructions to userspace. Only I/O instructions interacting with I/O interrupts need to be handled in-kernel: - TEST PENDING INTERRUPTION (tpi) dequeues and stores pending interrupts entirely in-kernel. - TEST SUBCHANNEL (tsch) dequeues pending interrupts in-kernel and exits via KVM_EXIT_S390_TSCH to userspace for subchannel- related processing. Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com> Reviewed-by: Alexander Graf <agraf@suse.de> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--Documentation/virtual/kvm/api.txt30
-rw-r--r--arch/s390/include/asm/kvm_host.h1
-rw-r--r--arch/s390/kvm/intercept.c1
-rw-r--r--arch/s390/kvm/interrupt.c37
-rw-r--r--arch/s390/kvm/kvm-s390.c12
-rw-r--r--arch/s390/kvm/kvm-s390.h2
-rw-r--r--arch/s390/kvm/priv.c91
-rw-r--r--arch/s390/kvm/trace-s390.h20
-rw-r--r--include/trace/events/kvm.h2
-rw-r--r--include/uapi/linux/kvm.h11
10 files changed, 202 insertions, 5 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 73bd159c5559..f2d6391178b9 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2350,6 +2350,22 @@ The possible hypercalls are defined in the Power Architecture Platform
2350Requirements (PAPR) document available from www.power.org (free 2350Requirements (PAPR) document available from www.power.org (free
2351developer registration required to access it). 2351developer registration required to access it).
2352 2352
2353 /* KVM_EXIT_S390_TSCH */
2354 struct {
2355 __u16 subchannel_id;
2356 __u16 subchannel_nr;
2357 __u32 io_int_parm;
2358 __u32 io_int_word;
2359 __u32 ipb;
2360 __u8 dequeued;
2361 } s390_tsch;
2362
2363s390 specific. This exit occurs when KVM_CAP_S390_CSS_SUPPORT has been enabled
2364and TEST SUBCHANNEL was intercepted. If dequeued is set, a pending I/O
2365interrupt for the target subchannel has been dequeued and subchannel_id,
2366subchannel_nr, io_int_parm and io_int_word contain the parameters for that
2367interrupt. ipb is needed for instruction parameter decoding.
2368
2353 /* Fix the size of the union. */ 2369 /* Fix the size of the union. */
2354 char padding[256]; 2370 char padding[256];
2355 }; 2371 };
@@ -2471,3 +2487,17 @@ For mmu types KVM_MMU_FSL_BOOKE_NOHV and KVM_MMU_FSL_BOOKE_HV:
2471 where "num_sets" is the tlb_sizes[] value divided by the tlb_ways[] value. 2487 where "num_sets" is the tlb_sizes[] value divided by the tlb_ways[] value.
2472 - The tsize field of mas1 shall be set to 4K on TLB0, even though the 2488 - The tsize field of mas1 shall be set to 4K on TLB0, even though the
2473 hardware ignores this value for TLB0. 2489 hardware ignores this value for TLB0.
2490
24916.4 KVM_CAP_S390_CSS_SUPPORT
2492
2493Architectures: s390
2494Parameters: none
2495Returns: 0 on success; -1 on error
2496
2497This capability enables support for handling of channel I/O instructions.
2498
2499TEST PENDING INTERRUPTION and the interrupt portion of TEST SUBCHANNEL are
2500handled in-kernel, while the other I/O instructions are passed to userspace.
2501
2502When this capability is enabled, KVM_EXIT_S390_TSCH will occur on TEST
2503SUBCHANNEL intercepts.
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 29363d155cd5..16bd5d169cdb 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -262,6 +262,7 @@ struct kvm_arch{
262 debug_info_t *dbf; 262 debug_info_t *dbf;
263 struct kvm_s390_float_interrupt float_int; 263 struct kvm_s390_float_interrupt float_int;
264 struct gmap *gmap; 264 struct gmap *gmap;
265 int css_support;
265}; 266};
266 267
267extern int sie64a(struct kvm_s390_sie_block *, u64 *); 268extern int sie64a(struct kvm_s390_sie_block *, u64 *);
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 71af87dbb42c..f26ff1e31bdb 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -264,6 +264,7 @@ static const intercept_handler_t intercept_funcs[] = {
264 [0x0C >> 2] = handle_instruction_and_prog, 264 [0x0C >> 2] = handle_instruction_and_prog,
265 [0x10 >> 2] = handle_noop, 265 [0x10 >> 2] = handle_noop,
266 [0x14 >> 2] = handle_noop, 266 [0x14 >> 2] = handle_noop,
267 [0x18 >> 2] = handle_noop,
267 [0x1C >> 2] = kvm_s390_handle_wait, 268 [0x1C >> 2] = kvm_s390_handle_wait,
268 [0x20 >> 2] = handle_validity, 269 [0x20 >> 2] = handle_validity,
269 [0x28 >> 2] = handle_stop, 270 [0x28 >> 2] = handle_stop,
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index b3b4748485ee..9a128357fd15 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -709,6 +709,43 @@ int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
709 return 0; 709 return 0;
710} 710}
711 711
712struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
713 u64 cr6, u64 schid)
714{
715 struct kvm_s390_float_interrupt *fi;
716 struct kvm_s390_interrupt_info *inti, *iter;
717
718 if ((!schid && !cr6) || (schid && cr6))
719 return NULL;
720 mutex_lock(&kvm->lock);
721 fi = &kvm->arch.float_int;
722 spin_lock(&fi->lock);
723 inti = NULL;
724 list_for_each_entry(iter, &fi->list, list) {
725 if (!is_ioint(iter->type))
726 continue;
727 if (cr6 && ((cr6 & iter->io.io_int_word) == 0))
728 continue;
729 if (schid) {
730 if (((schid & 0x00000000ffff0000) >> 16) !=
731 iter->io.subchannel_id)
732 continue;
733 if ((schid & 0x000000000000ffff) !=
734 iter->io.subchannel_nr)
735 continue;
736 }
737 inti = iter;
738 break;
739 }
740 if (inti)
741 list_del_init(&inti->list);
742 if (list_empty(&fi->list))
743 atomic_set(&fi->active, 0);
744 spin_unlock(&fi->lock);
745 mutex_unlock(&kvm->lock);
746 return inti;
747}
748
712int kvm_s390_inject_vm(struct kvm *kvm, 749int kvm_s390_inject_vm(struct kvm *kvm,
713 struct kvm_s390_interrupt *s390int) 750 struct kvm_s390_interrupt *s390int)
714{ 751{
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 5ff26033825c..5b01f0953900 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -141,6 +141,7 @@ int kvm_dev_ioctl_check_extension(long ext)
141 case KVM_CAP_SYNC_REGS: 141 case KVM_CAP_SYNC_REGS:
142 case KVM_CAP_ONE_REG: 142 case KVM_CAP_ONE_REG:
143 case KVM_CAP_ENABLE_CAP: 143 case KVM_CAP_ENABLE_CAP:
144 case KVM_CAP_S390_CSS_SUPPORT:
144 r = 1; 145 r = 1;
145 break; 146 break;
146 case KVM_CAP_NR_VCPUS: 147 case KVM_CAP_NR_VCPUS:
@@ -235,6 +236,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
235 if (!kvm->arch.gmap) 236 if (!kvm->arch.gmap)
236 goto out_nogmap; 237 goto out_nogmap;
237 } 238 }
239
240 kvm->arch.css_support = 0;
241
238 return 0; 242 return 0;
239out_nogmap: 243out_nogmap:
240 debug_unregister(kvm->arch.dbf); 244 debug_unregister(kvm->arch.dbf);
@@ -658,6 +662,7 @@ rerun_vcpu:
658 case KVM_EXIT_INTR: 662 case KVM_EXIT_INTR:
659 case KVM_EXIT_S390_RESET: 663 case KVM_EXIT_S390_RESET:
660 case KVM_EXIT_S390_UCONTROL: 664 case KVM_EXIT_S390_UCONTROL:
665 case KVM_EXIT_S390_TSCH:
661 break; 666 break;
662 default: 667 default:
663 BUG(); 668 BUG();
@@ -818,6 +823,13 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
818 return -EINVAL; 823 return -EINVAL;
819 824
820 switch (cap->cap) { 825 switch (cap->cap) {
826 case KVM_CAP_S390_CSS_SUPPORT:
827 if (!vcpu->kvm->arch.css_support) {
828 vcpu->kvm->arch.css_support = 1;
829 trace_kvm_s390_enable_css(vcpu->kvm);
830 }
831 r = 0;
832 break;
821 default: 833 default:
822 r = -EINVAL; 834 r = -EINVAL;
823 break; 835 break;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 211b340385a7..3e05deff21b6 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -113,6 +113,8 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
113 struct kvm_s390_interrupt *s390int); 113 struct kvm_s390_interrupt *s390int);
114int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); 114int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
115int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action); 115int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action);
116struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
117 u64 cr6, u64 schid);
116 118
117/* implemented in priv.c */ 119/* implemented in priv.c */
118int kvm_s390_handle_b2(struct kvm_vcpu *vcpu); 120int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 8ad776f87856..0ef9894606e5 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -127,15 +127,98 @@ static int handle_skey(struct kvm_vcpu *vcpu)
127 return 0; 127 return 0;
128} 128}
129 129
130static int handle_io_inst(struct kvm_vcpu *vcpu) 130static int handle_tpi(struct kvm_vcpu *vcpu)
131{ 131{
132 VCPU_EVENT(vcpu, 4, "%s", "I/O instruction"); 132 u64 addr;
133 /* condition code 3 */ 133 struct kvm_s390_interrupt_info *inti;
134 int cc;
135
136 addr = kvm_s390_get_base_disp_s(vcpu);
137
138 inti = kvm_s390_get_io_int(vcpu->kvm, vcpu->run->s.regs.crs[6], 0);
139 if (inti) {
140 if (addr) {
141 /*
142 * Store the two-word I/O interruption code into the
143 * provided area.
144 */
145 put_guest_u16(vcpu, addr, inti->io.subchannel_id);
146 put_guest_u16(vcpu, addr + 2, inti->io.subchannel_nr);
147 put_guest_u32(vcpu, addr + 4, inti->io.io_int_parm);
148 } else {
149 /*
150 * Store the three-word I/O interruption code into
151 * the appropriate lowcore area.
152 */
153 put_guest_u16(vcpu, 184, inti->io.subchannel_id);
154 put_guest_u16(vcpu, 186, inti->io.subchannel_nr);
155 put_guest_u32(vcpu, 188, inti->io.io_int_parm);
156 put_guest_u32(vcpu, 192, inti->io.io_int_word);
157 }
158 cc = 1;
159 } else
160 cc = 0;
161 kfree(inti);
162 /* Set condition code and we're done. */
134 vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); 163 vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
135 vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; 164 vcpu->arch.sie_block->gpsw.mask |= (cc & 3ul) << 44;
136 return 0; 165 return 0;
137} 166}
138 167
168static int handle_tsch(struct kvm_vcpu *vcpu)
169{
170 struct kvm_s390_interrupt_info *inti;
171
172 inti = kvm_s390_get_io_int(vcpu->kvm, 0,
173 vcpu->run->s.regs.gprs[1]);
174
175 /*
176 * Prepare exit to userspace.
177 * We indicate whether we dequeued a pending I/O interrupt
178 * so that userspace can re-inject it if the instruction gets
179 * a program check. While this may re-order the pending I/O
180 * interrupts, this is no problem since the priority is kept
181 * intact.
182 */
183 vcpu->run->exit_reason = KVM_EXIT_S390_TSCH;
184 vcpu->run->s390_tsch.dequeued = !!inti;
185 if (inti) {
186 vcpu->run->s390_tsch.subchannel_id = inti->io.subchannel_id;
187 vcpu->run->s390_tsch.subchannel_nr = inti->io.subchannel_nr;
188 vcpu->run->s390_tsch.io_int_parm = inti->io.io_int_parm;
189 vcpu->run->s390_tsch.io_int_word = inti->io.io_int_word;
190 }
191 vcpu->run->s390_tsch.ipb = vcpu->arch.sie_block->ipb;
192 kfree(inti);
193 return -EREMOTE;
194}
195
196static int handle_io_inst(struct kvm_vcpu *vcpu)
197{
198 VCPU_EVENT(vcpu, 4, "%s", "I/O instruction");
199
200 if (vcpu->kvm->arch.css_support) {
201 /*
202 * Most I/O instructions will be handled by userspace.
203 * Exceptions are tpi and the interrupt portion of tsch.
204 */
205 if (vcpu->arch.sie_block->ipa == 0xb236)
206 return handle_tpi(vcpu);
207 if (vcpu->arch.sie_block->ipa == 0xb235)
208 return handle_tsch(vcpu);
209 /* Handle in userspace. */
210 return -EOPNOTSUPP;
211 } else {
212 /*
213 * Set condition code 3 to stop the guest from issueing channel
214 * I/O instructions.
215 */
216 vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
217 vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44;
218 return 0;
219 }
220}
221
139static int handle_stfl(struct kvm_vcpu *vcpu) 222static int handle_stfl(struct kvm_vcpu *vcpu)
140{ 223{
141 unsigned int facility_list; 224 unsigned int facility_list;
diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/trace-s390.h
index 95fbc1ab88dc..13f30f58a2df 100644
--- a/arch/s390/kvm/trace-s390.h
+++ b/arch/s390/kvm/trace-s390.h
@@ -204,6 +204,26 @@ TRACE_EVENT(kvm_s390_stop_request,
204 ); 204 );
205 205
206 206
207/*
208 * Trace point for enabling channel I/O instruction support.
209 */
210TRACE_EVENT(kvm_s390_enable_css,
211 TP_PROTO(void *kvm),
212 TP_ARGS(kvm),
213
214 TP_STRUCT__entry(
215 __field(void *, kvm)
216 ),
217
218 TP_fast_assign(
219 __entry->kvm = kvm;
220 ),
221
222 TP_printk("enabling channel I/O support (kvm @ %p)\n",
223 __entry->kvm)
224 );
225
226
207#endif /* _TRACE_KVMS390_H */ 227#endif /* _TRACE_KVMS390_H */
208 228
209/* This part must be outside protection */ 229/* This part must be outside protection */
diff --git a/include/trace/events/kvm.h b/include/trace/events/kvm.h
index 7ef9e759f499..a23f47c884cf 100644
--- a/include/trace/events/kvm.h
+++ b/include/trace/events/kvm.h
@@ -14,7 +14,7 @@
14 ERSN(SHUTDOWN), ERSN(FAIL_ENTRY), ERSN(INTR), ERSN(SET_TPR), \ 14 ERSN(SHUTDOWN), ERSN(FAIL_ENTRY), ERSN(INTR), ERSN(SET_TPR), \
15 ERSN(TPR_ACCESS), ERSN(S390_SIEIC), ERSN(S390_RESET), ERSN(DCR),\ 15 ERSN(TPR_ACCESS), ERSN(S390_SIEIC), ERSN(S390_RESET), ERSN(DCR),\
16 ERSN(NMI), ERSN(INTERNAL_ERROR), ERSN(OSI), ERSN(PAPR_HCALL), \ 16 ERSN(NMI), ERSN(INTERNAL_ERROR), ERSN(OSI), ERSN(PAPR_HCALL), \
17 ERSN(S390_UCONTROL) 17 ERSN(S390_UCONTROL), ERSN(S390_TSCH)
18 18
19TRACE_EVENT(kvm_userspace_exit, 19TRACE_EVENT(kvm_userspace_exit,
20 TP_PROTO(__u32 reason, int errno), 20 TP_PROTO(__u32 reason, int errno),
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 80bb3b801116..8bb0bf83afc5 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -168,6 +168,7 @@ struct kvm_pit_config {
168#define KVM_EXIT_PAPR_HCALL 19 168#define KVM_EXIT_PAPR_HCALL 19
169#define KVM_EXIT_S390_UCONTROL 20 169#define KVM_EXIT_S390_UCONTROL 20
170#define KVM_EXIT_WATCHDOG 21 170#define KVM_EXIT_WATCHDOG 21
171#define KVM_EXIT_S390_TSCH 22
171 172
172/* For KVM_EXIT_INTERNAL_ERROR */ 173/* For KVM_EXIT_INTERNAL_ERROR */
173/* Emulate instruction failed. */ 174/* Emulate instruction failed. */
@@ -285,6 +286,15 @@ struct kvm_run {
285 __u64 ret; 286 __u64 ret;
286 __u64 args[9]; 287 __u64 args[9];
287 } papr_hcall; 288 } papr_hcall;
289 /* KVM_EXIT_S390_TSCH */
290 struct {
291 __u16 subchannel_id;
292 __u16 subchannel_nr;
293 __u32 io_int_parm;
294 __u32 io_int_word;
295 __u32 ipb;
296 __u8 dequeued;
297 } s390_tsch;
288 /* Fix the size of the union. */ 298 /* Fix the size of the union. */
289 char padding[256]; 299 char padding[256];
290 }; 300 };
@@ -645,6 +655,7 @@ struct kvm_ppc_smmu_info {
645#define KVM_CAP_IRQFD_RESAMPLE 82 655#define KVM_CAP_IRQFD_RESAMPLE 82
646#define KVM_CAP_PPC_BOOKE_WATCHDOG 83 656#define KVM_CAP_PPC_BOOKE_WATCHDOG 83
647#define KVM_CAP_PPC_HTAB_FD 84 657#define KVM_CAP_PPC_HTAB_FD 84
658#define KVM_CAP_S390_CSS_SUPPORT 85
648 659
649#ifdef KVM_CAP_IRQ_ROUTING 660#ifdef KVM_CAP_IRQ_ROUTING
650 661