From: Marc Zyngier <maz@kernel.org>
To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu
Cc: Andre Przywara <andre.przywara@arm.com>,
Alexandru Elisei <alexandru.elisei@arm.com>,
Will Deacon <will@kernel.org>
Subject: [PATCH][kvmtool] virtio/pci: Size the MSI-X bar according to the number of MSI-X
Date: Fri, 27 Aug 2021 12:54:05 +0100 [thread overview]
Message-ID: <20210827115405.1981529-1-maz@kernel.org> (raw)
Since 45d3b59e8c45 ("kvm tools: Increase amount of possible interrupts
per PCI device"), the number of MSI-S has gone from 4 to 33.
However, the corresponding storage hasn't been upgraded, and writing
to the MSI-X table is a pretty risky business. Now that the Linux
kernel writes to *all* MSI-X entries before doing anything else
with the device, kvmtool dies a horrible death.
Fix it by properly defining the size of the MSI-X bar, and make
Linux great again.
This includes some fixes the PBA region decoding, as well as minor
cleanups to make this code a bit more maintainable.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
virtio/pci.c | 42 ++++++++++++++++++++++++++++++------------
1 file changed, 30 insertions(+), 12 deletions(-)
diff --git a/virtio/pci.c b/virtio/pci.c
index eb91f512..41085291 100644
--- a/virtio/pci.c
+++ b/virtio/pci.c
@@ -7,6 +7,7 @@
#include "kvm/irq.h"
#include "kvm/virtio.h"
#include "kvm/ioeventfd.h"
+#include "kvm/util.h"
#include <sys/ioctl.h>
#include <linux/virtio_pci.h>
@@ -14,6 +15,13 @@
#include <assert.h>
#include <string.h>
+#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);
@@ -333,18 +341,27 @@ static void virtio_pci__msix_mmio_callback(struct kvm_cpu *vcpu,
struct virtio_pci *vpci = vdev->virtio;
struct msix_table *table;
u32 msix_io_addr = virtio_pci__msix_io_addr(vpci);
+ u32 pba_offset;
int vecnum;
size_t offset;
- if (addr > msix_io_addr + PCI_IO_SIZE) {
+ BUILD_BUG_ON(VIRTIO_NR_MSIX > (sizeof(vpci->msix_pba) * 8));
+
+ pba_offset = vpci->pci_hdr.msix.pba_offset & ~PCI_MSIX_TABLE_BIR;
+ if (addr >= msix_io_addr + pba_offset) {
+ /* Read access to PBA */
if (is_write)
return;
- table = (struct msix_table *)&vpci->msix_pba;
- offset = addr - (msix_io_addr + PCI_IO_SIZE);
- } else {
- table = vpci->msix_table;
- offset = addr - msix_io_addr;
+ offset = addr - (msix_io_addr + pba_offset);
+ if ((offset + len) > sizeof (vpci->msix_pba))
+ return;
+ memcpy(data, (void *)&vpci->msix_pba + offset, len);
+ return;
}
+
+ table = vpci->msix_table;
+ offset = addr - msix_io_addr;
+
vecnum = offset / sizeof(struct msix_table);
offset = offset % sizeof(struct msix_table);
@@ -520,7 +537,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
port_addr = pci_get_io_port_block(PCI_IO_SIZE);
mmio_addr = pci_get_mmio_block(PCI_IO_SIZE);
- msix_io_block = pci_get_mmio_block(PCI_IO_SIZE * 2);
+ msix_io_block = pci_get_mmio_block(VIRTIO_MSIX_BAR_SIZE);
vpci->pci_hdr = (struct pci_device_header) {
.vendor_id = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
@@ -543,7 +560,7 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
.capabilities = (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr,
.bar_size[0] = cpu_to_le32(PCI_IO_SIZE),
.bar_size[1] = cpu_to_le32(PCI_IO_SIZE),
- .bar_size[2] = cpu_to_le32(PCI_IO_SIZE*2),
+ .bar_size[2] = cpu_to_le32(VIRTIO_MSIX_BAR_SIZE),
};
r = pci__register_bar_regions(kvm, &vpci->pci_hdr,
@@ -560,8 +577,9 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
vpci->pci_hdr.msix.next = 0;
/*
- * We at most have VIRTIO_PCI_MAX_VQ entries for virt queue,
- * VIRTIO_PCI_MAX_CONFIG entries for config.
+ * We at most have VIRTIO_NR_MSIX entries (VIRTIO_PCI_MAX_VQ
+ * entries for virt queue, VIRTIO_PCI_MAX_CONFIG entries for
+ * config).
*
* To quote the PCI spec:
*
@@ -570,11 +588,11 @@ int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
* For example, a returned value of "00000000011"
* indicates a table size of 4.
*/
- vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG - 1);
+ vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_NR_MSIX - 1);
/* 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 | PCI_IO_SIZE);
+ vpci->pci_hdr.msix.pba_offset = cpu_to_le32(2 | VIRTIO_MSIX_TABLE_SIZE);
vpci->config_vector = 0;
if (irq__can_signal_msi(kvm))
--
2.30.2
next reply other threads:[~2021-08-27 11:54 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-27 11:54 Marc Zyngier [this message]
2021-08-31 11:10 ` [PATCH][kvmtool] virtio/pci: Size the MSI-X bar according to the number of MSI-X Andre Przywara
2021-08-31 11:28 ` Marc Zyngier
2021-08-31 11:39 ` Andre Przywara
2021-08-31 15:05 ` Will Deacon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210827115405.1981529-1-maz@kernel.org \
--to=maz@kernel.org \
--cc=alexandru.elisei@arm.com \
--cc=andre.przywara@arm.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).