Add qemu CLI support for EGM memory device model:
- Specify EGM device path to memory-backend-file object
- Support acpi-egm-memory object with id, pci-dev, and
  node attributes

Signed-off-by: Ian May <[email protected]>
Signed-off-by: Nathan Chen <[email protected]>
---
 src/qemu/qemu_alias.c          | 17 +++++++++
 src/qemu/qemu_capabilities.c   |  2 ++
 src/qemu/qemu_capabilities.h   |  1 +
 src/qemu/qemu_command.c        | 66 ++++++++++++++++++++++++++++++++--
 src/qemu/qemu_domain.c         | 13 ++++++-
 src/qemu/qemu_domain_address.c |  6 ++++
 src/qemu/qemu_driver.c         |  1 +
 src/qemu/qemu_hotplug.c        |  1 +
 src/qemu/qemu_monitor_json.c   |  1 +
 src/qemu/qemu_postparse.c      |  1 +
 src/qemu/qemu_process.c        |  2 ++
 src/qemu/qemu_validate.c       |  6 ++++
 12 files changed, 114 insertions(+), 3 deletions(-)

diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c
index b0bc057bd1..0e87968bf6 100644
--- a/src/qemu/qemu_alias.c
+++ b/src/qemu/qemu_alias.c
@@ -553,6 +553,23 @@ qemuAssignDeviceMemoryAlias(virDomainDef *def,
     case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
         prefix = "epc";
         break;
+    case VIR_DOMAIN_MEMORY_MODEL_EGM: {
+        const char *egm_devname = NULL;
+
+        if (mem->source.egm.path) {
+            egm_devname = strrchr(mem->source.egm.path, '/');
+            if (egm_devname)
+                egm_devname++;
+            else
+                egm_devname = mem->source.egm.path;
+
+            mem->info.alias = g_strdup(egm_devname);
+            return 0;
+        }
+
+        prefix = "egm";
+        break;
+    }
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
     default:
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 83946123be..1344519074 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -746,6 +746,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
 
               /* 485 */
               "acpi-generic-initiator", /* QEMU_CAPS_ACPI_GENERIC_INITIATOR */
+              "acpi-egm-memory", /* QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY */
     );
 
 
@@ -1440,6 +1441,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = {
     { "tpm-emulator", QEMU_CAPS_DEVICE_TPM_EMULATOR },
     { "tpm-passthrough", QEMU_CAPS_DEVICE_TPM_PASSTHROUGH },
     { "acpi-generic-initiator", QEMU_CAPS_ACPI_GENERIC_INITIATOR },
+    { "acpi-egm-memory", QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY },
 };
 
 
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 2b454e0352..61ffd7a8a8 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -727,6 +727,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for 
syntax-check */
 
     /* 485 */
     QEMU_CAPS_ACPI_GENERIC_INITIATOR, /* -object acpi-generic-initiator */
