1 | /* |
2 | * Non-Volatile Dual In-line Memory Module Virtualization Implementation |
3 | * |
4 | * Copyright(C) 2015 Intel Corporation. |
5 | * |
6 | * Author: |
7 | * Xiao Guangrong <guangrong.xiao@linux.intel.com> |
8 | * |
9 | * NVDIMM specifications and some documents can be found at: |
10 | * NVDIMM ACPI device and NFIT are introduced in ACPI 6: |
11 | * http://www.uefi.org/sites/default/files/resources/ACPI_6.0.pdf |
12 | * NVDIMM Namespace specification: |
13 | * http://pmem.io/documents/NVDIMM_Namespace_Spec.pdf |
14 | * DSM Interface Example: |
15 | * http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf |
16 | * Driver Writer's Guide: |
17 | * http://pmem.io/documents/NVDIMM_Driver_Writers_Guide.pdf |
18 | * |
19 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
20 | * See the COPYING file in the top-level directory. |
21 | */ |
22 | |
23 | #ifndef QEMU_NVDIMM_H |
24 | #define QEMU_NVDIMM_H |
25 | |
26 | #include "hw/mem/pc-dimm.h" |
27 | #include "hw/acpi/bios-linker-loader.h" |
28 | |
29 | #define NVDIMM_DEBUG 0 |
30 | #define nvdimm_debug(fmt, ...) \ |
31 | do { \ |
32 | if (NVDIMM_DEBUG) { \ |
33 | fprintf(stderr, "nvdimm: " fmt, ## __VA_ARGS__); \ |
34 | } \ |
35 | } while (0) |
36 | |
37 | /* |
38 | * The minimum label data size is required by NVDIMM Namespace |
39 | * specification, see the chapter 2 Namespaces: |
40 | * "NVDIMMs following the NVDIMM Block Mode Specification use an area |
41 | * at least 128KB in size, which holds around 1000 labels." |
42 | */ |
43 | #define MIN_NAMESPACE_LABEL_SIZE (128UL << 10) |
44 | |
45 | #define TYPE_NVDIMM "nvdimm" |
46 | #define NVDIMM(obj) OBJECT_CHECK(NVDIMMDevice, (obj), TYPE_NVDIMM) |
47 | #define NVDIMM_CLASS(oc) OBJECT_CLASS_CHECK(NVDIMMClass, (oc), TYPE_NVDIMM) |
48 | #define NVDIMM_GET_CLASS(obj) OBJECT_GET_CLASS(NVDIMMClass, (obj), \ |
49 | TYPE_NVDIMM) |
50 | |
51 | #define NVDIMM_LABEL_SIZE_PROP "label-size" |
52 | #define NVDIMM_UNARMED_PROP "unarmed" |
53 | |
54 | struct NVDIMMDevice { |
55 | /* private */ |
56 | PCDIMMDevice parent_obj; |
57 | |
58 | /* public */ |
59 | |
60 | /* |
61 | * the size of label data in NVDIMM device which is presented to |
62 | * guest via __DSM "Get Namespace Label Size" function. |
63 | */ |
64 | uint64_t label_size; |
65 | |
66 | /* |
67 | * the address of label data which is read by __DSM "Get Namespace |
68 | * Label Data" function and written by __DSM "Set Namespace Label |
69 | * Data" function. |
70 | */ |
71 | void *label_data; |
72 | |
73 | /* |
74 | * it's the PMEM region in NVDIMM device, which is presented to |
75 | * guest via ACPI NFIT and _FIT method if NVDIMM hotplug is supported. |
76 | */ |
77 | MemoryRegion *nvdimm_mr; |
78 | |
79 | /* |
80 | * The 'on' value results in the unarmed flag set in ACPI NFIT, |
81 | * which can be used to notify guest implicitly that the host |
82 | * backend (e.g., files on HDD, /dev/pmemX, etc.) cannot guarantee |
83 | * the guest write persistence. |
84 | */ |
85 | bool unarmed; |
86 | }; |
87 | typedef struct NVDIMMDevice NVDIMMDevice; |
88 | |
89 | struct NVDIMMClass { |
90 | /* private */ |
91 | PCDIMMDeviceClass parent_class; |
92 | |
93 | /* public */ |
94 | |
95 | /* read @size bytes from NVDIMM label data at @offset into @buf. */ |
96 | void (*read_label_data)(NVDIMMDevice *nvdimm, void *buf, |
97 | uint64_t size, uint64_t offset); |
98 | /* write @size bytes from @buf to NVDIMM label data at @offset. */ |
99 | void (*write_label_data)(NVDIMMDevice *nvdimm, const void *buf, |
100 | uint64_t size, uint64_t offset); |
101 | }; |
102 | typedef struct NVDIMMClass NVDIMMClass; |
103 | |
104 | #define NVDIMM_DSM_MEM_FILE "etc/acpi/nvdimm-mem" |
105 | |
106 | /* |
107 | * 32 bits IO port starting from 0x0a18 in guest is reserved for |
108 | * NVDIMM ACPI emulation. |
109 | */ |
110 | #define NVDIMM_ACPI_IO_BASE 0x0a18 |
111 | #define NVDIMM_ACPI_IO_LEN 4 |
112 | |
113 | /* |
114 | * NvdimmFitBuffer: |
115 | * @fit: FIT structures for present NVDIMMs. It is updated when |
116 | * the NVDIMM device is plugged or unplugged. |
117 | * @dirty: It allows OSPM to detect change and restart read in |
118 | * progress if there is any. |
119 | */ |
120 | struct NvdimmFitBuffer { |
121 | GArray *fit; |
122 | bool dirty; |
123 | }; |
124 | typedef struct NvdimmFitBuffer NvdimmFitBuffer; |
125 | |
126 | struct NVDIMMState { |
127 | /* detect if NVDIMM support is enabled. */ |
128 | bool is_enabled; |
129 | |
130 | /* the data of the fw_cfg file NVDIMM_DSM_MEM_FILE. */ |
131 | GArray *dsm_mem; |
132 | |
133 | NvdimmFitBuffer fit_buf; |
134 | |
135 | /* the IO region used by OSPM to transfer control to QEMU. */ |
136 | MemoryRegion io_mr; |
137 | |
138 | /* |
139 | * Platform capabilities, section 5.2.25.9 of ACPI 6.2 Errata A |
140 | */ |
141 | int32_t persistence; |
142 | char *persistence_string; |
143 | }; |
144 | typedef struct NVDIMMState NVDIMMState; |
145 | |
146 | void nvdimm_init_acpi_state(NVDIMMState *state, MemoryRegion *io, |
147 | FWCfgState *fw_cfg, Object *owner); |
148 | void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data, |
149 | BIOSLinker *linker, NVDIMMState *state, |
150 | uint32_t ram_slots); |
151 | void nvdimm_plug(NVDIMMState *state); |
152 | void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev); |
153 | #endif |
154 | |