[RFC PATCH v3 29/31] hw/cxl/device: Implement get/set LSA

Ben Widawsky
2021-02-02T01:02:28Z

Signed-off-by: Ben Widawsky <ben.widawsky@intel.com>
---
hw/cxl/cxl-mailbox-utils.c | 50 +++++++++++++++++++++++++++++++++
hw/mem/cxl_type3.c | 56 ++++++++++++++++++++++++++++++++++++-
include/hw/cxl/cxl_device.h | 9 ++++++
3 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 2637250c7b..c133cf0341 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -55,6 +55,8 @@ enum {
#define MEMORY_DEVICE 0x0
CCLS = 0x41,
#define GET_PARTITION_INFO 0x0
+ #define GET_LSA 0x2
+ #define SET_LSA 0x3
};

/* 8.2.8.4.5.1 Command Return Codes */
@@ -136,8 +138,11 @@ declare_mailbox_handler(LOGS_GET_SUPPORTED);
declare_mailbox_handler(LOGS_GET_LOG);
declare_mailbox_handler(IDENTIFY_MEMORY_DEVICE);
declare_mailbox_handler(CCLS_GET_PARTITION_INFO);
+declare_mailbox_handler(CCLS_GET_LSA);
+declare_mailbox_handler(CCLS_SET_LSA);

#define IMMEDIATE_CONFIG_CHANGE (1 << 1)
+#define IMMEDIATE_DATA_CHANGE (1 << 1)
#define IMMEDIATE_POLICY_CHANGE (1 << 3)
#define IMMEDIATE_LOG_CHANGE (1 << 4)

@@ -156,6 +161,8 @@ static struct cxl_cmd cxl_cmd_set[256][256] = {
CXL_CMD(LOGS, GET_LOG, 0x18, 0),
CXL_CMD(IDENTIFY, MEMORY_DEVICE, 0, 0),
CXL_CMD(CCLS, GET_PARTITION_INFO, 0, 0),
+ CXL_CMD(CCLS, GET_LSA, 0, 0),
+ CXL_CMD(CCLS, SET_LSA, ~0, IMMEDIATE_CONFIG_CHANGE | IMMEDIATE_DATA_CHANGE),
};

#undef CXL_CMD
@@ -365,6 +372,49 @@ define_mailbox_handler(CCLS_GET_PARTITION_INFO)
return CXL_MBOX_SUCCESS;
}

+define_mailbox_handler(CCLS_GET_LSA)
+{
+ struct {
+ uint32_t offset;
+ uint32_t length;
+ } __attribute__((packed, __aligned__(16))) *get_lsa;
+ CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate);
+ CXLType3Class *cvc = CXL_TYPE3_DEV_GET_CLASS(ct3d);
+ uint32_t offset, length;
+
+ get_lsa = (void *)cmd->payload;
+ offset = get_lsa->offset;
+ length = get_lsa->length;
+
+ *len = 0;
+ if (offset + length > cvc->get_lsa_size(ct3d)) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ *len = cvc->get_lsa(ct3d, get_lsa, length, offset);
+ return CXL_MBOX_SUCCESS;
+}
+
+define_mailbox_handler(CCLS_SET_LSA)
+{
+ struct {
+ uint32_t offset;
+ uint32_t rsvd;
+ void *data;
+ } __attribute__((packed, __aligned__(16))) *set_lsa = (void *)cmd->payload;
+ CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate);
+ CXLType3Class *cvc = CXL_TYPE3_DEV_GET_CLASS(ct3d);
+ uint16_t plen = *len;
+
+ *len = 0;
+ if ((set_lsa->offset + plen) > cvc->get_lsa_size(ct3d)) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ cvc->set_lsa(ct3d, set_lsa->data, plen, set_lsa->offset);
+ return CXL_MBOX_SUCCESS;
+}
+
void cxl_process_mailbox(CXLDeviceState *cxl_dstate)
{
uint16_t ret = CXL_MBOX_SUCCESS;
diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index 074d1dd41f..d091e645aa 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -8,6 +8,7 @@
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
+#include "qemu/pmem.h"
#include "qemu/range.h"
#include "qemu/rcu.h"
#include "sysemu/hostmem.h"
@@ -148,6 +149,11 @@ static void cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
return;
}

