From patchwork Tue Sep 4 15:13:24 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cornelia Huck X-Patchwork-Id: 181620 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id E4F812C0098 for ; Wed, 5 Sep 2012 02:31:52 +1000 (EST) Received: from localhost ([::1]:53229 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T8upu-00038Z-AO for incoming@patchwork.ozlabs.org; Tue, 04 Sep 2012 11:14:42 -0400 Received: from eggs.gnu.org ([208.118.235.92]:38069) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T8uov-0000w0-By for qemu-devel@nongnu.org; Tue, 04 Sep 2012 11:13:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1T8uoq-00031K-Fi for qemu-devel@nongnu.org; Tue, 04 Sep 2012 11:13:41 -0400 Received: from e06smtp15.uk.ibm.com ([195.75.94.111]:47532) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T8uop-00030o-UF for qemu-devel@nongnu.org; Tue, 04 Sep 2012 11:13:36 -0400 Received: from /spool/local by e06smtp15.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 4 Sep 2012 16:13:35 +0100 Received: from b06cxnps3075.portsmouth.uk.ibm.com (9.149.109.195) by e06smtp15.uk.ibm.com (192.168.101.145) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 4 Sep 2012 16:13:32 +0100 Received: from d06av08.portsmouth.uk.ibm.com (d06av08.portsmouth.uk.ibm.com [9.149.37.249]) by b06cxnps3075.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q84FDQWg59244608 for ; Tue, 4 Sep 2012 15:13:26 GMT Received: from d06av08.portsmouth.uk.ibm.com (loopback [127.0.0.1]) by d06av08.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q84FDWbb021093 for ; Tue, 4 Sep 2012 09:13:32 -0600 Received: from tuxmaker.boeblingen.de.ibm.com (tuxmaker.boeblingen.de.ibm.com [9.152.85.9]) by d06av08.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id q84FDVoD021024; Tue, 4 Sep 2012 09:13:31 -0600 From: Cornelia Huck To: KVM , linux-s390 , qemu-devel Date: Tue, 4 Sep 2012 17:13:24 +0200 Message-Id: <1346771610-52423-2-git-send-email-cornelia.huck@de.ibm.com> X-Mailer: git-send-email 1.7.11.5 In-Reply-To: <1346771610-52423-1-git-send-email-cornelia.huck@de.ibm.com> References: <1346771610-52423-1-git-send-email-cornelia.huck@de.ibm.com> x-cbid: 12090415-0342-0000-0000-000002BFB2C1 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 195.75.94.111 Cc: Carsten Otte , Anthony Liguori , Rusty Russell , Sebastian Ott , Marcelo Tosatti , Heiko Carstens , Alexander Graf , Christian Borntraeger , Avi Kivity , Martin Schwidefsky Subject: [Qemu-devel] [PATCH v2 1/7] s390/kvm: Support for I/O interrupts. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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. Signed-off-by: Cornelia Huck --- arch/s390/include/asm/kvm_host.h | 2 + arch/s390/kvm/interrupt.c | 115 +++++++++++++++++++++++++++++++++++++-- include/linux/kvm.h | 6 ++ 3 files changed, 118 insertions(+), 5 deletions(-) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index b784154..e47f697 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -76,6 +76,7 @@ struct kvm_s390_sie_block { __u64 epoch; /* 0x0038 */ __u8 reserved40[4]; /* 0x0040 */ #define LCTL_CR0 0x8000 +#define LCTL_CR6 0x0200 __u16 lctl; /* 0x0044 */ __s16 icpua; /* 0x0046 */ __u32 ictl; /* 0x0048 */ @@ -127,6 +128,7 @@ struct kvm_vcpu_stat { u32 deliver_prefix_signal; u32 deliver_restart_signal; u32 deliver_program_int; + u32 deliver_io_int; u32 exit_wait_state; u32 instruction_stidp; u32 instruction_spx; diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 7556231..1dccfe7 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -21,11 +21,26 @@ #include "gaccess.h" #include "trace-s390.h" +#define IOINT_SCHID_MASK 0x0000ffff +#define IOINT_SSID_MASK 0x00030000 +#define IOINT_CSSID_MASK 0x03fc0000 +#define IOINT_AI_MASK 0x04000000 + +static int is_ioint(u64 type) +{ + return ((type & 0xfffe0000u) != 0xfffe0000u); +} + static int psw_extint_disabled(struct kvm_vcpu *vcpu) { return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT); } +static int psw_ioint_disabled(struct kvm_vcpu *vcpu) +{ + return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_IO); +} + static int psw_interrupts_disabled(struct kvm_vcpu *vcpu) { if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PER) || @@ -68,7 +83,18 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu, case KVM_S390_RESTART: return 1; default: - BUG(); + if (is_ioint(inti->type)) { + if (psw_ioint_disabled(vcpu)) + return 0; + if (vcpu->arch.sie_block->gcr[6] & + inti->io.io_int_word) + return 1; + return 0; + } else { + printk(KERN_WARNING "illegal interrupt type %llx\n", + inti->type); + BUG(); + } } return 0; } @@ -117,6 +143,13 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu, __set_cpuflag(vcpu, CPUSTAT_STOP_INT); break; default: + if (is_ioint(inti->type)) { + if (psw_ioint_disabled(vcpu)) + __set_cpuflag(vcpu, CPUSTAT_IO_INT); + else + vcpu->arch.sie_block->lctl |= LCTL_CR6; + break; + } BUG(); } } @@ -298,7 +331,49 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, break; default: - BUG(); + if (is_ioint(inti->type)) { + __u32 param0 = ((__u32)inti->io.subchannel_id << 16) | + inti->io.subchannel_nr; + __u64 param1 = ((__u64)inti->io.io_int_parm << 32) | + inti->io.io_int_word; + VCPU_EVENT(vcpu, 4, + "interrupt: I/O %llx", inti->type); + vcpu->stat.deliver_io_int++; + trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type, + param0, param1); + rc = put_guest_u16(vcpu, __LC_SUBCHANNEL_ID, + inti->io.subchannel_id); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u16(vcpu, __LC_SUBCHANNEL_NR, + inti->io.subchannel_nr); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u32(vcpu, __LC_IO_INT_PARM, + inti->io.io_int_parm); + if (rc == -EFAULT) + exception = 1; + + rc = put_guest_u32(vcpu, __LC_IO_INT_WORD, + inti->io.io_int_word); + if (rc == -EFAULT) + exception = 1; + + rc = copy_to_guest(vcpu, __LC_IO_OLD_PSW, + &vcpu->arch.sie_block->gpsw, + sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + + rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, + __LC_IO_NEW_PSW, sizeof(psw_t)); + if (rc == -EFAULT) + exception = 1; + break; + } else + BUG(); } if (exception) { printk("kvm: The guest lowcore is not mapped during interrupt " @@ -547,7 +622,7 @@ int kvm_s390_inject_vm(struct kvm *kvm, { struct kvm_s390_local_interrupt *li; struct kvm_s390_float_interrupt *fi; - struct kvm_s390_interrupt_info *inti; + struct kvm_s390_interrupt_info *inti, *iter; int sigcpu; inti = kzalloc(sizeof(*inti), GFP_KERNEL); @@ -571,9 +646,26 @@ int kvm_s390_inject_vm(struct kvm *kvm, case KVM_S390_SIGP_STOP: case KVM_S390_INT_EXTERNAL_CALL: case KVM_S390_INT_EMERGENCY: - default: kfree(inti); return -EINVAL; + default: + if (!is_ioint(s390int->type)) { + kfree(inti); + return -EINVAL; + } + if (s390int->type & IOINT_AI_MASK) + VM_EVENT(kvm, 5, "%s", "inject: I/O (AI)"); + else + VM_EVENT(kvm, 5, "inject: I/O css %x ss %x schid %04x", + s390int->type & IOINT_CSSID_MASK, + s390int->type & IOINT_SSID_MASK, + s390int->type & IOINT_SCHID_MASK); + inti->type = s390int->type; + inti->io.subchannel_id = s390int->parm >> 16; + inti->io.subchannel_nr = s390int->parm & 0x0000ffffu; + inti->io.io_int_parm = s390int->parm64 >> 32; + inti->io.io_int_word = s390int->parm64 & 0x00000000ffffffffull; + break; } trace_kvm_s390_inject_vm(s390int->type, s390int->parm, s390int->parm64, 2); @@ -581,7 +673,19 @@ int kvm_s390_inject_vm(struct kvm *kvm, mutex_lock(&kvm->lock); fi = &kvm->arch.float_int; spin_lock(&fi->lock); - list_add_tail(&inti->list, &fi->list); + if (!is_ioint(inti->type)) + list_add_tail(&inti->list, &fi->list); + else { + /* Keep I/O interrupts sorted in isc order. */ + list_for_each_entry(iter, &fi->list, list) { + if (!is_ioint(iter->type)) + continue; + if (iter->io.io_int_word <= inti->io.io_int_word) + continue; + break; + } + list_add_tail(&inti->list, &iter->list); + } atomic_set(&fi->active, 1); sigcpu = find_first_bit(fi->idle_mask, KVM_MAX_VCPUS); if (sigcpu == KVM_MAX_VCPUS) { @@ -639,6 +743,7 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, case KVM_S390_INT_VIRTIO: case KVM_S390_INT_SERVICE: default: + /* also includes IOINT */ kfree(inti); return -EINVAL; } diff --git a/include/linux/kvm.h b/include/linux/kvm.h index d808694..5a36e65 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -396,6 +396,12 @@ struct kvm_s390_psw { #define KVM_S390_INT_SERVICE 0xffff2401u #define KVM_S390_INT_EMERGENCY 0xffff1201u #define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u +#define KVM_S390_INT_IO(ai,cssid,ssid,schid) \ + (((schid)) | \ + ((ssid) << 16) | \ + ((cssid) << 18) | \ + ((ai) << 26)) + struct kvm_s390_interrupt { __u32 type;