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 09/16] nvdimm: build ACPI NFIT table
Date: Wed,  1 Jul 2015 22:50:25 +0800	[thread overview]
Message-ID: <1435762232-15543-10-git-send-email-guangrong.xiao@linux.intel.com> (raw)
In-Reply-To: <1435762232-15543-1-git-send-email-guangrong.xiao@linux.intel.com>

NFIT is defined in ACPI 6.0: 5.2.25 NVDIMM Firmware Interface Table (NFIT)

Currently, we only support PMEM mode. Each device has 3 tables:
- SPA table, define the PMEM region info

- MEM DEV table, it has the @handle which is used to associate specified
  ACPI NVDIMM  device we will introduce in later patch.
  Also we can happily ignored the memory device's interleave, the real
  nvdimm hardware access is hidden behind host

- DCR table, it defines Vendor ID used to associate specified vendor
  nvdimm driver. Since we only implement PMEM mode this time, Command
  window and Data window are not needed

Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
 hw/i386/acpi-build.c       |   3 +
 hw/mem/pc-nvdimm.c         | 286 +++++++++++++++++++++++++++++++++++++++++++++
 include/hw/mem/pc-nvdimm.h |   8 ++
 3 files changed, 297 insertions(+)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 6a1ab09..80c21be 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -39,6 +39,7 @@
 #include "hw/loader.h"
 #include "hw/isa/isa.h"
 #include "hw/acpi/memory_hotplug.h"
+#include "hw/mem/pc-nvdimm.h"
 #include "sysemu/tpm.h"
 #include "hw/acpi/tpm.h"
 #include "sysemu/tpm_backend.h"
@@ -1741,6 +1742,8 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
         build_dmar_q35(tables_blob, tables->linker);
     }
 
+    pc_nvdimm_build_nfit_table(table_offsets, tables_blob, tables->linker);
+
     /* Add tables supplied by user (if any) */
     for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
         unsigned len = acpi_table_len(u);
diff --git a/hw/mem/pc-nvdimm.c b/hw/mem/pc-nvdimm.c
index 9531935..e7cff29 100644
--- a/hw/mem/pc-nvdimm.c
+++ b/hw/mem/pc-nvdimm.c
@@ -27,10 +27,12 @@
 #include <linux/fs.h>
 
 #include "exec/address-spaces.h"
+#include "hw/acpi/aml-build.h"
 #include "hw/mem/pc-nvdimm.h"
 
 #define PAGE_SIZE               (1UL << 12)
 
+#define MAX_NVDIMM_NUMBER       (10)
 #define MIN_CONFIG_DATA_SIZE    (128 << 10)
 
 static struct nvdimms_info {
@@ -65,6 +67,290 @@ static uint32_t new_device_index(void)
     return nvdimms_info.device_index++;
 }
 
