Blame SOURCES/kvm-virtio-pci-Replace-modern_as-with-direct-access-to-m.patch

4a2fec
From ff5e61b600d9a130faad32ceda3cd212dcb387d4 Mon Sep 17 00:00:00 2001
4a2fec
From: David Gibson <dgibson@redhat.com>
4a2fec
Date: Thu, 16 Nov 2017 03:07:11 +0100
4a2fec
Subject: [PATCH 07/30] virtio-pci: Replace modern_as with direct access to
4a2fec
 modern_bar
4a2fec
4a2fec
RH-Author: David Gibson <dgibson@redhat.com>
4a2fec
Message-id: <20171116030732.8560-2-dgibson@redhat.com>
4a2fec
Patchwork-id: 77689
4a2fec
O-Subject: [PATCH 01/22] virtio-pci: Replace modern_as with direct access to modern_bar
4a2fec
Bugzilla: 1481593
4a2fec
RH-Acked-by: Thomas Huth <thuth@redhat.com>
4a2fec
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
4a2fec
RH-Acked-by: Eduardo Habkost <ehabkost@redhat.com>
4a2fec
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
4a2fec
4a2fec
From: Alexey Kardashevskiy <aik@ozlabs.ru>
4a2fec
4a2fec
The modern bar is accessed now via yet another address space created just
4a2fec
for that purpose and it does not really need FlatView and dispatch tree
4a2fec
as it has a single memory region so it is just a waste of memory. Things
4a2fec
get even worse when there are dozens or hundreds of virtio-pci devices -
4a2fec
since these address spaces are global, changing any of them triggers
4a2fec
rebuilding all address spaces.
4a2fec
4a2fec
This replaces indirect accesses to the modern BAR with a simple lookup
4a2fec
and direct calls to memory_region_dispatch_read/write.
4a2fec
4a2fec
This is expected to save lots of memory at boot time after applying:
4a2fec
[Qemu-devel] [PULL 00/32] Misc changes for 2017-09-22
4a2fec
4a2fec
Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
4a2fec
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
4a2fec
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
4a2fec
(cherry picked from commit a93c8d828af186d9a6a1c915a1be8ba22fb89849)
4a2fec
4a2fec
Signed-off-by: David Gibson <dgibson@redhat.com>
4a2fec
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
---
4a2fec
 hw/virtio/virtio-pci.c | 75 +++++++++++++++++++++++++++++---------------------
4a2fec
 hw/virtio/virtio-pci.h | 17 +++++++-----
4a2fec
 2 files changed, 54 insertions(+), 38 deletions(-)
4a2fec
4a2fec
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
4a2fec
index 6e497c8..4b041bb 100644
4a2fec
--- a/hw/virtio/virtio-pci.c
4a2fec
+++ b/hw/virtio/virtio-pci.c
4a2fec
@@ -545,6 +545,24 @@ static const MemoryRegionOps virtio_pci_config_ops = {
4a2fec
     .endianness = DEVICE_LITTLE_ENDIAN,
4a2fec
 };
4a2fec
 
4a2fec
+static MemoryRegion *virtio_address_space_lookup(VirtIOPCIProxy *proxy,
4a2fec
+                                                 hwaddr *off, int len)
4a2fec
+{
4a2fec
+    int i;
4a2fec
+    VirtIOPCIRegion *reg;
4a2fec
+
4a2fec
+    for (i = 0; i < ARRAY_SIZE(proxy->regs); ++i) {
4a2fec
+        reg = &proxy->regs[i];
4a2fec
+        if (*off >= reg->offset &&
4a2fec
+            *off + len <= reg->offset + reg->size) {
4a2fec
+            *off -= reg->offset;
4a2fec
+            return &reg->mr;
4a2fec
+        }
4a2fec
+    }
4a2fec
+
4a2fec
+    return NULL;
4a2fec
+}
4a2fec
+
4a2fec
 /* Below are generic functions to do memcpy from/to an address space,
4a2fec
  * without byteswaps, with input validation.
4a2fec
  *
4a2fec
@@ -558,63 +576,72 @@ static const MemoryRegionOps virtio_pci_config_ops = {
4a2fec
  * Note: host pointer must be aligned.
4a2fec
  */