+    QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY, /* For using extended GPU memory */
 
     QEMU_CAPS_LAST /* this must always be the last item */
 } virQEMUCapsFlags;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index fcf5fc1935..d4e2fc8d7a 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -990,6 +990,7 @@ qemuBuildVirtioDevGetConfigDev(const virDomainDeviceDef 
*device,
             case VIR_DOMAIN_MEMORY_MODEL_DIMM:
             case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
             case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+            case VIR_DOMAIN_MEMORY_MODEL_EGM:
             case VIR_DOMAIN_MEMORY_MODEL_NONE:
             case VIR_DOMAIN_MEMORY_MODEL_LAST:
                 break;
@@ -3144,6 +3145,7 @@ qemuBuildMemoryGetPagesize(virQEMUDriverConfig *cfg,
         nvdimmPath = mem->source.virtio_pmem.path;
         break;
     case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+    case VIR_DOMAIN_MEMORY_MODEL_EGM:
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
         break;
@@ -3344,6 +3346,9 @@ qemuBuildMemoryBackendProps(virJSONValue **backendProps,
     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
         nvdimmPath = mem->source.virtio_pmem.path;
         break;
+    case VIR_DOMAIN_MEMORY_MODEL_EGM:
+        nvdimmPath = mem->source.egm.path;
+        break;
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
         break;
@@ -3559,6 +3564,7 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd,
 {
     g_autoptr(virJSONValue) props = NULL;
     g_autoptr(virJSONValue) tcProps = NULL;
+    g_autoptr(virJSONValue) egmProps = NULL;
     virBitmap *nodemask = NULL;
     g_autofree char *alias = NULL;
 
@@ -3584,6 +3590,33 @@ qemuBuildMemoryDimmBackendStr(virCommand *cmd,
     if (qemuBuildObjectCommandlineFromJSON(cmd, props) < 0)
         return -1;
 
+    if (mem->model == VIR_DOMAIN_MEMORY_MODEL_EGM) {
+        g_autofree char *egmId = NULL;
+        g_autofree char *egmObjStr = NULL;
+        g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+        const char *basename = NULL;
+
+        /* Extract basename from host path under /dev/ */
+        basename = strrchr(mem->source.egm.path, '/');
+        if (basename && *(basename + 1)) {
+            egmId = g_strdup(basename + 1);
+        } else {
+            egmId = g_strdup(mem->source.egm.path);
+        }
+
+        virBufferAsprintf(&buf, "acpi-egm-memory,id=%s", egmId);
+
+        if (mem->target.egm.pciDev)
+            virBufferAsprintf(&buf, ",pci-dev=%s", mem->target.egm.pciDev);
+
+        if (mem->targetNode >= 0)
+            virBufferAsprintf(&buf, ",node=%d", mem->targetNode);
+
+        egmObjStr = virBufferContentAndReset(&buf);
+
+        virCommandAddArgList(cmd, "-object", egmObjStr, NULL);
+    }
+
     return 0;
 }
 
@@ -3653,6 +3686,7 @@ qemuBuildMemoryDeviceProps(virQEMUDriverConfig *cfg,
         dynamicMemslots = mem->target.virtio_mem.dynamicMemslots;
         break;
 
+    case VIR_DOMAIN_MEMORY_MODEL_EGM:
     case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
@@ -7053,6 +7087,7 @@ qemuAppendDomainMemoryMachineParams(virBuffer *buf,
         case VIR_DOMAIN_MEMORY_MODEL_DIMM:
         case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
         case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
+        case VIR_DOMAIN_MEMORY_MODEL_EGM:
         case VIR_DOMAIN_MEMORY_MODEL_NONE:
         case VIR_DOMAIN_MEMORY_MODEL_LAST:
             break;
@@ -7781,6 +7816,13 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg,
         hmat = true;
     }
 
+    for (i = 0; i < def->nmems; i++) {
+        if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM) {
+            if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg, 
priv) < 0)
+                goto cleanup;
+        }
+    }
+
     nodeBackends = g_new0(virJSONValue *, ncells);
     nodemask = g_new0(virBitmap *, ncells);
 
@@ -7816,8 +7858,18 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg,
     for (i = 0; i < ncells; i++) {
         ssize_t initiator = virDomainNumaGetNodeInitiator(def->numa, i);
         unsigned long long memSize = virDomainNumaGetNodeMemorySize(def->numa, 
i);
+        bool egmBacked = false;
+        size_t k;
+
+        for (k = 0; k < def->nmems; k++) {
+            if (def->mems[k]->model == VIR_DOMAIN_MEMORY_MODEL_EGM &&
+                def->mems[k]->targetNode == (int)i) {
+                egmBacked = true;
+                break;
+            }
+        }
 
-        if (needBackend && memSize > 0) {
+        if (needBackend && memSize > 0 && !egmBacked) {
             g_autoptr(virJSONValue) tcProps = NULL;
 
             if (qemuBuildThreadContextProps(&tcProps, &nodeBackends[i],
@@ -7847,7 +7899,11 @@ qemuBuildNumaCommandLine(virQEMUDriverConfig *cfg,
 
         if (memSize > 0) {
             if (needBackend) {
-                virBufferAsprintf(&buf, ",memdev=ram-node%zu", i);
+                if (egmBacked) {
+                    virBufferAsprintf(&buf, ",memdev=mem%s", 
def->mems[k]->info.alias);
+                } else {
+                    virBufferAsprintf(&buf, ",memdev=ram-node%zu", i);
+                }
             } else {
                 virBufferAsprintf(&buf, ",mem=%llu", memSize / 1024);
             }
@@ -7911,6 +7967,9 @@ qemuBuildMemoryDeviceCommandLine(virCommand *cmd,
     for (i = 0; i < def->nmems; i++) {
         g_autoptr(virJSONValue) props = NULL;
 
+        if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_EGM)
+            continue;
+
         if (qemuBuildMemoryDimmBackendStr(cmd, def->mems[i], def, cfg, priv) < 
0)
             return -1;
 
@@ -7931,6 +7990,9 @@ qemuBuildMemoryDeviceCommandLine(virCommand *cmd,
         case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
             break;
 
+        /* EGM memory backing is via memory-backend-file object */
+        case VIR_DOMAIN_MEMORY_MODEL_EGM:
+            break;
         case VIR_DOMAIN_MEMORY_MODEL_NONE:
         case VIR_DOMAIN_MEMORY_MODEL_LAST:
             break;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 375e0e441a..75095b4de8 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -7220,6 +7220,7 @@ qemuDomainUpdateMemoryDeviceInfo(virDomainObj *vm,
             break;
 
         case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+        case VIR_DOMAIN_MEMORY_MODEL_EGM:
         case VIR_DOMAIN_MEMORY_MODEL_NONE:
         case VIR_DOMAIN_MEMORY_MODEL_LAST:
             break;
@@ -7454,7 +7455,8 @@ qemuDomainAlignMemorySizes(virDomainDef *def)
             def->mems[i]->size = VIR_ROUND_UP(def->mems[i]->size, align);
         }
 
-        hotplugmem += def->mems[i]->size;
+        if (def->mems[i]->model != VIR_DOMAIN_MEMORY_MODEL_EGM)
+            hotplugmem += def->mems[i]->size;
 
         if (def->mems[i]->size > maxmemkb) {
             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -7942,6 +7944,12 @@ qemuDomainDefValidateMemoryHotplugDevice(const 
virDomainMemoryDef *mem,
                        virDomainMemoryModelTypeToString(mem->model));
             return -1;
 
+    case VIR_DOMAIN_MEMORY_MODEL_EGM:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("hotplug is not supported for the %1$s device"),
+                       virDomainMemoryModelTypeToString(mem->model));
+            return -1;
+
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
         return -1;
@@ -8000,6 +8008,7 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef 
*def,
         case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
         case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
         case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+        case VIR_DOMAIN_MEMORY_MODEL_EGM:
         case VIR_DOMAIN_MEMORY_MODEL_LAST:
         case VIR_DOMAIN_MEMORY_MODEL_NONE:
             break;
@@ -8047,6 +8056,8 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef 
*def,
 
         case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
             /* sgx epc memory does not support hotplug, skip this check */
+        case VIR_DOMAIN_MEMORY_MODEL_EGM:
+            /* egm memory does not support hotplug, skip this check */
         case VIR_DOMAIN_MEMORY_MODEL_LAST:
         case VIR_DOMAIN_MEMORY_MODEL_NONE:
             break;
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 774541ca06..0d9f2b5649 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -303,6 +303,7 @@ qemuDomainPrimeVirtioDeviceAddresses(virDomainDef *def,
         case VIR_DOMAIN_MEMORY_MODEL_DIMM:
         case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
         case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+        case VIR_DOMAIN_MEMORY_MODEL_EGM:
         case VIR_DOMAIN_MEMORY_MODEL_LAST:
             break;
         }
@@ -1033,6 +1034,7 @@ 
qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDef *dev,
         case VIR_DOMAIN_MEMORY_MODEL_DIMM:
         case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
         case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+        case VIR_DOMAIN_MEMORY_MODEL_EGM:
         case VIR_DOMAIN_MEMORY_MODEL_LAST:
             return 0;
         }
@@ -2455,6 +2457,7 @@ qemuDomainAssignDevicePCISlots(virDomainDef *def,
         case VIR_DOMAIN_MEMORY_MODEL_DIMM:
         case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
         case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+        case VIR_DOMAIN_MEMORY_MODEL_EGM:
         case VIR_DOMAIN_MEMORY_MODEL_LAST:
             break;
         }
@@ -3151,6 +3154,7 @@ qemuDomainAssignMemoryDeviceSlot(virDomainObj *vm,
         return qemuDomainEnsureVirtioAddress(&releaseaddr, vm, &dev);
 
     case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+    case VIR_DOMAIN_MEMORY_MODEL_EGM:
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
         break;
@@ -3178,6 +3182,7 @@ qemuDomainReleaseMemoryDeviceSlot(virDomainObj *vm,
         break;
 
     case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+    case VIR_DOMAIN_MEMORY_MODEL_EGM:
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
         break;
@@ -3212,6 +3217,7 @@ qemuDomainAssignMemorySlots(virDomainDef *def)
             /* handled in qemuDomainAssignPCIAddresses() */
             break;
         case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+        case VIR_DOMAIN_MEMORY_MODEL_EGM:
         case VIR_DOMAIN_MEMORY_MODEL_NONE:
         case VIR_DOMAIN_MEMORY_MODEL_LAST:
             break;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b0eff443aa..9d17c159e4 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6704,6 +6704,7 @@ qemuDomainAttachMemoryConfig(virDomainDef *vmdef,
     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
     case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+    case VIR_DOMAIN_MEMORY_MODEL_EGM:
         break;
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index fb426deb1a..890bb052b6 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -7348,6 +7348,7 @@ qemuDomainChangeMemoryLiveValidateChange(const 
virDomainMemoryDef *oldDef,
     case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
     case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+    case VIR_DOMAIN_MEMORY_MODEL_EGM:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("cannot modify memory of model '%1$s'"),
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index c121c05ffd..2c2273d927 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -7088,6 +7088,7 @@ qemuMonitorJSONGetMemoryDeviceInfo(qemuMonitor *mon,
         switch ((virDomainMemoryModel) model) {
         case VIR_DOMAIN_MEMORY_MODEL_DIMM:
         case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
+        case VIR_DOMAIN_MEMORY_MODEL_EGM:
         case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
         case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
             /* While 'id' attribute is marked as optional in QEMU's QAPI
diff --git a/src/qemu/qemu_postparse.c b/src/qemu/qemu_postparse.c
index fd27f8be27..b23dd94d2c 100644
--- a/src/qemu/qemu_postparse.c
+++ b/src/qemu/qemu_postparse.c
@@ -1838,6 +1838,7 @@ qemuDomainDefNumaAutoAdd(virDomainDef *def,
         case VIR_DOMAIN_MEMORY_MODEL_NONE:
         case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
         case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+        case VIR_DOMAIN_MEMORY_MODEL_EGM:
         case VIR_DOMAIN_MEMORY_MODEL_LAST:
             break;
         }
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 9926998f85..e41767a70f 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4066,6 +4066,7 @@ qemuProcessDomainMemoryDefNeedHugepagesPath(const 
virDomainMemoryDef *mem,
     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
         pagesize = mem->source.virtio_mem.pagesize;
         break;
+    case VIR_DOMAIN_MEMORY_MODEL_EGM:
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
@@ -4155,6 +4156,7 @@ qemuProcessNeedMemoryBackingPath(virDomainDef *def,
         case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
         case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
         case VIR_DOMAIN_MEMORY_MODEL_SGX_EPC:
+        case VIR_DOMAIN_MEMORY_MODEL_EGM:
         case VIR_DOMAIN_MEMORY_MODEL_LAST:
             /* Backed by user provided path. Not stored in memory
              * backing dir anyway. */
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index 3e8fdb2268..e8d6fe21cb 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -5812,6 +5812,12 @@ qemuValidateDomainDeviceDefMemory(const 
virDomainMemoryDef *mem,
 
         break;
 
+    case VIR_DOMAIN_MEMORY_MODEL_EGM:
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ACPI_EGM_MEMORY)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                          _("ACPI EGM memory device is not supported with this 
QEMU binary"));
+            return -1;
+        }
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
         break;
-- 
2.43.0

Reply via email to