+static int pc_nvdimm_built_list(Object *obj, void *opaque)
+{
+    GSList **list = opaque;
+
+    if (object_dynamic_cast(obj, TYPE_PC_NVDIMM)) {
+        PCNVDIMMDevice *nvdimm = PC_NVDIMM(obj);
+
+        /* only realized NVDIMMs matter */
+        if (memory_region_size(&nvdimm->mr)) {
+            *list = g_slist_append(*list, nvdimm);
+        }
+    }
+
+    object_child_foreach(obj, pc_nvdimm_built_list, opaque);
+    return 0;
+}
+
+static GSList *get_nvdimm_built_list(void)
+{
+    GSList *list = NULL;
+
+    object_child_foreach(qdev_get_machine(), pc_nvdimm_built_list, &list);
+    return list;
+}
+
+static int get_nvdimm_device_number(GSList *list)
+{
+    int nr = 0;
+
+    for (; list; list = list->next) {
+        nr++;
+    }
+
+    return nr;
+}
+
+static uint32_t nvdimm_index_to_sn(int index)
+{
+    return 0x123456 + index;
+}
+
+static uint32_t nvdimm_index_to_handle(int index)
+{
+    return index + 1;
+}
+
+typedef struct {
+    uint8_t b[16];
+} uuid_le;
+
+#define UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)                   \
+((uuid_le)                                                                 \
+{ { (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+    (b) & 0xff, ((b) >> 8) & 0xff, (c) & 0xff, ((c) >> 8) & 0xff,          \
+    (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) } })
+
+static void nfit_spa_uuid_pm(void *uuid)
+{
+    uuid_le uuid_pm = UUID_LE(0x66f0d379, 0xb4f3, 0x4074, 0xac, 0x43, 0x0d,
+                              0x33, 0x18, 0xb7, 0x8c, 0xdb);
+    memcpy(uuid, &uuid_pm, sizeof(uuid_pm));
+}
+
+enum {
+    NFIT_TABLE_SPA = 0,
+    NFIT_TABLE_MEM = 1,
+    NFIT_TABLE_IDT = 2,
+    NFIT_TABLE_SMBIOS = 3,
+    NFIT_TABLE_DCR = 4,
+    NFIT_TABLE_BDW = 5,
+    NFIT_TABLE_FLUSH = 6,
+};
+
+enum {
+    EFI_MEMORY_UC = 0x1ULL,
+    EFI_MEMORY_WC = 0x2ULL,
+    EFI_MEMORY_WT = 0x4ULL,
+    EFI_MEMORY_WB = 0x8ULL,
+    EFI_MEMORY_UCE = 0x10ULL,
+    EFI_MEMORY_WP = 0x1000ULL,
+    EFI_MEMORY_RP = 0x2000ULL,
+    EFI_MEMORY_XP = 0x4000ULL,
+    EFI_MEMORY_NV = 0x8000ULL,
+    EFI_MEMORY_MORE_RELIABLE = 0x10000ULL,
+};
+
+/*
+ * struct nfit - Nvdimm Firmware Interface Table
+ * @signature: "NFIT"
+ */
+struct nfit {
+    ACPI_TABLE_HEADER_DEF
+    uint32_t reserved;
+} QEMU_PACKED;
+
+/*
+ * struct nfit_spa - System Physical Address Range Structure
+ */
+struct nfit_spa {
+    uint16_t type;
+    uint16_t length;
+    uint16_t spa_index;
+    uint16_t flags;
+    uint32_t reserved;
+    uint32_t proximity_domain;
+    uint8_t type_uuid[16];
+    uint64_t spa_base;
+    uint64_t spa_length;
+    uint64_t mem_attr;
+} QEMU_PACKED;
+
+/*
+ * struct nfit_memdev - Memory Device to SPA Map Structure
+ */
+struct nfit_memdev {
+    uint16_t type;
+    uint16_t length;
+    uint32_t nfit_handle;
+    uint16_t phys_id;
+    uint16_t region_id;
+    uint16_t spa_index;
+    uint16_t dcr_index;
+    uint64_t region_len;
+    uint64_t region_spa_offset;
+    uint64_t region_dpa;
+    uint16_t idt_index;
+    uint16_t interleave_ways;
+    uint16_t flags;
+    uint16_t reserved;
+} QEMU_PACKED;
+
+/*
+ * struct nfit_dcr - NVDIMM Control Region Structure
+ */
+struct nfit_dcr {
+    uint16_t type;
+    uint16_t length;
+    uint16_t dcr_index;
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint16_t revision_id;
+    uint16_t sub_vendor_id;
+    uint16_t sub_device_id;
+    uint16_t sub_revision_id;
+    uint8_t reserved[6];
+    uint32_t serial_number;
+    uint16_t fic;
+    uint16_t num_bcw;
+    uint64_t bcw_size;
+    uint64_t cmd_offset;
+    uint64_t cmd_size;
+    uint64_t status_offset;
+    uint64_t status_size;
+    uint16_t flags;
+    uint8_t reserved2[6];
+} QEMU_PACK;
+
+#define REVSISON_ID    1
+#define NFIT_FIC1      0x201
+
+static size_t get_nfit_total_size(int nr)
+{
+    /* each nvdimm has 3 tables. */
+    return sizeof(struct nfit) + nr * (sizeof(struct nfit_spa) +
+                  sizeof(struct nfit_memdev) + sizeof(struct nfit_dcr));
+}
+
+static int build_spa_table(void *buf, PCNVDIMMDevice *nvdimm, int spa_index)
+{
+    struct nfit_spa *nfit_spa;
+    uint64_t addr = object_property_get_int(OBJECT(&nvdimm->mr), "addr", NULL);
+
+    nfit_spa = (struct nfit_spa *)buf;
+
+    /*
+     * nfit_spa->flags is set to zero so that proximity_domain
+     * info is ignored.
+     */
+    nfit_spa->type = cpu_to_le16(NFIT_TABLE_SPA);
+    nfit_spa->length = cpu_to_le16(sizeof(*nfit_spa));
+    nfit_spa_uuid_pm(&nfit_spa->type_uuid);
+    nfit_spa->spa_index = cpu_to_le16(spa_index);
+    nfit_spa->spa_base = cpu_to_le64(addr);
+    nfit_spa->spa_length = cpu_to_le64(memory_region_size(&nvdimm->mr));
+    nfit_spa->mem_attr = cpu_to_le64(EFI_MEMORY_WB | EFI_MEMORY_NV);
+
+    return sizeof(*nfit_spa);
+}
+
+static int build_memdev_table(void *buf, PCNVDIMMDevice *nvdimm,
+                              int spa_index, int dcr_index)
+{
+    struct nfit_memdev *nfit_memdev;
+    uint64_t addr = object_property_get_int(OBJECT(&nvdimm->mr), "addr", NULL);
+    uint32_t handle = nvdimm_index_to_handle(nvdimm->device_index);
+
+    nfit_memdev = (struct nfit_memdev *)buf;
+    nfit_memdev->type = cpu_to_le16(NFIT_TABLE_MEM);
+    nfit_memdev->length = cpu_to_le16(sizeof(*nfit_memdev));
+    nfit_memdev->nfit_handle = cpu_to_le32(handle);
+    /* point to nfit_spa. */
+    nfit_memdev->spa_index = cpu_to_le16(spa_index);
+    /* point to nfit_dcr. */
+    nfit_memdev->dcr_index = cpu_to_le16(dcr_index);
+    nfit_memdev->region_len = cpu_to_le64(memory_region_size(&nvdimm->mr));
+    nfit_memdev->region_dpa = cpu_to_le64(addr);
+    /* Only one interleave for pmem. */
+    nfit_memdev->interleave_ways = cpu_to_le16(1);
+
+    return sizeof(*nfit_memdev);
+}
+
+static int build_dcr_table(void *buf, PCNVDIMMDevice *nvdimm, int dcr_index)
+{
+    struct nfit_dcr *nfit_dcr;
+    uint32_t sn = nvdimm_index_to_sn(nvdimm->device_index);
+
+    nfit_dcr = (struct nfit_dcr *)buf;
+    nfit_dcr->type = cpu_to_le16(NFIT_TABLE_DCR);
+    nfit_dcr->length = cpu_to_le16(sizeof(*nfit_dcr));
+    nfit_dcr->dcr_index = cpu_to_le16(dcr_index);
+    nfit_dcr->vendor_id = cpu_to_le16(0x8086);
+    nfit_dcr->device_id = cpu_to_le16(1);
+    nfit_dcr->revision_id = cpu_to_le16(REVSISON_ID);
+    nfit_dcr->serial_number = cpu_to_le32(sn);
+    nfit_dcr->fic = cpu_to_le16(NFIT_FIC1);
+
+    return sizeof(*nfit_dcr);
+}
+
+static void build_nfit_table(GSList *device_list, char *buf)
+{
+    int index = 0;
+
+    buf += sizeof(struct nfit);
+
+    for (; device_list; device_list = device_list->next) {
+        PCNVDIMMDevice *nvdimm = device_list->data;
+        int spa_index, dcr_index;
+
+        spa_index = ++index;
+        dcr_index = ++index;
+
+        /* build System Physical Address Range Description Table. */
+        buf += build_spa_table(buf, nvdimm, spa_index);
+
+        /*
+         * build Memory Device to System Physical Address Range Mapping
+         * Table.
+         */
+        buf += build_memdev_table(buf, nvdimm, spa_index, dcr_index);
+
+        /* build Control Region Descriptor Table. */
+        buf += build_dcr_table(buf, nvdimm, dcr_index);
+    }
+}
+
+void pc_nvdimm_build_nfit_table(GArray *table_offsets, GArray *table_data,
+                                GArray *linker)
+{
+    GSList *list = get_nvdimm_built_list();
+    size_t total;
+    char *buf;
+    int nfit_start, nr;
+
+    nr = get_nvdimm_device_number(list);
+    total = get_nfit_total_size(nr);
+
+    if (nr <= 0 || nr > MAX_NVDIMM_NUMBER) {
+        goto exit;
+    }
+
+    nfit_start = table_data->len;
+    acpi_add_table(table_offsets, table_data);
+
+    buf = acpi_data_push(table_data, total);
+    build_nfit_table(list, buf);
+
+    build_header(linker, table_data, (void *)(table_data->data + nfit_start),
+                 "NFIT", table_data->len - nfit_start, 1);
+exit:
+    g_slist_free(list);
+}
+
 static char *get_file(Object *obj, Error **errp)
 {
     PCNVDIMMDevice *nvdimm = PC_NVDIMM(obj);
diff --git a/include/hw/mem/pc-nvdimm.h b/include/hw/mem/pc-nvdimm.h
index e743ed1..74d989b 100644
--- a/include/hw/mem/pc-nvdimm.h
+++ b/include/hw/mem/pc-nvdimm.h
@@ -34,9 +34,17 @@ typedef struct PCNVDIMMDevice {
     OBJECT_CHECK(PCNVDIMMDevice, (obj), TYPE_PC_NVDIMM)
 
 void pc_nvdimm_reserve_range(ram_addr_t offset);
+void pc_nvdimm_build_nfit_table(GArray *table_offsets, GArray *table_data,
+                                GArray *linker);
 #else	/* !CONFIG_LINUX */
 static inline void pc_nvdimm_reserve_range(ram_addr_t offset)
 {
 }
+
+static inline void
+pc_nvdimm_build_nfit_table(GArray *table_offsets, GArray *table_data,
+                           GArray *linker)
+{
+}
 #endif
 #endif
-- 
2.1.0


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 09/16] nvdimm: build ACPI NFIT table
Date: Wed,  1 Jul 2015 22:50:25 +0800	[thread overview]
Message-ID: <1435762232-15543-10-git-send-email-guangrong.xiao@linux.intel.com> (raw)
In-Reply-To: <1435762232-15543-1-git-send-email-guangrong.xiao@linux.intel.com>

NFIT is defined in ACPI 6.0: 5.2.25 NVDIMM Firmware Interface Table (NFIT)

Currently, we only support PMEM mode. Each device has 3 tables:
- SPA table, define the PMEM region info

- MEM DEV table, it has the @handle which is used to associate specified
  ACPI NVDIMM  device we will introduce in later patch.
  Also we can happily ignored the memory device's interleave, the real
  nvdimm hardware access is hidden behind host

- DCR table, it defines Vendor ID used to associate specified vendor
  nvdimm driver. Since we only implement PMEM mode this time, Command
  window and Data window are not needed

Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
 hw/i386/acpi-build.c       |   3 +
 hw/mem/pc-nvdimm.c         | 286 +++++++++++++++++++++++++++++++++++++++++++++
 include/hw/mem/pc-nvdimm.h |   8 ++
 3 files changed, 297 insertions(+)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 6a1ab09..80c21be 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -39,6 +39,7 @@
 #include "hw/loader.h"
 #include "hw/isa/isa.h"
 #include "hw/acpi/memory_hotplug.h"
+#include "hw/mem/pc-nvdimm.h"
 #include "sysemu/tpm.h"
 #include "hw/acpi/tpm.h"
 #include "sysemu/tpm_backend.h"
@@ -1741,6 +1742,8 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
         build_dmar_q35(tables_blob, tables->linker);
     }
 
+    pc_nvdimm_build_nfit_table(table_offsets, tables_blob, tables->linker);
+
     /* Add tables supplied by user (if any) */
     for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
         unsigned len = acpi_table_len(u);
diff --git a/hw/mem/pc-nvdimm.c b/hw/mem/pc-nvdimm.c
index 9531935..e7cff29 100644
--- a/hw/mem/pc-nvdimm.c
+++ b/hw/mem/pc-nvdimm.c
@@ -27,10 +27,12 @@
 #include <linux/fs.h>
 
 #include "exec/address-spaces.h"
+#include "hw/acpi/aml-build.h"
 #include "hw/mem/pc-nvdimm.h"
 
 #define PAGE_SIZE               (1UL << 12)
 
+#define MAX_NVDIMM_NUMBER       (10)
 #define MIN_CONFIG_DATA_SIZE    (128 << 10)
 
 static struct nvdimms_info {
@@ -65,6 +67,290 @@ static uint32_t new_device_index(void)
     return nvdimms_info.device_index++;
 }
 
+static int pc_nvdimm_built_list(Object *obj, void *opaque)
+{
+    GSList **list = opaque;
+
+    if (object_dynamic_cast(obj, TYPE_PC_NVDIMM)) {
+        PCNVDIMMDevice *nvdimm = PC_NVDIMM(obj);
+
+        /* only realized NVDIMMs matter */
+        if (memory_region_size(&nvdimm->mr)) {
+            *list = g_slist_append(*list, nvdimm);
+        }
+    }
+
+    object_child_foreach(obj, pc_nvdimm_built_list, opaque);
+    return 0;
+}
+
+static GSList *get_nvdimm_built_list(void)
+{
+    GSList *list = NULL;
+
+    object_child_foreach(qdev_get_machine(), pc_nvdimm_built_list, &list);
+    return list;
+}
+
+static int get_nvdimm_device_number(GSList *list)
+{
+    int nr = 0;
+
+    for (; list; list = list->next) {
+        nr++;
+    }
+
+    return nr;
+}
+
+static uint32_t nvdimm_index_to_sn(int index)
+{
+    return 0x123456 + index;
+}
+
+static uint32_t nvdimm_index_to_handle(int index)
+{
+    return index + 1;
+}
+
+typedef struct {
+    uint8_t b[16];
+} uuid_le;
+
+#define UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)                   \
+((uuid_le)                                                                 \
+{ { (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
+    (b) & 0xff, ((b) >> 8) & 0xff, (c) & 0xff, ((c) >> 8) & 0xff,          \
+    (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) } })
+
+static void nfit_spa_uuid_pm(void *uuid)
+{
+    uuid_le uuid_pm = UUID_LE(0x66f0d379, 0xb4f3, 0x4074, 0xac, 0x43, 0x0d,
+                              0x33, 0x18, 0xb7, 0x8c, 0xdb);
+    memcpy(uuid, &uuid_pm, sizeof(uuid_pm));
+}
+
+enum {
+    NFIT_TABLE_SPA = 0,
+    NFIT_TABLE_MEM = 1,
+    NFIT_TABLE_IDT = 2,
+    NFIT_TABLE_SMBIOS = 3,
+    NFIT_TABLE_DCR = 4,
+    NFIT_TABLE_BDW = 5,
+    NFIT_TABLE_FLUSH = 6,
+};
+
+enum {
+    EFI_MEMORY_UC = 0x1ULL,
+    EFI_MEMORY_WC = 0x2ULL,
+    EFI_MEMORY_WT = 0x4ULL,
+    EFI_MEMORY_WB = 0x8ULL,
+    EFI_MEMORY_UCE = 0x10ULL,
+    EFI_MEMORY_WP = 0x1000ULL,
+    EFI_MEMORY_RP = 0x2000ULL,
+    EFI_MEMORY_XP = 0x4000ULL,
+    EFI_MEMORY_NV = 0x8000ULL,
+    EFI_MEMORY_MORE_RELIABLE = 0x10000ULL,
+};
+
+/*
+ * struct nfit - Nvdimm Firmware Interface Table
+ * @signature: "NFIT"
+ */
+struct nfit {
+    ACPI_TABLE_HEADER_DEF
+    uint32_t reserved;
+} QEMU_PACKED;
+
+/*
+ * struct nfit_spa - System Physical Address Range Structure
+ */
+struct nfit_spa {
+    uint16_t type;
+    uint16_t length;
+    uint16_t spa_index;
+    uint16_t flags;
+    uint32_t reserved;
+    uint32_t proximity_domain;
+    uint8_t type_uuid[16];
+    uint64_t spa_base;
+    uint64_t spa_length;
+    uint64_t mem_attr;
+} QEMU_PACKED;
+
+/*
+ * struct nfit_memdev - Memory Device to SPA Map Structure
+ */
+struct nfit_memdev {
+    uint16_t type;
+    uint16_t length;
+    uint32_t nfit_handle;
+    uint16_t phys_id;
+    uint16_t region_id;
+    uint16_t spa_index;
+    uint16_t dcr_index;
+    uint64_t region_len;
+    uint64_t region_spa_offset;
+    uint64_t region_dpa;
+    uint16_t idt_index;
+    uint16_t interleave_ways;
+    uint16_t flags;
+    uint16_t reserved;
+} QEMU_PACKED;
+
+/*
+ * struct nfit_dcr - NVDIMM Control Region Structure
+ */
+struct nfit_dcr {
+    uint16_t type;
+    uint16_t length;
+    uint16_t dcr_index;
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint16_t revision_id;
+    uint16_t sub_vendor_id;
+    uint16_t sub_device_id;
+    uint16_t sub_revision_id;
+    uint8_t reserved[6];
+    uint32_t serial_number;
+    uint16_t fic;
+    uint16_t num_bcw;
+    uint64_t bcw_size;
+    uint64_t cmd_offset;
+    uint64_t cmd_size;
+    uint64_t status_offset;
+    uint64_t status_size;
+    uint16_t flags;
+    uint8_t reserved2[6];
+} QEMU_PACK;
+
+#define REVSISON_ID    1
+#define NFIT_FIC1      0x201
+
+static size_t get_nfit_total_size(int nr)
+{
+    /* each nvdimm has 3 tables. */
+    return sizeof(struct nfit) + nr * (sizeof(struct nfit_spa) +
+                  sizeof(struct nfit_memdev) + sizeof(struct nfit_dcr));
+}
+
+static int build_spa_table(void *buf, PCNVDIMMDevice *nvdimm, int spa_index)
+{
+    struct nfit_spa *nfit_spa;
+    uint64_t addr = object_property_get_int(OBJECT(&nvdimm->mr), "addr", NULL);
+
+    nfit_spa = (struct nfit_spa *)buf;
+
+    /*
+     * nfit_spa->flags is set to zero so that proximity_domain
+     * info is ignored.
+     */
+    nfit_spa->type = cpu_to_le16(NFIT_TABLE_SPA);
+    nfit_spa->length = cpu_to_le16(sizeof(*nfit_spa));
+    nfit_spa_uuid_pm(&nfit_spa->type_uuid);
+    nfit_spa->spa_index = cpu_to_le16(spa_index);
+    nfit_spa->spa_base = cpu_to_le64(addr);
+    nfit_spa->spa_length = cpu_to_le64(memory_region_size(&nvdimm->mr));
+    nfit_spa->mem_attr = cpu_to_le64(EFI_MEMORY_WB | EFI_MEMORY_NV);
+
+    return sizeof(*nfit_spa);
+}
+
+static int build_memdev_table(void *buf, PCNVDIMMDevice *nvdimm,
+                              int spa_index, int dcr_index)
+{
+    struct nfit_memdev *nfit_memdev;
+    uint64_t addr = object_property_get_int(OBJECT(&nvdimm->mr), "addr", NULL);
+    uint32_t handle = nvdimm_index_to_handle(nvdimm->device_index);
+
+    nfit_memdev = (struct nfit_memdev *)buf;
+    nfit_memdev->type = cpu_to_le16(NFIT_TABLE_MEM);
+    nfit_memdev->length = cpu_to_le16(sizeof(*nfit_memdev));
+    nfit_memdev->nfit_handle = cpu_to_le32(handle);
+    /* point to nfit_spa. */
+    nfit_memdev->spa_index = cpu_to_le16(spa_index);
+    /* point to nfit_dcr. */
+    nfit_memdev->dcr_index = cpu_to_le16(dcr_index);
+    nfit_memdev->region_len = cpu_to_le64(memory_region_size(&nvdimm->mr));
+    nfit_memdev->region_dpa = cpu_to_le64(addr);
+    /* Only one interleave for pmem. */
+    nfit_memdev->interleave_ways = cpu_to_le16(1);
+
+    return sizeof(*nfit_memdev);
+}
+
+static int build_dcr_table(void *buf, PCNVDIMMDevice *nvdimm, int dcr_index)
+{
+    struct nfit_dcr *nfit_dcr;
+    uint32_t sn = nvdimm_index_to_sn(nvdimm->device_index);
+
+    nfit_dcr = (struct nfit_dcr *)buf;
+    nfit_dcr->type = cpu_to_le16(NFIT_TABLE_DCR);
+    nfit_dcr->length = cpu_to_le16(sizeof(*nfit_dcr));
+    nfit_dcr->dcr_index = cpu_to_le16(dcr_index);
+    nfit_dcr->vendor_id = cpu_to_le16(0x8086);
+    nfit_dcr->device_id = cpu_to_le16(1);
+    nfit_dcr->revision_id = cpu_to_le16(REVSISON_ID);
+    nfit_dcr->serial_number = cpu_to_le32(sn);
+    nfit_dcr->fic = cpu_to_le16(NFIT_FIC1);
+
+    return sizeof(*nfit_dcr);
+}
+
+static void build_nfit_table(GSList *device_list, char *buf)
+{
+    int index = 0;
+
+    buf += sizeof(struct nfit);
+
+    for (; device_list; device_list = device_list->next) {
+        PCNVDIMMDevice *nvdimm = device_list->data;
+        int spa_index, dcr_index;
+
+        spa_index = ++index;
+        dcr_index = ++index;
+
+        /* build System Physical Address Range Description Table. */
+        buf += build_spa_table(buf, nvdimm, spa_index);
+
+        /*
+         * build Memory Device to System Physical Address Range Mapping
+         * Table.
+         */
+        buf += build_memdev_table(buf, nvdimm, spa_index, dcr_index);
+
+        /* build Control Region Descriptor Table. */
+        buf += build_dcr_table(buf, nvdimm, dcr_index);
+    }
+}
+
+void pc_nvdimm_build_nfit_table(GArray *table_offsets, GArray *table_data,
+                                GArray *linker)
+{
+    GSList *list = get_nvdimm_built_list();
+    size_t total;
+    char *buf;
+    int nfit_start, nr;
+
+    nr = get_nvdimm_device_number(list);
+    total = get_nfit_total_size(nr);
+
+    if (nr <= 0 || nr > MAX_NVDIMM_NUMBER) {
+        goto exit;
+    }
+
+    nfit_start = table_data->len;
+    acpi_add_table(table_offsets, table_data);
+
+    buf = acpi_data_push(table_data, total);
+    build_nfit_table(list, buf);
+
+    build_header(linker, table_data, (void *)(table_data->data + nfit_start),
+                 "NFIT", table_data->len - nfit_start, 1);
+exit:
+    g_slist_free(list);
+}
+
 static char *get_file(Object *obj, Error **errp)
 {
     PCNVDIMMDevice *nvdimm = PC_NVDIMM(obj);
diff --git a/include/hw/mem/pc-nvdimm.h b/include/hw/mem/pc-nvdimm.h
index e743ed1..74d989b 100644
--- a/include/hw/mem/pc-nvdimm.h
+++ b/include/hw/mem/pc-nvdimm.h
@@ -34,9 +34,17 @@ typedef struct PCNVDIMMDevice {
     OBJECT_CHECK(PCNVDIMMDevice, (obj), TYPE_PC_NVDIMM)
 
 void pc_nvdimm_reserve_range(ram_addr_t offset);
+void pc_nvdimm_build_nfit_table(GArray *table_offsets, GArray *table_data,
+                                GArray *linker);
 #else	/* !CONFIG_LINUX */
 static inline void pc_nvdimm_reserve_range(ram_addr_t offset)
 {
 }
+
+static inline void
+pc_nvdimm_build_nfit_table(GArray *table_offsets, GArray *table_data,
+                           GArray *linker)
+{
+}
 #endif
 #endif
-- 
2.1.0

  parent reply	other threads:[~2015-07-01 14:55 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-07-01 14:50 [PATCH 00/16] implement vNVDIMM Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 01/16] acpi: allow aml_operation_region() working on 64 bit offset Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 02/16] i386/acpi-build: allow SSDT to operate on 64 bit Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 03/16] acpi: add aml_derefof Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 04/16] acpi: add aml_sizeof Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 05/16] acpi: add aml_create_field Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 06/16] pc: implement NVDIMM device abstract Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 07/16] nvdimm: reserve address range for NVDIMM Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 08/16] nvdimm: init backend memory mapping and config data area Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` Xiao Guangrong [this message]
2015-07-01 14:50   ` [Qemu-devel] [PATCH 09/16] nvdimm: build ACPI NFIT table Xiao Guangrong
2015-07-01 14:50 ` [PATCH 10/16] nvdimm: init the address region used by _DSM method Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 11/16] nvdimm: build ACPI nvdimm devices Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 12/16] nvdimm: save arg3 for NVDIMM device _DSM method Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 13/16] nvdimm: support NFIT_CMD_IMPLEMENTED function Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 14/16] nvdimm: support NFIT_CMD_GET_CONFIG_SIZE function Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-02  9:23   ` Stefan Hajnoczi
2015-07-02  9:23     ` [Qemu-devel] " Stefan Hajnoczi
2015-07-02 18:02     ` Xiao Guangrong
2015-07-02 18:02       ` Xiao Guangrong
2015-07-01 14:50 ` [PATCH 15/16] nvdimm: support NFIT_CMD_GET_CONFIG_DATA Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-01 14:50 ` [PATCH 16/16] nvdimm: support NFIT_CMD_SET_CONFIG_DATA Xiao Guangrong
2015-07-01 14:50   ` [Qemu-devel] " Xiao Guangrong
2015-07-02  6:17 ` [PATCH 00/16] implement vNVDIMM Michael S. Tsirkin
2015-07-02  6:17   ` [Qemu-devel] " Michael S. Tsirkin
2015-07-02  6:34   ` Xiao Guangrong
2015-07-02  6:34     ` [Qemu-devel] " Xiao Guangrong
2015-07-02  8:31     ` Stefan Hajnoczi
2015-07-02  8:31       ` Stefan Hajnoczi
2015-07-02  8:35       ` Michael S. Tsirkin
2015-07-02  8:35         ` Michael S. Tsirkin
2015-07-02  9:20 ` Stefan Hajnoczi
2015-07-02  9:20   ` Stefan Hajnoczi
2015-07-02  9:52   ` Paolo Bonzini
2015-07-02  9:52     ` Paolo Bonzini
2015-07-02 18:01     ` Xiao Guangrong
2015-07-02 18:01       ` [Qemu-devel] " Xiao Guangrong
2015-07-02 18:11       ` Paolo Bonzini
2015-07-02 18:11         ` Paolo Bonzini
2015-07-29  8:41         ` Xiao Guangrong

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=1435762232-15543-10-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.