2 * CXL Type 3 (memory expander) device
4 * Copyright(C) 2020 Intel Corporation.
6 * This work is licensed under the terms of the GNU GPL, version 2. See the
7 * COPYING file in the top-level directory.
9 * SPDX-License-Identifier: GPL-v2-only
12 #include "qemu/osdep.h"
13 #include "qemu/units.h"
14 #include "qemu/error-report.h"
15 #include "qapi/qapi-commands-cxl.h"
16 #include "hw/mem/memory-device.h"
17 #include "hw/mem/pc-dimm.h"
18 #include "hw/pci/pci.h"
19 #include "hw/qdev-properties.h"
20 #include "qapi/error.h"
22 #include "qemu/module.h"
23 #include "qemu/pmem.h"
24 #include "qemu/range.h"
26 #include "qemu/guest-random.h"
27 #include "sysemu/hostmem.h"
28 #include "sysemu/numa.h"
29 #include "hw/cxl/cxl.h"
30 #include "hw/pci/msix.h"
33 #define CXL_CAPACITY_MULTIPLIER (256 * MiB)
35 /* Default CDAT entries for a memory region */
46 static void ct3_build_cdat_entries_for_mr(CDATSubHeader
**cdat_table
,
47 int dsmad_handle
, uint64_t size
,
48 bool is_pmem
, bool is_dynamic
,
58 dsmas
= g_malloc(sizeof(*dsmas
));
59 *dsmas
= (CDATDsmas
) {
61 .type
= CDAT_TYPE_DSMAS
,
62 .length
= sizeof(*dsmas
),
64 .DSMADhandle
= dsmad_handle
,
65 .flags
= (is_pmem
? CDAT_DSMAS_FLAG_NV
: 0) |
66 (is_dynamic
? CDAT_DSMAS_FLAG_DYNAMIC_CAP
: 0),
71 /* For now, no memory side cache, plausiblish numbers */
72 dslbis0
= g_malloc(sizeof(*dslbis0
));
73 *dslbis0
= (CDATDslbis
) {
75 .type
= CDAT_TYPE_DSLBIS
,
76 .length
= sizeof(*dslbis0
),
78 .handle
= dsmad_handle
,
79 .flags
= HMAT_LB_MEM_MEMORY
,
80 .data_type
= HMAT_LB_DATA_READ_LATENCY
,
81 .entry_base_unit
= 10000, /* 10ns base */
82 .entry
[0] = 15, /* 150ns */
85 dslbis1
= g_malloc(sizeof(*dslbis1
));
86 *dslbis1
= (CDATDslbis
) {
88 .type
= CDAT_TYPE_DSLBIS
,
89 .length
= sizeof(*dslbis1
),
91 .handle
= dsmad_handle
,
92 .flags
= HMAT_LB_MEM_MEMORY
,
93 .data_type
= HMAT_LB_DATA_WRITE_LATENCY
,
94 .entry_base_unit
= 10000,
95 .entry
[0] = 25, /* 250ns */
98 dslbis2
= g_malloc(sizeof(*dslbis2
));
99 *dslbis2
= (CDATDslbis
) {
101 .type
= CDAT_TYPE_DSLBIS
,
102 .length
= sizeof(*dslbis2
),
104 .handle
= dsmad_handle
,
105 .flags
= HMAT_LB_MEM_MEMORY
,
106 .data_type
= HMAT_LB_DATA_READ_BANDWIDTH
,
107 .entry_base_unit
= 1000, /* GB/s */
111 dslbis3
= g_malloc(sizeof(*dslbis3
));
112 *dslbis3
= (CDATDslbis
) {
114 .type
= CDAT_TYPE_DSLBIS
,
115 .length
= sizeof(*dslbis3
),
117 .handle
= dsmad_handle
,
118 .flags
= HMAT_LB_MEM_MEMORY
,
119 .data_type
= HMAT_LB_DATA_WRITE_BANDWIDTH
,
120 .entry_base_unit
= 1000, /* GB/s */
124 dsemts
= g_malloc(sizeof(*dsemts
));
125 *dsemts
= (CDATDsemts
) {
127 .type
= CDAT_TYPE_DSEMTS
,
128 .length
= sizeof(*dsemts
),
130 .DSMAS_handle
= dsmad_handle
,
132 * NV: Reserved - the non volatile from DSMAS matters
135 .EFI_memory_type_attr
= is_pmem
? 2 : 1,
140 /* Header always at start of structure */
141 cdat_table
[CT3_CDAT_DSMAS
] = (CDATSubHeader
*)dsmas
;
142 cdat_table
[CT3_CDAT_DSLBIS0
] = (CDATSubHeader
*)dslbis0
;
143 cdat_table
[CT3_CDAT_DSLBIS1
] = (CDATSubHeader
*)dslbis1
;
144 cdat_table
[CT3_CDAT_DSLBIS2
] = (CDATSubHeader
*)dslbis2
;
145 cdat_table
[CT3_CDAT_DSLBIS3
] = (CDATSubHeader
*)dslbis3
;
146 cdat_table
[CT3_CDAT_DSEMTS
] = (CDATSubHeader
*)dsemts
;
149 static int ct3_build_cdat_table(CDATSubHeader
***cdat_table
, void *priv
)
151 g_autofree CDATSubHeader
**table
= NULL
;
152 CXLType3Dev
*ct3d
= priv
;
153 MemoryRegion
*volatile_mr
= NULL
, *nonvolatile_mr
= NULL
;
154 MemoryRegion
*dc_mr
= NULL
;
155 uint64_t vmr_size
= 0, pmr_size
= 0;
156 int dsmad_handle
= 0;
160 if (!ct3d
->hostpmem
&& !ct3d
->hostvmem
&& !ct3d
->dc
.num_regions
) {
164 if (ct3d
->hostvmem
) {
165 volatile_mr
= host_memory_backend_get_memory(ct3d
->hostvmem
);
169 len
+= CT3_CDAT_NUM_ENTRIES
;
170 vmr_size
= memory_region_size(volatile_mr
);
173 if (ct3d
->hostpmem
) {
174 nonvolatile_mr
= host_memory_backend_get_memory(ct3d
->hostpmem
);
175 if (!nonvolatile_mr
) {
178 len
+= CT3_CDAT_NUM_ENTRIES
;
179 pmr_size
= memory_region_size(nonvolatile_mr
);
182 if (ct3d
->dc
.num_regions
) {
183 if (!ct3d
->dc
.host_dc
) {
186 dc_mr
= host_memory_backend_get_memory(ct3d
->dc
.host_dc
);
190 len
+= CT3_CDAT_NUM_ENTRIES
* ct3d
->dc
.num_regions
;
193 table
= g_malloc0(len
* sizeof(*table
));
195 /* Now fill them in */
197 ct3_build_cdat_entries_for_mr(table
, dsmad_handle
++, vmr_size
,
199 cur_ent
= CT3_CDAT_NUM_ENTRIES
;
202 if (nonvolatile_mr
) {
203 uint64_t base
= vmr_size
;
204 ct3_build_cdat_entries_for_mr(&(table
[cur_ent
]), dsmad_handle
++,
205 pmr_size
, true, false, base
);
206 cur_ent
+= CT3_CDAT_NUM_ENTRIES
;
211 uint64_t region_base
= vmr_size
+ pmr_size
;
214 * We assume the dynamic capacity to be volatile for now.
215 * Non-volatile dynamic capacity will be added if needed in the
218 for (i
= 0; i
< ct3d
->dc
.num_regions
; i
++) {
219 ct3_build_cdat_entries_for_mr(&(table
[cur_ent
]),
221 ct3d
->dc
.regions
[i
].len
,
222 false, true, region_base
);
223 ct3d
->dc
.regions
[i
].dsmadhandle
= dsmad_handle
- 1;
225 cur_ent
+= CT3_CDAT_NUM_ENTRIES
;
226 region_base
+= ct3d
->dc
.regions
[i
].len
;
230 assert(len
== cur_ent
);
232 *cdat_table
= g_steal_pointer(&table
);
237 static void ct3_free_cdat_table(CDATSubHeader
**cdat_table
, int num
, void *priv
)
241 for (i
= 0; i
< num
; i
++) {
242 g_free(cdat_table
[i
]);
247 static bool cxl_doe_cdat_rsp(DOECap
*doe_cap
)
249 CDATObject
*cdat
= &CXL_TYPE3(doe_cap
->pdev
)->cxl_cstate
.cdat
;
253 CDATReq
*req
= pcie_doe_get_write_mbox_ptr(doe_cap
);
256 assert(cdat
->entry_len
);
258 /* Discard if request length mismatched */
259 if (pcie_doe_get_obj_len(req
) <
260 DIV_ROUND_UP(sizeof(CDATReq
), DWORD_BYTE
)) {
264 ent
= req
->entry_handle
;
265 base
= cdat
->entry
[ent
].base
;
266 len
= cdat
->entry
[ent
].length
;
270 .vendor_id
= CXL_VENDOR_ID
,
271 .data_obj_type
= CXL_DOE_TABLE_ACCESS
,
273 .length
= DIV_ROUND_UP((sizeof(rsp
) + len
), DWORD_BYTE
),
275 .rsp_code
= CXL_DOE_TAB_RSP
,
276 .table_type
= CXL_DOE_TAB_TYPE_CDAT
,
277 .entry_handle
= (ent
< cdat
->entry_len
- 1) ?
278 ent
+ 1 : CXL_DOE_TAB_ENT_MAX
,
281 memcpy(doe_cap
->read_mbox
, &rsp
, sizeof(rsp
));
282 memcpy(doe_cap
->read_mbox
+ DIV_ROUND_UP(sizeof(rsp
), DWORD_BYTE
),
285 doe_cap
->read_mbox_len
+= rsp
.header
.length
;
290 static uint32_t ct3d_config_read(PCIDevice
*pci_dev
, uint32_t addr
, int size
)
292 CXLType3Dev
*ct3d
= CXL_TYPE3(pci_dev
);
295 if (pcie_doe_read_config(&ct3d
->doe_cdat
, addr
, size
, &val
)) {
299 return pci_default_read_config(pci_dev
, addr
, size
);
302 static void ct3d_config_write(PCIDevice
*pci_dev
, uint32_t addr
, uint32_t val
,
305 CXLType3Dev
*ct3d
= CXL_TYPE3(pci_dev
);
307 pcie_doe_write_config(&ct3d
->doe_cdat
, addr
, val
, size
);
308 pci_default_write_config(pci_dev
, addr
, val
, size
);
309 pcie_aer_write_config(pci_dev
, addr
, val
, size
);
313 * Null value of all Fs suggested by IEEE RA guidelines for use of
316 #define UI64_NULL ~(0ULL)
318 static void build_dvsecs(CXLType3Dev
*ct3d
)
320 CXLComponentState
*cxl_cstate
= &ct3d
->cxl_cstate
;
322 uint32_t range1_size_hi
, range1_size_lo
,
323 range1_base_hi
= 0, range1_base_lo
= 0,
324 range2_size_hi
= 0, range2_size_lo
= 0,
325 range2_base_hi
= 0, range2_base_lo
= 0;
328 * Volatile memory is mapped as (0x0)
329 * Persistent memory is mapped at (volatile->size)
331 if (ct3d
->hostvmem
) {
332 range1_size_hi
= ct3d
->hostvmem
->size
>> 32;
333 range1_size_lo
= (2 << 5) | (2 << 2) | 0x3 |
334 (ct3d
->hostvmem
->size
& 0xF0000000);
335 if (ct3d
->hostpmem
) {
336 range2_size_hi
= ct3d
->hostpmem
->size
>> 32;
337 range2_size_lo
= (2 << 5) | (2 << 2) | 0x3 |
338 (ct3d
->hostpmem
->size
& 0xF0000000);
340 } else if (ct3d
->hostpmem
) {
341 range1_size_hi
= ct3d
->hostpmem
->size
>> 32;
342 range1_size_lo
= (2 << 5) | (2 << 2) | 0x3 |
343 (ct3d
->hostpmem
->size
& 0xF0000000);
346 * For DCD with no static memory, set memory active, memory class bits.
350 range1_size_lo
= (2 << 5) | (2 << 2) | 0x3;
353 dvsec
= (uint8_t *)&(CXLDVSECDevice
){
357 .range1_size_hi
= range1_size_hi
,
358 .range1_size_lo
= range1_size_lo
,
359 .range1_base_hi
= range1_base_hi
,
360 .range1_base_lo
= range1_base_lo
,
361 .range2_size_hi
= range2_size_hi
,
362 .range2_size_lo
= range2_size_lo
,
363 .range2_base_hi
= range2_base_hi
,
364 .range2_base_lo
= range2_base_lo
,
366 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
367 PCIE_CXL_DEVICE_DVSEC_LENGTH
,
368 PCIE_CXL_DEVICE_DVSEC
,
369 PCIE_CXL31_DEVICE_DVSEC_REVID
, dvsec
);
371 dvsec
= (uint8_t *)&(CXLDVSECRegisterLocator
){
373 .reg0_base_lo
= RBI_COMPONENT_REG
| CXL_COMPONENT_REG_BAR_IDX
,
375 .reg1_base_lo
= RBI_CXL_DEVICE_REG
| CXL_DEVICE_REG_BAR_IDX
,
378 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
379 REG_LOC_DVSEC_LENGTH
, REG_LOC_DVSEC
,
380 REG_LOC_DVSEC_REVID
, dvsec
);
381 dvsec
= (uint8_t *)&(CXLDVSECDeviceGPF
){
382 .phase2_duration
= 0x603, /* 3 seconds */
383 .phase2_power
= 0x33, /* 0x33 miliwatts */
385 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
386 GPF_DEVICE_DVSEC_LENGTH
, GPF_DEVICE_DVSEC
,
387 GPF_DEVICE_DVSEC_REVID
, dvsec
);
389 dvsec
= (uint8_t *)&(CXLDVSECPortFlexBus
){
390 .cap
= 0x26, /* 68B, IO, Mem, non-MLD */
391 .ctrl
= 0x02, /* IO always enabled */
392 .status
= 0x26, /* same as capabilities */
393 .rcvd_mod_ts_data_phase1
= 0xef, /* WTF? */
395 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
396 PCIE_CXL3_FLEXBUS_PORT_DVSEC_LENGTH
,
397 PCIE_FLEXBUS_PORT_DVSEC
,
398 PCIE_CXL3_FLEXBUS_PORT_DVSEC_REVID
, dvsec
);
401 static void hdm_decoder_commit(CXLType3Dev
*ct3d
, int which
)
403 int hdm_inc
= R_CXL_HDM_DECODER1_BASE_LO
- R_CXL_HDM_DECODER0_BASE_LO
;
404 ComponentRegisters
*cregs
= &ct3d
->cxl_cstate
.crb
;
405 uint32_t *cache_mem
= cregs
->cache_mem_registers
;
408 ctrl
= ldl_le_p(cache_mem
+ R_CXL_HDM_DECODER0_CTRL
+ which
* hdm_inc
);
409 /* TODO: Sanity checks that the decoder is possible */
410 ctrl
= FIELD_DP32(ctrl
, CXL_HDM_DECODER0_CTRL
, ERR
, 0);
411 ctrl
= FIELD_DP32(ctrl
, CXL_HDM_DECODER0_CTRL
, COMMITTED
, 1);
413 stl_le_p(cache_mem
+ R_CXL_HDM_DECODER0_CTRL
+ which
* hdm_inc
, ctrl
);
416 static void hdm_decoder_uncommit(CXLType3Dev
*ct3d
, int which
)
418 int hdm_inc
= R_CXL_HDM_DECODER1_BASE_LO
- R_CXL_HDM_DECODER0_BASE_LO
;
419 ComponentRegisters
*cregs
= &ct3d
->cxl_cstate
.crb
;
420 uint32_t *cache_mem
= cregs
->cache_mem_registers
;
423 ctrl
= ldl_le_p(cache_mem
+ R_CXL_HDM_DECODER0_CTRL
+ which
* hdm_inc
);
425 ctrl
= FIELD_DP32(ctrl
, CXL_HDM_DECODER0_CTRL
, ERR
, 0);
426 ctrl
= FIELD_DP32(ctrl
, CXL_HDM_DECODER0_CTRL
, COMMITTED
, 0);
428 stl_le_p(cache_mem
+ R_CXL_HDM_DECODER0_CTRL
+ which
* hdm_inc
, ctrl
);
431 static int ct3d_qmp_uncor_err_to_cxl(CxlUncorErrorType qmp_err
)
434 case CXL_UNCOR_ERROR_TYPE_CACHE_DATA_PARITY
:
435 return CXL_RAS_UNC_ERR_CACHE_DATA_PARITY
;
436 case CXL_UNCOR_ERROR_TYPE_CACHE_ADDRESS_PARITY
:
437 return CXL_RAS_UNC_ERR_CACHE_ADDRESS_PARITY
;
438 case CXL_UNCOR_ERROR_TYPE_CACHE_BE_PARITY
:
439 return CXL_RAS_UNC_ERR_CACHE_BE_PARITY
;
440 case CXL_UNCOR_ERROR_TYPE_CACHE_DATA_ECC
:
441 return CXL_RAS_UNC_ERR_CACHE_DATA_ECC
;
442 case CXL_UNCOR_ERROR_TYPE_MEM_DATA_PARITY
:
443 return CXL_RAS_UNC_ERR_MEM_DATA_PARITY
;
444 case CXL_UNCOR_ERROR_TYPE_MEM_ADDRESS_PARITY
:
445 return CXL_RAS_UNC_ERR_MEM_ADDRESS_PARITY
;
446 case CXL_UNCOR_ERROR_TYPE_MEM_BE_PARITY
:
447 return CXL_RAS_UNC_ERR_MEM_BE_PARITY
;
448 case CXL_UNCOR_ERROR_TYPE_MEM_DATA_ECC
:
449 return CXL_RAS_UNC_ERR_MEM_DATA_ECC
;
450 case CXL_UNCOR_ERROR_TYPE_REINIT_THRESHOLD
:
451 return CXL_RAS_UNC_ERR_REINIT_THRESHOLD
;
452 case CXL_UNCOR_ERROR_TYPE_RSVD_ENCODING
:
453 return CXL_RAS_UNC_ERR_RSVD_ENCODING
;
454 case CXL_UNCOR_ERROR_TYPE_POISON_RECEIVED
:
455 return CXL_RAS_UNC_ERR_POISON_RECEIVED
;
456 case CXL_UNCOR_ERROR_TYPE_RECEIVER_OVERFLOW
:
457 return CXL_RAS_UNC_ERR_RECEIVER_OVERFLOW
;
458 case CXL_UNCOR_ERROR_TYPE_INTERNAL
:
459 return CXL_RAS_UNC_ERR_INTERNAL
;
460 case CXL_UNCOR_ERROR_TYPE_CXL_IDE_TX
:
461 return CXL_RAS_UNC_ERR_CXL_IDE_TX
;
462 case CXL_UNCOR_ERROR_TYPE_CXL_IDE_RX
:
463 return CXL_RAS_UNC_ERR_CXL_IDE_RX
;
469 static int ct3d_qmp_cor_err_to_cxl(CxlCorErrorType qmp_err
)
472 case CXL_COR_ERROR_TYPE_CACHE_DATA_ECC
:
473 return CXL_RAS_COR_ERR_CACHE_DATA_ECC
;
474 case CXL_COR_ERROR_TYPE_MEM_DATA_ECC
:
475 return CXL_RAS_COR_ERR_MEM_DATA_ECC
;
476 case CXL_COR_ERROR_TYPE_CRC_THRESHOLD
:
477 return CXL_RAS_COR_ERR_CRC_THRESHOLD
;
478 case CXL_COR_ERROR_TYPE_RETRY_THRESHOLD
:
479 return CXL_RAS_COR_ERR_RETRY_THRESHOLD
;
480 case CXL_COR_ERROR_TYPE_CACHE_POISON_RECEIVED
:
481 return CXL_RAS_COR_ERR_CACHE_POISON_RECEIVED
;
482 case CXL_COR_ERROR_TYPE_MEM_POISON_RECEIVED
:
483 return CXL_RAS_COR_ERR_MEM_POISON_RECEIVED
;
484 case CXL_COR_ERROR_TYPE_PHYSICAL
:
485 return CXL_RAS_COR_ERR_PHYSICAL
;
491 static void ct3d_reg_write(void *opaque
, hwaddr offset
, uint64_t value
,
494 CXLComponentState
*cxl_cstate
= opaque
;
495 ComponentRegisters
*cregs
= &cxl_cstate
->crb
;
496 CXLType3Dev
*ct3d
= container_of(cxl_cstate
, CXLType3Dev
, cxl_cstate
);
497 uint32_t *cache_mem
= cregs
->cache_mem_registers
;
498 bool should_commit
= false;
499 bool should_uncommit
= false;
503 g_assert(offset
< CXL2_COMPONENT_CM_REGION_SIZE
);
506 case A_CXL_HDM_DECODER0_CTRL
:
507 should_commit
= FIELD_EX32(value
, CXL_HDM_DECODER0_CTRL
, COMMIT
);
508 should_uncommit
= !should_commit
;
511 case A_CXL_HDM_DECODER1_CTRL
:
512 should_commit
= FIELD_EX32(value
, CXL_HDM_DECODER0_CTRL
, COMMIT
);
513 should_uncommit
= !should_commit
;
516 case A_CXL_HDM_DECODER2_CTRL
:
517 should_commit
= FIELD_EX32(value
, CXL_HDM_DECODER0_CTRL
, COMMIT
);
518 should_uncommit
= !should_commit
;
521 case A_CXL_HDM_DECODER3_CTRL
:
522 should_commit
= FIELD_EX32(value
, CXL_HDM_DECODER0_CTRL
, COMMIT
);
523 should_uncommit
= !should_commit
;
526 case A_CXL_RAS_UNC_ERR_STATUS
:
528 uint32_t capctrl
= ldl_le_p(cache_mem
+ R_CXL_RAS_ERR_CAP_CTRL
);
529 uint32_t fe
= FIELD_EX32(capctrl
, CXL_RAS_ERR_CAP_CTRL
,
530 FIRST_ERROR_POINTER
);
535 * If single bit written that corresponds to the first error
536 * pointer being cleared, update the status and header log.
538 if (!QTAILQ_EMPTY(&ct3d
->error_list
)) {
539 if ((1 << fe
) ^ value
) {
542 * Software is using wrong flow for multiple header recording
543 * Following behavior in PCIe r6.0 and assuming multiple
544 * header support. Implementation defined choice to clear all
545 * matching records if more than one bit set - which corresponds
546 * closest to behavior of hardware not capable of multiple
549 QTAILQ_FOREACH_SAFE(cxl_err
, &ct3d
->error_list
, node
,
551 if ((1 << cxl_err
->type
) & value
) {
552 QTAILQ_REMOVE(&ct3d
->error_list
, cxl_err
, node
);
557 /* Done with previous FE, so drop from list */
558 cxl_err
= QTAILQ_FIRST(&ct3d
->error_list
);
559 QTAILQ_REMOVE(&ct3d
->error_list
, cxl_err
, node
);
564 * If there is another FE, then put that in place and update
567 if (!QTAILQ_EMPTY(&ct3d
->error_list
)) {
568 uint32_t *header_log
= &cache_mem
[R_CXL_RAS_ERR_HEADER0
];
571 cxl_err
= QTAILQ_FIRST(&ct3d
->error_list
);
572 for (i
= 0; i
< CXL_RAS_ERR_HEADER_NUM
; i
++) {
573 stl_le_p(header_log
+ i
, cxl_err
->header
[i
]);
575 capctrl
= FIELD_DP32(capctrl
, CXL_RAS_ERR_CAP_CTRL
,
576 FIRST_ERROR_POINTER
, cxl_err
->type
);
579 * If no more errors, then follow recommendation of PCI spec
580 * r6.0 6.2.4.2 to set the first error pointer to a status
581 * bit that will never be used.
583 capctrl
= FIELD_DP32(capctrl
, CXL_RAS_ERR_CAP_CTRL
,
585 CXL_RAS_UNC_ERR_CXL_UNUSED
);
587 stl_le_p((uint8_t *)cache_mem
+ A_CXL_RAS_ERR_CAP_CTRL
, capctrl
);
590 QTAILQ_FOREACH(cxl_err
, &ct3d
->error_list
, node
) {
591 unc_err
|= 1 << cxl_err
->type
;
593 stl_le_p((uint8_t *)cache_mem
+ offset
, unc_err
);
597 case A_CXL_RAS_COR_ERR_STATUS
:
599 uint32_t rw1c
= value
;
600 uint32_t temp
= ldl_le_p((uint8_t *)cache_mem
+ offset
);
602 stl_le_p((uint8_t *)cache_mem
+ offset
, temp
);
609 stl_le_p((uint8_t *)cache_mem
+ offset
, value
);
611 hdm_decoder_commit(ct3d
, which_hdm
);
612 } else if (should_uncommit
) {
613 hdm_decoder_uncommit(ct3d
, which_hdm
);
618 * TODO: dc region configuration will be updated once host backend and address
619 * space support is added for DCD.
621 static bool cxl_create_dc_regions(CXLType3Dev
*ct3d
, Error
**errp
)
624 uint64_t region_base
= 0;
627 uint64_t blk_size
= 2 * MiB
;
632 mr
= host_memory_backend_get_memory(ct3d
->dc
.host_dc
);
633 dc_size
= memory_region_size(mr
);
634 region_len
= DIV_ROUND_UP(dc_size
, ct3d
->dc
.num_regions
);
636 if (dc_size
% (ct3d
->dc
.num_regions
* CXL_CAPACITY_MULTIPLIER
) != 0) {
638 "backend size is not multiple of region len: 0x%" PRIx64
,
642 if (region_len
% CXL_CAPACITY_MULTIPLIER
!= 0) {
643 error_setg(errp
, "DC region size is unaligned to 0x%" PRIx64
,
644 CXL_CAPACITY_MULTIPLIER
);
647 decode_len
= region_len
;
649 if (ct3d
->hostvmem
) {
650 mr
= host_memory_backend_get_memory(ct3d
->hostvmem
);
651 region_base
+= memory_region_size(mr
);
653 if (ct3d
->hostpmem
) {
654 mr
= host_memory_backend_get_memory(ct3d
->hostpmem
);
655 region_base
+= memory_region_size(mr
);
657 if (region_base
% CXL_CAPACITY_MULTIPLIER
!= 0) {
658 error_setg(errp
, "DC region base not aligned to 0x%" PRIx64
,
659 CXL_CAPACITY_MULTIPLIER
);
663 for (i
= 0, region
= &ct3d
->dc
.regions
[0];
664 i
< ct3d
->dc
.num_regions
;
665 i
++, region
++, region_base
+= region_len
) {
666 *region
= (CXLDCRegion
) {
668 .decode_len
= decode_len
,
670 .block_size
= blk_size
,
671 /* dsmad_handle set when creating CDAT table entries */
674 ct3d
->dc
.total_capacity
+= region
->len
;
675 region
->blk_bitmap
= bitmap_new(region
->len
/ region
->block_size
);
677 QTAILQ_INIT(&ct3d
->dc
.extents
);
678 QTAILQ_INIT(&ct3d
->dc
.extents_pending
);
683 static void cxl_destroy_dc_regions(CXLType3Dev
*ct3d
)
685 CXLDCExtent
*ent
, *ent_next
;
686 CXLDCExtentGroup
*group
, *group_next
;
690 QTAILQ_FOREACH_SAFE(ent
, &ct3d
->dc
.extents
, node
, ent_next
) {
691 cxl_remove_extent_from_extent_list(&ct3d
->dc
.extents
, ent
);
694 QTAILQ_FOREACH_SAFE(group
, &ct3d
->dc
.extents_pending
, node
, group_next
) {
695 QTAILQ_REMOVE(&ct3d
->dc
.extents_pending
, group
, node
);
696 QTAILQ_FOREACH_SAFE(ent
, &group
->list
, node
, ent_next
) {
697 cxl_remove_extent_from_extent_list(&group
->list
, ent
);
702 for (i
= 0; i
< ct3d
->dc
.num_regions
; i
++) {
703 region
= &ct3d
->dc
.regions
[i
];
704 g_free(region
->blk_bitmap
);
708 static bool cxl_setup_memory(CXLType3Dev
*ct3d
, Error
**errp
)
710 DeviceState
*ds
= DEVICE(ct3d
);
712 if (!ct3d
->hostmem
&& !ct3d
->hostvmem
&& !ct3d
->hostpmem
713 && !ct3d
->dc
.num_regions
) {
714 error_setg(errp
, "at least one memdev property must be set");
716 } else if (ct3d
->hostmem
&& ct3d
->hostpmem
) {
717 error_setg(errp
, "[memdev] cannot be used with new "
718 "[persistent-memdev] property");
720 } else if (ct3d
->hostmem
) {
721 /* Use of hostmem property implies pmem */
722 ct3d
->hostpmem
= ct3d
->hostmem
;
723 ct3d
->hostmem
= NULL
;
726 if (ct3d
->hostpmem
&& !ct3d
->lsa
) {
727 error_setg(errp
, "lsa property must be set for persistent devices");
731 if (ct3d
->hostvmem
) {
735 vmr
= host_memory_backend_get_memory(ct3d
->hostvmem
);
737 error_setg(errp
, "volatile memdev must have backing device");
740 if (host_memory_backend_is_mapped(ct3d
->hostvmem
)) {
741 error_setg(errp
, "memory backend %s can't be used multiple times.",
742 object_get_canonical_path_component(OBJECT(ct3d
->hostvmem
)));
745 memory_region_set_nonvolatile(vmr
, false);
746 memory_region_set_enabled(vmr
, true);
747 host_memory_backend_set_mapped(ct3d
->hostvmem
, true);
749 v_name
= g_strdup_printf("cxl-type3-dpa-vmem-space:%s", ds
->id
);
751 v_name
= g_strdup("cxl-type3-dpa-vmem-space");
753 address_space_init(&ct3d
->hostvmem_as
, vmr
, v_name
);
754 ct3d
->cxl_dstate
.vmem_size
= memory_region_size(vmr
);
755 ct3d
->cxl_dstate
.static_mem_size
+= memory_region_size(vmr
);
759 if (ct3d
->hostpmem
) {
763 pmr
= host_memory_backend_get_memory(ct3d
->hostpmem
);
765 error_setg(errp
, "persistent memdev must have backing device");
768 if (host_memory_backend_is_mapped(ct3d
->hostpmem
)) {
769 error_setg(errp
, "memory backend %s can't be used multiple times.",
770 object_get_canonical_path_component(OBJECT(ct3d
->hostpmem
)));
773 memory_region_set_nonvolatile(pmr
, true);
774 memory_region_set_enabled(pmr
, true);
775 host_memory_backend_set_mapped(ct3d
->hostpmem
, true);
777 p_name
= g_strdup_printf("cxl-type3-dpa-pmem-space:%s", ds
->id
);
779 p_name
= g_strdup("cxl-type3-dpa-pmem-space");
781 address_space_init(&ct3d
->hostpmem_as
, pmr
, p_name
);
782 ct3d
->cxl_dstate
.pmem_size
= memory_region_size(pmr
);
783 ct3d
->cxl_dstate
.static_mem_size
+= memory_region_size(pmr
);
787 ct3d
->dc
.total_capacity
= 0;
788 if (ct3d
->dc
.num_regions
> 0) {
792 if (!ct3d
->dc
.host_dc
) {
793 error_setg(errp
, "dynamic capacity must have a backing device");
797 dc_mr
= host_memory_backend_get_memory(ct3d
->dc
.host_dc
);
799 error_setg(errp
, "dynamic capacity must have a backing device");
803 if (host_memory_backend_is_mapped(ct3d
->dc
.host_dc
)) {
804 error_setg(errp
, "memory backend %s can't be used multiple times.",
805 object_get_canonical_path_component(OBJECT(ct3d
->dc
.host_dc
)));
809 * Set DC regions as volatile for now, non-volatile support can
810 * be added in the future if needed.
812 memory_region_set_nonvolatile(dc_mr
, false);
813 memory_region_set_enabled(dc_mr
, true);
814 host_memory_backend_set_mapped(ct3d
->dc
.host_dc
, true);
816 dc_name
= g_strdup_printf("cxl-dcd-dpa-dc-space:%s", ds
->id
);
818 dc_name
= g_strdup("cxl-dcd-dpa-dc-space");
820 address_space_init(&ct3d
->dc
.host_dc_as
, dc_mr
, dc_name
);
823 if (!cxl_create_dc_regions(ct3d
, errp
)) {
824 error_append_hint(errp
, "setup DC regions failed");
832 static DOEProtocol doe_cdat_prot
[] = {
833 { CXL_VENDOR_ID
, CXL_DOE_TABLE_ACCESS
, cxl_doe_cdat_rsp
},
837 static void ct3_realize(PCIDevice
*pci_dev
, Error
**errp
)
840 CXLType3Dev
*ct3d
= CXL_TYPE3(pci_dev
);
841 CXLComponentState
*cxl_cstate
= &ct3d
->cxl_cstate
;
842 ComponentRegisters
*regs
= &cxl_cstate
->crb
;
843 MemoryRegion
*mr
= ®s
->component_registers
;
844 uint8_t *pci_conf
= pci_dev
->config
;
845 unsigned short msix_num
= 6;
849 QTAILQ_INIT(&ct3d
->error_list
);
851 if (!cxl_setup_memory(ct3d
, errp
)) {
855 pci_config_set_prog_interface(pci_conf
, 0x10);
857 pcie_endpoint_cap_init(pci_dev
, 0x80);
858 if (ct3d
->sn
!= UI64_NULL
) {
859 pcie_dev_ser_num_init(pci_dev
, 0x100, ct3d
->sn
);
860 cxl_cstate
->dvsec_offset
= 0x100 + 0x0c;
862 cxl_cstate
->dvsec_offset
= 0x100;
865 ct3d
->cxl_cstate
.pdev
= pci_dev
;
868 regs
->special_ops
= g_new0(MemoryRegionOps
, 1);
869 regs
->special_ops
->write
= ct3d_reg_write
;
871 cxl_component_register_block_init(OBJECT(pci_dev
), cxl_cstate
,
875 pci_dev
, CXL_COMPONENT_REG_BAR_IDX
,
876 PCI_BASE_ADDRESS_SPACE_MEMORY
| PCI_BASE_ADDRESS_MEM_TYPE_64
, mr
);
878 cxl_device_register_block_init(OBJECT(pci_dev
), &ct3d
->cxl_dstate
,
880 pci_register_bar(pci_dev
, CXL_DEVICE_REG_BAR_IDX
,
881 PCI_BASE_ADDRESS_SPACE_MEMORY
|
882 PCI_BASE_ADDRESS_MEM_TYPE_64
,
883 &ct3d
->cxl_dstate
.device_registers
);
885 /* MSI(-X) Initialization */
886 rc
= msix_init_exclusive_bar(pci_dev
, msix_num
, 4, NULL
);
888 goto err_address_space_free
;
890 for (i
= 0; i
< msix_num
; i
++) {
891 msix_vector_use(pci_dev
, i
);
894 /* DOE Initialization */
895 pcie_doe_init(pci_dev
, &ct3d
->doe_cdat
, 0x190, doe_cdat_prot
, true, 0);
897 cxl_cstate
->cdat
.build_cdat_table
= ct3_build_cdat_table
;
898 cxl_cstate
->cdat
.free_cdat_table
= ct3_free_cdat_table
;
899 cxl_cstate
->cdat
.private = ct3d
;
900 if (!cxl_doe_cdat_init(cxl_cstate
, errp
)) {
901 goto err_free_special_ops
;
904 pcie_cap_deverr_init(pci_dev
);
905 /* Leave a bit of room for expansion */
906 rc
= pcie_aer_init(pci_dev
, PCI_ERR_VER
, 0x200, PCI_ERR_SIZEOF
, NULL
);
908 goto err_release_cdat
;
910 cxl_event_init(&ct3d
->cxl_dstate
, 2);
912 /* Set default value for patrol scrub attributes */
913 ct3d
->patrol_scrub_attrs
.scrub_cycle_cap
=
914 CXL_MEMDEV_PS_SCRUB_CYCLE_CHANGE_CAP_DEFAULT
|
915 CXL_MEMDEV_PS_SCRUB_REALTIME_REPORT_CAP_DEFAULT
;
916 ct3d
->patrol_scrub_attrs
.scrub_cycle
=
917 CXL_MEMDEV_PS_CUR_SCRUB_CYCLE_DEFAULT
|
918 (CXL_MEMDEV_PS_MIN_SCRUB_CYCLE_DEFAULT
<< 8);
919 ct3d
->patrol_scrub_attrs
.scrub_flags
= CXL_MEMDEV_PS_ENABLE_DEFAULT
;
921 /* Set default value for DDR5 ECS read attributes */
922 for (count
= 0; count
< CXL_ECS_NUM_MEDIA_FRUS
; count
++) {
923 ct3d
->ecs_attrs
[count
].ecs_log_cap
=
924 CXL_ECS_LOG_ENTRY_TYPE_DEFAULT
;
925 ct3d
->ecs_attrs
[count
].ecs_cap
=
926 CXL_ECS_REALTIME_REPORT_CAP_DEFAULT
;
927 ct3d
->ecs_attrs
[count
].ecs_config
=
928 CXL_ECS_THRESHOLD_COUNT_DEFAULT
|
929 (CXL_ECS_MODE_DEFAULT
<< 3);
931 ct3d
->ecs_attrs
[count
].ecs_flags
= 0;
937 cxl_doe_cdat_release(cxl_cstate
);
938 err_free_special_ops
:
939 g_free(regs
->special_ops
);
940 err_address_space_free
:
941 if (ct3d
->dc
.host_dc
) {
942 cxl_destroy_dc_regions(ct3d
);
943 address_space_destroy(&ct3d
->dc
.host_dc_as
);
945 if (ct3d
->hostpmem
) {
946 address_space_destroy(&ct3d
->hostpmem_as
);
948 if (ct3d
->hostvmem
) {
949 address_space_destroy(&ct3d
->hostvmem_as
);
954 static void ct3_exit(PCIDevice
*pci_dev
)
956 CXLType3Dev
*ct3d
= CXL_TYPE3(pci_dev
);
957 CXLComponentState
*cxl_cstate
= &ct3d
->cxl_cstate
;
958 ComponentRegisters
*regs
= &cxl_cstate
->crb
;
960 pcie_aer_exit(pci_dev
);
961 cxl_doe_cdat_release(cxl_cstate
);
962 g_free(regs
->special_ops
);
963 if (ct3d
->dc
.host_dc
) {
964 cxl_destroy_dc_regions(ct3d
);
965 address_space_destroy(&ct3d
->dc
.host_dc_as
);
967 if (ct3d
->hostpmem
) {
968 address_space_destroy(&ct3d
->hostpmem_as
);
970 if (ct3d
->hostvmem
) {
971 address_space_destroy(&ct3d
->hostvmem_as
);
976 * Mark the DPA range [dpa, dap + len - 1] to be backed and accessible. This
977 * happens when a DC extent is added and accepted by the host.
979 void ct3_set_region_block_backed(CXLType3Dev
*ct3d
, uint64_t dpa
,
984 region
= cxl_find_dc_region(ct3d
, dpa
, len
);
989 bitmap_set(region
->blk_bitmap
, (dpa
- region
->base
) / region
->block_size
,
990 len
/ region
->block_size
);
994 * Check whether the DPA range [dpa, dpa + len - 1] is backed with DC extents.
995 * Used when validating read/write to dc regions
997 bool ct3_test_region_block_backed(CXLType3Dev
*ct3d
, uint64_t dpa
,
1000 CXLDCRegion
*region
;
1004 region
= cxl_find_dc_region(ct3d
, dpa
, len
);
1009 nr
= (dpa
- region
->base
) / region
->block_size
;
1010 nbits
= DIV_ROUND_UP(len
, region
->block_size
);
1012 * if bits between [dpa, dpa + len) are all 1s, meaning the DPA range is
1013 * backed with DC extents, return true; else return false.
1015 return find_next_zero_bit(region
->blk_bitmap
, nr
+ nbits
, nr
) == nr
+ nbits
;
1019 * Mark the DPA range [dpa, dap + len - 1] to be unbacked and inaccessible.
1020 * This happens when a dc extent is released by the host.
1022 void ct3_clear_region_block_backed(CXLType3Dev
*ct3d
, uint64_t dpa
,
1025 CXLDCRegion
*region
;
1029 region
= cxl_find_dc_region(ct3d
, dpa
, len
);
1034 nr
= (dpa
- region
->base
) / region
->block_size
;
1035 nbits
= len
/ region
->block_size
;
1036 bitmap_clear(region
->blk_bitmap
, nr
, nbits
);
1039 static bool cxl_type3_dpa(CXLType3Dev
*ct3d
, hwaddr host_addr
, uint64_t *dpa
)
1041 int hdm_inc
= R_CXL_HDM_DECODER1_BASE_LO
- R_CXL_HDM_DECODER0_BASE_LO
;
1042 uint32_t *cache_mem
= ct3d
->cxl_cstate
.crb
.cache_mem_registers
;
1043 unsigned int hdm_count
;
1045 uint64_t dpa_base
= 0;
1048 cap
= ldl_le_p(cache_mem
+ R_CXL_HDM_DECODER_CAPABILITY
);
1049 hdm_count
= cxl_decoder_count_dec(FIELD_EX32(cap
,
1050 CXL_HDM_DECODER_CAPABILITY
,
1053 for (i
= 0; i
< hdm_count
; i
++) {
1054 uint64_t decoder_base
, decoder_size
, hpa_offset
, skip
;
1055 uint32_t hdm_ctrl
, low
, high
;
1058 low
= ldl_le_p(cache_mem
+ R_CXL_HDM_DECODER0_BASE_LO
+ i
* hdm_inc
);
1059 high
= ldl_le_p(cache_mem
+ R_CXL_HDM_DECODER0_BASE_HI
+ i
* hdm_inc
);
1060 decoder_base
= ((uint64_t)high
<< 32) | (low
& 0xf0000000);
1062 low
= ldl_le_p(cache_mem
+ R_CXL_HDM_DECODER0_SIZE_LO
+ i
* hdm_inc
);
1063 high
= ldl_le_p(cache_mem
+ R_CXL_HDM_DECODER0_SIZE_HI
+ i
* hdm_inc
);
1064 decoder_size
= ((uint64_t)high
<< 32) | (low
& 0xf0000000);
1066 low
= ldl_le_p(cache_mem
+ R_CXL_HDM_DECODER0_DPA_SKIP_LO
+
1068 high
= ldl_le_p(cache_mem
+ R_CXL_HDM_DECODER0_DPA_SKIP_HI
+
1070 skip
= ((uint64_t)high
<< 32) | (low
& 0xf0000000);
1073 hpa_offset
= (uint64_t)host_addr
- decoder_base
;
1075 hdm_ctrl
= ldl_le_p(cache_mem
+ R_CXL_HDM_DECODER0_CTRL
+ i
* hdm_inc
);
1076 iw
= FIELD_EX32(hdm_ctrl
, CXL_HDM_DECODER0_CTRL
, IW
);
1077 ig
= FIELD_EX32(hdm_ctrl
, CXL_HDM_DECODER0_CTRL
, IG
);
1078 if (!FIELD_EX32(hdm_ctrl
, CXL_HDM_DECODER0_CTRL
, COMMITTED
)) {
1081 if (((uint64_t)host_addr
< decoder_base
) ||
1082 (hpa_offset
>= decoder_size
)) {
1083 int decoded_iw
= cxl_interleave_ways_dec(iw
, &error_fatal
);
1085 if (decoded_iw
== 0) {
1089 dpa_base
+= decoder_size
/ decoded_iw
;
1094 ((MAKE_64BIT_MASK(0, 8 + ig
) & hpa_offset
) |
1095 ((MAKE_64BIT_MASK(8 + ig
+ iw
, 64 - 8 - ig
- iw
) & hpa_offset
)
1103 static int cxl_type3_hpa_to_as_and_dpa(CXLType3Dev
*ct3d
,
1107 uint64_t *dpa_offset
)
1109 MemoryRegion
*vmr
= NULL
, *pmr
= NULL
, *dc_mr
= NULL
;
1110 uint64_t vmr_size
= 0, pmr_size
= 0, dc_size
= 0;
1112 if (ct3d
->hostvmem
) {
1113 vmr
= host_memory_backend_get_memory(ct3d
->hostvmem
);
1114 vmr_size
= memory_region_size(vmr
);
1116 if (ct3d
->hostpmem
) {
1117 pmr
= host_memory_backend_get_memory(ct3d
->hostpmem
);
1118 pmr_size
= memory_region_size(pmr
);
1120 if (ct3d
->dc
.host_dc
) {
1121 dc_mr
= host_memory_backend_get_memory(ct3d
->dc
.host_dc
);
1122 dc_size
= memory_region_size(dc_mr
);
1125 if (!vmr
&& !pmr
&& !dc_mr
) {
1129 if (!cxl_type3_dpa(ct3d
, host_addr
, dpa_offset
)) {
1133 if (*dpa_offset
>= vmr_size
+ pmr_size
+ dc_size
) {
1137 if (*dpa_offset
< vmr_size
) {
1138 *as
= &ct3d
->hostvmem_as
;
1139 } else if (*dpa_offset
< vmr_size
+ pmr_size
) {
1140 *as
= &ct3d
->hostpmem_as
;
1141 *dpa_offset
-= vmr_size
;
1143 if (!ct3_test_region_block_backed(ct3d
, *dpa_offset
, size
)) {
1147 *as
= &ct3d
->dc
.host_dc_as
;
1148 *dpa_offset
-= (vmr_size
+ pmr_size
);
1154 MemTxResult
cxl_type3_read(PCIDevice
*d
, hwaddr host_addr
, uint64_t *data
,
1155 unsigned size
, MemTxAttrs attrs
)
1157 CXLType3Dev
*ct3d
= CXL_TYPE3(d
);
1158 uint64_t dpa_offset
= 0;
1159 AddressSpace
*as
= NULL
;
1162 res
= cxl_type3_hpa_to_as_and_dpa(ct3d
, host_addr
, size
,
1168 if (cxl_dev_media_disabled(&ct3d
->cxl_dstate
)) {
1169 qemu_guest_getrandom_nofail(data
, size
);
1173 return address_space_read(as
, dpa_offset
, attrs
, data
, size
);
1176 MemTxResult
cxl_type3_write(PCIDevice
*d
, hwaddr host_addr
, uint64_t data
,
1177 unsigned size
, MemTxAttrs attrs
)
1179 CXLType3Dev
*ct3d
= CXL_TYPE3(d
);
1180 uint64_t dpa_offset
= 0;
1181 AddressSpace
*as
= NULL
;
1184 res
= cxl_type3_hpa_to_as_and_dpa(ct3d
, host_addr
, size
,
1190 if (cxl_dev_media_disabled(&ct3d
->cxl_dstate
)) {
1194 return address_space_write(as
, dpa_offset
, attrs
, &data
, size
);
1197 static void ct3d_reset(DeviceState
*dev
)
1199 CXLType3Dev
*ct3d
= CXL_TYPE3(dev
);
1200 uint32_t *reg_state
= ct3d
->cxl_cstate
.crb
.cache_mem_registers
;
1201 uint32_t *write_msk
= ct3d
->cxl_cstate
.crb
.cache_mem_regs_write_mask
;
1203 cxl_component_register_init_common(reg_state
, write_msk
, CXL2_TYPE3_DEVICE
);
1204 cxl_device_register_init_t3(ct3d
);
1207 * Bring up an endpoint to target with MCTP over VDM.
1208 * This device is emulating an MLD with single LD for now.
1210 cxl_initialize_t3_fm_owned_ld_mctpcci(&ct3d
->vdm_fm_owned_ld_mctp_cci
,
1211 DEVICE(ct3d
), DEVICE(ct3d
),
1212 512); /* Max payload made up */
1213 cxl_initialize_t3_ld_cci(&ct3d
->ld0_cci
, DEVICE(ct3d
), DEVICE(ct3d
),
1214 512); /* Max payload made up */
1218 static Property ct3_props
[] = {
1219 DEFINE_PROP_LINK("memdev", CXLType3Dev
, hostmem
, TYPE_MEMORY_BACKEND
,
1220 HostMemoryBackend
*), /* for backward compatibility */
1221 DEFINE_PROP_LINK("persistent-memdev", CXLType3Dev
, hostpmem
,
1222 TYPE_MEMORY_BACKEND
, HostMemoryBackend
*),
1223 DEFINE_PROP_LINK("volatile-memdev", CXLType3Dev
, hostvmem
,
1224 TYPE_MEMORY_BACKEND
, HostMemoryBackend
*),
1225 DEFINE_PROP_LINK("lsa", CXLType3Dev
, lsa
, TYPE_MEMORY_BACKEND
,
1226 HostMemoryBackend
*),
1227 DEFINE_PROP_UINT64("sn", CXLType3Dev
, sn
, UI64_NULL
),
1228 DEFINE_PROP_STRING("cdat", CXLType3Dev
, cxl_cstate
.cdat
.filename
),
1229 DEFINE_PROP_UINT8("num-dc-regions", CXLType3Dev
, dc
.num_regions
, 0),
1230 DEFINE_PROP_LINK("volatile-dc-memdev", CXLType3Dev
, dc
.host_dc
,
1231 TYPE_MEMORY_BACKEND
, HostMemoryBackend
*),
1232 DEFINE_PROP_END_OF_LIST(),
1235 static uint64_t get_lsa_size(CXLType3Dev
*ct3d
)
1243 mr
= host_memory_backend_get_memory(ct3d
->lsa
);
1244 return memory_region_size(mr
);
1247 static void validate_lsa_access(MemoryRegion
*mr
, uint64_t size
,
1250 assert(offset
+ size
<= memory_region_size(mr
));
1251 assert(offset
+ size
> offset
);
1254 static uint64_t get_lsa(CXLType3Dev
*ct3d
, void *buf
, uint64_t size
,
1264 mr
= host_memory_backend_get_memory(ct3d
->lsa
);
1265 validate_lsa_access(mr
, size
, offset
);
1267 lsa
= memory_region_get_ram_ptr(mr
) + offset
;
1268 memcpy(buf
, lsa
, size
);
1273 static void set_lsa(CXLType3Dev
*ct3d
, const void *buf
, uint64_t size
,
1283 mr
= host_memory_backend_get_memory(ct3d
->lsa
);
1284 validate_lsa_access(mr
, size
, offset
);
1286 lsa
= memory_region_get_ram_ptr(mr
) + offset
;
1287 memcpy(lsa
, buf
, size
);
1288 memory_region_set_dirty(mr
, offset
, size
);
1291 * Just like the PMEM, if the guest is not allowed to exit gracefully, label
1292 * updates will get lost.
1296 static bool set_cacheline(CXLType3Dev
*ct3d
, uint64_t dpa_offset
, uint8_t *data
)
1298 MemoryRegion
*vmr
= NULL
, *pmr
= NULL
, *dc_mr
= NULL
;
1300 uint64_t vmr_size
= 0, pmr_size
= 0, dc_size
= 0;
1302 if (ct3d
->hostvmem
) {
1303 vmr
= host_memory_backend_get_memory(ct3d
->hostvmem
);
1304 vmr_size
= memory_region_size(vmr
);
1306 if (ct3d
->hostpmem
) {
1307 pmr
= host_memory_backend_get_memory(ct3d
->hostpmem
);
1308 pmr_size
= memory_region_size(pmr
);
1310 if (ct3d
->dc
.host_dc
) {
1311 dc_mr
= host_memory_backend_get_memory(ct3d
->dc
.host_dc
);
1312 dc_size
= memory_region_size(dc_mr
);
1315 if (!vmr
&& !pmr
&& !dc_mr
) {
1319 if (dpa_offset
+ CXL_CACHE_LINE_SIZE
> vmr_size
+ pmr_size
+ dc_size
) {
1323 if (dpa_offset
< vmr_size
) {
1324 as
= &ct3d
->hostvmem_as
;
1325 } else if (dpa_offset
< vmr_size
+ pmr_size
) {
1326 as
= &ct3d
->hostpmem_as
;
1327 dpa_offset
-= vmr_size
;
1329 as
= &ct3d
->dc
.host_dc_as
;
1330 dpa_offset
-= (vmr_size
+ pmr_size
);
1333 address_space_write(as
, dpa_offset
, MEMTXATTRS_UNSPECIFIED
, data
,
1334 CXL_CACHE_LINE_SIZE
);
1338 void cxl_set_poison_list_overflowed(CXLType3Dev
*ct3d
)
1340 ct3d
->poison_list_overflowed
= true;
1341 ct3d
->poison_list_overflow_ts
=
1342 cxl_device_get_timestamp(&ct3d
->cxl_dstate
);
1345 void cxl_clear_poison_list_overflowed(CXLType3Dev
*ct3d
)
1347 ct3d
->poison_list_overflowed
= false;
1348 ct3d
->poison_list_overflow_ts
= 0;
1351 void qmp_cxl_inject_poison(const char *path
, uint64_t start
, uint64_t length
,
1354 Object
*obj
= object_resolve_path(path
, NULL
);
1359 error_setg(errp
, "Poison injection must be in multiples of 64 bytes");
1363 error_setg(errp
, "Poison start address must be 64 byte aligned");
1367 error_setg(errp
, "Unable to resolve path");
1370 if (!object_dynamic_cast(obj
, TYPE_CXL_TYPE3
)) {
1371 error_setg(errp
, "Path does not point to a CXL type 3 device");
1375 ct3d
= CXL_TYPE3(obj
);
1377 QLIST_FOREACH(p
, &ct3d
->poison_list
, node
) {
1378 if (((start
>= p
->start
) && (start
< p
->start
+ p
->length
)) ||
1379 ((start
+ length
> p
->start
) &&
1380 (start
+ length
<= p
->start
+ p
->length
))) {
1382 "Overlap with existing poisoned region not supported");
1387 p
= g_new0(CXLPoison
, 1);
1390 /* Different from injected via the mbox */
1391 p
->type
= CXL_POISON_TYPE_INTERNAL
;
1393 if (ct3d
->poison_list_cnt
< CXL_POISON_LIST_LIMIT
) {
1394 QLIST_INSERT_HEAD(&ct3d
->poison_list
, p
, node
);
1395 ct3d
->poison_list_cnt
++;
1397 if (!ct3d
->poison_list_overflowed
) {
1398 cxl_set_poison_list_overflowed(ct3d
);
1400 QLIST_INSERT_HEAD(&ct3d
->poison_list_bkp
, p
, node
);
1404 /* For uncorrectable errors include support for multiple header recording */
1405 void qmp_cxl_inject_uncorrectable_errors(const char *path
,
1406 CXLUncorErrorRecordList
*errors
,
1409 Object
*obj
= object_resolve_path(path
, NULL
);
1410 static PCIEAERErr err
= {};
1413 uint32_t *reg_state
;
1418 error_setg(errp
, "Unable to resolve path");
1422 if (!object_dynamic_cast(obj
, TYPE_CXL_TYPE3
)) {
1423 error_setg(errp
, "Path does not point to a CXL type 3 device");
1427 err
.status
= PCI_ERR_UNC_INTN
;
1428 err
.source_id
= pci_requester_id(PCI_DEVICE(obj
));
1431 ct3d
= CXL_TYPE3(obj
);
1433 first
= QTAILQ_EMPTY(&ct3d
->error_list
);
1434 reg_state
= ct3d
->cxl_cstate
.crb
.cache_mem_registers
;
1436 uint32List
*header
= errors
->value
->header
;
1437 uint8_t header_count
= 0;
1440 cxl_err_code
= ct3d_qmp_uncor_err_to_cxl(errors
->value
->type
);
1441 if (cxl_err_code
< 0) {
1442 error_setg(errp
, "Unknown error code");
1446 /* If the error is masked, nothing to do here */
1447 if (!((1 << cxl_err_code
) &
1448 ~ldl_le_p(reg_state
+ R_CXL_RAS_UNC_ERR_MASK
))) {
1449 errors
= errors
->next
;
1453 cxl_err
= g_malloc0(sizeof(*cxl_err
));
1455 cxl_err
->type
= cxl_err_code
;
1456 while (header
&& header_count
< 32) {
1457 cxl_err
->header
[header_count
++] = header
->value
;
1458 header
= header
->next
;
1460 if (header_count
> 32) {
1461 error_setg(errp
, "Header must be 32 DWORD or less");
1464 QTAILQ_INSERT_TAIL(&ct3d
->error_list
, cxl_err
, node
);
1466 errors
= errors
->next
;
1469 if (first
&& !QTAILQ_EMPTY(&ct3d
->error_list
)) {
1470 uint32_t *cache_mem
= ct3d
->cxl_cstate
.crb
.cache_mem_registers
;
1471 uint32_t capctrl
= ldl_le_p(cache_mem
+ R_CXL_RAS_ERR_CAP_CTRL
);
1472 uint32_t *header_log
= &cache_mem
[R_CXL_RAS_ERR_HEADER0
];
1475 cxl_err
= QTAILQ_FIRST(&ct3d
->error_list
);
1476 for (i
= 0; i
< CXL_RAS_ERR_HEADER_NUM
; i
++) {
1477 stl_le_p(header_log
+ i
, cxl_err
->header
[i
]);
1480 capctrl
= FIELD_DP32(capctrl
, CXL_RAS_ERR_CAP_CTRL
,
1481 FIRST_ERROR_POINTER
, cxl_err
->type
);
1482 stl_le_p(cache_mem
+ R_CXL_RAS_ERR_CAP_CTRL
, capctrl
);
1486 QTAILQ_FOREACH(cxl_err
, &ct3d
->error_list
, node
) {
1487 unc_err
|= (1 << cxl_err
->type
);
1493 stl_le_p(reg_state
+ R_CXL_RAS_UNC_ERR_STATUS
, unc_err
);
1494 pcie_aer_inject_error(PCI_DEVICE(obj
), &err
);
1499 void qmp_cxl_inject_correctable_error(const char *path
, CxlCorErrorType type
,
1502 static PCIEAERErr err
= {};
1503 Object
*obj
= object_resolve_path(path
, NULL
);
1505 uint32_t *reg_state
;
1510 error_setg(errp
, "Unable to resolve path");
1513 if (!object_dynamic_cast(obj
, TYPE_CXL_TYPE3
)) {
1514 error_setg(errp
, "Path does not point to a CXL type 3 device");
1518 err
.status
= PCI_ERR_COR_INTERNAL
;
1519 err
.source_id
= pci_requester_id(PCI_DEVICE(obj
));
1520 err
.flags
= PCIE_AER_ERR_IS_CORRECTABLE
;
1522 ct3d
= CXL_TYPE3(obj
);
1523 reg_state
= ct3d
->cxl_cstate
.crb
.cache_mem_registers
;
1524 cor_err
= ldl_le_p(reg_state
+ R_CXL_RAS_COR_ERR_STATUS
);
1526 cxl_err_type
= ct3d_qmp_cor_err_to_cxl(type
);
1527 if (cxl_err_type
< 0) {
1528 error_setg(errp
, "Invalid COR error");
1531 /* If the error is masked, nothting to do here */
1532 if (!((1 << cxl_err_type
) &
1533 ~ldl_le_p(reg_state
+ R_CXL_RAS_COR_ERR_MASK
))) {
1537 cor_err
|= (1 << cxl_err_type
);
1538 stl_le_p(reg_state
+ R_CXL_RAS_COR_ERR_STATUS
, cor_err
);
1540 pcie_aer_inject_error(PCI_DEVICE(obj
), &err
);
1543 static void cxl_assign_event_header(CXLEventRecordHdr
*hdr
,
1544 const QemuUUID
*uuid
, uint32_t flags
,
1545 uint8_t length
, uint64_t timestamp
)
1547 st24_le_p(&hdr
->flags
, flags
);
1548 hdr
->length
= length
;
1549 memcpy(&hdr
->id
, uuid
, sizeof(hdr
->id
));
1550 stq_le_p(&hdr
->timestamp
, timestamp
);
1553 static const QemuUUID gen_media_uuid
= {
1554 .data
= UUID(0xfbcd0a77, 0xc260, 0x417f,
1555 0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6),
1558 static const QemuUUID dram_uuid
= {
1559 .data
= UUID(0x601dcbb3, 0x9c06, 0x4eab, 0xb8, 0xaf,
1560 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24),
1563 static const QemuUUID memory_module_uuid
= {
1564 .data
= UUID(0xfe927475, 0xdd59, 0x4339, 0xa5, 0x86,
1565 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74),
1568 #define CXL_GMER_VALID_CHANNEL BIT(0)
1569 #define CXL_GMER_VALID_RANK BIT(1)
1570 #define CXL_GMER_VALID_DEVICE BIT(2)
1571 #define CXL_GMER_VALID_COMPONENT BIT(3)
1573 static int ct3d_qmp_cxl_event_log_enc(CxlEventLog log
)
1576 case CXL_EVENT_LOG_INFORMATIONAL
:
1577 return CXL_EVENT_TYPE_INFO
;
1578 case CXL_EVENT_LOG_WARNING
:
1579 return CXL_EVENT_TYPE_WARN
;
1580 case CXL_EVENT_LOG_FAILURE
:
1581 return CXL_EVENT_TYPE_FAIL
;
1582 case CXL_EVENT_LOG_FATAL
:
1583 return CXL_EVENT_TYPE_FATAL
;
1588 /* Component ID is device specific. Define this as a string. */
1589 void qmp_cxl_inject_general_media_event(const char *path
, CxlEventLog log
,
1590 uint8_t flags
, uint64_t dpa
,
1591 uint8_t descriptor
, uint8_t type
,
1592 uint8_t transaction_type
,
1593 bool has_channel
, uint8_t channel
,
1594 bool has_rank
, uint8_t rank
,
1595 bool has_device
, uint32_t device
,
1596 const char *component_id
,
1599 Object
*obj
= object_resolve_path(path
, NULL
);
1600 CXLEventGenMedia gem
;
1601 CXLEventRecordHdr
*hdr
= &gem
.hdr
;
1602 CXLDeviceState
*cxlds
;
1604 uint16_t valid_flags
= 0;
1609 error_setg(errp
, "Unable to resolve path");
1612 if (!object_dynamic_cast(obj
, TYPE_CXL_TYPE3
)) {
1613 error_setg(errp
, "Path does not point to a CXL type 3 device");
1616 ct3d
= CXL_TYPE3(obj
);
1617 cxlds
= &ct3d
->cxl_dstate
;
1619 rc
= ct3d_qmp_cxl_event_log_enc(log
);
1621 error_setg(errp
, "Unhandled error log type");
1626 memset(&gem
, 0, sizeof(gem
));
1627 cxl_assign_event_header(hdr
, &gen_media_uuid
, flags
, sizeof(gem
),
1628 cxl_device_get_timestamp(&ct3d
->cxl_dstate
));
1630 stq_le_p(&gem
.phys_addr
, dpa
);
1631 gem
.descriptor
= descriptor
;
1633 gem
.transaction_type
= transaction_type
;
1636 gem
.channel
= channel
;
1637 valid_flags
|= CXL_GMER_VALID_CHANNEL
;
1642 valid_flags
|= CXL_GMER_VALID_RANK
;
1646 st24_le_p(gem
.device
, device
);
1647 valid_flags
|= CXL_GMER_VALID_DEVICE
;
1651 strncpy((char *)gem
.component_id
, component_id
,
1652 sizeof(gem
.component_id
) - 1);
1653 valid_flags
|= CXL_GMER_VALID_COMPONENT
;
1656 stw_le_p(&gem
.validity_flags
, valid_flags
);
1658 if (cxl_event_insert(cxlds
, enc_log
, (CXLEventRecordRaw
*)&gem
)) {
1659 cxl_event_irq_assert(ct3d
);
1663 #define CXL_DRAM_VALID_CHANNEL BIT(0)
1664 #define CXL_DRAM_VALID_RANK BIT(1)
1665 #define CXL_DRAM_VALID_NIBBLE_MASK BIT(2)
1666 #define CXL_DRAM_VALID_BANK_GROUP BIT(3)
1667 #define CXL_DRAM_VALID_BANK BIT(4)
1668 #define CXL_DRAM_VALID_ROW BIT(5)
1669 #define CXL_DRAM_VALID_COLUMN BIT(6)
1670 #define CXL_DRAM_VALID_CORRECTION_MASK BIT(7)
1672 void qmp_cxl_inject_dram_event(const char *path
, CxlEventLog log
, uint8_t flags
,
1673 uint64_t dpa
, uint8_t descriptor
,
1674 uint8_t type
, uint8_t transaction_type
,
1675 bool has_channel
, uint8_t channel
,
1676 bool has_rank
, uint8_t rank
,
1677 bool has_nibble_mask
, uint32_t nibble_mask
,
1678 bool has_bank_group
, uint8_t bank_group
,
1679 bool has_bank
, uint8_t bank
,
1680 bool has_row
, uint32_t row
,
1681 bool has_column
, uint16_t column
,
1682 bool has_correction_mask
,
1683 uint64List
*correction_mask
,
1686 Object
*obj
= object_resolve_path(path
, NULL
);
1688 CXLEventRecordHdr
*hdr
= &dram
.hdr
;
1689 CXLDeviceState
*cxlds
;
1691 uint16_t valid_flags
= 0;
1696 error_setg(errp
, "Unable to resolve path");
1699 if (!object_dynamic_cast(obj
, TYPE_CXL_TYPE3
)) {
1700 error_setg(errp
, "Path does not point to a CXL type 3 device");
1703 ct3d
= CXL_TYPE3(obj
);
1704 cxlds
= &ct3d
->cxl_dstate
;
1706 rc
= ct3d_qmp_cxl_event_log_enc(log
);
1708 error_setg(errp
, "Unhandled error log type");
1713 memset(&dram
, 0, sizeof(dram
));
1714 cxl_assign_event_header(hdr
, &dram_uuid
, flags
, sizeof(dram
),
1715 cxl_device_get_timestamp(&ct3d
->cxl_dstate
));
1716 stq_le_p(&dram
.phys_addr
, dpa
);
1717 dram
.descriptor
= descriptor
;
1719 dram
.transaction_type
= transaction_type
;
1722 dram
.channel
= channel
;
1723 valid_flags
|= CXL_DRAM_VALID_CHANNEL
;
1728 valid_flags
|= CXL_DRAM_VALID_RANK
;
1731 if (has_nibble_mask
) {
1732 st24_le_p(dram
.nibble_mask
, nibble_mask
);
1733 valid_flags
|= CXL_DRAM_VALID_NIBBLE_MASK
;
1736 if (has_bank_group
) {
1737 dram
.bank_group
= bank_group
;
1738 valid_flags
|= CXL_DRAM_VALID_BANK_GROUP
;
1743 valid_flags
|= CXL_DRAM_VALID_BANK
;
1747 st24_le_p(dram
.row
, row
);
1748 valid_flags
|= CXL_DRAM_VALID_ROW
;
1752 stw_le_p(&dram
.column
, column
);
1753 valid_flags
|= CXL_DRAM_VALID_COLUMN
;
1756 if (has_correction_mask
) {
1758 while (correction_mask
&& count
< 4) {
1759 stq_le_p(&dram
.correction_mask
[count
],
1760 correction_mask
->value
);
1762 correction_mask
= correction_mask
->next
;
1764 valid_flags
|= CXL_DRAM_VALID_CORRECTION_MASK
;
1767 stw_le_p(&dram
.validity_flags
, valid_flags
);
1769 if (cxl_event_insert(cxlds
, enc_log
, (CXLEventRecordRaw
*)&dram
)) {
1770 cxl_event_irq_assert(ct3d
);
1775 void qmp_cxl_inject_memory_module_event(const char *path
, CxlEventLog log
,
1776 uint8_t flags
, uint8_t type
,
1777 uint8_t health_status
,
1778 uint8_t media_status
,
1779 uint8_t additional_status
,
1781 int16_t temperature
,
1782 uint32_t dirty_shutdown_count
,
1783 uint32_t corrected_volatile_error_count
,
1784 uint32_t corrected_persist_error_count
,
1787 Object
*obj
= object_resolve_path(path
, NULL
);
1788 CXLEventMemoryModule module
;
1789 CXLEventRecordHdr
*hdr
= &module
.hdr
;
1790 CXLDeviceState
*cxlds
;
1796 error_setg(errp
, "Unable to resolve path");
1799 if (!object_dynamic_cast(obj
, TYPE_CXL_TYPE3
)) {
1800 error_setg(errp
, "Path does not point to a CXL type 3 device");
1803 ct3d
= CXL_TYPE3(obj
);
1804 cxlds
= &ct3d
->cxl_dstate
;
1806 rc
= ct3d_qmp_cxl_event_log_enc(log
);
1808 error_setg(errp
, "Unhandled error log type");
1813 memset(&module
, 0, sizeof(module
));
1814 cxl_assign_event_header(hdr
, &memory_module_uuid
, flags
, sizeof(module
),
1815 cxl_device_get_timestamp(&ct3d
->cxl_dstate
));
1818 module
.health_status
= health_status
;
1819 module
.media_status
= media_status
;
1820 module
.additional_status
= additional_status
;
1821 module
.life_used
= life_used
;
1822 stw_le_p(&module
.temperature
, temperature
);
1823 stl_le_p(&module
.dirty_shutdown_count
, dirty_shutdown_count
);
1824 stl_le_p(&module
.corrected_volatile_error_count
,
1825 corrected_volatile_error_count
);
1826 stl_le_p(&module
.corrected_persistent_error_count
,
1827 corrected_persist_error_count
);
1829 if (cxl_event_insert(cxlds
, enc_log
, (CXLEventRecordRaw
*)&module
)) {
1830 cxl_event_irq_assert(ct3d
);
1834 /* CXL r3.1 Table 8-50: Dynamic Capacity Event Record */
1835 static const QemuUUID dynamic_capacity_uuid
= {
1836 .data
= UUID(0xca95afa7, 0xf183, 0x4018, 0x8c, 0x2f,
1837 0x95, 0x26, 0x8e, 0x10, 0x1a, 0x2a),
1840 typedef enum CXLDCEventType
{
1841 DC_EVENT_ADD_CAPACITY
= 0x0,
1842 DC_EVENT_RELEASE_CAPACITY
= 0x1,
1843 DC_EVENT_FORCED_RELEASE_CAPACITY
= 0x2,
1844 DC_EVENT_REGION_CONFIG_UPDATED
= 0x3,
1845 DC_EVENT_ADD_CAPACITY_RSP
= 0x4,
1846 DC_EVENT_CAPACITY_RELEASED
= 0x5,
1850 * Check whether the range [dpa, dpa + len - 1] has overlaps with extents in
1852 * Return value: return true if has overlaps; otherwise, return false
1854 static bool cxl_extents_overlaps_dpa_range(CXLDCExtentList
*list
,
1855 uint64_t dpa
, uint64_t len
)
1858 Range range1
, range2
;
1864 range_init_nofail(&range1
, dpa
, len
);
1865 QTAILQ_FOREACH(ent
, list
, node
) {
1866 range_init_nofail(&range2
, ent
->start_dpa
, ent
->len
);
1867 if (range_overlaps_range(&range1
, &range2
)) {
1875 * Check whether the range [dpa, dpa + len - 1] is contained by extents in
1877 * Will check multiple extents containment once superset release is added.
1878 * Return value: return true if range is contained; otherwise, return false
1880 bool cxl_extents_contains_dpa_range(CXLDCExtentList
*list
,
1881 uint64_t dpa
, uint64_t len
)
1884 Range range1
, range2
;
1890 range_init_nofail(&range1
, dpa
, len
);
1891 QTAILQ_FOREACH(ent
, list
, node
) {
1892 range_init_nofail(&range2
, ent
->start_dpa
, ent
->len
);
1893 if (range_contains_range(&range2
, &range1
)) {
1900 static bool cxl_extent_groups_overlaps_dpa_range(CXLDCExtentGroupList
*list
,
1901 uint64_t dpa
, uint64_t len
)
1903 CXLDCExtentGroup
*group
;
1909 QTAILQ_FOREACH(group
, list
, node
) {
1910 if (cxl_extents_overlaps_dpa_range(&group
->list
, dpa
, len
)) {
1918 * The main function to process dynamic capacity event with extent list.
1919 * Currently DC extents add/release requests are processed.
1921 static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path
,
1922 uint16_t hid
, CXLDCEventType type
, uint8_t rid
,
1923 CxlDynamicCapacityExtentList
*records
, Error
**errp
)
1926 CXLEventDynamicCapacity dCap
= {};
1927 CXLEventRecordHdr
*hdr
= &dCap
.hdr
;
1929 uint8_t flags
= 1 << CXL_EVENT_TYPE_INFO
;
1930 uint32_t num_extents
= 0;
1931 CxlDynamicCapacityExtentList
*list
;
1932 CXLDCExtentGroup
*group
= NULL
;
1933 g_autofree CXLDCExtentRaw
*extents
= NULL
;
1934 uint8_t enc_log
= CXL_EVENT_TYPE_DYNAMIC_CAP
;
1935 uint64_t dpa
, offset
, len
, block_size
;
1936 g_autofree
unsigned long *blk_bitmap
= NULL
;
1939 obj
= object_resolve_path_type(path
, TYPE_CXL_TYPE3
, NULL
);
1941 error_setg(errp
, "Unable to resolve CXL type 3 device");
1945 dcd
= CXL_TYPE3(obj
);
1946 if (!dcd
->dc
.num_regions
) {
1947 error_setg(errp
, "No dynamic capacity support from the device");
1952 if (rid
>= dcd
->dc
.num_regions
) {
1953 error_setg(errp
, "region id is too large");
1956 block_size
= dcd
->dc
.regions
[rid
].block_size
;
1957 blk_bitmap
= bitmap_new(dcd
->dc
.regions
[rid
].len
/ block_size
);
1959 /* Sanity check and count the extents */
1962 offset
= list
->value
->offset
;
1963 len
= list
->value
->len
;
1964 dpa
= offset
+ dcd
->dc
.regions
[rid
].base
;
1967 error_setg(errp
, "extent with 0 length is not allowed");
1971 if (offset
% block_size
|| len
% block_size
) {
1972 error_setg(errp
, "dpa or len is not aligned to region block size");
1976 if (offset
+ len
> dcd
->dc
.regions
[rid
].len
) {
1977 error_setg(errp
, "extent range is beyond the region end");
1981 /* No duplicate or overlapped extents are allowed */
1982 if (test_any_bits_set(blk_bitmap
, offset
/ block_size
,
1983 len
/ block_size
)) {
1984 error_setg(errp
, "duplicate or overlapped extents are detected");
1987 bitmap_set(blk_bitmap
, offset
/ block_size
, len
/ block_size
);
1989 if (type
== DC_EVENT_RELEASE_CAPACITY
) {
1990 if (cxl_extent_groups_overlaps_dpa_range(&dcd
->dc
.extents_pending
,
1993 "cannot release extent with pending DPA range");
1996 if (!ct3_test_region_block_backed(dcd
, dpa
, len
)) {
1998 "cannot release extent with non-existing DPA range");
2001 } else if (type
== DC_EVENT_ADD_CAPACITY
) {
2002 if (cxl_extents_overlaps_dpa_range(&dcd
->dc
.extents
, dpa
, len
)) {
2004 "cannot add DPA already accessible to the same LD");
2007 if (cxl_extent_groups_overlaps_dpa_range(&dcd
->dc
.extents_pending
,
2010 "cannot add DPA again while still pending");
2018 /* Create extent list for event being passed to host */
2021 extents
= g_new0(CXLDCExtentRaw
, num_extents
);
2023 offset
= list
->value
->offset
;
2024 len
= list
->value
->len
;
2025 dpa
= dcd
->dc
.regions
[rid
].base
+ offset
;
2027 extents
[i
].start_dpa
= dpa
;
2028 extents
[i
].len
= len
;
2029 memset(extents
[i
].tag
, 0, 0x10);
2030 extents
[i
].shared_seq
= 0;
2031 if (type
== DC_EVENT_ADD_CAPACITY
) {
2032 group
= cxl_insert_extent_to_extent_group(group
,
2033 extents
[i
].start_dpa
,
2036 extents
[i
].shared_seq
);
2043 cxl_extent_group_list_insert_tail(&dcd
->dc
.extents_pending
, group
);
2047 * CXL r3.1 section 8.2.9.2.1.6: Dynamic Capacity Event Record
2049 * All Dynamic Capacity event records shall set the Event Record Severity
2050 * field in the Common Event Record Format to Informational Event. All
2051 * Dynamic Capacity related events shall be logged in the Dynamic Capacity
2054 cxl_assign_event_header(hdr
, &dynamic_capacity_uuid
, flags
, sizeof(dCap
),
2055 cxl_device_get_timestamp(&dcd
->cxl_dstate
));
2058 /* FIXME: for now, validity flag is cleared */
2059 dCap
.validity_flags
= 0;
2060 stw_le_p(&dCap
.host_id
, hid
);
2061 /* only valid for DC_REGION_CONFIG_UPDATED event */
2062 dCap
.updated_region_id
= 0;
2064 for (i
= 0; i
< num_extents
; i
++) {
2065 memcpy(&dCap
.dynamic_capacity_extent
, &extents
[i
],
2066 sizeof(CXLDCExtentRaw
));
2068 if (i
< num_extents
- 1) {
2069 /* Set "More" flag */
2070 dCap
.flags
|= BIT(0);
2073 if (cxl_event_insert(&dcd
->cxl_dstate
, enc_log
,
2074 (CXLEventRecordRaw
*)&dCap
)) {
2075 cxl_event_irq_assert(dcd
);
2080 void qmp_cxl_add_dynamic_capacity(const char *path
, uint16_t host_id
,
2081 CxlExtentSelectionPolicy sel_policy
,
2082 uint8_t region
, const char *tag
,
2083 CxlDynamicCapacityExtentList
*extents
,
2086 switch (sel_policy
) {
2087 case CXL_EXTENT_SELECTION_POLICY_PRESCRIPTIVE
:
2088 qmp_cxl_process_dynamic_capacity_prescriptive(path
, host_id
,
2089 DC_EVENT_ADD_CAPACITY
,
2090 region
, extents
, errp
);
2093 error_setg(errp
, "Selection policy not supported");
2098 void qmp_cxl_release_dynamic_capacity(const char *path
, uint16_t host_id
,
2099 CxlExtentRemovalPolicy removal_policy
,
2100 bool has_forced_removal
,
2101 bool forced_removal
,
2102 bool has_sanitize_on_release
,
2103 bool sanitize_on_release
,
2106 CxlDynamicCapacityExtentList
*extents
,
2109 CXLDCEventType type
= DC_EVENT_RELEASE_CAPACITY
;
2111 if (has_forced_removal
&& forced_removal
) {
2112 /* TODO: enable forced removal in the future */
2113 type
= DC_EVENT_FORCED_RELEASE_CAPACITY
;
2114 error_setg(errp
, "Forced removal not supported yet");
2118 switch (removal_policy
) {
2119 case CXL_EXTENT_REMOVAL_POLICY_PRESCRIPTIVE
:
2120 qmp_cxl_process_dynamic_capacity_prescriptive(path
, host_id
, type
,
2121 region
, extents
, errp
);
2124 error_setg(errp
, "Removal policy not supported");
2129 static void ct3_class_init(ObjectClass
*oc
, void *data
)
2131 DeviceClass
*dc
= DEVICE_CLASS(oc
);
2132 PCIDeviceClass
*pc
= PCI_DEVICE_CLASS(oc
);
2133 CXLType3Class
*cvc
= CXL_TYPE3_CLASS(oc
);
2135 pc
->realize
= ct3_realize
;
2136 pc
->exit
= ct3_exit
;
2137 pc
->class_id
= PCI_CLASS_MEMORY_CXL
;
2138 pc
->vendor_id
= PCI_VENDOR_ID_INTEL
;
2139 pc
->device_id
= 0xd93; /* LVF for now */
2142 pc
->config_write
= ct3d_config_write
;
2143 pc
->config_read
= ct3d_config_read
;
2145 set_bit(DEVICE_CATEGORY_STORAGE
, dc
->categories
);
2146 dc
->desc
= "CXL Memory Device (Type 3)";
2147 device_class_set_legacy_reset(dc
, ct3d_reset
);
2148 device_class_set_props(dc
, ct3_props
);
2150 cvc
->get_lsa_size
= get_lsa_size
;
2151 cvc
->get_lsa
= get_lsa
;
2152 cvc
->set_lsa
= set_lsa
;
2153 cvc
->set_cacheline
= set_cacheline
;
2156 static const TypeInfo ct3d_info
= {
2157 .name
= TYPE_CXL_TYPE3
,
2158 .parent
= TYPE_PCI_DEVICE
,
2159 .class_size
= sizeof(struct CXLType3Class
),
2160 .class_init
= ct3_class_init
,
2161 .instance_size
= sizeof(CXLType3Dev
),
2162 .interfaces
= (InterfaceInfo
[]) {
2163 { INTERFACE_CXL_DEVICE
},
2164 { INTERFACE_PCIE_DEVICE
},
2169 static void ct3d_registers(void)
2171 type_register_static(&ct3d_info
);
2174 type_init(ct3d_registers
);