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"
10 #include "qemu/module.h"
11 #include "qemu/pmem.h"
12 #include "qemu/range.h"
14 #include "sysemu/hostmem.h"
15 #include "hw/cxl/cxl.h"
16 #include "hw/pci/msix.h"
19 * Null value of all Fs suggested by IEEE RA guidelines for use of
22 #define UI64_NULL ~(0ULL)
24 static void build_dvsecs(CXLType3Dev
*ct3d
)
26 CXLComponentState
*cxl_cstate
= &ct3d
->cxl_cstate
;
29 dvsec
= (uint8_t *)&(CXLDVSECDevice
){
33 .range1_size_hi
= ct3d
->hostmem
->size
>> 32,
34 .range1_size_lo
= (2 << 5) | (2 << 2) | 0x3 |
35 (ct3d
->hostmem
->size
& 0xF0000000),
39 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
40 PCIE_CXL_DEVICE_DVSEC_LENGTH
,
41 PCIE_CXL_DEVICE_DVSEC
,
42 PCIE_CXL2_DEVICE_DVSEC_REVID
, dvsec
);
44 dvsec
= (uint8_t *)&(CXLDVSECRegisterLocator
){
46 .reg0_base_lo
= RBI_COMPONENT_REG
| CXL_COMPONENT_REG_BAR_IDX
,
48 .reg1_base_lo
= RBI_CXL_DEVICE_REG
| CXL_DEVICE_REG_BAR_IDX
,
51 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
52 REG_LOC_DVSEC_LENGTH
, REG_LOC_DVSEC
,
53 REG_LOC_DVSEC_REVID
, dvsec
);
54 dvsec
= (uint8_t *)&(CXLDVSECDeviceGPF
){
55 .phase2_duration
= 0x603, /* 3 seconds */
56 .phase2_power
= 0x33, /* 0x33 miliwatts */
58 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
59 GPF_DEVICE_DVSEC_LENGTH
, GPF_DEVICE_DVSEC
,
60 GPF_DEVICE_DVSEC_REVID
, dvsec
);
63 static void hdm_decoder_commit(CXLType3Dev
*ct3d
, int which
)
65 ComponentRegisters
*cregs
= &ct3d
->cxl_cstate
.crb
;
66 uint32_t *cache_mem
= cregs
->cache_mem_registers
;
70 /* TODO: Sanity checks that the decoder is possible */
71 ARRAY_FIELD_DP32(cache_mem
, CXL_HDM_DECODER0_CTRL
, COMMIT
, 0);
72 ARRAY_FIELD_DP32(cache_mem
, CXL_HDM_DECODER0_CTRL
, ERR
, 0);
74 ARRAY_FIELD_DP32(cache_mem
, CXL_HDM_DECODER0_CTRL
, COMMITTED
, 1);
77 static void ct3d_reg_write(void *opaque
, hwaddr offset
, uint64_t value
,
80 CXLComponentState
*cxl_cstate
= opaque
;
81 ComponentRegisters
*cregs
= &cxl_cstate
->crb
;
82 CXLType3Dev
*ct3d
= container_of(cxl_cstate
, CXLType3Dev
, cxl_cstate
);
83 uint32_t *cache_mem
= cregs
->cache_mem_registers
;
84 bool should_commit
= false;
88 g_assert(offset
< CXL2_COMPONENT_CM_REGION_SIZE
);
91 case A_CXL_HDM_DECODER0_CTRL
:
92 should_commit
= FIELD_EX32(value
, CXL_HDM_DECODER0_CTRL
, COMMIT
);
99 stl_le_p((uint8_t *)cache_mem
+ offset
, value
);
101 hdm_decoder_commit(ct3d
, which_hdm
);
105 static bool cxl_setup_memory(CXLType3Dev
*ct3d
, Error
**errp
)
107 DeviceState
*ds
= DEVICE(ct3d
);
111 if (!ct3d
->hostmem
) {
112 error_setg(errp
, "memdev property must be set");
116 mr
= host_memory_backend_get_memory(ct3d
->hostmem
);
118 error_setg(errp
, "memdev property must be set");
121 memory_region_set_nonvolatile(mr
, true);
122 memory_region_set_enabled(mr
, true);
123 host_memory_backend_set_mapped(ct3d
->hostmem
, true);
126 name
= g_strdup_printf("cxl-type3-dpa-space:%s", ds
->id
);
128 name
= g_strdup("cxl-type3-dpa-space");
130 address_space_init(&ct3d
->hostmem_as
, mr
, name
);
133 ct3d
->cxl_dstate
.pmem_size
= ct3d
->hostmem
->size
;
136 error_setg(errp
, "lsa property must be set");
143 static void ct3_realize(PCIDevice
*pci_dev
, Error
**errp
)
145 CXLType3Dev
*ct3d
= CXL_TYPE3(pci_dev
);
146 CXLComponentState
*cxl_cstate
= &ct3d
->cxl_cstate
;
147 ComponentRegisters
*regs
= &cxl_cstate
->crb
;
148 MemoryRegion
*mr
= ®s
->component_registers
;
149 uint8_t *pci_conf
= pci_dev
->config
;
150 unsigned short msix_num
= 1;
153 if (!cxl_setup_memory(ct3d
, errp
)) {
157 pci_config_set_prog_interface(pci_conf
, 0x10);
158 pci_config_set_class(pci_conf
, PCI_CLASS_MEMORY_CXL
);
160 pcie_endpoint_cap_init(pci_dev
, 0x80);
161 if (ct3d
->sn
!= UI64_NULL
) {
162 pcie_dev_ser_num_init(pci_dev
, 0x100, ct3d
->sn
);
163 cxl_cstate
->dvsec_offset
= 0x100 + 0x0c;
165 cxl_cstate
->dvsec_offset
= 0x100;
168 ct3d
->cxl_cstate
.pdev
= pci_dev
;
171 regs
->special_ops
= g_new0(MemoryRegionOps
, 1);
172 regs
->special_ops
->write
= ct3d_reg_write
;
174 cxl_component_register_block_init(OBJECT(pci_dev
), cxl_cstate
,
178 pci_dev
, CXL_COMPONENT_REG_BAR_IDX
,
179 PCI_BASE_ADDRESS_SPACE_MEMORY
| PCI_BASE_ADDRESS_MEM_TYPE_64
, mr
);
181 cxl_device_register_block_init(OBJECT(pci_dev
), &ct3d
->cxl_dstate
);
182 pci_register_bar(pci_dev
, CXL_DEVICE_REG_BAR_IDX
,
183 PCI_BASE_ADDRESS_SPACE_MEMORY
|
184 PCI_BASE_ADDRESS_MEM_TYPE_64
,
185 &ct3d
->cxl_dstate
.device_registers
);
187 /* MSI(-X) Initailization */
188 msix_init_exclusive_bar(pci_dev
, msix_num
, 4, NULL
);
189 for (i
= 0; i
< msix_num
; i
++) {
190 msix_vector_use(pci_dev
, i
);
194 static void ct3_exit(PCIDevice
*pci_dev
)
196 CXLType3Dev
*ct3d
= CXL_TYPE3(pci_dev
);
197 CXLComponentState
*cxl_cstate
= &ct3d
->cxl_cstate
;
198 ComponentRegisters
*regs
= &cxl_cstate
->crb
;
200 g_free(regs
->special_ops
);
201 address_space_destroy(&ct3d
->hostmem_as
);
204 /* TODO: Support multiple HDM decoders and DPA skip */
205 static bool cxl_type3_dpa(CXLType3Dev
*ct3d
, hwaddr host_addr
, uint64_t *dpa
)
207 uint32_t *cache_mem
= ct3d
->cxl_cstate
.crb
.cache_mem_registers
;
208 uint64_t decoder_base
, decoder_size
, hpa_offset
;
212 decoder_base
= (((uint64_t)cache_mem
[R_CXL_HDM_DECODER0_BASE_HI
] << 32) |
213 cache_mem
[R_CXL_HDM_DECODER0_BASE_LO
]);
214 if ((uint64_t)host_addr
< decoder_base
) {
218 hpa_offset
= (uint64_t)host_addr
- decoder_base
;
220 decoder_size
= ((uint64_t)cache_mem
[R_CXL_HDM_DECODER0_SIZE_HI
] << 32) |
221 cache_mem
[R_CXL_HDM_DECODER0_SIZE_LO
];
222 if (hpa_offset
>= decoder_size
) {
226 hdm0_ctrl
= cache_mem
[R_CXL_HDM_DECODER0_CTRL
];
227 iw
= FIELD_EX32(hdm0_ctrl
, CXL_HDM_DECODER0_CTRL
, IW
);
228 ig
= FIELD_EX32(hdm0_ctrl
, CXL_HDM_DECODER0_CTRL
, IG
);
230 *dpa
= (MAKE_64BIT_MASK(0, 8 + ig
) & hpa_offset
) |
231 ((MAKE_64BIT_MASK(8 + ig
+ iw
, 64 - 8 - ig
- iw
) & hpa_offset
) >> iw
);
236 MemTxResult
cxl_type3_read(PCIDevice
*d
, hwaddr host_addr
, uint64_t *data
,
237 unsigned size
, MemTxAttrs attrs
)
239 CXLType3Dev
*ct3d
= CXL_TYPE3(d
);
243 /* TODO support volatile region */
244 mr
= host_memory_backend_get_memory(ct3d
->hostmem
);
249 if (!cxl_type3_dpa(ct3d
, host_addr
, &dpa_offset
)) {
253 if (dpa_offset
> int128_get64(mr
->size
)) {
257 return address_space_read(&ct3d
->hostmem_as
, dpa_offset
, attrs
, data
, size
);
260 MemTxResult
cxl_type3_write(PCIDevice
*d
, hwaddr host_addr
, uint64_t data
,
261 unsigned size
, MemTxAttrs attrs
)
263 CXLType3Dev
*ct3d
= CXL_TYPE3(d
);
267 mr
= host_memory_backend_get_memory(ct3d
->hostmem
);
272 if (!cxl_type3_dpa(ct3d
, host_addr
, &dpa_offset
)) {
276 if (dpa_offset
> int128_get64(mr
->size
)) {
279 return address_space_write(&ct3d
->hostmem_as
, dpa_offset
, attrs
,
283 static void ct3d_reset(DeviceState
*dev
)
285 CXLType3Dev
*ct3d
= CXL_TYPE3(dev
);
286 uint32_t *reg_state
= ct3d
->cxl_cstate
.crb
.cache_mem_registers
;
287 uint32_t *write_msk
= ct3d
->cxl_cstate
.crb
.cache_mem_regs_write_mask
;
289 cxl_component_register_init_common(reg_state
, write_msk
, CXL2_TYPE3_DEVICE
);
290 cxl_device_register_init_common(&ct3d
->cxl_dstate
);
293 static Property ct3_props
[] = {
294 DEFINE_PROP_LINK("memdev", CXLType3Dev
, hostmem
, TYPE_MEMORY_BACKEND
,
295 HostMemoryBackend
*),
296 DEFINE_PROP_LINK("lsa", CXLType3Dev
, lsa
, TYPE_MEMORY_BACKEND
,
297 HostMemoryBackend
*),
298 DEFINE_PROP_UINT64("sn", CXLType3Dev
, sn
, UI64_NULL
),
299 DEFINE_PROP_END_OF_LIST(),
302 static uint64_t get_lsa_size(CXLType3Dev
*ct3d
)
306 mr
= host_memory_backend_get_memory(ct3d
->lsa
);
307 return memory_region_size(mr
);
310 static void validate_lsa_access(MemoryRegion
*mr
, uint64_t size
,
313 assert(offset
+ size
<= memory_region_size(mr
));
314 assert(offset
+ size
> offset
);
317 static uint64_t get_lsa(CXLType3Dev
*ct3d
, void *buf
, uint64_t size
,
323 mr
= host_memory_backend_get_memory(ct3d
->lsa
);
324 validate_lsa_access(mr
, size
, offset
);
326 lsa
= memory_region_get_ram_ptr(mr
) + offset
;
327 memcpy(buf
, lsa
, size
);
332 static void set_lsa(CXLType3Dev
*ct3d
, const void *buf
, uint64_t size
,
338 mr
= host_memory_backend_get_memory(ct3d
->lsa
);
339 validate_lsa_access(mr
, size
, offset
);
341 lsa
= memory_region_get_ram_ptr(mr
) + offset
;
342 memcpy(lsa
, buf
, size
);
343 memory_region_set_dirty(mr
, offset
, size
);
346 * Just like the PMEM, if the guest is not allowed to exit gracefully, label
347 * updates will get lost.
351 static void ct3_class_init(ObjectClass
*oc
, void *data
)
353 DeviceClass
*dc
= DEVICE_CLASS(oc
);
354 PCIDeviceClass
*pc
= PCI_DEVICE_CLASS(oc
);
355 CXLType3Class
*cvc
= CXL_TYPE3_CLASS(oc
);
357 pc
->realize
= ct3_realize
;
359 pc
->class_id
= PCI_CLASS_STORAGE_EXPRESS
;
360 pc
->vendor_id
= PCI_VENDOR_ID_INTEL
;
361 pc
->device_id
= 0xd93; /* LVF for now */
364 set_bit(DEVICE_CATEGORY_STORAGE
, dc
->categories
);
365 dc
->desc
= "CXL PMEM Device (Type 3)";
366 dc
->reset
= ct3d_reset
;
367 device_class_set_props(dc
, ct3_props
);
369 cvc
->get_lsa_size
= get_lsa_size
;
370 cvc
->get_lsa
= get_lsa
;
371 cvc
->set_lsa
= set_lsa
;
374 static const TypeInfo ct3d_info
= {
375 .name
= TYPE_CXL_TYPE3
,
376 .parent
= TYPE_PCI_DEVICE
,
377 .class_size
= sizeof(struct CXLType3Class
),
378 .class_init
= ct3_class_init
,
379 .instance_size
= sizeof(CXLType3Dev
),
380 .interfaces
= (InterfaceInfo
[]) {
381 { INTERFACE_CXL_DEVICE
},
382 { INTERFACE_PCIE_DEVICE
},
387 static void ct3d_registers(void)
389 type_register_static(&ct3d_info
);
392 type_init(ct3d_registers
);