From: Manish Honap <[email protected]>

Report CXL Reset Mem Clr Capable and zero the volatile backend when
Initiate CXL Reset is set with CXL Reset Mem Clr Enable (CXL r4.0
Section 9.7). A failed clear ends the reset with CXL Reset Error.

AI-used-for: code (prototype)
Signed-off-by: Manish Honap <[email protected]>
---
 hw/mem/cxl_type2.c | 36 +++++++++++++++++++++++++++++++-----
 1 file changed, 31 insertions(+), 5 deletions(-)

diff --git a/hw/mem/cxl_type2.c b/hw/mem/cxl_type2.c
index 137758cfd9..2183b0c326 100644
--- a/hw/mem/cxl_type2.c
+++ b/hw/mem/cxl_type2.c
@@ -18,6 +18,7 @@
 #include "hw/pci/pcie_port.h"
 #include "migration/vmstate.h"
 #include "system/hostmem.h"
+#include "system/ramblock.h"
 
 static void clean_memory(PCIDevice *pci_dev)
 {
@@ -215,7 +216,7 @@ static void update_dvsecs(CXLType2Dev *ct2d)
         .cap = CXL_DVSEC_CAP_CACHE | CXL_DVSEC_CAP_IO | CXL_DVSEC_CAP_MEM |
                CXL_DVSEC_CAP_MEM_HWINIT |
                1 << CXL_DVSEC_CAP_HDM_COUNT_SHIFT | CXL_DVSEC_CAP_CACHE_WBI |
-               CXL_DVSEC_CAP_RST,
+               CXL_DVSEC_CAP_RST | CXL_DVSEC_CAP_RST_MEM_CLR,
         .ctrl = CXL_DVSEC_CTRL_IO_EN,
         .range1_size_hi = size >> 32,
         .range1_size_lo = (2 << 5) | (2 << 2) | 0x3 | (size & 0xF0000000),
@@ -260,7 +261,8 @@ static void build_dvsecs(CXLType2Dev *ct2d)
                  cxl_type2_dvsec(ct2d, offsetof(CXLDVSECDevice, ctrl2)),
                  CXL_DVSEC_CTRL2_DISABLE_CACHING |
                  CXL_DVSEC_CTRL2_INIT_CACHE_WBI |
-                 CXL_DVSEC_CTRL2_INIT_CXL_RST);
+                 CXL_DVSEC_CTRL2_INIT_CXL_RST |
+                 CXL_DVSEC_CTRL2_RST_MEM_CLR_EN);
 
     memcpy(ct2d->dvsec_wmask, PCI_DEVICE(ct2d)->wmask +
            range_lob(&cxl_cstate->dvsecs[PCIE_CXL_DEVICE_DVSEC]),
@@ -293,12 +295,31 @@ static void cxl_type2_update_status2(CXLType2Dev *ct2d, 
uint16_t clear,
     pci_set_word(reg, (pci_get_word(reg) & ~clear) | set);
 }
 
+/*
+ * A discard would change the file behind a private file mapping and undo
+ * the preallocation of a prealloc backend, so those get zeros written.
+ */
+static bool cxl_type2_clear_memory(CXLType2Dev *ct2d)
+{
+    MemoryRegion *vmr = host_memory_backend_get_memory(ct2d->hostvmem);
+    RAMBlock *rb = vmr->ram_block;
+    uint64_t size = memory_region_size(vmr);
+
+    if (rb && !ct2d->hostvmem->prealloc && !ram_block_discard_is_disabled() &&
+        (qemu_ram_get_fd(rb) < 0 || qemu_ram_is_shared(rb)) &&
+        !ram_block_discard_range(rb, 0, size)) {
+        return true;
+    }
+    return address_space_set(&ct2d->hostvmem_as, 0, 0, size,
+                             MEMTXATTRS_UNSPECIFIED) == MEMTX_OK;
+}
+
 /*
  * CXL r4.0 Section 9.7. Fields locked by CONFIG_LOCK or Lock On Commit keep
  * their values. The CXL.io part of the reset, which has the scope of an FLR,
  * is not emulated.
  */
-static void cxl_type2_cxl_reset(CXLType2Dev *ct2d)
+static void cxl_type2_cxl_reset(CXLType2Dev *ct2d, uint16_t ctrl2)
 {
     static const size_t range_bases[] = {
         offsetof(CXLDVSECDevice, range1_base_hi),
@@ -309,6 +330,7 @@ static void cxl_type2_cxl_reset(CXLType2Dev *ct2d)
     uint8_t *config = PCI_DEVICE(ct2d)->config;
     uint32_t *cache_mem = ct2d->cxl_cstate.crb.cache_mem_registers;
     uint16_t lock = cxl_type2_dvsec(ct2d, offsetof(CXLDVSECDevice, lock));
+    bool cleared = true;
 
     cxl_type2_update_status2(ct2d, CXL_DVSEC_STATUS2_RST_DONE |
                              CXL_DVSEC_STATUS2_RST_ERR, 0);
@@ -328,8 +350,12 @@ static void cxl_type2_cxl_reset(CXLType2Dev *ct2d)
 
     cxl_type2_update_mem_active(ct2d);
 
+    if (ctrl2 & CXL_DVSEC_CTRL2_RST_MEM_CLR_EN) {
+        cleared = cxl_type2_clear_memory(ct2d);
+    }
     cxl_type2_update_status2(ct2d, CXL_DVSEC_STATUS2_CACHE_INV,
-                             CXL_DVSEC_STATUS2_RST_DONE);
+                             cleared ? CXL_DVSEC_STATUS2_RST_DONE :
+                             CXL_DVSEC_STATUS2_RST_ERR);
 }
 
 /*
@@ -355,7 +381,7 @@ static void cxl_type2_ctrl2_write(CXLType2Dev *ct2d)
     }
     /* Initiate CXL Reset reads as 0; the reset clears all of Control2 */
     if (ctrl2 & CXL_DVSEC_CTRL2_INIT_CXL_RST) {
-        cxl_type2_cxl_reset(ct2d);
+        cxl_type2_cxl_reset(ct2d, ctrl2);
     }
 }
 
-- 
2.53.0


Reply via email to