[PATCH] hw/nvme: allow to pass a memory backend object for the CMB

Wertenbroek Rick posted 1 patch 2 years ago
Failed in applying to current master (apply log)
There is a newer version of this series
hw/nvme/ctrl.c | 65 ++++++++++++++++++++++++++++++++++++++------------
hw/nvme/nvme.h |  9 +++----
2 files changed, 55 insertions(+), 19 deletions(-)
[PATCH] hw/nvme: allow to pass a memory backend object for the CMB
Posted by Wertenbroek Rick 2 years ago
Adds the optional -cmbdev= option that takes a QEMU memory backend
-object to be used to for the CMB (Controller Memory Buffer).
This option takes precedence over cmb_size_mb= if both used.
(The size will be deduced from the memory backend option).

Signed-off-by: Rick Wertenbroek <rick.wertenbroek@heig-vd.ch>
---
hw/nvme/ctrl.c | 65 ++++++++++++++++++++++++++++++++++++++------------
hw/nvme/nvme.h |  9 +++----
2 files changed, 55 insertions(+), 19 deletions(-)

diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 03760ddeae..9bcc7d6db0 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -29,6 +29,7 @@
 *      -device nvme-subsys,id=<subsys_id>,nqn=<nqn_id>
 *      -device nvme,serial=<serial>,id=<bus_name>, \
 *              cmb_size_mb=<cmb_size_mb[optional]>, \
+ *              [cmbdev=<mem_backend_id>,] \
 *              [pmrdev=<mem_backend_file_id>,] \
 *              max_ioqpairs=<N[optional]>, \
 *              aerl=<N[optional]>,aer_max_queued=<N[optional]>, \
@@ -44,6 +45,11 @@
 * offset 0 in BAR2 and supports only WDS, RDS and SQS for now. By default, the
 * device will use the "v1.4 CMB scheme" - use the `legacy-cmb` parameter to
 * always enable the CMBLOC and CMBSZ registers (v1.3 behavior).
+ * Enabling cmb emulation can also be achieved by pointing to a memory-backend
+ * For example:
+ * -object memory-backend-ram,id=<mem_id>,size=<size> \
+ * -device nvme,...,cmbdev=<mem_id>
+ * cmbdev= will take precedence over cmb_size_mb= when both provided.
 *
 * Enabling pmr emulation can be achieved by pointing to memory-backend-file.
 * For example:
@@ -341,16 +347,26 @@ static bool nvme_addr_is_cmb(NvmeCtrl *n, hwaddr addr)
        return false;
    }

-    lo = n->params.legacy_cmb ? n->cmb.mem.addr : n->cmb.cba;
-    hi = lo + int128_get64(n->cmb.mem.size);
+    if (n->cmb.dev) {
+        lo = n->params.legacy_cmb ? host_memory_backend_get_memory(n->cmb.dev)->addr : n->cmb.cba;
+        hi = lo + int128_get64(host_memory_backend_get_memory(n->cmb.dev)->size);
+    } else {
+        lo = n->params.legacy_cmb ? n->cmb.mem.addr : n->cmb.cba;
+        hi = lo + int128_get64(n->cmb.mem.size);
+    }

    return addr >= lo && addr < hi;
}

static inline void *nvme_addr_to_cmb(NvmeCtrl *n, hwaddr addr)
{
-    hwaddr base = n->params.legacy_cmb ? n->cmb.mem.addr : n->cmb.cba;
-    return &n->cmb.buf[addr - base];
+    if (n->cmb.dev) {
+        hwaddr base = n->params.legacy_cmb ? host_memory_backend_get_memory(n->cmb.dev)->addr : n->cmb.cba;
+        return memory_region_get_ram_ptr(&n->cmb.dev->mr) + (addr - base);
+    } else {
+        hwaddr base = n->params.legacy_cmb ? n->cmb.mem.addr : n->cmb.cba;
+        return &n->cmb.buf[addr - base];
+    }
}

static bool nvme_addr_is_pmr(NvmeCtrl *n, hwaddr addr)
@@ -6584,16 +6600,33 @@ static void nvme_init_state(NvmeCtrl *n)

