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"
18 * Null value of all Fs suggested by IEEE RA guidelines for use of
21 #define UI64_NULL ~(0ULL)
23 static void build_dvsecs(CXLType3Dev
*ct3d
)
25 CXLComponentState
*cxl_cstate
= &ct3d
->cxl_cstate
;
28 dvsec
= (uint8_t *)&(CXLDVSECDevice
){
32 .range1_size_hi
= ct3d
->hostmem
->size
>> 32,
33 .range1_size_lo
= (2 << 5) | (2 << 2) | 0x3 |
34 (ct3d
->hostmem
->size
& 0xF0000000),
38 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
39 PCIE_CXL_DEVICE_DVSEC_LENGTH
,
40 PCIE_CXL_DEVICE_DVSEC
,
41 PCIE_CXL2_DEVICE_DVSEC_REVID
, dvsec
);
43 dvsec
= (uint8_t *)&(CXLDVSECRegisterLocator
){
45 .reg0_base_lo
= RBI_COMPONENT_REG
| CXL_COMPONENT_REG_BAR_IDX
,
47 .reg1_base_lo
= RBI_CXL_DEVICE_REG
| CXL_DEVICE_REG_BAR_IDX
,
50 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
51 REG_LOC_DVSEC_LENGTH
, REG_LOC_DVSEC
,
52 REG_LOC_DVSEC_REVID
, dvsec
);
53 dvsec
= (uint8_t *)&(CXLDVSECDeviceGPF
){
54 .phase2_duration
= 0x603, /* 3 seconds */
55 .phase2_power
= 0x33, /* 0x33 miliwatts */
57 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
58 GPF_DEVICE_DVSEC_LENGTH
, GPF_DEVICE_DVSEC
,
59 GPF_DEVICE_DVSEC_REVID
, dvsec
);
62 static void hdm_decoder_commit(CXLType3Dev
*ct3d
, int which
)
64 ComponentRegisters
*cregs
= &ct3d
->cxl_cstate
.crb
;
65 uint32_t *cache_mem
= cregs
->cache_mem_registers
;
69 /* TODO: Sanity checks that the decoder is possible */
70 ARRAY_FIELD_DP32(cache_mem
, CXL_HDM_DECODER0_CTRL
, COMMIT
, 0);
71 ARRAY_FIELD_DP32(cache_mem
, CXL_HDM_DECODER0_CTRL
, ERR
, 0);
73 ARRAY_FIELD_DP32(cache_mem
, CXL_HDM_DECODER0_CTRL
, COMMITTED
, 1);
76 static void ct3d_reg_write(void *opaque
, hwaddr offset
, uint64_t value
,
79 CXLComponentState
*cxl_cstate
= opaque
;
80 ComponentRegisters
*cregs
= &cxl_cstate
->crb
;
81 CXLType3Dev
*ct3d
= container_of(cxl_cstate
, CXLType3Dev
, cxl_cstate
);
82 uint32_t *cache_mem
= cregs
->cache_mem_registers
;
83 bool should_commit
= false;
87 g_assert(offset
< CXL2_COMPONENT_CM_REGION_SIZE
);
90 case A_CXL_HDM_DECODER0_CTRL
:
91 should_commit
= FIELD_EX32(value
, CXL_HDM_DECODER0_CTRL
, COMMIT
);
98 stl_le_p((uint8_t *)cache_mem
+ offset
, value
);
100 hdm_decoder_commit(ct3d
, which_hdm
);
104 static bool cxl_setup_memory(CXLType3Dev
*ct3d
, Error
**errp
)
106 DeviceState
*ds
= DEVICE(ct3d
);
110 if (!ct3d
->hostmem
) {
111 error_setg(errp
, "memdev property must be set");
115 mr
= host_memory_backend_get_memory(ct3d
->hostmem
);
117 error_setg(errp
, "memdev property must be set");
120 memory_region_set_nonvolatile(mr
, true);
121 memory_region_set_enabled(mr
, true);
122 host_memory_backend_set_mapped(ct3d
->hostmem
, true);
125 name
= g_strdup_printf("cxl-type3-dpa-space:%s", ds
->id
);
127 name
= g_strdup("cxl-type3-dpa-space");
129 address_space_init(&ct3d
->hostmem_as
, mr
, name
);
132 ct3d
->cxl_dstate
.pmem_size
= ct3d
->hostmem
->size
;
135 error_setg(errp
, "lsa property must be set");
142 static void ct3_realize(PCIDevice
*pci_dev
, Error
**errp
)
144 CXLType3Dev
*ct3d
= CXL_TYPE3(pci_dev
);
145 CXLComponentState
*cxl_cstate
= &ct3d
->cxl_cstate
;
146 ComponentRegisters
*regs
= &cxl_cstate
->crb
;
147 MemoryRegion
*mr
= ®s
->component_registers
;
148 uint8_t *pci_conf
= pci_dev
->config
;
150 if (!cxl_setup_memory(ct3d
, errp
)) {
154 pci_config_set_prog_interface(pci_conf
, 0x10);
155 pci_config_set_class(pci_conf
, PCI_CLASS_MEMORY_CXL
);
157 pcie_endpoint_cap_init(pci_dev
, 0x80);
158 if (ct3d
->sn
!= UI64_NULL
) {
159 pcie_dev_ser_num_init(pci_dev
, 0x100, ct3d
->sn
);
160 cxl_cstate
->dvsec_offset
= 0x100 + 0x0c;
162 cxl_cstate
->dvsec_offset
= 0x100;
165 ct3d
->cxl_cstate
.pdev
= pci_dev
;
168 regs
->special_ops
= g_new0(MemoryRegionOps
, 1);
169 regs
->special_ops
->write
= ct3d_reg_write
;
171 cxl_component_register_block_init(OBJECT(pci_dev
), cxl_cstate
,
175 pci_dev
, CXL_COMPONENT_REG_BAR_IDX
,
176 PCI_BASE_ADDRESS_SPACE_MEMORY
| PCI_BASE_ADDRESS_MEM_TYPE_64
, mr
);
178 cxl_device_register_block_init(OBJECT(pci_dev
), &ct3d
->cxl_dstate
);
179 pci_register_bar(pci_dev
, CXL_DEVICE_REG_BAR_IDX
,
180 PCI_BASE_ADDRESS_SPACE_MEMORY
|
181 PCI_BASE_ADDRESS_MEM_TYPE_64
,
182 &ct3d
->cxl_dstate
.device_registers
);
185 static void ct3_exit(PCIDevice
*pci_dev
)
187 CXLType3Dev
*ct3d
= CXL_TYPE3(pci_dev
);
188 CXLComponentState
*cxl_cstate
= &ct3d
->cxl_cstate
;
189 ComponentRegisters
*regs
= &cxl_cstate
->crb
;
191 g_free(regs
->special_ops
);
192 address_space_destroy(&ct3d
->hostmem_as
);
195 /* TODO: Support multiple HDM decoders and DPA skip */
196 static bool cxl_type3_dpa(CXLType3Dev
*ct3d
, hwaddr host_addr
, uint64_t *dpa
)
198 uint32_t *cache_mem
= ct3d
->cxl_cstate
.crb
.cache_mem_registers
;
199 uint64_t decoder_base
, decoder_size
, hpa_offset
;
203 decoder_base
= (((uint64_t)cache_mem
[R_CXL_HDM_DECODER0_BASE_HI
] << 32) |
204 cache_mem
[R_CXL_HDM_DECODER0_BASE_LO
]);
205 if ((uint64_t)host_addr
< decoder_base
) {
209 hpa_offset
= (uint64_t)host_addr
- decoder_base
;
211 decoder_size
= ((uint64_t)cache_mem
[R_CXL_HDM_DECODER0_SIZE_HI
] << 32) |
212 cache_mem
[R_CXL_HDM_DECODER0_SIZE_LO
];
213 if (hpa_offset
>= decoder_size
) {
217 hdm0_ctrl
= cache_mem
[R_CXL_HDM_DECODER0_CTRL
];
218 iw
= FIELD_EX32(hdm0_ctrl
, CXL_HDM_DECODER0_CTRL
, IW
);
219 ig
= FIELD_EX32(hdm0_ctrl
, CXL_HDM_DECODER0_CTRL
, IG
);
221 *dpa
= (MAKE_64BIT_MASK(0, 8 + ig
) & hpa_offset
) |
222 ((MAKE_64BIT_MASK(8 + ig
+ iw
, 64 - 8 - ig
- iw
) & hpa_offset
) >> iw
);
227 MemTxResult
cxl_type3_read(PCIDevice
*d
, hwaddr host_addr
, uint64_t *data
,
228 unsigned size
, MemTxAttrs attrs
)
230 CXLType3Dev
*ct3d
= CXL_TYPE3(d
);
234 /* TODO support volatile region */
235 mr
= host_memory_backend_get_memory(ct3d
->hostmem
);
240 if (!cxl_type3_dpa(ct3d
, host_addr
, &dpa_offset
)) {
244 if (dpa_offset
> int128_get64(mr
->size
)) {
248 return address_space_read(&ct3d
->hostmem_as
, dpa_offset
, attrs
, data
, size
);
251 MemTxResult
cxl_type3_write(PCIDevice
*d
, hwaddr host_addr
, uint64_t data
,
252 unsigned size
, MemTxAttrs attrs
)
254 CXLType3Dev
*ct3d
= CXL_TYPE3(d
);
258 mr
= host_memory_backend_get_memory(ct3d
->hostmem
);
263 if (!cxl_type3_dpa(ct3d
, host_addr
, &dpa_offset
)) {
267 if (dpa_offset
> int128_get64(mr
->size
)) {
270 return address_space_write(&ct3d
->hostmem_as
, dpa_offset
, attrs
,
274 static void ct3d_reset(DeviceState
*dev
)
276 CXLType3Dev
*ct3d
= CXL_TYPE3(dev
);
277 uint32_t *reg_state
= ct3d
->cxl_cstate
.crb
.cache_mem_registers
;
278 uint32_t *write_msk
= ct3d
->cxl_cstate
.crb
.cache_mem_regs_write_mask
;
280 cxl_component_register_init_common(reg_state
, write_msk
, CXL2_TYPE3_DEVICE
);
281 cxl_device_register_init_common(&ct3d
->cxl_dstate
);
284 static Property ct3_props
[] = {
285 DEFINE_PROP_LINK("memdev", CXLType3Dev
, hostmem
, TYPE_MEMORY_BACKEND
,
286 HostMemoryBackend
*),
287 DEFINE_PROP_LINK("lsa", CXLType3Dev
, lsa
, TYPE_MEMORY_BACKEND
,
288 HostMemoryBackend
*),
289 DEFINE_PROP_UINT64("sn", CXLType3Dev
, sn
, UI64_NULL
),
290 DEFINE_PROP_END_OF_LIST(),
293 static uint64_t get_lsa_size(CXLType3Dev
*ct3d
)
297 mr
= host_memory_backend_get_memory(ct3d
->lsa
);
298 return memory_region_size(mr
);
301 static void validate_lsa_access(MemoryRegion
*mr
, uint64_t size
,
304 assert(offset
+ size
<= memory_region_size(mr
));
305 assert(offset
+ size
> offset
);
308 static uint64_t get_lsa(CXLType3Dev
*ct3d
, void *buf
, uint64_t size
,
314 mr
= host_memory_backend_get_memory(ct3d
->lsa
);
315 validate_lsa_access(mr
, size
, offset
);
317 lsa
= memory_region_get_ram_ptr(mr
) + offset
;
318 memcpy(buf
, lsa
, size
);
323 static void set_lsa(CXLType3Dev
*ct3d
, const void *buf
, uint64_t size
,
329 mr
= host_memory_backend_get_memory(ct3d
->lsa
);
330 validate_lsa_access(mr
, size
, offset
);
332 lsa
= memory_region_get_ram_ptr(mr
) + offset
;
333 memcpy(lsa
, buf
, size
);
334 memory_region_set_dirty(mr
, offset
, size
);
337 * Just like the PMEM, if the guest is not allowed to exit gracefully, label
338 * updates will get lost.
342 static void ct3_class_init(ObjectClass
*oc
, void *data
)
344 DeviceClass
*dc
= DEVICE_CLASS(oc
);
345 PCIDeviceClass
*pc
= PCI_DEVICE_CLASS(oc
);
346 CXLType3Class
*cvc
= CXL_TYPE3_CLASS(oc
);
348 pc
->realize
= ct3_realize
;
350 pc
->class_id
= PCI_CLASS_STORAGE_EXPRESS
;
351 pc
->vendor_id
= PCI_VENDOR_ID_INTEL
;
352 pc
->device_id
= 0xd93; /* LVF for now */
355 set_bit(DEVICE_CATEGORY_STORAGE
, dc
->categories
);
356 dc
->desc
= "CXL PMEM Device (Type 3)";
357 dc
->reset
= ct3d_reset
;
358 device_class_set_props(dc
, ct3_props
);
360 cvc
->get_lsa_size
= get_lsa_size
;
361 cvc
->get_lsa
= get_lsa
;
362 cvc
->set_lsa
= set_lsa
;
365 static const TypeInfo ct3d_info
= {
366 .name
= TYPE_CXL_TYPE3
,
367 .parent
= TYPE_PCI_DEVICE
,
368 .class_size
= sizeof(struct CXLType3Class
),
369 .class_init
= ct3_class_init
,
370 .instance_size
= sizeof(CXLType3Dev
),
371 .interfaces
= (InterfaceInfo
[]) {
372 { INTERFACE_CXL_DEVICE
},
373 { INTERFACE_PCIE_DEVICE
},
378 static void ct3d_registers(void)
380 type_register_static(&ct3d_info
);
383 type_init(ct3d_registers
);