@@ -84,6 +84,8 @@ enum {
#define GET_PHYSICAL_PORT_STATE 0x1
TUNNEL = 0x53,
#define MANAGEMENT_COMMAND 0x0
+ MHD = 0x55,
+ #define GET_MHD_INFO 0x0
};
/* CCI Message Format CXL r3.0 Figure 7-19 */
@@ -1155,6 +1157,56 @@ static CXLRetCode cmd_media_clear_poison(const struct cxl_cmd *cmd,
return CXL_MBOX_SUCCESS;
}
+static CXLRetCode cmd_mhd_get_info(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ struct {
+ uint8_t start_ld;
+ uint8_t ldmap_len;
+ } QEMU_PACKED *input = (void *)payload_in;
+
+ struct {
+ uint8_t nr_lds;
+ uint8_t nr_heads;
+ uint16_t resv1;
+ uint8_t start_ld;
+ uint8_t ldmap_len;
+ uint16_t resv2;
+ uint8_t ldmap[];
+ } QEMU_PACKED *output = (void *)payload_out;
+
+ uint8_t start_ld = input->start_ld;
+ uint8_t ldmap_len = input->ldmap_len;
+ uint8_t i;
+
+ if (!ct3d->is_mhd) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
+ if (start_ld >= ct3d->mhd_state->nr_lds) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ output->nr_lds = ct3d->mhd_state->nr_lds;
+ output->nr_heads = ct3d->mhd_state->nr_heads;
+ output->resv1 = 0;
+ output->start_ld = start_ld;
+ output->resv2 = 0;
+
+ for (i = 0; i < ldmap_len && (start_ld + i) < output->nr_lds; i++) {
+ output->ldmap[i] = ct3d->mhd_state->ldmap[start_ld + i];
+ }
+ output->ldmap_len = i;
+
+ *len_out = sizeof(*output) + output->ldmap_len;
+ return CXL_MBOX_SUCCESS;
+}
+
#define IMMEDIATE_CONFIG_CHANGE (1 << 1)
#define IMMEDIATE_DATA_CHANGE (1 << 2)
#define IMMEDIATE_POLICY_CHANGE (1 << 3)
@@ -1195,6 +1247,7 @@ static const struct cxl_cmd cxl_cmd_set[256][256] = {
cmd_media_inject_poison, 8, 0 },
[MEDIA_AND_POISON][CLEAR_POISON] = { "MEDIA_AND_POISON_CLEAR_POISON",
cmd_media_clear_poison, 72, 0 },
+ [MHD][GET_MHD_INFO] = {"GET_MULTI_HEADED_INFO", cmd_mhd_get_info, 2, 0},
};
static const struct cxl_cmd cxl_cmd_set_sw[256][256] = {
@@ -18,6 +18,7 @@
#include "hw/cxl/cxl.h"
#include "hw/pci/msix.h"
#include "hw/pci/spdm.h"
+#include <sys/shm.h>
#define DWORD_BYTE 4
@@ -794,6 +795,45 @@ static DOEProtocol doe_spdm_prot[] = {
{ }
};
+static bool cxl_setup_mhd(CXLType3Dev *ct3d, Error **errp)
+{
+ if (ct3d->is_mhd && (!ct3d->mhd_shmid || (ct3d->mhd_head == ~(0)))) {
+ error_setg(errp, "is_mhd requires a shared memory region (mhd_shmid) and mhd_head < 32");
+ return false;
+ } else if (!ct3d->is_mhd && (ct3d->mhd_shmid || (ct3d->mhd_head == ~(0)))) {
+ error_setg(errp, "(is_mhd,mhd_head,mhd_shmid) fields must be used together");
+ return false;
+ } else if (!ct3d->is_mhd) {
+ return true;
+ }
+
+ if (ct3d->mhd_head >= 32) {
+ error_setg(errp, "MHD Head ID must be between 0-31");
+ return false;
+ }
+
+ ct3d->mhd_state = shmat(ct3d->mhd_shmid, NULL, 0);
+ if (ct3d->mhd_state == (void*)-1) {
+ ct3d->mhd_state = NULL;
+ error_setg(errp, "Unable to attach MHD State. Check ipcs is valid");
+ return false;
+ }
+
+ /* For now, limit the number of heads to the number of LD's (SLD) */
+ if (ct3d->mhd_state->nr_heads <= ct3d->mhd_head) {
+ error_setg(errp, "Invalid head ID for multiheaded device.");
+ return false;
+ }
+
+ if (ct3d->mhd_state->nr_lds <= ct3d->mhd_head) {
+ error_setg(errp, "MHD Shared state does not have sufficient lds.");
+ return false;
+ }
+
+ ct3d->mhd_state->ldmap[ct3d->mhd_head] = ct3d->mhd_head;
+ return true;
+}
+
static void ct3_realize(PCIDevice *pci_dev, Error **errp)
{
CXLType3Dev *ct3d = CXL_TYPE3(pci_dev);
@@ -806,6 +846,10 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
QTAILQ_INIT(&ct3d->error_list);
+ if (!cxl_setup_mhd(ct3d, errp)) {
+ return;
+ }
+
if (!cxl_setup_memory(ct3d, errp)) {
return;
}
@@ -910,6 +954,9 @@ static void ct3_exit(PCIDevice *pci_dev)
if (ct3d->hostvmem) {
address_space_destroy(&ct3d->hostvmem_as);
}
+ if (ct3d->mhd_state) {
+ shmdt(ct3d->mhd_state);
+ }
}
static bool cxl_type3_dpa(CXLType3Dev *ct3d, hwaddr host_addr, uint64_t *dpa)
@@ -1067,6 +1114,9 @@ static Property ct3_props[] = {
DEFINE_PROP_UINT64("sn", CXLType3Dev, sn, UI64_NULL),
DEFINE_PROP_STRING("cdat", CXLType3Dev, cxl_cstate.cdat.filename),
DEFINE_PROP_UINT16("spdm", CXLType3Dev, spdm_port, 0),
+ DEFINE_PROP_BOOL("is_mhd", CXLType3Dev, is_mhd, false),
+ DEFINE_PROP_UINT32("mhd_head", CXLType3Dev, mhd_head, 0),
+ DEFINE_PROP_UINT32("mhd_shmid", CXLType3Dev, mhd_shmid, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -406,6 +406,12 @@ typedef struct CXLPoison {
typedef QLIST_HEAD(, CXLPoison) CXLPoisonList;
#define CXL_POISON_LIST_LIMIT 256
+struct CXLMHD_SharedState {
+ uint8_t nr_heads;
+ uint8_t nr_lds;
+ uint8_t ldmap[];
+};
+
struct CXLType3Dev {
/* Private */
PCIDevice parent_obj;
@@ -440,6 +446,12 @@ struct CXLType3Dev {
unsigned int poison_list_cnt;
bool poison_list_overflowed;
uint64_t poison_list_overflow_ts;
+
+ /* Multi-headed Device */
+ bool is_mhd;
+ uint32_t mhd_head;
+ uint32_t mhd_shmid;
+ struct CXLMHD_SharedState *mhd_state;
};
#define TYPE_CXL_TYPE3 "cxl-type3"
new file mode 100644
@@ -0,0 +1,63 @@
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+struct mhd_state {
+ uint8_t nr_heads;
+ uint8_t nr_lds;
+ uint8_t ldmap[];
+};
+
+int main(int argc, char *argv[]) {
+ int shmid = 0;
+ uint32_t heads = 0;
+ struct mhd_state* mhd_state = 0;
+ uint8_t i;
+
+ if (argc != 3) {
+ printf("usage: cxl_mhd_init <heads> <shmid>\n"
+ "\theads : number of heads on the device\n"
+ "\tshmid : /tmp/mytoken.tmp\n");
+ return -1;
+ }
+
+ // must have at least 1 head
+ heads = (uint32_t)atoi(argv[1]);
+ if (heads == 0 || heads > 32) {
+ printf("bad heads argument (1-32)\n");
+ return -1;
+ }
+
+ shmid = (uint32_t)atoi(argv[2]);
+ if (shmid== 0) {
+ printf("bad shmid argument\n");
+ return -1;
+ }
+
+ mhd_state = shmat(shmid, NULL, 0);
+ if (mhd_state == (void*)-1) {
+ printf("Unable to attach to shared memory\n");
+ return -1;
+ }
+
+ // Initialize the mhd_state
+ size_t mhd_state_size = sizeof(struct mhd_state) + (sizeof(uint8_t) * heads);
+ memset(mhd_state, 0, mhd_state_size);
+ mhd_state->nr_heads = heads;
+ mhd_state->nr_lds = heads;
+
+ // Head ID == LD ID for now
+ for (i = 0; i < heads; i++)
+ mhd_state->ldmap[i] = i;
+
+ printf("mhd initialized\n");
+ shmdt(mhd_state);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,3 @@
+executable('cxl_mhd_init', files('cxl_mhd_init.c'),
+ install: true,
+ install_dir: get_option('libexecdir'))
@@ -0,0 +1 @@
+subdir('cxl')