diff mbox series

[2/3] hw/cxl: introduce cxl_component_update_dvsec()

Message ID 20241212130422.69380-3-zhiw@nvidia.com (mailing list archive)
State New
Headers show
Series Introduce CXL type-2 device emulation | expand

Commit Message

Zhi Wang Dec. 12, 2024, 1:04 p.m. UTC
There are many DVSEC registers in the PCI configuration space that are
configurable. E.g. DVS control. They are configured and initalized in
cxl_component_create_dvsec(). When the virtual machine reboots, the
reset callback in the emulation of the emulated CXL device resets the
device states back to default states.

So far, there is no decent approach to reset the values of CXL DVSEC
registers in the PCI configuation space one for all. Without reseting
the values of CXL DVSEC registers, the CXL type-2 driver failing to
claim the endpoint:

- DVS_CONTROL.MEM_ENABLE is left to be 1 across the system reboot.
- Type-2 driver loads.
- In the endpoint probe, the kernel CXL core sees the
  DVS_CONTROL.MEM_ENABLE is set.
- The kernel CXL core wrongly thinks the HDM decoder is pre-configured
  by BIOS/UEFI.
- The kernel CXL core uses the garbage in the HDM decoder registers and
  fails:

[   74.586911] cxl_accel_vfio_pci 0000:0d:00.0: Range register decodes
outside platform defined CXL ranges.
[   74.588585] cxl_mem mem0: endpoint2 failed probe
[   74.589478] cxl_accel_vfio_pci 0000:0d:00.0: Fail to acquire CXL
endpoint
[   74.591944] pcieport 0000:0c:00.0: unlocked secondary bus reset via:
pciehp_reset_slot+0xa8/0x150

Introduce cxl_component_update_dvsec() for the emulation of CXL devices
to reset the CXL DVSEC registers in the PCI configuration space.

Signed-off-by: Zhi Wang <zhiw@nvidia.com>
---
 hw/cxl/cxl-component-utils.c   | 36 ++++++++++++++++++++++++++++------
 include/hw/cxl/cxl_component.h |  3 +++
 2 files changed, 33 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c
index aa5fb20d25..355103d165 100644
--- a/hw/cxl/cxl-component-utils.c
+++ b/hw/cxl/cxl-component-utils.c
@@ -365,9 +365,13 @@  void cxl_component_register_init_common(uint32_t *reg_state,
  * Helper to creates a DVSEC header for a CXL entity. The caller is responsible
  * for tracking the valid offset.
  *
- * This function will build the DVSEC header on behalf of the caller and then
- * copy in the remaining data for the vendor specific bits.
- * It will also set up appropriate write masks.
+ * This function will build the DVSEC header on behalf of the caller. It will
+ * also set up appropriate write masks.
+ *
+ * If required, it will copy in the remaining data for the vendor specific bits.
+ * Or the caller can also fill the remaining data later after the DVSEC header
+ * is built via cxl_component_update_dvsec().
+ *
  */
 void cxl_component_create_dvsec(CXLComponentState *cxl,
                                 enum reg_type cxl_dev_type, uint16_t length,
@@ -387,9 +391,12 @@  void cxl_component_create_dvsec(CXLComponentState *cxl,
     pci_set_long(pdev->config + offset + PCIE_DVSEC_HEADER1_OFFSET,
                  (length << 20) | (rev << 16) | CXL_VENDOR_ID);
     pci_set_word(pdev->config + offset + PCIE_DVSEC_ID_OFFSET, type);
-    memcpy(pdev->config + offset + sizeof(DVSECHeader),
-           body + sizeof(DVSECHeader),
-           length - sizeof(DVSECHeader));
+
+    if (body) {
+        memcpy(pdev->config + offset + sizeof(DVSECHeader),
+                body + sizeof(DVSECHeader),
+                length - sizeof(DVSECHeader));
+    }
 
     /* Configure write masks */
     switch (type) {
@@ -481,6 +488,23 @@  void cxl_component_create_dvsec(CXLComponentState *cxl,
     cxl->dvsec_offset += length;
 }
 
+void cxl_component_update_dvsec(CXLComponentState *cxl, uint16_t length,
+                                uint16_t type, uint8_t *body)
+{
+    PCIDevice *pdev = cxl->pdev;
+    struct Range *r;
+
+    assert(type < CXL20_MAX_DVSEC);
+
+    r = &cxl->dvsecs[type];
+
+    assert(range_size(r) == length);
+
+    memcpy(pdev->config + r->lob + sizeof(DVSECHeader),
+           body + sizeof(DVSECHeader),
+           length - sizeof(DVSECHeader));
+}
+
 /* CXL r3.1 Section 8.2.4.20.7 CXL HDM Decoder n Control Register */
 uint8_t cxl_interleave_ways_enc(int iw, Error **errp)
 {
diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h
index abb2e874b2..30fe4bfa24 100644
--- a/include/hw/cxl/cxl_component.h
+++ b/include/hw/cxl/cxl_component.h
@@ -261,6 +261,9 @@  void cxl_component_create_dvsec(CXLComponentState *cxl_cstate,
                                 enum reg_type cxl_dev_type, uint16_t length,
                                 uint16_t type, uint8_t rev, uint8_t *body);
 
+void cxl_component_update_dvsec(CXLComponentState *cxl, uint16_t length,
+                                uint16_t type, uint8_t *body);
+
 int cxl_decoder_count_enc(int count);
 int cxl_decoder_count_dec(int enc_cnt);