static void nvme_init_cmb(NvmeCtrl *n, PCIDevice *pci_dev)
{
-    uint64_t cmb_size = n->params.cmb_size_mb * MiB;
+    uint64_t cmb_size;
    uint64_t cap = ldq_le_p(&n->bar.cap);

-    n->cmb.buf = g_malloc0(cmb_size);
-    memory_region_init_io(&n->cmb.mem, OBJECT(n), &nvme_cmb_ops, n,
-                          "nvme-cmb", cmb_size);
-    pci_register_bar(pci_dev, NVME_CMB_BIR,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY |
-                     PCI_BASE_ADDRESS_MEM_TYPE_64 |
-                     PCI_BASE_ADDRESS_MEM_PREFETCH, &n->cmb.mem);
+    if (n->cmb.dev) {
+        if (n->params.cmb_size_mb) {
+            warn_report("Option cmb_size_mb is ignored when a cmbdev is provided");
+        }
+        n->params.cmb_size_mb = n->cmb.dev->size / MiB;
+        cmb_size = n->cmb.dev->size;
+
+        MemoryRegion *mr = host_memory_backend_get_memory(n->cmb.dev);
+        assert(mr);
+
+        pci_register_bar(pci_dev, NVME_CMB_BIR,
+                         PCI_BASE_ADDRESS_SPACE_MEMORY |
+                         PCI_BASE_ADDRESS_MEM_TYPE_64 |
+                         PCI_BASE_ADDRESS_MEM_PREFETCH, mr);
+    } else {
+        cmb_size = n->params.cmb_size_mb * MiB;
+        n->cmb.buf = g_malloc0(cmb_size);
+        memory_region_init_io(&n->cmb.mem, OBJECT(n), &nvme_cmb_ops, n,
+                              "nvme-cmb", cmb_size);
+        pci_register_bar(pci_dev, NVME_CMB_BIR,
+                         PCI_BASE_ADDRESS_SPACE_MEMORY |
+                         PCI_BASE_ADDRESS_MEM_TYPE_64 |
+                         PCI_BASE_ADDRESS_MEM_PREFETCH, &n->cmb.mem);
+    }

    NVME_CAP_SET_CMBS(cap, 1);
    stq_le_p(&n->bar.cap, cap);
@@ -6678,7 +6711,7 @@ static int nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
        }
    }

-    if (n->params.cmb_size_mb) {
+    if (n->params.cmb_size_mb || n->cmb.dev) {
        nvme_init_cmb(n, pci_dev);
    }

@@ -6793,7 +6826,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
    NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_CSI_SUPP);
    NVME_CAP_SET_CSS(cap, NVME_CAP_CSS_ADMIN_ONLY);
    NVME_CAP_SET_MPSMAX(cap, 4);
-    NVME_CAP_SET_CMBS(cap, n->params.cmb_size_mb ? 1 : 0);
+    NVME_CAP_SET_CMBS(cap, (n->params.cmb_size_mb || n->cmb.dev) ? 1 : 0);
    NVME_CAP_SET_PMRS(cap, n->pmr.dev ? 1 : 0);
    stq_le_p(&n->bar.cap, cap);

@@ -6893,7 +6926,7 @@ static void nvme_exit(PCIDevice *pci_dev)
    g_free(n->sq);
    g_free(n->aer_reqs);

-    if (n->params.cmb_size_mb) {
+    if (!n->cmb.dev && n->params.cmb_size_mb) {
        g_free(n->cmb.buf);
    }

@@ -6908,6 +6941,8 @@ static Property nvme_props[] = {
    DEFINE_BLOCK_PROPERTIES(NvmeCtrl, namespace.blkconf),
    DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmr.dev, TYPE_MEMORY_BACKEND,
                     HostMemoryBackend *),
+    DEFINE_PROP_LINK("cmbdev", NvmeCtrl, cmb.dev, TYPE_MEMORY_BACKEND,
+                     HostMemoryBackend *),
    DEFINE_PROP_LINK("subsys", NvmeCtrl, subsys, TYPE_NVME_SUBSYS,
                     NvmeSubsystem *),
    DEFINE_PROP_STRING("serial", NvmeCtrl, params.serial),
diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h
index 739c8b8f79..63747cf967 100644
--- a/hw/nvme/nvme.h
+++ b/hw/nvme/nvme.h
@@ -434,10 +434,11 @@ typedef struct NvmeCtrl {
    uint8_t     smart_critical_warning;

    struct {
-        MemoryRegion mem;
-        uint8_t      *buf;
-        bool         cmse;
-        hwaddr       cba;
+        MemoryRegion      mem;
+        HostMemoryBackend *dev;
+        uint8_t           *buf;
+        bool              cmse;
+        hwaddr            cba;
    } cmb;

    struct {
-- 
2.24.3 (Apple Git-128)