diff options
| author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2012-12-20 09:32:12 -0500 |
|---|---|---|
| committer | Marcelo Tosatti <mtosatti@redhat.com> | 2013-01-07 16:53:43 -0500 |
| commit | fa6b7fe9928d50444c29b29c8563746c6b0c6299 (patch) | |
| tree | 0be284cf322eb82eefdb3df2743740e5578ba5c4 | |
| parent | d6712df95bcfea597fc3ea2405ec13e8b69a7b8c (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.txt | 30 | ||||
| -rw-r--r-- | arch/s390/include/asm/kvm_host.h | 1 | ||||
| -rw-r--r-- | arch/s390/kvm/intercept.c | 1 | ||||
| -rw-r--r-- | arch/s390/kvm/interrupt.c | 37 | ||||
| -rw-r--r-- | arch/s390/kvm/kvm-s390.c | 12 | ||||
| -rw-r--r-- | arch/s390/kvm/kvm-s390.h | 2 | ||||
| -rw-r--r-- | arch/s390/kvm/priv.c | 91 | ||||
| -rw-r--r-- | arch/s390/kvm/trace-s390.h | 20 | ||||
| -rw-r--r-- | include/trace/events/kvm.h | 2 | ||||
| -rw-r--r-- | include/uapi/linux/kvm.h | 11 |
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 | |||
| 2350 | Requirements (PAPR) document available from www.power.org (free | 2350 | Requirements (PAPR) document available from www.power.org (free |
| 2351 | developer registration required to access it). | 2351 | developer 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 | |||
| 2363 | s390 specific. This exit occurs when KVM_CAP_S390_CSS_SUPPORT has been enabled | ||
| 2364 | and TEST SUBCHANNEL was intercepted. If dequeued is set, a pending I/O | ||
| 2365 | interrupt for the target subchannel has been dequeued and subchannel_id, | ||
| 2366 | subchannel_nr, io_int_parm and io_int_word contain the parameters for that | ||
| 2367 | interrupt. 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 | |||
| 2491 | 6.4 KVM_CAP_S390_CSS_SUPPORT | ||
| 2492 | |||
| 2493 | Architectures: s390 | ||
| 2494 | Parameters: none | ||
| 2495 | Returns: 0 on success; -1 on error | ||
| 2496 | |||
| 2497 | This capability enables support for handling of channel I/O instructions. | ||
| 2498 | |||
| 2499 | TEST PENDING INTERRUPTION and the interrupt portion of TEST SUBCHANNEL are | ||
| 2500 | handled in-kernel, while the other I/O instructions are passed to userspace. | ||
| 2501 | |||
| 2502 | When this capability is enabled, KVM_EXIT_S390_TSCH will occur on TEST | ||
| 2503 | SUBCHANNEL 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 | ||
| 267 | extern int sie64a(struct kvm_s390_sie_block *, u64 *); | 268 | extern 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 | ||
| 712 | struct 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 | |||
| 712 | int kvm_s390_inject_vm(struct kvm *kvm, | 749 | int 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; |
| 239 | out_nogmap: | 243 | out_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); |
| 114 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); | ||
