* [Qemu-devel] [PATCH 00/16] implement vNVDIMM
@ 2015-07-01 14:50 Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 01/16] acpi: allow aml_operation_region() working on 64 bit offset Xiao Guangrong
` (17 more replies)
0 siblings, 18 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
====== Background ======
NVDIMM (A Non-Volatile Dual In-line Memory Module) is going to be supported
on Intel's platform. They are discovered via ACPI and configured by _DSM
method of NVDIMM device in ACPI. There has some supporting documents which
can be found at:
ACPI 6: http://www.uefi.org/sites/default/files/resources/ACPI_6.0.pdf
NVDIMM Namespace: http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf
DSM Interface Example: http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
Driver Writer's Guide: http://pmem.io/documents/NVDIMM_Driver_Writers_Guide.pdf
Currently, the NVDIMM driver has been merged into upstream Linux Kernel and
this patchset tries to enable it in virtualization field
====== Design ======
NVDIMM supports two mode accesses, one is PMEM which maps NVDIMM into CPU's
address space then CPU can directly access it as normal memory, another is
BLK which is used as block device to reduce the occupying of CPU address
space
BLK mode accesses NVDIMM via Command Register window and Data Register window.
BLK virtualization has high workload since each sector access will cause at
least two VM-EXIT. So we currently only imperilment vPMEM in this patchset
--- vPMEM design ---
We introduce a new device named "pc-nvdimm", it has a parameter, file, which
is the file-based backed memory passed to guest. The file can be regular file
and block device. We can use any file when we do test or emulation, however,
in the real word, the files passed to guest are:
- the regular file in the filesystem with DAX enabled created on NVDIMM device
on host
- the raw PMEM device on host, e,g /dev/pmem0
Memory access on the address created by mmap on these kinds of files can
directly reach NVDIMM device on host.
--- vConfigure data area design ---
Each NVDIMM device has a configure data area which is used to store label
namespace data. In order to emulating this area, we divide the file into two
parts:
- first parts is (0, size - 128K], which is used as PMEM
- 128K at the end of the file, which is used as Config Data Area
So that the label namespace data can be persistent during power lose or system
failure
--- _DSM method design ---
_DSM in ACPI is used to configure NVDIMM, currently we only allow access of
label namespace data, i.e, Get Namespace Label Size (Function Index 4),
Get Namespace Label Data (Function Index 5) and Set Namespace Label Data
(Function Index 6)
_DSM uses two pages to transfer data between ACPI and Qemu, the first page
is RAM-based used to save the input info of _DSM method and Qemu reuse it
store output info and another page is MMIO-based, ACPI write data to this
page to transfer the control to Qemu
We use the address region above 4G to map these pages because there is huge
free space above 4G and it can avoid the address overlap with PCI and other
address reserved component (e,g HPET). This is also the reason we choose MMIO
notification instead of PIO
====== Test ======
In host
1) create memory backed file, e.g # dd if=zero of=/tmp/nvdimm bs=1G count=10
2) append '-device pc-nvdimm,file=/tmp/nvdimm' in Qemu command line
In guest, download the latest upsteam kernel (4.2 merge window) and enable
ACPI_NFIT, LIBNVDIMM and BLK_DEV_PMEM.
1) insmod drivers/nvdimm/libnvdimm.ko
2) insmod drivers/acpi/nfit.ko
3) insmod drivers/nvdimm/nd_btt.ko
4) insmod drivers/nvdimm/nd_pmem.ko
You can see the whole nvdimm device used as a single namespace and /dev/pmem0
appears. You can do whatever on /dev/pmem0 including DAX access.
Currently Linux NVDIMM driver does not support namespace operation on this
kind of PMEM, apply below changes to support dynamical namespace:
@@ -798,7 +823,8 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *a
continue;
}
- if (nfit_mem->bdw && nfit_mem->memdev_pmem)
+ //if (nfit_mem->bdw && nfit_mem->memdev_pmem)
+ if (nfit_mem->memdev_pmem)
flags |= NDD_ALIASING;
You can append another NVDIMM device in guest and do:
# cd /sys/bus/nd/devices/
# cd namespace1.0/
# echo `uuidgen` > uuid
# echo `expr 1024 \* 1024 \* 128` > size
then reload nd.pmem.ko
You can see /dev/pmem1 appears
====== TODO ======
1) NVDIMM NUMA support
2) NVDIMM hotplug support
Xiao Guangrong (16):
acpi: allow aml_operation_region() working on 64 bit offset
i386/acpi-build: allow SSDT to operate on 64 bit
acpi: add aml_derefof
acpi: add aml_sizeof
acpi: add aml_create_field
pc: implement NVDIMM device abstract
nvdimm: reserve address range for NVDIMM
nvdimm: init backend memory mapping and config data area
nvdimm: build ACPI NFIT table
nvdimm: init the address region used by _DSM method
nvdimm: build ACPI nvdimm devices
nvdimm: save arg3 for NVDIMM device _DSM method
nvdimm: support NFIT_CMD_IMPLEMENTED function
nvdimm: support NFIT_CMD_GET_CONFIG_SIZE function
nvdimm: support NFIT_CMD_GET_CONFIG_DATA
nvdimm: support NFIT_CMD_SET_CONFIG_DATA
hw/acpi/aml-build.c | 32 +-
hw/i386/acpi-build.c | 9 +-
hw/i386/acpi-dsdt.dsl | 2 +-
hw/i386/pc.c | 11 +-
hw/mem/Makefile.objs | 1 +
hw/mem/pc-nvdimm.c | 1040 +++++++++++++++++++++++++++++++++++++++++++
include/hw/acpi/aml-build.h | 5 +-
include/hw/mem/pc-nvdimm.h | 56 +++
8 files changed, 1149 insertions(+), 7 deletions(-)
create mode 100644 hw/mem/pc-nvdimm.c
create mode 100644 include/hw/mem/pc-nvdimm.h
--
2.1.0
^ permalink raw reply [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 01/16] acpi: allow aml_operation_region() working on 64 bit offset
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 02/16] i386/acpi-build: allow SSDT to operate on 64 bit Xiao Guangrong
` (16 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
Currently, the offset in OperationRegion is limited to 32 bit, extend it
to 64 bit so that we can switch SSDT to 64 bit in later patch
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/acpi/aml-build.c | 2 +-
include/hw/acpi/aml-build.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 0d4b324..02f9e3d 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -752,7 +752,7 @@ Aml *aml_package(uint8_t num_elements)
/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefOpRegion */
Aml *aml_operation_region(const char *name, AmlRegionSpace rs,
- uint32_t offset, uint32_t len)
+ uint64_t offset, uint32_t len)
{
Aml *var = aml_alloc();
build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index e3afa13..996ac5b 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -222,7 +222,7 @@ Aml *aml_interrupt(AmlConsumerAndProducer con_and_pro,
Aml *aml_io(AmlIODecode dec, uint16_t min_base, uint16_t max_base,
uint8_t aln, uint8_t len);
Aml *aml_operation_region(const char *name, AmlRegionSpace rs,
- uint32_t offset, uint32_t len);
+ uint64_t offset, uint32_t len);
Aml *aml_irq_no_flags(uint8_t irq);
Aml *aml_named_field(const char *name, unsigned length);
Aml *aml_reserved_field(unsigned length);
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 02/16] i386/acpi-build: allow SSDT to operate on 64 bit
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 01/16] acpi: allow aml_operation_region() working on 64 bit offset Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 03/16] acpi: add aml_derefof Xiao Guangrong
` (15 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
Only 512M is left for MMIO below 4G and that are used by PCI, BIOS etc.
Other components also reserve regions from their internal usage, e.g,
[0xFED00000, 0xFED00000 + 0x400) is reserved for HPET
Switch SSDT to 64 bit to use the huge free room above 4G. In the later
patches, we will dynamical allocate free space within this region which
is used by NVDIMM _DSM method
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/i386/acpi-build.c | 4 ++--
hw/i386/acpi-dsdt.dsl | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 00818b9..6a1ab09 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1348,7 +1348,7 @@ build_ssdt(GArray *table_data, GArray *linker,
g_array_append_vals(table_data, ssdt->buf->data, ssdt->buf->len);
build_header(linker, table_data,
(void *)(table_data->data + table_data->len - ssdt->buf->len),
- "SSDT", ssdt->buf->len, 1);
+ "SSDT", ssdt->buf->len, 2);
free_aml_allocator();
}
@@ -1586,7 +1586,7 @@ build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc)
memset(dsdt, 0, sizeof *dsdt);
build_header(linker, table_data, dsdt, "DSDT",
- misc->dsdt_size, 1);
+ misc->dsdt_size, 2);
}
static GArray *
diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl
index a2d84ec..5cd3f0e 100644
--- a/hw/i386/acpi-dsdt.dsl
+++ b/hw/i386/acpi-dsdt.dsl
@@ -22,7 +22,7 @@ ACPI_EXTRACT_ALL_CODE AcpiDsdtAmlCode
DefinitionBlock (
"acpi-dsdt.aml", // Output Filename
"DSDT", // Signature
- 0x01, // DSDT Compliance Revision
+ 0x02, // DSDT Compliance Revision
"BXPC", // OEMID
"BXDSDT", // TABLE ID
0x1 // OEM Revision
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 03/16] acpi: add aml_derefof
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 01/16] acpi: allow aml_operation_region() working on 64 bit offset Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 02/16] i386/acpi-build: allow SSDT to operate on 64 bit Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 04/16] acpi: add aml_sizeof Xiao Guangrong
` (14 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
Implement DeRefOf term which is used by NVDIMM _DSM method in later patch
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/acpi/aml-build.c | 8 ++++++++
include/hw/acpi/aml-build.h | 1 +
2 files changed, 9 insertions(+)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 02f9e3d..9e89efc 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1135,6 +1135,14 @@ Aml *aml_unicode(const char *str)
return var;
}
+/* ACPI 6.0: 20.2.5.4 Type 2 Opcodes Encoding: DefDerefOf */
+Aml *aml_derefof(Aml *arg)
+{
+ Aml *var = aml_opcode(0x83 /* DerefOfOp */);
+ aml_append(var, arg);
+ return var;
+}
+
void
build_header(GArray *linker, GArray *table_data,
AcpiTableHeader *h, const char *sig, int len, uint8_t rev)
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 996ac5b..21dc5e9 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -275,6 +275,7 @@ Aml *aml_create_dword_field(Aml *srcbuf, Aml *index, const char *name);
Aml *aml_varpackage(uint32_t num_elements);
Aml *aml_touuid(const char *uuid);
Aml *aml_unicode(const char *str);
+Aml *aml_derefof(Aml *arg);
void
build_header(GArray *linker, GArray *table_data,
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 04/16] acpi: add aml_sizeof
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (2 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 03/16] acpi: add aml_derefof Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 05/16] acpi: add aml_create_field Xiao Guangrong
` (13 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
Implement SizeOf term which is used by NVDIMM _DSM method in later patch
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/acpi/aml-build.c | 8 ++++++++
include/hw/acpi/aml-build.h | 1 +
2 files changed, 9 insertions(+)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 9e89efc..a526eed 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1143,6 +1143,14 @@ Aml *aml_derefof(Aml *arg)
return var;
}
+/* ACPI 6.0: 20.2.5.4 Type 2 Opcodes Encoding: DefSizeOf */
+Aml *aml_sizeof(Aml *arg)
+{
+ Aml *var = aml_opcode(0x87 /* SizeOfOp */);
+ aml_append(var, arg);
+ return var;
+}
+
void
build_header(GArray *linker, GArray *table_data,
AcpiTableHeader *h, const char *sig, int len, uint8_t rev)
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 21dc5e9..6b591ab 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -276,6 +276,7 @@ Aml *aml_varpackage(uint32_t num_elements);
Aml *aml_touuid(const char *uuid);
Aml *aml_unicode(const char *str);
Aml *aml_derefof(Aml *arg);
+Aml *aml_sizeof(Aml *arg);
void
build_header(GArray *linker, GArray *table_data,
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 05/16] acpi: add aml_create_field
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (3 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 04/16] acpi: add aml_sizeof Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 06/16] pc: implement NVDIMM device abstract Xiao Guangrong
` (12 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
Implement CreateField term which are used by NVDIMM _DSM method in later patch
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/acpi/aml-build.c | 14 ++++++++++++++
include/hw/acpi/aml-build.h | 1 +
2 files changed, 15 insertions(+)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index a526eed..debdad2 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1151,6 +1151,20 @@ Aml *aml_sizeof(Aml *arg)
return var;
}
+/* ACPI 6.0: 20.2.5.2 Named Objects Encoding: DefCreateField */
+Aml *aml_create_field(Aml *srcbuf, Aml *index, Aml *len, const char *name)
+{
+ Aml *var = aml_alloc();
+
+ build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */
+ build_append_byte(var->buf, 0x13); /* CreateFieldOp */
+ aml_append(var, srcbuf);
+ aml_append(var, index);
+ aml_append(var, len);
+ build_append_namestring(var->buf, "%s", name);
+ return var;
+}
+
void
build_header(GArray *linker, GArray *table_data,
AcpiTableHeader *h, const char *sig, int len, uint8_t rev)
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 6b591ab..d4dbd44 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -277,6 +277,7 @@ Aml *aml_touuid(const char *uuid);
Aml *aml_unicode(const char *str);
Aml *aml_derefof(Aml *arg);
Aml *aml_sizeof(Aml *arg);
+Aml *aml_create_field(Aml *srcbuf, Aml *index, Aml *len, const char *name);
void
build_header(GArray *linker, GArray *table_data,
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 06/16] pc: implement NVDIMM device abstract
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (4 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 05/16] acpi: add aml_create_field Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 07/16] nvdimm: reserve address range for NVDIMM Xiao Guangrong
` (11 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
Introduce "pc-nvdimm" device and it only has one parameter, @file, which
is the backed memory file for NVDIMM device
We can use "-device pc-nvdimm,file=/dev/pmem" in the Qemu command to
create NVDIMM device for the guest
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/mem/Makefile.objs | 1 +
hw/mem/pc-nvdimm.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++
include/hw/mem/pc-nvdimm.h | 32 ++++++++++++++++++
3 files changed, 116 insertions(+)
create mode 100644 hw/mem/pc-nvdimm.c
create mode 100644 include/hw/mem/pc-nvdimm.h
diff --git a/hw/mem/Makefile.objs b/hw/mem/Makefile.objs
index b000fb4..9a7f5a9 100644
--- a/hw/mem/Makefile.objs
+++ b/hw/mem/Makefile.objs
@@ -1 +1,2 @@
common-obj-$(CONFIG_MEM_HOTPLUG) += pc-dimm.o
+common-obj-$(CONFIG_LINUX) += pc-nvdimm.o
diff --git a/hw/mem/pc-nvdimm.c b/hw/mem/pc-nvdimm.c
new file mode 100644
index 0000000..0209ea9
--- /dev/null
+++ b/hw/mem/pc-nvdimm.c
@@ -0,0 +1,83 @@
+/*
+ * NVDIMM (A Non-Volatile Dual In-line Memory Module) Virtualization Implement
+ *
+ * Copyright(C) 2015 Intel Corporation.
+ *
+ * Author:
+ * Xiao Guangrong <guangrong.xiao@linux.intel.com>
+ *
+ * Currently, it only supports PMEM Virtualization.
+ *
+ * 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"
+
+static char *get_file(Object *obj, Error **errp)
+{
+ PCNVDIMMDevice *nvdimm = PC_NVDIMM(obj);
+
+ return g_strdup(nvdimm->file);
+}
+
+static void set_file(Object *obj, const char *str, Error **errp)
+{
+ PCNVDIMMDevice *nvdimm = PC_NVDIMM(obj);
+
+ if (nvdimm->file) {
+ g_free(nvdimm->file);
+ }
+
+ nvdimm->file = g_strdup(str);
+}
+
+static void pc_nvdimm_init(Object *obj)
+{
+ object_property_add_str(obj, "file", get_file, set_file, NULL);
+}
+
+static void pc_nvdimm_realize(DeviceState *dev, Error **errp)
+{
+ PCNVDIMMDevice *nvdimm = PC_NVDIMM(dev);
+
+ if (!nvdimm->file) {
+ error_setg(errp, "file property is not set");
+ }
+}
+
+static void pc_nvdimm_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ /* nvdimm hotplug has not supported yet. */
+ dc->hotpluggable = false;
+
+ dc->realize = pc_nvdimm_realize;
+ dc->desc = "NVDIMM memory module";
+}
+
+static TypeInfo pc_nvdimm_info = {
+ .name = TYPE_PC_NVDIMM,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(PCNVDIMMDevice),
+ .instance_init = pc_nvdimm_init,
+ .class_init = pc_nvdimm_class_init,
+};
+
+static void pc_nvdimm_register_types(void)
+{
+ type_register_static(&pc_nvdimm_info);
+}
+
+type_init(pc_nvdimm_register_types)
diff --git a/include/hw/mem/pc-nvdimm.h b/include/hw/mem/pc-nvdimm.h
new file mode 100644
index 0000000..7f37b46
--- /dev/null
+++ b/include/hw/mem/pc-nvdimm.h
@@ -0,0 +1,32 @@
+/*
+ * NVDIMM (A Non-Volatile Dual In-line Memory Module) Virtualization Implement
+ *
+ * Copyright(C) 2015 Intel Corporation.
+ *
+ * Author:
+ * Xiao Guangrong <guangrong.xiao@linux.intel.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef __PC_NVDIMM_H
+#define __PC_NVDIMM_H
+
+#include "hw/qdev.h"
+
+#ifdef CONFIG_LINUX
+typedef struct PCNVDIMMDevice {
+ /* private */
+ DeviceState parent_obj;
+
+ char *file;
+} PCNVDIMMDevice;
+
+#define TYPE_PC_NVDIMM "pc-nvdimm"
+
+#define PC_NVDIMM(obj) \
+ OBJECT_CHECK(PCNVDIMMDevice, (obj), TYPE_PC_NVDIMM)
+#else /* !CONFIG_LINUX */
+#endif
+#endif
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 07/16] nvdimm: reserve address range for NVDIMM
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (5 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 06/16] pc: implement NVDIMM device abstract Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 08/16] nvdimm: init backend memory mapping and config data area Xiao Guangrong
` (10 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
NVDIMM reserves all the free range above 4G to do:
- Persistent Memory (PMEM) mapping
- implement NVDIMM ACPI device _DSM method
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/i386/pc.c | 11 +++++++++--
hw/mem/pc-nvdimm.c | 13 +++++++++++++
include/hw/mem/pc-nvdimm.h | 5 +++++
3 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 7072930..82e80a9 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -64,6 +64,7 @@
#include "hw/pci/pci_host.h"
#include "acpi-build.h"
#include "hw/mem/pc-dimm.h"
+#include "hw/mem/pc-nvdimm.h"
#include "trace.h"
#include "qapi/visitor.h"
#include "qapi-visit.h"
@@ -1241,6 +1242,7 @@ FWCfgState *pc_memory_init(MachineState *machine,
MemoryRegion *ram_below_4g, *ram_above_4g;
FWCfgState *fw_cfg;
PCMachineState *pcms = PC_MACHINE(machine);
+ ram_addr_t offset;
assert(machine->ram_size == below_4g_mem_size + above_4g_mem_size);
@@ -1278,6 +1280,8 @@ FWCfgState *pc_memory_init(MachineState *machine,
exit(EXIT_FAILURE);
}
+ offset = 0x100000000ULL + above_4g_mem_size;
+
/* initialize hotplug memory address space */
if (guest_info->has_reserved_memory &&
(machine->ram_size < machine->maxram_size)) {
@@ -1297,8 +1301,7 @@ FWCfgState *pc_memory_init(MachineState *machine,
exit(EXIT_FAILURE);
}
- pcms->hotplug_memory_base =
- ROUND_UP(0x100000000ULL + above_4g_mem_size, 1ULL << 30);
+ pcms->hotplug_memory_base = ROUND_UP(offset, 1ULL << 30);
if (pcms->enforce_aligned_dimm) {
/* size hotplug region assuming 1G page max alignment per slot */
@@ -1316,8 +1319,12 @@ FWCfgState *pc_memory_init(MachineState *machine,
"hotplug-memory", hotplug_mem_size);
memory_region_add_subregion(system_memory, pcms->hotplug_memory_base,
&pcms->hotplug_memory);
+ offset = pcms->hotplug_memory_base + hotplug_mem_size;
}
+ /* all the space left above 4G is reserved for NVDIMM. */
+ pc_nvdimm_reserve_range(offset);
+
/* Initialize PC system firmware */
pc_system_firmware_init(rom_memory, guest_info->isapc_ram_fw);
diff --git a/hw/mem/pc-nvdimm.c b/hw/mem/pc-nvdimm.c
index 0209ea9..b40d4e7 100644
--- a/hw/mem/pc-nvdimm.c
+++ b/hw/mem/pc-nvdimm.c
@@ -24,6 +24,19 @@
#include "hw/mem/pc-nvdimm.h"
+#define PAGE_SIZE (1UL << 12)
+
+static struct nvdimms_info {
+ ram_addr_t current_addr;
+} nvdimms_info;
+
+/* the address range [offset, ~0ULL) is reserved for NVDIMM. */
+void pc_nvdimm_reserve_range(ram_addr_t offset)
+{
+ offset = ROUND_UP(offset, PAGE_SIZE);
+ nvdimms_info.current_addr = offset;
+}
+
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 7f37b46..2081e7c 100644
--- a/include/hw/mem/pc-nvdimm.h
+++ b/include/hw/mem/pc-nvdimm.h
@@ -27,6 +27,11 @@ typedef struct PCNVDIMMDevice {
#define PC_NVDIMM(obj) \
OBJECT_CHECK(PCNVDIMMDevice, (obj), TYPE_PC_NVDIMM)
+
+void pc_nvdimm_reserve_range(ram_addr_t offset);
#else /* !CONFIG_LINUX */
+static inline void pc_nvdimm_reserve_range(ram_addr_t offset)
+{
+}
#endif
#endif
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 08/16] nvdimm: init backend memory mapping and config data area
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (6 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 07/16] nvdimm: reserve address range for NVDIMM Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 09/16] nvdimm: build ACPI NFIT table Xiao Guangrong
` (9 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
The parameter @file is used as backed memory for NVDIMM which is
divided into two parts:
- first parts is (0, size - 128K], which is used as PMEM (Persistent
Memory)
- 128K at the end of the file, which is used as Config Data Area, it's
used to store Label namespace data
The @file supports both regular file and block device, of course we
can assign any these two kinds of files for test and emulation, however,
in the real word for performance reason, we usually used these files as
NVDIMM backed file:
- the regular file in the filesystem with DAX enabled created on NVDIMM
device on host
- the raw PMEM device on host, e,g /dev/pmem0
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/mem/pc-nvdimm.c | 102 ++++++++++++++++++++++++++++++++++++++++++++-
include/hw/mem/pc-nvdimm.h | 5 +++
2 files changed, 106 insertions(+), 1 deletion(-)
diff --git a/hw/mem/pc-nvdimm.c b/hw/mem/pc-nvdimm.c
index b40d4e7..9531935 100644
--- a/hw/mem/pc-nvdimm.c
+++ b/hw/mem/pc-nvdimm.c
@@ -22,12 +22,20 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+
+#include "exec/address-spaces.h"
#include "hw/mem/pc-nvdimm.h"
-#define PAGE_SIZE (1UL << 12)
+#define PAGE_SIZE (1UL << 12)
+
+#define MIN_CONFIG_DATA_SIZE (128 << 10)
static struct nvdimms_info {
ram_addr_t current_addr;
+ int device_index;
} nvdimms_info;
/* the address range [offset, ~0ULL) is reserved for NVDIMM. */
@@ -37,6 +45,26 @@ void pc_nvdimm_reserve_range(ram_addr_t offset)
nvdimms_info.current_addr = offset;
}
+static ram_addr_t reserved_range_push(uint64_t size)
+{
+ uint64_t current;
+
+ current = ROUND_UP(nvdimms_info.current_addr, PAGE_SIZE);
+
+ /* do not have enough space? */
+ if (current + size < current) {
+ return 0;
+ }
+
+ nvdimms_info.current_addr = current + size;
+ return current;
+}
+
+static uint32_t new_device_index(void)
+{
+ return nvdimms_info.device_index++;
+}
+
static char *get_file(Object *obj, Error **errp)
{
PCNVDIMMDevice *nvdimm = PC_NVDIMM(obj);
@@ -48,6 +76,11 @@ static void set_file(Object *obj, const char *str, Error **errp)
{
PCNVDIMMDevice *nvdimm = PC_NVDIMM(obj);
+ if (memory_region_size(&nvdimm->mr)) {
+ error_setg(errp, "cannot change property value");
+ return;
+ }
+
if (nvdimm->file) {
g_free(nvdimm->file);
}
@@ -60,13 +93,80 @@ static void pc_nvdimm_init(Object *obj)
object_property_add_str(obj, "file", get_file, set_file, NULL);
}
+static uint64_t get_file_size(int fd)
+{
+ struct stat stat_buf;
+ uint64_t size;
+
+ if (fstat(fd, &stat_buf) < 0) {
+ return 0;
+ }
+
+ if (S_ISREG(stat_buf.st_mode)) {
+ return stat_buf.st_size;
+ }
+
+ if (S_ISBLK(stat_buf.st_mode) && !ioctl(fd, BLKGETSIZE64, &size)) {
+ return size;
+ }
+
+ return 0;
+}
+
static void pc_nvdimm_realize(DeviceState *dev, Error **errp)
{
PCNVDIMMDevice *nvdimm = PC_NVDIMM(dev);
+ char name[512];
+ void *buf;
+ ram_addr_t addr;
+ uint64_t size;
+ int fd;
if (!nvdimm->file) {
error_setg(errp, "file property is not set");
}
+
+ fd = open(nvdimm->file, O_RDWR);
+ if (fd < 0) {
+ error_setg(errp, "can not open %s", nvdimm->file);
+ return;
+ }
+
+ /* reserve MIN_CONFIGDATA_AREA_SIZE for configue data */
+ size = get_file_size(fd) - MIN_CONFIG_DATA_SIZE;
+ if ((int64_t)size <= 0) {
+ error_setg(errp, "file size is too small to store NVDIMM"
+ " configure data");
+ goto do_close;
+ }
+
+ buf = mmap(NULL, size + MIN_CONFIG_DATA_SIZE, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if (buf == MAP_FAILED) {
+ error_setg(errp, "can not do mmap on %s", nvdimm->file);
+ goto do_close;
+ }
+
+ addr = reserved_range_push(size);
+ if (!addr) {
+ error_setg(errp, "do not have enough space for size %#lx.\n", size);
+ goto do_unmap;
+ }
+
+ nvdimm->device_index = new_device_index();
+ sprintf(name, "NVDIMM-%d", nvdimm->device_index);
+ memory_region_init_ram_ptr(&nvdimm->mr, OBJECT(dev), name, size, buf);
+ vmstate_register_ram(&nvdimm->mr, DEVICE(dev));
+ memory_region_add_subregion(get_system_memory(), addr, &nvdimm->mr);
+
+ nvdimm->config_data_addr = buf + size;
+ nvdimm->config_data_size = MIN_CONFIG_DATA_SIZE;
+
+ return;
+do_unmap:
+ munmap(buf, size);
+do_close:
+ close(fd);
}
static void pc_nvdimm_class_init(ObjectClass *oc, void *data)
diff --git a/include/hw/mem/pc-nvdimm.h b/include/hw/mem/pc-nvdimm.h
index 2081e7c..e743ed1 100644
--- a/include/hw/mem/pc-nvdimm.h
+++ b/include/hw/mem/pc-nvdimm.h
@@ -21,6 +21,11 @@ typedef struct PCNVDIMMDevice {
DeviceState parent_obj;
char *file;
+ void *config_data_addr;
+ uint64_t config_data_size;
+
+ int device_index;
+ MemoryRegion mr;
} PCNVDIMMDevice;
#define TYPE_PC_NVDIMM "pc-nvdimm"
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 09/16] nvdimm: build ACPI NFIT table
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (7 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 08/16] nvdimm: init backend memory mapping and config data area Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 10/16] nvdimm: init the address region used by _DSM method Xiao Guangrong
` (8 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
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
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 10/16] nvdimm: init the address region used by _DSM method
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (8 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 09/16] nvdimm: build ACPI NFIT table Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 11/16] nvdimm: build ACPI nvdimm devices Xiao Guangrong
` (7 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
This memory range is used to transfer data between ACPI in guest and Qemu,
it occupies two pages:
- one is RAM-based used to save the input info of _DSM method and Qemu reuse
it store output info
- another one is MMIO-based, ACPI write data to this page to transfer the
control to Qemu
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/mem/pc-nvdimm.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 79 insertions(+), 1 deletion(-)
diff --git a/hw/mem/pc-nvdimm.c b/hw/mem/pc-nvdimm.c
index e7cff29..4c290cb 100644
--- a/hw/mem/pc-nvdimm.c
+++ b/hw/mem/pc-nvdimm.c
@@ -37,6 +37,10 @@
static struct nvdimms_info {
ram_addr_t current_addr;
+
+ ram_addr_t dsm_addr;
+ int dsm_size;
+
int device_index;
} nvdimms_info;
@@ -324,14 +328,88 @@ static void build_nfit_table(GSList *device_list, char *buf)
}
}
+struct dsm_buffer {
+ /* RAM page. */
+ uint32_t handle;
+ uint8_t arg0[16];
+ uint32_t arg1;
+ uint32_t arg2;
+ union {
+ char arg3[PAGE_SIZE - 3 * sizeof(uint32_t) - 16 * sizeof(uint8_t)];
+ };
+
+ /* MMIO page. */
+ union {
+ uint32_t notify;
+ char pedding[PAGE_SIZE];
+ };
+};
+
+static uint64_t dsm_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ return 0;
+}
+
+static void dsm_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+}
+
+static const MemoryRegionOps dsm_ops = {
+ .read = dsm_read,
+ .write = dsm_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int build_dsm_buffer(void)
+{
+ MemoryRegion *dsm_ram_mr, *dsm_mmio_mr;
+ ram_addr_t addr;;
+
+ QEMU_BUILD_BUG_ON(PAGE_SIZE * 2 != sizeof(struct dsm_buffer));
+
+ /* DSM buffer has already been built. */
+ if (nvdimms_info.dsm_addr) {
+ return 0;
+ }
+
+ addr = reserved_range_push(2 * PAGE_SIZE);
+ if (!addr) {
+ return -1;
+ }
+
+ nvdimms_info.dsm_addr = addr;
+ nvdimms_info.dsm_size = PAGE_SIZE * 2;
+
+ dsm_ram_mr = g_new(MemoryRegion, 1);
+ memory_region_init_ram(dsm_ram_mr, NULL, "dsm_ram", PAGE_SIZE,
+ &error_abort);
+ vmstate_register_ram_global(dsm_ram_mr);
+ memory_region_add_subregion(get_system_memory(), addr, dsm_ram_mr);
+
+ dsm_mmio_mr = g_new(MemoryRegion, 1);
+ memory_region_init_io(dsm_mmio_mr, NULL, &dsm_ops, dsm_ram_mr,
+ "dsm_mmio", PAGE_SIZE);
+ memory_region_add_subregion(get_system_memory(), addr + PAGE_SIZE,
+ dsm_mmio_mr);
+ return 0;
+}
+
void pc_nvdimm_build_nfit_table(GArray *table_offsets, GArray *table_data,
GArray *linker)
{
- GSList *list = get_nvdimm_built_list();
+ GSList *list;
size_t total;
char *buf;
int nfit_start, nr;
+ if (build_dsm_buffer()) {
+ fprintf(stderr, "do not have enough space for DSM buffer.\n");
+ return;
+ }
+
+ list = get_nvdimm_built_list();
nr = get_nvdimm_device_number(list);
total = get_nfit_total_size(nr);
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 11/16] nvdimm: build ACPI nvdimm devices
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (9 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 10/16] nvdimm: init the address region used by _DSM method Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 12/16] nvdimm: save arg3 for NVDIMM device _DSM method Xiao Guangrong
` (6 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
NVDIMM devices is defined in ACPI 6.0 9.20 NVDIMM Devices
This is a root device under \_SB and specified NVDIMM device are under the
root device. Each NVDIMM device has _ADR which return its handle used to
associate MEMDEV table in NFIT
We reserve handle 0 for root device. In this patch, we save handle, arg0,
arg1 and arg2. Arg3 is conditionally saved in later patch
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/i386/acpi-build.c | 2 +
hw/mem/pc-nvdimm.c | 126 +++++++++++++++++++++++++++++++++++++++++++++
include/hw/mem/pc-nvdimm.h | 6 +++
3 files changed, 134 insertions(+)
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 80c21be..85c7226 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1342,6 +1342,8 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(sb_scope, scope);
}
}
+
+ pc_nvdimm_build_acpi_devices(sb_scope);
aml_append(ssdt, sb_scope);
}
diff --git a/hw/mem/pc-nvdimm.c b/hw/mem/pc-nvdimm.c
index 4c290cb..0e2a9d5 100644
--- a/hw/mem/pc-nvdimm.c
+++ b/hw/mem/pc-nvdimm.c
@@ -32,6 +32,7 @@
#define PAGE_SIZE (1UL << 12)
+#define NOTIFY_VALUE (0x99)
#define MAX_NVDIMM_NUMBER (10)
#define MIN_CONFIG_DATA_SIZE (128 << 10)
@@ -348,12 +349,15 @@ struct dsm_buffer {
static uint64_t dsm_read(void *opaque, hwaddr addr,
unsigned size)
{
+ fprintf(stderr, "BUG: we never read DSM notification MMIO.\n");
+ assert(0);
return 0;
}
static void dsm_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
+ assert(val == NOTIFY_VALUE);
}
static const MemoryRegionOps dsm_ops = {
@@ -429,6 +433,128 @@ exit:
g_slist_free(list);
}
+#define BUILD_STA_METHOD(_dev_, _method_) \
+ do { \
+ _method_ = aml_method("_STA", 0); \
+ aml_append(_method_, aml_return(aml_int(0x0f))); \
+ aml_append(_dev_, _method_); \
+ } while (0)
+
+#define SAVE_ARG012_HANDLE(_method_, _handle_) \
+ do { \
+ aml_append(_method_, aml_store(_handle_, aml_name("HDLE"))); \
+ aml_append(_method_, aml_store(aml_arg(0), aml_name("ARG0"))); \
+ aml_append(_method_, aml_store(aml_arg(1), aml_name("ARG1"))); \
+ aml_append(_method_, aml_store(aml_arg(2), aml_name("ARG2"))); \
+ } while (0)
+
+#define NOTIFY_AND_RETURN(_method_) \
+ do { \
+ aml_append(_method_, aml_store(aml_int(NOTIFY_VALUE), \
+ aml_name("NOTI"))); \
+ aml_append(_method_, aml_return(aml_name("ODAT"))); \
+ } while (0)
+
+static void build_nvdimm_devices(Aml *root_dev, GSList *list)
+{
+ for (; list; list = list->next) {
+ PCNVDIMMDevice *nvdimm = list->data;
+ uint32_t handle = nvdimm_index_to_handle(nvdimm->device_index);
+ Aml *dev, *method;
+
+ dev = aml_device("NVD%d", nvdimm->device_index);
+ aml_append(dev, aml_name_decl("_ADR", aml_int(handle)));
+
+ BUILD_STA_METHOD(dev, method);
+
+ method = aml_method("_DSM", 4);
+ {
+ SAVE_ARG012_HANDLE(method, aml_int(handle));
+ NOTIFY_AND_RETURN(method);
+ }
+ aml_append(dev, method);
+
+ aml_append(root_dev, dev);
+ }
+}
+
+void pc_nvdimm_build_acpi_devices(Aml *sb_scope)
+{
+ Aml *dev, *method, *field;
+ struct dsm_buffer *dsm_buf;
+ GSList *list = get_nvdimm_built_list();
+ int nr = get_nvdimm_device_number(list);
+
+ if (nr <= 0 || nr > MAX_NVDIMM_NUMBER) {
+ g_slist_free(list);
+ return;
+ }
+
+ dev = aml_device("NVDR");
+ aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0012")));
+
+ /* map DSM buffer into ACPI namespace. */
+ aml_append(dev, aml_operation_region("DSMR", AML_SYSTEM_MEMORY,
+ nvdimms_info.dsm_addr, nvdimms_info.dsm_size));
+
+ /*
+ * DSM input:
+ * @HDLE: store device's handle, it's zero if the _DSM call happens
+ * on ROOT.
+ * @ARG0 ~ @ARG3: store the parameters of _DSM call.
+ *
+ * They are ram mapping on host so that these access never cause VM-EXIT.
+ */
+ field = aml_field("DSMR", AML_DWORD_ACC, AML_PRESERVE);
+ aml_append(field, aml_named_field("HDLE",
+ sizeof(dsm_buf->handle) * BITS_PER_BYTE));
+ aml_append(field, aml_named_field("ARG0",
+ sizeof(dsm_buf->arg0) * BITS_PER_BYTE));
+ aml_append(field, aml_named_field("ARG1",
+ sizeof(dsm_buf->arg1) * BITS_PER_BYTE));
+ aml_append(field, aml_named_field("ARG2",
+ sizeof(dsm_buf->arg2) * BITS_PER_BYTE));
+ aml_append(field, aml_named_field("ARG3",
+ sizeof(dsm_buf->arg3) * BITS_PER_BYTE));
+ /*
+ * DSM input:
+ * @NOTI: write value to it will notify QEMU that _DSM method is being
+ * called and the parameters can be found in dsm_buf.
+ *
+ * It is MMIO mapping on host so that it will cause VM-exit and QEMU
+ * gets control.
+ */
+ aml_append(field, aml_named_field("NOTI",
+ sizeof(dsm_buf->notify) * BITS_PER_BYTE));
+ aml_append(dev, field);
+
+ /*
+ * DSM output:
+ * @ODAT: it resues the first page of dsm buffer and QEMU uses it to
+ * stores the result
+ *
+ * Since the first page is reused by both input and out, the input data
+ * will be lost after storing new result into @ODAT
+ */
+ field = aml_field("DSMR", AML_DWORD_ACC, AML_PRESERVE);
+ aml_append(field, aml_named_field("ODAT", PAGE_SIZE * BITS_PER_BYTE));
+ aml_append(dev, field);
+
+ BUILD_STA_METHOD(dev, method);
+
+ method = aml_method("_DSM", 4);
+ {
+ SAVE_ARG012_HANDLE(method, aml_int(0));
+ NOTIFY_AND_RETURN(method);
+ }
+ aml_append(dev, method);
+
+ build_nvdimm_devices(dev, list);
+
+ aml_append(sb_scope, dev);
+ 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 74d989b..eb916e5 100644
--- a/include/hw/mem/pc-nvdimm.h
+++ b/include/hw/mem/pc-nvdimm.h
@@ -14,6 +14,7 @@
#define __PC_NVDIMM_H
#include "hw/qdev.h"
+#include "hw/acpi/aml-build.h"
#ifdef CONFIG_LINUX
typedef struct PCNVDIMMDevice {
@@ -36,6 +37,7 @@ typedef struct PCNVDIMMDevice {
void pc_nvdimm_reserve_range(ram_addr_t offset);
void pc_nvdimm_build_nfit_table(GArray *table_offsets, GArray *table_data,
GArray *linker);
+void pc_nvdimm_build_acpi_devices(Aml *sb_scope);
#else /* !CONFIG_LINUX */
static inline void pc_nvdimm_reserve_range(ram_addr_t offset)
{
@@ -46,5 +48,9 @@ pc_nvdimm_build_nfit_table(GArray *table_offsets, GArray *table_data,
GArray *linker)
{
}
+
+static inline void pc_nvdimm_build_acpi_devices(Aml *sb_scope)
+{
+}
#endif
#endif
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 12/16] nvdimm: save arg3 for NVDIMM device _DSM method
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (10 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 11/16] nvdimm: build ACPI nvdimm devices Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 13/16] nvdimm: support NFIT_CMD_IMPLEMENTED function Xiao Guangrong
` (5 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
Check if the function (Arg2) has additional input info (arg3) and save
the info if needed
We only do the save on NVDIMM device since we are not going to support any
function on root device
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/mem/pc-nvdimm.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 72 insertions(+), 1 deletion(-)
diff --git a/hw/mem/pc-nvdimm.c b/hw/mem/pc-nvdimm.c
index 0e2a9d5..c0965ae 100644
--- a/hw/mem/pc-nvdimm.c
+++ b/hw/mem/pc-nvdimm.c
@@ -329,6 +329,26 @@ static void build_nfit_table(GSList *device_list, char *buf)
}
}
+enum {
+ NFIT_CMD_IMPLEMENTED = 0,
+
+ /* bus commands */
+ NFIT_CMD_ARS_CAP = 1,
+ NFIT_CMD_ARS_START = 2,
+ NFIT_CMD_ARS_QUERY = 3,
+
+ /* per-dimm commands */
+ NFIT_CMD_SMART = 1,
+ NFIT_CMD_SMART_THRESHOLD = 2,
+ NFIT_CMD_DIMM_FLAGS = 3,
+ NFIT_CMD_GET_CONFIG_SIZE = 4,
+ NFIT_CMD_GET_CONFIG_DATA = 5,
+ NFIT_CMD_SET_CONFIG_DATA = 6,
+ NFIT_CMD_VENDOR_EFFECT_LOG_SIZE = 7,
+ NFIT_CMD_VENDOR_EFFECT_LOG = 8,
+ NFIT_CMD_VENDOR = 9,
+};
+
struct dsm_buffer {
/* RAM page. */
uint32_t handle;
@@ -433,6 +453,19 @@ exit:
g_slist_free(list);
}
+static bool device_cmd_has_arg3[] = {
+ false, /* NFIT_CMD_IMPLEMENTED */
+ false, /* NFIT_CMD_SMART */
+ false, /* NFIT_CMD_SMART_THRESHOLD */
+ false, /* NFIT_CMD_DIMM_FLAGS */
+ false, /* NFIT_CMD_GET_CONFIG_SIZE */
+ true, /* NFIT_CMD_GET_CONFIG_DATA */
+ true, /* NFIT_CMD_SET_CONFIG_DATA */
+ false, /* NFIT_CMD_VENDOR_EFFECT_LOG_SIZE */
+ false, /* NFIT_CMD_VENDOR_EFFECT_LOG */
+ false, /* NFIT_CMD_VENDOR */
+};
+
#define BUILD_STA_METHOD(_dev_, _method_) \
do { \
_method_ = aml_method("_STA", 0); \
@@ -457,10 +490,20 @@ exit:
static void build_nvdimm_devices(Aml *root_dev, GSList *list)
{
+ Aml *has_arg3;
+ int i, cmd_nr;
+
+ cmd_nr = ARRAY_SIZE(device_cmd_has_arg3);
+ has_arg3 = aml_package(cmd_nr);
+ for (i = 0; i < cmd_nr; i++) {
+ aml_append(has_arg3, aml_int(device_cmd_has_arg3[i]));
+ }
+ aml_append(root_dev, aml_name_decl("CAG3", has_arg3));
+
for (; list; list = list->next) {
PCNVDIMMDevice *nvdimm = list->data;
uint32_t handle = nvdimm_index_to_handle(nvdimm->device_index);
- Aml *dev, *method;
+ Aml *dev, *method, *ifctx;
dev = aml_device("NVD%d", nvdimm->device_index);
aml_append(dev, aml_name_decl("_ADR", aml_int(handle)));
@@ -470,6 +513,34 @@ static void build_nvdimm_devices(Aml *root_dev, GSList *list)
method = aml_method("_DSM", 4);
{
SAVE_ARG012_HANDLE(method, aml_int(handle));
+
+ /* Local5 = DeRefOf(Index(CAG3, Arg2)) */
+ aml_append(method,
+ aml_store(aml_derefof(aml_index(aml_name("CAG3"),
+ aml_arg(2))), aml_local(5)));
+ /* if 0 < local5 */
+ ifctx = aml_if(aml_lless(aml_int(0), aml_local(5)));
+ {
+ /* Local0 = Index(Arg3, 0) */
+ aml_append(ifctx, aml_store(aml_index(aml_arg(3), aml_int(0)),
+ aml_local(0)));
+ /* Local1 = sizeof(Local0) */
+ aml_append(ifctx, aml_store(aml_sizeof(aml_local(0)),
+ aml_local(1)));
+ /* Local2 = Local1 << 3 */
+ aml_append(ifctx, aml_store(aml_shiftleft(aml_local(1),
+ aml_int(3)), aml_local(2)));
+ /* Local3 = DeRefOf(Local0) */
+ aml_append(ifctx, aml_store(aml_derefof(aml_local(0)),
+ aml_local(3)));
+ /* CreateField(Local3, 0, local2, IBUF) */
+ aml_append(ifctx, aml_create_field(aml_local(3),
+ aml_int(0), aml_local(2), "IBUF"));
+ /* ARG3 = IBUF */
+ aml_append(ifctx, aml_store(aml_name("IBUF"),
+ aml_name("ARG3")));
+ }
+ aml_append(method, ifctx);
NOTIFY_AND_RETURN(method);
}
aml_append(dev, method);
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 13/16] nvdimm: support NFIT_CMD_IMPLEMENTED function
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (11 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 12/16] nvdimm: save arg3 for NVDIMM device _DSM method Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 14/16] nvdimm: support NFIT_CMD_GET_CONFIG_SIZE function Xiao Guangrong
` (4 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
__DSM is defined in ACPI 6.0: 9.14.1 _DSM (Device Specific Method)
Function 0 is a query function. We do not support any function on root
device and only 3 functions are support for NVDIMM device,
NFIT_CMD_GET_CONFIG_SIZE, NFIT_CMD_GET_CONFIG_DATA and
NFIT_CMD_SET_CONFIG_DATA, that means we currently only allow to access
device's Label Namespace
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/mem/pc-nvdimm.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 126 insertions(+)
diff --git a/hw/mem/pc-nvdimm.c b/hw/mem/pc-nvdimm.c
index c0965ae..b586bf7 100644
--- a/hw/mem/pc-nvdimm.c
+++ b/hw/mem/pc-nvdimm.c
@@ -29,6 +29,15 @@
#include "exec/address-spaces.h"
#include "hw/acpi/aml-build.h"
#include "hw/mem/pc-nvdimm.h"
+#include "sysemu/sysemu.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)
@@ -135,6 +144,22 @@ static void nfit_spa_uuid_pm(void *uuid)
memcpy(uuid, &uuid_pm, sizeof(uuid_pm));
}
+static bool dsm_is_root_uuid(uint8_t *uuid)
+{
+ uuid_le uuid_root = UUID_LE(0x2f10e7a4, 0x9e91, 0x11e4, 0x89,
+ 0xd3, 0x12, 0x3b, 0x93, 0xf7, 0x5c, 0xba);
+
+ return !memcmp(uuid, &uuid_root, sizeof(uuid_root));
+}
+
+static bool dsm_is_dimm_uuid(uint8_t *uuid)
+{
+ uuid_le uuid_dimm = UUID_LE(0x4309ac30, 0x0d11, 0x11e4, 0x91,
+ 0x91, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66);
+
+ return !memcmp(uuid, &uuid_dimm, sizeof(uuid_dimm));
+}
+
enum {
NFIT_TABLE_SPA = 0,
NFIT_TABLE_MEM = 1,
@@ -349,6 +374,23 @@ enum {
NFIT_CMD_VENDOR = 9,
};
+enum {
+ NFIT_STATUS_SUCCESS = 0,
+ NFIT_STATUS_NOT_SUPPORTED = 1,
+ NFIT_STATUS_NON_EXISTING_MEM_DEV = 2,
+ NFIT_STATUS_INVALID_PARAS = 3,
+ NFIT_STATUS_VENDOR_SPECIFIC_ERROR = 4,
+};
+
+#define DSM_REVISION (1)
+
+/* do not support any command except NFIT_CMD_ARS_CAP on root. */
+#define ROOT_SUPPORT_CMD (1 << NFIT_CMD_ARS_CAP)
+#define DIMM_SUPPORT_CMD ((1 << NFIT_CMD_IMPLEMENTED) \
+ | (1 << NFIT_CMD_GET_CONFIG_SIZE) \
+ | (1 << NFIT_CMD_GET_CONFIG_DATA) \
+ | (1 << NFIT_CMD_SET_CONFIG_DATA))
+
struct dsm_buffer {
/* RAM page. */
uint32_t handle;
@@ -366,6 +408,18 @@ struct dsm_buffer {
};
};
+struct cmd_out_implemented {
+ uint64_t cmd_list;
+};
+
+struct dsm_out {
+ union {
+ uint32_t status;
+ struct cmd_out_implemented cmd_implemented;
+ uint8_t data[PAGE_SIZE];
+ };
+};
+
static uint64_t dsm_read(void *opaque, hwaddr addr,
unsigned size)
{
@@ -374,10 +428,82 @@ static uint64_t dsm_read(void *opaque, hwaddr addr,
return 0;
}
+static void dsm_write_root(struct dsm_buffer *in, struct dsm_out *out)
+{
+ uint32_t function = in->arg2;
+
+ if (function == NFIT_CMD_IMPLEMENTED) {
+ out->cmd_implemented.cmd_list = ROOT_SUPPORT_CMD;
+ return;
+ }
+
+ out->status = NFIT_STATUS_NOT_SUPPORTED;
+ nvdebug("Return status %#x.\n", out->status);
+}
+
+static void dsm_write_nvdimm(struct dsm_buffer *in, struct dsm_out *out)
+{
+ uint32_t function = in->arg2;
+ uint32_t status;
+
+ switch (function) {
+ case NFIT_CMD_IMPLEMENTED:
+ out->cmd_implemented.cmd_list = DIMM_SUPPORT_CMD;
+ return;
+ default:
+ status = NFIT_STATUS_NOT_SUPPORTED;
+ };
+
+ nvdebug("Return status %#x.\n", status);
+ out->status = status;
+}
+
static void dsm_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
+ struct MemoryRegion *dsm_ram_mr = opaque;
+ struct dsm_buffer *dsm;
+ struct dsm_out *out;
+ void *buf;
+
assert(val == NOTIFY_VALUE);
+
+ buf = memory_region_get_ram_ptr(dsm_ram_mr);
+ dsm = buf;
+ out = buf;
+
+ nvdebug("Arg0 " UUID_FMT ".\n", dsm->arg0[0], dsm->arg0[1], dsm->arg0[2],
+ dsm->arg0[3], dsm->arg0[4], dsm->arg0[5], dsm->arg0[6],
+ dsm->arg0[7], dsm->arg0[8], dsm->arg0[9], dsm->arg0[10],
+ dsm->arg0[11], dsm->arg0[12], dsm->arg0[13], dsm->arg0[14],
+ dsm->arg0[15]);
+ nvdebug("Handler %#x, Arg1 %#x, Arg2 %#x.\n", dsm->handle, dsm->arg1,
+ dsm->arg2);
+
+ if (dsm->arg1 != DSM_REVISION) {
+ nvdebug("Revision %#x is not supported, expect %#x.\n",
+ dsm->arg1, DSM_REVISION);
+ goto exit;
+ }
+
+ if (!dsm->handle) {
+ if (!dsm_is_root_uuid(dsm->arg0)) {
+ nvdebug("Root UUID does not match.\n");
+ goto exit;
+ }
+
+ return dsm_write_root(dsm, out);
+ }
+
+ if (!dsm_is_dimm_uuid(dsm->arg0)) {
+ nvdebug("DIMM UUID does not match.\n");
+ goto exit;
+ }
+
+ return dsm_write_nvdimm(dsm, out);
+
+exit:
+ out->status = NFIT_STATUS_NOT_SUPPORTED;
}
static const MemoryRegionOps dsm_ops = {
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 14/16] nvdimm: support NFIT_CMD_GET_CONFIG_SIZE function
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (12 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 13/16] nvdimm: support NFIT_CMD_IMPLEMENTED function Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-02 9:23 ` Stefan Hajnoczi
2015-07-01 14:50 ` [Qemu-devel] [PATCH 15/16] nvdimm: support NFIT_CMD_GET_CONFIG_DATA Xiao Guangrong
` (3 subsequent siblings)
17 siblings, 1 reply; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
Function 4 is used to get Namespace lable size
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/mem/pc-nvdimm.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
diff --git a/hw/mem/pc-nvdimm.c b/hw/mem/pc-nvdimm.c
index b586bf7..7e5446c 100644
--- a/hw/mem/pc-nvdimm.c
+++ b/hw/mem/pc-nvdimm.c
@@ -127,6 +127,20 @@ static uint32_t nvdimm_index_to_handle(int index)
return index + 1;
}
+static PCNVDIMMDevice
+*get_nvdimm_device_by_handle(GSList *list, uint32_t handle)
+{
+ for (; list; list = list->next) {
+ PCNVDIMMDevice *nvdimm = list->data;
+
+ if (nvdimm_index_to_handle(nvdimm->device_index) == handle) {
+ return nvdimm;
+ }
+ }
+
+ return NULL;
+}
+
typedef struct {
uint8_t b[16];
} uuid_le;
@@ -391,6 +405,17 @@ enum {
| (1 << NFIT_CMD_GET_CONFIG_DATA) \
| (1 << NFIT_CMD_SET_CONFIG_DATA))
+struct cmd_in_get_config_data {
+ uint32_t offset;
+ uint32_t length;
+} QEMU_PACKED;
+
+struct cmd_in_set_config_data {
+ uint32_t offset;
+ uint32_t length;
+ uint8_t in_buf[0];
+} QEMU_PACKED;
+
struct dsm_buffer {
/* RAM page. */
uint32_t handle;
@@ -398,6 +423,7 @@ struct dsm_buffer {
uint32_t arg1;
uint32_t arg2;
union {
+ struct cmd_in_set_config_data cmd_config_set;
char arg3[PAGE_SIZE - 3 * sizeof(uint32_t) - 16 * sizeof(uint8_t)];
};
@@ -412,10 +438,23 @@ struct cmd_out_implemented {
uint64_t cmd_list;
};
+struct cmd_out_get_config_size {
+ uint32_t status;
+ uint32_t config_size;
+ uint32_t max_xfer;
+} QEMU_PACKED;
+
+struct cmd_out_get_config_data {
+ uint32_t status;
+ uint8_t out_buf[0];
+} QEMU_PACKED;
+
struct dsm_out {
union {
uint32_t status;
struct cmd_out_implemented cmd_implemented;
+ struct cmd_out_get_config_size cmd_config_size;
+ struct cmd_out_get_config_data cmd_config_get;
uint8_t data[PAGE_SIZE];
};
};
@@ -441,6 +480,51 @@ static void dsm_write_root(struct dsm_buffer *in, struct dsm_out *out)
nvdebug("Return status %#x.\n", out->status);
}
+/*
+ * the max transfer size is the max size transfered by both a
+ * NFIT_CMD_GET_CONFIG_DATA and a NFIT_CMD_SET_CONFIG_DATA
+ * command.
+ */
+static uint32_t max_xfer_config_size(void)
+{
+ struct dsm_buffer *in;
+ struct dsm_out *out;
+ uint32_t max_get_size, max_set_size;
+
+ /*
+ * the max data ACPI can read one time which is transfered by
+ * the response of NFIT_CMD_GET_CONFIG_DATA.
+ */
+ max_get_size = sizeof(out->data) - sizeof(out->cmd_config_get);
+
+ /*
+ * the max data ACPI can write one time which is transfered by
+ * NFIT_CMD_SET_CONFIG_DATA
+ */
+ max_set_size = sizeof(in->arg3) - sizeof(in->cmd_config_set);
+ return MIN(max_get_size, max_set_size);
+}
+
+static uint32_t dsm_cmd_config_size(struct dsm_buffer *in, struct dsm_out *out)
+{
+ GSList *list = get_nvdimm_built_list();
+ PCNVDIMMDevice *nvdimm = get_nvdimm_device_by_handle(list, in->handle);
+ uint32_t status = NFIT_STATUS_NON_EXISTING_MEM_DEV;
+
+ if (!nvdimm) {
+ goto exit;
+ }
+
+ status = NFIT_STATUS_SUCCESS;
+ out->cmd_config_size.config_size = nvdimm->config_data_size;
+ out->cmd_config_size.max_xfer = max_xfer_config_size();
+ nvdebug("%s config_size %#x, max_xfer %#x.\n", __func__,
+ out->cmd_config_size.config_size, out->cmd_config_size.max_xfer);
+exit:
+ g_slist_free(list);
+ return status;
+}
+
static void dsm_write_nvdimm(struct dsm_buffer *in, struct dsm_out *out)
{
uint32_t function = in->arg2;
@@ -450,6 +534,9 @@ static void dsm_write_nvdimm(struct dsm_buffer *in, struct dsm_out *out)
case NFIT_CMD_IMPLEMENTED:
out->cmd_implemented.cmd_list = DIMM_SUPPORT_CMD;
return;
+ case NFIT_CMD_GET_CONFIG_SIZE:
+ status = dsm_cmd_config_size(in, out);
+ break;
default:
status = NFIT_STATUS_NOT_SUPPORTED;
};
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 15/16] nvdimm: support NFIT_CMD_GET_CONFIG_DATA
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (13 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 14/16] nvdimm: support NFIT_CMD_GET_CONFIG_SIZE function Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 16/16] nvdimm: support NFIT_CMD_SET_CONFIG_DATA Xiao Guangrong
` (2 subsequent siblings)
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
Function 5 is used to get Namespace Label Data
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/mem/pc-nvdimm.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/hw/mem/pc-nvdimm.c b/hw/mem/pc-nvdimm.c
index 7e5446c..0498de3 100644
--- a/hw/mem/pc-nvdimm.c
+++ b/hw/mem/pc-nvdimm.c
@@ -423,6 +423,7 @@ struct dsm_buffer {
uint32_t arg1;
uint32_t arg2;
union {
+ struct cmd_in_get_config_data cmd_config_get;
struct cmd_in_set_config_data cmd_config_set;
char arg3[PAGE_SIZE - 3 * sizeof(uint32_t) - 16 * sizeof(uint8_t)];
};
@@ -525,6 +526,35 @@ exit:
return status;
}
+static uint32_t dsm_cmd_config_get(struct dsm_buffer *in, struct dsm_out *out)
+{
+ GSList *list = get_nvdimm_built_list();
+ PCNVDIMMDevice *nvdimm = get_nvdimm_device_by_handle(list, in->handle);
+ struct cmd_in_get_config_data *cmd_in = &in->cmd_config_get;
+ uint32_t status = NFIT_STATUS_NON_EXISTING_MEM_DEV;
+
+ if (!nvdimm) {
+ goto exit;
+ }
+
+ nvdebug("Read Config: offset %#x length %#x.\n", cmd_in->offset,
+ cmd_in->length);
+ if (nvdimm->config_data_size < cmd_in->length + cmd_in->offset) {
+ nvdebug("position %#x is beyond config data (len = %#lx).\n",
+ cmd_in->length + cmd_in->offset, nvdimm->config_data_size);
+ status = NFIT_STATUS_INVALID_PARAS;
+ goto exit;
+ }
+
+ status = NFIT_STATUS_SUCCESS;
+ memcpy(out->cmd_config_get.out_buf, nvdimm->config_data_addr +
+ cmd_in->offset, cmd_in->length);
+
+exit:
+ g_slist_free(list);
+ return status;
+}
+
static void dsm_write_nvdimm(struct dsm_buffer *in, struct dsm_out *out)
{
uint32_t function = in->arg2;
@@ -537,6 +567,9 @@ static void dsm_write_nvdimm(struct dsm_buffer *in, struct dsm_out *out)
case NFIT_CMD_GET_CONFIG_SIZE:
status = dsm_cmd_config_size(in, out);
break;
+ case NFIT_CMD_GET_CONFIG_DATA:
+ status = dsm_cmd_config_get(in, out);
+ break;
default:
status = NFIT_STATUS_NOT_SUPPORTED;
};
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PATCH 16/16] nvdimm: support NFIT_CMD_SET_CONFIG_DATA
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (14 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 15/16] nvdimm: support NFIT_CMD_GET_CONFIG_DATA Xiao Guangrong
@ 2015-07-01 14:50 ` Xiao Guangrong
2015-07-02 6:17 ` [Qemu-devel] [PATCH 00/16] implement vNVDIMM Michael S. Tsirkin
2015-07-02 9:20 ` Stefan Hajnoczi
17 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-01 14:50 UTC (permalink / raw)
To: pbonzini, imammedo
Cc: Xiao Guangrong, ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
stefanha, rth
Function 6 is used to set Namespace Label Data
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
---
hw/mem/pc-nvdimm.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/hw/mem/pc-nvdimm.c b/hw/mem/pc-nvdimm.c
index 0498de3..0d2d9fb 100644
--- a/hw/mem/pc-nvdimm.c
+++ b/hw/mem/pc-nvdimm.c
@@ -450,12 +450,17 @@ struct cmd_out_get_config_data {
uint8_t out_buf[0];
} QEMU_PACKED;
+struct cmd_out_set_config_data {
+ uint32_t status;
+} QEMU_PACKED;
+
struct dsm_out {
union {
uint32_t status;
struct cmd_out_implemented cmd_implemented;
struct cmd_out_get_config_size cmd_config_size;
struct cmd_out_get_config_data cmd_config_get;
+ struct cmd_out_set_config_data cmd_config_set;
uint8_t data[PAGE_SIZE];
};
};
@@ -555,6 +560,35 @@ exit:
return status;
}
+static uint32_t dsm_cmd_config_set(struct dsm_buffer *in, struct dsm_out *out)
+{
+ GSList *list = get_nvdimm_built_list();
+ PCNVDIMMDevice *nvdimm = get_nvdimm_device_by_handle(list, in->handle);
+ struct cmd_in_set_config_data *cmd_in = &in->cmd_config_set;
+ uint32_t status = NFIT_STATUS_NON_EXISTING_MEM_DEV;
+
+ if (!nvdimm) {
+ goto exit;
+ }
+
+ nvdebug("Write Config: offset %#x length %#x.\n", cmd_in->offset,
+ cmd_in->length);
+ if (nvdimm->config_data_size < cmd_in->length + cmd_in->offset) {
+ nvdebug("position %#x is beyond config data (len = %#lx).\n",
+ cmd_in->length + cmd_in->offset, nvdimm->config_data_size);
+ status = NFIT_STATUS_INVALID_PARAS;
+ goto exit;
+ }
+
+ status = NFIT_STATUS_SUCCESS;
+ memcpy(nvdimm->config_data_addr + cmd_in->offset, cmd_in->in_buf,
+ cmd_in->length);
+
+exit:
+ g_slist_free(list);
+ return status;
+}
+
static void dsm_write_nvdimm(struct dsm_buffer *in, struct dsm_out *out)
{
uint32_t function = in->arg2;
@@ -570,6 +604,9 @@ static void dsm_write_nvdimm(struct dsm_buffer *in, struct dsm_out *out)
case NFIT_CMD_GET_CONFIG_DATA:
status = dsm_cmd_config_get(in, out);
break;
+ case NFIT_CMD_SET_CONFIG_DATA:
+ status = dsm_cmd_config_set(in, out);
+ break;
default:
status = NFIT_STATUS_NOT_SUPPORTED;
};
--
2.1.0
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 00/16] implement vNVDIMM
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (15 preceding siblings ...)
2015-07-01 14:50 ` [Qemu-devel] [PATCH 16/16] nvdimm: support NFIT_CMD_SET_CONFIG_DATA Xiao Guangrong
@ 2015-07-02 6:17 ` Michael S. Tsirkin
2015-07-02 6:34 ` Xiao Guangrong
2015-07-02 9:20 ` Stefan Hajnoczi
17 siblings, 1 reply; 28+ messages in thread
From: Michael S. Tsirkin @ 2015-07-02 6:17 UTC (permalink / raw)
To: Xiao Guangrong
Cc: ehabkost, kvm, gleb, mtosatti, qemu-devel, stefanha, imammedo,
pbonzini, rth
On Wed, Jul 01, 2015 at 10:50:16PM +0800, Xiao Guangrong wrote:
> hw/acpi/aml-build.c | 32 +-
> hw/i386/acpi-build.c | 9 +-
> hw/i386/acpi-dsdt.dsl | 2 +-
> hw/i386/pc.c | 11 +-
> hw/mem/Makefile.objs | 1 +
> hw/mem/pc-nvdimm.c | 1040 +++++++++++++++++++++++++++++++++++++++++++
> include/hw/acpi/aml-build.h | 5 +-
> include/hw/mem/pc-nvdimm.h | 56 +++
> 8 files changed, 1149 insertions(+), 7 deletions(-)
> create mode 100644 hw/mem/pc-nvdimm.c
> create mode 100644 include/hw/mem/pc-nvdimm.h
Given the amount of code, this is definitely not 2.4 material.
Maybe others will have the time to review it before this, but
in any case please remember to repost after 2.4 is out.
Thanks!
> --
> 2.1.0
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 00/16] implement vNVDIMM
2015-07-02 6:17 ` [Qemu-devel] [PATCH 00/16] implement vNVDIMM Michael S. Tsirkin
@ 2015-07-02 6:34 ` Xiao Guangrong
2015-07-02 8:31 ` Stefan Hajnoczi
0 siblings, 1 reply; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-02 6:34 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: ehabkost, kvm, gleb, mtosatti, qemu-devel, stefanha, imammedo,
pbonzini, rth
On 07/02/2015 02:17 PM, Michael S. Tsirkin wrote:
> On Wed, Jul 01, 2015 at 10:50:16PM +0800, Xiao Guangrong wrote:
>> hw/acpi/aml-build.c | 32 +-
>> hw/i386/acpi-build.c | 9 +-
>> hw/i386/acpi-dsdt.dsl | 2 +-
>> hw/i386/pc.c | 11 +-
>> hw/mem/Makefile.objs | 1 +
>> hw/mem/pc-nvdimm.c | 1040 +++++++++++++++++++++++++++++++++++++++++++
>> include/hw/acpi/aml-build.h | 5 +-
>> include/hw/mem/pc-nvdimm.h | 56 +++
>> 8 files changed, 1149 insertions(+), 7 deletions(-)
>> create mode 100644 hw/mem/pc-nvdimm.c
>> create mode 100644 include/hw/mem/pc-nvdimm.h
>
> Given the amount of code, this is definitely not 2.4 material.
> Maybe others will have the time to review it before this, but
> in any case please remember to repost after 2.4 is out.
I see, thanks for your reminder, Michael!
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 00/16] implement vNVDIMM
2015-07-02 6:34 ` Xiao Guangrong
@ 2015-07-02 8:31 ` Stefan Hajnoczi
2015-07-02 8:35 ` Michael S. Tsirkin
0 siblings, 1 reply; 28+ messages in thread
From: Stefan Hajnoczi @ 2015-07-02 8:31 UTC (permalink / raw)
To: Xiao Guangrong
Cc: ehabkost, kvm, Michael S. Tsirkin, gleb, mtosatti, qemu-devel,
stefanha, pbonzini, imammedo, rth
[-- Attachment #1: Type: text/plain, Size: 1331 bytes --]
On Thu, Jul 02, 2015 at 02:34:05PM +0800, Xiao Guangrong wrote:
> On 07/02/2015 02:17 PM, Michael S. Tsirkin wrote:
> >On Wed, Jul 01, 2015 at 10:50:16PM +0800, Xiao Guangrong wrote:
> >> hw/acpi/aml-build.c | 32 +-
> >> hw/i386/acpi-build.c | 9 +-
> >> hw/i386/acpi-dsdt.dsl | 2 +-
> >> hw/i386/pc.c | 11 +-
> >> hw/mem/Makefile.objs | 1 +
> >> hw/mem/pc-nvdimm.c | 1040 +++++++++++++++++++++++++++++++++++++++++++
> >> include/hw/acpi/aml-build.h | 5 +-
> >> include/hw/mem/pc-nvdimm.h | 56 +++
> >> 8 files changed, 1149 insertions(+), 7 deletions(-)
> >> create mode 100644 hw/mem/pc-nvdimm.c
> >> create mode 100644 include/hw/mem/pc-nvdimm.h
> >
> >Given the amount of code, this is definitely not 2.4 material.
> >Maybe others will have the time to review it before this, but
> >in any case please remember to repost after 2.4 is out.
>
> I see, thanks for your reminder, Michael!
I will review the series now.
Here is the QEMU release schedule:
http://qemu-project.org/Planning/2.4
Hard freeze - 7 July
QEMU 2.4 release - 4 August
It could be merged into a maintainer's tree when the -next branches are
opened (it's up to each maintainer but for the block and net trees I do
that at hard freeze time).
[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 00/16] implement vNVDIMM
2015-07-02 8:31 ` Stefan Hajnoczi
@ 2015-07-02 8:35 ` Michael S. Tsirkin
0 siblings, 0 replies; 28+ messages in thread
From: Michael S. Tsirkin @ 2015-07-02 8:35 UTC (permalink / raw)
To: Stefan Hajnoczi
Cc: Xiao Guangrong, ehabkost, kvm, gleb, mtosatti, qemu-devel,
stefanha, pbonzini, imammedo, rth
On Thu, Jul 02, 2015 at 09:31:23AM +0100, Stefan Hajnoczi wrote:
> On Thu, Jul 02, 2015 at 02:34:05PM +0800, Xiao Guangrong wrote:
> > On 07/02/2015 02:17 PM, Michael S. Tsirkin wrote:
> > >On Wed, Jul 01, 2015 at 10:50:16PM +0800, Xiao Guangrong wrote:
> > >> hw/acpi/aml-build.c | 32 +-
> > >> hw/i386/acpi-build.c | 9 +-
> > >> hw/i386/acpi-dsdt.dsl | 2 +-
> > >> hw/i386/pc.c | 11 +-
> > >> hw/mem/Makefile.objs | 1 +
> > >> hw/mem/pc-nvdimm.c | 1040 +++++++++++++++++++++++++++++++++++++++++++
> > >> include/hw/acpi/aml-build.h | 5 +-
> > >> include/hw/mem/pc-nvdimm.h | 56 +++
> > >> 8 files changed, 1149 insertions(+), 7 deletions(-)
> > >> create mode 100644 hw/mem/pc-nvdimm.c
> > >> create mode 100644 include/hw/mem/pc-nvdimm.h
> > >
> > >Given the amount of code, this is definitely not 2.4 material.
> > >Maybe others will have the time to review it before this, but
> > >in any case please remember to repost after 2.4 is out.
> >
> > I see, thanks for your reminder, Michael!
>
> I will review the series now.
>
> Here is the QEMU release schedule:
> http://qemu-project.org/Planning/2.4
>
> Hard freeze - 7 July
>
> QEMU 2.4 release - 4 August
>
> It could be merged into a maintainer's tree when the -next branches are
> opened (it's up to each maintainer but for the block and net trees I do
> that at hard freeze time).
Absolutely, but I'm not sure I'll do a next tree this time around.
--
MST
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 00/16] implement vNVDIMM
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
` (16 preceding siblings ...)
2015-07-02 6:17 ` [Qemu-devel] [PATCH 00/16] implement vNVDIMM Michael S. Tsirkin
@ 2015-07-02 9:20 ` Stefan Hajnoczi
2015-07-02 9:52 ` Paolo Bonzini
17 siblings, 1 reply; 28+ messages in thread
From: Stefan Hajnoczi @ 2015-07-02 9:20 UTC (permalink / raw)
To: Xiao Guangrong
Cc: ehabkost, kvm, mst, gleb, mtosatti, qemu-devel, stefanha,
imammedo, pbonzini, rth
[-- Attachment #1: Type: text/plain, Size: 1226 bytes --]
On Wed, Jul 01, 2015 at 10:50:16PM +0800, Xiao Guangrong wrote:
> ====== Background ======
> NVDIMM (A Non-Volatile Dual In-line Memory Module) is going to be supported
> on Intel's platform. They are discovered via ACPI and configured by _DSM
> method of NVDIMM device in ACPI. There has some supporting documents which
> can be found at:
> ACPI 6: http://www.uefi.org/sites/default/files/resources/ACPI_6.0.pdf
> NVDIMM Namespace: http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf
> DSM Interface Example: http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
> Driver Writer's Guide: http://pmem.io/documents/NVDIMM_Driver_Writers_Guide.pdf
>
> Currently, the NVDIMM driver has been merged into upstream Linux Kernel and
> this patchset tries to enable it in virtualization field
From a device model perspective, have you checked whether it makes sense
to integrate nvdimms into the pc-dimm and hostmem code that is used for
memory hotplug and NUMA?
The NVDIMM device in your patches is a completely new TYPE_DEVICE so it
doesn't share any interfaces or code with existing memory devices.
Maybe that is the right solution here because NVDIMMs have different
characteristics, but I'm not sure.
[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 14/16] nvdimm: support NFIT_CMD_GET_CONFIG_SIZE function
2015-07-01 14:50 ` [Qemu-devel] [PATCH 14/16] nvdimm: support NFIT_CMD_GET_CONFIG_SIZE function Xiao Guangrong
@ 2015-07-02 9:23 ` Stefan Hajnoczi
2015-07-02 18:02 ` Xiao Guangrong
0 siblings, 1 reply; 28+ messages in thread
From: Stefan Hajnoczi @ 2015-07-02 9:23 UTC (permalink / raw)
To: Xiao Guangrong
Cc: ehabkost, kvm, mst, gleb, mtosatti, qemu-devel, stefanha,
imammedo, pbonzini, rth
[-- Attachment #1: Type: text/plain, Size: 683 bytes --]
On Wed, Jul 01, 2015 at 10:50:30PM +0800, Xiao Guangrong wrote:
> +static uint32_t dsm_cmd_config_size(struct dsm_buffer *in, struct dsm_out *out)
> +{
> + GSList *list = get_nvdimm_built_list();
> + PCNVDIMMDevice *nvdimm = get_nvdimm_device_by_handle(list, in->handle);
> + uint32_t status = NFIT_STATUS_NON_EXISTING_MEM_DEV;
> +
> + if (!nvdimm) {
> + goto exit;
> + }
> +
> + status = NFIT_STATUS_SUCCESS;
> + out->cmd_config_size.config_size = nvdimm->config_data_size;
> + out->cmd_config_size.max_xfer = max_xfer_config_size();
cpu_to_*() missing?
It should be possible to emulate NVDIMMs for a x86_64 guest on a
big-endian host, for example.
[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 00/16] implement vNVDIMM
2015-07-02 9:20 ` Stefan Hajnoczi
@ 2015-07-02 9:52 ` Paolo Bonzini
2015-07-02 18:01 ` Xiao Guangrong
0 siblings, 1 reply; 28+ messages in thread
From: Paolo Bonzini @ 2015-07-02 9:52 UTC (permalink / raw)
To: Stefan Hajnoczi, Xiao Guangrong
Cc: ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
Marc-André Lureau, stefanha, imammedo, rth
On 02/07/2015 11:20, Stefan Hajnoczi wrote:
> > Currently, the NVDIMM driver has been merged into upstream Linux Kernel and
> > this patchset tries to enable it in virtualization field
>
> From a device model perspective, have you checked whether it makes sense
> to integrate nvdimms into the pc-dimm and hostmem code that is used for
> memory hotplug and NUMA?
>
> The NVDIMM device in your patches is a completely new TYPE_DEVICE so it
> doesn't share any interfaces or code with existing memory devices.
> Maybe that is the right solution here because NVDIMMs have different
> characteristics, but I'm not sure.
The hostmem code should definitely be shared, e.g. by adding a new
"file" property to the memory-backend-file class. ivshmem can also use
it---CCing Marc-André.
I don't know about the pc-dimm devices. If the NVDIMM devices can do
_OST and can be hotplugged, then the answer is probably yes.
Paolo
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 00/16] implement vNVDIMM
2015-07-02 9:52 ` Paolo Bonzini
@ 2015-07-02 18:01 ` Xiao Guangrong
2015-07-02 18:11 ` Paolo Bonzini
0 siblings, 1 reply; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-02 18:01 UTC (permalink / raw)
To: Paolo Bonzini, Stefan Hajnoczi
Cc: ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
Marc-André Lureau, stefanha, imammedo, rth
Thanks for your review, Stefan and Paolo!
On 07/02/2015 05:52 PM, Paolo Bonzini wrote:
>
>
> On 02/07/2015 11:20, Stefan Hajnoczi wrote:
>>> Currently, the NVDIMM driver has been merged into upstream Linux Kernel and
>>> this patchset tries to enable it in virtualization field
>>
>> From a device model perspective, have you checked whether it makes sense
>> to integrate nvdimms into the pc-dimm and hostmem code that is used for
>> memory hotplug and NUMA?
>>
>> The NVDIMM device in your patches is a completely new TYPE_DEVICE so it
>> doesn't share any interfaces or code with existing memory devices.
>> Maybe that is the right solution here because NVDIMMs have different
>> characteristics, but I'm not sure.
>
> The hostmem code should definitely be shared, e.g. by adding a new
> "file" property to the memory-backend-file class. ivshmem can also use
> it---CCing Marc-Andr�.
However, file-based memory used by NVDIMM is special, it divides the file
to two parts, one part is used as PMEM and another part is used to store
NVDIMM's configure data.
Maybe we can introduce "end-reserved" property to reserve specified size
at the end of the file. Or create a new class type based on
memory-backend-file (named nvdimm-backend-file) class to hide this magic
thing?
>
> I don't know about the pc-dimm devices. If the NVDIMM devices can do
> _OST and can be hotplugged, then the answer is probably yes.
_OST is not needed for NVDIMM.
NVDIMM is completely different with dimm memory device in ACPI - it has
different HID, method object, memory range detection, device organization,
etc. So i prefer to introducing new device class for NVDIMM.
For hotplug, NVDIMM and DIMM can share some logic, e.g, free-address-range
management, slot management ... ( but new Object initiation in ACPI is
complete different), we can abstract these operation as common part.
NUMA detection is also different between NVDIMM, DIMM is also different,
NVDIMM need to report its NUMA affinity in SPA table. But they can share
some common function i think.
BTW, i am going to implement vNVDIMM hotplug once linux NVDIMM driver
supports it.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 14/16] nvdimm: support NFIT_CMD_GET_CONFIG_SIZE function
2015-07-02 9:23 ` Stefan Hajnoczi
@ 2015-07-02 18:02 ` Xiao Guangrong
0 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-02 18:02 UTC (permalink / raw)
To: Stefan Hajnoczi
Cc: ehabkost, kvm, mst, gleb, mtosatti, qemu-devel, stefanha,
pbonzini, imammedo, rth
On 07/02/2015 05:23 PM, Stefan Hajnoczi wrote:
> On Wed, Jul 01, 2015 at 10:50:30PM +0800, Xiao Guangrong wrote:
>> +static uint32_t dsm_cmd_config_size(struct dsm_buffer *in, struct dsm_out *out)
>> +{
>> + GSList *list = get_nvdimm_built_list();
>> + PCNVDIMMDevice *nvdimm = get_nvdimm_device_by_handle(list, in->handle);
>> + uint32_t status = NFIT_STATUS_NON_EXISTING_MEM_DEV;
>> +
>> + if (!nvdimm) {
>> + goto exit;
>> + }
>> +
>> + status = NFIT_STATUS_SUCCESS;
>> + out->cmd_config_size.config_size = nvdimm->config_data_size;
>> + out->cmd_config_size.max_xfer = max_xfer_config_size();
>
> cpu_to_*() missing?
>
> It should be possible to emulate NVDIMMs for a x86_64 guest on a
> big-endian host, for example.
Indeed, will fix it in the next version, thank you for pointing it out.
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 00/16] implement vNVDIMM
2015-07-02 18:01 ` Xiao Guangrong
@ 2015-07-02 18:11 ` Paolo Bonzini
2015-07-29 8:41 ` Xiao Guangrong
0 siblings, 1 reply; 28+ messages in thread
From: Paolo Bonzini @ 2015-07-02 18:11 UTC (permalink / raw)
To: Xiao Guangrong, Stefan Hajnoczi
Cc: ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
Marc-André Lureau, stefanha, imammedo, rth
On 02/07/2015 20:01, Xiao Guangrong wrote:
>
> Thanks for your review, Stefan and Paolo!
>
> On 07/02/2015 05:52 PM, Paolo Bonzini wrote:
>>
>>
>> On 02/07/2015 11:20, Stefan Hajnoczi wrote:
>>>> Currently, the NVDIMM driver has been merged into upstream Linux
>>>> Kernel and
>>>> this patchset tries to enable it in virtualization field
>>>
>>> From a device model perspective, have you checked whether it makes
>>> sense
>>> to integrate nvdimms into the pc-dimm and hostmem code that is used for
>>> memory hotplug and NUMA?
>>>
>>> The NVDIMM device in your patches is a completely new TYPE_DEVICE so it
>>> doesn't share any interfaces or code with existing memory devices.
>>> Maybe that is the right solution here because NVDIMMs have different
>>> characteristics, but I'm not sure.
>>
>> The hostmem code should definitely be shared, e.g. by adding a new
>> "file" property to the memory-backend-file class. ivshmem can also use
>> it---CCing Marc-Andr�.
>
> However, file-based memory used by NVDIMM is special, it divides the file
> to two parts, one part is used as PMEM and another part is used to store
> NVDIMM's configure data.
>
> Maybe we can introduce "end-reserved" property to reserve specified size
> at the end of the file. Or create a new class type based on
> memory-backend-file (named nvdimm-backend-file) class to hide this magic
> thing?
I need to read the code then. :)
Paolo
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PATCH 00/16] implement vNVDIMM
2015-07-02 18:11 ` Paolo Bonzini
@ 2015-07-29 8:41 ` Xiao Guangrong
0 siblings, 0 replies; 28+ messages in thread
From: Xiao Guangrong @ 2015-07-29 8:41 UTC (permalink / raw)
To: Paolo Bonzini, Stefan Hajnoczi
Cc: ehabkost, kvm, mst, gleb, mtosatti, qemu-devel,
Marc-André Lureau, stefanha, imammedo, rth
On 07/03/2015 02:11 AM, Paolo Bonzini wrote:
>
>
> On 02/07/2015 20:01, Xiao Guangrong wrote:
>>
>> Thanks for your review, Stefan and Paolo!
>>
>> On 07/02/2015 05:52 PM, Paolo Bonzini wrote:
>>>
>>>
>>> On 02/07/2015 11:20, Stefan Hajnoczi wrote:
>>>>> Currently, the NVDIMM driver has been merged into upstream Linux
>>>>> Kernel and
>>>>> this patchset tries to enable it in virtualization field
>>>>
>>>> From a device model perspective, have you checked whether it makes
>>>> sense
>>>> to integrate nvdimms into the pc-dimm and hostmem code that is used for
>>>> memory hotplug and NUMA?
>>>>
>>>> The NVDIMM device in your patches is a completely new TYPE_DEVICE so it
>>>> doesn't share any interfaces or code with existing memory devices.
>>>> Maybe that is the right solution here because NVDIMMs have different
>>>> characteristics, but I'm not sure.
>>>
>>> The hostmem code should definitely be shared, e.g. by adding a new
>>> "file" property to the memory-backend-file class. ivshmem can also use
>>> it---CCing Marc-Andr�.
>>
>> However, file-based memory used by NVDIMM is special, it divides the file
>> to two parts, one part is used as PMEM and another part is used to store
>> NVDIMM's configure data.
>>
>> Maybe we can introduce "end-reserved" property to reserve specified size
>> at the end of the file. Or create a new class type based on
>> memory-backend-file (named nvdimm-backend-file) class to hide this magic
>> thing?
>
> I need to read the code then. :)
Paolo, do you have any comment? :)
^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2015-07-29 8:47 UTC | newest]
Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-01 14:50 [Qemu-devel] [PATCH 00/16] implement vNVDIMM Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 01/16] acpi: allow aml_operation_region() working on 64 bit offset Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 02/16] i386/acpi-build: allow SSDT to operate on 64 bit Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 03/16] acpi: add aml_derefof Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 04/16] acpi: add aml_sizeof Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 05/16] acpi: add aml_create_field Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 06/16] pc: implement NVDIMM device abstract Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 07/16] nvdimm: reserve address range for NVDIMM Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 08/16] nvdimm: init backend memory mapping and config data area Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 09/16] nvdimm: build ACPI NFIT table Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 10/16] nvdimm: init the address region used by _DSM method Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 11/16] nvdimm: build ACPI nvdimm devices Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 12/16] nvdimm: save arg3 for NVDIMM device _DSM method Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 13/16] nvdimm: support NFIT_CMD_IMPLEMENTED function Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 14/16] nvdimm: support NFIT_CMD_GET_CONFIG_SIZE function Xiao Guangrong
2015-07-02 9:23 ` Stefan Hajnoczi
2015-07-02 18:02 ` Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 15/16] nvdimm: support NFIT_CMD_GET_CONFIG_DATA Xiao Guangrong
2015-07-01 14:50 ` [Qemu-devel] [PATCH 16/16] nvdimm: support NFIT_CMD_SET_CONFIG_DATA Xiao Guangrong
2015-07-02 6:17 ` [Qemu-devel] [PATCH 00/16] implement vNVDIMM Michael S. Tsirkin
2015-07-02 6:34 ` Xiao Guangrong
2015-07-02 8:31 ` Stefan Hajnoczi
2015-07-02 8:35 ` Michael S. Tsirkin
2015-07-02 9:20 ` Stefan Hajnoczi
2015-07-02 9:52 ` Paolo Bonzini
2015-07-02 18:01 ` Xiao Guangrong
2015-07-02 18:11 ` Paolo Bonzini
2015-07-29 8:41 ` Xiao Guangrong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).