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"
17 static void build_dvsecs(CXLType3Dev
*ct3d
)
19 CXLComponentState
*cxl_cstate
= &ct3d
->cxl_cstate
;
22 dvsec
= (uint8_t *)&(CXLDVSECDevice
){
26 .range1_size_hi
= ct3d
->hostmem
->size
>> 32,
27 .range1_size_lo
= (2 << 5) | (2 << 2) | 0x3 |
28 (ct3d
->hostmem
->size
& 0xF0000000),
32 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
33 PCIE_CXL_DEVICE_DVSEC_LENGTH
,
34 PCIE_CXL_DEVICE_DVSEC
,
35 PCIE_CXL2_DEVICE_DVSEC_REVID
, dvsec
);
37 dvsec
= (uint8_t *)&(CXLDVSECRegisterLocator
){
39 .reg0_base_lo
= RBI_COMPONENT_REG
| CXL_COMPONENT_REG_BAR_IDX
,
41 .reg1_base_lo
= RBI_CXL_DEVICE_REG
| CXL_DEVICE_REG_BAR_IDX
,
44 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
45 REG_LOC_DVSEC_LENGTH
, REG_LOC_DVSEC
,
46 REG_LOC_DVSEC_REVID
, dvsec
);
47 dvsec
= (uint8_t *)&(CXLDVSECDeviceGPF
){
48 .phase2_duration
= 0x603, /* 3 seconds */
49 .phase2_power
= 0x33, /* 0x33 miliwatts */
51 cxl_component_create_dvsec(cxl_cstate
, CXL2_TYPE3_DEVICE
,
52 GPF_DEVICE_DVSEC_LENGTH
, GPF_PORT_DVSEC
,
53 GPF_DEVICE_DVSEC_REVID
, dvsec
);
56 static void hdm_decoder_commit(CXLType3Dev
*ct3d
, int which
)
58 ComponentRegisters
*cregs
= &ct3d
->cxl_cstate
.crb
;
59 uint32_t *cache_mem
= cregs
->cache_mem_registers
;
63 /* TODO: Sanity checks that the decoder is possible */
64 ARRAY_FIELD_DP32(cache_mem
, CXL_HDM_DECODER0_CTRL
, COMMIT
, 0);
65 ARRAY_FIELD_DP32(cache_mem
, CXL_HDM_DECODER0_CTRL
, ERR
, 0);
67 ARRAY_FIELD_DP32(cache_mem
, CXL_HDM_DECODER0_CTRL
, COMMITTED
, 1);
70 static void ct3d_reg_write(void *opaque
, hwaddr offset
, uint64_t value
,
73 CXLComponentState
*cxl_cstate
= opaque
;
74 ComponentRegisters
*cregs
= &cxl_cstate
->crb
;
75 CXLType3Dev
*ct3d
= container_of(cxl_cstate
, CXLType3Dev
, cxl_cstate
);
76 uint32_t *cache_mem
= cregs
->cache_mem_registers
;
77 bool should_commit
= false;
81 g_assert(offset
< CXL2_COMPONENT_CM_REGION_SIZE
);
84 case A_CXL_HDM_DECODER0_CTRL
:
85 should_commit
= FIELD_EX32(value
, CXL_HDM_DECODER0_CTRL
, COMMIT
);
92 stl_le_p((uint8_t *)cache_mem
+ offset
, value
);
94 hdm_decoder_commit(ct3d
, which_hdm
);
98 static bool cxl_setup_memory(CXLType3Dev
*ct3d
, Error
**errp
)
100 DeviceState
*ds
= DEVICE(ct3d
);
104 if (!ct3d
->hostmem
) {
105 error_setg(errp
, "memdev property must be set");
109 mr
= host_memory_backend_get_memory(ct3d
->hostmem
);
111 error_setg(errp
, "memdev property must be set");
114 memory_region_set_nonvolatile(mr
, true);
115 memory_region_set_enabled(mr
, true);
116 host_memory_backend_set_mapped(ct3d
->hostmem
, true);
119 name
= g_strdup_printf("cxl-type3-dpa-space:%s", ds
->id
);
121 name
= g_strdup("cxl-type3-dpa-space");
123 address_space_init(&ct3d
->hostmem_as
, mr
, name
);
126 ct3d
->cxl_dstate
.pmem_size
= ct3d
->hostmem
->size
;
129 error_setg(errp
, "lsa property must be set");
136 static void ct3_realize(PCIDevice
*pci_dev
, Error
**errp
)
138 CXLType3Dev
*ct3d
= CXL_TYPE3(pci_dev
);
139 CXLComponentState
*cxl_cstate
= &ct3d
->cxl_cstate
;
140 ComponentRegisters
*regs
= &cxl_cstate
->crb
;
141 MemoryRegion
*mr
= ®s
->component_registers
;
142 uint8_t *pci_conf
= pci_dev
->config
;
144 if (!cxl_setup_memory(ct3d
, errp
)) {
148 pci_config_set_prog_interface(pci_conf
, 0x10);
149 pci_config_set_class(pci_conf
, PCI_CLASS_MEMORY_CXL
);
151 pcie_endpoint_cap_init(pci_dev
, 0x80);
152 cxl_cstate
->dvsec_offset
= 0x100;
154 ct3d
->cxl_cstate
.pdev
= pci_dev
;
157 regs
->special_ops
= g_new0(MemoryRegionOps
, 1);
158 regs
->special_ops
->write
= ct3d_reg_write
;
160 cxl_component_register_block_init(OBJECT(pci_dev
), cxl_cstate
,
164 pci_dev
, CXL_COMPONENT_REG_BAR_IDX
,
165 PCI_BASE_ADDRESS_SPACE_MEMORY
| PCI_BASE_ADDRESS_MEM_TYPE_64
, mr
);
167 cxl_device_register_block_init(OBJECT(pci_dev
), &ct3d
->cxl_dstate
);
168 pci_register_bar(pci_dev
, CXL_DEVICE_REG_BAR_IDX
,
169 PCI_BASE_ADDRESS_SPACE_MEMORY
|
170 PCI_BASE_ADDRESS_MEM_TYPE_64
,
171 &ct3d
->cxl_dstate
.device_registers
);
174 static void ct3_exit(PCIDevice
*pci_dev
)
176 CXLType3Dev
*ct3d
= CXL_TYPE3(pci_dev
);
177 CXLComponentState
*cxl_cstate
= &ct3d
->cxl_cstate
;
178 ComponentRegisters
*regs
= &cxl_cstate
->crb
;
180 g_free(regs
->special_ops
);
181 address_space_destroy(&ct3d
->hostmem_as
);
184 /* TODO: Support multiple HDM decoders and DPA skip */
185 static bool cxl_type3_dpa(CXLType3Dev
*ct3d
, hwaddr host_addr
, uint64_t *dpa
)
187 uint32_t *cache_mem
= ct3d
->cxl_cstate
.crb
.cache_mem_registers
;
188 uint64_t decoder_base
, decoder_size
, hpa_offset
;
192 decoder_base
= (((uint64_t)cache_mem
[R_CXL_HDM_DECODER0_BASE_HI
] << 32) |
193 cache_mem
[R_CXL_HDM_DECODER0_BASE_LO
]);
194 if ((uint64_t)host_addr
< decoder_base
) {
198 hpa_offset
= (uint64_t)host_addr
- decoder_base
;
200 decoder_size
= ((uint64_t)cache_mem
[R_CXL_HDM_DECODER0_SIZE_HI
] << 32) |
201 cache_mem
[R_CXL_HDM_DECODER0_SIZE_LO
];
202 if (hpa_offset
>= decoder_size
) {
206 hdm0_ctrl
= cache_mem
[R_CXL_HDM_DECODER0_CTRL
];
207 iw
= FIELD_EX32(hdm0_ctrl
, CXL_HDM_DECODER0_CTRL
, IW
);
208 ig
= FIELD_EX32(hdm0_ctrl
, CXL_HDM_DECODER0_CTRL
, IG
);
210 *dpa
= (MAKE_64BIT_MASK(0, 8 + ig
) & hpa_offset
) |
211 ((MAKE_64BIT_MASK(8 + ig
+ iw
, 64 - 8 - ig
- iw
) & hpa_offset
) >> iw
);
216 MemTxResult
cxl_type3_read(PCIDevice
*d
, hwaddr host_addr
, uint64_t *data
,
217 unsigned size
, MemTxAttrs attrs
)
219 CXLType3Dev
*ct3d
= CXL_TYPE3(d
);
223 /* TODO support volatile region */
224 mr
= host_memory_backend_get_memory(ct3d
->hostmem
);
229 if (!cxl_type3_dpa(ct3d
, host_addr
, &dpa_offset
)) {
233 if (dpa_offset
> int128_get64(mr
->size
)) {
237 return address_space_read(&ct3d
->hostmem_as
, dpa_offset
, attrs
, data
, size
);
240 MemTxResult
cxl_type3_write(PCIDevice
*d
, hwaddr host_addr
, uint64_t data
,
241 unsigned size
, MemTxAttrs attrs
)
243 CXLType3Dev
*ct3d
= CXL_TYPE3(d
);
247 mr
= host_memory_backend_get_memory(ct3d
->hostmem
);
252 if (!cxl_type3_dpa(ct3d
, host_addr
, &dpa_offset
)) {
256 if (dpa_offset
> int128_get64(mr
->size
)) {
259 return address_space_write(&ct3d
->hostmem_as
, dpa_offset
, attrs
,
263 static void ct3d_reset(DeviceState
*dev
)
265 CXLType3Dev
*ct3d
= CXL_TYPE3(dev
);
266 uint32_t *reg_state
= ct3d
->cxl_cstate
.crb
.cache_mem_registers
;
267 uint32_t *write_msk
= ct3d
->cxl_cstate
.crb
.cache_mem_regs_write_mask
;
269 cxl_component_register_init_common(reg_state
, write_msk
, CXL2_TYPE3_DEVICE
);
270 cxl_device_register_init_common(&ct3d
->cxl_dstate
);
273 static Property ct3_props
[] = {
274 DEFINE_PROP_LINK("memdev", CXLType3Dev
, hostmem
, TYPE_MEMORY_BACKEND
,
275 HostMemoryBackend
*),
276 DEFINE_PROP_LINK("lsa", CXLType3Dev
, lsa
, TYPE_MEMORY_BACKEND
,
277 HostMemoryBackend
*),
278 DEFINE_PROP_END_OF_LIST(),
281 static uint64_t get_lsa_size(CXLType3Dev
*ct3d
)
285 mr
= host_memory_backend_get_memory(ct3d
->lsa
);
286 return memory_region_size(mr
);
289 static void validate_lsa_access(MemoryRegion
*mr
, uint64_t size
,
292 assert(offset
+ size
<= memory_region_size(mr
));
293 assert(offset
+ size
> offset
);
296 static uint64_t get_lsa(CXLType3Dev
*ct3d
, void *buf
, uint64_t size
,
302 mr
= host_memory_backend_get_memory(ct3d
->lsa
);
303 validate_lsa_access(mr
, size
, offset
);
305 lsa
= memory_region_get_ram_ptr(mr
) + offset
;
306 memcpy(buf
, lsa
, size
);
311 static void set_lsa(CXLType3Dev
*ct3d
, const void *buf
, uint64_t size
,
317 mr
= host_memory_backend_get_memory(ct3d
->lsa
);
318 validate_lsa_access(mr
, size
, offset
);
320 lsa
= memory_region_get_ram_ptr(mr
) + offset
;
321 memcpy(lsa
, buf
, size
);
322 memory_region_set_dirty(mr
, offset
, size
);
325 * Just like the PMEM, if the guest is not allowed to exit gracefully, label
326 * updates will get lost.
330 static void ct3_class_init(ObjectClass
*oc
, void *data
)
332 DeviceClass
*dc
= DEVICE_CLASS(oc
);
333 PCIDeviceClass
*pc
= PCI_DEVICE_CLASS(oc
);
334 CXLType3Class
*cvc
= CXL_TYPE3_CLASS(oc
);
336 pc
->realize
= ct3_realize
;
338 pc
->class_id
= PCI_CLASS_STORAGE_EXPRESS
;
339 pc
->vendor_id
= PCI_VENDOR_ID_INTEL
;
340 pc
->device_id
= 0xd93; /* LVF for now */
343 set_bit(DEVICE_CATEGORY_STORAGE
, dc
->categories
);
344 dc
->desc
= "CXL PMEM Device (Type 3)";
345 dc
->reset
= ct3d_reset
;
346 device_class_set_props(dc
, ct3_props
);
348 cvc
->get_lsa_size
= get_lsa_size
;
349 cvc
->get_lsa
= get_lsa
;
350 cvc
->set_lsa
= set_lsa
;
353 static const TypeInfo ct3d_info
= {
354 .name
= TYPE_CXL_TYPE3
,
355 .parent
= TYPE_PCI_DEVICE
,
356 .class_size
= sizeof(struct CXLType3Class
),
357 .class_init
= ct3_class_init
,
358 .instance_size
= sizeof(CXLType3Dev
),
359 .interfaces
= (InterfaceInfo
[]) {
360 { INTERFACE_CXL_DEVICE
},
361 { INTERFACE_PCIE_DEVICE
},
366 static void ct3d_registers(void)
368 type_register_static(&ct3d_info
);
371 type_init(ct3d_registers
);