qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH 4/4] nvdimm acpi: build flush hint address struc


From: Haozhong Zhang
Subject: [Qemu-devel] [RFC PATCH 4/4] nvdimm acpi: build flush hint address structure if required
Date: Fri, 31 Mar 2017 16:41:47 +0800

Add an boolean option 'flush-hint' to device 'nvdimm'. If it's on, a
flush hint address structure will be constructed for each nvdimm
device.

Signed-off-by: Haozhong Zhang <address@hidden>
---
 hw/acpi/nvdimm.c        | 106 +++++++++++++++++++++++++++++++++++++++++++++---
 hw/i386/pc.c            |   5 ++-
 hw/mem/nvdimm.c         |  26 ++++++++++++
 include/hw/mem/nvdimm.h |   2 +-
 4 files changed, 132 insertions(+), 7 deletions(-)

diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c
index ea2ac3e..a7ff0b2 100644
--- a/hw/acpi/nvdimm.c
+++ b/hw/acpi/nvdimm.c
@@ -32,6 +32,8 @@
 #include "hw/acpi/bios-linker-loader.h"
 #include "hw/nvram/fw_cfg.h"
 #include "hw/mem/nvdimm.h"
+#include "exec/address-spaces.h"
+#include "qapi/error.h"
 
 static int nvdimm_device_list(Object *obj, void *opaque)
 {
@@ -168,6 +170,22 @@ struct NvdimmNfitControlRegion {
 typedef struct NvdimmNfitControlRegion NvdimmNfitControlRegion;
 
 /*
+ * NVDIMM Flush Hint Address Structure
+ *
+ * It enables the data durability mechanism via ACPI.
+ */
+struct NvdimmNfitFlushHintAddress {
+    uint16_t type;
+    uint16_t length;
+    uint32_t nfit_handle;
+    uint16_t nr_flush_hint_addr;
+    uint8_t  reserved[6];
+#define NR_FLUSH_HINT_ADDR 1
+    uint64_t flush_hint_addr[NR_FLUSH_HINT_ADDR];
+} QEMU_PACKED;
+typedef struct NvdimmNfitFlushHintAddress NvdimmNfitFlushHintAddress;
+
+/*
  * Module serial number is a unique number for each device. We use the
  * slot id of NVDIMM device to generate this number so that each device
  * associates with a different number.
@@ -343,10 +361,79 @@ static void nvdimm_build_structure_dcr(GArray 
*structures, DeviceState *dev)
                                          (DSM) in DSM Spec Rev1.*/);
 }
 
-static GArray *nvdimm_build_device_structure(void)
+static uint64_t nvdimm_flush_hint_read(void *opaque, hwaddr addr, unsigned 
size)
+{
+    return 0;
+}
+
+static void nvdimm_flush_hint_write(void *opaque, hwaddr addr,
+                                    uint64_t data, unsigned size)
+{
+    nvdimm_debug("Write Flush Hint: offset 0x%"HWADDR_PRIx", data 
0x%"PRIx64"\n",
+                 addr, data);
+    nvdimm_flush((NVDIMMDevice *)opaque);
+}
+
+static const MemoryRegionOps nvdimm_flush_hint_ops = {
+    .read = nvdimm_flush_hint_read,
+    .write = nvdimm_flush_hint_write,
+};
+
+/*
+ * ACPI 6.0: 5.2.25.7 Flush Hint Address Structure
+ */
+static void nvdimm_build_structure_flush_hint(GArray *structures,
+                                              DeviceState *dev,
+                                              unsigned int cache_line_size,
+                                              Error **errp)
+{
+    NvdimmNfitFlushHintAddress *flush_hint;
+    int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, NULL);
+    PCDIMMDevice *dimm = PC_DIMM(dev);
+    NVDIMMDevice *nvdimm = NVDIMM(dev);
+    uint64_t addr;
+    unsigned int i;
+    MemoryRegion *mr;
+    Error *local_err = NULL;
+
+    if (!nvdimm->flush_hint_enabled) {
+        return;
+    }
+
+    if (cache_line_size * NR_FLUSH_HINT_ADDR > dimm->reserved_size) {
+        error_setg(&local_err,
+                   "insufficient reserved space for flush hint buffers");
+        goto out;
+    }
+
+    addr = object_property_get_int(OBJECT(dev), PC_DIMM_ADDR_PROP, NULL);
+    addr += object_property_get_int(OBJECT(dev), PC_DIMM_SIZE_PROP, NULL);
+
+    flush_hint = acpi_data_push(structures, sizeof(*flush_hint));
+    flush_hint->type = cpu_to_le16(6 /* Flush Hint Address Structure */);
+    flush_hint->length = cpu_to_le16(sizeof(*flush_hint));
+    flush_hint->nfit_handle = cpu_to_le32(nvdimm_slot_to_handle(slot));
+    flush_hint->nr_flush_hint_addr = cpu_to_le16(NR_FLUSH_HINT_ADDR);
+
+    for (i = 0; i < NR_FLUSH_HINT_ADDR; i++, addr += cache_line_size) {
+        flush_hint->flush_hint_addr[i] = cpu_to_le64(addr);
+
+        mr = g_new0(MemoryRegion, 1);
+        memory_region_init_io(mr, OBJECT(dev), &nvdimm_flush_hint_ops, nvdimm,
+                              "nvdimm-flush-hint", cache_line_size);
+        memory_region_add_subregion(get_system_memory(), addr, mr);
+    }
+
+ out:
+    error_propagate(errp, local_err);
+}
+
+static GArray *nvdimm_build_device_structure(AcpiNVDIMMState *state,
+                                             Error **errp)
 {
     GSList *device_list = nvdimm_get_device_list();
     GArray *structures = g_array_new(false, true /* clear */, 1);
+    Error *local_err = NULL;
 
     for (; device_list; device_list = device_list->next) {
         DeviceState *dev = device_list->data;
@@ -362,9 +449,17 @@ static GArray *nvdimm_build_device_structure(void)
 
         /* build NVDIMM Control Region Structure. */
         nvdimm_build_structure_dcr(structures, dev);
+
+        /* build Flush Hint Address Structure */
+        nvdimm_build_structure_flush_hint(structures, dev,
+                                          state->cache_line_size, &local_err);
+        if (local_err) {
+            break;
+        }
     }
     g_slist_free(device_list);
 
+    error_propagate(errp, local_err);
     return structures;
 }
 
