From patchwork Mon Apr 13 07:30:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Huacai Chen X-Patchwork-Id: 11485209 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 91B7217D4 for ; Mon, 13 Apr 2020 07:27:44 +0000 (UTC) Received: from vger.kernel.org (unknown [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 51F9220774 for ; Mon, 13 Apr 2020 07:27:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="U+9g9P4V" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 51F9220774 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=lemote.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=kvm-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729300AbgDMH1n (ORCPT ); Mon, 13 Apr 2020 03:27:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.18]:60576 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727612AbgDMH1n (ORCPT ); Mon, 13 Apr 2020 03:27:43 -0400 Received: from mail-pg1-x542.google.com (mail-pg1-x542.google.com [IPv6:2607:f8b0:4864:20::542]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A6F1EC008651; Mon, 13 Apr 2020 00:27:42 -0700 (PDT) Received: by mail-pg1-x542.google.com with SMTP id g6so4104882pgs.9; Mon, 13 Apr 2020 00:27:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=E5XZsIYrkFoN+5jD0I/wrFbIiXPkxWIW2fV5KwTgBEQ=; b=U+9g9P4Vw69qaDQk3gys+jQLuU/kCp9CvuU+g3pGc6BKknmKHDJlxVPExvg3zBv4kD lF6tUZYcIYyR6DhGqHo/XF+ASNt9ZnmkERoe3Y45rLMaWjMfh6SWtlBqX1x05NyWLRaS /ZxSGletmTcXrnBUObh+xfVJI1XH6GugJnx9HtFAfCK/nu9JZgd220pi0pAkA1/IXHD0 bEuPYNzFJktX/fFdkaiBYlke0PGujrhfIfjMLzlfMd056gSDZ7Y7CGycGjyBBHsG6BL5 zkEfelWSnOJ800NfTODxsu7UJj5sp1ewMm4cvNvC6IHq4hMG7HkEAPcuUjyNyQDBErRk 57Hw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=E5XZsIYrkFoN+5jD0I/wrFbIiXPkxWIW2fV5KwTgBEQ=; b=EekY3lV8/0OZ+qQl3WwwbF3071Lg2kVZRQBMdieZdwA4J/UO0pJPCBCZvaRSPb4J+r 6QaT42LMsMiSDsU7318D9RN3p1T0q7AK2J3qN2Ww1dj2z3ibMcPF+vZ3Dc3q3ao6vuYh A4YND+AiC8lnzc8JPKEdjllTxwTy5Fp+X6OR5VABE0OtLMIqqN0X6QW7mbI0KioExdXG 1BlXOLdRKH/A5mFwihmHFK+14hZwSnArB61PQtOoA1DWNa3cTfC8yuddsJK8rBgQLMhm 8181Hsa0UmkrqTxtmbC4RW4LDdlt9LrYZpVGiosc8zalMKIdbIyFFFmG5wsNMKzWBwZn l4Ug== X-Gm-Message-State: AGi0Pub3bhDqQDa7ScDEUt0mmtnYFL67ds+IEV60MLF6/Dp3kImn2nFz dOjQ9ZqKckEAntyYLqUcllw= X-Google-Smtp-Source: APiQypJOPUPgo1mrI2VzVpnQy4tPiVfjCCn1bn/fu8hLYrHYsLB8kwYoXC4VuJRWgZ3eO9qL2aDOrA== X-Received: by 2002:a63:5f01:: with SMTP id t1mr15385599pgb.186.1586762862161; Mon, 13 Apr 2020 00:27:42 -0700 (PDT) Received: from software.domain.org (28.144.92.34.bc.googleusercontent.com. [34.92.144.28]) by smtp.gmail.com with ESMTPSA id u8sm7241341pgl.19.2020.04.13.00.27.39 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 13 Apr 2020 00:27:41 -0700 (PDT) From: Huacai Chen To: Paolo Bonzini , Thomas Bogendoerfer Cc: kvm@vger.kernel.org, qemu-devel@nongnu.org, linux-mips@vger.kernel.org, Fuxin Zhang , Huacai Chen , Jiaxun Yang , Huacai Chen Subject: [PATCH 11/15] KVM: MIPS: Add Loongson-3 Virtual IPI interrupt support Date: Mon, 13 Apr 2020 15:30:20 +0800 Message-Id: <1586763024-12197-12-git-send-email-chenhc@lemote.com> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1586763024-12197-1-git-send-email-chenhc@lemote.com> References: <1586763024-12197-1-git-send-email-chenhc@lemote.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org This patch add Loongson-3 Virtual IPI interrupt support in the kernel, because emulate it in QEMU is too expensive for performance. Signed-off-by: Huacai Chen Co-developed-by: Jiaxun Yang --- arch/mips/include/asm/kvm_host.h | 32 ++++++ arch/mips/kvm/Makefile | 3 + arch/mips/kvm/emulate.c | 21 +++- arch/mips/kvm/loongson_ipi.c | 215 +++++++++++++++++++++++++++++++++++++++ arch/mips/kvm/mips.c | 6 ++ 5 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 arch/mips/kvm/loongson_ipi.c diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index 2258a2e..4022712 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -23,6 +23,8 @@ #include #include +#include + /* MIPS KVM register ids */ #define MIPS_CP0_32(_R, _S) \ (KVM_REG_MIPS_CP0 | KVM_REG_SIZE_U32 | (8 * (_R) + (_S))) @@ -181,11 +183,39 @@ struct kvm_vcpu_stat { struct kvm_arch_memory_slot { }; +#ifdef CONFIG_CPU_LOONGSON64 +typedef struct ipi_state { + uint32_t status; + uint32_t en; + uint32_t set; + uint32_t clear; + uint64_t buf[4]; +} ipi_state; + +struct loongson_kvm_ipi; + +typedef struct ipi_io_device { + int node_id; + struct loongson_kvm_ipi *ipi; + struct kvm_io_device device; +} ipi_io_device; + +struct loongson_kvm_ipi { + spinlock_t lock; + struct kvm *kvm; + ipi_state ipistate[16]; + ipi_io_device dev_ipi[4]; +}; +#endif + struct kvm_arch { /* Guest physical mm */ struct mm_struct gpa_mm; /* Mask of CPUs needing GPA ASID flush */ cpumask_t asid_flush_mask; +#ifdef CONFIG_CPU_LOONGSON64 + struct loongson_kvm_ipi ipi; +#endif }; #define N_MIPS_COPROC_REGS 32 @@ -1133,6 +1163,8 @@ extern int kvm_mips_trans_mtc0(union mips_instruction inst, u32 *opc, /* Misc */ extern void kvm_mips_dump_stats(struct kvm_vcpu *vcpu); extern unsigned long kvm_mips_get_ramsize(struct kvm *kvm); +extern int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, + struct kvm_mips_interrupt *irq); static inline void kvm_arch_hardware_unsetup(void) {} static inline void kvm_arch_sync_events(struct kvm *kvm) {} diff --git a/arch/mips/kvm/Makefile b/arch/mips/kvm/Makefile index 0a3cef6..506c4ac 100644 --- a/arch/mips/kvm/Makefile +++ b/arch/mips/kvm/Makefile @@ -13,6 +13,9 @@ kvm-objs := $(common-objs-y) mips.o emulate.o entry.o \ fpu.o kvm-objs += hypcall.o kvm-objs += mmu.o +ifdef CONFIG_CPU_LOONGSON64 +kvm-objs += loongson_ipi.o +endif ifdef CONFIG_KVM_MIPS_VZ kvm-objs += vz.o diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c index 754094b..aa2db51 100644 --- a/arch/mips/kvm/emulate.c +++ b/arch/mips/kvm/emulate.c @@ -1600,6 +1600,7 @@ enum emulation_result kvm_mips_emulate_store(union mips_instruction inst, struct kvm_run *run, struct kvm_vcpu *vcpu) { + int r; enum emulation_result er; u32 rt; void *data = run->mmio.data; @@ -1666,9 +1667,17 @@ enum emulation_result kvm_mips_emulate_store(union mips_instruction inst, goto out_fail; } - run->mmio.is_write = 1; vcpu->mmio_needed = 1; + run->mmio.is_write = 1; vcpu->mmio_is_write = 1; + + r = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr, run->mmio.len, data); + + if (!r) { + vcpu->mmio_needed = 0; + return EMULATE_DONE; + } + return EMULATE_DO_MMIO; out_fail: @@ -1681,6 +1690,7 @@ enum emulation_result kvm_mips_emulate_load(union mips_instruction inst, u32 cause, struct kvm_run *run, struct kvm_vcpu *vcpu) { + int r; enum emulation_result er; unsigned long curr_pc; u32 op, rt; @@ -1745,6 +1755,15 @@ enum emulation_result kvm_mips_emulate_load(union mips_instruction inst, run->mmio.is_write = 0; vcpu->mmio_is_write = 0; + + r = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr, run->mmio.len, run->mmio.data); + + if (!r) { + kvm_mips_complete_mmio_load(vcpu, run); + vcpu->mmio_needed = 0; + return EMULATE_DONE; + } + return EMULATE_DO_MMIO; } diff --git a/arch/mips/kvm/loongson_ipi.c b/arch/mips/kvm/loongson_ipi.c new file mode 100644 index 00000000..3e22532 --- /dev/null +++ b/arch/mips/kvm/loongson_ipi.c @@ -0,0 +1,215 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Loongson-3 Virtual IPI interrupt support. + * + * Copyright (C) 2019 Loongson Technologies, Inc. All rights reserved. + * + * Authors: Chen Zhu + * Authors: Huacai Chen + */ + +#include + +#define IPI_BASE 0x3ff01000ULL + +#define CORE0_STATUS_OFF 0x000 +#define CORE0_EN_OFF 0x004 +#define CORE0_SET_OFF 0x008 +#define CORE0_CLEAR_OFF 0x00c +#define CORE0_BUF_20 0x020 +#define CORE0_BUF_28 0x028 +#define CORE0_BUF_30 0x030 +#define CORE0_BUF_38 0x038 + +#define CORE1_STATUS_OFF 0x100 +#define CORE1_EN_OFF 0x104 +#define CORE1_SET_OFF 0x108 +#define CORE1_CLEAR_OFF 0x10c +#define CORE1_BUF_20 0x120 +#define CORE1_BUF_28 0x128 +#define CORE1_BUF_30 0x130 +#define CORE1_BUF_38 0x138 + +#define CORE2_STATUS_OFF 0x200 +#define CORE2_EN_OFF 0x204 +#define CORE2_SET_OFF 0x208 +#define CORE2_CLEAR_OFF 0x20c +#define CORE2_BUF_20 0x220 +#define CORE2_BUF_28 0x228 +#define CORE2_BUF_30 0x230 +#define CORE2_BUF_38 0x238 + +#define CORE3_STATUS_OFF 0x300 +#define CORE3_EN_OFF 0x304 +#define CORE3_SET_OFF 0x308 +#define CORE3_CLEAR_OFF 0x30c +#define CORE3_BUF_20 0x320 +#define CORE3_BUF_28 0x328 +#define CORE3_BUF_30 0x330 +#define CORE3_BUF_38 0x338 + +static int loongson_vipi_read(struct loongson_kvm_ipi *ipi, gpa_t addr, int len, void *val) +{ + uint32_t core = (addr >> 8) & 3; + uint32_t node = (addr >> 44) & 3; + uint32_t id = core + node * 4; + uint64_t offset = addr & 0xff; + void *pbuf; + ipi_state *s = &(ipi->ipistate[id]); + + BUG_ON(offset & (len - 1)); + + switch (offset) { + case CORE0_STATUS_OFF: + *(uint64_t *)val = s->status; + break; + + case CORE0_EN_OFF: + *(uint64_t *)val = s->en; + break; + + case CORE0_SET_OFF: + *(uint64_t *)val = 0; + break; + + case CORE0_CLEAR_OFF: + *(uint64_t *)val = 0; + break; + + case CORE0_BUF_20 ... CORE0_BUF_38: + pbuf = (void *)s->buf + (offset - 0x20); + if (len == 8) + *(uint64_t *)val = *(uint64_t *)pbuf; + else /* Assume len == 4 */ + *(uint32_t *)val = *(uint32_t *)pbuf; + break; + + default: + printk("loongson_vipi_read() with unknown addr %llx \n", addr); + break; + } + + return 0; +} + +static int loongson_vipi_write(struct loongson_kvm_ipi *ipi, gpa_t addr, int len, const void *val) +{ + uint32_t core = (addr >> 8) & 3; + uint32_t node = (addr >> 44) & 3; + uint32_t id = core + node * 4; + uint64_t data, offset = addr & 0xff; + void *pbuf; + struct kvm *kvm = ipi->kvm; + struct kvm_mips_interrupt irq; + ipi_state *s = &(ipi->ipistate[id]); + + data = *(uint64_t *)val; + BUG_ON(offset & (len - 1)); + + switch (offset) { + case CORE0_STATUS_OFF: + break; + + case CORE0_EN_OFF: + s->en = data; + break; + + case CORE0_SET_OFF: + s->status |= data; + irq.cpu = id; + irq.irq = 6; + kvm_vcpu_ioctl_interrupt(kvm->vcpus[id], &irq); + break; + + case CORE0_CLEAR_OFF: + s->status &= ~data; + if (!s->status) { + irq.cpu = id; + irq.irq = -6; + kvm_vcpu_ioctl_interrupt(kvm->vcpus[id],&irq); + } + break; + + case CORE0_BUF_20 ... CORE0_BUF_38: + pbuf = (void *)s->buf + (offset - 0x20); + if (len == 8) + *(uint64_t *)pbuf = (uint64_t)data; + else /* Assume len == 4 */ + *(uint32_t *)pbuf = (uint32_t)data; + break; + + default: + printk("loongson_vipi_write() with unknown addr %llx \n", addr); + break; + } + + return 0; +} + +static int kvm_ipi_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev, + gpa_t addr, int len, void *val) +{ + unsigned long flags; + ipi_io_device *ipi_device; + struct loongson_kvm_ipi *ipi; + + ipi_device = container_of(dev, ipi_io_device, device); + ipi = ipi_device->ipi; + + spin_lock_irqsave(&ipi->lock, flags); + loongson_vipi_read(ipi, addr, len, val); + spin_unlock_irqrestore(&ipi->lock, flags); + + return 0; +} + +static int kvm_ipi_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev, + gpa_t addr, int len, const void *val) +{ + unsigned long flags; + ipi_io_device *ipi_device; + struct loongson_kvm_ipi *ipi; + + ipi_device = container_of(dev, ipi_io_device, device); + ipi = ipi_device->ipi; + + spin_lock_irqsave(&ipi->lock, flags); + loongson_vipi_write(ipi, addr, len, val); + spin_unlock_irqrestore(&ipi->lock, flags); + + return 0; +} + +static const struct kvm_io_device_ops kvm_ipi_ops = { + .read = kvm_ipi_read, + .write = kvm_ipi_write, +}; + +void kvm_init_loongson_ipi(struct kvm *kvm) +{ + int i; + unsigned long addr; + struct loongson_kvm_ipi *s; + struct kvm_io_device *device; + + s = &kvm->arch.ipi; + s->kvm = kvm; + spin_lock_init(&s->lock); + + /* + * Initialize IPI device + */ + for (i = 0; i < 4; i++) { + device = &s->dev_ipi[i].device; + kvm_iodevice_init(device, &kvm_ipi_ops); + addr = (((unsigned long)i) << 44) + IPI_BASE; + mutex_lock(&kvm->slots_lock); + kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, addr, 0x400, device); + mutex_unlock(&kvm->slots_lock); + s->dev_ipi[i].ipi = s; + s->dev_ipi[i].node_id = i; + } +} diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 5c3a414..20acd50 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -128,6 +128,8 @@ int kvm_arch_check_processor_compat(void) return 0; } +extern void kvm_init_loongson_ipi(struct kvm *kvm); + int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) { switch (type) { @@ -147,6 +149,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) if (!kvm->arch.gpa_mm.pgd) return -ENOMEM; +#ifdef CONFIG_CPU_LOONGSON64 + kvm_init_loongson_ipi(kvm); +#endif + return 0; }