All of lore.kernel.org
 help / color / mirror / Atom feed
From: Xiao Guangrong <guangrong.xiao@linux.intel.com>
To: pbonzini@redhat.com, imammedo@redhat.com
Cc: gleb@kernel.org, mtosatti@redhat.com, stefanha@redhat.com,
	mst@redhat.com, rth@twiddle.net, ehabkost@redhat.com,
	kvm@vger.kernel.org, qemu-devel@nongnu.org,
	Xiao Guangrong <guangrong.xiao@linux.intel.com>
Subject: [PATCH v2 13/18] nvdimm: build namespace config data
Date: Fri, 14 Aug 2015 22:52:06 +0800	[thread overview]
Message-ID: <1439563931-12352-14-git-send-email-guangrong.xiao@linux.intel.com> (raw)
In-Reply-To: <1439563931-12352-1-git-send-email-guangrong.xiao@linux.intel.com>

If @configdata is false, Qemu will build a static and readonly
namespace in memory and use it serveing for
DSM GET_CONFIG_SIZE/GET_CONFIG_DATA requests

Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
 hw/mem/Makefile.objs       |   3 +-
 hw/mem/nvdimm/acpi.c       |  10 ++
 hw/mem/nvdimm/internal.h   |  12 ++
 hw/mem/nvdimm/namespace.c  | 307 +++++++++++++++++++++++++++++++++++++++++++++
 include/hw/mem/pc-nvdimm.h |   2 +
 5 files changed, 333 insertions(+), 1 deletion(-)
 create mode 100644 hw/mem/nvdimm/namespace.c

diff --git a/hw/mem/Makefile.objs b/hw/mem/Makefile.objs
index 7a6948d..7f3fab2 100644
--- a/hw/mem/Makefile.objs
+++ b/hw/mem/Makefile.objs
@@ -1,2 +1,3 @@
 common-obj-$(CONFIG_MEM_HOTPLUG) += pc-dimm.o
-common-obj-$(CONFIG_NVDIMM) += nvdimm/pc-nvdimm.o nvdimm/acpi.o
+common-obj-$(CONFIG_NVDIMM) += nvdimm/pc-nvdimm.o nvdimm/acpi.o	\
+			       nvdimm/namespace.o
diff --git a/hw/mem/nvdimm/acpi.c b/hw/mem/nvdimm/acpi.c
index 0b09efa..c773954 100644
--- a/hw/mem/nvdimm/acpi.c
+++ b/hw/mem/nvdimm/acpi.c
@@ -240,6 +240,8 @@ static void build_nfit_table(GSList *device_list, char *buf)
 
     for (; device_list; device_list = device_list->next) {
         PCNVDIMMDevice *nvdimm = device_list->data;
+        struct nfit_memdev *nfit_memdev;
+        struct nfit_dcr *nfit_dcr;
         int spa_index, dcr_index;
 
         spa_index = ++index;
@@ -252,10 +254,15 @@ static void build_nfit_table(GSList *device_list, char *buf)
          * build Memory Device to System Physical Address Range Mapping
          * Table.
          */
+        nfit_memdev = (struct nfit_memdev *)buf;
         buf += build_memdev_table(buf, nvdimm, spa_index, dcr_index);
 
         /* build Control Region Descriptor Table. */
+        nfit_dcr = (struct nfit_dcr *)buf;
         buf += build_dcr_table(buf, nvdimm, dcr_index);
+
+        calculate_nvdimm_isetcookie(nvdimm, nfit_memdev->region_spa_offset,
+                                    nfit_dcr->serial_number);
     }
 }
 
@@ -382,6 +389,9 @@ void pc_nvdimm_build_nfit_table(GArray *table_offsets, GArray *table_data,
 
     build_header(linker, table_data, (void *)(table_data->data + nfit_start),
                  "NFIT", table_data->len - nfit_start, 1);
+
+    build_nvdimm_configdata(list);
+
 exit:
     g_slist_free(list);
 }
diff --git a/hw/mem/nvdimm/internal.h b/hw/mem/nvdimm/internal.h
index 90d54dc..b1f3f16 100644
--- a/hw/mem/nvdimm/internal.h
+++ b/hw/mem/nvdimm/internal.h
@@ -13,6 +13,14 @@
 #ifndef __NVDIMM_INTERNAL_H
 #define __NVDIMM_INTERNAL_H
 
