1#include "qemu/osdep.h"
2#include "qemu/units.h"
3#include "qemu/error-report.h"
4#include "qapi/qapi-commands-cxl.h"
5#include "hw/mem/memory-device.h"
6#include "hw/mem/pc-dimm.h"
7#include "hw/pci/pci.h"
8#include "hw/qdev-properties.h"
9#include "qapi/error.h"
10#include "qemu/log.h"
11#include "qemu/module.h"
12#include "qemu/pmem.h"
13#include "qemu/range.h"
14#include "qemu/rcu.h"
15#include "sysemu/hostmem.h"
16#include "sysemu/numa.h"
17#include "hw/cxl/cxl.h"
18#include "hw/pci/msix.h"
19
20#define DWORD_BYTE 4
21
22
23enum {
24 CT3_CDAT_DSMAS,
25 CT3_CDAT_DSLBIS0,
26 CT3_CDAT_DSLBIS1,
27 CT3_CDAT_DSLBIS2,
28 CT3_CDAT_DSLBIS3,
29 CT3_CDAT_DSEMTS,
30 CT3_CDAT_NUM_ENTRIES
31};
32
33static int ct3_build_cdat_entries_for_mr(CDATSubHeader **cdat_table,
34 int dsmad_handle, MemoryRegion *mr)
35{
36 g_autofree CDATDsmas *dsmas = NULL;
37 g_autofree CDATDslbis *dslbis0 = NULL;
38 g_autofree CDATDslbis *dslbis1 = NULL;
39 g_autofree CDATDslbis *dslbis2 = NULL;
40 g_autofree CDATDslbis *dslbis3 = NULL;
41 g_autofree CDATDsemts *dsemts = NULL;
42
43 dsmas = g_malloc(sizeof(*dsmas));
44 if (!dsmas) {
45 return -ENOMEM;
46 }
47 *dsmas = (CDATDsmas) {
48 .header = {
49 .type = CDAT_TYPE_DSMAS,
50 .length = sizeof(*dsmas),
51 },
52 .DSMADhandle = dsmad_handle,
53 .flags = CDAT_DSMAS_FLAG_NV,
54 .DPA_base = 0,
55 .DPA_length = int128_get64(mr->size),
56 };
57
58
59 dslbis0 = g_malloc(sizeof(*dslbis0));
60 if (!dslbis0) {
61 return -ENOMEM;
62 }
63 *dslbis0 = (CDATDslbis) {
64 .header = {
65 .type = CDAT_TYPE_DSLBIS,
66 .length = sizeof(*dslbis0),
67 },
68 .handle = dsmad_handle,
69 .flags = HMAT_LB_MEM_MEMORY,
70 .data_type = HMAT_LB_DATA_READ_LATENCY,
71 .entry_base_unit = 10000,
72 .entry[0] = 15,
73 };
74
75 dslbis1 = g_malloc(sizeof(*dslbis1));
76 if (!dslbis1) {
77 return -ENOMEM;
78 }
79 *dslbis1 = (CDATDslbis) {
80 .header = {
81 .type = CDAT_TYPE_DSLBIS,
82 .length = sizeof(*dslbis1),
83 },
84 .handle = dsmad_handle,
85 .flags = HMAT_LB_MEM_MEMORY,
86 .data_type = HMAT_LB_DATA_WRITE_LATENCY,
87 .entry_base_unit = 10000,
88 .entry[0] = 25,
89 };
90
91 dslbis2 = g_malloc(sizeof(*dslbis2));
92 if (!dslbis2) {
93 return -ENOMEM;
94 }
95 *dslbis2 = (CDATDslbis) {
96 .header = {
97 .type = CDAT_TYPE_DSLBIS,
98 .length = sizeof(*dslbis2),
99 },
100 .handle = dsmad_handle,
101 .flags = HMAT_LB_MEM_MEMORY,
102 .data_type = HMAT_LB_DATA_READ_BANDWIDTH,
103 .entry_base_unit = 1000,
104 .entry[0] = 16,
105 };
106
107 dslbis3 = g_malloc(sizeof(*dslbis3));
108 if (!dslbis3) {
109 return -ENOMEM;
110 }
111 *dslbis3 = (CDATDslbis) {
112 .header = {
113 .type = CDAT_TYPE_DSLBIS,
114 .length = sizeof(*dslbis3),
115 },
116 .handle = dsmad_handle,
117 .flags = HMAT_LB_MEM_MEMORY,
118 .data_type = HMAT_LB_DATA_WRITE_BANDWIDTH,
119 .entry_base_unit = 1000,
120 .entry[0] = 16,
121 };
122
123 dsemts = g_malloc(sizeof(*dsemts));
124 if (!dsemts) {
125 return -ENOMEM;
126 }
127 *dsemts = (CDATDsemts) {
128 .header = {
129 .type = CDAT_TYPE_DSEMTS,
130 .length = sizeof(*dsemts),
131 },
132 .DSMAS_handle = dsmad_handle,
133
134 .EFI_memory_type_attr = 2,
135 .DPA_offset = 0,
136 .DPA_length = int128_get64(mr->size),
137 };
138
139
140 cdat_table[CT3_CDAT_DSMAS] = g_steal_pointer(&dsmas);
141 cdat_table[CT3_CDAT_DSLBIS0] = g_steal_pointer(&dslbis0);
142 cdat_table[CT3_CDAT_DSLBIS1] = g_steal_pointer(&dslbis1);
143 cdat_table[CT3_CDAT_DSLBIS2] = g_steal_pointer(&dslbis2);
144 cdat_table[CT3_CDAT_DSLBIS3] = g_steal_pointer(&dslbis3);
145 cdat_table[CT3_CDAT_DSEMTS] = g_steal_pointer(&dsemts);
146
147 return 0;
148}
149
150static int ct3_build_cdat_table(CDATSubHeader ***cdat_table, void *priv)
151{
152 g_autofree CDATSubHeader **table = NULL;
153 MemoryRegion *nonvolatile_mr;
154 CXLType3Dev *ct3d = priv;
155 int dsmad_handle = 0;
156 int rc;
157
158 if (!ct3d->hostmem) {
159 return 0;
160 }
161
162 nonvolatile_mr = host_memory_backend_get_memory(ct3d->hostmem);
163 if (!nonvolatile_mr) {
164 return -EINVAL;
165 }
166
167 table = g_malloc0(CT3_CDAT_NUM_ENTRIES * sizeof(*table));
168 if (!table) {
169 return -ENOMEM;
170 }
171
172 rc = ct3_build_cdat_entries_for_mr(table, dsmad_handle++, nonvolatile_mr);
173 if (rc < 0) {
174 return rc;
175 }
176
177 *cdat_table = g_steal_pointer(&table);
178
179 return CT3_CDAT_NUM_ENTRIES;
180}
181
182static void ct3_free_cdat_table(CDATSubHeader **cdat_table, int num, void *priv)
183{
184 int i;
185
186 for (i = 0; i < num; i++) {
187 g_free(cdat_table[i]);
188 }
189 g_free(cdat_table);
190}
191
192static bool cxl_doe_cdat_rsp(DOECap *doe_cap)
193{
194 CDATObject *cdat = &CXL_TYPE3(doe_cap->pdev)->cxl_cstate.cdat;
195 uint16_t ent;
196 void *base;
197 uint32_t len;
198 CDATReq *req = pcie_doe_get_write_mbox_ptr(doe_cap);
199 CDATRsp rsp;
200
201 assert(cdat->entry_len);
202
203
204 if (pcie_doe_get_obj_len(req) <
205 DIV_ROUND_UP(sizeof(CDATReq), DWORD_BYTE)) {
206 return false;
207 }
208
209 ent = req->entry_handle;
210 base = cdat->entry[ent].base;
211 len = cdat->entry[ent].length;
212
213 rsp = (CDATRsp) {
214 .header = {
215 .vendor_id = CXL_VENDOR_ID,
216 .data_obj_type = CXL_DOE_TABLE_ACCESS,
217 .reserved = 0x0,
218 .length = DIV_ROUND_UP((sizeof(rsp) + len), DWORD_BYTE),
219 },
220 .rsp_code = CXL_DOE_TAB_RSP,
221 .table_type = CXL_DOE_TAB_TYPE_CDAT,
222 .entry_handle = (ent < cdat->entry_len - 1) ?
223 ent + 1 : CXL_DOE_TAB_ENT_MAX,
224 };
225
226 memcpy(doe_cap->read_mbox, &rsp, sizeof(rsp));
227 memcpy(doe_cap->read_mbox + DIV_ROUND_UP(sizeof(rsp), DWORD_BYTE),
228 base, len);
229
230 doe_cap->read_mbox_len += rsp.header.length;
231
232 return true;
233}
234
235static uint32_t ct3d_config_read(PCIDevice *pci_dev, uint32_t addr, int size)
236{
237 CXLType3Dev *ct3d = CXL_TYPE3(pci_dev);
238 uint32_t val;
239
240 if (pcie_doe_read_config(&ct3d->doe_cdat, addr, size, &val)) {
241 return val;
242 }
243
244 return pci_default_read_config(pci_dev, addr, size);
245}
246
247static void ct3d_config_write(PCIDevice *pci_dev, uint32_t addr, uint32_t val,
248 int size)
249{
250 CXLType3Dev *ct3d = CXL_TYPE3(pci_dev);
251
252 pcie_doe_write_config(&ct3d->doe_cdat, addr, val, size);
253 pci_default_write_config(pci_dev, addr, val, size);
254 pcie_aer_write_config(pci_dev, addr, val, size);
255}
256
257
258
259
260
261#define UI64_NULL ~(0ULL)
262
263static void build_dvsecs(CXLType3Dev *ct3d)
264{
265 CXLComponentState *cxl_cstate = &ct3d->cxl_cstate;
266 uint8_t *dvsec;
267
268 dvsec = (uint8_t *)&(CXLDVSECDevice){
269 .cap = 0x1e,
270 .ctrl = 0x2,
271 .status2 = 0x2,
272 .range1_size_hi = ct3d->hostmem->size >> 32,
273 .range1_size_lo = (2 << 5) | (2 << 2) | 0x3 |
274 (ct3d->hostmem->size & 0xF0000000),
275 .range1_base_hi = 0,
276 .range1_base_lo = 0,
277 };
278 cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE,
279 PCIE_CXL_DEVICE_DVSEC_LENGTH,
280 PCIE_CXL_DEVICE_DVSEC,
281 PCIE_CXL2_DEVICE_DVSEC_REVID, dvsec);
282
283 dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){
284 .rsvd = 0,
285 .reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX,
286 .reg0_base_hi = 0,
287 .reg1_base_lo = RBI_CXL_DEVICE_REG | CXL_DEVICE_REG_BAR_IDX,
288 .reg1_base_hi = 0,
289 };
290 cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE,
291 REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC,
292 REG_LOC_DVSEC_REVID, dvsec);
293 dvsec = (uint8_t *)&(CXLDVSECDeviceGPF){
294 .phase2_duration = 0x603,
295 .phase2_power = 0x33,
296 };
297 cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE,
298 GPF_DEVICE_DVSEC_LENGTH, GPF_DEVICE_DVSEC,
299 GPF_DEVICE_DVSEC_REVID, dvsec);
300
301 dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){
302 .cap = 0x26,
303 .ctrl = 0x02,
304 .status = 0x26,
305 .rcvd_mod_ts_data_phase1 = 0xef,
306 };
307 cxl_component_create_dvsec(cxl_cstate, CXL2_TYPE3_DEVICE,
308 PCIE_FLEXBUS_PORT_DVSEC_LENGTH_2_0,
309 PCIE_FLEXBUS_PORT_DVSEC,
310 PCIE_FLEXBUS_PORT_DVSEC_REVID_2_0, dvsec);
311}
312
313static void hdm_decoder_commit(CXLType3Dev *ct3d, int which)
314{
315 ComponentRegisters *cregs = &ct3d->cxl_cstate.crb;
316 uint32_t *cache_mem = cregs->cache_mem_registers;
317
318 assert(which == 0);
319
320
321 ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMIT, 0);
322 ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, ERR, 0);
323
324 ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMITTED, 1);
325}
326
327static int ct3d_qmp_uncor_err_to_cxl(CxlUncorErrorType qmp_err)
328{
329 switch (qmp_err) {
330 case CXL_UNCOR_ERROR_TYPE_CACHE_DATA_PARITY:
331 return CXL_RAS_UNC_ERR_CACHE_DATA_PARITY;
332 case CXL_UNCOR_ERROR_TYPE_CACHE_ADDRESS_PARITY:
333 return CXL_RAS_UNC_ERR_CACHE_ADDRESS_PARITY;
334 case CXL_UNCOR_ERROR_TYPE_CACHE_BE_PARITY:
335 return CXL_RAS_UNC_ERR_CACHE_BE_PARITY;
336 case CXL_UNCOR_ERROR_TYPE_CACHE_DATA_ECC:
337 return CXL_RAS_UNC_ERR_CACHE_DATA_ECC;
338 case CXL_UNCOR_ERROR_TYPE_MEM_DATA_PARITY:
339 return CXL_RAS_UNC_ERR_MEM_DATA_PARITY;
340 case CXL_UNCOR_ERROR_TYPE_MEM_ADDRESS_PARITY:
341 return CXL_RAS_UNC_ERR_MEM_ADDRESS_PARITY;
342 case CXL_UNCOR_ERROR_TYPE_MEM_BE_PARITY:
343 return CXL_RAS_UNC_ERR_MEM_BE_PARITY;
344 case CXL_UNCOR_ERROR_TYPE_MEM_DATA_ECC:
345 return CXL_RAS_UNC_ERR_MEM_DATA_ECC;
346 case CXL_UNCOR_ERROR_TYPE_REINIT_THRESHOLD:
347 return CXL_RAS_UNC_ERR_REINIT_THRESHOLD;
348 case CXL_UNCOR_ERROR_TYPE_RSVD_ENCODING:
349 return CXL_RAS_UNC_ERR_RSVD_ENCODING;
350 case CXL_UNCOR_ERROR_TYPE_POISON_RECEIVED:
351 return CXL_RAS_UNC_ERR_POISON_RECEIVED;
352 case CXL_UNCOR_ERROR_TYPE_RECEIVER_OVERFLOW:
353 return CXL_RAS_UNC_ERR_RECEIVER_OVERFLOW;
354 case CXL_UNCOR_ERROR_TYPE_INTERNAL:
355 return CXL_RAS_UNC_ERR_INTERNAL;
356 case CXL_UNCOR_ERROR_TYPE_CXL_IDE_TX:
357 return CXL_RAS_UNC_ERR_CXL_IDE_TX;
358 case CXL_UNCOR_ERROR_TYPE_CXL_IDE_RX:
359 return CXL_RAS_UNC_ERR_CXL_IDE_RX;
360 default:
361 return -EINVAL;
362 }
363}
364
365static int ct3d_qmp_cor_err_to_cxl(CxlCorErrorType qmp_err)
366{
367 switch (qmp_err) {
368 case CXL_COR_ERROR_TYPE_CACHE_DATA_ECC:
369 return CXL_RAS_COR_ERR_CACHE_DATA_ECC;
370 case CXL_COR_ERROR_TYPE_MEM_DATA_ECC:
371 return CXL_RAS_COR_ERR_MEM_DATA_ECC;
372 case CXL_COR_ERROR_TYPE_CRC_THRESHOLD:
373 return CXL_RAS_COR_ERR_CRC_THRESHOLD;
374 case CXL_COR_ERROR_TYPE_RETRY_THRESHOLD:
375 return CXL_RAS_COR_ERR_RETRY_THRESHOLD;
376 case CXL_COR_ERROR_TYPE_CACHE_POISON_RECEIVED:
377 return CXL_RAS_COR_ERR_CACHE_POISON_RECEIVED;
378 case CXL_COR_ERROR_TYPE_MEM_POISON_RECEIVED:
379 return CXL_RAS_COR_ERR_MEM_POISON_RECEIVED;
380 case CXL_COR_ERROR_TYPE_PHYSICAL:
381 return CXL_RAS_COR_ERR_PHYSICAL;
382 default:
383 return -EINVAL;
384 }
385}
386
387static void ct3d_reg_write(void *opaque, hwaddr offset, uint64_t value,
388 unsigned size)
389{
390 CXLComponentState *cxl_cstate = opaque;
391 ComponentRegisters *cregs = &cxl_cstate->crb;
392 CXLType3Dev *ct3d = container_of(cxl_cstate, CXLType3Dev, cxl_cstate);
393 uint32_t *cache_mem = cregs->cache_mem_registers;
394 bool should_commit = false;
395 int which_hdm = -1;
396
397 assert(size == 4);
398 g_assert(offset < CXL2_COMPONENT_CM_REGION_SIZE);
399
400 switch (offset) {
401 case A_CXL_HDM_DECODER0_CTRL:
402 should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT);
403 which_hdm = 0;
404 break;
405 case A_CXL_RAS_UNC_ERR_STATUS:
406 {
407 uint32_t capctrl = ldl_le_p(cache_mem + R_CXL_RAS_ERR_CAP_CTRL);
408 uint32_t fe = FIELD_EX32(capctrl, CXL_RAS_ERR_CAP_CTRL, FIRST_ERROR_POINTER);
409 CXLError *cxl_err;
410 uint32_t unc_err;
411
412
413
414
415
416 if (!QTAILQ_EMPTY(&ct3d->error_list)) {
417 if ((1 << fe) ^ value) {
418 CXLError *cxl_next;
419
420
421
422
423
424
425
426
427 QTAILQ_FOREACH_SAFE(cxl_err, &ct3d->error_list, node, cxl_next) {
428 if ((1 << cxl_err->type) & value) {
429 QTAILQ_REMOVE(&ct3d->error_list, cxl_err, node);
430 g_free(cxl_err);
431 }
432 }
433 } else {
434
435 cxl_err = QTAILQ_FIRST(&ct3d->error_list);
436 QTAILQ_REMOVE(&ct3d->error_list, cxl_err, node);
437 g_free(cxl_err);
438 }
439
440
441
442
443
444 if (!QTAILQ_EMPTY(&ct3d->error_list)) {
445 uint32_t *header_log = &cache_mem[R_CXL_RAS_ERR_HEADER0];
446 int i;
447
448 cxl_err = QTAILQ_FIRST(&ct3d->error_list);
449 for (i = 0; i < CXL_RAS_ERR_HEADER_NUM; i++) {
450 stl_le_p(header_log + i, cxl_err->header[i]);
451 }
452 capctrl = FIELD_DP32(capctrl, CXL_RAS_ERR_CAP_CTRL,
453 FIRST_ERROR_POINTER, cxl_err->type);
454 } else {
455
456
457
458
459
460 capctrl = FIELD_DP32(capctrl, CXL_RAS_ERR_CAP_CTRL,
461 FIRST_ERROR_POINTER,
462 CXL_RAS_UNC_ERR_CXL_UNUSED);
463 }
464 stl_le_p((uint8_t *)cache_mem + A_CXL_RAS_ERR_CAP_CTRL, capctrl);
465 }
466 unc_err = 0;
467 QTAILQ_FOREACH(cxl_err, &ct3d->error_list, node) {
468 unc_err |= 1 << cxl_err->type;
469 }
470 stl_le_p((uint8_t *)cache_mem + offset, unc_err);
471
472 return;
473 }
474 case A_CXL_RAS_COR_ERR_STATUS:
475 {
476 uint32_t rw1c = value;
477 uint32_t temp = ldl_le_p((uint8_t *)cache_mem + offset);
478 temp &= ~rw1c;
479 stl_le_p((uint8_t *)cache_mem + offset, temp);
480 return;
481 }
482 default:
483 break;
484 }
485
486 stl_le_p((uint8_t *)cache_mem + offset, value);
487 if (should_commit) {
488 hdm_decoder_commit(ct3d, which_hdm);
489 }
490}
491
492static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
493{
494 DeviceState *ds = DEVICE(ct3d);
495 MemoryRegion *mr;
496 char *name;
497
498 if (!ct3d->hostmem) {
499 error_setg(errp, "memdev property must be set");
500 return false;
501 }
502
503 mr = host_memory_backend_get_memory(ct3d->hostmem);
504 if (!mr) {
505 error_setg(errp, "memdev property must be set");
506 return false;
507 }
508 memory_region_set_nonvolatile(mr, true);
509 memory_region_set_enabled(mr, true);
510 host_memory_backend_set_mapped(ct3d->hostmem, true);
511
512 if (ds->id) {
513 name = g_strdup_printf("cxl-type3-dpa-space:%s", ds->id);
514 } else {
515 name = g_strdup("cxl-type3-dpa-space");
516 }
517 address_space_init(&ct3d->hostmem_as, mr, name);
518 g_free(name);
519
520 ct3d->cxl_dstate.pmem_size = ct3d->hostmem->size;
521
522 if (!ct3d->lsa) {
523 error_setg(errp, "lsa property must be set");
524 return false;
525 }
526
527 return true;
528}
529
530static DOEProtocol doe_cdat_prot[] = {
531 { CXL_VENDOR_ID, CXL_DOE_TABLE_ACCESS, cxl_doe_cdat_rsp },
532 { }
533};
534
535static void ct3_realize(PCIDevice *pci_dev, Error **errp)
536{
537 CXLType3Dev *ct3d = CXL_TYPE3(pci_dev);
538 CXLComponentState *cxl_cstate = &ct3d->cxl_cstate;
539 ComponentRegisters *regs = &cxl_cstate->crb;
540 MemoryRegion *mr = ®s->component_registers;
541 uint8_t *pci_conf = pci_dev->config;
542 unsigned short msix_num = 1;
543 int i, rc;
544
545 QTAILQ_INIT(&ct3d->error_list);
546
547 if (!cxl_setup_memory(ct3d, errp)) {
548 return;
549 }
550
551 pci_config_set_prog_interface(pci_conf, 0x10);
552
553 pcie_endpoint_cap_init(pci_dev, 0x80);
554 if (ct3d->sn != UI64_NULL) {
555 pcie_dev_ser_num_init(pci_dev, 0x100, ct3d->sn);
556 cxl_cstate->dvsec_offset = 0x100 + 0x0c;
557 } else {
558 cxl_cstate->dvsec_offset = 0x100;
559 }
560
561 ct3d->cxl_cstate.pdev = pci_dev;
562 build_dvsecs(ct3d);
563
564 regs->special_ops = g_new0(MemoryRegionOps, 1);
565 regs->special_ops->write = ct3d_reg_write;
566
567 cxl_component_register_block_init(OBJECT(pci_dev), cxl_cstate,
568 TYPE_CXL_TYPE3);
569
570 pci_register_bar(
571 pci_dev, CXL_COMPONENT_REG_BAR_IDX,
572 PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64, mr);
573
574 cxl_device_register_block_init(OBJECT(pci_dev), &ct3d->cxl_dstate);
575 pci_register_bar(pci_dev, CXL_DEVICE_REG_BAR_IDX,
576 PCI_BASE_ADDRESS_SPACE_MEMORY |
577 PCI_BASE_ADDRESS_MEM_TYPE_64,
578 &ct3d->cxl_dstate.device_registers);
579
580
581 rc = msix_init_exclusive_bar(pci_dev, msix_num, 4, NULL);
582 if (rc) {
583 goto err_address_space_free;
584 }
585 for (i = 0; i < msix_num; i++) {
586 msix_vector_use(pci_dev, i);
587 }
588
589
590 pcie_doe_init(pci_dev, &ct3d->doe_cdat, 0x190, doe_cdat_prot, true, 0);
591
592 cxl_cstate->cdat.build_cdat_table = ct3_build_cdat_table;
593 cxl_cstate->cdat.free_cdat_table = ct3_free_cdat_table;
594 cxl_cstate->cdat.private = ct3d;
595 cxl_doe_cdat_init(cxl_cstate, errp);
596
597 pcie_cap_deverr_init(pci_dev);
598
599 rc = pcie_aer_init(pci_dev, PCI_ERR_VER, 0x200, PCI_ERR_SIZEOF, NULL);
600 if (rc) {
601 goto err_release_cdat;
602 }
603
604 return;
605
606err_release_cdat:
607 cxl_doe_cdat_release(cxl_cstate);
608 g_free(regs->special_ops);
609err_address_space_free:
610 address_space_destroy(&ct3d->hostmem_as);
611 return;
612}
613
614static void ct3_exit(PCIDevice *pci_dev)
615{
616 CXLType3Dev *ct3d = CXL_TYPE3(pci_dev);
617 CXLComponentState *cxl_cstate = &ct3d->cxl_cstate;
618 ComponentRegisters *regs = &cxl_cstate->crb;
619
620 pcie_aer_exit(pci_dev);
621 cxl_doe_cdat_release(cxl_cstate);
622 g_free(regs->special_ops);
623 address_space_destroy(&ct3d->hostmem_as);
624}
625
626
627static bool cxl_type3_dpa(CXLType3Dev *ct3d, hwaddr host_addr, uint64_t *dpa)
628{
629 uint32_t *cache_mem = ct3d->cxl_cstate.crb.cache_mem_registers;
630 uint64_t decoder_base, decoder_size, hpa_offset;
631 uint32_t hdm0_ctrl;
632 int ig, iw;
633
634 decoder_base = (((uint64_t)cache_mem[R_CXL_HDM_DECODER0_BASE_HI] << 32) |
635 cache_mem[R_CXL_HDM_DECODER0_BASE_LO]);
636 if ((uint64_t)host_addr < decoder_base) {
637 return false;
638 }
639
640 hpa_offset = (uint64_t)host_addr - decoder_base;
641
642 decoder_size = ((uint64_t)cache_mem[R_CXL_HDM_DECODER0_SIZE_HI] << 32) |
643 cache_mem[R_CXL_HDM_DECODER0_SIZE_LO];
644 if (hpa_offset >= decoder_size) {
645 return false;
646 }
647
648 hdm0_ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL];
649 iw = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IW);
650 ig = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IG);
651
652 *dpa = (MAKE_64BIT_MASK(0, 8 + ig) & hpa_offset) |
653 ((MAKE_64BIT_MASK(8 + ig + iw, 64 - 8 - ig - iw) & hpa_offset) >> iw);
654
655 return true;
656}
657
658MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data,
659 unsigned size, MemTxAttrs attrs)
660{
661 CXLType3Dev *ct3d = CXL_TYPE3(d);
662 uint64_t dpa_offset;
663 MemoryRegion *mr;
664
665
666 mr = host_memory_backend_get_memory(ct3d->hostmem);
667 if (!mr) {
668 return MEMTX_ERROR;
669 }
670
671 if (!cxl_type3_dpa(ct3d, host_addr, &dpa_offset)) {
672 return MEMTX_ERROR;
673 }
674
675 if (dpa_offset > int128_get64(mr->size)) {
676 return MEMTX_ERROR;
677 }
678
679 return address_space_read(&ct3d->hostmem_as, dpa_offset, attrs, data, size);
680}
681
682MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data,
683 unsigned size, MemTxAttrs attrs)
684{
685 CXLType3Dev *ct3d = CXL_TYPE3(d);
686 uint64_t dpa_offset;
687 MemoryRegion *mr;
688
689 mr = host_memory_backend_get_memory(ct3d->hostmem);
690 if (!mr) {
691 return MEMTX_OK;
692 }
693
694 if (!cxl_type3_dpa(ct3d, host_addr, &dpa_offset)) {
695 return MEMTX_OK;
696 }
697
698 if (dpa_offset > int128_get64(mr->size)) {
699 return MEMTX_OK;
700 }
701 return address_space_write(&ct3d->hostmem_as, dpa_offset, attrs,
702 &data, size);
703}
704
705static void ct3d_reset(DeviceState *dev)
706{
707 CXLType3Dev *ct3d = CXL_TYPE3(dev);
708 uint32_t *reg_state = ct3d->cxl_cstate.crb.cache_mem_registers;
709 uint32_t *write_msk = ct3d->cxl_cstate.crb.cache_mem_regs_write_mask;
710
711 cxl_component_register_init_common(reg_state, write_msk, CXL2_TYPE3_DEVICE);
712 cxl_device_register_init_common(&ct3d->cxl_dstate);
713}
714
715static Property ct3_props[] = {
716 DEFINE_PROP_LINK("memdev", CXLType3Dev, hostmem, TYPE_MEMORY_BACKEND,
717 HostMemoryBackend *),
718 DEFINE_PROP_LINK("lsa", CXLType3Dev, lsa, TYPE_MEMORY_BACKEND,
719 HostMemoryBackend *),
720 DEFINE_PROP_UINT64("sn", CXLType3Dev, sn, UI64_NULL),
721 DEFINE_PROP_STRING("cdat", CXLType3Dev, cxl_cstate.cdat.filename),
722 DEFINE_PROP_END_OF_LIST(),
723};
724
725static uint64_t get_lsa_size(CXLType3Dev *ct3d)
726{
727 MemoryRegion *mr;
728
729 mr = host_memory_backend_get_memory(ct3d->lsa);
730 return memory_region_size(mr);
731}
732
733static void validate_lsa_access(MemoryRegion *mr, uint64_t size,
734 uint64_t offset)
735{
736 assert(offset + size <= memory_region_size(mr));
737 assert(offset + size > offset);
738}
739
740static uint64_t get_lsa(CXLType3Dev *ct3d, void *buf, uint64_t size,
741 uint64_t offset)
742{
743 MemoryRegion *mr;
744 void *lsa;
745
746 mr = host_memory_backend_get_memory(ct3d->lsa);
747 validate_lsa_access(mr, size, offset);
748
749 lsa = memory_region_get_ram_ptr(mr) + offset;
750 memcpy(buf, lsa, size);
751
752 return size;
753}
754
755static void set_lsa(CXLType3Dev *ct3d, const void *buf, uint64_t size,
756 uint64_t offset)
757{
758 MemoryRegion *mr;
759 void *lsa;
760
761 mr = host_memory_backend_get_memory(ct3d->lsa);
762 validate_lsa_access(mr, size, offset);
763
764 lsa = memory_region_get_ram_ptr(mr) + offset;
765 memcpy(lsa, buf, size);
766 memory_region_set_dirty(mr, offset, size);
767
768
769
770
771
772}
773
774
775void qmp_cxl_inject_uncorrectable_errors(const char *path,
776 CXLUncorErrorRecordList *errors,
777 Error **errp)
778{
779 Object *obj = object_resolve_path(path, NULL);
780 static PCIEAERErr err = {};
781 CXLType3Dev *ct3d;
782 CXLError *cxl_err;
783 uint32_t *reg_state;
784 uint32_t unc_err;
785 bool first;
786
787 if (!obj) {
788 error_setg(errp, "Unable to resolve path");
789 return;
790 }
791
792 if (!object_dynamic_cast(obj, TYPE_CXL_TYPE3)) {
793 error_setg(errp, "Path does not point to a CXL type 3 device");
794 return;
795 }
796
797 err.status = PCI_ERR_UNC_INTN;
798 err.source_id = pci_requester_id(PCI_DEVICE(obj));
799 err.flags = 0;
800
801 ct3d = CXL_TYPE3(obj);
802
803 first = QTAILQ_EMPTY(&ct3d->error_list);
804 reg_state = ct3d->cxl_cstate.crb.cache_mem_registers;
805 while (errors) {
806 uint32List *header = errors->value->header;
807 uint8_t header_count = 0;
808 int cxl_err_code;
809
810 cxl_err_code = ct3d_qmp_uncor_err_to_cxl(errors->value->type);
811 if (cxl_err_code < 0) {
812 error_setg(errp, "Unknown error code");
813 return;
814 }
815
816
817 if (!((1 << cxl_err_code) &
818 ~ldl_le_p(reg_state + R_CXL_RAS_UNC_ERR_MASK))) {
819 errors = errors->next;
820 continue;
821 }
822
823 cxl_err = g_malloc0(sizeof(*cxl_err));
824 if (!cxl_err) {
825 return;
826 }
827
828 cxl_err->type = cxl_err_code;
829 while (header && header_count < 32) {
830 cxl_err->header[header_count++] = header->value;
831 header = header->next;
832 }
833 if (header_count > 32) {
834 error_setg(errp, "Header must be 32 DWORD or less");
835 return;
836 }
837 QTAILQ_INSERT_TAIL(&ct3d->error_list, cxl_err, node);
838
839 errors = errors->next;
840 }
841
842 if (first && !QTAILQ_EMPTY(&ct3d->error_list)) {
843 uint32_t *cache_mem = ct3d->cxl_cstate.crb.cache_mem_registers;
844 uint32_t capctrl = ldl_le_p(cache_mem + R_CXL_RAS_ERR_CAP_CTRL);
845 uint32_t *header_log = &cache_mem[R_CXL_RAS_ERR_HEADER0];
846 int i;
847
848 cxl_err = QTAILQ_FIRST(&ct3d->error_list);
849 for (i = 0; i < CXL_RAS_ERR_HEADER_NUM; i++) {
850 stl_le_p(header_log + i, cxl_err->header[i]);
851 }
852
853 capctrl = FIELD_DP32(capctrl, CXL_RAS_ERR_CAP_CTRL,
854 FIRST_ERROR_POINTER, cxl_err->type);
855 stl_le_p(cache_mem + R_CXL_RAS_ERR_CAP_CTRL, capctrl);
856 }
857
858 unc_err = 0;
859 QTAILQ_FOREACH(cxl_err, &ct3d->error_list, node) {
860 unc_err |= (1 << cxl_err->type);
861 }
862 if (!unc_err) {
863 return;
864 }
865
866 stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_STATUS, unc_err);
867 pcie_aer_inject_error(PCI_DEVICE(obj), &err);
868
869 return;
870}
871
872void qmp_cxl_inject_correctable_error(const char *path, CxlCorErrorType type,
873 Error **errp)
874{
875 static PCIEAERErr err = {};
876 Object *obj = object_resolve_path(path, NULL);
877 CXLType3Dev *ct3d;
878 uint32_t *reg_state;
879 uint32_t cor_err;
880 int cxl_err_type;
881
882 if (!obj) {
883 error_setg(errp, "Unable to resolve path");
884 return;
885 }
886 if (!object_dynamic_cast(obj, TYPE_CXL_TYPE3)) {
887 error_setg(errp, "Path does not point to a CXL type 3 device");
888 return;
889 }
890
891 err.status = PCI_ERR_COR_INTERNAL;
892 err.source_id = pci_requester_id(PCI_DEVICE(obj));
893 err.flags = PCIE_AER_ERR_IS_CORRECTABLE;
894
895 ct3d = CXL_TYPE3(obj);
896 reg_state = ct3d->cxl_cstate.crb.cache_mem_registers;
897 cor_err = ldl_le_p(reg_state + R_CXL_RAS_COR_ERR_STATUS);
898
899 cxl_err_type = ct3d_qmp_cor_err_to_cxl(type);
900 if (cxl_err_type < 0) {
901 error_setg(errp, "Invalid COR error");
902 return;
903 }
904
905 if (!((1 << cxl_err_type) & ~ldl_le_p(reg_state + R_CXL_RAS_COR_ERR_MASK))) {
906 return;
907 }
908
909 cor_err |= (1 << cxl_err_type);
910 stl_le_p(reg_state + R_CXL_RAS_COR_ERR_STATUS, cor_err);
911
912 pcie_aer_inject_error(PCI_DEVICE(obj), &err);
913}
914
915static void ct3_class_init(ObjectClass *oc, void *data)
916{
917 DeviceClass *dc = DEVICE_CLASS(oc);
918 PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
919 CXLType3Class *cvc = CXL_TYPE3_CLASS(oc);
920
921 pc->realize = ct3_realize;
922 pc->exit = ct3_exit;
923 pc->class_id = PCI_CLASS_MEMORY_CXL;
924 pc->vendor_id = PCI_VENDOR_ID_INTEL;
925 pc->device_id = 0xd93;
926 pc->revision = 1;
927
928 pc->config_write = ct3d_config_write;
929 pc->config_read = ct3d_config_read;
930
931 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
932 dc->desc = "CXL PMEM Device (Type 3)";
933 dc->reset = ct3d_reset;
934 device_class_set_props(dc, ct3_props);
935
936 cvc->get_lsa_size = get_lsa_size;
937 cvc->get_lsa = get_lsa;
938 cvc->set_lsa = set_lsa;
939}
940
941static const TypeInfo ct3d_info = {
942 .name = TYPE_CXL_TYPE3,
943 .parent = TYPE_PCI_DEVICE,
944 .class_size = sizeof(struct CXLType3Class),
945 .class_init = ct3_class_init,
946 .instance_size = sizeof(CXLType3Dev),
947 .interfaces = (InterfaceInfo[]) {
948 { INTERFACE_CXL_DEVICE },
949 { INTERFACE_PCIE_DEVICE },
950 {}
951 },
952};
953
954static void ct3d_registers(void)
955{
956 type_register_static(&ct3d_info);
957}
958
959type_init(ct3d_registers);
960