From patchwork Fri Jul 1 14:24:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12903403 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8A81DC433EF for ; Fri, 1 Jul 2022 14:30:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232012AbiGAOam (ORCPT ); Fri, 1 Jul 2022 10:30:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48264 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233015AbiGAO3i (ORCPT ); Fri, 1 Jul 2022 10:29:38 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 596DA3A181 for ; Fri, 1 Jul 2022 07:25:34 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id DB2D61424; Fri, 1 Jul 2022 07:25:21 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 47CA83F792; Fri, 1 Jul 2022 07:25:20 -0700 (PDT) From: Jean-Philippe Brucker To: will@kernel.org Cc: andre.przywara@arm.com, alexandru.elisei@arm.com, kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org, jean-philippe@linaro.org Subject: [PATCH kvmtool v2 01/12] virtio/pci: Delete MSI routes Date: Fri, 1 Jul 2022 15:24:23 +0100 Message-Id: <20220701142434.75170-2-jean-philippe.brucker@arm.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com> References: <20220701142434.75170-1-jean-philippe.brucker@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org On exit_vq() and device reset, remove the MSI routes that were set up at runtime. Signed-off-by: Jean-Philippe Brucker --- virtio/pci.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/virtio/pci.c b/virtio/pci.c index 1a549314..9b710852 100644 --- a/virtio/pci.c +++ b/virtio/pci.c @@ -60,6 +60,13 @@ static int virtio_pci__add_msix_route(struct virtio_pci *vpci, u32 vec) return gsi; } +static void virtio_pci__del_msix_route(struct virtio_pci *vpci, u32 gsi) +{ + struct msi_msg msg = { 0 }; + + irq__update_msix_route(vpci->kvm, gsi, &msg); +} + static void virtio_pci__ioevent_callback(struct kvm *kvm, void *param) { struct virtio_pci_ioevent_param *ioeventfd = param; @@ -128,6 +135,9 @@ static void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, u32 mmio_addr = virtio_pci__mmio_addr(vpci); u16 port_addr = virtio_pci__port_addr(vpci); + virtio_pci__del_msix_route(vpci, vpci->gsis[vq]); + vpci->gsis[vq] = 0; + vpci->vq_vector[vq] = VIRTIO_MSI_NO_VECTOR; ioeventfd__del_event(mmio_addr + VIRTIO_PCI_QUEUE_NOTIFY, vq); ioeventfd__del_event(port_addr + VIRTIO_PCI_QUEUE_NOTIFY, vq); virtio_exit_vq(kvm, vdev, vpci->dev, vq); @@ -623,6 +633,10 @@ int virtio_pci__reset(struct kvm *kvm, struct virtio_device *vdev) unsigned int vq; struct virtio_pci *vpci = vdev->virtio; + virtio_pci__del_msix_route(vpci, vpci->config_gsi); + vpci->config_gsi = 0; + vpci->config_vector = VIRTIO_MSI_NO_VECTOR; + for (vq = 0; vq < vdev->ops->get_vq_count(kvm, vpci->dev); vq++) virtio_pci_exit_vq(kvm, vdev, vq); From patchwork Fri Jul 1 14:24:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12903405 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 303C7C43334 for ; Fri, 1 Jul 2022 14:30:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233024AbiGAOar (ORCPT ); Fri, 1 Jul 2022 10:30:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49598 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233017AbiGAO3i (ORCPT ); Fri, 1 Jul 2022 10:29:38 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 98D8F3DA7E for ; Fri, 1 Jul 2022 07:25:34 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 7ED7C143D; Fri, 1 Jul 2022 07:25:23 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id DDEB03F792; Fri, 1 Jul 2022 07:25:21 -0700 (PDT) From: Jean-Philippe Brucker To: will@kernel.org Cc: andre.przywara@arm.com, alexandru.elisei@arm.com, kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org, jean-philippe@linaro.org Subject: [PATCH kvmtool v2 02/12] virtio: Extract init_vq() for PCI and MMIO Date: Fri, 1 Jul 2022 15:24:24 +0100 Message-Id: <20220701142434.75170-3-jean-philippe.brucker@arm.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com> References: <20220701142434.75170-1-jean-philippe.brucker@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Modern virtio will need to reuse this code when initializing a virtqueue. It's not much, but still nicer to have next to exit_vq(). Signed-off-by: Jean-Philippe Brucker --- virtio/mmio.c | 19 +++++++++++++++---- virtio/pci.c | 19 +++++++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/virtio/mmio.c b/virtio/mmio.c index 268a4391..2a96e0e3 100644 --- a/virtio/mmio.c +++ b/virtio/mmio.c @@ -79,6 +79,20 @@ int virtio_mmio_signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq) return 0; } +static int virtio_mmio_init_vq(struct kvm *kvm, struct virtio_device *vdev, + int vq) +{ + int ret; + struct virtio_mmio *vmmio = vdev->virtio; + + ret = virtio_mmio_init_ioeventfd(vmmio->kvm, vdev, vq); + if (ret) { + pr_err("couldn't add ioeventfd for vq %d: %d", vq, ret); + return ret; + } + return vdev->ops->init_vq(vmmio->kvm, vmmio->dev, vq); +} + static void virtio_mmio_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq) { @@ -200,10 +214,7 @@ static void virtio_mmio_config_out(struct kvm_cpu *vcpu, .align = vmmio->hdr.queue_align, .pgsize = vmmio->hdr.guest_page_size, }; - virtio_mmio_init_ioeventfd(vmmio->kvm, vdev, - vmmio->hdr.queue_sel); - vdev->ops->init_vq(vmmio->kvm, vmmio->dev, - vmmio->hdr.queue_sel); + virtio_mmio_init_vq(kvm, vdev, vmmio->hdr.queue_sel); } else { virtio_mmio_exit_vq(kvm, vdev, vmmio->hdr.queue_sel); } diff --git a/virtio/pci.c b/virtio/pci.c index 9b710852..f0459925 100644 --- a/virtio/pci.c +++ b/virtio/pci.c @@ -128,6 +128,20 @@ free_ioport_evt: return r; } +static int virtio_pci_init_vq(struct kvm *kvm, struct virtio_device *vdev, + int vq) +{ + int ret; + struct virtio_pci *vpci = vdev->virtio; + + ret = virtio_pci__init_ioeventfd(kvm, vdev, vq); + if (ret) { + pr_err("couldn't add ioeventfd for vq %d: %d", vq, ret); + return ret; + } + return vdev->ops->init_vq(kvm, vpci->dev, vq); +} + static void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq) { @@ -314,10 +328,7 @@ static bool virtio_pci__data_out(struct kvm_cpu *vcpu, struct virtio_device *vde .align = VIRTIO_PCI_VRING_ALIGN, .pgsize = 1 << VIRTIO_PCI_QUEUE_ADDR_SHIFT, }; - virtio_pci__init_ioeventfd(kvm, vdev, - vpci->queue_selector); - vdev->ops->init_vq(kvm, vpci->dev, - vpci->queue_selector); + virtio_pci_init_vq(kvm, vdev, vpci->queue_selector); } else { virtio_pci_exit_vq(kvm, vdev, vpci->queue_selector); } From patchwork Fri Jul 1 14:24:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12903406 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0DC3EC433EF for ; Fri, 1 Jul 2022 14:30:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233258AbiGAOaw (ORCPT ); Fri, 1 Jul 2022 10:30:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48640 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231757AbiGAO3j (ORCPT ); Fri, 1 Jul 2022 10:29:39 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 8DA9F6EEAA for ; Fri, 1 Jul 2022 07:25:36 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 1DB861515; Fri, 1 Jul 2022 07:25:25 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 808693F792; Fri, 1 Jul 2022 07:25:23 -0700 (PDT) From: Jean-Philippe Brucker To: will@kernel.org Cc: andre.przywara@arm.com, alexandru.elisei@arm.com, kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org, jean-philippe@linaro.org Subject: [PATCH kvmtool v2 03/12] virtio/pci: Make doorbell offset dynamic Date: Fri, 1 Jul 2022 15:24:25 +0100 Message-Id: <20220701142434.75170-4-jean-philippe.brucker@arm.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com> References: <20220701142434.75170-1-jean-philippe.brucker@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org The doorbell offset depends on the transport - virtio-legacy uses a fixed offset, but modern virtio can have per-vq offsets. Add an offset field to the virtio_pci structure. Signed-off-by: Jean-Philippe Brucker --- include/kvm/virtio-pci.h | 1 + virtio/pci.c | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/kvm/virtio-pci.h b/include/kvm/virtio-pci.h index 959b4b81..d64e5c99 100644 --- a/include/kvm/virtio-pci.h +++ b/include/kvm/virtio-pci.h @@ -24,6 +24,7 @@ struct virtio_pci { void *dev; struct kvm *kvm; + u32 doorbell_offset; u8 status; u8 isr; u32 features; diff --git a/virtio/pci.c b/virtio/pci.c index f0459925..c02534a6 100644 --- a/virtio/pci.c +++ b/virtio/pci.c @@ -81,6 +81,7 @@ static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vde struct virtio_pci *vpci = vdev->virtio; u32 mmio_addr = virtio_pci__mmio_addr(vpci); u16 port_addr = virtio_pci__port_addr(vpci); + off_t offset = vpci->doorbell_offset; int r, flags = 0; int fd; @@ -104,7 +105,7 @@ static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vde flags |= IOEVENTFD_FLAG_USER_POLL; /* ioport */ - ioevent.io_addr = port_addr + VIRTIO_PCI_QUEUE_NOTIFY; + ioevent.io_addr = port_addr + offset; ioevent.io_len = sizeof(u16); ioevent.fd = fd = eventfd(0, 0); r = ioeventfd__add_event(&ioevent, flags | IOEVENTFD_FLAG_PIO); @@ -112,7 +113,7 @@ static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vde return r; /* mmio */ - ioevent.io_addr = mmio_addr + VIRTIO_PCI_QUEUE_NOTIFY; + ioevent.io_addr = mmio_addr + offset; ioevent.io_len = sizeof(u16); ioevent.fd = eventfd(0, 0); r = ioeventfd__add_event(&ioevent, flags); @@ -124,7 +125,7 @@ static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vde return 0; free_ioport_evt: - ioeventfd__del_event(port_addr + VIRTIO_PCI_QUEUE_NOTIFY, vq); + ioeventfd__del_event(port_addr + offset, vq); return r; } @@ -148,12 +149,13 @@ static void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, struct virtio_pci *vpci = vdev->virtio; u32 mmio_addr = virtio_pci__mmio_addr(vpci); u16 port_addr = virtio_pci__port_addr(vpci); + off_t offset = vpci->doorbell_offset; virtio_pci__del_msix_route(vpci, vpci->gsis[vq]); vpci->gsis[vq] = 0; vpci->vq_vector[vq] = VIRTIO_MSI_NO_VECTOR; - ioeventfd__del_event(mmio_addr + VIRTIO_PCI_QUEUE_NOTIFY, vq); - ioeventfd__del_event(port_addr + VIRTIO_PCI_QUEUE_NOTIFY, vq); + ioeventfd__del_event(mmio_addr + offset, vq); + ioeventfd__del_event(port_addr + offset, vq); virtio_exit_vq(kvm, vdev, vpci->dev, vq); } @@ -571,6 +573,8 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev, mmio_addr = pci_get_mmio_block(PCI_IO_SIZE); msix_io_block = pci_get_mmio_block(VIRTIO_MSIX_BAR_SIZE); + vpci->doorbell_offset = VIRTIO_PCI_QUEUE_NOTIFY; + vpci->pci_hdr = (struct pci_device_header) { .vendor_id = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET), .device_id = cpu_to_le16(device_id), From patchwork Fri Jul 1 14:24:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12903407 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 401AFC433EF for ; Fri, 1 Jul 2022 14:30:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232937AbiGAOay (ORCPT ); Fri, 1 Jul 2022 10:30:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40810 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232741AbiGAO3k (ORCPT ); Fri, 1 Jul 2022 10:29:40 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 09A4D3EA98 for ; Fri, 1 Jul 2022 07:25:38 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id B82F415A1; Fri, 1 Jul 2022 07:25:26 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 1F28B3F792; Fri, 1 Jul 2022 07:25:24 -0700 (PDT) From: Jean-Philippe Brucker To: will@kernel.org Cc: andre.przywara@arm.com, alexandru.elisei@arm.com, kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org, jean-philippe@linaro.org Subject: [PATCH kvmtool v2 04/12] virtio/pci: Use the correct eventfd for vhost notification Date: Fri, 1 Jul 2022 15:24:26 +0100 Message-Id: <20220701142434.75170-5-jean-philippe.brucker@arm.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com> References: <20220701142434.75170-1-jean-philippe.brucker@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Legacy virtio drivers write to the I/O port BAR, and the modern virtio device uses the MMIO BAR. Since vhost can only listen on one ioeventfd, select the one that the guest will use. Signed-off-by: Jean-Philippe Brucker --- virtio/pci.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/virtio/pci.c b/virtio/pci.c index c02534a6..320865c1 100644 --- a/virtio/pci.c +++ b/virtio/pci.c @@ -83,7 +83,7 @@ static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vde u16 port_addr = virtio_pci__port_addr(vpci); off_t offset = vpci->doorbell_offset; int r, flags = 0; - int fd; + int pio_fd, mmio_fd; vpci->ioeventfds[vq] = (struct virtio_pci_ioevent_param) { .vdev = vdev, @@ -107,7 +107,7 @@ static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vde /* ioport */ ioevent.io_addr = port_addr + offset; ioevent.io_len = sizeof(u16); - ioevent.fd = fd = eventfd(0, 0); + ioevent.fd = pio_fd = eventfd(0, 0); r = ioeventfd__add_event(&ioevent, flags | IOEVENTFD_FLAG_PIO); if (r) return r; @@ -115,13 +115,14 @@ static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vde /* mmio */ ioevent.io_addr = mmio_addr + offset; ioevent.io_len = sizeof(u16); - ioevent.fd = eventfd(0, 0); + ioevent.fd = mmio_fd = eventfd(0, 0); r = ioeventfd__add_event(&ioevent, flags); if (r) goto free_ioport_evt; if (vdev->ops->notify_vq_eventfd) - vdev->ops->notify_vq_eventfd(kvm, vpci->dev, vq, fd); + vdev->ops->notify_vq_eventfd(kvm, vpci->dev, vq, + vdev->legacy ? pio_fd : mmio_fd); return 0; free_ioport_evt: From patchwork Fri Jul 1 14:24:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12903409 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B7D1FC43334 for ; Fri, 1 Jul 2022 14:31:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233234AbiGAObK (ORCPT ); Fri, 1 Jul 2022 10:31:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49590 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233233AbiGAOak (ORCPT ); Fri, 1 Jul 2022 10:30:40 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 1742D7125C for ; Fri, 1 Jul 2022 07:25:51 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 592DB1BF7; Fri, 1 Jul 2022 07:25:28 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id BB5A13F792; Fri, 1 Jul 2022 07:25:26 -0700 (PDT) From: Jean-Philippe Brucker To: will@kernel.org Cc: andre.przywara@arm.com, alexandru.elisei@arm.com, kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org, jean-philippe@linaro.org Subject: [PATCH kvmtool v2 05/12] virtio/net: Set vhost backend after queue address Date: Fri, 1 Jul 2022 15:24:27 +0100 Message-Id: <20220701142434.75170-6-jean-philippe.brucker@arm.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com> References: <20220701142434.75170-1-jean-philippe.brucker@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org We currently call VHOST_SET_BACKEND from notify_vq_gsi(), which can't work with modern virtio because vhost checks that the virtqueue is accessible when handling VHOST_SET_BACKEND, and the modern driver initializes the MSIs before setting up the virtqueue. Move VHOST_SET_BACKEND to init_vq(). Signed-off-by: Jean-Philippe Brucker --- virtio/net.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/virtio/net.c b/virtio/net.c index f8c40d40..dcf9210d 100644 --- a/virtio/net.c +++ b/virtio/net.c @@ -601,6 +601,7 @@ static bool is_ctrl_vq(struct net_dev *ndev, u32 vq) static int init_vq(struct kvm *kvm, void *dev, u32 vq) { struct vhost_vring_state state = { .index = vq }; + struct vhost_vring_file file = { .index = vq }; struct net_dev_queue *net_queue; struct vhost_vring_addr addr; struct net_dev *ndev = dev; @@ -656,6 +657,11 @@ static int init_vq(struct kvm *kvm, void *dev, u32 vq) if (r < 0) die_perror("VHOST_SET_VRING_ADDR failed"); + file.fd = ndev->tap_fd; + r = ioctl(ndev->vhost_fd, VHOST_NET_SET_BACKEND, &file); + if (r < 0) + die_perror("VHOST_NET_SET_BACKEND failed"); + return 0; } @@ -713,11 +719,6 @@ static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi) r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_CALL, &file); if (r < 0) die_perror("VHOST_SET_VRING_CALL failed"); - file.fd = ndev->tap_fd; - r = ioctl(ndev->vhost_fd, VHOST_NET_SET_BACKEND, &file); - if (r != 0) - die("VHOST_NET_SET_BACKEND failed %d", errno); - } static void notify_vq_eventfd(struct kvm *kvm, void *dev, u32 vq, u32 efd) From patchwork Fri Jul 1 14:24:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12903408 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EE03AC433EF for ; Fri, 1 Jul 2022 14:31:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232636AbiGAObI (ORCPT ); Fri, 1 Jul 2022 10:31:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48264 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233225AbiGAOak (ORCPT ); Fri, 1 Jul 2022 10:30:40 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 743C07125D for ; Fri, 1 Jul 2022 07:25:51 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 019D31C00; Fri, 1 Jul 2022 07:25:30 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 5C5713F792; Fri, 1 Jul 2022 07:25:28 -0700 (PDT) From: Jean-Philippe Brucker To: will@kernel.org Cc: andre.przywara@arm.com, alexandru.elisei@arm.com, kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org, jean-philippe@linaro.org Subject: [PATCH kvmtool v2 06/12] virtio: Prepare for more feature bits Date: Fri, 1 Jul 2022 15:24:28 +0100 Message-Id: <20220701142434.75170-7-jean-philippe.brucker@arm.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com> References: <20220701142434.75170-1-jean-philippe.brucker@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Modern virtio uses more than 32 bits of features. Bump the feature bitfield size to 64 bits. virtio_set_guest_features() changes in behavior because it will now be called multiple times, each time the guest writes to a 32-bit slice of the features. Signed-off-by: Jean-Philippe Brucker --- include/kvm/virtio.h | 6 +++--- virtio/9p.c | 2 +- virtio/balloon.c | 2 +- virtio/blk.c | 2 +- virtio/console.c | 2 +- virtio/core.c | 4 ++-- virtio/net.c | 4 ++-- virtio/rng.c | 2 +- virtio/scsi.c | 2 +- virtio/vsock.c | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h index 8c05bae2..57da2047 100644 --- a/include/kvm/virtio.h +++ b/include/kvm/virtio.h @@ -203,14 +203,14 @@ struct virtio_device { void *virtio; struct virtio_ops *ops; u16 endian; - u32 features; + u64 features; u32 status; }; struct virtio_ops { u8 *(*get_config)(struct kvm *kvm, void *dev); size_t (*get_config_size)(struct kvm *kvm, void *dev); - u32 (*get_host_features)(struct kvm *kvm, void *dev); + u64 (*get_host_features)(struct kvm *kvm, void *dev); unsigned int (*get_vq_count)(struct kvm *kvm, void *dev); int (*init_vq)(struct kvm *kvm, void *dev, u32 vq); void (*exit_vq)(struct kvm *kvm, void *dev, u32 vq); @@ -242,7 +242,7 @@ bool virtio_access_config(struct kvm *kvm, struct virtio_device *vdev, void *dev unsigned long offset, void *data, size_t size, bool is_write); void virtio_set_guest_features(struct kvm *kvm, struct virtio_device *vdev, - void *dev, u32 features); + void *dev, u64 features); void virtio_notify_status(struct kvm *kvm, struct virtio_device *vdev, void *dev, u8 status); diff --git a/virtio/9p.c b/virtio/9p.c index cb3a42a4..19b66df8 100644 --- a/virtio/9p.c +++ b/virtio/9p.c @@ -1382,7 +1382,7 @@ static size_t get_config_size(struct kvm *kvm, void *dev) return p9dev->config_size; } -static u32 get_host_features(struct kvm *kvm, void *dev) +static u64 get_host_features(struct kvm *kvm, void *dev) { return 1 << VIRTIO_9P_MOUNT_TAG; } diff --git a/virtio/balloon.c b/virtio/balloon.c index 6f10219e..3a734322 100644 --- a/virtio/balloon.c +++ b/virtio/balloon.c @@ -200,7 +200,7 @@ static size_t get_config_size(struct kvm *kvm, void *dev) return sizeof(bdev->config); } -static u32 get_host_features(struct kvm *kvm, void *dev) +static u64 get_host_features(struct kvm *kvm, void *dev) { return 1 << VIRTIO_BALLOON_F_STATS_VQ; } diff --git a/virtio/blk.c b/virtio/blk.c index 54035af4..2d06391f 100644 --- a/virtio/blk.c +++ b/virtio/blk.c @@ -169,7 +169,7 @@ static size_t get_config_size(struct kvm *kvm, void *dev) return sizeof(bdev->blk_config); } -static u32 get_host_features(struct kvm *kvm, void *dev) +static u64 get_host_features(struct kvm *kvm, void *dev) { struct blk_dev *bdev = dev; diff --git a/virtio/console.c b/virtio/console.c index c42c8b9f..d29319c8 100644 --- a/virtio/console.c +++ b/virtio/console.c @@ -120,7 +120,7 @@ static size_t get_config_size(struct kvm *kvm, void *dev) return sizeof(cdev->config); } -static u32 get_host_features(struct kvm *kvm, void *dev) +static u64 get_host_features(struct kvm *kvm, void *dev) { return 1 << VIRTIO_F_ANY_LAYOUT; } diff --git a/virtio/core.c b/virtio/core.c index 09abbf40..6688cb44 100644 --- a/virtio/core.c +++ b/virtio/core.c @@ -245,11 +245,11 @@ bool virtio_queue__should_signal(struct virt_queue *vq) } void virtio_set_guest_features(struct kvm *kvm, struct virtio_device *vdev, - void *dev, u32 features) + void *dev, u64 features) { /* TODO: fail negotiation if features & ~host_features */ - vdev->features = features; + vdev->features |= features; } void virtio_notify_status(struct kvm *kvm, struct virtio_device *vdev, diff --git a/virtio/net.c b/virtio/net.c index dcf9210d..c4e302bd 100644 --- a/virtio/net.c +++ b/virtio/net.c @@ -482,9 +482,9 @@ static size_t get_config_size(struct kvm *kvm, void *dev) return sizeof(ndev->config); } -static u32 get_host_features(struct kvm *kvm, void *dev) +static u64 get_host_features(struct kvm *kvm, void *dev) { - u32 features; + u64 features; struct net_dev *ndev = dev; features = 1UL << VIRTIO_NET_F_MAC diff --git a/virtio/rng.c b/virtio/rng.c index 8fda9dd6..f9d607f6 100644 --- a/virtio/rng.c +++ b/virtio/rng.c @@ -52,7 +52,7 @@ static size_t get_config_size(struct kvm *kvm, void *dev) return 0; } -static u32 get_host_features(struct kvm *kvm, void *dev) +static u64 get_host_features(struct kvm *kvm, void *dev) { /* Unused */ return 0; diff --git a/virtio/scsi.c b/virtio/scsi.c index d69183b7..0286b86f 100644 --- a/virtio/scsi.c +++ b/virtio/scsi.c @@ -44,7 +44,7 @@ static size_t get_config_size(struct kvm *kvm, void *dev) return sizeof(sdev->config); } -static u32 get_host_features(struct kvm *kvm, void *dev) +static u64 get_host_features(struct kvm *kvm, void *dev) { return 1UL << VIRTIO_RING_F_EVENT_IDX | 1UL << VIRTIO_RING_F_INDIRECT_DESC; diff --git a/virtio/vsock.c b/virtio/vsock.c index 02cee683..18b45f3b 100644 --- a/virtio/vsock.c +++ b/virtio/vsock.c @@ -49,7 +49,7 @@ static size_t get_config_size(struct kvm *kvm, void *dev) return sizeof(vdev->config); } -static u32 get_host_features(struct kvm *kvm, void *dev) +static u64 get_host_features(struct kvm *kvm, void *dev) { return 1UL << VIRTIO_RING_F_EVENT_IDX | 1UL << VIRTIO_RING_F_INDIRECT_DESC; From patchwork Fri Jul 1 14:24:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12903411 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CD39FC433EF for ; Fri, 1 Jul 2022 14:31:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233299AbiGAObL (ORCPT ); Fri, 1 Jul 2022 10:31:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49656 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231757AbiGAOaw (ORCPT ); Fri, 1 Jul 2022 10:30:52 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 3769F71BC2 for ; Fri, 1 Jul 2022 07:25:55 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id BF09D1C01; Fri, 1 Jul 2022 07:25:31 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 049EA3F792; Fri, 1 Jul 2022 07:25:29 -0700 (PDT) From: Jean-Philippe Brucker To: will@kernel.org Cc: andre.przywara@arm.com, alexandru.elisei@arm.com, kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org, jean-philippe@linaro.org Subject: [PATCH kvmtool v2 07/12] virtio: Move PCI transport to pci-legacy Date: Fri, 1 Jul 2022 15:24:29 +0100 Message-Id: <20220701142434.75170-8-jean-philippe.brucker@arm.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com> References: <20220701142434.75170-1-jean-philippe.brucker@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org To make space for the more recent virtio version, move the legacy bits of virtio-pci to a different file. Signed-off-by: Jean-Philippe Brucker --- Makefile | 1 + include/kvm/virtio-pci.h | 39 +++++++ virtio/pci-legacy.c | 205 ++++++++++++++++++++++++++++++++ virtio/pci.c | 245 ++------------------------------------- 4 files changed, 254 insertions(+), 236 deletions(-) create mode 100644 virtio/pci-legacy.c diff --git a/Makefile b/Makefile index 77cfa9a9..6dc2d95e 100644 --- a/Makefile +++ b/Makefile @@ -74,6 +74,7 @@ OBJS += virtio/rng.o OBJS += virtio/balloon.o OBJS += virtio/pci.o OBJS += virtio/vsock.o +OBJS += virtio/pci-legacy.o OBJS += disk/blk.o OBJS += disk/qcow.o OBJS += disk/raw.o diff --git a/include/kvm/virtio-pci.h b/include/kvm/virtio-pci.h index d64e5c99..8cce5528 100644 --- a/include/kvm/virtio-pci.h +++ b/include/kvm/virtio-pci.h @@ -4,12 +4,15 @@ #include "kvm/devices.h" #include "kvm/pci.h" +#include +#include #include #define VIRTIO_PCI_MAX_VQ 32 #define VIRTIO_PCI_MAX_CONFIG 1 struct kvm; +struct kvm_cpu; struct virtio_pci_ioevent_param { struct virtio_device *vdev; @@ -18,6 +21,13 @@ struct virtio_pci_ioevent_param { #define VIRTIO_PCI_F_SIGNAL_MSI (1 << 0) +#define ALIGN_UP(x, s) ALIGN((x) + (s) - 1, (s)) +#define VIRTIO_NR_MSIX (VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG) +#define VIRTIO_MSIX_TABLE_SIZE (VIRTIO_NR_MSIX * 16) +#define VIRTIO_MSIX_PBA_SIZE (ALIGN_UP(VIRTIO_MSIX_TABLE_SIZE, 64) / 8) +#define VIRTIO_MSIX_BAR_SIZE (1UL << fls_long(VIRTIO_MSIX_TABLE_SIZE + \ + VIRTIO_MSIX_PBA_SIZE)) + struct virtio_pci { struct pci_device_header pci_hdr; struct device_header dev_hdr; @@ -57,4 +67,33 @@ int virtio_pci__reset(struct kvm *kvm, struct virtio_device *vdev); int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev, int device_id, int subsys_id, int class); +static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci) +{ + return vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE); +} + +static inline u16 virtio_pci__port_addr(struct virtio_pci *vpci) +{ + return pci__bar_address(&vpci->pci_hdr, 0); +} + +static inline u32 virtio_pci__mmio_addr(struct virtio_pci *vpci) +{ + return pci__bar_address(&vpci->pci_hdr, 1); +} + +static inline u32 virtio_pci__msix_io_addr(struct virtio_pci *vpci) +{ + return pci__bar_address(&vpci->pci_hdr, 2); +} + +int virtio_pci__add_msix_route(struct virtio_pci *vpci, u32 vec); +int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, + u32 vq); +int virtio_pci_init_vq(struct kvm *kvm, struct virtio_device *vdev, int vq); +void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq); + +void virtio_pci_legacy__io_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, + u32 len, u8 is_write, void *ptr); + #endif diff --git a/virtio/pci-legacy.c b/virtio/pci-legacy.c new file mode 100644 index 00000000..58047967 --- /dev/null +++ b/virtio/pci-legacy.c @@ -0,0 +1,205 @@ +#include "kvm/virtio-pci.h" + +#include "kvm/ioport.h" +#include "kvm/virtio.h" + +static bool virtio_pci__specific_data_in(struct kvm *kvm, struct virtio_device *vdev, + void *data, u32 size, unsigned long offset) +{ + u32 config_offset; + struct virtio_pci *vpci = vdev->virtio; + int type = virtio__get_dev_specific_field(offset - 20, + virtio_pci__msix_enabled(vpci), + &config_offset); + if (type == VIRTIO_PCI_O_MSIX) { + switch (offset) { + case VIRTIO_MSI_CONFIG_VECTOR: + ioport__write16(data, vpci->config_vector); + break; + case VIRTIO_MSI_QUEUE_VECTOR: + ioport__write16(data, vpci->vq_vector[vpci->queue_selector]); + break; + }; + + return true; + } else if (type == VIRTIO_PCI_O_CONFIG) { + return virtio_access_config(kvm, vdev, vpci->dev, config_offset, + data, size, false); + } + + return false; +} + +static bool virtio_pci__data_in(struct kvm_cpu *vcpu, struct virtio_device *vdev, + unsigned long offset, void *data, u32 size) +{ + bool ret = true; + struct virtio_pci *vpci; + struct virt_queue *vq; + struct kvm *kvm; + u32 val; + + kvm = vcpu->kvm; + vpci = vdev->virtio; + + switch (offset) { + case VIRTIO_PCI_HOST_FEATURES: + val = vdev->ops->get_host_features(kvm, vpci->dev); + ioport__write32(data, val); + break; + case VIRTIO_PCI_QUEUE_PFN: + vq = vdev->ops->get_vq(kvm, vpci->dev, vpci->queue_selector); + ioport__write32(data, vq->vring_addr.pfn); + break; + case VIRTIO_PCI_QUEUE_NUM: + val = vdev->ops->get_size_vq(kvm, vpci->dev, vpci->queue_selector); + ioport__write16(data, val); + break; + case VIRTIO_PCI_STATUS: + ioport__write8(data, vpci->status); + break; + case VIRTIO_PCI_ISR: + ioport__write8(data, vpci->isr); + kvm__irq_line(kvm, vpci->legacy_irq_line, VIRTIO_IRQ_LOW); + vpci->isr = VIRTIO_IRQ_LOW; + break; + default: + ret = virtio_pci__specific_data_in(kvm, vdev, data, size, offset); + break; + }; + + return ret; +} + +static bool virtio_pci__specific_data_out(struct kvm *kvm, struct virtio_device *vdev, + void *data, u32 size, unsigned long offset) +{ + struct virtio_pci *vpci = vdev->virtio; + u32 config_offset, vec; + int gsi; + int type = virtio__get_dev_specific_field(offset - 20, virtio_pci__msix_enabled(vpci), + &config_offset); + if (type == VIRTIO_PCI_O_MSIX) { + switch (offset) { + case VIRTIO_MSI_CONFIG_VECTOR: + vec = vpci->config_vector = ioport__read16(data); + + gsi = virtio_pci__add_msix_route(vpci, vec); + if (gsi < 0) + break; + + vpci->config_gsi = gsi; + break; + case VIRTIO_MSI_QUEUE_VECTOR: + vec = ioport__read16(data); + vpci->vq_vector[vpci->queue_selector] = vec; + + gsi = virtio_pci__add_msix_route(vpci, vec); + if (gsi < 0) + break; + + vpci->gsis[vpci->queue_selector] = gsi; + if (vdev->ops->notify_vq_gsi) + vdev->ops->notify_vq_gsi(kvm, vpci->dev, + vpci->queue_selector, + gsi); + break; + }; + + return true; + } else if (type == VIRTIO_PCI_O_CONFIG) { + return virtio_access_config(kvm, vdev, vpci->dev, config_offset, + data, size, true); + } + + return false; +} + +static bool virtio_pci__data_out(struct kvm_cpu *vcpu, struct virtio_device *vdev, + unsigned long offset, void *data, u32 size) +{ + bool ret = true; + struct virtio_pci *vpci; + struct virt_queue *vq; + struct kvm *kvm; + u32 val; + unsigned int vq_count; + + kvm = vcpu->kvm; + vpci = vdev->virtio; + vq_count = vdev->ops->get_vq_count(kvm, vpci->dev); + + switch (offset) { + case VIRTIO_PCI_GUEST_FEATURES: + val = ioport__read32(data); + virtio_set_guest_features(kvm, vdev, vpci->dev, val); + break; + case VIRTIO_PCI_QUEUE_PFN: + val = ioport__read32(data); + if (val) { + vq = vdev->ops->get_vq(kvm, vpci->dev, + vpci->queue_selector); + vq->vring_addr = (struct vring_addr) { + .legacy = true, + .pfn = val, + .align = VIRTIO_PCI_VRING_ALIGN, + .pgsize = 1 << VIRTIO_PCI_QUEUE_ADDR_SHIFT, + }; + virtio_pci_init_vq(kvm, vdev, vpci->queue_selector); + } else { + virtio_pci_exit_vq(kvm, vdev, vpci->queue_selector); + } + break; + case VIRTIO_PCI_QUEUE_SEL: + val = ioport__read16(data); + if (val >= vq_count) { + WARN_ONCE(1, "QUEUE_SEL value (%u) is larger than VQ count (%u)\n", + val, vq_count); + return false; + } + vpci->queue_selector = val; + break; + case VIRTIO_PCI_QUEUE_NOTIFY: + val = ioport__read16(data); + if (val >= vq_count) { + WARN_ONCE(1, "QUEUE_SEL value (%u) is larger than VQ count (%u)\n", + val, vq_count); + return false; + } + vdev->ops->notify_vq(kvm, vpci->dev, val); + break; + case VIRTIO_PCI_STATUS: + vpci->status = ioport__read8(data); + if (!vpci->status) /* Sample endianness on reset */ + vdev->endian = kvm_cpu__get_endianness(vcpu); + virtio_notify_status(kvm, vdev, vpci->dev, vpci->status); + break; + default: + ret = virtio_pci__specific_data_out(kvm, vdev, data, size, offset); + break; + }; + + return ret; +} + +void virtio_pci_legacy__io_mmio_callback(struct kvm_cpu *vcpu, u64 addr, + u8 *data, u32 len, u8 is_write, + void *ptr) +{ + struct virtio_device *vdev = ptr; + struct virtio_pci *vpci = vdev->virtio; + u32 ioport_addr = virtio_pci__port_addr(vpci); + u32 base_addr; + + if (addr >= ioport_addr && + addr < ioport_addr + pci__bar_size(&vpci->pci_hdr, 0)) + base_addr = ioport_addr; + else + base_addr = virtio_pci__mmio_addr(vpci); + + if (!is_write) + virtio_pci__data_in(vcpu, vdev, addr - base_addr, data, len); + else + virtio_pci__data_out(vcpu, vdev, addr - base_addr, data, len); +} + diff --git a/virtio/pci.c b/virtio/pci.c index 320865c1..35362423 100644 --- a/virtio/pci.c +++ b/virtio/pci.c @@ -11,33 +11,10 @@ #include #include -#include #include #include -#define ALIGN_UP(x, s) ALIGN((x) + (s) - 1, (s)) -#define VIRTIO_NR_MSIX (VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG) -#define VIRTIO_MSIX_TABLE_SIZE (VIRTIO_NR_MSIX * 16) -#define VIRTIO_MSIX_PBA_SIZE (ALIGN_UP(VIRTIO_MSIX_TABLE_SIZE, 64) / 8) -#define VIRTIO_MSIX_BAR_SIZE (1UL << fls_long(VIRTIO_MSIX_TABLE_SIZE + \ - VIRTIO_MSIX_PBA_SIZE)) - -static u16 virtio_pci__port_addr(struct virtio_pci *vpci) -{ - return pci__bar_address(&vpci->pci_hdr, 0); -} - -static u32 virtio_pci__mmio_addr(struct virtio_pci *vpci) -{ - return pci__bar_address(&vpci->pci_hdr, 1); -} - -static u32 virtio_pci__msix_io_addr(struct virtio_pci *vpci) -{ - return pci__bar_address(&vpci->pci_hdr, 2); -} - -static int virtio_pci__add_msix_route(struct virtio_pci *vpci, u32 vec) +int virtio_pci__add_msix_route(struct virtio_pci *vpci, u32 vec) { int gsi; struct msi_msg *msg; @@ -75,7 +52,8 @@ static void virtio_pci__ioevent_callback(struct kvm *kvm, void *param) ioeventfd->vdev->ops->notify_vq(kvm, vpci->dev, ioeventfd->vq); } -static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, u32 vq) +int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, + u32 vq) { struct ioevent ioevent; struct virtio_pci *vpci = vdev->virtio; @@ -130,8 +108,7 @@ free_ioport_evt: return r; } -static int virtio_pci_init_vq(struct kvm *kvm, struct virtio_device *vdev, - int vq) +int virtio_pci_init_vq(struct kvm *kvm, struct virtio_device *vdev, int vq) { int ret; struct virtio_pci *vpci = vdev->virtio; @@ -144,8 +121,7 @@ static int virtio_pci_init_vq(struct kvm *kvm, struct virtio_device *vdev, return vdev->ops->init_vq(kvm, vpci->dev, vq); } -static void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, - int vq) +void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq) { struct virtio_pci *vpci = vdev->virtio; u32 mmio_addr = virtio_pci__mmio_addr(vpci); @@ -160,79 +136,6 @@ static void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, virtio_exit_vq(kvm, vdev, vpci->dev, vq); } -static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci) -{ - return vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE); -} - -static bool virtio_pci__specific_data_in(struct kvm *kvm, struct virtio_device *vdev, - void *data, u32 size, unsigned long offset) -{ - u32 config_offset; - struct virtio_pci *vpci = vdev->virtio; - int type = virtio__get_dev_specific_field(offset - 20, - virtio_pci__msix_enabled(vpci), - &config_offset); - if (type == VIRTIO_PCI_O_MSIX) { - switch (offset) { - case VIRTIO_MSI_CONFIG_VECTOR: - ioport__write16(data, vpci->config_vector); - break; - case VIRTIO_MSI_QUEUE_VECTOR: - ioport__write16(data, vpci->vq_vector[vpci->queue_selector]); - break; - }; - - return true; - } else if (type == VIRTIO_PCI_O_CONFIG) { - return virtio_access_config(kvm, vdev, vpci->dev, config_offset, - data, size, false); - } - - return false; -} - -static bool virtio_pci__data_in(struct kvm_cpu *vcpu, struct virtio_device *vdev, - unsigned long offset, void *data, u32 size) -{ - bool ret = true; - struct virtio_pci *vpci; - struct virt_queue *vq; - struct kvm *kvm; - u32 val; - - kvm = vcpu->kvm; - vpci = vdev->virtio; - - switch (offset) { - case VIRTIO_PCI_HOST_FEATURES: - val = vdev->ops->get_host_features(kvm, vpci->dev); - ioport__write32(data, val); - break; - case VIRTIO_PCI_QUEUE_PFN: - vq = vdev->ops->get_vq(kvm, vpci->dev, vpci->queue_selector); - ioport__write32(data, vq->vring_addr.pfn); - break; - case VIRTIO_PCI_QUEUE_NUM: - val = vdev->ops->get_size_vq(kvm, vpci->dev, vpci->queue_selector); - ioport__write16(data, val); - break; - case VIRTIO_PCI_STATUS: - ioport__write8(data, vpci->status); - break; - case VIRTIO_PCI_ISR: - ioport__write8(data, vpci->isr); - kvm__irq_line(kvm, vpci->legacy_irq_line, VIRTIO_IRQ_LOW); - vpci->isr = VIRTIO_IRQ_LOW; - break; - default: - ret = virtio_pci__specific_data_in(kvm, vdev, data, size, offset); - break; - }; - - return ret; -} - static void update_msix_map(struct virtio_pci *vpci, struct msix_table *msix_entry, u32 vecnum) { @@ -257,117 +160,6 @@ static void update_msix_map(struct virtio_pci *vpci, irq__update_msix_route(vpci->kvm, gsi, &msix_entry->msg); } -static bool virtio_pci__specific_data_out(struct kvm *kvm, struct virtio_device *vdev, - void *data, u32 size, unsigned long offset) -{ - struct virtio_pci *vpci = vdev->virtio; - u32 config_offset, vec; - int gsi; - int type = virtio__get_dev_specific_field(offset - 20, virtio_pci__msix_enabled(vpci), - &config_offset); - if (type == VIRTIO_PCI_O_MSIX) { - switch (offset) { - case VIRTIO_MSI_CONFIG_VECTOR: - vec = vpci->config_vector = ioport__read16(data); - - gsi = virtio_pci__add_msix_route(vpci, vec); - if (gsi < 0) - break; - - vpci->config_gsi = gsi; - break; - case VIRTIO_MSI_QUEUE_VECTOR: - vec = ioport__read16(data); - vpci->vq_vector[vpci->queue_selector] = vec; - - gsi = virtio_pci__add_msix_route(vpci, vec); - if (gsi < 0) - break; - - vpci->gsis[vpci->queue_selector] = gsi; - if (vdev->ops->notify_vq_gsi) - vdev->ops->notify_vq_gsi(kvm, vpci->dev, - vpci->queue_selector, - gsi); - break; - }; - - return true; - } else if (type == VIRTIO_PCI_O_CONFIG) { - return virtio_access_config(kvm, vdev, vpci->dev, config_offset, - data, size, true); - } - - return false; -} - -static bool virtio_pci__data_out(struct kvm_cpu *vcpu, struct virtio_device *vdev, - unsigned long offset, void *data, u32 size) -{ - bool ret = true; - struct virtio_pci *vpci; - struct virt_queue *vq; - struct kvm *kvm; - u32 val; - unsigned int vq_count; - - kvm = vcpu->kvm; - vpci = vdev->virtio; - vq_count = vdev->ops->get_vq_count(kvm, vpci->dev); - - switch (offset) { - case VIRTIO_PCI_GUEST_FEATURES: - val = ioport__read32(data); - virtio_set_guest_features(kvm, vdev, vpci->dev, val); - break; - case VIRTIO_PCI_QUEUE_PFN: - val = ioport__read32(data); - if (val) { - vq = vdev->ops->get_vq(kvm, vpci->dev, - vpci->queue_selector); - vq->vring_addr = (struct vring_addr) { - .legacy = true, - .pfn = val, - .align = VIRTIO_PCI_VRING_ALIGN, - .pgsize = 1 << VIRTIO_PCI_QUEUE_ADDR_SHIFT, - }; - virtio_pci_init_vq(kvm, vdev, vpci->queue_selector); - } else { - virtio_pci_exit_vq(kvm, vdev, vpci->queue_selector); - } - break; - case VIRTIO_PCI_QUEUE_SEL: - val = ioport__read16(data); - if (val >= vq_count) { - WARN_ONCE(1, "QUEUE_SEL value (%u) is larger than VQ count (%u)\n", - val, vq_count); - return false; - } - vpci->queue_selector = val; - break; - case VIRTIO_PCI_QUEUE_NOTIFY: - val = ioport__read16(data); - if (val >= vq_count) { - WARN_ONCE(1, "QUEUE_SEL value (%u) is larger than VQ count (%u)\n", - val, vq_count); - return false; - } - vdev->ops->notify_vq(kvm, vpci->dev, val); - break; - case VIRTIO_PCI_STATUS: - vpci->status = ioport__read8(data); - if (!vpci->status) /* Sample endianness on reset */ - vdev->endian = kvm_cpu__get_endianness(vcpu); - virtio_notify_status(kvm, vdev, vpci->dev, vpci->status); - break; - default: - ret = virtio_pci__specific_data_out(kvm, vdev, data, size, offset); - break; - }; - - return ret; -} - static void virtio_pci__msix_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr) @@ -478,27 +270,6 @@ int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev) return 0; } -static void virtio_pci__io_mmio_callback(struct kvm_cpu *vcpu, - u64 addr, u8 *data, u32 len, - u8 is_write, void *ptr) -{ - struct virtio_device *vdev = ptr; - struct virtio_pci *vpci = vdev->virtio; - u32 ioport_addr = virtio_pci__port_addr(vpci); - u32 base_addr; - - if (addr >= ioport_addr && - addr < ioport_addr + pci__bar_size(&vpci->pci_hdr, 0)) - base_addr = ioport_addr; - else - base_addr = virtio_pci__mmio_addr(vpci); - - if (!is_write) - virtio_pci__data_in(vcpu, vdev, addr - base_addr, data, len); - else - virtio_pci__data_out(vcpu, vdev, addr - base_addr, data, len); -} - static int virtio_pci__bar_activate(struct kvm *kvm, struct pci_device_header *pci_hdr, int bar_num, void *data) @@ -515,11 +286,13 @@ static int virtio_pci__bar_activate(struct kvm *kvm, switch (bar_num) { case 0: r = kvm__register_pio(kvm, bar_addr, bar_size, - virtio_pci__io_mmio_callback, vdev); + virtio_pci_legacy__io_mmio_callback, + vdev); break; case 1: r = kvm__register_mmio(kvm, bar_addr, bar_size, false, - virtio_pci__io_mmio_callback, vdev); + virtio_pci_legacy__io_mmio_callback, + vdev); break; case 2: r = kvm__register_mmio(kvm, bar_addr, bar_size, false, From patchwork Fri Jul 1 14:24:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12903410 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 75041CCA479 for ; Fri, 1 Jul 2022 14:31:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233236AbiGAObK (ORCPT ); Fri, 1 Jul 2022 10:31:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49660 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233259AbiGAOaw (ORCPT ); Fri, 1 Jul 2022 10:30:52 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 14D8871BC1 for ; Fri, 1 Jul 2022 07:25:55 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 8BEC81C0A; Fri, 1 Jul 2022 07:25:33 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id C2A763F792; Fri, 1 Jul 2022 07:25:31 -0700 (PDT) From: Jean-Philippe Brucker To: will@kernel.org Cc: andre.przywara@arm.com, alexandru.elisei@arm.com, kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org, jean-philippe@linaro.org Subject: [PATCH kvmtool v2 08/12] virtio: Add support for modern virtio-pci Date: Fri, 1 Jul 2022 15:24:30 +0100 Message-Id: <20220701142434.75170-9-jean-philippe.brucker@arm.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com> References: <20220701142434.75170-1-jean-philippe.brucker@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add support for modern virtio-pci implementation (based on the 1.0 virtio spec). We add a new transport, alongside MMIO and PCI-legacy. This is now the default when selecting PCI, but users can still select the legacy transport for all virtio devices by passing "--virtio-legacy" on the command-line. The main change in modern PCI is the way we address virtqueues, using 64-bit values instead of PFNs. To keep the queue configuration atomic the device also gets a "queue enable" register. Configuration is also made extensible by more feature bits and PCI capabilities. Scalability is improved as well, as devices can have notification registers for each virtqueue on separate pages. However this implementation keeps a single notification register. Signed-off-by: Sasha Levin Signed-off-by: Jean-Philippe Brucker --- Makefile | 1 + arm/include/arm-common/kvm-arch.h | 6 +- include/kvm/kvm-config.h | 1 + include/kvm/kvm.h | 6 + include/kvm/pci.h | 11 + include/kvm/virtio-pci-dev.h | 4 + include/kvm/virtio-pci.h | 6 + include/kvm/virtio.h | 1 + mips/include/kvm/kvm-arch.h | 2 - powerpc/include/kvm/kvm-arch.h | 2 - x86/include/kvm/kvm-arch.h | 2 - builtin-run.c | 2 + virtio/core.c | 6 +- virtio/pci-modern.c | 390 ++++++++++++++++++++++++++++++ virtio/pci.c | 24 +- 15 files changed, 445 insertions(+), 19 deletions(-) create mode 100644 virtio/pci-modern.c diff --git a/Makefile b/Makefile index 6dc2d95e..56cfaaf4 100644 --- a/Makefile +++ b/Makefile @@ -75,6 +75,7 @@ OBJS += virtio/balloon.o OBJS += virtio/pci.o OBJS += virtio/vsock.o OBJS += virtio/pci-legacy.o +OBJS += virtio/pci-modern.o OBJS += disk/blk.o OBJS += disk/qcow.o OBJS += disk/raw.o diff --git a/arm/include/arm-common/kvm-arch.h b/arm/include/arm-common/kvm-arch.h index fc55360d..0a960f4f 100644 --- a/arm/include/arm-common/kvm-arch.h +++ b/arm/include/arm-common/kvm-arch.h @@ -81,8 +81,10 @@ #define KVM_VM_TYPE 0 -#define VIRTIO_DEFAULT_TRANS(kvm) \ - ((kvm)->cfg.arch.virtio_trans_pci ? VIRTIO_PCI : VIRTIO_MMIO) +#define VIRTIO_DEFAULT_TRANS(kvm) \ + ((kvm)->cfg.arch.virtio_trans_pci ? \ + ((kvm)->cfg.virtio_legacy ? VIRTIO_PCI_LEGACY : VIRTIO_PCI) : \ + VIRTIO_MMIO) #define VIRTIO_RING_ENDIAN (VIRTIO_ENDIAN_LE | VIRTIO_ENDIAN_BE) diff --git a/include/kvm/kvm-config.h b/include/kvm/kvm-config.h index 6a5720c4..0e72d84c 100644 --- a/include/kvm/kvm-config.h +++ b/include/kvm/kvm-config.h @@ -62,6 +62,7 @@ struct kvm_config { bool no_dhcp; bool ioport_debug; bool mmio_debug; + bool virtio_legacy; }; #endif diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h index ad732e56..36a688d6 100644 --- a/include/kvm/kvm.h +++ b/include/kvm/kvm.h @@ -45,6 +45,12 @@ struct kvm_cpu; typedef void (*mmio_handler_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr); +/* Archs can override this in kvm-arch.h */ +#ifndef VIRTIO_DEFAULT_TRANS +#define VIRTIO_DEFAULT_TRANS(kvm) \ + ((kvm)->cfg.virtio_legacy ? VIRTIO_PCI_LEGACY : VIRTIO_PCI) +#endif + enum { KVM_VMSTATE_RUNNING, KVM_VMSTATE_PAUSED, diff --git a/include/kvm/pci.h b/include/kvm/pci.h index d6eb3986..25113f60 100644 --- a/include/kvm/pci.h +++ b/include/kvm/pci.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -142,6 +143,14 @@ struct msi_cap_32 { u32 pend_bits; }; +struct virtio_caps { + struct virtio_pci_cap common; + struct virtio_pci_notify_cap notify; + struct virtio_pci_cap isr; + struct virtio_pci_cap device; + struct virtio_pci_cfg_cap pci; +}; + struct pci_cap_hdr { u8 type; u8 next; @@ -212,6 +221,7 @@ struct pci_device_header { struct msix_cap msix; /* Used only by architectures which support PCIE */ struct pci_exp_cap pci_exp; + struct virtio_caps virtio; } __attribute__((packed)); /* Pad to PCI config space size */ u8 __pad[PCI_DEV_CFG_SIZE]; @@ -232,6 +242,7 @@ struct pci_device_header { }; #define PCI_CAP(pci_hdr, pos) ((void *)(pci_hdr) + (pos)) +#define PCI_CAP_OFF(pci_hdr, cap) ((void *)&(pci_hdr)->cap - (void *)(pci_hdr)) #define pci_for_each_cap(pos, cap, hdr) \ for ((pos) = (hdr)->capabilities & ~3; \ diff --git a/include/kvm/virtio-pci-dev.h b/include/kvm/virtio-pci-dev.h index 7bf35cdb..9d59e677 100644 --- a/include/kvm/virtio-pci-dev.h +++ b/include/kvm/virtio-pci-dev.h @@ -19,6 +19,10 @@ #define PCI_DEVICE_ID_VESA 0x2000 #define PCI_DEVICE_ID_PCI_SHMEM 0x0001 +/* Modern virtio device IDs start at 1040 */ +#define PCI_DEVICE_ID_VIRTIO_BASE 0x1040 +#define PCI_SUBSYS_ID_VIRTIO_BASE 0x0040 + #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 #define PCI_VENDOR_ID_PCI_SHMEM 0x0001 #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 diff --git a/include/kvm/virtio-pci.h b/include/kvm/virtio-pci.h index 8cce5528..47075334 100644 --- a/include/kvm/virtio-pci.h +++ b/include/kvm/virtio-pci.h @@ -3,6 +3,7 @@ #include "kvm/devices.h" #include "kvm/pci.h" +#include "kvm/virtio.h" #include #include @@ -37,6 +38,8 @@ struct virtio_pci { u32 doorbell_offset; u8 status; u8 isr; + u32 device_features_sel; + u32 driver_features_sel; u32 features; /* @@ -66,6 +69,7 @@ int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev); int virtio_pci__reset(struct kvm *kvm, struct virtio_device *vdev); int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev, int device_id, int subsys_id, int class); +int virtio_pci_modern_init(struct virtio_device *vdev); static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci) { @@ -95,5 +99,7 @@ void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq); void virtio_pci_legacy__io_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr); +void virtio_pci_modern__io_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, + u32 len, u8 is_write, void *ptr); #endif diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h index 57da2047..869064ba 100644 --- a/include/kvm/virtio.h +++ b/include/kvm/virtio.h @@ -194,6 +194,7 @@ int virtio__get_dev_specific_field(int offset, bool msix, u32 *config_off); enum virtio_trans { VIRTIO_PCI, + VIRTIO_PCI_LEGACY, VIRTIO_MMIO, }; diff --git a/mips/include/kvm/kvm-arch.h b/mips/include/kvm/kvm-arch.h index e2f048a0..f5b9044f 100644 --- a/mips/include/kvm/kvm-arch.h +++ b/mips/include/kvm/kvm-arch.h @@ -35,8 +35,6 @@ #define KVM_IOEVENTFD_HAS_PIO 0 -#define VIRTIO_DEFAULT_TRANS(kvm) VIRTIO_PCI - #define MAX_PAGE_SIZE SZ_64K #include diff --git a/powerpc/include/kvm/kvm-arch.h b/powerpc/include/kvm/kvm-arch.h index 8eeca507..ff42c132 100644 --- a/powerpc/include/kvm/kvm-arch.h +++ b/powerpc/include/kvm/kvm-arch.h @@ -51,8 +51,6 @@ #define MAX_PAGE_SIZE SZ_256K -#define VIRTIO_DEFAULT_TRANS(kvm) VIRTIO_PCI - struct spapr_phb; struct kvm_arch { diff --git a/x86/include/kvm/kvm-arch.h b/x86/include/kvm/kvm-arch.h index d8a7312d..73a957bb 100644 --- a/x86/include/kvm/kvm-arch.h +++ b/x86/include/kvm/kvm-arch.h @@ -33,8 +33,6 @@ #define MAX_PAGE_SIZE SZ_4K -#define VIRTIO_DEFAULT_TRANS(kvm) VIRTIO_PCI - struct kvm_arch { u16 boot_selector; u16 boot_ip; diff --git a/builtin-run.c b/builtin-run.c index 9a1a0c1f..5b9d8f0e 100644 --- a/builtin-run.c +++ b/builtin-run.c @@ -128,6 +128,8 @@ void kvm_run_set_wrapper_sandbox(void) " rootfs"), \ OPT_STRING('\0', "hugetlbfs", &(cfg)->hugetlbfs_path, "path", \ "Hugetlbfs path"), \ + OPT_BOOLEAN('\0', "virtio-legacy", &(cfg)->virtio_legacy, \ + "Use legacy virtio transport"), \ \ OPT_GROUP("Kernel options:"), \ OPT_STRING('k', "kernel", &(cfg)->kernel_filename, "kernel", \ diff --git a/virtio/core.c b/virtio/core.c index 6688cb44..5fc2e789 100644 --- a/virtio/core.c +++ b/virtio/core.c @@ -14,7 +14,7 @@ const char* virtio_trans_name(enum virtio_trans trans) { - if (trans == VIRTIO_PCI) + if (trans == VIRTIO_PCI || trans == VIRTIO_PCI_LEGACY) return "pci"; else if (trans == VIRTIO_MMIO) return "mmio"; @@ -329,8 +329,10 @@ int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev, int r; switch (trans) { - case VIRTIO_PCI: + case VIRTIO_PCI_LEGACY: vdev->legacy = true; + /* fall through */ + case VIRTIO_PCI: virtio = calloc(sizeof(struct virtio_pci), 1); if (!virtio) return -ENOMEM; diff --git a/virtio/pci-modern.c b/virtio/pci-modern.c new file mode 100644 index 00000000..753e95bd --- /dev/null +++ b/virtio/pci-modern.c @@ -0,0 +1,390 @@ +#include "kvm/virtio-pci.h" + +#include "kvm/ioport.h" +#include "kvm/virtio.h" +#include "kvm/virtio-pci-dev.h" + +#include + +#define VPCI_CFG_COMMON_SIZE sizeof(struct virtio_pci_common_cfg) +#define VPCI_CFG_COMMON_START 0 +#define VPCI_CFG_COMMON_END (VPCI_CFG_COMMON_SIZE - 1) +/* + * Use a naturally aligned 4-byte doorbell, in case we ever want to + * implement VIRTIO_F_NOTIFICATION_DATA + */ +#define VPCI_CFG_NOTIFY_SIZE 4 +#define VPCI_CFG_NOTIFY_START (VPCI_CFG_COMMON_END + 1) +#define VPCI_CFG_NOTIFY_END (VPCI_CFG_COMMON_END + VPCI_CFG_NOTIFY_SIZE) +#define VPCI_CFG_ISR_SIZE 4 +#define VPCI_CFG_ISR_START (VPCI_CFG_NOTIFY_END + 1) +#define VPCI_CFG_ISR_END (VPCI_CFG_NOTIFY_END + VPCI_CFG_ISR_SIZE) +/* + * We're at 64 bytes. Use the remaining 192 bytes in PCI_IO_SIZE for the + * device-specific config space. It's sufficient for the devices we + * currently implement (virtio_blk_config is 60 bytes) and, I think, all + * existing virtio 1.2 devices. + */ +#define VPCI_CFG_DEV_START (VPCI_CFG_ISR_END + 1) +#define VPCI_CFG_DEV_END ((PCI_IO_SIZE) - 1) +#define VPCI_CFG_DEV_SIZE (VPCI_CFG_DEV_END - VPCI_CFG_DEV_START + 1) + +#define vpci_selected_vq(vpci) \ + vdev->ops->get_vq((vpci)->kvm, (vpci)->dev, (vpci)->queue_selector) + +typedef bool (*access_handler_t)(struct virtio_device *, unsigned long, void *, int); + +static bool virtio_pci__common_write(struct virtio_device *vdev, + unsigned long offset, void *data, int size) +{ + u64 features; + u32 val, gsi, vec; + struct virtio_pci *vpci = vdev->virtio; + + switch (offset - VPCI_CFG_COMMON_START) { + case VIRTIO_PCI_COMMON_DFSELECT: + vpci->device_features_sel = ioport__read32(data); + break; + case VIRTIO_PCI_COMMON_GFSELECT: + vpci->driver_features_sel = ioport__read32(data); + break; + case VIRTIO_PCI_COMMON_GF: + val = ioport__read32(data); + if (vpci->driver_features_sel > 1) + break; + + features = (u64)val << (32 * vpci->driver_features_sel); + virtio_set_guest_features(vpci->kvm, vdev, vpci->dev, features); + break; + case VIRTIO_PCI_COMMON_MSIX: + vec = vpci->config_vector = ioport__read16(data); + gsi = virtio_pci__add_msix_route(vpci, vec); + if (gsi < 0) + break; + + vpci->config_gsi = gsi; + break; + case VIRTIO_PCI_COMMON_STATUS: + vpci->status = ioport__read8(data); + virtio_notify_status(vpci->kvm, vdev, vpci->dev, vpci->status); + break; + case VIRTIO_PCI_COMMON_Q_SELECT: + val = ioport__read16(data); + if (val >= (u32)vdev->ops->get_vq_count(vpci->kvm, vpci->dev)) + pr_warning("invalid vq number %u", val); + else + vpci->queue_selector = val; + break; + case VIRTIO_PCI_COMMON_Q_SIZE: + vdev->ops->set_size_vq(vpci->kvm, vpci->dev, + vpci->queue_selector, + ioport__read16(data)); + break; + case VIRTIO_PCI_COMMON_Q_MSIX: + vec = vpci->vq_vector[vpci->queue_selector] = ioport__read16(data); + + gsi = virtio_pci__add_msix_route(vpci, vec); + if (gsi < 0) + break; + + vpci->gsis[vpci->queue_selector] = gsi; + if (vdev->ops->notify_vq_gsi) + vdev->ops->notify_vq_gsi(vpci->kvm, vpci->dev, + vpci->queue_selector, gsi); + break; + case VIRTIO_PCI_COMMON_Q_ENABLE: + val = ioport__read16(data); + if (val) + virtio_pci_init_vq(vpci->kvm, vdev, vpci->queue_selector); + else + virtio_pci_exit_vq(vpci->kvm, vdev, vpci->queue_selector); + break; + case VIRTIO_PCI_COMMON_Q_DESCLO: + vpci_selected_vq(vpci)->vring_addr.desc_lo = ioport__read32(data); + break; + case VIRTIO_PCI_COMMON_Q_DESCHI: + vpci_selected_vq(vpci)->vring_addr.desc_hi = ioport__read32(data); + break; + case VIRTIO_PCI_COMMON_Q_AVAILLO: + vpci_selected_vq(vpci)->vring_addr.avail_lo = ioport__read32(data); + break; + case VIRTIO_PCI_COMMON_Q_AVAILHI: + vpci_selected_vq(vpci)->vring_addr.avail_hi = ioport__read32(data); + break; + case VIRTIO_PCI_COMMON_Q_USEDLO: + vpci_selected_vq(vpci)->vring_addr.used_lo = ioport__read32(data); + break; + case VIRTIO_PCI_COMMON_Q_USEDHI: + vpci_selected_vq(vpci)->vring_addr.used_hi = ioport__read32(data); + break; + } + + return true; +} + +static bool virtio_pci__notify_write(struct virtio_device *vdev, + unsigned long offset, void *data, int size) +{ + u16 vq = ioport__read16(data); + struct virtio_pci *vpci = vdev->virtio; + + vdev->ops->notify_vq(vpci->kvm, vpci->dev, vq); + + return true; +} + +static bool virtio_pci__config_write(struct virtio_device *vdev, + unsigned long offset, void *data, int size) +{ + struct virtio_pci *vpci = vdev->virtio; + + return virtio_access_config(vpci->kvm, vdev, vpci->dev, + offset - VPCI_CFG_DEV_START, data, size, + true); +} + +static bool virtio_pci__common_read(struct virtio_device *vdev, + unsigned long offset, void *data, int size) +{ + u32 val; + struct virtio_pci *vpci = vdev->virtio; + u64 features = 1ULL << VIRTIO_F_VERSION_1; + + switch (offset - VPCI_CFG_COMMON_START) { + case VIRTIO_PCI_COMMON_DFSELECT: + val = vpci->device_features_sel; + ioport__write32(data, val); + break; + case VIRTIO_PCI_COMMON_DF: + if (vpci->device_features_sel > 1) + break; + features |= vdev->ops->get_host_features(vpci->kvm, vpci->dev); + val = features >> (32 * vpci->device_features_sel); + ioport__write32(data, val); + break; + case VIRTIO_PCI_COMMON_GFSELECT: + val = vpci->driver_features_sel; + ioport__write32(data, val); + break; + case VIRTIO_PCI_COMMON_MSIX: + val = vpci->config_vector; + ioport__write32(data, val); + break; + case VIRTIO_PCI_COMMON_NUMQ: + val = vdev->ops->get_vq_count(vpci->kvm, vpci->dev); + ioport__write32(data, val); + break; + case VIRTIO_PCI_COMMON_STATUS: + ioport__write8(data, vpci->status); + break; + case VIRTIO_PCI_COMMON_CFGGENERATION: + /* + * The config generation changes when the device updates a + * config field larger than 32 bits, that the driver may read + * using multiple accesses. Since kvmtool doesn't use any + * mutable config field larger than 32 bits, the generation is + * constant. + */ + ioport__write8(data, 0); + break; + case VIRTIO_PCI_COMMON_Q_SELECT: + ioport__write16(data, vpci->queue_selector); + break; + case VIRTIO_PCI_COMMON_Q_SIZE: + val = vdev->ops->get_size_vq(vpci->kvm, vpci->dev, + vpci->queue_selector); + ioport__write16(data, val); + break; + case VIRTIO_PCI_COMMON_Q_MSIX: + val = vpci->vq_vector[vpci->queue_selector]; + ioport__write16(data, val); + break; + case VIRTIO_PCI_COMMON_Q_ENABLE: + val = vpci_selected_vq(vpci)->enabled; + ioport__write16(data, val); + break; + case VIRTIO_PCI_COMMON_Q_NOFF: + val = vpci->queue_selector; + ioport__write16(data, val); + break; + case VIRTIO_PCI_COMMON_Q_DESCLO: + val = vpci_selected_vq(vpci)->vring_addr.desc_lo; + ioport__write32(data, val); + break; + case VIRTIO_PCI_COMMON_Q_DESCHI: + val = vpci_selected_vq(vpci)->vring_addr.desc_hi; + ioport__write32(data, val); + break; + case VIRTIO_PCI_COMMON_Q_AVAILLO: + val = vpci_selected_vq(vpci)->vring_addr.avail_lo; + ioport__write32(data, val); + break; + case VIRTIO_PCI_COMMON_Q_AVAILHI: + val = vpci_selected_vq(vpci)->vring_addr.avail_hi; + ioport__write32(data, val); + break; + case VIRTIO_PCI_COMMON_Q_USEDLO: + val = vpci_selected_vq(vpci)->vring_addr.used_lo; + ioport__write32(data, val); + break; + case VIRTIO_PCI_COMMON_Q_USEDHI: + val = vpci_selected_vq(vpci)->vring_addr.used_hi; + ioport__write32(data, val); + break; + }; + + return true; +} + +static bool virtio_pci__isr_read(struct virtio_device *vdev, + unsigned long offset, void *data, int size) +{ + struct virtio_pci *vpci = vdev->virtio; + + if (WARN_ON(offset - VPCI_CFG_ISR_START != 0)) + return false; + + ioport__write8(data, vpci->isr); + /* + * Interrupts are edge triggered (yes, going against the PCI and virtio + * specs), so no need to deassert the IRQ line. + */ + vpci->isr = 0; + + return 0; +} + +static bool virtio_pci__config_read(struct virtio_device *vdev, + unsigned long offset, void *data, int size) +{ + struct virtio_pci *vpci = vdev->virtio; + + return virtio_access_config(vpci->kvm, vdev, vpci->dev, + offset - VPCI_CFG_DEV_START, data, size, + false); +} + +static bool virtio_pci_access(struct kvm_cpu *vcpu, struct virtio_device *vdev, + unsigned long offset, void *data, int size, + bool write) +{ + access_handler_t handler = NULL; + + switch (offset) { + case VPCI_CFG_COMMON_START...VPCI_CFG_COMMON_END: + if (write) + handler = virtio_pci__common_write; + else + handler = virtio_pci__common_read; + break; + case VPCI_CFG_NOTIFY_START...VPCI_CFG_NOTIFY_END: + if (write) + handler = virtio_pci__notify_write; + break; + case VPCI_CFG_ISR_START...VPCI_CFG_ISR_END: + if (!write) + handler = virtio_pci__isr_read; + break; + case VPCI_CFG_DEV_START...VPCI_CFG_DEV_END: + if (write) + handler = virtio_pci__config_write; + else + handler = virtio_pci__config_read; + break; + } + + if (!handler) + return false; + + return handler(vdev, offset, data, size); +} + +void virtio_pci_modern__io_mmio_callback(struct kvm_cpu *vcpu, u64 addr, + u8 *data, u32 len, u8 is_write, + void *ptr) +{ + struct virtio_device *vdev = ptr; + struct virtio_pci *vpci = vdev->virtio; + u32 mmio_addr = virtio_pci__mmio_addr(vpci); + + virtio_pci_access(vcpu, vdev, addr - mmio_addr, data, len, is_write); +} + +int virtio_pci_modern_init(struct virtio_device *vdev) +{ + int subsys_id; + struct virtio_pci *vpci = vdev->virtio; + struct pci_device_header *hdr = &vpci->pci_hdr; + + subsys_id = le16_to_cpu(hdr->subsys_id); + + hdr->device_id = cpu_to_le16(PCI_DEVICE_ID_VIRTIO_BASE + subsys_id); + hdr->subsys_id = cpu_to_le16(PCI_SUBSYS_ID_VIRTIO_BASE + subsys_id); + + vpci->doorbell_offset = VPCI_CFG_NOTIFY_START; + vdev->endian = VIRTIO_ENDIAN_LE; + + hdr->msix.next = PCI_CAP_OFF(hdr, virtio); + + hdr->virtio.common = (struct virtio_pci_cap) { + .cap_vndr = PCI_CAP_ID_VNDR, + .cap_next = PCI_CAP_OFF(hdr, virtio.notify), + .cap_len = sizeof(hdr->virtio.common), + .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG, + .bar = 1, + .offset = cpu_to_le32(VPCI_CFG_COMMON_START), + .length = cpu_to_le32(VPCI_CFG_COMMON_SIZE), + }; + BUILD_BUG_ON(VPCI_CFG_COMMON_START & 0x3); + + hdr->virtio.notify = (struct virtio_pci_notify_cap) { + .cap.cap_vndr = PCI_CAP_ID_VNDR, + .cap.cap_next = PCI_CAP_OFF(hdr, virtio.isr), + .cap.cap_len = sizeof(hdr->virtio.notify), + .cap.cfg_type = VIRTIO_PCI_CAP_NOTIFY_CFG, + .cap.bar = 1, + .cap.offset = cpu_to_le32(VPCI_CFG_NOTIFY_START), + .cap.length = cpu_to_le32(VPCI_CFG_NOTIFY_SIZE), + /* + * Notify multiplier is 0, meaning that notifications are all on + * the same register + */ + }; + BUILD_BUG_ON(VPCI_CFG_NOTIFY_START & 0x3); + + hdr->virtio.isr = (struct virtio_pci_cap) { + .cap_vndr = PCI_CAP_ID_VNDR, + .cap_next = PCI_CAP_OFF(hdr, virtio.device), + .cap_len = sizeof(hdr->virtio.isr), + .cfg_type = VIRTIO_PCI_CAP_ISR_CFG, + .bar = 1, + .offset = cpu_to_le32(VPCI_CFG_ISR_START), + .length = cpu_to_le32(VPCI_CFG_ISR_SIZE), + }; + + hdr->virtio.device = (struct virtio_pci_cap) { + .cap_vndr = PCI_CAP_ID_VNDR, + .cap_next = PCI_CAP_OFF(hdr, virtio.pci), + .cap_len = sizeof(hdr->virtio.device), + .cfg_type = VIRTIO_PCI_CAP_DEVICE_CFG, + .bar = 1, + .offset = cpu_to_le32(VPCI_CFG_DEV_START), + .length = cpu_to_le32(VPCI_CFG_DEV_SIZE), + }; + BUILD_BUG_ON(VPCI_CFG_DEV_START & 0x3); + + /* + * TODO: implement this weird proxy capability (it is a "MUST" in the + * spec, but I don't know if anyone actually uses it). + * It doesn't use any BAR space. Instead the driver writes .cap.offset + * and .cap.length to access a register in a BAR. + */ + hdr->virtio.pci = (struct virtio_pci_cfg_cap) { + .cap.cap_vndr = PCI_CAP_ID_VNDR, + .cap.cap_next = 0, + .cap.cap_len = sizeof(hdr->virtio.pci), + .cap.cfg_type = VIRTIO_PCI_CAP_PCI_CFG, + }; + + return 0; +} diff --git a/virtio/pci.c b/virtio/pci.c index 35362423..c645d4a0 100644 --- a/virtio/pci.c +++ b/virtio/pci.c @@ -275,9 +275,15 @@ static int virtio_pci__bar_activate(struct kvm *kvm, int bar_num, void *data) { struct virtio_device *vdev = data; + mmio_handler_fn mmio_fn; u32 bar_addr, bar_size; int r = -EINVAL; + if (vdev->legacy) + mmio_fn = &virtio_pci_legacy__io_mmio_callback; + else + mmio_fn = &virtio_pci_modern__io_mmio_callback; + assert(bar_num <= 2); bar_addr = pci__bar_address(pci_hdr, bar_num); @@ -285,13 +291,10 @@ static int virtio_pci__bar_activate(struct kvm *kvm, switch (bar_num) { case 0: - r = kvm__register_pio(kvm, bar_addr, bar_size, - virtio_pci_legacy__io_mmio_callback, - vdev); + r = kvm__register_pio(kvm, bar_addr, bar_size, mmio_fn, vdev); break; case 1: - r = kvm__register_mmio(kvm, bar_addr, bar_size, false, - virtio_pci_legacy__io_mmio_callback, + r = kvm__register_mmio(kvm, bar_addr, bar_size, false, mmio_fn, vdev); break; case 2: @@ -347,14 +350,12 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev, mmio_addr = pci_get_mmio_block(PCI_IO_SIZE); msix_io_block = pci_get_mmio_block(VIRTIO_MSIX_BAR_SIZE); - vpci->doorbell_offset = VIRTIO_PCI_QUEUE_NOTIFY; - vpci->pci_hdr = (struct pci_device_header) { .vendor_id = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET), .device_id = cpu_to_le16(device_id), .command = PCI_COMMAND_IO | PCI_COMMAND_MEMORY, .header_type = PCI_HEADER_TYPE_NORMAL, - .revision_id = 0, + .revision_id = vdev->legacy ? 0 : 1, .class[0] = class & 0xff, .class[1] = (class >> 8) & 0xff, .class[2] = (class >> 16) & 0xff, @@ -367,7 +368,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev, .bar[2] = cpu_to_le32(msix_io_block | PCI_BASE_ADDRESS_SPACE_MEMORY), .status = cpu_to_le16(PCI_STATUS_CAP_LIST), - .capabilities = (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr, + .capabilities = PCI_CAP_OFF(&vpci->pci_hdr, msix), .bar_size[0] = cpu_to_le32(PCI_IO_SIZE), .bar_size[1] = cpu_to_le32(PCI_IO_SIZE), .bar_size[2] = cpu_to_le32(VIRTIO_MSIX_BAR_SIZE), @@ -414,6 +415,11 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev, if (r < 0) return r; + if (vdev->legacy) + vpci->doorbell_offset = VIRTIO_PCI_QUEUE_NOTIFY; + else + return virtio_pci_modern_init(vdev); + return 0; } From patchwork Fri Jul 1 14:24:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12903412 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EF0C2C43334 for ; Fri, 1 Jul 2022 14:31:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232475AbiGAObN (ORCPT ); Fri, 1 Jul 2022 10:31:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48694 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233262AbiGAOax (ORCPT ); Fri, 1 Jul 2022 10:30:53 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 5695171BDD for ; Fri, 1 Jul 2022 07:25:56 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 449A51C14; Fri, 1 Jul 2022 07:25:35 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id A4B4D3F792; Fri, 1 Jul 2022 07:25:33 -0700 (PDT) From: Jean-Philippe Brucker To: will@kernel.org Cc: andre.przywara@arm.com, alexandru.elisei@arm.com, kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org, jean-philippe@linaro.org Subject: [PATCH kvmtool v2 09/12] virtio: Move MMIO transport to mmio-legacy Date: Fri, 1 Jul 2022 15:24:31 +0100 Message-Id: <20220701142434.75170-10-jean-philippe.brucker@arm.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com> References: <20220701142434.75170-1-jean-philippe.brucker@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org To make space for the modern register layout, move the current code to mmio-legacy. Signed-off-by: Jean-Philippe Brucker --- Makefile | 1 + include/kvm/virtio-mmio.h | 9 +++ virtio/mmio-legacy.c | 150 +++++++++++++++++++++++++++++++++++ virtio/mmio.c | 160 ++------------------------------------ 4 files changed, 165 insertions(+), 155 deletions(-) create mode 100644 virtio/mmio-legacy.c diff --git a/Makefile b/Makefile index 56cfaaf4..4063d185 100644 --- a/Makefile +++ b/Makefile @@ -106,6 +106,7 @@ OBJS += virtio/9p-pdu.o OBJS += kvm-ipc.o OBJS += builtin-sandbox.o OBJS += virtio/mmio.o +OBJS += virtio/mmio-legacy.o # Translate uname -m into ARCH string ARCH ?= $(shell uname -m | sed -e s/i.86/i386/ -e s/ppc.*/powerpc/ \ diff --git a/include/kvm/virtio-mmio.h b/include/kvm/virtio-mmio.h index 6bc50bd1..e7ef8386 100644 --- a/include/kvm/virtio-mmio.h +++ b/include/kvm/virtio-mmio.h @@ -4,6 +4,8 @@ #include #include +#include + #define VIRTIO_MMIO_MAX_VQ 32 #define VIRTIO_MMIO_MAX_CONFIG 1 #define VIRTIO_MMIO_IO_SIZE 0x200 @@ -57,4 +59,11 @@ int virtio_mmio_exit(struct kvm *kvm, struct virtio_device *vdev); int virtio_mmio_reset(struct kvm *kvm, struct virtio_device *vdev); int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev, int device_id, int subsys_id, int class); +int virtio_mmio_init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, + u32 vq); + +void virtio_mmio_legacy_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, + u32 len, u8 is_write, void *ptr); +int virtio_mmio_init_vq(struct kvm *kvm, struct virtio_device *vdev, int vq); +void virtio_mmio_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq); #endif diff --git a/virtio/mmio-legacy.c b/virtio/mmio-legacy.c new file mode 100644 index 00000000..7ca7e69f --- /dev/null +++ b/virtio/mmio-legacy.c @@ -0,0 +1,150 @@ +#include "kvm/ioport.h" +#include "kvm/virtio.h" +#include "kvm/virtio-mmio.h" + +#include + +#define vmmio_selected_vq(vdev, vmmio) \ + (vdev)->ops->get_vq((vmmio)->kvm, (vmmio)->dev, (vmmio)->hdr.queue_sel) + +static void virtio_mmio_config_in(struct kvm_cpu *vcpu, + u64 addr, void *data, u32 len, + struct virtio_device *vdev) +{ + struct virtio_mmio *vmmio = vdev->virtio; + struct virt_queue *vq; + u32 val = 0; + + switch (addr) { + case VIRTIO_MMIO_MAGIC_VALUE: + case VIRTIO_MMIO_VERSION: + case VIRTIO_MMIO_DEVICE_ID: + case VIRTIO_MMIO_VENDOR_ID: + case VIRTIO_MMIO_STATUS: + case VIRTIO_MMIO_INTERRUPT_STATUS: + ioport__write32(data, *(u32 *)(((void *)&vmmio->hdr) + addr)); + break; + case VIRTIO_MMIO_DEVICE_FEATURES: + if (vmmio->hdr.host_features_sel == 0) + val = vdev->ops->get_host_features(vmmio->kvm, + vmmio->dev); + ioport__write32(data, val); + break; + case VIRTIO_MMIO_QUEUE_PFN: + vq = vmmio_selected_vq(vdev, vmmio); + ioport__write32(data, vq->vring_addr.pfn); + break; + case VIRTIO_MMIO_QUEUE_NUM_MAX: + val = vdev->ops->get_size_vq(vmmio->kvm, vmmio->dev, + vmmio->hdr.queue_sel); + ioport__write32(data, val); + break; + default: + break; + } +} + +static void virtio_mmio_config_out(struct kvm_cpu *vcpu, + u64 addr, void *data, u32 len, + struct virtio_device *vdev) +{ + struct virtio_mmio *vmmio = vdev->virtio; + struct kvm *kvm = vmmio->kvm; + unsigned int vq_count = vdev->ops->get_vq_count(kvm, vmmio->dev); + struct virt_queue *vq; + u32 val = 0; + + switch (addr) { + case VIRTIO_MMIO_DEVICE_FEATURES_SEL: + case VIRTIO_MMIO_DRIVER_FEATURES_SEL: + val = ioport__read32(data); + *(u32 *)(((void *)&vmmio->hdr) + addr) = val; + break; + case VIRTIO_MMIO_QUEUE_SEL: + val = ioport__read32(data); + if (val >= vq_count) { + WARN_ONCE(1, "QUEUE_SEL value (%u) is larger than VQ count (%u)\n", + val, vq_count); + break; + } + *(u32 *)(((void *)&vmmio->hdr) + addr) = val; + break; + case VIRTIO_MMIO_STATUS: + vmmio->hdr.status = ioport__read32(data); + if (!vmmio->hdr.status) /* Sample endianness on reset */ + vdev->endian = kvm_cpu__get_endianness(vcpu); + virtio_notify_status(kvm, vdev, vmmio->dev, vmmio->hdr.status); + break; + case VIRTIO_MMIO_DRIVER_FEATURES: + if (vmmio->hdr.guest_features_sel == 0) { + val = ioport__read32(data); + virtio_set_guest_features(vmmio->kvm, vdev, + vmmio->dev, val); + } + break; + case VIRTIO_MMIO_GUEST_PAGE_SIZE: + val = ioport__read32(data); + vmmio->hdr.guest_page_size = val; + break; + case VIRTIO_MMIO_QUEUE_NUM: + val = ioport__read32(data); + vmmio->hdr.queue_num = val; + vdev->ops->set_size_vq(vmmio->kvm, vmmio->dev, + vmmio->hdr.queue_sel, val); + break; + case VIRTIO_MMIO_QUEUE_ALIGN: + val = ioport__read32(data); + vmmio->hdr.queue_align = val; + break; + case VIRTIO_MMIO_QUEUE_PFN: + val = ioport__read32(data); + if (val) { + vq = vmmio_selected_vq(vdev, vmmio); + vq->vring_addr = (struct vring_addr) { + .legacy = true, + .pfn = val, + .align = vmmio->hdr.queue_align, + .pgsize = vmmio->hdr.guest_page_size, + }; + virtio_mmio_init_vq(kvm, vdev, vmmio->hdr.queue_sel); + } else { + virtio_mmio_exit_vq(kvm, vdev, vmmio->hdr.queue_sel); + } + break; + case VIRTIO_MMIO_QUEUE_NOTIFY: + val = ioport__read32(data); + if (val >= vq_count) { + WARN_ONCE(1, "QUEUE_NOTIFY value (%u) is larger than VQ count (%u)\n", + val, vq_count); + break; + } + vdev->ops->notify_vq(vmmio->kvm, vmmio->dev, val); + break; + case VIRTIO_MMIO_INTERRUPT_ACK: + val = ioport__read32(data); + vmmio->hdr.interrupt_state &= ~val; + break; + default: + break; + }; +} + +void virtio_mmio_legacy_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, + u32 len, u8 is_write, void *ptr) +{ + struct virtio_device *vdev = ptr; + struct virtio_mmio *vmmio = vdev->virtio; + u32 offset = addr - vmmio->addr; + + if (offset >= VIRTIO_MMIO_CONFIG) { + offset -= VIRTIO_MMIO_CONFIG; + virtio_access_config(vmmio->kvm, vdev, vmmio->dev, offset, data, + len, is_write); + return; + } + + if (is_write) + virtio_mmio_config_out(vcpu, offset, data, len, ptr); + else + virtio_mmio_config_in(vcpu, offset, data, len, ptr); +} diff --git a/virtio/mmio.c b/virtio/mmio.c index 2a96e0e3..fab45733 100644 --- a/virtio/mmio.c +++ b/virtio/mmio.c @@ -1,10 +1,8 @@ #include "kvm/devices.h" #include "kvm/virtio-mmio.h" #include "kvm/ioeventfd.h" -#include "kvm/ioport.h" #include "kvm/virtio.h" #include "kvm/kvm.h" -#include "kvm/kvm-cpu.h" #include "kvm/irq.h" #include "kvm/fdt.h" @@ -29,8 +27,8 @@ static void virtio_mmio_ioevent_callback(struct kvm *kvm, void *param) ioeventfd->vdev->ops->notify_vq(kvm, vmmio->dev, ioeventfd->vq); } -static int virtio_mmio_init_ioeventfd(struct kvm *kvm, - struct virtio_device *vdev, u32 vq) +int virtio_mmio_init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, + u32 vq) { struct virtio_mmio *vmmio = vdev->virtio; struct ioevent ioevent; @@ -79,8 +77,7 @@ int virtio_mmio_signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq) return 0; } -static int virtio_mmio_init_vq(struct kvm *kvm, struct virtio_device *vdev, - int vq) +int virtio_mmio_init_vq(struct kvm *kvm, struct virtio_device *vdev, int vq) { int ret; struct virtio_mmio *vmmio = vdev->virtio; @@ -93,8 +90,7 @@ static int virtio_mmio_init_vq(struct kvm *kvm, struct virtio_device *vdev, return vdev->ops->init_vq(vmmio->kvm, vmmio->dev, vq); } -static void virtio_mmio_exit_vq(struct kvm *kvm, struct virtio_device *vdev, - int vq) +void virtio_mmio_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq) { struct virtio_mmio *vmmio = vdev->virtio; @@ -112,152 +108,6 @@ int virtio_mmio_signal_config(struct kvm *kvm, struct virtio_device *vdev) return 0; } -#define vmmio_selected_vq(vdev, vmmio) \ - (vdev)->ops->get_vq((vmmio)->kvm, (vmmio)->dev, (vmmio)->hdr.queue_sel) - -static void virtio_mmio_config_in(struct kvm_cpu *vcpu, - u64 addr, void *data, u32 len, - struct virtio_device *vdev) -{ - struct virtio_mmio *vmmio = vdev->virtio; - struct virt_queue *vq; - u32 val = 0; - - switch (addr) { - case VIRTIO_MMIO_MAGIC_VALUE: - case VIRTIO_MMIO_VERSION: - case VIRTIO_MMIO_DEVICE_ID: - case VIRTIO_MMIO_VENDOR_ID: - case VIRTIO_MMIO_STATUS: - case VIRTIO_MMIO_INTERRUPT_STATUS: - ioport__write32(data, *(u32 *)(((void *)&vmmio->hdr) + addr)); - break; - case VIRTIO_MMIO_DEVICE_FEATURES: - if (vmmio->hdr.host_features_sel == 0) - val = vdev->ops->get_host_features(vmmio->kvm, - vmmio->dev); - ioport__write32(data, val); - break; - case VIRTIO_MMIO_QUEUE_PFN: - vq = vmmio_selected_vq(vdev, vmmio); - ioport__write32(data, vq->vring_addr.pfn); - break; - case VIRTIO_MMIO_QUEUE_NUM_MAX: - val = vdev->ops->get_size_vq(vmmio->kvm, vmmio->dev, - vmmio->hdr.queue_sel); - ioport__write32(data, val); - break; - default: - break; - } -} - -static void virtio_mmio_config_out(struct kvm_cpu *vcpu, - u64 addr, void *data, u32 len, - struct virtio_device *vdev) -{ - struct virtio_mmio *vmmio = vdev->virtio; - struct kvm *kvm = vmmio->kvm; - unsigned int vq_count = vdev->ops->get_vq_count(kvm, vmmio->dev); - struct virt_queue *vq; - u32 val = 0; - - switch (addr) { - case VIRTIO_MMIO_DEVICE_FEATURES_SEL: - case VIRTIO_MMIO_DRIVER_FEATURES_SEL: - val = ioport__read32(data); - *(u32 *)(((void *)&vmmio->hdr) + addr) = val; - break; - case VIRTIO_MMIO_QUEUE_SEL: - val = ioport__read32(data); - if (val >= vq_count) { - WARN_ONCE(1, "QUEUE_SEL value (%u) is larger than VQ count (%u)\n", - val, vq_count); - break; - } - *(u32 *)(((void *)&vmmio->hdr) + addr) = val; - break; - case VIRTIO_MMIO_STATUS: - vmmio->hdr.status = ioport__read32(data); - if (!vmmio->hdr.status) /* Sample endianness on reset */ - vdev->endian = kvm_cpu__get_endianness(vcpu); - virtio_notify_status(kvm, vdev, vmmio->dev, vmmio->hdr.status); - break; - case VIRTIO_MMIO_DRIVER_FEATURES: - if (vmmio->hdr.guest_features_sel == 0) { - val = ioport__read32(data); - virtio_set_guest_features(vmmio->kvm, vdev, - vmmio->dev, val); - } - break; - case VIRTIO_MMIO_GUEST_PAGE_SIZE: - val = ioport__read32(data); - vmmio->hdr.guest_page_size = val; - break; - case VIRTIO_MMIO_QUEUE_NUM: - val = ioport__read32(data); - vmmio->hdr.queue_num = val; - vdev->ops->set_size_vq(vmmio->kvm, vmmio->dev, - vmmio->hdr.queue_sel, val); - break; - case VIRTIO_MMIO_QUEUE_ALIGN: - val = ioport__read32(data); - vmmio->hdr.queue_align = val; - break; - case VIRTIO_MMIO_QUEUE_PFN: - val = ioport__read32(data); - if (val) { - vq = vmmio_selected_vq(vdev, vmmio); - vq->vring_addr = (struct vring_addr) { - .legacy = true, - .pfn = val, - .align = vmmio->hdr.queue_align, - .pgsize = vmmio->hdr.guest_page_size, - }; - virtio_mmio_init_vq(kvm, vdev, vmmio->hdr.queue_sel); - } else { - virtio_mmio_exit_vq(kvm, vdev, vmmio->hdr.queue_sel); - } - break; - case VIRTIO_MMIO_QUEUE_NOTIFY: - val = ioport__read32(data); - if (val >= vq_count) { - WARN_ONCE(1, "QUEUE_NOTIFY value (%u) is larger than VQ count (%u)\n", - val, vq_count); - break; - } - vdev->ops->notify_vq(vmmio->kvm, vmmio->dev, val); - break; - case VIRTIO_MMIO_INTERRUPT_ACK: - val = ioport__read32(data); - vmmio->hdr.interrupt_state &= ~val; - break; - default: - break; - }; -} - -static void virtio_mmio_mmio_callback(struct kvm_cpu *vcpu, - u64 addr, u8 *data, u32 len, - u8 is_write, void *ptr) -{ - struct virtio_device *vdev = ptr; - struct virtio_mmio *vmmio = vdev->virtio; - u32 offset = addr - vmmio->addr; - - if (offset >= VIRTIO_MMIO_CONFIG) { - offset -= VIRTIO_MMIO_CONFIG; - virtio_access_config(vmmio->kvm, vdev, vmmio->dev, offset, data, - len, is_write); - return; - } - - if (is_write) - virtio_mmio_config_out(vcpu, offset, data, len, ptr); - else - virtio_mmio_config_in(vcpu, offset, data, len, ptr); -} - #ifdef CONFIG_HAS_LIBFDT #define DEVICE_NAME_MAX_LEN 32 static @@ -307,7 +157,7 @@ int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev, vmmio->dev = dev; r = kvm__register_mmio(kvm, vmmio->addr, VIRTIO_MMIO_IO_SIZE, - false, virtio_mmio_mmio_callback, vdev); + false, virtio_mmio_legacy_callback, vdev); if (r < 0) return r; From patchwork Fri Jul 1 14:24:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12903415 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3B939CCA47B for ; Fri, 1 Jul 2022 14:31:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233279AbiGAObP (ORCPT ); Fri, 1 Jul 2022 10:31:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48760 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232558AbiGAOay (ORCPT ); Fri, 1 Jul 2022 10:30:54 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id AF2CF71BE4 for ; Fri, 1 Jul 2022 07:25:56 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 392E91C25; Fri, 1 Jul 2022 07:25:37 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 485733F792; Fri, 1 Jul 2022 07:25:35 -0700 (PDT) From: Jean-Philippe Brucker To: will@kernel.org Cc: andre.przywara@arm.com, alexandru.elisei@arm.com, kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org, jean-philippe@linaro.org Subject: [PATCH kvmtool v2 10/12] virtio: Add support for modern virtio-mmio Date: Fri, 1 Jul 2022 15:24:32 +0100 Message-Id: <20220701142434.75170-11-jean-philippe.brucker@arm.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com> References: <20220701142434.75170-1-jean-philippe.brucker@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add modern MMIO transport to virtio, make it the default. Legacy transport can be enabled with --virtio-legacy. The main change for MMIO is the queue addresses. They are now 64-bit addresses instead of 32-bit PFNs. Apart from that all changes for supporting modern devices are already implemented. Signed-off-by: Jean-Philippe Brucker --- Makefile | 1 + arm/include/arm-common/kvm-arch.h | 2 +- include/kvm/virtio-mmio.h | 20 +++- include/kvm/virtio.h | 1 + riscv/include/kvm/kvm-arch.h | 3 +- virtio/core.c | 6 +- virtio/mmio-modern.c | 161 ++++++++++++++++++++++++++++++ virtio/mmio.c | 12 ++- 8 files changed, 195 insertions(+), 11 deletions(-) create mode 100644 virtio/mmio-modern.c diff --git a/Makefile b/Makefile index 4063d185..349468f3 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,7 @@ OBJS += kvm-ipc.o OBJS += builtin-sandbox.o OBJS += virtio/mmio.o OBJS += virtio/mmio-legacy.o +OBJS += virtio/mmio-modern.o # Translate uname -m into ARCH string ARCH ?= $(shell uname -m | sed -e s/i.86/i386/ -e s/ppc.*/powerpc/ \ diff --git a/arm/include/arm-common/kvm-arch.h b/arm/include/arm-common/kvm-arch.h index 0a960f4f..a4c7604a 100644 --- a/arm/include/arm-common/kvm-arch.h +++ b/arm/include/arm-common/kvm-arch.h @@ -84,7 +84,7 @@ #define VIRTIO_DEFAULT_TRANS(kvm) \ ((kvm)->cfg.arch.virtio_trans_pci ? \ ((kvm)->cfg.virtio_legacy ? VIRTIO_PCI_LEGACY : VIRTIO_PCI) : \ - VIRTIO_MMIO) + ((kvm)->cfg.virtio_legacy ? VIRTIO_MMIO_LEGACY : VIRTIO_MMIO)) #define VIRTIO_RING_ENDIAN (VIRTIO_ENDIAN_LE | VIRTIO_ENDIAN_BE) diff --git a/include/kvm/virtio-mmio.h b/include/kvm/virtio-mmio.h index e7ef8386..b428b8d3 100644 --- a/include/kvm/virtio-mmio.h +++ b/include/kvm/virtio-mmio.h @@ -27,20 +27,30 @@ struct virtio_mmio_hdr { u32 reserved_1[2]; u32 guest_features; u32 guest_features_sel; - u32 guest_page_size; + u32 guest_page_size; /* legacy */ u32 reserved_2; u32 queue_sel; u32 queue_num_max; u32 queue_num; - u32 queue_align; - u32 queue_pfn; - u32 reserved_3[3]; + u32 queue_align; /* legacy */ + u32 queue_pfn; /* legacy */ + u32 queue_ready; /* modern */ + u32 reserved_3[2]; u32 queue_notify; u32 reserved_4[3]; u32 interrupt_state; u32 interrupt_ack; u32 reserved_5[2]; u32 status; + u32 reserved_7[3]; + u32 queue_desc_low; /* modern */ + u32 queue_desc_high; + u32 reserved_8[2]; + u32 queue_avail_low; + u32 queue_avail_high; + u32 reserved_9[2]; + u32 queue_used_low; + u32 queue_used_high; } __attribute__((packed)); struct virtio_mmio { @@ -64,6 +74,8 @@ int virtio_mmio_init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, void virtio_mmio_legacy_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr); +void virtio_mmio_modern_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, + u32 len, u8 is_write, void *ptr); int virtio_mmio_init_vq(struct kvm *kvm, struct virtio_device *vdev, int vq); void virtio_mmio_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq); #endif diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h index 869064ba..94bddefe 100644 --- a/include/kvm/virtio.h +++ b/include/kvm/virtio.h @@ -196,6 +196,7 @@ enum virtio_trans { VIRTIO_PCI, VIRTIO_PCI_LEGACY, VIRTIO_MMIO, + VIRTIO_MMIO_LEGACY, }; struct virtio_device { diff --git a/riscv/include/kvm/kvm-arch.h b/riscv/include/kvm/kvm-arch.h index f090883c..1e130f59 100644 --- a/riscv/include/kvm/kvm-arch.h +++ b/riscv/include/kvm/kvm-arch.h @@ -46,7 +46,8 @@ #define KVM_VM_TYPE 0 -#define VIRTIO_DEFAULT_TRANS(kvm) VIRTIO_MMIO +#define VIRTIO_DEFAULT_TRANS(kvm) \ + ((kvm)->cfg.virtio_legacy ? VIRTIO_MMIO_LEGACY : VIRTIO_MMIO) #define VIRTIO_RING_ENDIAN VIRTIO_ENDIAN_LE diff --git a/virtio/core.c b/virtio/core.c index 5fc2e789..f432421a 100644 --- a/virtio/core.c +++ b/virtio/core.c @@ -16,7 +16,7 @@ const char* virtio_trans_name(enum virtio_trans trans) { if (trans == VIRTIO_PCI || trans == VIRTIO_PCI_LEGACY) return "pci"; - else if (trans == VIRTIO_MMIO) + else if (trans == VIRTIO_MMIO || trans == VIRTIO_MMIO_LEGACY) return "mmio"; return "unknown"; } @@ -345,8 +345,10 @@ int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev, vdev->ops->reset = virtio_pci__reset; r = vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class); break; - case VIRTIO_MMIO: + case VIRTIO_MMIO_LEGACY: vdev->legacy = true; + /* fall through */ + case VIRTIO_MMIO: virtio = calloc(sizeof(struct virtio_mmio), 1); if (!virtio) return -ENOMEM; diff --git a/virtio/mmio-modern.c b/virtio/mmio-modern.c new file mode 100644 index 00000000..6c0bb382 --- /dev/null +++ b/virtio/mmio-modern.c @@ -0,0 +1,161 @@ +#include "kvm/virtio.h" +#include "kvm/virtio-mmio.h" + +#include + +#define vmmio_selected_vq(vmmio) \ + vdev->ops->get_vq((vmmio)->kvm, (vmmio)->dev, (vmmio)->hdr.queue_sel) + +static void virtio_mmio_config_in(struct kvm_cpu *vcpu, + u64 addr, u32 *data, u32 len, + struct virtio_device *vdev) +{ + struct virtio_mmio *vmmio = vdev->virtio; + u64 features = 1ULL << VIRTIO_F_VERSION_1; + u32 val = 0; + + switch (addr) { + case VIRTIO_MMIO_MAGIC_VALUE: + case VIRTIO_MMIO_VERSION: + case VIRTIO_MMIO_DEVICE_ID: + case VIRTIO_MMIO_VENDOR_ID: + case VIRTIO_MMIO_STATUS: + case VIRTIO_MMIO_INTERRUPT_STATUS: + val = *(u32 *)(((void *)&vmmio->hdr) + addr); + break; + case VIRTIO_MMIO_DEVICE_FEATURES: + if (vmmio->hdr.host_features_sel > 1) + break; + features |= vdev->ops->get_host_features(vmmio->kvm, vmmio->dev); + val = features >> (32 * vmmio->hdr.host_features_sel); + break; + case VIRTIO_MMIO_QUEUE_NUM_MAX: + val = vdev->ops->get_size_vq(vmmio->kvm, vmmio->dev, + vmmio->hdr.queue_sel); + break; + case VIRTIO_MMIO_QUEUE_READY: + val = vmmio_selected_vq(vmmio)->enabled; + break; + case VIRTIO_MMIO_QUEUE_DESC_LOW: + val = vmmio_selected_vq(vmmio)->vring_addr.desc_lo; + break; + case VIRTIO_MMIO_QUEUE_DESC_HIGH: + val = vmmio_selected_vq(vmmio)->vring_addr.desc_hi; + break; + case VIRTIO_MMIO_QUEUE_USED_LOW: + val = vmmio_selected_vq(vmmio)->vring_addr.used_lo; + break; + case VIRTIO_MMIO_QUEUE_USED_HIGH: + val = vmmio_selected_vq(vmmio)->vring_addr.used_hi; + break; + case VIRTIO_MMIO_QUEUE_AVAIL_LOW: + val = vmmio_selected_vq(vmmio)->vring_addr.avail_lo; + break; + case VIRTIO_MMIO_QUEUE_AVAIL_HIGH: + val = vmmio_selected_vq(vmmio)->vring_addr.avail_hi; + break; + case VIRTIO_MMIO_CONFIG_GENERATION: + /* + * The config generation changes when the device updates a + * config field larger than 32 bits, that the driver reads using + * multiple accesses. Since kvmtool doesn't use any mutable + * config field larger than 32 bits, the generation is constant. + */ + break; + default: + return; + } + + *data = cpu_to_le32(val); +} + +static void virtio_mmio_config_out(struct kvm_cpu *vcpu, + u64 addr, u32 *data, u32 len, + struct virtio_device *vdev) +{ + struct virtio_mmio *vmmio = vdev->virtio; + struct kvm *kvm = vmmio->kvm; + u32 val = le32_to_cpu(*data); + u64 features; + + switch (addr) { + case VIRTIO_MMIO_DEVICE_FEATURES_SEL: + case VIRTIO_MMIO_DRIVER_FEATURES_SEL: + case VIRTIO_MMIO_QUEUE_SEL: + *(u32 *)(((void *)&vmmio->hdr) + addr) = val; + break; + case VIRTIO_MMIO_STATUS: + vmmio->hdr.status = val; + virtio_notify_status(kvm, vdev, vmmio->dev, val); + break; + case VIRTIO_MMIO_DRIVER_FEATURES: + if (vmmio->hdr.guest_features_sel > 1) + break; + + features = (u64)val << (32 * vmmio->hdr.guest_features_sel); + virtio_set_guest_features(vmmio->kvm, vdev, vmmio->dev, + features); + break; + case VIRTIO_MMIO_QUEUE_NUM: + vmmio->hdr.queue_num = val; + vdev->ops->set_size_vq(vmmio->kvm, vmmio->dev, + vmmio->hdr.queue_sel, val); + break; + case VIRTIO_MMIO_QUEUE_READY: + if (val) + virtio_mmio_init_vq(kvm, vdev, vmmio->hdr.queue_sel); + else + virtio_mmio_exit_vq(kvm, vdev, vmmio->hdr.queue_sel); + break; + case VIRTIO_MMIO_QUEUE_NOTIFY: + vdev->ops->notify_vq(vmmio->kvm, vmmio->dev, val); + break; + case VIRTIO_MMIO_INTERRUPT_ACK: + vmmio->hdr.interrupt_state &= ~val; + break; + case VIRTIO_MMIO_QUEUE_DESC_LOW: + vmmio_selected_vq(vmmio)->vring_addr.desc_lo = val; + break; + case VIRTIO_MMIO_QUEUE_DESC_HIGH: + vmmio_selected_vq(vmmio)->vring_addr.desc_hi = val; + break; + case VIRTIO_MMIO_QUEUE_USED_LOW: + vmmio_selected_vq(vmmio)->vring_addr.used_lo = val; + break; + case VIRTIO_MMIO_QUEUE_USED_HIGH: + vmmio_selected_vq(vmmio)->vring_addr.used_hi = val; + break; + case VIRTIO_MMIO_QUEUE_AVAIL_LOW: + vmmio_selected_vq(vmmio)->vring_addr.avail_lo = val; + break; + case VIRTIO_MMIO_QUEUE_AVAIL_HIGH: + vmmio_selected_vq(vmmio)->vring_addr.avail_hi = val; + break; + }; +} + +void virtio_mmio_modern_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, + u32 len, u8 is_write, void *ptr) +{ + struct virtio_device *vdev = ptr; + struct virtio_mmio *vmmio = vdev->virtio; + u32 offset = addr - vmmio->addr; + + if (offset >= VIRTIO_MMIO_CONFIG) { + offset -= VIRTIO_MMIO_CONFIG; + virtio_access_config(vmmio->kvm, vdev, vmmio->dev, offset, data, + len, is_write); + return; + } + + if (len != 4) { + pr_debug("Invalid %s size %d at 0x%llx", is_write ? "write" : + "read", len, addr); + return; + } + + if (is_write) + virtio_mmio_config_out(vcpu, offset, (void *)data, len, ptr); + else + virtio_mmio_config_in(vcpu, offset, (void *)data, len, ptr); +} diff --git a/virtio/mmio.c b/virtio/mmio.c index fab45733..fae73b52 100644 --- a/virtio/mmio.c +++ b/virtio/mmio.c @@ -149,6 +149,7 @@ static void generate_virtio_mmio_fdt_node(void *fdt, int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev, int device_id, int subsys_id, int class) { + bool legacy = vdev->legacy; struct virtio_mmio *vmmio = vdev->virtio; int r; @@ -156,14 +157,19 @@ int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev, vmmio->kvm = kvm; vmmio->dev = dev; - r = kvm__register_mmio(kvm, vmmio->addr, VIRTIO_MMIO_IO_SIZE, - false, virtio_mmio_legacy_callback, vdev); + if (!legacy) + vdev->endian = VIRTIO_ENDIAN_LE; + + r = kvm__register_mmio(kvm, vmmio->addr, VIRTIO_MMIO_IO_SIZE, false, + legacy ? virtio_mmio_legacy_callback : + virtio_mmio_modern_callback, + vdev); if (r < 0) return r; vmmio->hdr = (struct virtio_mmio_hdr) { .magic = {'v', 'i', 'r', 't'}, - .version = 1, + .version = legacy ? 1 : 2, .device_id = subsys_id, .vendor_id = 0x4d564b4c , /* 'LKVM' */ .queue_num_max = 256, From patchwork Fri Jul 1 14:24:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12903413 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 17B1ECCA479 for ; Fri, 1 Jul 2022 14:31:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230396AbiGAObO (ORCPT ); Fri, 1 Jul 2022 10:31:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51700 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232723AbiGAOay (ORCPT ); Fri, 1 Jul 2022 10:30:54 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 788DB3FBE1 for ; Fri, 1 Jul 2022 07:25:58 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id CC70A1C2B; Fri, 1 Jul 2022 07:25:38 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 3B7023F792; Fri, 1 Jul 2022 07:25:37 -0700 (PDT) From: Jean-Philippe Brucker To: will@kernel.org Cc: andre.przywara@arm.com, alexandru.elisei@arm.com, kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org, jean-philippe@linaro.org Subject: [PATCH kvmtool v2 11/12] virtio/pci: Initialize all vectors to VIRTIO_MSI_NO_VECTOR Date: Fri, 1 Jul 2022 15:24:33 +0100 Message-Id: <20220701142434.75170-12-jean-philippe.brucker@arm.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com> References: <20220701142434.75170-1-jean-philippe.brucker@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org According to the virtio spec, all vectors must be initialized to VIRTIO_MSI_NO_VECTOR (0xffff). In 4.1.5.1.2.1 "Device Requirements: MSI-X Vector Configuration": The device MUST return vector mapped to a given event, (NO_VECTOR if unmapped) on read of config_msix_vector/queue_msix_vector. Currently we return 0, which is a valid MSI vector. Return NO_VECTOR instead. Signed-off-by: Jean-Philippe Brucker --- include/kvm/virtio-pci.h | 2 +- virtio/pci.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/kvm/virtio-pci.h b/include/kvm/virtio-pci.h index 47075334..4590d1b3 100644 --- a/include/kvm/virtio-pci.h +++ b/include/kvm/virtio-pci.h @@ -53,7 +53,7 @@ struct virtio_pci { /* MSI-X */ u16 config_vector; u32 config_gsi; - u32 vq_vector[VIRTIO_PCI_MAX_VQ]; + u16 vq_vector[VIRTIO_PCI_MAX_VQ]; u32 gsis[VIRTIO_PCI_MAX_VQ]; u64 msix_pba; struct msix_table msix_table[VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG]; diff --git a/virtio/pci.c b/virtio/pci.c index c645d4a0..cffabc76 100644 --- a/virtio/pci.c +++ b/virtio/pci.c @@ -404,7 +404,9 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev, /* Both table and PBA are mapped to the same BAR (2) */ vpci->pci_hdr.msix.table_offset = cpu_to_le32(2); vpci->pci_hdr.msix.pba_offset = cpu_to_le32(2 | VIRTIO_MSIX_TABLE_SIZE); - vpci->config_vector = 0; + vpci->config_vector = VIRTIO_MSI_NO_VECTOR; + /* Initialize all vq vectors to NO_VECTOR */ + memset(vpci->vq_vector, 0xff, sizeof(vpci->vq_vector)); if (irq__can_signal_msi(kvm)) vpci->features |= VIRTIO_PCI_F_SIGNAL_MSI; From patchwork Fri Jul 1 14:24:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jean-Philippe Brucker X-Patchwork-Id: 12903414 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BAA8DC433EF for ; Fri, 1 Jul 2022 14:31:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233289AbiGAObQ (ORCPT ); Fri, 1 Jul 2022 10:31:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50074 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232938AbiGAOay (ORCPT ); Fri, 1 Jul 2022 10:30:54 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 9F5663FBF9 for ; Fri, 1 Jul 2022 07:25:58 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 6C2FD1CC4; Fri, 1 Jul 2022 07:25:40 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id CE9513F792; Fri, 1 Jul 2022 07:25:38 -0700 (PDT) From: Jean-Philippe Brucker To: will@kernel.org Cc: andre.przywara@arm.com, alexandru.elisei@arm.com, kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org, jean-philippe@linaro.org Subject: [PATCH kvmtool v2 12/12] virtio/pci: Remove VIRTIO_PCI_F_SIGNAL_MSI Date: Fri, 1 Jul 2022 15:24:34 +0100 Message-Id: <20220701142434.75170-13-jean-philippe.brucker@arm.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com> References: <20220701142434.75170-1-jean-philippe.brucker@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org VIRTIO_PCI_F_SIGNAL_MSI is not a virtio feature but an internal flag. Change it to bool to avoid confusion. Signed-off-by: Jean-Philippe Brucker --- include/kvm/virtio-pci.h | 4 +--- virtio/pci.c | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/include/kvm/virtio-pci.h b/include/kvm/virtio-pci.h index 4590d1b3..143028b1 100644 --- a/include/kvm/virtio-pci.h +++ b/include/kvm/virtio-pci.h @@ -20,8 +20,6 @@ struct virtio_pci_ioevent_param { u32 vq; }; -#define VIRTIO_PCI_F_SIGNAL_MSI (1 << 0) - #define ALIGN_UP(x, s) ALIGN((x) + (s) - 1, (s)) #define VIRTIO_NR_MSIX (VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG) #define VIRTIO_MSIX_TABLE_SIZE (VIRTIO_NR_MSIX * 16) @@ -36,11 +34,11 @@ struct virtio_pci { struct kvm *kvm; u32 doorbell_offset; + bool signal_msi; u8 status; u8 isr; u32 device_features_sel; u32 driver_features_sel; - u32 features; /* * We cannot rely on the INTERRUPT_LINE byte in the config space once diff --git a/virtio/pci.c b/virtio/pci.c index cffabc76..701f4566 100644 --- a/virtio/pci.c +++ b/virtio/pci.c @@ -28,7 +28,7 @@ int virtio_pci__add_msix_route(struct virtio_pci *vpci, u32 vec) * We don't need IRQ routing if we can use * MSI injection via the KVM_SIGNAL_MSI ioctl. */ - if (gsi == -ENXIO && vpci->features & VIRTIO_PCI_F_SIGNAL_MSI) + if (gsi == -ENXIO && vpci->signal_msi) return gsi; if (gsi < 0) @@ -234,7 +234,7 @@ int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq) return 0; } - if (vpci->features & VIRTIO_PCI_F_SIGNAL_MSI) + if (vpci->signal_msi) virtio_pci__signal_msi(kvm, vpci, vpci->vq_vector[vq]); else kvm__irq_trigger(kvm, vpci->gsis[vq]); @@ -258,7 +258,7 @@ int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev) return 0; } - if (vpci->features & VIRTIO_PCI_F_SIGNAL_MSI) + if (vpci->signal_msi) virtio_pci__signal_msi(kvm, vpci, tbl); else kvm__irq_trigger(kvm, vpci->config_gsi); @@ -409,7 +409,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev, memset(vpci->vq_vector, 0xff, sizeof(vpci->vq_vector)); if (irq__can_signal_msi(kvm)) - vpci->features |= VIRTIO_PCI_F_SIGNAL_MSI; + vpci->signal_msi = true; vpci->legacy_irq_line = pci__assign_irq(&vpci->pci_hdr);