@@ -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
@@ -368,6 +375,53 @@ 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__(8))) *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;
+ } __attribute__((packed, __aligned__(8))) *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 (!plen) {
+ return CXL_MBOX_SUCCESS;
+ }
+
+ if (set_lsa->offset + plen > cvc->get_lsa_size(ct3d) + sizeof(*set_lsa)) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ cvc->set_lsa(ct3d, (void *)set_lsa + sizeof(*set_lsa),
+ plen - sizeof(*set_lsa), set_lsa->offset);
+ return CXL_MBOX_SUCCESS;
+}
+
void cxl_process_mailbox(CXLDeviceState *cxl_dstate)
{
uint16_t ret = CXL_MBOX_SUCCESS;
@@ -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"
@@ -114,6 +115,11 @@ static void cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
memory_region_set_enabled(mr, true);
host_memory_backend_set_mapped(ct3d->hostmem, true);
ct3d->cxl_dstate.pmem_size = ct3d->hostmem->size;
+
+ if (!ct3d->lsa) {
+ error_setg(errp, "lsa property must be set");
+ return;
+ }
}
@@ -168,12 +174,58 @@ 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(),
};
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)
@@ -194,6 +246,8 @@ static void ct3_class_init(ObjectClass *oc, void *data)
device_class_set_props(dc, ct3_props);
cvc->get_lsa_size = get_lsa_size;
+ cvc->get_lsa = get_lsa;
+ cvc->set_lsa = set_lsa;
}
static const TypeInfo ct3d_info = {
@@ -251,6 +251,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