+/* #define NVDIMM_DEBUG */
+
+#ifdef NVDIMM_DEBUG
+#define nvdebug(fmt, ...) fprintf(stderr, "nvdimm: " fmt, ## __VA_ARGS__)
+#else
+#define nvdebug(...)
+#endif
+
 #define PAGE_SIZE               (1UL << 12)
 
 typedef struct {
@@ -27,4 +35,8 @@ typedef struct {
 
 GSList *get_nvdimm_built_list(void);
 ram_addr_t reserved_range_push(uint64_t size);
+
+void calculate_nvdimm_isetcookie(PCNVDIMMDevice *nvdimm, uint64_t spa,
+                                 uint32_t sn);
+void build_nvdimm_configdata(GSList *device_list);
 #endif
diff --git a/hw/mem/nvdimm/namespace.c b/hw/mem/nvdimm/namespace.c
new file mode 100644
index 0000000..04626da
--- /dev/null
+++ b/hw/mem/nvdimm/namespace.c
@@ -0,0 +1,307 @@
+/*
+ * NVDIMM  Namespace Support
+ *
+ * Copyright(C) 2015 Intel Corporation.
+ *
+ * Author:
+ *  Xiao Guangrong <guangrong.xiao@linux.intel.com>
+ *
+ * NVDIMM namespace specification can be found at:
+ *      http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "hw/mem/pc-nvdimm.h"
+
+#include "internal.h"
+
+static uint64_t fletcher64(void *addr, size_t len)
+{
+    uint32_t *buf = addr;
+    uint32_t lo32 = 0;
+    uint64_t hi32 = 0;
+    int i;
+
+    for (i = 0; i < len / sizeof(uint32_t); i++) {
+        lo32 += cpu_to_le32(buf[i]);
+        hi32 += lo32;
+    }
+
+    return hi32 << 32 | lo32;
+}
+
+struct interleave_set_info {
+    struct interleave_set_info_map {
+        uint64_t region_spa_offset;
+        uint32_t serial_number;
+        uint32_t zero;
+    } mapping[1];
+};
+
+void calculate_nvdimm_isetcookie(PCNVDIMMDevice *nvdimm, uint64_t spa,
+                                 uint32_t sn)
+{
+    struct interleave_set_info info;
+
+    info.mapping[0].region_spa_offset = spa;
+    info.mapping[0].serial_number = sn;
+    info.mapping[0].zero = 0;
+
+    nvdimm->isetcookie = fletcher64(&info, sizeof(info));
+}
+
+#define NSINDEX_SIGNATURE      "NAMESPACE_INDEX\0"
+
+enum {
+    NSINDEX_SIG_LEN = 16,
+    NSINDEX_ALIGN = 256,
+    NSINDEX_SEQ_MASK = 0x3,
+    NSINDEX_MAJOR = 0x1,
+    NSINDEX_MINOR = 0x1,
+
+    NSLABEL_UUID_LEN = 16,
+    NSLABEL_NAME_LEN = 64,
+    NSLABEL_FLAG_ROLABEL = 0x1,  /* read-only label */
+    NSLABEL_FLAG_LOCAL = 0x2,    /* DIMM-local namespace */
+    NSLABEL_FLAG_BTT = 0x4,      /* namespace contains a BTT */
+    NSLABEL_FLAG_UPDATING = 0x8, /* label being updated */
+};
+
+/*
+ * struct nd_namespace_index - label set superblock
+ * @sig: NAMESPACE_INDEX\0
+ * @flags: placeholder
+ * @seq: sequence number for this index
+ * @myoff: offset of this index in label area
+ * @mysize: size of this index struct
+ * @otheroff: offset of other index
+ * @labeloff: offset of first label slot
+ * @nslot: total number of label slots
+ * @major: label area major version
+ * @minor: label area minor version
+ * @checksum: fletcher64 of all fields
+ * @free[0]: bitmap, nlabel bits
+ *
+ * The size of free[] is rounded up so the total struct size is a
+ * multiple of NSINDEX_ALIGN bytes.  Any bits this allocates beyond
+ * nlabel bits must be zero.
+ */
+struct namespace_label_index_block {
+    uint8_t sig[NSINDEX_SIG_LEN];
+    uint32_t flags;
+    uint32_t seq;
+    uint64_t myoff;
+    uint64_t mysize;
+    uint64_t otheroff;
+    uint64_t labeloff;
+    uint32_t nlabel;
+    uint16_t major;
+    uint16_t minor;
+    uint64_t checksum;
+    uint8_t free[0];
+} QEMU_PACKED;
+
+/*
+ * struct nd_namespace_label - namespace superblock
+ * @uuid: UUID per RFC 4122
+ * @name: optional name (NULL-terminated)
+ * @flags: see NSLABEL_FLAG_*
+ * @nlabel: num labels to describe this ns
+ * @position: labels position in set
+ * @isetcookie: interleave set cookie
+ * @lbasize: LBA size in bytes or 0 for pmem
+ * @dpa: DPA of NVM range on this DIMM
+ * @rawsize: size of namespace
+ * @slot: slot of this label in label area
+ * @unused: must be zero
+ */
+struct namespace_label {
+    uint8_t uuid[NSLABEL_UUID_LEN];
+    uint8_t name[NSLABEL_NAME_LEN];
+    uint32_t flags;
+    uint16_t nlabel;
+    uint16_t position;
+    uint64_t isetcookie;
+    uint64_t lbasize;
+    uint64_t dpa;
+    uint64_t rawsize;
+    uint32_t slot;
+    uint32_t unused;
+} QEMU_PACKED;
+
+/*calculate the number of label can be contained in whole config space. */
+static int config_space_max_label_nr(PCNVDIMMDevice *nvdimm, size_t block_size)
+{
+    /* totally we have 2 namespace label index block. */
+    if (block_size * 2 >= nvdimm->config_data_size) {
+        return 0;
+    }
+
+    return (nvdimm->config_data_size - block_size * 2) /
+            sizeof(struct namespace_label);
+}
+
+/*calculate the number of label can be contained in index block. */
+static int label_index_block_max_label_nr(size_t block_size)
+{
+    int free_size;
+
+    free_size = block_size - sizeof(struct namespace_label_index_block);
+
+    return free_size * BITS_PER_BYTE;
+}
+
+static int calculate_max_label_nr(PCNVDIMMDevice *nvdimm, size_t block_size)
+{
+    return MIN(label_index_block_max_label_nr(block_size),
+        config_space_max_label_nr(nvdimm, block_size));
+}
+
+/*
+ * check if we can increase the size of namespace_label_index_block to
+ * contain more labels.
+ */
+static bool can_increase_index_block(PCNVDIMMDevice *nvdimm,
+                                     size_t block_size, int label_nr)
+{
+    size_t remaining;
+
+    remaining = nvdimm->config_data_size - block_size * 2 -
+                label_nr * sizeof(struct namespace_label);
+
+    assert((int64_t)remaining >= 0);
+
+    /* can contain 1 label at least. */
+    return remaining >=  NSINDEX_ALIGN * 2 + sizeof(struct namespace_label);
+}
+
+static void count_label_nr(PCNVDIMMDevice *nvdimm, size_t *label_block_size,
+                           int *label_nr)
+{
+    *label_block_size = 0;
+
+    do {
+        /*
+          * The minimum size of an index block is 256 bytes and the size must
+          * be a multiple of 256 bytes.
+          */
+        *label_block_size += NSINDEX_ALIGN;
+
+        *label_nr = calculate_max_label_nr(nvdimm, *label_block_size);
+    } while (can_increase_index_block(nvdimm, *label_block_size, *label_nr));
+}
+
+static void namespace_label_uuid(PCNVDIMMDevice *nvdimm, void *uuid)
+{
+    uuid_le label_uuid_init = UUID_LE(0x137e67a9, 0x7dcb, 0x4c66, 0xb2,
+                                      0xe6, 0x05, 0x06, 0x5b, 0xeb,
+                                      0x6a, 0x00);
+
+    assert(nvdimm->device_index <= 0xff);
+
+    label_uuid_init.b[0] += nvdimm->device_index;
+    memcpy(uuid, &label_uuid_init, sizeof(label_uuid_init));
+}
+
+static void init_namespace(PCNVDIMMDevice *nvdimm)
+{
+    struct namespace_label_index_block *index1, *index2;
+    struct namespace_label *label;
+    int i;
+
+    size_t label_block_size;
+    int label_nr;
+
+    assert(!nvdimm->configdata);
+
+    count_label_nr(nvdimm, &label_block_size, &label_nr);
+    nvdebug("nvdimm%d: label_block_size 0x%lx label_nr %d.\n",
+            nvdimm->device_index, label_block_size, label_nr);
+
+    index1 = nvdimm->config_data_addr;
+
+    /*
+     * init the first namespace label index block, except @otheroff
+     * and @checksum. we will do it later.
+     */
+    memcpy(index1->sig, NSINDEX_SIGNATURE, sizeof(NSINDEX_SIGNATURE));
+    index1->flags = cpu_to_le32(0);
+    index1->seq = cpu_to_le32(0x1);
+    index1->myoff = cpu_to_le64(0);
+    index1->mysize = cpu_to_le64(label_block_size);
+    index1->labeloff = cpu_to_le64(label_block_size * 2);
+    index1->nlabel = cpu_to_le32(label_nr);
+    index1->major = cpu_to_le16(NSINDEX_MAJOR);
+    index1->minor = cpu_to_le16(NSINDEX_MINOR);
+    index1->checksum = cpu_to_le64(0);
+    memset(index1->free, 0,
+           label_block_size - sizeof(struct namespace_label_index_block));
+
+    /*
+     * the label slot with the lowest offset in the label storage area is
+     * tracked by the least significant bit of the first byte of the free
+     * array.
+     *
+     * the fist label is used.
+     */
+    for (i = 1; i < index1->nlabel; i++) {
+        set_bit(i, (unsigned long *)index1->free);
+    }
+
+    /* init the second namespace label index block. */
+    index2 = (void *)index1 + label_block_size;
+    memcpy(index2, index1, label_block_size);
+    index2->seq = cpu_to_le32(0x2);
+    index2->myoff = cpu_to_le64(label_block_size);
+
+    /* init @otheroff and @checksume. */
+    index1->otheroff = cpu_to_le64(index2->myoff);
+    index2->otheroff = cpu_to_le64(index1->myoff);
+    index1->checksum = cpu_to_le64(fletcher64(index1, label_block_size));
+    index2->checksum = cpu_to_le64(fletcher64(index2, label_block_size));
+
+    /* only one label is used which is the first label and is readonly. */
+    label = nvdimm->config_data_addr + label_block_size * 2;
+    namespace_label_uuid(nvdimm, label->uuid);
+    sprintf((char *)label->name, "QEMU NS%d", nvdimm->device_index);
+    label->flags = cpu_to_le32(NSLABEL_FLAG_ROLABEL);
+    label->nlabel = cpu_to_le16(1);
+    label->position = cpu_to_le16(0);
+    label->isetcookie = cpu_to_le64(nvdimm->isetcookie);
+    label->lbasize = cpu_to_le64(0);
+    label->dpa = cpu_to_le64(object_property_get_int(OBJECT(&nvdimm->mr),
+                                                     "addr", NULL));
+    label->rawsize = cpu_to_le64(memory_region_size(&nvdimm->mr));
+    label->slot = cpu_to_le32(0);
+    label->unused = cpu_to_le32(0);
+
+    nvdebug("nvdimm%d, checksum1 0x%lx checksum2 0x%lx isetcookie 0x%lx.\n",
+            nvdimm->device_index, index1->checksum, index2->checksum,
+            label->isetcookie);
+}
+
+void build_nvdimm_configdata(GSList *device_list)
+{
+    for (; device_list; device_list = device_list->next) {
+        PCNVDIMMDevice *nvdimm = device_list->data;
+
+        if (nvdimm->config_data_addr) {
+            return;
+        }
+
+        nvdimm->config_data_addr = g_malloc(nvdimm->config_data_size);
+        init_namespace(nvdimm);
+    }
+}
diff --git a/include/hw/mem/pc-nvdimm.h b/include/hw/mem/pc-nvdimm.h
index b7faec3..8aa7086 100644
--- a/include/hw/mem/pc-nvdimm.h
+++ b/include/hw/mem/pc-nvdimm.h
@@ -28,6 +28,8 @@ typedef struct PCNVDIMMDevice {
     uint64_t config_data_size;
     void *config_data_addr;
 
+    uint64_t isetcookie;
+
     MemoryRegion mr;
 } PCNVDIMMDevice;
 
-- 
2.4.3


WARNING: multiple messages have this Message-ID (diff)
From: Xiao Guangrong <guangrong.xiao@linux.intel.com>
To: pbonzini@redhat.com, imammedo@redhat.com
Cc: Xiao Guangrong <guangrong.xiao@linux.intel.com>,
	ehabkost@redhat.com, kvm@vger.kernel.org, mst@redhat.com,
	gleb@kernel.org, mtosatti@redhat.com, qemu-devel@nongnu.org,
	stefanha@redhat.com, rth@twiddle.net
Subject: [Qemu-devel] [PATCH v2 13/18] nvdimm: build namespace config data
Date: Fri, 14 Aug 2015 22:52:06 +0800	[thread overview]
Message-ID: <1439563931-12352-14-git-send-email-guangrong.xiao@linux.intel.com> (raw)
In-Reply-To: <1439563931-12352-1-git-send-email-guangrong.xiao@linux.intel.com>

If @configdata is false, Qemu will build a static and readonly
namespace in memory and use it serveing for
DSM GET_CONFIG_SIZE/GET_CONFIG_DATA requests

Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
 hw/mem/Makefile.objs       |   3 +-
 hw/mem/nvdimm/acpi.c       |  10 ++
 hw/mem/nvdimm/internal.h   |  12 ++
 hw/mem/nvdimm/namespace.c  | 307 +++++++++++++++++++++++++++++++++++++++++++++
 include/hw/mem/pc-nvdimm.h |   2 +
 5 files changed, 333 insertions(+), 1 deletion(-)
 create mode 100644 hw/mem/nvdimm/namespace.c

diff --git a/hw/mem/Makefile.objs b/hw/mem/Makefile.objs
index 7a6948d..7f3fab2 100644
--- a/hw/mem/Makefile.objs
+++ b/hw/mem/Makefile.objs
@@ -1,2 +1,3 @@
 common-obj-$(CONFIG_MEM_HOTPLUG) += pc-dimm.o
-common-obj-$(CONFIG_NVDIMM) += nvdimm/pc-nvdimm.o nvdimm/acpi.o
+common-obj-$(CONFIG_NVDIMM) += nvdimm/pc-nvdimm.o nvdimm/acpi.o	\
+			       nvdimm/namespace.o
diff --git a/hw/mem/nvdimm/acpi.c b/hw/mem/nvdimm/acpi.c
index 0b09efa..c773954 100644
--- a/hw/mem/nvdimm/acpi.c
+++ b/hw/mem/nvdimm/acpi.c
@@ -240,6 +240,8 @@ static void build_nfit_table(GSList *device_list, char *buf)
 
     for (; device_list; device_list = device_list->next) {
         PCNVDIMMDevice *nvdimm = device_list->data;
+        struct nfit_memdev *nfit_memdev;
+        struct nfit_dcr *nfit_dcr;
         int spa_index, dcr_index;
 
         spa_index = ++index;
@@ -252,10 +254,15 @@ static void build_nfit_table(GSList *device_list, char *buf)
          * build Memory Device to System Physical Address Range Mapping
          * Table.
          */
+        nfit_memdev = (struct nfit_memdev *)buf;
         buf += build_memdev_table(buf, nvdimm, spa_index, dcr_index);
 
         /* build Control Region Descriptor Table. */
+        nfit_dcr = (struct nfit_dcr *)buf;
         buf += build_dcr_table(buf, nvdimm, dcr_index);
+
+        calculate_nvdimm_isetcookie(nvdimm, nfit_memdev->region_spa_offset,
+                                    nfit_dcr->serial_number);
     }
 }
 