4a2fec
 static
4a2fec
-void virtio_address_space_write(AddressSpace *as, hwaddr addr,
4a2fec
+void virtio_address_space_write(VirtIOPCIProxy *proxy, hwaddr addr,
4a2fec
                                 const uint8_t *buf, int len)
4a2fec
 {
4a2fec
-    uint32_t val;
4a2fec
+    uint64_t val;
4a2fec
+    MemoryRegion *mr;
4a2fec
 
4a2fec
     /* address_space_* APIs assume an aligned address.
4a2fec
      * As address is under guest control, handle illegal values.
4a2fec
      */
4a2fec
     addr &= ~(len - 1);
4a2fec
 
4a2fec
+    mr = virtio_address_space_lookup(proxy, &addr, len);
4a2fec
+    if (!mr) {
4a2fec
+        return;
4a2fec
+    }
4a2fec
+
4a2fec
     /* Make sure caller aligned buf properly */
4a2fec
     assert(!(((uintptr_t)buf) & (len - 1)));
4a2fec
 
4a2fec
     switch (len) {
4a2fec
     case 1:
4a2fec
         val = pci_get_byte(buf);
4a2fec
-        address_space_stb(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
4a2fec
         break;
4a2fec
     case 2:
4a2fec
-        val = pci_get_word(buf);
4a2fec
-        address_space_stw_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
4a2fec
+        val = cpu_to_le16(pci_get_word(buf));
4a2fec
         break;
4a2fec
     case 4:
4a2fec
-        val = pci_get_long(buf);
4a2fec
-        address_space_stl_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
4a2fec
+        val = cpu_to_le32(pci_get_long(buf));
4a2fec
         break;
4a2fec
     default:
4a2fec
         /* As length is under guest control, handle illegal values. */
4a2fec
-        break;
4a2fec
+        return;
4a2fec
     }
4a2fec
+    memory_region_dispatch_write(mr, addr, val, len, MEMTXATTRS_UNSPECIFIED);
4a2fec
 }
4a2fec
 
4a2fec
 static void
4a2fec
-virtio_address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len)
4a2fec
+virtio_address_space_read(VirtIOPCIProxy *proxy, hwaddr addr,
4a2fec
+                          uint8_t *buf, int len)
4a2fec
 {
4a2fec
-    uint32_t val;
4a2fec
+    uint64_t val;
4a2fec
+    MemoryRegion *mr;
4a2fec
 
4a2fec
     /* address_space_* APIs assume an aligned address.
4a2fec
      * As address is under guest control, handle illegal values.
4a2fec
      */
4a2fec
     addr &= ~(len - 1);
4a2fec
 
4a2fec
+    mr = virtio_address_space_lookup(proxy, &addr, len);
4a2fec
+    if (!mr) {
4a2fec
+        return;
4a2fec
+    }
4a2fec
+
4a2fec
     /* Make sure caller aligned buf properly */
4a2fec
     assert(!(((uintptr_t)buf) & (len - 1)));
4a2fec
 
4a2fec
+    memory_region_dispatch_read(mr, addr, &val, len, MEMTXATTRS_UNSPECIFIED);
4a2fec
     switch (len) {
4a2fec
     case 1:
4a2fec
-        val = address_space_ldub(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
4a2fec
         pci_set_byte(buf, val);
4a2fec
         break;
4a2fec
     case 2:
4a2fec
-        val = address_space_lduw_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
4a2fec
-        pci_set_word(buf, val);
4a2fec
+        pci_set_word(buf, le16_to_cpu(val));
4a2fec
         break;
4a2fec
     case 4:
4a2fec
-        val = address_space_ldl_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
4a2fec
-        pci_set_long(buf, val);
4a2fec
+        pci_set_long(buf, le32_to_cpu(val));
4a2fec
         break;
4a2fec
     default:
4a2fec
         /* As length is under guest control, handle illegal values. */
4a2fec
@@ -650,8 +677,7 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
4a2fec
 
4a2fec
         if (len == 1 || len == 2 || len == 4) {
4a2fec
             assert(len <= sizeof cfg->pci_cfg_data);
4a2fec
-            virtio_address_space_write(&proxy->modern_as, off,
4a2fec
-                                       cfg->pci_cfg_data, len);
4a2fec
+            virtio_address_space_write(proxy, off, cfg->pci_cfg_data, len);
4a2fec
         }
4a2fec
     }
4a2fec
 }
4a2fec
@@ -675,8 +701,7 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev,
4a2fec
 
4a2fec
         if (len == 1 || len == 2 || len == 4) {
4a2fec
             assert(len <= sizeof cfg->pci_cfg_data);
4a2fec
-            virtio_address_space_read(&proxy->modern_as, off,
4a2fec
-                                      cfg->pci_cfg_data, len);
4a2fec
+            virtio_address_space_read(proxy, off, cfg->pci_cfg_data, len);
4a2fec
         }
4a2fec
     }
4a2fec
 
4a2fec
@@ -1783,15 +1808,6 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
4a2fec
                        /* PCI BAR regions must be powers of 2 */
4a2fec
                        pow2ceil(proxy->notify.offset + proxy->notify.size));
