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.wertenbr...@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)