]> git.proxmox.com Git - mirror_qemu.git/blob - hw/mem/cxl_type3.c
target/sh4: Fix TB_FLAG_UNALIGN
[mirror_qemu.git] / hw / mem / cxl_type3.c
1 #include "qemu/osdep.h"
2 #include "qemu/units.h"
3 #include "qemu/error-report.h"
4 #include "hw/mem/memory-device.h"
5 #include "hw/mem/pc-dimm.h"
6 #include "hw/pci/pci.h"
7 #include "hw/qdev-properties.h"
8 #include "qapi/error.h"
9 #include "qemu/log.h"
10 #include "qemu/module.h"
11 #include "qemu/pmem.h"
12 #include "qemu/range.h"
13 #include "qemu/rcu.h"
14 #include "sysemu/hostmem.h"
15 #include "hw/cxl/cxl.h"
16
17 static void build_dvsecs(CXLType3Dev *ct3d)
18 {
19 CXLComponentState *cxl_cstate = &ct3d->cxl_cstate;
20 uint8_t *dvsec;
21
22 dvsec = (uint8_t *)&(CXLDVSECDevice){
23 .cap = 0x1e,
24 .ctrl = 0x2,
25 .status2 = 0x2,
26 .range1_size_hi = ct3d->hostmem->size >> 32,
27 .range1_size_lo = (2 << 5) | (2 << 2) | 0x3 |
28 (ct3d->hostmem->size & 0xF0000000),
29 .range1_base_hi = 0,
30 .range1_base_lo = 0,
31 };
32 cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE,
33 PCIE_CXL_DEVICE_DVSEC_LENGTH,
34 PCIE_CXL_DEVICE_DVSEC,
35 PCIE_CXL2_DEVICE_DVSEC_REVID, dvsec);
36
37 dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){
38 .rsvd = 0,
39 .reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX,
40 .reg0_base_hi = 0,
41 .reg1_base_lo = RBI_CXL_DEVICE_REG | CXL_DEVICE_REG_BAR_IDX,
42 .reg1_base_hi = 0,
43 };
44 cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE,
45 REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC,
46 REG_LOC_DVSEC_REVID, dvsec);
47 dvsec = (uint8_t *)&(CXLDVSECDeviceGPF){
48 .phase2_duration = 0x603, /* 3 seconds */
49 .phase2_power = 0x33, /* 0x33 miliwatts */
50 };
51 cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE,
52 GPF_DEVICE_DVSEC_LENGTH, GPF_PORT_DVSEC,
53 GPF_DEVICE_DVSEC_REVID, dvsec);
54 }
55
56 static void hdm_decoder_commit(CXLType3Dev *ct3d, int which)
57 {
58 ComponentRegisters *cregs = &ct3d->cxl_cstate.crb;
59 uint32_t *cache_mem = cregs->cache_mem_registers;
60
61 assert(which == 0);
62
63 /* TODO: Sanity checks that the decoder is possible */
64 ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMIT, 0);
65 ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, ERR, 0);
66
67 ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMITTED, 1);
68 }
69
70 static void ct3d_reg_write(void *opaque, hwaddr offset, uint64_t value,
71 unsigned size)
72 {
73 CXLComponentState *cxl_cstate = opaque;
74 ComponentRegisters *cregs = &cxl_cstate->crb;
75 CXLType3Dev *ct3d = container_of(cxl_cstate, CXLType3Dev, cxl_cstate);
76 uint32_t *cache_mem = cregs->cache_mem_registers;
77 bool should_commit = false;
78 int which_hdm = -1;
79
80 assert(size == 4);
81 g_assert(offset < CXL2_COMPONENT_CM_REGION_SIZE);
82
83 switch (offset) {
84 case A_CXL_HDM_DECODER0_CTRL:
85 should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT);
86 which_hdm = 0;
87 break;
88 default:
89 break;
90 }
91
92 stl_le_p((uint8_t *)cache_mem + offset, value);
93 if (should_commit) {
94 hdm_decoder_commit(ct3d, which_hdm);
95 }
96 }
97
98 static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
99 {
100 DeviceState *ds = DEVICE(ct3d);
101 MemoryRegion *mr;
102 char *name;
103
104 if (!ct3d->hostmem) {
105 error_setg(errp, "memdev property must be set");
106 return false;
107 }
108
109 mr = host_memory_backend_get_memory(ct3d->hostmem);
110 if (!mr) {
111 error_setg(errp, "memdev property must be set");
112 return false;
113 }
114 memory_region_set_nonvolatile(mr, true);
115 memory_region_set_enabled(mr, true);
116 host_memory_backend_set_mapped(ct3d->hostmem, true);
117
118 if (ds->id) {
119 name = g_strdup_printf("cxl-type3-dpa-space:%s", ds->id);
120 } else {
121 name = g_strdup("cxl-type3-dpa-space");
122 }
123 address_space_init(&ct3d->hostmem_as, mr, name);
124 g_free(name);
125
126 ct3d->cxl_dstate.pmem_size = ct3d->hostmem->size;
127
128 if (!ct3d->lsa) {
129 error_setg(errp, "lsa property must be set");
130 return false;
131 }
132
133 return true;
134 }
135
136 static void ct3_realize(PCIDevice *pci_dev, Error **errp)
137 {
138 CXLType3Dev *ct3d = CXL_TYPE3(pci_dev);
139 CXLComponentState *cxl_cstate = &ct3d->cxl_cstate;
140 ComponentRegisters *regs = &cxl_cstate->crb;
141 MemoryRegion *mr = &regs->component_registers;
142 uint8_t *pci_conf = pci_dev->config;
143
144 if (!cxl_setup_memory(ct3d, errp)) {
145 return;
146 }
147
148 pci_config_set_prog_interface(pci_conf, 0x10);
149 pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_CXL);
150
151 pcie_endpoint_cap_init(pci_dev, 0x80);
152 cxl_cstate->dvsec_offset = 0x100;
153
154 ct3d->cxl_cstate.pdev = pci_dev;
155 build_dvsecs(ct3d);
156
157 regs->special_ops = g_new0(MemoryRegionOps, 1);
158 regs->special_ops->write = ct3d_reg_write;
159
160 cxl_component_register_block_init(OBJECT(pci_dev), cxl_cstate,
161 TYPE_CXL_TYPE3);
162
163 pci_register_bar(
164 pci_dev, CXL_COMPONENT_REG_BAR_IDX,
165 PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, mr);
166
167 cxl_device_register_block_init(OBJECT(pci_dev), &ct3d->cxl_dstate);
168 pci_register_bar(pci_dev, CXL_DEVICE_REG_BAR_IDX,
169 PCI_BASE_ADDRESS_SPACE_MEMORY |
170 PCI_BASE_ADDRESS_MEM_TYPE_64,
171 &ct3d->cxl_dstate.device_registers);
172 }
173
174 static void ct3_exit(PCIDevice *pci_dev)
175 {
176 CXLType3Dev *ct3d = CXL_TYPE3(pci_dev);
177 CXLComponentState *cxl_cstate = &ct3d->cxl_cstate;
178 ComponentRegisters *regs = &cxl_cstate->crb;
179
180 g_free(regs->special_ops);
181 address_space_destroy(&ct3d->hostmem_as);
182 }
183
184 /* TODO: Support multiple HDM decoders and DPA skip */
185 static bool cxl_type3_dpa(CXLType3Dev *ct3d, hwaddr host_addr, uint64_t *dpa)
186 {
187 uint32_t *cache_mem = ct3d->cxl_cstate.crb.cache_mem_registers;
188 uint64_t decoder_base, decoder_size, hpa_offset;
189 uint32_t hdm0_ctrl;
190 int ig, iw;
191
192 decoder_base = (((uint64_t)cache_mem[R_CXL_HDM_DECODER0_BASE_HI] << 32) |
193 cache_mem[R_CXL_HDM_DECODER0_BASE_LO]);
194 if ((uint64_t)host_addr < decoder_base) {
195 return false;
196 }
197
198 hpa_offset = (uint64_t)host_addr - decoder_base;
199
200 decoder_size = ((uint64_t)cache_mem[R_CXL_HDM_DECODER0_SIZE_HI] << 32) |
201 cache_mem[R_CXL_HDM_DECODER0_SIZE_LO];
202 if (hpa_offset >= decoder_size) {
203 return false;
204 }
205
206 hdm0_ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL];
207 iw = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IW);
208 ig = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IG);
209
210 *dpa = (MAKE_64BIT_MASK(0, 8 + ig) & hpa_offset) |
211 ((MAKE_64BIT_MASK(8 + ig + iw, 64 - 8 - ig - iw) & hpa_offset) >> iw);
212
213 return true;
214 }
215
216 MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data,
217 unsigned size, MemTxAttrs attrs)
218 {
219 CXLType3Dev *ct3d = CXL_TYPE3(d);
220 uint64_t dpa_offset;
221 MemoryRegion *mr;
222
223 /* TODO support volatile region */
224 mr = host_memory_backend_get_memory(ct3d->hostmem);
225 if (!mr) {
226 return MEMTX_ERROR;
227 }
228
229 if (!cxl_type3_dpa(ct3d, host_addr, &dpa_offset)) {
230 return MEMTX_ERROR;
231 }
232
233 if (dpa_offset > int128_get64(mr->size)) {
234 return MEMTX_ERROR;
235 }
236
237 return address_space_read(&ct3d->hostmem_as, dpa_offset, attrs, data, size);
238 }
239
240 MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data,
241 unsigned size, MemTxAttrs attrs)
242 {
243 CXLType3Dev *ct3d = CXL_TYPE3(d);
244 uint64_t dpa_offset;
245 MemoryRegion *mr;
246
247 mr = host_memory_backend_get_memory(ct3d->hostmem);
248 if (!mr) {
249 return MEMTX_OK;
250 }
251
252 if (!cxl_type3_dpa(ct3d, host_addr, &dpa_offset)) {
253 return MEMTX_OK;
254 }
255
256 if (dpa_offset > int128_get64(mr->size)) {
257 return MEMTX_OK;
258 }
259 return address_space_write(&ct3d->hostmem_as, dpa_offset, attrs,
260 &data, size);
261 }
262
263 static void ct3d_reset(DeviceState *dev)
264 {
265 CXLType3Dev *ct3d = CXL_TYPE3(dev);
266 uint32_t *reg_state = ct3d->cxl_cstate.crb.cache_mem_registers;
267 uint32_t *write_msk = ct3d->cxl_cstate.crb.cache_mem_regs_write_mask;
268
269 cxl_component_register_init_common(reg_state, write_msk, CXL2_TYPE3_DEVICE);
270 cxl_device_register_init_common(&ct3d->cxl_dstate);
271 }
272
273 static Property ct3_props[] = {
274 DEFINE_PROP_LINK("memdev", CXLType3Dev, hostmem, TYPE_MEMORY_BACKEND,
275 HostMemoryBackend *),
276 DEFINE_PROP_LINK("lsa", CXLType3Dev, lsa, TYPE_MEMORY_BACKEND,
277 HostMemoryBackend *),
278 DEFINE_PROP_END_OF_LIST(),
279 };
280
281 static uint64_t get_lsa_size(CXLType3Dev *ct3d)
282 {
283 MemoryRegion *mr;
284
285 mr = host_memory_backend_get_memory(ct3d->lsa);
286 return memory_region_size(mr);
287 }
288
289 static void validate_lsa_access(MemoryRegion *mr, uint64_t size,
290 uint64_t offset)
291 {
292 assert(offset + size <= memory_region_size(mr));
293 assert(offset + size > offset);
294 }
295
296 static uint64_t get_lsa(CXLType3Dev *ct3d, void *buf, uint64_t size,
297 uint64_t offset)
298 {
299 MemoryRegion *mr;
300 void *lsa;
301
302 mr = host_memory_backend_get_memory(ct3d->lsa);
303 validate_lsa_access(mr, size, offset);
304
305 lsa = memory_region_get_ram_ptr(mr) + offset;
306 memcpy(buf, lsa, size);
307
308 return size;
309 }
310
311 static void set_lsa(CXLType3Dev *ct3d, const void *buf, uint64_t size,
312 uint64_t offset)
313 {
314 MemoryRegion *mr;
315 void *lsa;
316
317 mr = host_memory_backend_get_memory(ct3d->lsa);
318 validate_lsa_access(mr, size, offset);
319
320 lsa = memory_region_get_ram_ptr(mr) + offset;
321 memcpy(lsa, buf, size);
322 memory_region_set_dirty(mr, offset, size);
323
324 /*
325 * Just like the PMEM, if the guest is not allowed to exit gracefully, label
326 * updates will get lost.
327 */
328 }
329
330 static void ct3_class_init(ObjectClass *oc, void *data)
331 {
332 DeviceClass *dc = DEVICE_CLASS(oc);
333 PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
334 CXLType3Class *cvc = CXL_TYPE3_CLASS(oc);
335
336 pc->realize = ct3_realize;
337 pc->exit = ct3_exit;
338 pc->class_id = PCI_CLASS_STORAGE_EXPRESS;
339 pc->vendor_id = PCI_VENDOR_ID_INTEL;
340 pc->device_id = 0xd93; /* LVF for now */
341 pc->revision = 1;
342
343 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
344 dc->desc = "CXL PMEM Device (Type 3)";
345 dc->reset = ct3d_reset;
346 device_class_set_props(dc, ct3_props);
347
348 cvc->get_lsa_size = get_lsa_size;
349 cvc->get_lsa = get_lsa;
350 cvc->set_lsa = set_lsa;
351 }
352
353 static const TypeInfo ct3d_info = {
354 .name = TYPE_CXL_TYPE3,
355 .parent = TYPE_PCI_DEVICE,
356 .class_size = sizeof(struct CXLType3Class),
357 .class_init = ct3_class_init,
358 .instance_size = sizeof(CXLType3Dev),
359 .interfaces = (InterfaceInfo[]) {
360 { INTERFACE_CXL_DEVICE },
361 { INTERFACE_PCIE_DEVICE },
362 {}
363 },
364 };
365
366 static void ct3d_registers(void)
367 {
368 type_register_static(&ct3d_info);
369 }
370
371 type_init(ct3d_registers);