4a2fec
 
4a2fec
-    memory_region_init_alias(&proxy->modern_cfg,
4a2fec
-                             OBJECT(proxy),
4a2fec
-                             "virtio-pci-cfg",
4a2fec
-                             &proxy->modern_bar,
4a2fec
-                             0,
4a2fec
-                             memory_region_size(&proxy->modern_bar));
4a2fec
-
4a2fec
-    address_space_init(&proxy->modern_as, &proxy->modern_cfg, "virtio-pci-cfg-as");
4a2fec
-
4a2fec
     if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) {
4a2fec
         proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
4a2fec
     }
4a2fec
@@ -1860,10 +1876,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
4a2fec
 
4a2fec
 static void virtio_pci_exit(PCIDevice *pci_dev)
4a2fec
 {
4a2fec
-    VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
4a2fec
-
4a2fec
     msix_uninit_exclusive_bar(pci_dev);
4a2fec
-    address_space_destroy(&proxy->modern_as);
4a2fec
 }
4a2fec
 
4a2fec
 static void virtio_pci_reset(DeviceState *qdev)
4a2fec
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
4a2fec
index 69f5959..12d3a90 100644
4a2fec
--- a/hw/virtio/virtio-pci.h
4a2fec
+++ b/hw/virtio/virtio-pci.h
4a2fec
@@ -155,15 +155,18 @@ typedef struct VirtIOPCIQueue {
4a2fec
 struct VirtIOPCIProxy {
4a2fec
     PCIDevice pci_dev;
4a2fec
     MemoryRegion bar;
4a2fec
-    VirtIOPCIRegion common;
4a2fec
-    VirtIOPCIRegion isr;
4a2fec
-    VirtIOPCIRegion device;
4a2fec
-    VirtIOPCIRegion notify;
4a2fec
-    VirtIOPCIRegion notify_pio;
4a2fec
+    union {
4a2fec
+        struct {
4a2fec
+            VirtIOPCIRegion common;
4a2fec
+            VirtIOPCIRegion isr;
4a2fec
+            VirtIOPCIRegion device;
4a2fec
+            VirtIOPCIRegion notify;
4a2fec
+            VirtIOPCIRegion notify_pio;
4a2fec
+        };
4a2fec
+        VirtIOPCIRegion regs[5];
4a2fec
+    };
4a2fec
     MemoryRegion modern_bar;
4a2fec
     MemoryRegion io_bar;
4a2fec
-    MemoryRegion modern_cfg;
4a2fec
-    AddressSpace modern_as;
4a2fec
     uint32_t legacy_io_bar_idx;
4a2fec
     uint32_t msix_bar_idx;
4a2fec
     uint32_t modern_io_bar_idx;
4a2fec
-- 
4a2fec
1.8.3.1
4a2fec