+ if (!ct3d->lsa) {
+ error_setg(errp, "lsa property must be set");
+ return;
+ }
+
/* FIXME: need to check mr is the host bridge's MR */
mr = host_memory_backend_get_memory(ct3d->hostmem);

@@ -267,6 +273,8 @@ static Property ct3_props[] = {
DEFINE_PROP_SIZE("size", CXLType3Dev, size, -1),
DEFINE_PROP_LINK("memdev", CXLType3Dev, hostmem, TYPE_MEMORY_BACKEND,
HostMemoryBackend *),
+ DEFINE_PROP_LINK("lsa", CXLType3Dev, lsa, TYPE_MEMORY_BACKEND,
+ HostMemoryBackend *),
DEFINE_PROP_END_OF_LIST(),
};

@@ -297,7 +305,51 @@ static void pc_dimm_md_fill_device_info(const MemoryDeviceState *md,

static uint64_t get_lsa_size(CXLType3Dev *ct3d)
{
- return 0;
+ MemoryRegion *mr;
+
+ mr = host_memory_backend_get_memory(ct3d->lsa);
+ return memory_region_size(mr);
+}
+
+static void validate_lsa_access(MemoryRegion *mr, uint64_t size,
+ uint64_t offset)
+{
+ assert(offset + size <= memory_region_size(mr));
+ assert(offset + size > offset);
+}
+
+static uint64_t get_lsa(CXLType3Dev *ct3d, void *buf, uint64_t size,
+ uint64_t offset)
+{
+ MemoryRegion *mr;
+ void *lsa;
+
+ mr = host_memory_backend_get_memory(ct3d->lsa);
+ validate_lsa_access(mr, size, offset);
+
+ lsa = memory_region_get_ram_ptr(mr) + offset;
+ memcpy(buf, lsa, size);
+
+ return size;
+}
+
+static void set_lsa(CXLType3Dev *ct3d, const void *buf, uint64_t size,
+ uint64_t offset)
+{
+ MemoryRegion *mr;
+ void *lsa;
+
+ mr = host_memory_backend_get_memory(ct3d->lsa);
+ validate_lsa_access(mr, size, offset);
+
+ lsa = memory_region_get_ram_ptr(mr) + offset;
+ memcpy(lsa, buf, size);
+ memory_region_set_dirty(mr, offset, size);
+
+ /*
+ * Just like the PMEM, if the guest is not allowed to exit gracefully, label
+ * updates will get lost.
+ */
}

static void ct3_class_init(ObjectClass *oc, void *data)
@@ -325,6 +377,8 @@ static void ct3_class_init(ObjectClass *oc, void *data)
mdc->set_addr = cxl_md_set_addr;

cvc->get_lsa_size = get_lsa_size;
+ cvc->get_lsa = get_lsa;
+ cvc->set_lsa = set_lsa;
}

static const TypeInfo ct3d_info = {
diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h
index a79a0f106c..1869876ef6 100644
--- a/include/hw/cxl/cxl_device.h
+++ b/include/hw/cxl/cxl_device.h
@@ -233,7 +233,11 @@ typedef struct cxl_type3_dev {
CXLDeviceState cxl_dstate;
} CXLType3Dev;

+#ifndef TYPE_CXL_TYPE3_DEV
+#define TYPE_CXL_TYPE3_DEV "cxl-type3"
+#endif
#define CT3(obj) OBJECT_CHECK(CXLType3Dev, (obj), TYPE_CXL_TYPE3_DEV)
+OBJECT_DECLARE_TYPE(CXLType3Device, CXLType3Class, CXL_TYPE3_DEV)

struct CXLType3Class {
/* Private */
@@ -241,6 +245,11 @@ struct CXLType3Class {

/* public */
uint64_t (*get_lsa_size)(CXLType3Dev *ct3d);
+
+ uint64_t (*get_lsa)(CXLType3Dev *ct3d, void *buf, uint64_t size,
+ uint64_t offset);
+ void (*set_lsa)(CXLType3Dev *ct3d, const void *buf, uint64_t size,
+ uint64_t offset);
};

#endif
--
2.30.0