|
@@ -9,6 +9,7 @@
|
|
|
|
|
|
#include "qemu/osdep.h"
|
|
|
#include "hw/cxl/cxl.h"
|
|
|
+#include "hw/cxl/cxl_events.h"
|
|
|
#include "hw/pci/pci.h"
|
|
|
#include "qemu/cutils.h"
|
|
|
#include "qemu/log.h"
|
|
@@ -62,36 +63,12 @@ enum {
|
|
|
#define GET_PARTITION_INFO 0x0
|
|
|
#define GET_LSA 0x2
|
|
|
#define SET_LSA 0x3
|
|
|
+ MEDIA_AND_POISON = 0x43,
|
|
|
+ #define GET_POISON_LIST 0x0
|
|
|
+ #define INJECT_POISON 0x1
|
|
|
+ #define CLEAR_POISON 0x2
|
|
|
};
|
|
|
|
|
|
-/* 8.2.8.4.5.1 Command Return Codes */
|
|
|
-typedef enum {
|
|
|
- CXL_MBOX_SUCCESS = 0x0,
|
|
|
- CXL_MBOX_BG_STARTED = 0x1,
|
|
|
- CXL_MBOX_INVALID_INPUT = 0x2,
|
|
|
- CXL_MBOX_UNSUPPORTED = 0x3,
|
|
|
- CXL_MBOX_INTERNAL_ERROR = 0x4,
|
|
|
- CXL_MBOX_RETRY_REQUIRED = 0x5,
|
|
|
- CXL_MBOX_BUSY = 0x6,
|
|
|
- CXL_MBOX_MEDIA_DISABLED = 0x7,
|
|
|
- CXL_MBOX_FW_XFER_IN_PROGRESS = 0x8,
|
|
|
- CXL_MBOX_FW_XFER_OUT_OF_ORDER = 0x9,
|
|
|
- CXL_MBOX_FW_AUTH_FAILED = 0xa,
|
|
|
- CXL_MBOX_FW_INVALID_SLOT = 0xb,
|
|
|
- CXL_MBOX_FW_ROLLEDBACK = 0xc,
|
|
|
- CXL_MBOX_FW_REST_REQD = 0xd,
|
|
|
- CXL_MBOX_INVALID_HANDLE = 0xe,
|
|
|
- CXL_MBOX_INVALID_PA = 0xf,
|
|
|
- CXL_MBOX_INJECT_POISON_LIMIT = 0x10,
|
|
|
- CXL_MBOX_PERMANENT_MEDIA_FAILURE = 0x11,
|
|
|
- CXL_MBOX_ABORTED = 0x12,
|
|
|
- CXL_MBOX_INVALID_SECURITY_STATE = 0x13,
|
|
|
- CXL_MBOX_INCORRECT_PASSPHRASE = 0x14,
|
|
|
- CXL_MBOX_UNSUPPORTED_MAILBOX = 0x15,
|
|
|
- CXL_MBOX_INVALID_PAYLOAD_LENGTH = 0x16,
|
|
|
- CXL_MBOX_MAX = 0x17
|
|
|
-} CXLRetCode;
|
|
|
-
|
|
|
struct cxl_cmd;
|
|
|
typedef CXLRetCode (*opcode_handler)(struct cxl_cmd *cmd,
|
|
|
CXLDeviceState *cxl_dstate, uint16_t *len);
|
|
@@ -103,26 +80,124 @@ struct cxl_cmd {
|
|
|
uint8_t *payload;
|
|
|
};
|
|
|
|
|
|
-#define DEFINE_MAILBOX_HANDLER_ZEROED(name, size) \
|
|
|
- uint16_t __zero##name = size; \
|
|
|
- static CXLRetCode cmd_##name(struct cxl_cmd *cmd, \
|
|
|
- CXLDeviceState *cxl_dstate, uint16_t *len) \
|
|
|
- { \
|
|
|
- *len = __zero##name; \
|
|
|
- memset(cmd->payload, 0, *len); \
|
|
|
- return CXL_MBOX_SUCCESS; \
|
|
|
+static CXLRetCode cmd_events_get_records(struct cxl_cmd *cmd,
|
|
|
+ CXLDeviceState *cxlds,
|
|
|
+ uint16_t *len)
|
|
|
+{
|
|
|
+ CXLGetEventPayload *pl;
|
|
|
+ uint8_t log_type;
|
|
|
+ int max_recs;
|
|
|
+
|
|
|
+ if (cmd->in < sizeof(log_type)) {
|
|
|
+ return CXL_MBOX_INVALID_INPUT;
|
|
|
+ }
|
|
|
+
|
|
|
+ log_type = *((uint8_t *)cmd->payload);
|
|
|
+
|
|
|
+ pl = (CXLGetEventPayload *)cmd->payload;
|
|
|
+ memset(pl, 0, sizeof(*pl));
|
|
|
+
|
|
|
+ max_recs = (cxlds->payload_size - CXL_EVENT_PAYLOAD_HDR_SIZE) /
|
|
|
+ CXL_EVENT_RECORD_SIZE;
|
|
|
+ if (max_recs > 0xFFFF) {
|
|
|
+ max_recs = 0xFFFF;
|
|
|
+ }
|
|
|
+
|
|
|
+ return cxl_event_get_records(cxlds, pl, log_type, max_recs, len);
|
|
|
+}
|
|
|
+
|
|
|
+static CXLRetCode cmd_events_clear_records(struct cxl_cmd *cmd,
|
|
|
+ CXLDeviceState *cxlds,
|
|
|
+ uint16_t *len)
|
|
|
+{
|
|
|
+ CXLClearEventPayload *pl;
|
|
|
+
|
|
|
+ pl = (CXLClearEventPayload *)cmd->payload;
|
|
|
+ *len = 0;
|
|
|
+ return cxl_event_clear_records(cxlds, pl);
|
|
|
+}
|
|
|
+
|
|
|
+static CXLRetCode cmd_events_get_interrupt_policy(struct cxl_cmd *cmd,
|
|
|
+ CXLDeviceState *cxlds,
|
|
|
+ uint16_t *len)
|
|
|
+{
|
|
|
+ CXLEventInterruptPolicy *policy;
|
|
|
+ CXLEventLog *log;
|
|
|
+
|
|
|
+ policy = (CXLEventInterruptPolicy *)cmd->payload;
|
|
|
+ memset(policy, 0, sizeof(*policy));
|
|
|
+
|
|
|
+ log = &cxlds->event_logs[CXL_EVENT_TYPE_INFO];
|
|
|
+ if (log->irq_enabled) {
|
|
|
+ policy->info_settings = CXL_EVENT_INT_SETTING(log->irq_vec);
|
|
|
+ }
|
|
|
+
|
|
|
+ log = &cxlds->event_logs[CXL_EVENT_TYPE_WARN];
|
|
|
+ if (log->irq_enabled) {
|
|
|
+ policy->warn_settings = CXL_EVENT_INT_SETTING(log->irq_vec);
|
|
|
+ }
|
|
|
+
|
|
|
+ log = &cxlds->event_logs[CXL_EVENT_TYPE_FAIL];
|
|
|
+ if (log->irq_enabled) {
|
|
|
+ policy->failure_settings = CXL_EVENT_INT_SETTING(log->irq_vec);
|
|
|
+ }
|
|
|
+
|
|
|
+ log = &cxlds->event_logs[CXL_EVENT_TYPE_FATAL];
|
|
|
+ if (log->irq_enabled) {
|
|
|
+ policy->fatal_settings = CXL_EVENT_INT_SETTING(log->irq_vec);
|
|
|
+ }
|
|
|
+
|
|
|
+ log = &cxlds->event_logs[CXL_EVENT_TYPE_DYNAMIC_CAP];
|
|
|
+ if (log->irq_enabled) {
|
|
|
+ /* Dynamic Capacity borrows the same vector as info */
|
|
|
+ policy->dyn_cap_settings = CXL_INT_MSI_MSIX;
|
|
|
+ }
|
|
|
+
|
|
|
+ *len = sizeof(*policy);
|
|
|
+ return CXL_MBOX_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+static CXLRetCode cmd_events_set_interrupt_policy(struct cxl_cmd *cmd,
|
|
|
+ CXLDeviceState *cxlds,
|
|
|
+ uint16_t *len)
|
|
|
+{
|
|
|
+ CXLEventInterruptPolicy *policy;
|
|
|
+ CXLEventLog *log;
|
|
|
+
|
|
|
+ if (*len < CXL_EVENT_INT_SETTING_MIN_LEN) {
|
|
|
+ return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
|
|
}
|
|
|
-#define DEFINE_MAILBOX_HANDLER_NOP(name) \
|
|
|
- static CXLRetCode cmd_##name(struct cxl_cmd *cmd, \
|
|
|
- CXLDeviceState *cxl_dstate, uint16_t *len) \
|
|
|
- { \
|
|
|
- return CXL_MBOX_SUCCESS; \
|
|
|
+
|
|
|
+ policy = (CXLEventInterruptPolicy *)cmd->payload;
|
|
|
+
|
|
|
+ log = &cxlds->event_logs[CXL_EVENT_TYPE_INFO];
|
|
|
+ log->irq_enabled = (policy->info_settings & CXL_EVENT_INT_MODE_MASK) ==
|
|
|
+ CXL_INT_MSI_MSIX;
|
|
|
+
|
|
|
+ log = &cxlds->event_logs[CXL_EVENT_TYPE_WARN];
|
|
|
+ log->irq_enabled = (policy->warn_settings & CXL_EVENT_INT_MODE_MASK) ==
|
|
|
+ CXL_INT_MSI_MSIX;
|
|
|
+
|
|
|
+ log = &cxlds->event_logs[CXL_EVENT_TYPE_FAIL];
|
|
|
+ log->irq_enabled = (policy->failure_settings & CXL_EVENT_INT_MODE_MASK) ==
|
|
|
+ CXL_INT_MSI_MSIX;
|
|
|
+
|
|
|
+ log = &cxlds->event_logs[CXL_EVENT_TYPE_FATAL];
|
|
|
+ log->irq_enabled = (policy->fatal_settings & CXL_EVENT_INT_MODE_MASK) ==
|
|
|
+ CXL_INT_MSI_MSIX;
|
|
|
+
|
|
|
+ /* DCD is optional */
|
|
|
+ if (*len < sizeof(*policy)) {
|
|
|
+ return CXL_MBOX_SUCCESS;
|
|
|
}
|
|
|
|
|
|
-DEFINE_MAILBOX_HANDLER_ZEROED(events_get_records, 0x20);
|
|
|
-DEFINE_MAILBOX_HANDLER_NOP(events_clear_records);
|
|
|
-DEFINE_MAILBOX_HANDLER_ZEROED(events_get_interrupt_policy, 4);
|
|
|
-DEFINE_MAILBOX_HANDLER_NOP(events_set_interrupt_policy);
|
|
|
+ log = &cxlds->event_logs[CXL_EVENT_TYPE_DYNAMIC_CAP];
|
|
|
+ log->irq_enabled = (policy->dyn_cap_settings & CXL_EVENT_INT_MODE_MASK) ==
|
|
|
+ CXL_INT_MSI_MSIX;
|
|
|
+
|
|
|
+ *len = sizeof(*policy);
|
|
|
+ return CXL_MBOX_SUCCESS;
|
|
|
+}
|
|
|
|
|
|
/* 8.2.9.2.1 */
|
|
|
static CXLRetCode cmd_firmware_update_get_info(struct cxl_cmd *cmd,
|
|
@@ -295,6 +370,10 @@ static CXLRetCode cmd_identify_memory_device(struct cxl_cmd *cmd,
|
|
|
stq_le_p(&id->persistent_capacity, cxl_dstate->pmem_size / CXL_CAPACITY_MULTIPLIER);
|
|
|
stq_le_p(&id->volatile_capacity, cxl_dstate->vmem_size / CXL_CAPACITY_MULTIPLIER);
|
|
|
stl_le_p(&id->lsa_size, cvc->get_lsa_size(ct3d));
|
|
|
+ /* 256 poison records */
|
|
|
+ st24_le_p(id->poison_list_max_mer, 256);
|
|
|
+ /* No limit - so limited by main poison record limit */
|
|
|
+ stw_le_p(&id->inject_poison_limit, 0);
|
|
|
|
|
|
*len = sizeof(*id);
|
|
|
return CXL_MBOX_SUCCESS;
|
|
@@ -384,6 +463,206 @@ static CXLRetCode cmd_ccls_set_lsa(struct cxl_cmd *cmd,
|
|
|
return CXL_MBOX_SUCCESS;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * This is very inefficient, but good enough for now!
|
|
|
+ * Also the payload will always fit, so no need to handle the MORE flag and
|
|
|
+ * make this stateful. We may want to allow longer poison lists to aid
|
|
|
+ * testing that kernel functionality.
|
|
|
+ */
|
|
|
+static CXLRetCode cmd_media_get_poison_list(struct cxl_cmd *cmd,
|
|
|
+ CXLDeviceState *cxl_dstate,
|
|
|
+ uint16_t *len)
|
|
|
+{
|
|
|
+ struct get_poison_list_pl {
|
|
|
+ uint64_t pa;
|
|
|
+ uint64_t length;
|
|
|
+ } QEMU_PACKED;
|
|
|
+
|
|
|
+ struct get_poison_list_out_pl {
|
|
|
+ uint8_t flags;
|
|
|
+ uint8_t rsvd1;
|
|
|
+ uint64_t overflow_timestamp;
|
|
|
+ uint16_t count;
|
|
|
+ uint8_t rsvd2[0x14];
|
|
|
+ struct {
|
|
|
+ uint64_t addr;
|
|
|
+ uint32_t length;
|
|
|
+ uint32_t resv;
|
|
|
+ } QEMU_PACKED records[];
|
|
|
+ } QEMU_PACKED;
|
|
|
+
|
|
|
+ struct get_poison_list_pl *in = (void *)cmd->payload;
|
|
|
+ struct get_poison_list_out_pl *out = (void *)cmd->payload;
|
|
|
+ CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate);
|
|
|
+ uint16_t record_count = 0, i = 0;
|
|
|
+ uint64_t query_start, query_length;
|
|
|
+ CXLPoisonList *poison_list = &ct3d->poison_list;
|
|
|
+ CXLPoison *ent;
|
|
|
+ uint16_t out_pl_len;
|
|
|
+
|
|
|
+ query_start = ldq_le_p(&in->pa);
|
|
|
+ /* 64 byte alignemnt required */
|
|
|
+ if (query_start & 0x3f) {
|
|
|
+ return CXL_MBOX_INVALID_INPUT;
|
|
|
+ }
|
|
|
+ query_length = ldq_le_p(&in->length) * CXL_CACHE_LINE_SIZE;
|
|
|
+
|
|
|
+ QLIST_FOREACH(ent, poison_list, node) {
|
|
|
+ /* Check for no overlap */
|
|
|
+ if (ent->start >= query_start + query_length ||
|
|
|
+ ent->start + ent->length <= query_start) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ record_count++;
|
|
|
+ }
|
|
|
+ out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]);
|
|
|
+ assert(out_pl_len <= CXL_MAILBOX_MAX_PAYLOAD_SIZE);
|
|
|
+
|
|
|
+ memset(out, 0, out_pl_len);
|
|
|
+ QLIST_FOREACH(ent, poison_list, node) {
|
|
|
+ uint64_t start, stop;
|
|
|
+
|
|
|
+ /* Check for no overlap */
|
|
|
+ if (ent->start >= query_start + query_length ||
|
|
|
+ ent->start + ent->length <= query_start) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Deal with overlap */
|
|
|
+ start = MAX(ROUND_DOWN(ent->start, 64ull), query_start);
|
|
|
+ stop = MIN(ROUND_DOWN(ent->start, 64ull) + ent->length,
|
|
|
+ query_start + query_length);
|
|
|
+ stq_le_p(&out->records[i].addr, start | (ent->type & 0x7));
|
|
|
+ stl_le_p(&out->records[i].length, (stop - start) / CXL_CACHE_LINE_SIZE);
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ if (ct3d->poison_list_overflowed) {
|
|
|
+ out->flags = (1 << 1);
|
|
|
+ stq_le_p(&out->overflow_timestamp, ct3d->poison_list_overflow_ts);
|
|
|
+ }
|
|
|
+ stw_le_p(&out->count, record_count);
|
|
|
+ *len = out_pl_len;
|
|
|
+ return CXL_MBOX_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+static CXLRetCode cmd_media_inject_poison(struct cxl_cmd *cmd,
|
|
|
+ CXLDeviceState *cxl_dstate,
|
|
|
+ uint16_t *len_unused)
|
|
|
+{
|
|
|
+ CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate);
|
|
|
+ CXLPoisonList *poison_list = &ct3d->poison_list;
|
|
|
+ CXLPoison *ent;
|
|
|
+ struct inject_poison_pl {
|
|
|
+ uint64_t dpa;
|
|
|
+ };
|
|
|
+ struct inject_poison_pl *in = (void *)cmd->payload;
|
|
|
+ uint64_t dpa = ldq_le_p(&in->dpa);
|
|
|
+ CXLPoison *p;
|
|
|
+
|
|
|
+ QLIST_FOREACH(ent, poison_list, node) {
|
|
|
+ if (dpa >= ent->start &&
|
|
|
+ dpa + CXL_CACHE_LINE_SIZE <= ent->start + ent->length) {
|
|
|
+ return CXL_MBOX_SUCCESS;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ct3d->poison_list_cnt == CXL_POISON_LIST_LIMIT) {
|
|
|
+ return CXL_MBOX_INJECT_POISON_LIMIT;
|
|
|
+ }
|
|
|
+ p = g_new0(CXLPoison, 1);
|
|
|
+
|
|
|
+ p->length = CXL_CACHE_LINE_SIZE;
|
|
|
+ p->start = dpa;
|
|
|
+ p->type = CXL_POISON_TYPE_INJECTED;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Possible todo: Merge with existing entry if next to it and if same type
|
|
|
+ */
|
|
|
+ QLIST_INSERT_HEAD(poison_list, p, node);
|
|
|
+ ct3d->poison_list_cnt++;
|
|
|
+
|
|
|
+ return CXL_MBOX_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+static CXLRetCode cmd_media_clear_poison(struct cxl_cmd *cmd,
|
|
|
+ CXLDeviceState *cxl_dstate,
|
|
|
+ uint16_t *len_unused)
|
|
|
+{
|
|
|
+ CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate);
|
|
|
+ CXLPoisonList *poison_list = &ct3d->poison_list;
|
|
|
+ CXLType3Class *cvc = CXL_TYPE3_GET_CLASS(ct3d);
|
|
|
+ struct clear_poison_pl {
|
|
|
+ uint64_t dpa;
|
|
|
+ uint8_t data[64];
|
|
|
+ };
|
|
|
+ CXLPoison *ent;
|
|
|
+ uint64_t dpa;
|
|
|
+
|
|
|
+ struct clear_poison_pl *in = (void *)cmd->payload;
|
|
|
+
|
|
|
+ dpa = ldq_le_p(&in->dpa);
|
|
|
+ if (dpa + CXL_CACHE_LINE_SIZE > cxl_dstate->mem_size) {
|
|
|
+ return CXL_MBOX_INVALID_PA;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Clearing a region with no poison is not an error so always do so */
|
|
|
+ if (cvc->set_cacheline) {
|
|
|
+ if (!cvc->set_cacheline(ct3d, dpa, in->data)) {
|
|
|
+ return CXL_MBOX_INTERNAL_ERROR;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ QLIST_FOREACH(ent, poison_list, node) {
|
|
|
+ /*
|
|
|
+ * Test for contained in entry. Simpler than general case
|
|
|
+ * as clearing 64 bytes and entries 64 byte aligned
|
|
|
+ */
|
|
|
+ if ((dpa >= ent->start) && (dpa < ent->start + ent->length)) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!ent) {
|
|
|
+ return CXL_MBOX_SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ QLIST_REMOVE(ent, node);
|
|
|
+ ct3d->poison_list_cnt--;
|
|
|
+
|
|
|
+ if (dpa > ent->start) {
|
|
|
+ CXLPoison *frag;
|
|
|
+ /* Cannot overflow as replacing existing entry */
|
|
|
+
|
|
|
+ frag = g_new0(CXLPoison, 1);
|
|
|
+
|
|
|
+ frag->start = ent->start;
|
|
|
+ frag->length = dpa - ent->start;
|
|
|
+ frag->type = ent->type;
|
|
|
+
|
|
|
+ QLIST_INSERT_HEAD(poison_list, frag, node);
|
|
|
+ ct3d->poison_list_cnt++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dpa + CXL_CACHE_LINE_SIZE < ent->start + ent->length) {
|
|
|
+ CXLPoison *frag;
|
|
|
+
|
|
|
+ if (ct3d->poison_list_cnt == CXL_POISON_LIST_LIMIT) {
|
|
|
+ cxl_set_poison_list_overflowed(ct3d);
|
|
|
+ } else {
|
|
|
+ frag = g_new0(CXLPoison, 1);
|
|
|
+
|
|
|
+ frag->start = dpa + CXL_CACHE_LINE_SIZE;
|
|
|
+ frag->length = ent->start + ent->length - frag->start;
|
|
|
+ frag->type = ent->type;
|
|
|
+ QLIST_INSERT_HEAD(poison_list, frag, node);
|
|
|
+ ct3d->poison_list_cnt++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* Any fragments have been added, free original entry */
|
|
|
+ g_free(ent);
|
|
|
+
|
|
|
+ return CXL_MBOX_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
#define IMMEDIATE_CONFIG_CHANGE (1 << 1)
|
|
|
#define IMMEDIATE_DATA_CHANGE (1 << 2)
|
|
|
#define IMMEDIATE_POLICY_CHANGE (1 << 3)
|
|
@@ -395,9 +674,10 @@ static struct cxl_cmd cxl_cmd_set[256][256] = {
|
|
|
[EVENTS][CLEAR_RECORDS] = { "EVENTS_CLEAR_RECORDS",
|
|
|
cmd_events_clear_records, ~0, IMMEDIATE_LOG_CHANGE },
|
|
|
[EVENTS][GET_INTERRUPT_POLICY] = { "EVENTS_GET_INTERRUPT_POLICY",
|
|
|
- cmd_events_get_interrupt_policy, 0, 0 },
|
|
|
+ cmd_events_get_interrupt_policy, 0, 0 },
|
|
|
[EVENTS][SET_INTERRUPT_POLICY] = { "EVENTS_SET_INTERRUPT_POLICY",
|
|
|
- cmd_events_set_interrupt_policy, 4, IMMEDIATE_CONFIG_CHANGE },
|
|
|
+ cmd_events_set_interrupt_policy,
|
|
|
+ ~0, IMMEDIATE_CONFIG_CHANGE },
|
|
|
[FIRMWARE_UPDATE][GET_INFO] = { "FIRMWARE_UPDATE_GET_INFO",
|
|
|
cmd_firmware_update_get_info, 0, 0 },
|
|
|
[TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 },
|
|
@@ -411,6 +691,12 @@ static struct cxl_cmd cxl_cmd_set[256][256] = {
|
|
|
[CCLS][GET_LSA] = { "CCLS_GET_LSA", cmd_ccls_get_lsa, 8, 0 },
|
|
|
[CCLS][SET_LSA] = { "CCLS_SET_LSA", cmd_ccls_set_lsa,
|
|
|
~0, IMMEDIATE_CONFIG_CHANGE | IMMEDIATE_DATA_CHANGE },
|
|
|
+ [MEDIA_AND_POISON][GET_POISON_LIST] = { "MEDIA_AND_POISON_GET_POISON_LIST",
|
|
|
+ cmd_media_get_poison_list, 16, 0 },
|
|
|
+ [MEDIA_AND_POISON][INJECT_POISON] = { "MEDIA_AND_POISON_INJECT_POISON",
|
|
|
+ cmd_media_inject_poison, 8, 0 },
|
|
|
+ [MEDIA_AND_POISON][CLEAR_POISON] = { "MEDIA_AND_POISON_CLEAR_POISON",
|
|
|
+ cmd_media_clear_poison, 72, 0 },
|
|
|
};
|
|
|
|
|
|
void cxl_process_mailbox(CXLDeviceState *cxl_dstate)
|