@@ -373,16 +468,17 @@ static void nvdimm_init_fit_buffer(NvdimmFitBuffer 
*fit_buf)
     fit_buf->fit = g_array_new(false, true /* clear */, 1);
 }
 
-static void nvdimm_build_fit_buffer(NvdimmFitBuffer *fit_buf)
+static void nvdimm_build_fit_buffer(AcpiNVDIMMState *state, Error **errp)
 {
+    NvdimmFitBuffer *fit_buf = &state->fit_buf;
     g_array_free(fit_buf->fit, true);
-    fit_buf->fit = nvdimm_build_device_structure();
+    fit_buf->fit = nvdimm_build_device_structure(state, errp);
     fit_buf->dirty = true;
 }
 
-void nvdimm_plug(AcpiNVDIMMState *state)
+void nvdimm_plug(AcpiNVDIMMState *state, Error **errp)
 {
-    nvdimm_build_fit_buffer(&state->fit_buf);
+    nvdimm_build_fit_buffer(state, errp);
 }
 
 static void nvdimm_build_nfit(AcpiNVDIMMState *state, GArray *table_offsets,
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index d24388e..da4a5d7 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1718,7 +1718,10 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev,
                        "nvdimm is not enabled: missing 'nvdimm' in '-M'");
             goto out;
         }
-        nvdimm_plug(&pcms->acpi_nvdimm_state);
+        nvdimm_plug(&pcms->acpi_nvdimm_state, &local_err);
+        if (local_err) {
+            goto out;
+        }
     }
 
     hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c
index 484ab8b..a26908b 100644
--- a/hw/mem/nvdimm.c
+++ b/hw/mem/nvdimm.c
@@ -64,11 +64,37 @@ out:
     error_propagate(errp, local_err);
 }
 
+static bool nvdimm_get_flush_hint(Object *obj, Error **errp)
+{
+    NVDIMMDevice *nvdimm = NVDIMM(obj);
+
+    return nvdimm->flush_hint_enabled;
+}
+
+static void nvdimm_set_flush_hint(Object *obj, bool val, Error **errp)
+{
+    NVDIMMDevice *nvdimm = NVDIMM(obj);
+    Error *local_err = NULL;
+
+    if (nvdimm->flush_hint_enabled) {
+        error_setg(&local_err, "cannot change property value");
+        goto out;
+    }
+
+    nvdimm->flush_hint_enabled = val;
+
+ out:
+    error_propagate(errp, local_err);
+}
+
 static void nvdimm_init(Object *obj)
 {
     object_property_add(obj, "label-size", "int",
                         nvdimm_get_label_size, nvdimm_set_label_size, NULL,
                         NULL, NULL);
+    object_property_add_bool(obj, "flush-hint",
+                             nvdimm_get_flush_hint, nvdimm_set_flush_hint,
+                             NULL);
 }
 
 static MemoryRegion *nvdimm_get_memory_region(PCDIMMDevice *dimm)
diff --git a/include/hw/mem/nvdimm.h b/include/hw/mem/nvdimm.h
index 888def6..726f4d9 100644
--- a/include/hw/mem/nvdimm.h
+++ b/include/hw/mem/nvdimm.h
@@ -145,7 +145,7 @@ void nvdimm_init_acpi_state(AcpiNVDIMMState *state, 
MemoryRegion *io,
 void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data,
                        BIOSLinker *linker, AcpiNVDIMMState *state,
                        uint32_t ram_slots);
-void nvdimm_plug(AcpiNVDIMMState *state);
+void nvdimm_plug(AcpiNVDIMMState *state, Error **errp);
 void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev);
 void nvdimm_flush(NVDIMMDevice *nvdimm);
 #endif
-- 
2.10.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]