History

KVM: s390: Support for I/O interrupts.

Add support for handling I/O interrupts (standard, subchannel-related ones and rudimentary adapter interrupts). The subchannel-identifying parameters are encoded into the interrupt type. I/O interrupts are floating, so they can't be injected on a specific vcpu.

Cornelia Huck committed 13 years ago

Commit d8346b71 parent b1c571a4 files · +116 −2Browse files

Unified · Split

4 files
  1. Documentation/virtual/kvm/api.txt +4 −0
  2. arch/s390/include/asm/kvm_host.h +2 −0
  3. arch/s390/kvm/interrupt.c +101 −2
  4. include/uapi/linux/kvm.h +9 −0
Documentation/virtual/kvm/api.txt+4−0
@@ -2069,6 +2069,10 @@ KVM_S390_INT_VIRTIO (vm) - virtio external interrupt; external interrupt · 2068 unmodified lines
2069KVM_S390_INT_SERVICE (vm) - sclp external interrupt; sclp parameter in parm2069KVM_S390_INT_SERVICE (vm) - sclp external interrupt; sclp parameter in parm
2070KVM_S390_INT_EMERGENCY (vcpu) - sigp emergency; source cpu in parm2070KVM_S390_INT_EMERGENCY (vcpu) - sigp emergency; source cpu in parm
2071KVM_S390_INT_EXTERNAL_CALL (vcpu) - sigp external call; source cpu in parm2071KVM_S390_INT_EXTERNAL_CALL (vcpu) - sigp external call; source cpu in parm
2072KVM_S390_INT_IO(ai,cssid,ssid,schid) (vm) - compound value to indicate an
2073 I/O interrupt (ai - adapter interrupt; cssid,ssid,schid - subchannel);
2074 I/O interruption parameters in parm (subchannel) and parm64 (intparm,
2075 interruption subclass)
2072 2076
2073Note that the vcpu ioctl is asynchronous to vcpu execution.2077Note that the vcpu ioctl is asynchronous to vcpu execution.
2074 2078
arch/s390/include/asm/kvm_host.h+2−0
@@ -74,6 +74,7 @@ struct kvm_s390_sie_block { · 73 unmodified lines
74 __u64 epoch; /* 0x0038 */74 __u64 epoch; /* 0x0038 */
75 __u8 reserved40[4]; /* 0x0040 */75 __u8 reserved40[4]; /* 0x0040 */
76#define LCTL_CR0 0x800076#define LCTL_CR0 0x8000
77#define LCTL_CR6 0x0200
77 __u16 lctl; /* 0x0044 */78 __u16 lctl; /* 0x0044 */
78 __s16 icpua; /* 0x0046 */79 __s16 icpua; /* 0x0046 */
79 __u32 ictl; /* 0x0048 */80 __u32 ictl; /* 0x0048 */
@@ -125,6 +126,7 @@ struct kvm_vcpu_stat { · 45 unmodified lines
125 u32 deliver_prefix_signal;126 u32 deliver_prefix_signal;
126 u32 deliver_restart_signal;127 u32 deliver_restart_signal;
127 u32 deliver_program_int;128 u32 deliver_program_int;
129 u32 deliver_io_int;
128 u32 exit_wait_state;130 u32 exit_wait_state;
129 u32 instruction_stidp;131 u32 instruction_stidp;
130 u32 instruction_spx;132 u32 instruction_spx;
arch/s390/kvm/interrupt.c+101−2
@@ -21,11 +21,26 @@ · 20 unmodified lines
21#include "gaccess.h"21#include "gaccess.h"
22#include "trace-s390.h"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
29static int is_ioint(u64 type)
30{
31 return ((type & 0xfffe0000u) != 0xfffe0000u);
32}
33
24static int psw_extint_disabled(struct kvm_vcpu *vcpu)34static int psw_extint_disabled(struct kvm_vcpu *vcpu)
25{35{
26 return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT);36 return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT);
27}37}
28 38
39static int psw_ioint_disabled(struct kvm_vcpu *vcpu)
40{
41 return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO);
42}
43
29static int psw_interrupts_disabled(struct kvm_vcpu *vcpu)44static int psw_interrupts_disabled(struct kvm_vcpu *vcpu)
30{45{
31 if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) ||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 case KVM_S390_SIGP_SET_PREFIX:82 case KVM_S390_SIGP_SET_PREFIX:
68 case KVM_S390_RESTART:83 case KVM_S390_RESTART:
69 return 1;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 default:91 default:
92 printk(KERN_WARNING "illegal interrupt type %llx\n",
93 inti->type);
71 BUG();94 BUG();
72 }95 }
73 return 0;96 return 0;
@@ -116,6 +139,12 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu, · 42 unmodified lines
116 case KVM_S390_SIGP_STOP:139 case KVM_S390_SIGP_STOP:
117 __set_cpuflag(vcpu, CPUSTAT_STOP_INT);140 __set_cpuflag(vcpu, CPUSTAT_STOP_INT);
118 break;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 default:148 default:
120 BUG();149 BUG();
121 }150 }
@@ -297,6 +326,47 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, · 175 unmodified lines
297 exception = 1;326 exception = 1;
298 break;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 default:370 default:
301 BUG();371 BUG();
302 }372 }
@@ -545,7 +615,7 @@ int kvm_s390_inject_vm(struct kvm *kvm, · 242 unmodified lines
545{615{
546 struct kvm_s390_local_interrupt *li;616 struct kvm_s390_local_interrupt *li;
547 struct kvm_s390_float_interrupt *fi;617 struct kvm_s390_float_interrupt *fi;
548 struct kvm_s390_interrupt_info *inti;618 struct kvm_s390_interrupt_info *inti, *iter;
549 int sigcpu;619 int sigcpu;
550 620
551 inti = kzalloc(sizeof(*inti), GFP_KERNEL);621 inti = kzalloc(sizeof(*inti), GFP_KERNEL);
@@ -569,6 +639,22 @@ int kvm_s390_inject_vm(struct kvm *kvm, · 17 unmodified lines
569 case KVM_S390_SIGP_STOP:639 case KVM_S390_SIGP_STOP:
570 case KVM_S390_INT_EXTERNAL_CALL:640 case KVM_S390_INT_EXTERNAL_CALL:
571 case KVM_S390_INT_EMERGENCY: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 default:658 default:
573 kfree(inti);659 kfree(inti);
574 return -EINVAL;660 return -EINVAL;
@@ -579,7 +665,19 @@ int kvm_s390_inject_vm(struct kvm *kvm, · 4 unmodified lines
579 mutex_lock(&kvm->lock);665 mutex_lock(&kvm->lock);
580 fi = &kvm->arch.float_int;666 fi = &kvm->arch.float_int;
581 spin_lock(&fi->lock);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 atomic_set(&fi->active, 1);681 atomic_set(&fi->active, 1);
584 sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);682 sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS);
585 if (sigcpu == KVM_MAX_VCPUS) {683 if (sigcpu == KVM_MAX_VCPUS) {
@@ -653,6 +751,7 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, · 67 unmodified lines
653 break;751 break;
654 case KVM_S390_INT_VIRTIO:752 case KVM_S390_INT_VIRTIO:
655 case KVM_S390_INT_SERVICE:753 case KVM_S390_INT_SERVICE:
754 case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
656 default:755 default:
657 kfree(inti);756 kfree(inti);
658 return -EINVAL;757 return -EINVAL;
include/uapi/linux/kvm.h+9−0
@@ -401,6 +401,15 @@ struct kvm_s390_psw { · 400 unmodified lines
401#define KVM_S390_INT_SERVICE 0xffff2401u401#define KVM_S390_INT_SERVICE 0xffff2401u
402#define KVM_S390_INT_EMERGENCY 0xffff1201u402#define KVM_S390_INT_EMERGENCY 0xffff1201u
403#define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u403#define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u
404/* Anything below 0xfffe0000u is taken by INT_IO */
405#define KVM_S390_INT_IO(ai,cssid,ssid,schid) \
406 (((schid)) | \
407 ((ssid) << 16) | \
408 ((cssid) << 18) | \
409 ((ai) << 26))
410#define KVM_S390_INT_IO_MIN 0x00000000u
411#define KVM_S390_INT_IO_MAX 0xfffdffffu
412
404 413
405struct kvm_s390_interrupt {414struct kvm_s390_interrupt {
406 __u32 type;415 __u32 type;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t