@@ -382,6 +389,9 @@ void pc_nvdimm_build_nfit_table(GArray *table_offsets, GArray *table_data,
 
     build_header(linker, table_data, (void *)(table_data->data + nfit_start),
                  "NFIT", table_data->len - nfit_start, 1);
+
+    build_nvdimm_configdata(list);
+
 exit:
     g_slist_free(list);
 }
diff --git a/hw/mem/nvdimm/internal.h b/hw/mem/nvdimm/internal.h
index 90d54dc..b1f3f16 100644
--- a/hw/mem/nvdimm/internal.h
+++ b/hw/mem/nvdimm/internal.h
@@ -13,6 +13,14 @@
 #ifndef __NVDIMM_INTERNAL_H
 #define __NVDIMM_INTERNAL_H
 
+/* #define NVDIMM_DEBUG */
+
+#ifdef NVDIMM_DEBUG
+#define nvdebug(fmt, ...) fprintf(stderr, "nvdimm: " fmt, ## __VA_ARGS__)
+#else
+#define nvdebug(...)
+#endif
+
 #define PAGE_SIZE               (1UL << 12)
 
 typedef struct {
@@ -27,4 +35,8 @@ typedef struct {
 
 GSList *get_nvdimm_built_list(void);
 ram_addr_t reserved_range_push(uint64_t size);
+
+void calculate_nvdimm_isetcookie(PCNVDIMMDevice *nvdimm, uint64_t spa,
+                                 uint32_t sn);
+void build_nvdimm_configdata(GSList *device_list);
 #endif
diff --git a/hw/mem/nvdimm/namespace.c b/hw/mem/nvdimm/namespace.c
new file mode 100644
index 0000000..04626da
--- /dev/null
+++ b/hw/mem/nvdimm/namespace.c
@@ -0,0 +1,307 @@
+/*
+ * NVDIMM  Namespace Support
+ *
+ * Copyright(C) 2015 Intel Corporation.
+ *
+ * Author:
+ *  Xiao Guangrong <guangrong.xiao@linux.intel.com>
+ *
+ * NVDIMM namespace specification can be found at:
+ *      http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "hw/mem/pc-nvdimm.h"
+
+#include "internal.h"
+
+static uint64_t fletcher64(void *addr, size_t len)
+{
+    uint32_t *buf = addr;
+    uint32_t lo32 = 0;
+    uint64_t hi32 = 0;
+    int i;
+
+    for (i = 0; i < len / sizeof(uint32_t); i++) {
+        lo32 += cpu_to_le32(buf[i]);
+        hi32 += lo32;
+    }
+
+    return hi32 << 32 | lo32;
+}
+
+struct interleave_set_info {
+    struct interleave_set_info_map {
+        uint64_t region_spa_offset;
+        uint32_t serial_number;
+        uint32_t zero;
+    } mapping[1];
+};
+
+void calculate_nvdimm_isetcookie(PCNVDIMMDevice *nvdimm, uint64_t spa,
+                                 uint32_t sn)
+{
+    struct interleave_set_info info;
+
+    info.mapping[0].region_spa_offset = spa;
+    info.mapping[0].serial_number = sn;
+    info.mapping[0].zero = 0;
+
+    nvdimm->isetcookie = fletcher64(&info, sizeof(info));
+}
+
+#define NSINDEX_SIGNATURE      "NAMESPACE_INDEX\0"
+
+enum {
+    NSINDEX_SIG_LEN = 16,
+    NSINDEX_ALIGN = 256,
+    NSINDEX_SEQ_MASK = 0x3,
+    NSINDEX_MAJOR = 0x1,
+    NSINDEX_MINOR = 0x1,
+
+    NSLABEL_UUID_LEN = 16,
+    NSLABEL_NAME_LEN = 64,
+    NSLABEL_FLAG_ROLABEL = 0x1,  /* read-only label */
+    NSLABEL_FLAG_LOCAL = 0x2,    /* DIMM-local namespace */
+    NSLABEL_FLAG_BTT = 0x4,      /* namespace contains a BTT */
+    NSLABEL_FLAG_UPDATING = 0x8, /* label being updated */
+};
+
+/*
+ * struct nd_namespace_index - label set superblock
+ * @sig: NAMESPACE_INDEX\0
+ * @flags: placeholder
+ * @seq: sequence number for this index
+ * @myoff: offset of this index in label area
+ * @mysize: size of this index struct
+ * @otheroff: offset of other index
+ * @labeloff: offset of first label slot
+ * @nslot: total number of label slots
+ * @major: label area major version
+ * @minor: label area minor version
+ * @checksum: fletcher64 of all fields
+ * @free[0]: bitmap, nlabel bits
+ *
+ * The size of free[] is rounded up so the total struct size is a
+ * multiple of NSINDEX_ALIGN bytes.  Any bits this allocates beyond
+ * nlabel bits must be zero.
+ */
+struct namespace_label_index_block {
+    uint8_t sig[NSINDEX_SIG_LEN];
+    uint32_t flags;
+    uint32_t seq;
+    uint64_t myoff;
+    uint64_t mysize;
+    uint64_t otheroff;
+    uint64_t labeloff;
+    uint32_t nlabel;
+    uint16_t major;
+    uint16_t minor;
+    uint64_t checksum;
+    uint8_t free[0];
+} QEMU_PACKED;
+
+/*
+ * struct nd_namespace_label - namespace superblock
+ * @uuid: UUID per RFC 4122
+ * @name: optional name (NULL-terminated)
+ * @flags: see NSLABEL_FLAG_*
+ * @nlabel: num labels to describe this ns
+ * @position: labels position in set
+ * @isetcookie: interleave set cookie
+ * @lbasize: LBA size in bytes or 0 for pmem
+ * @dpa: DPA of NVM range on this DIMM
+ * @rawsize: size of namespace
+ * @slot: slot of this label in label area
+ * @unused: must be zero
+ */
+struct namespace_label {
+    uint8_t uuid[NSLABEL_UUID_LEN];
+    uint8_t name[NSLABEL_NAME_LEN];
+    uint32_t flags;
+    uint16_t nlabel;
+    uint16_t position;
+    uint64_t isetcookie;
+    uint64_t lbasize;
+    uint64_t dpa;
+    uint64_t rawsize;
+    uint32_t slot;
+    uint32_t unused;
+} QEMU_PACKED;
+
+/*calculate the number of label can be contained in whole config space. */
+static int config_space_max_label_nr(PCNVDIMMDevice *nvdimm, size_t block_size)
+{
+    /* totally we have 2 namespace label index block. */
+    if (block_size * 2 >= nvdimm->config_data_size) {
+        return 0;
+    }
+
+    return (nvdimm->config_data_size - block_size * 2) /
+            sizeof(struct namespace_label);
+}
+
+/*calculate the number of label can be contained in index block. */
+static int label_index_block_max_label_nr(size_t block_size)
+{
+    int free_size;
+
+    free_size = block_size - sizeof(struct namespace_label_index_block);
+
+    return free_size * BITS_PER_BYTE;
+}
+
+static int calculate_max_label_nr(PCNVDIMMDevice *nvdimm, size_t block_size)
+{
+    return MIN(label_index_block_max_label_nr(block_size),
+        config_space_max_label_nr(nvdimm, block_size));
+}
+
+/*
+ * check if we can increase the size of namespace_label_index_block to
+ * contain more labels.
+ */
+static bool can_increase_index_block(PCNVDIMMDevice *nvdimm,
+                                     size_t block_size, int label_nr)
+{
+    size_t remaining;
+
+    remaining = nvdimm->config_data_size - block_size * 2 -
+                label_nr * sizeof(struct namespace_label);
+
+    assert((int64_t)remaining >= 0);
+
+    /* can contain 1 label at least. */
+    return remaining >=  NSINDEX_ALIGN * 2 + sizeof(struct namespace_label);
+}
+
+static void count_label_nr(PCNVDIMMDevice *nvdimm, size_t *label_block_size,
+                           int *label_nr)
+{
+    *label_block_size = 0;
+
+    do {
+        /*
+          * The minimum size of an index block is 256 bytes and the size must
+          * be a multiple of 256 bytes.
+          */
+        *label_block_size += NSINDEX_ALIGN;
+
+        *label_nr = calculate_max_label_nr(nvdimm, *label_block_size);
+    } while (can_increase_index_block(nvdimm, *label_block_size, *label_nr));
+}
+
+static void namespace_label_uuid(PCNVDIMMDevice *nvdimm, void *uuid)
+{
+    uuid_le label_uuid_init = UUID_LE(0x137e67a9, 0x7dcb, 0x4c66, 0xb2,
+                                      0xe6, 0x05, 0x06, 0x5b, 0xeb,
+                                      0x6a, 0x00);
+
+    assert(nvdimm->device_index <= 0xff);
+
+    label_uuid_init.b[0] += nvdimm->device_index;
+    memcpy(uuid, &label_uuid_init, sizeof(label_uuid_init));
+}
+
+static void init_namespace(PCNVDIMMDevice *nvdimm)
+{
+    struct namespace_label_index_block *index1, *index2;
+    struct namespace_label *label;
+    int i;
+
+    size_t label_block_size;
+    int label_nr;
+
+    assert(!nvdimm->configdata);
+
+    count_label_nr(nvdimm, &label_block_size, &label_nr);
+    nvdebug("nvdimm%d: label_block_size 0x%lx label_nr %d.\n",
+            nvdimm->device_index, label_block_size, label_nr);
+
+    index1 = nvdimm->config_data_addr;
+
+    /*
+     * init the first namespace label index block, except @otheroff
+     * and @checksum. we will do it later.
+     */
+    memcpy(index1->sig, NSINDEX_SIGNATURE, sizeof(NSINDEX_SIGNATURE));
+    index1->flags = cpu_to_le32(0);
+    index1->seq = cpu_to_le32(0x1);
+    index1->myoff = cpu_to_le64(0);
+    index1->mysize = cpu_to_le64(label_block_size);
+    index1->labeloff = cpu_to_le64(label_block_size * 2);
+    index1->nlabel = cpu_to_le32(label_nr);
+    index1->major = cpu_to_le16(NSINDEX_MAJOR);
+    index1->minor = cpu_to_le16(NSINDEX_MINOR);
+    index1->checksum = cpu_to_le64(0);
+    memset(index1->free, 0,
+           label_block_size - sizeof(struct namespace_label_index_block));
+
+    /*
+     * the label slot with the lowest offset in the label storage area is
+     * tracked by the least significant bit of the first byte of the free
+     * array.
+     *
+     * the fist label is used.
+     */
+    for (i = 1; i < index1->nlabel; i++) {
+        set_bit(i, (unsigned long *)index1->free);
+    }
+
+    /* init the second namespace label index block. */
+    index2 = (void *)index1 + label_block_size;
+    memcpy(index2, index1, label_block_size);
+    index2->seq = cpu_to_le32(0x2);
+    index2->myoff = cpu_to_le64(label_block_size);
+
+    /* init @otheroff and @checksume. */
+    index1->otheroff = cpu_to_le64(index2->myoff);
+    index2->otheroff = cpu_to_le64(index1->myoff);
+    index1->checksum = cpu_to_le64(fletcher64(index1, label_block_size));
+    index2->checksum = cpu_to_le64(fletcher64(index2, label_block_size));
+
+    /* only one label is used which is the first label and is readonly. */
+    label = nvdimm->config_data_addr + label_block_size * 2;
+    namespace_label_uuid(nvdimm, label->uuid);
+    sprintf((char *)label->name, "QEMU NS%d", nvdimm->device_index);
+    label->flags = cpu_to_le32(NSLABEL_FLAG_ROLABEL);
+    label->nlabel = cpu_to_le16(1);
+    label->position = cpu_to_le16(0);
+    label->isetcookie = cpu_to_le64(nvdimm->isetcookie);
+    label->lbasize = cpu_to_le64(0);
+    label->dpa = cpu_to_le64(object_property_get_int(OBJECT(&nvdimm->mr),
+                                                     "addr", NULL));
+    label->rawsize = cpu_to_le64(memory_region_size(&nvdimm->mr));
+    label->slot = cpu_to_le32(0);
+    label->unused = cpu_to_le32(0);
+
+    nvdebug("nvdimm%d, checksum1 0x%lx checksum2 0x%lx isetcookie 0x%lx.\n",
+            nvdimm->device_index, index1->checksum, index2->checksum,
+            label->isetcookie);
+}
+
+void build_nvdimm_configdata(GSList *device_list)
+{
+    for (; device_list; device_list = device_list->next) {
+        PCNVDIMMDevice *nvdimm = device_list->data;
+
+        if (nvdimm->config_data_addr) {
+            return;
+        }
+
+        nvdimm->config_data_addr = g_malloc(nvdimm->config_data_size);
+        init_namespace(nvdimm);
+    }
+}
diff --git a/include/hw/mem/pc-nvdimm.h b/include/hw/mem/pc-nvdimm.h
index b7faec3..8aa7086 100644
--- a/include/hw/mem/pc-nvdimm.h
+++ b/include/hw/mem/pc-nvdimm.h
@@ -28,6 +28,8 @@ typedef struct PCNVDIMMDevice {
     uint64_t config_data_size;
     void *config_data_addr;
 
+    uint64_t isetcookie;
+
     MemoryRegion mr;
 } PCNVDIMMDevice;
 
-- 
2.4.3

  parent reply	other threads:[~2015-08-14 14:58 UTC|newest]

Thread overview: 164+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-08-14 14:51 [PATCH v2 00/18] implement vNVDIMM Xiao Guangrong
2015-08-14 14:51 ` [Qemu-devel] " Xiao Guangrong
2015-08-14 14:51 ` [PATCH v2 01/18] acpi: allow aml_operation_region() working on 64 bit offset Xiao Guangrong
2015-08-14 14:51   ` [Qemu-devel] " Xiao Guangrong
2015-09-02  8:05   ` Igor Mammedov
2015-09-02  8:05     ` [Qemu-devel] " Igor Mammedov
2015-08-14 14:51 ` [PATCH v2 02/18] i386/acpi-build: allow SSDT to operate on 64 bit Xiao Guangrong
2015-08-14 14:51   ` [Qemu-devel] " Xiao Guangrong
2015-09-02 10:06   ` Igor Mammedov
2015-09-02 10:06     ` [Qemu-devel] " Igor Mammedov
2015-09-02 10:43     ` Xiao Guangrong
2015-09-02 11:42       ` Igor Mammedov
2015-09-06  7:01         ` Xiao Guangrong
2015-09-02 12:05     ` Michael S. Tsirkin
2015-09-02 12:05       ` [Qemu-devel] " Michael S. Tsirkin
2015-08-14 14:51 ` [PATCH v2 03/18] acpi: add aml_derefof Xiao Guangrong
2015-08-14 14:51   ` [Qemu-devel] " Xiao Guangrong
2015-09-02 10:16   ` Igor Mammedov
2015-09-02 10:16     ` [Qemu-devel] " Igor Mammedov
2015-09-02 10:38     ` Xiao Guangrong
2015-09-02 10:38       ` [Qemu-devel] " Xiao Guangrong
2015-08-14 14:51 ` [PATCH v2 04/18] acpi: add aml_sizeof Xiao Guangrong
2015-08-14 14:51   ` [Qemu-devel] " Xiao Guangrong
2015-09-02 10:18   ` Igor Mammedov
2015-09-02 10:18     ` [Qemu-devel] " Igor Mammedov
2015-09-02 10:39     ` Xiao Guangrong
2015-09-02 10:39       ` [Qemu-devel] " Xiao Guangrong
2015-08-14 14:51 ` [PATCH v2 05/18] acpi: add aml_create_field Xiao Guangrong
2015-08-14 14:51   ` [Qemu-devel] " Xiao Guangrong
2015-09-02 11:10   ` Igor Mammedov
2015-09-02 11:10     ` [Qemu-devel] " Igor Mammedov
2015-09-06  5:32     ` Xiao Guangrong
2015-09-06  5:32       ` [Qemu-devel] " Xiao Guangrong
2015-08-14 14:51 ` [PATCH v2 06/18] pc: implement NVDIMM device abstract Xiao Guangrong
2015-08-14 14:51   ` [Qemu-devel] " Xiao Guangrong
2015-08-25 14:57   ` Stefan Hajnoczi
2015-08-25 14:57     ` Stefan Hajnoczi
2015-08-26  9:37     ` Xiao Guangrong
2015-08-26  9:37       ` Xiao Guangrong
2015-09-02  9:58   ` Igor Mammedov
2015-09-02  9:58     ` Igor Mammedov
2015-09-02 10:36     ` Xiao Guangrong
2015-09-02 10:36       ` Xiao Guangrong
2015-09-02 11:31       ` Igor Mammedov
2015-09-02 11:31         ` Igor Mammedov
2015-09-06  6:07         ` Xiao Guangrong
2015-09-06  6:07           ` Xiao Guangrong
2015-09-07 13:40           ` Igor Mammedov
2015-09-07 13:40             ` Igor Mammedov
2015-09-08 14:03             ` Xiao Guangrong
2015-09-10  9:47               ` Igor Mammedov
2015-08-14 14:52 ` [PATCH v2 07/18] nvdimm: reserve address range for NVDIMM Xiao Guangrong
2015-08-14 14:52   ` [Qemu-devel] " Xiao Guangrong
2015-08-25 15:12   ` Stefan Hajnoczi
2015-08-25 15:12     ` [Qemu-devel] " Stefan Hajnoczi
2015-08-26  9:39     ` Xiao Guangrong
2015-08-26  9:40     ` Xiao Guangrong
2015-08-26  9:40       ` Xiao Guangrong
2015-08-25 15:39   ` Stefan Hajnoczi
2015-08-25 15:39     ` [Qemu-devel] " Stefan Hajnoczi
2015-08-28 17:25   ` Eduardo Habkost
2015-08-28 17:25     ` [Qemu-devel] " Eduardo Habkost
2015-08-31  7:01     ` Xiao Guangrong
2015-08-31  7:01       ` [Qemu-devel] " Xiao Guangrong
2015-09-04 12:02   ` Igor Mammedov
2015-09-04 12:02     ` [Qemu-devel] " Igor Mammedov
2015-09-06  7:22     ` Xiao Guangrong
2015-09-06  7:22       ` Xiao Guangrong
2015-08-14 14:52 ` [PATCH v2 08/18] nvdimm: init backend memory mapping and config data area Xiao Guangrong
2015-08-14 14:52   ` [Qemu-devel] " Xiao Guangrong
2015-08-25 16:03   ` Stefan Hajnoczi
2015-08-25 16:03     ` [Qemu-devel] " Stefan Hajnoczi
2015-08-26 10:40     ` Xiao Guangrong
2015-08-26 10:40       ` [Qemu-devel] " Xiao Guangrong
2015-08-28 11:58       ` Stefan Hajnoczi
2015-08-28 11:58         ` [Qemu-devel] " Stefan Hajnoczi
2015-08-31  6:23         ` Xiao Guangrong
2015-08-31  6:23           ` [Qemu-devel] " Xiao Guangrong
2015-09-01  9:14           ` Stefan Hajnoczi
2015-09-01  9:14             ` [Qemu-devel] " Stefan Hajnoczi
2015-09-15 16:10             ` Paolo Bonzini
2015-09-15 16:10               ` [Qemu-devel] " Paolo Bonzini
2015-09-17  8:39               ` Xiao Guangrong
2015-09-17  8:39                 ` [Qemu-devel] " Xiao Guangrong
2015-09-17  9:04                 ` Igor Mammedov
2015-09-17  9:04                   ` [Qemu-devel] " Igor Mammedov
2015-09-17  9:14                   ` Xiao Guangrong
2015-09-17  9:14                     ` [Qemu-devel] " Xiao Guangrong
2015-09-17  9:34                     ` Paolo Bonzini
2015-09-17  9:34                       ` [Qemu-devel] " Paolo Bonzini
2015-09-17 12:43                       ` Xiao Guangrong
2015-09-15 16:07       ` Paolo Bonzini
2015-09-15 16:07         ` [Qemu-devel] " Paolo Bonzini
2015-09-17  8:23         ` Xiao Guangrong
2015-09-17  8:23           ` [Qemu-devel] " Xiao Guangrong
2015-09-15 16:06     ` Paolo Bonzini
2015-09-15 16:06       ` [Qemu-devel] " Paolo Bonzini
2015-09-17  8:21       ` Xiao Guangrong
2015-09-17  8:21         ` [Qemu-devel] " Xiao Guangrong
2015-09-07 14:11   ` Igor Mammedov
2015-09-07 14:11     ` Igor Mammedov
2015-09-08 13:38     ` Xiao Guangrong
2015-09-10 10:35       ` Igor Mammedov
2015-09-15 16:11     ` Paolo Bonzini
2015-08-14 14:52 ` [PATCH v2 09/18] nvdimm: build ACPI NFIT table Xiao Guangrong
2015-08-14 14:52   ` [Qemu-devel] " Xiao Guangrong
2015-09-15 16:12   ` Paolo Bonzini
2015-09-15 16:12     ` [Qemu-devel] " Paolo Bonzini
2015-09-15 17:35     ` Igor Mammedov
2015-09-15 17:35       ` [Qemu-devel] " Igor Mammedov
2015-08-14 14:52 ` [PATCH v2 10/18] nvdimm: init the address region used by DSM method Xiao Guangrong
2015-08-14 14:52   ` [Qemu-devel] " Xiao Guangrong
2015-08-25 16:11   ` Stefan Hajnoczi
2015-08-25 16:11     ` [Qemu-devel] " Stefan Hajnoczi
2015-08-26 10:41     ` Xiao Guangrong
2015-08-26 10:41       ` [Qemu-devel] " Xiao Guangrong
2015-08-14 14:52 ` [PATCH v2 11/18] nvdimm: build ACPI nvdimm devices Xiao Guangrong
2015-08-14 14:52   ` [Qemu-devel] " Xiao Guangrong
2015-08-14 14:52 ` [PATCH v2 12/18] nvdimm: save arg3 for NVDIMM device _DSM method Xiao Guangrong
2015-08-14 14:52   ` [Qemu-devel] " Xiao Guangrong
2015-08-14 14:52 ` Xiao Guangrong [this message]
2015-08-14 14:52   ` [Qemu-devel] [PATCH v2 13/18] nvdimm: build namespace config data Xiao Guangrong
2015-08-25 16:16   ` Stefan Hajnoczi
2015-08-25 16:16     ` Stefan Hajnoczi
2015-08-26 10:42     ` Xiao Guangrong
2015-08-26 10:42       ` Xiao Guangrong
2015-08-28 11:59       ` Stefan Hajnoczi
2015-08-28 11:59         ` Stefan Hajnoczi
2015-08-31  6:25         ` Xiao Guangrong
2015-08-31  6:25           ` Xiao Guangrong
2015-08-14 14:52 ` [PATCH v2 14/18] nvdimm: support NFIT_CMD_IMPLEMENTED function Xiao Guangrong
2015-08-14 14:52   ` [Qemu-devel] " Xiao Guangrong
2015-08-25 16:23   ` Stefan Hajnoczi
2015-08-25 16:23     ` [Qemu-devel] " Stefan Hajnoczi
2015-08-26 10:46     ` Xiao Guangrong
2015-08-26 10:46       ` [Qemu-devel] " Xiao Guangrong
2015-08-28 12:01       ` Stefan Hajnoczi
2015-08-28 12:01         ` [Qemu-devel] " Stefan Hajnoczi
2015-08-31  6:51         ` Xiao Guangrong
2015-08-31  6:51           ` Xiao Guangrong
2015-09-01  9:16           ` Stefan Hajnoczi
2015-09-01  9:16             ` Stefan Hajnoczi
2015-08-14 14:52 ` [PATCH v2 15/18] nvdimm: support NFIT_CMD_GET_CONFIG_SIZE function Xiao Guangrong
2015-08-14 14:52   ` [Qemu-devel] " Xiao Guangrong
2015-08-25 16:24   ` Stefan Hajnoczi
2015-08-25 16:24     ` [Qemu-devel] " Stefan Hajnoczi
2015-08-26 10:47     ` Xiao Guangrong
2015-08-26 10:47       ` [Qemu-devel] " Xiao Guangrong
2015-08-14 14:52 ` [PATCH v2 16/18] nvdimm: support NFIT_CMD_GET_CONFIG_DATA Xiao Guangrong
2015-08-14 14:52   ` [Qemu-devel] " Xiao Guangrong
2015-08-14 14:52 ` [PATCH v2 17/18] nvdimm: support NFIT_CMD_SET_CONFIG_DATA Xiao Guangrong
2015-08-14 14:52   ` [Qemu-devel] " Xiao Guangrong
2015-08-14 14:52 ` [PATCH v2 18/18] nvdimm: add maintain info Xiao Guangrong
2015-08-14 14:52   ` [Qemu-devel] " Xiao Guangrong
2015-08-25 16:26 ` [Qemu-devel] [PATCH v2 00/18] implement vNVDIMM Stefan Hajnoczi
2015-08-25 16:26   ` Stefan Hajnoczi
2015-08-26 10:49   ` Xiao Guangrong
2015-08-26 10:49     ` Xiao Guangrong
2015-10-07 14:02     ` Stefan Hajnoczi
2015-10-07 14:02       ` Stefan Hajnoczi
2015-10-07 14:43       ` Xiao Guangrong
2015-10-07 14:43         ` Xiao Guangrong
2015-10-09 10:38         ` Stefan Hajnoczi
2015-10-09 10:38           ` Stefan Hajnoczi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1439563931-12352-14-git-send-email-guangrong.xiao@linux.intel.com \
    --to=guangrong.xiao@linux.intel.com \
    --cc=ehabkost@redhat.com \
    --cc=gleb@kernel.org \
    --cc=imammedo@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=mst@redhat.com \
    --cc=mtosatti@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rth@twiddle.net \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.