| @@ -21,11 +21,26 @@ · 20 unmodified lines |
| 21 | 21 | #include "gaccess.h" |
| 22 | 22 | #include "trace-s390.h" |
| 23 | 23 | |
| 24 | +#define IOINT_SCHID_MASK 0x0000ffff |
| 25 | +#define IOINT_SSID_MASK 0x00030000 |
| 26 | +#define IOINT_CSSID_MASK 0x03fc0000 |
| 27 | +#define IOINT_AI_MASK 0x04000000 |
| 28 | + |
| 29 | +static int is_ioint(u64 type) |
| 30 | +{ |
| 31 | + return ((type & 0xfffe0000u) != 0xfffe0000u); |
| 32 | +} |
| 33 | + |
| 24 | 34 | static int psw_extint_disabled(struct kvm_vcpu *vcpu) |
| 25 | 35 | { |
| 26 | 36 | return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT); |
| 27 | 37 | } |
| 28 | 38 | |
| 39 | +static int psw_ioint_disabled(struct kvm_vcpu *vcpu) |
| 40 | +{ |
| 41 | + return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO); |
| 42 | +} |
| 43 | + |
| 29 | 44 | static int psw_interrupts_disabled(struct kvm_vcpu *vcpu) |
| 30 | 45 | { |
| 31 | 46 | if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) || |
| @@ -67,7 +82,15 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu, · 35 unmodified lines |
| 67 | 82 | case KVM_S390_SIGP_SET_PREFIX: |
| 68 | 83 | case KVM_S390_RESTART: |
| 69 | 84 | return 1; |
| 85 | + case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
| 86 | + if (psw_ioint_disabled(vcpu)) |
| 87 | + return 0; |
| 88 | + if (vcpu->arch.sie_block->gcr[6] & inti->io.io_int_word) |
| 89 | + return 1; |
| 90 | + return 0; |
| 70 | 91 | default: |
| 92 | + printk(KERN_WARNING "illegal interrupt type %llx\n", |
| 93 | + inti->type); |
| 71 | 94 | BUG(); |
| 72 | 95 | } |
| 73 | 96 | return 0; |
| @@ -116,6 +139,12 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu, · 42 unmodified lines |
| 116 | 139 | case KVM_S390_SIGP_STOP: |
| 117 | 140 | __set_cpuflag(vcpu, CPUSTAT_STOP_INT); |
| 118 | 141 | break; |
| 142 | + case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
| 143 | + if (psw_ioint_disabled(vcpu)) |
| 144 | + __set_cpuflag(vcpu, CPUSTAT_IO_INT); |
| 145 | + else |
| 146 | + vcpu->arch.sie_block->lctl |= LCTL_CR6; |
| 147 | + break; |
| 119 | 148 | default: |
| 120 | 149 | BUG(); |
| 121 | 150 | } |
| @@ -297,6 +326,47 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, · 175 unmodified lines |
| 297 | 326 | exception = 1; |
| 298 | 327 | break; |
| 299 | 328 | |
| 329 | + case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
| 330 | + { |
| 331 | + __u32 param0 = ((__u32)inti->io.subchannel_id << 16) | |
| 332 | + inti->io.subchannel_nr; |
| 333 | + __u64 param1 = ((__u64)inti->io.io_int_parm << 32) | |
| 334 | + inti->io.io_int_word; |
| 335 | + VCPU_EVENT(vcpu, 4, "interrupt: I/O %llx", inti->type); |
| 336 | + vcpu->stat.deliver_io_int++; |
| 337 | + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, |
| 338 | + param0, param1); |
| 339 | + rc = put_guest_u16(vcpu, __LC_SUBCHANNEL_ID, |
| 340 | + inti->io.subchannel_id); |
| 341 | + if (rc == -EFAULT) |
| 342 | + exception = 1; |
| 343 | + |
| 344 | + rc = put_guest_u16(vcpu, __LC_SUBCHANNEL_NR, |
| 345 | + inti->io.subchannel_nr); |
| 346 | + if (rc == -EFAULT) |
| 347 | + exception = 1; |
| 348 | + |
| 349 | + rc = put_guest_u32(vcpu, __LC_IO_INT_PARM, |
| 350 | + inti->io.io_int_parm); |
| 351 | + if (rc == -EFAULT) |
| 352 | + exception = 1; |
| 353 | + |
| 354 | + rc = put_guest_u32(vcpu, __LC_IO_INT_WORD, |
| 355 | + inti->io.io_int_word); |
| 356 | + if (rc == -EFAULT) |
| 357 | + exception = 1; |
| 358 | + |
| 359 | + rc = copy_to_guest(vcpu, __LC_IO_OLD_PSW, |
| 360 | + &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); |
| 361 | + if (rc == -EFAULT) |
| 362 | + exception = 1; |
| 363 | + |
| 364 | + rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, |
| 365 | + __LC_IO_NEW_PSW, sizeof(psw_t)); |
| 366 | + if (rc == -EFAULT) |
| 367 | + exception = 1; |
| 368 | + break; |
| 369 | + } |
| 300 | 370 | default: |
| 301 | 371 | BUG(); |
| 302 | 372 | } |
| @@ -545,7 +615,7 @@ int kvm_s390_inject_vm(struct kvm *kvm, · 242 unmodified lines |
| 545 | 615 | { |
| 546 | 616 | struct kvm_s390_local_interrupt *li; |
| 547 | 617 | struct kvm_s390_float_interrupt *fi; |
| 548 | | − struct kvm_s390_interrupt_info *inti; |
| 618 | + struct kvm_s390_interrupt_info *inti, *iter; |
| 549 | 619 | int sigcpu; |
| 550 | 620 | |
| 551 | 621 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); |
| @@ -569,6 +639,22 @@ int kvm_s390_inject_vm(struct kvm *kvm, · 17 unmodified lines |
| 569 | 639 | case KVM_S390_SIGP_STOP: |
| 570 | 640 | case KVM_S390_INT_EXTERNAL_CALL: |
| 571 | 641 | case KVM_S390_INT_EMERGENCY: |
| 642 | + kfree(inti); |
| 643 | + return -EINVAL; |
| 644 | + case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
| 645 | + if (s390int->type & IOINT_AI_MASK) |
| 646 | + VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)"); |
| 647 | + else |
| 648 | + VM_EVENT(kvm, 5, "inject: I/O css %x ss %x schid %04x", |
| 649 | + s390int->type & IOINT_CSSID_MASK, |
| 650 | + s390int->type & IOINT_SSID_MASK, |
| 651 | + s390int->type & IOINT_SCHID_MASK); |
| 652 | + inti->type = s390int->type; |
| 653 | + inti->io.subchannel_id = s390int->parm >> 16; |
| 654 | + inti->io.subchannel_nr = s390int->parm & 0x0000ffffu; |
| 655 | + inti->io.io_int_parm = s390int->parm64 >> 32; |
| 656 | + inti->io.io_int_word = s390int->parm64 & 0x00000000ffffffffull; |
| 657 | + break; |
| 572 | 658 | default: |
| 573 | 659 | kfree(inti); |
| 574 | 660 | return -EINVAL; |
| @@ -579,7 +665,19 @@ int kvm_s390_inject_vm(struct kvm *kvm, · 4 unmodified lines |
| 579 | 665 | mutex_lock(&kvm->lock); |
| 580 | 666 | fi = &kvm->arch.float_int; |
| 581 | 667 | spin_lock(&fi->lock); |
| 582 | | − list_add_tail(&inti->list, &fi->list); |
| 668 | + if (!is_ioint(inti->type)) |
| 669 | + list_add_tail(&inti->list, &fi->list); |
| 670 | + else { |
| 671 | + /* Keep I/O interrupts sorted in isc order. */ |
| 672 | + list_for_each_entry(iter, &fi->list, list) { |
| 673 | + if (!is_ioint(iter->type)) |
| 674 | + continue; |
| 675 | + if (iter->io.io_int_word <= inti->io.io_int_word) |
| 676 | + continue; |
| 677 | + break; |
| 678 | + } |
| 679 | + list_add_tail(&inti->list, &iter->list); |
| 680 | + } |
| 583 | 681 | atomic_set(&fi->active, 1); |
| 584 | 682 | sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS); |
| 585 | 683 | if (sigcpu == KVM_MAX_VCPUS) { |
| @@ -653,6 +751,7 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, · 67 unmodified lines |
| 653 | 751 | break; |
| 654 | 752 | case KVM_S390_INT_VIRTIO: |
| 655 | 753 | case KVM_S390_INT_SERVICE: |
| 754 | + case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: |
| 656 | 755 | default: |
| 657 | 756 | kfree(inti); |
| 658 | 757 | return -EINVAL; |