From 2b76db29c9b71b755e63b02e0e0987e3dc4a625d Mon Sep 17 00:00:00 2001 From: Grant Mackey Date: Mon, 22 Apr 2024 19:13:19 -0700 Subject: [PATCH] qemu support code added --- Makefile | 2 +- fmapi_isc_handler.c | 12 +- fmapi_psc_handler.c | 131 +++++++++++++++++++-- fmapi_vsc_handler.c | 34 ++++++ main.c | 6 +- options.c | 22 +++- options.h | 1 + state.c | 280 ++++++++++++++++++++++++++++++++++++++++++-- 8 files changed, 456 insertions(+), 32 deletions(-) diff --git a/Makefile b/Makefile index 92f5ec6..9595385 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ TARGET=cse all: $(TARGET) -$(TARGET): main.c options.o state.o signals.o emapi_handler.o fmapi_handler.o fmapi_isc_handler.o fmapi_psc_handler.o fmapi_vsc_handler.o fmapi_mpc_handler.o fmapi_mcc_handler.o +$(TARGET): main.c options.o state.o signals.o emapi_handler.o fmapi_handler.o fmapi_isc_handler.o fmapi_psc_handler.o fmapi_vsc_handler.o fmapi_mpc_handler.o fmapi_mcc_handler.o $(CC) $^ $(CFLAGS) $(MACROS) $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) -o $@ emapi_handler.o: emapi_handler.c emapi_handler.h diff --git a/fmapi_isc_handler.c b/fmapi_isc_handler.c index 7adee48..7776257 100644 --- a/fmapi_isc_handler.c +++ b/fmapi_isc_handler.c @@ -276,12 +276,12 @@ int fmop_isc_id(struct mctp *m, struct mctp_action *ma) STEP // 10: Perform Action STEP // 11: Prepare Response Object - rsp.obj.isc_id_rsp.vid = cxls->vid; - rsp.obj.isc_id_rsp.did = cxls->did; - rsp.obj.isc_id_rsp.svid = cxls->svid; - rsp.obj.isc_id_rsp.ssid = cxls->ssid; - rsp.obj.isc_id_rsp.sn = cxls->sn; - rsp.obj.isc_id_rsp.size = cxls->max_msg_size_n; + rsp.obj.isc_id_rsp.vid = cxls->vid; + rsp.obj.isc_id_rsp.did = cxls->did; + rsp.obj.isc_id_rsp.svid = cxls->svid; + rsp.obj.isc_id_rsp.ssid = cxls->ssid; + rsp.obj.isc_id_rsp.sn = cxls->sn; + rsp.obj.isc_id_rsp.size = cxls->max_msg_size_n; STEP // 12: Serialize Response Object len = fmapi_serialize(rsp.buf->payload, &rsp.obj, fmapi_fmob_rsp(req.hdr.opcode)); diff --git a/fmapi_psc_handler.c b/fmapi_psc_handler.c index 7b67eda..599e218 100644 --- a/fmapi_psc_handler.c +++ b/fmapi_psc_handler.c @@ -26,12 +26,18 @@ */ #include +#include + /* struct timespec * timespec_get() * */ #include +/* system() + */ +#include + /* autl_prnt_buf() */ #include @@ -190,10 +196,54 @@ int fmop_psc_cfg(struct mctp *m, struct mctp_action *ma) rsp.obj.psc_cfg_rsp.data[2] = 0; rsp.obj.psc_cfg_rsp.data[3] = 0; - if (req.obj.psc_cfg_req.fdbe & 0x01) rsp.obj.psc_cfg_rsp.data[0] = p->cfgspace[reg+0]; - if (req.obj.psc_cfg_req.fdbe & 0x02) rsp.obj.psc_cfg_rsp.data[1] = p->cfgspace[reg+1]; - if (req.obj.psc_cfg_req.fdbe & 0x04) rsp.obj.psc_cfg_rsp.data[2] = p->cfgspace[reg+2]; - if (req.obj.psc_cfg_req.fdbe & 0x08) rsp.obj.psc_cfg_rsp.data[3] = p->cfgspace[reg+3]; + if (opts[CLOP_QEMU].set == 1) + { + switch(req.obj.psc_cfg_req.fdbe) + { + case 0x01: + { + __u8 b = pci_read_byte(p->dev, reg); + + rsp.obj.psc_cfg_rsp.data[0] = b; + } break; + + case 0x03: + { + // Verify word aligned + if ((reg & 0x1) != 0) + goto send; + + __u16 w = pci_read_word(p->dev, reg); + + rsp.obj.psc_cfg_rsp.data[0] = ( w ) & 0x00FF; + rsp.obj.psc_cfg_rsp.data[1] = ( w >> 8 ) & 0x00FF; + } break; + + case 0x0F: + { + // Verify long aligned + if ((reg & 0x3) != 0) + goto send; + + __u32 l = pci_read_long(p->dev, reg); + + rsp.obj.psc_cfg_rsp.data[0] = ( l ) & 0x00FF; + rsp.obj.psc_cfg_rsp.data[1] = ( l >> 8 ) & 0x00FF; + rsp.obj.psc_cfg_rsp.data[2] = ( l >> 16) & 0x00FF; + rsp.obj.psc_cfg_rsp.data[3] = ( l >> 24) & 0x00FF; + } break; + + default: + goto send; + } + } + else + { + if (req.obj.psc_cfg_req.fdbe & 0x01) rsp.obj.psc_cfg_rsp.data[0] = p->cfgspace[reg+0]; + if (req.obj.psc_cfg_req.fdbe & 0x02) rsp.obj.psc_cfg_rsp.data[1] = p->cfgspace[reg+1]; + if (req.obj.psc_cfg_req.fdbe & 0x04) rsp.obj.psc_cfg_rsp.data[2] = p->cfgspace[reg+2]; + if (req.obj.psc_cfg_req.fdbe & 0x08) rsp.obj.psc_cfg_rsp.data[3] = p->cfgspace[reg+3]; + } } break; @@ -204,10 +254,52 @@ int fmop_psc_cfg(struct mctp *m, struct mctp_action *ma) reg = (req.obj.psc_cfg_req.ext << 8) | req.obj.psc_cfg_req.reg; - if (req.obj.psc_cfg_req.fdbe & 0x01) p->cfgspace[reg+0] = req.obj.psc_cfg_req.data[0]; - if (req.obj.psc_cfg_req.fdbe & 0x02) p->cfgspace[reg+1] = req.obj.psc_cfg_req.data[1]; - if (req.obj.psc_cfg_req.fdbe & 0x04) p->cfgspace[reg+2] = req.obj.psc_cfg_req.data[2]; - if (req.obj.psc_cfg_req.fdbe & 0x08) p->cfgspace[reg+3] = req.obj.psc_cfg_req.data[3]; + if (opts[CLOP_QEMU].set == 1) + { + switch(req.obj.psc_cfg_req.fdbe) + { + case 0x01: + { + pci_write_byte(p->dev, reg, req.obj.psc_cfg_req.data[0]); + } break; + + case 0x03: + { + // Verify word aligned + if ((reg & 0x1) != 0) + goto send; + + __u16 w = (req.obj.psc_cfg_req.data[1] << 8) + | req.obj.psc_cfg_req.data[0]; + + pci_write_word(p->dev, reg, w); + } break; + + case 0x0F: + { + // Verify long aligned + if ((reg & 0x3) != 0) + goto send; + + __u32 l = (req.obj.psc_cfg_req.data[3] << 24) + |(req.obj.psc_cfg_req.data[2] << 16) + |(req.obj.psc_cfg_req.data[1] << 8) + |(req.obj.psc_cfg_req.data[0] ); + + pci_write_long(p->dev, reg, l); + } break; + + default: + goto send; + } + } + else + { + if (req.obj.psc_cfg_req.fdbe & 0x01) p->cfgspace[reg+0] = req.obj.psc_cfg_req.data[0]; + if (req.obj.psc_cfg_req.fdbe & 0x02) p->cfgspace[reg+1] = req.obj.psc_cfg_req.data[1]; + if (req.obj.psc_cfg_req.fdbe & 0x04) p->cfgspace[reg+2] = req.obj.psc_cfg_req.data[2]; + if (req.obj.psc_cfg_req.fdbe & 0x08) p->cfgspace[reg+3] = req.obj.psc_cfg_req.data[3]; + } } break; } @@ -349,7 +441,7 @@ int fmop_psc_id(struct mctp *m, struct mctp_action *ma) } for ( int i = 0 ; i < cs->num_vcss ; i++ ) { - for ( int j = 0 ; j < MAX_VPPBS_PER_VCS ; j++ ) { + for ( int j = 0 ; j < cs->vcss[i].num ; j++ ) { if ( cs->vcss[i].vppbs[j].bind_status != FMBS_UNBOUND ) fi->active_vppbs++; } @@ -623,16 +715,33 @@ int fmop_psc_port_ctrl(struct mctp *m, struct mctp_action *ma) switch (req.obj.psc_port_ctrl_req.opcode) { case FMPO_ASSERT_PERST: // 0x00 + { + char cmd[64]; + sprintf(cmd, "echo 0 > /sys/bus/pci/slots/%d/power", p->ppid); + IFV(CLVB_ACTIONS) printf("%s ACT: Asserting PERST on PPID: %d\n", now, req.obj.psc_port_ctrl_req.ppid); + + // Disable the device + if ( opts[CLOP_QEMU].set == 1 ) + rv = system(cmd); + // Set PERST bit p->perst = 0x1; - break; + } break; case FMPO_DEASSERT_PERST: // 0x01 + { + char cmd[64]; + sprintf(cmd, "echo 1 > /sys/bus/pci/slots/%d/power", p->ppid); + IFV(CLVB_ACTIONS) printf("%s ACT: Deasserting PERST on PPID: %d\n", now, req.obj.psc_port_ctrl_req.ppid); + // Enable the device + if ( opts[CLOP_QEMU].set == 1 ) + rv = system(cmd); + p->perst = 0x0; - break; + } break; case FMPO_RESET_PPB: // 0x02 IFV(CLVB_ACTIONS) printf("%s ACT: Resetting PPID: %d\n", now, req.obj.psc_port_ctrl_req.ppid); diff --git a/fmapi_vsc_handler.c b/fmapi_vsc_handler.c index bd6571d..6d8ba86 100644 --- a/fmapi_vsc_handler.c +++ b/fmapi_vsc_handler.c @@ -22,6 +22,9 @@ */ #include +/* system() + */ +#include /* memset() */ #include @@ -351,6 +354,21 @@ int fmop_vsc_bind(struct mctp *m, struct mctp_action *ma) goto send; } + // Check if this physical port is already bound to a vppb + for ( int i = 0 ; i < cxls->num_vcss ; i++ ) + { + struct cxl_vcs *vcs = &cxls->vcss[i]; + for ( int k = 0 ; k < vcs->num ; k++ ) + { + struct cxl_vppb *vppb = &vcs->vppbs[k]; + if ( vppb->ppid == p->ppid ) + { + IFV(CLVB_ERRORS) printf("%s ERR: Specified PPID is already bound. PPBID: %d\n", now, req.obj.vsc_bind_req.ppid); + goto send; + } + } + } + STEP // 10: Perform Action IFV(CLVB_ACTIONS) printf("%s ACT: Binding VCSID: %d vPPBID: %d PPID: %d LDID: 0x%04x\n", now, req.obj.vsc_bind_req.vcsid, req.obj.vsc_bind_req.vppbid, req.obj.vsc_bind_req.ppid, req.obj.vsc_bind_req.ldid); @@ -378,6 +396,14 @@ int fmop_vsc_bind(struct mctp *m, struct mctp_action *ma) cxls->bos_rc = FMRC_SUCCESS; cxls->bos_ext = 0; + // If QEMU, enable power to physical device + if ( opts[CLOP_QEMU].set == 1 ) + { + char cmd[64]; + sprintf(cmd, "echo 1 > /sys/bus/pci/slots/%d/power", p->ppid); + rv = system(cmd); + } + STEP // 11: Prepare Response Object STEP // 12: Serialize Response Object @@ -704,6 +730,14 @@ int fmop_vsc_unbind(struct mctp *m, struct mctp_action *ma) cxls->bos_rc = FMRC_SUCCESS; cxls->bos_ext = 0; + // If QEMU, disable power to physical device + if ( opts[CLOP_QEMU].set == 1 ) + { + char cmd[64]; + sprintf(cmd, "echo 0 > /sys/bus/pci/slots/%d/power", p->ppid); + rv = system(cmd); + } + STEP // 11: Prepare Response Object STEP // 12: Serialize Response Object diff --git a/main.c b/main.c index 9d826d6..22787f0 100644 --- a/main.c +++ b/main.c @@ -67,13 +67,15 @@ #define IFV(u) if (opts[CLOP_VERBOSITY].u64 & u) #define CSLN_PORTS 32 -#define CSLN_VCSS 32 +#define CSLN_VCSS 16 #define CSLN_VPPBS 256 /* ENUMERATIONS ==============================================================*/ /* STRUCTS ===================================================================*/ +struct devices * qemu_devices; + /* PROTOTYPES ================================================================*/ /* GLOBAL VARIABLES ==========================================================*/ @@ -136,8 +138,6 @@ int main(int argc, char* argv[]) } } -// STEP // 4: Build PCI Representation - STEP // 5: Print the state if (opts[CLOP_PRINT_STATE].set) cxls_prnt(cxls); diff --git a/options.c b/options.c index 523dd05..7fd303d 100644 --- a/options.c +++ b/options.c @@ -73,7 +73,9 @@ char *STR_CLOP[] = { "PRINT_STATE", "PRINT_OPTIONS", "CONFIG_FILE", - "TCP_PORT" + "TCP_PORT", + "TCP_ADDRESS", + "QEMU" }; /** @@ -97,7 +99,7 @@ struct opt *opts = NULL; /** * Global string used by argp to print version with --version */ -const char *argp_program_version = "version 0.1"; +const char *argp_program_version = "version 0.2"; /** * Global string used by argp when printing the help message @@ -116,6 +118,8 @@ struct argp_option ao_main[] = { {0,0,0,0, "File Options",1}, {"config", 'c', "FILE", 0, "File name of CXL switch config file", 0}, + {"qemu-sim", 'q', NULL, OPTION_HIDDEN, "Enable control qemu devices, cse must be run as root", 0} + , {0,0,0,0, "Networking Options",2}, {"tcp-port", 'P', "INT", 0, "Server TCP Port", 0}, {"tcp-address", 'T', "INT", 0, "Server TCP Address", 0} @@ -193,6 +197,20 @@ static int pr_main ( o->str = strndup(arg, CLMR_MAX_ARG_STR_LEN); break; + // qemu-sim + case 'q': + if(!getuid()) + { + o = &opts[CLOP_QEMU]; + o->set = 1; + } + else + { + printf("-q option must be run as root \n"); + exit(0); + }; + break; + // help case 'h': print_help(); diff --git a/options.h b/options.h index a5e1af1..5911961 100644 --- a/options.h +++ b/options.h @@ -89,6 +89,7 @@ enum _CLOP CLOP_CONFIG_FILE, //!< File to load CXL Switch configuration data CLOP_TCP_PORT, //!< TCP Port to listen on for connections CLOP_TCP_ADDRESS, //!< TCP Address to listen on for connections + CLOP_QEMU, //!< qemu switches, no emulation (for now) CLOP_MAX }; diff --git a/state.c b/state.c index d42a806..d27ee5c 100644 --- a/state.c +++ b/state.c @@ -39,6 +39,8 @@ cxl_ * */ #include +#include + /** GHashTable * g_hash_table_foreach() / */ @@ -96,6 +98,7 @@ int state_load_emulator(struct cxl_switch *state, GHashTable *ht); int state_load_ports(struct cxl_switch *state, GHashTable *ht); int state_load_switch(struct cxl_switch *state, GHashTable *ht); int state_load_vcss(struct cxl_switch *state, GHashTable *ht); +int state_load_from_pci(struct cxl_switch *state); void _parse_devices(gpointer key, gpointer value, gpointer user_data); void _parse_device(gpointer key, gpointer value, gpointer user_data); @@ -137,9 +140,10 @@ struct cxl_switch *cxls; * 3: Parse Emulator configuration * 4: Parse Devices * 5: Parse Switch - * 6: Parse Ports - * 7: Parse VCSs - * 8: Free memory allocated for hash table + * 6: Load physical devices if in a QEMU environment + * 7: Parse Ports + * 8: Parse VCSs + * 9: Free memory allocated for hash table */ int state_load(struct cxl_switch *state, char *filename) { @@ -183,18 +187,30 @@ int state_load(struct cxl_switch *state, char *filename) rv = state_load_switch(state, ht); if (rv != 0) goto end; + + STEP // 6: Load physical devices if in a QEMU environment + if (opts[CLOP_QEMU].set == 1) + { + rv = state_load_from_pci(state); + if (rv != 0) + goto end; - STEP // 6: Parse Ports + goto success; + } + + STEP // 7: Parse Ports rv = state_load_ports(state, ht); if (rv != 0) goto end; - STEP // 7: Parse VCSs + STEP // 8: Parse VCSs rv = state_load_vcss(state, ht); if (rv != 0) goto end; - STEP // 8: Free memory allocated for hash table +success: + + STEP // 9: Free memory allocated for hash table yl_free(ht); rv = 0; @@ -289,6 +305,252 @@ end: return rv; } +/** + * Load ports and vcs from physical pci devices + * + * @param ht GHashTable holding contents of config.yaml file + * @return Returns 0 upon success. Non zero otherwise + * + * STEPS + */ +int state_load_from_pci(struct cxl_switch *state) +{ + INIT + + int rv, cache, mem; + unsigned int num_dvsec, nr; + __u32 l, type, vppbid; + __u16 w; + struct pci_dev *dev, *parent; + struct pci_cap *cap; + struct cxl_port cp; + __u32 fillflags; + + ENTER + + // Initialize variables + rv = 1; + fillflags = PCI_FILL_IDENT + |PCI_FILL_CLASS + |PCI_FILL_CAPS + |PCI_FILL_EXT_CAPS + |PCI_FILL_PHYS_SLOT + |PCI_FILL_MODULE_ALIAS + |PCI_FILL_LABEL + |PCI_FILL_NUMA_NODE + |PCI_FILL_IO_FLAGS + |PCI_FILL_CLASS_EXT + |PCI_FILL_SUBSYS + |PCI_FILL_PARENT + |PCI_FILL_DRIVER; + + STEP // : get pci_access ptr, init pci_access ptr, get all the devices + state->pacc = pci_alloc(); + pci_init(state->pacc); + pci_scan_bus(state->pacc); + + // STEP 3: Iiterate over all devices + for ( dev = state->pacc->devices ; dev ; dev = dev->next ) + { + pci_fill_info(dev, PCI_FILL_CLASS); + + // If this is a PCI-to-PCI Bridge then check if it is a CXL upstream port + if ( (dev->device_class >> 8) == 0x06 && (dev->device_class & 0x0FF) == 0x04 ) + { + // Get more info about this device + pci_fill_info(dev, fillflags); + + // Get PCI Express Capability + cap = pci_find_cap(dev, PCI_CAP_ID_EXP, PCI_CAP_NORMAL); + if (cap == NULL) + continue; + + // Determine port type + w = pci_read_word(dev, cap->addr + PCI_EXP_FLAGS); + type = (w & PCI_EXP_FLAGS_TYPE) >> 4; + if (type != PCI_EXP_TYPE_UPSTREAM) + continue; + + // Clear the local CXL Port before filling it + memset(&cp, 0, sizeof(cp)); + + // Get max speed / width / vppbid + l = pci_read_long(dev, cap->addr + PCI_EXP_LNKCAP); + cp.mls = l & PCI_EXP_LNKCAP_SPEED; + cp.mlw = (l & PCI_EXP_LNKCAP_WIDTH) >> 4; + vppbid = l >> 24; + + // Get cur speed / width + w = pci_read_word(dev, cap->addr + PCI_EXP_LNKSTA); + cp.cls = w & PCI_EXP_LNKSTA_SPEED; + cp.nlw = (w & PCI_EXP_LNKSTA_WIDTH) >> 4; + + // If parent is NULL, then skip this device as we know nothing about it + parent = dev->parent; + if (parent == NULL) + continue; + + // Get all info about the parent device + pci_fill_info(parent, fillflags); + + // Get PCI Express Capability + cap = pci_find_cap(parent, PCI_CAP_ID_EXP, PCI_CAP_NORMAL); + if (cap == NULL) + continue; + + // Get physical port id from Slot Number in PCI Express capability + l = pci_read_long(parent, cap->addr + PCI_EXP_SLTCAP); + cp.ppid = ((l & PCI_EXP_SLTCAP_PSN) >> 19); + + // Set switch IDs based on the upstream port identifiers + state->vid = dev->vendor_id; + state->did = dev->device_id; + state->ssid = dev->subsys_id; + state->svid = dev->subsys_vendor_id; + state->sn = ((__u64) dev->domain_16 ) << 48 + | ((__u64) dev->device_class ) << 32 + | ((__u64) dev->prog_if ) << 24 + | ((__u64) dev->bus ) << 16 + | ((__u64) dev->dev ) << 8 + | ((__u64) dev->func ) ; + + // Set bind in vcs + state->vcss[0].uspid = cp.ppid; + state->vcss[0].state = FMVS_ENABLED; + state->vcss[0].vppbs[vppbid].ppid = cp.ppid; + state->vcss[0].vppbs[vppbid].bind_status = FMBS_BOUND_PORT; + state->vcss[0].vppbs[vppbid].ldid = 0; + + // Fill local struct cxl_port fields + cp.state = FMPS_USP; + cp.dt = FMDT_CXL_TYPE_1; + cp.speeds = cp.mls; + cp.ltssm = FMLS_L0; + cp.lane = 0; + cp.lane_rev = 0; + cp.perst = 0; + cp.prsnt = 1; + cp.pwrctrl = 0; + cp.dev = dev; + cp.dv = FMDV_CXL2_0; + cp.cv = FMCV_CXL1_1 | FMCV_CXL2_0; + + // Copy local struct cxl_port into global state + memcpy(&state->ports[cp.ppid], &cp, sizeof(cp)); + } + + // If this is a CXL device, then gather more info and the parent's info + else if ( (dev->device_class >> 8) == 0x05 && (dev->device_class & 0x0FF) == 0x02 ) + { + // Get more info about this device + pci_fill_info(dev, fillflags); + + // If parent is NULL, then skip this device as we know nothing about it + parent = dev->parent; + if (parent == NULL) + continue; + + // Get all info about the parent device + pci_fill_info(parent, fillflags); + + // Get PCI Express Capability (Parent) + cap = pci_find_cap(parent, PCI_CAP_ID_EXP, PCI_CAP_NORMAL); + if (cap == NULL) + continue; + + // Determine port type (Parent) + w = pci_read_word(parent, cap->addr + PCI_EXP_FLAGS); + type = (w & PCI_EXP_FLAGS_TYPE) >> 4; + if ( type != PCI_EXP_TYPE_DOWNSTREAM ) + continue; + + // Clear the local CXL Port before filling it + memset(&cp, 0, sizeof(cp)); + + // Get physical port number from SLot number in PCI Express capability (Parent) + l = pci_read_long(parent, cap->addr + PCI_EXP_SLTCAP); + cp.ppid = ((l & PCI_EXP_SLTCAP_PSN) >> 19); + + // Get max speed / width / vppbid (Parent) + l = pci_read_long(parent, cap->addr + PCI_EXP_LNKCAP); + cp.mls = l & PCI_EXP_LNKCAP_SPEED; + cp.mlw = (l & PCI_EXP_LNKCAP_WIDTH) >> 4; + vppbid = l >> 24; + + // Get cur speeds + w = pci_read_word(parent, cap->addr + PCI_EXP_LNKSTA); + cp.cls = w & PCI_EXP_LNKSTA_SPEED; + cp.nlw = (w & PCI_EXP_LNKSTA_WIDTH) >> 4; + + // Get number of DVSEC Capabilities in Dev. Num returned in variable num_dvsec + num_dvsec = 0; + cap = pci_find_cap_nr(dev, PCI_EXT_CAP_ID_DVSEC, PCI_CAP_EXTENDED, &num_dvsec); + + // Loop through DVSEC capabilities + for ( nr = 0 ; nr < num_dvsec ; nr++) + { + // Get DVSEC Capability entry number nr + cap = pci_find_cap_nr(dev, PCI_EXT_CAP_ID_DVSEC, PCI_CAP_EXTENDED, &nr); + + // Get the DVSEC.type + w = pci_read_long(dev, cap->addr + PCI_DVSEC_HEADER2); + + // If DVSEC.type==0, this DVSEC Capability describes device type + if (w == 0) + { + // Get the flags indicating what CXL protocols are supported + w = pci_read_word(dev, cap->addr + PCI_CXL_DEV_CAP); + cache = w & PCI_CXL_DEV_CAP_CACHE; + mem = (w & PCI_CXL_DEV_CAP_MEM) >> 2; + + // Determine Device Type + if (cache == 1 && mem == 0) cp.dt = FMDT_CXL_TYPE_1; + else if (cache == 1 && mem == 1) cp.dt = FMDT_CXL_TYPE_2; + else if (cache == 0 && mem == 1) cp.dt = FMDT_CXL_TYPE_3; + + break; + } + + // If the DVSEC Type is 9 then this is a MLD DVSEC + else if (w == 9) + { + // Set that this is a MLD device + cp.ld = pci_read_word(dev, cap->addr + PCI_CXL_MLD_NUM_LD); + cp.dt = FMDT_CXL_TYPE_3_POOLED; + } + } + + // Set bind in vcs + state->vcss[0].state = FMVS_ENABLED; + state->vcss[0].vppbs[vppbid].ppid = cp.ppid; + state->vcss[0].vppbs[vppbid].bind_status = FMBS_BOUND_PORT; + state->vcss[0].vppbs[vppbid].ldid = 0; + + // Fill local struct cxl_port fields + cp.state = FMPS_DSP; + cp.speeds = cp.mls; + cp.ltssm = FMLS_L0; + cp.lane = 0; + cp.lane_rev = 0; + cp.perst = 0; + cp.prsnt = 1; + cp.pwrctrl = 0; + cp.dev = dev; + cp.dv = FMDV_CXL2_0; + cp.cv = FMCV_CXL1_1 | FMCV_CXL2_0; + + // Copy local struct cxl_port into global state + memcpy(&state->ports[cp.ppid], &cp, sizeof(cp)); + } + } + + rv = 0; + + return rv; +} + + + /** * Load port definitions from hash table into memory * @@ -960,13 +1222,13 @@ void _parse_switch(gpointer key, gpointer value, gpointer user_data) else if (!strcmp(key, "bos_ext")) s->bos_ext = strtoul(ylo->str, NULL,0); else if (!strcmp(key, "msg_rsp_limit_n")) s->msg_rsp_limit_n = atoi(ylo->str); else if (!strcmp(key, "ingress_port")) s->ingress_port = atoi(ylo->str); - else if (!strcmp(key, "num_ports")) s->num_ports = atoi(ylo->str); - else if (!strcmp(key, "num_vcss")) s->num_vcss = atoi(ylo->str); - else if (!strcmp(key, "num_vppbs")) s->num_vppbs = atoi(ylo->str); else if (!strcmp(key, "num_decoders")) s->num_decoders = atoi(ylo->str); else if (!strcmp(key, "mlw")) s->mlw = atoi(ylo->str); else if (!strcmp(key, "speeds")) s->speeds = strtoul(ylo->str, NULL, 0); else if (!strcmp(key, "mls")) s->mls = atoi(ylo->str); + else if (!strcmp(key, "num_ports")) cxls_init_ports(s, atoi(ylo->str)); + else if (!strcmp(key, "num_vcss")) cxls_init_vcss(s, atoi(ylo->str), s->num_vppbs); + else if (!strcmp(key, "num_vppbs")) cxls_init_vcss(s, s->num_vcss, atoi(ylo->str)); rv = 0;