diff --git a/cligen/gen/base.cxl.c b/cligen/gen/base.cxl.c index ee2d6b0..2ef95d1 100644 --- a/cligen/gen/base.cxl.c +++ b/cligen/gen/base.cxl.c @@ -69,7 +69,7 @@ static struct cmd_struct commands[] = { { "write-labels", .c_fn = cmd_write_labels }, { "id-cmd", .c_fn = cmd_identify }, { "get-supported-logs", .c_fn = cmd_get_supported_logs }, - { "get-cel-log", .c_fn = cmd_get_cel_log }, + { "get-log", .c_fn = cmd_get_log }, { "get-event-interrupt-policy", .c_fn = cmd_get_event_interrupt_policy }, { "set-event-interrupt-policy", .c_fn = cmd_set_event_interrupt_policy }, { "get-timestamp", .c_fn = cmd_get_timestamp }, diff --git a/cligen/gen/base.memdev.c b/cligen/gen/base.memdev.c index 56c3ebd..c5ec60e 100644 --- a/cligen/gen/base.memdev.c +++ b/cligen/gen/base.memdev.c @@ -668,10 +668,10 @@ int cmd_get_supported_logs(int argc, const char **argv, struct cxl_ctx *ctx) return rc >= 0 ? 0 : EXIT_FAILURE; } -int cmd_get_cel_log(int argc, const char **argv, struct cxl_ctx *ctx) +int cmd_get_log(int argc, const char **argv, struct cxl_ctx *ctx) { - int rc = memdev_action(argc, argv, ctx, action_cmd_get_cel_log, cmd_get_cel_log_options, - "cxl get-cel-log [..] []"); + int rc = memdev_action(argc, argv, ctx, action_cmd_get_log, cmd_get_log_options, + "cxl get-log [..] []"); return rc >= 0 ? 0 : EXIT_FAILURE; } diff --git a/cxl/builtin.h b/cxl/builtin.h index 5775f4a..e66d027 100644 --- a/cxl/builtin.h +++ b/cxl/builtin.h @@ -17,7 +17,7 @@ int cmd_init_labels(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_check_labels(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_identify(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_get_supported_logs(int argc, const char **argv, struct cxl_ctx *ctx); -int cmd_get_cel_log(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_get_log(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_get_event_interrupt_policy(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_set_event_interrupt_policy(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_get_timestamp(int argc, const char **argv, struct cxl_ctx *ctx); @@ -116,4 +116,44 @@ int cmd_osa_data_read(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_dimm_spd_read(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_ddr_training_status(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_dimm_slot_info(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_pmic_vtmon_info(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_margin_run(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_margin_status(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_margin_get(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_stats_run(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_stats_get(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_reboot_mode_set(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_curr_cxl_boot_mode_get(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_pcie_eye_run(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_pcie_eye_status(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_pcie_eye_get(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_get_cxl_link_status(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_get_device_info(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_read_ddr_temp(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_cxl_hpa_to_dpa(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_get_cxl_membridge_errors(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_get_ddr_bw(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_get_ddr_latency(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_i2c_read(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_i2c_write(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_get_ddr_ecc_err_info(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_start_ddr_ecc_scrub(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_ecc_scrub_status(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_cont_scrub_status(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_cont_scrub_set(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_init_status(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_get_cxl_membridge_stats(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_trigger_coredump(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_err_inj_en(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_dimm_level_training_status(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_param_set(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_param_get(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_core_volt_set(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_core_volt_get(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_oem_err_inj_viral(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_err_inj_ll_poison(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_pci_err_inj(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_read_ltssm_states(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_page_select_set(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_ddr_page_select_get(int argc, const char **argv, struct cxl_ctx *ctx); #endif /* _CXL_BUILTIN_H_ */ diff --git a/cxl/cxl.c b/cxl/cxl.c index 4b430b5..c44bb75 100644 --- a/cxl/cxl.c +++ b/cxl/cxl.c @@ -73,7 +73,7 @@ static struct cmd_struct commands[] = { { "write-labels", .c_fn = cmd_write_labels }, { "id-cmd", .c_fn = cmd_identify }, { "get-supported-logs", .c_fn = cmd_get_supported_logs }, - { "get-cel-log", .c_fn = cmd_get_cel_log }, + { "get-log", .c_fn = cmd_get_log }, { "get-event-interrupt-policy", .c_fn = cmd_get_event_interrupt_policy }, { "set-event-interrupt-policy", .c_fn = cmd_set_event_interrupt_policy }, { "get-timestamp", .c_fn = cmd_get_timestamp }, @@ -172,6 +172,46 @@ static struct cmd_struct commands[] = { { "dimm-spd-read", .c_fn = cmd_dimm_spd_read }, { "ddr-training-status", .c_fn = cmd_ddr_training_status }, { "dimm-slot-info", .c_fn = cmd_dimm_slot_info }, + { "pmic-vtmon-info", .c_fn = cmd_pmic_vtmon_info }, + { "ddr-margin-run", .c_fn = cmd_ddr_margin_run }, + { "ddr-margin-status", .c_fn = cmd_ddr_margin_status }, + { "ddr-margin-get", .c_fn = cmd_ddr_margin_get }, + { "ddr-stats-run", .c_fn = cmd_ddr_stats_run }, + { "ddr-stats-get", .c_fn = cmd_ddr_stats_get }, + { "reboot-mode-set", .c_fn = cmd_reboot_mode_set }, + { "curr-cxl-boot-mode-get", .c_fn = cmd_curr_cxl_boot_mode_get }, + { "pcie-eye-run", .c_fn = cmd_pcie_eye_run }, + { "pcie-eye-status", .c_fn = cmd_pcie_eye_status }, + { "pcie-eye-get", .c_fn = cmd_pcie_eye_get }, + { "get-cxl-link-status", .c_fn = cmd_get_cxl_link_status }, + { "get-device-info", .c_fn = cmd_get_device_info }, + { "read-ddr-temp", .c_fn = cmd_read_ddr_temp }, + { "cxl-hpa-to-dpa", .c_fn = cmd_cxl_hpa_to_dpa }, + { "get-cxl-membridge-errors", .c_fn = cmd_get_cxl_membridge_errors }, + { "get-ddr-bw", .c_fn = cmd_get_ddr_bw }, + { "get-ddr-latency", .c_fn = cmd_get_ddr_latency }, + { "i2c-read", .c_fn = cmd_i2c_read }, + { "i2c-write", .c_fn = cmd_i2c_write }, + { "get-ddr-ecc-err-info", .c_fn = cmd_get_ddr_ecc_err_info }, + { "start-ddr-ecc-scrub", .c_fn = cmd_start_ddr_ecc_scrub }, + { "ddr-ecc-scrub-status", .c_fn = cmd_ddr_ecc_scrub_status }, + { "ddr-cont-scrub-status", .c_fn = cmd_ddr_cont_scrub_status }, + { "ddr-cont-scrub-set", .c_fn = cmd_ddr_cont_scrub_set }, + { "ddr-init-status", .c_fn = cmd_ddr_init_status }, + { "get-cxl-membridge-stats", .c_fn = cmd_get_cxl_membridge_stats }, + { "trigger-coredump", .c_fn = cmd_trigger_coredump }, + { "ddr-err-inj-en", .c_fn = cmd_ddr_err_inj_en }, + { "ddr-dimm-level-training-status", .c_fn = cmd_ddr_dimm_level_training_status }, + { "ddr-param-set", .c_fn = cmd_ddr_param_set }, + { "ddr-param-get", .c_fn = cmd_ddr_param_get }, + { "core-volt-set", .c_fn = cmd_core_volt_set }, + { "core-volt-get", .c_fn = cmd_core_volt_get }, + { "oem-err-inj-viral", .c_fn = cmd_oem_err_inj_viral }, + { "err-inj-ll-poison", .c_fn = cmd_err_inj_ll_poison }, + { "pci-err-inj", .c_fn = cmd_pci_err_inj }, + { "read-ltssm-states", .c_fn = cmd_read_ltssm_states }, + { "ddr-page-select-set", .c_fn = cmd_ddr_page_select_set }, + { "ddr-page-select-get", .c_fn = cmd_ddr_page_select_get }, }; int main(int argc, const char **argv) diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index ba265ed..6fcb20e 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -1471,6 +1471,7 @@ out: } #define CEL_UUID "0da9c0b5-bf41-4b78-8f79-96b1623b3f17" +#define VENDOR_LOG_UUID "5e1819d9-11a9-400c-811f-d60719403d86" struct cxl_mbox_get_log { uuid_t uuid; @@ -1483,13 +1484,15 @@ struct cel_entry { __le16 effect; } __attribute__((packed)); -CXL_EXPORT int cxl_memdev_get_cel_log(struct cxl_memdev *memdev, const char* uuid) +CXL_EXPORT int cxl_memdev_get_log(struct cxl_memdev *memdev, const char* uuid, const unsigned int data_size) { struct cxl_cmd *cmd; struct cxl_mbox_get_log *get_log_input; struct cel_entry *cel_entries; int no_cel_entries; int rc = 0; + int remaining_bytes = data_size; + unsigned int bytes_read = 0; if (!uuid) { fprintf(stderr, "%s: Please specify log uuid argument\n", @@ -1497,49 +1500,63 @@ CXL_EXPORT int cxl_memdev_get_cel_log(struct cxl_memdev *memdev, const char* uui return -EINVAL; } - cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_GET_LOG); - if (!cmd) { - fprintf(stderr, "%s: cxl_memdev_get_cel_log returned Null output\n", - cxl_memdev_get_devname(memdev)); - return -ENOMEM; - } + do { + cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_GET_LOG); + if (!cmd) { + fprintf(stderr, "%s: cxl_memdev_get_log returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } - get_log_input = (void *) cmd->send_cmd->in.payload; - uuid_parse(uuid, get_log_input->uuid); - get_log_input->offset = 0; - get_log_input->length = cmd->memdev->payload_max; + get_log_input = (void *) cmd->send_cmd->in.payload; + uuid_parse(uuid, get_log_input->uuid); + get_log_input->offset = bytes_read; + get_log_input->length = cmd->memdev->payload_max; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } - rc = cxl_cmd_submit(cmd); - if (rc < 0) { - fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", - cxl_memdev_get_devname(memdev), rc, strerror(-rc)); - goto out; - } + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d:\n%s\n", + cxl_memdev_get_devname(memdev), rc, DEVICE_ERRORS[rc]); + rc = -ENXIO; + goto out; + } - rc = cxl_cmd_get_mbox_status(cmd); - if (rc != 0) { - fprintf(stderr, "%s: firmware status: %d:\n%s\n", - cxl_memdev_get_devname(memdev), rc, DEVICE_ERRORS[rc]); - rc = -ENXIO; - goto out; - } + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_GET_LOG) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_GET_LOG); + return -EINVAL; + } - if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_GET_LOG) { - fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", - cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_GET_LOG); - return -EINVAL; - } + fprintf(stdout, "payload info\n"); + fprintf(stdout, " out size: 0x%x\n", cmd->send_cmd->out.size); + + if (!strcmp(uuid, CEL_UUID)) { + cel_entries = (void *)cmd->send_cmd->out.payload; + no_cel_entries = (cmd->send_cmd->out.size)/sizeof(struct cel_entry); + fprintf(stdout, " no_cel_entries size: %d\n", no_cel_entries); + for (int e = 0; e < no_cel_entries; ++e) { + fprintf(stdout, " cel_entry[%d] opcode: 0x%x, effect: 0x%x\n", e, + le16_to_cpu(cel_entries[e].opcode), + le16_to_cpu(cel_entries[e].effect)); + } + } else if (!strcmp(uuid, VENDOR_LOG_UUID)) { + fprintf(stdout, " number of received bytes = %d\n", cmd->send_cmd->out.size); + fprintf(stdout, "%s", (char *)cmd->send_cmd->out.payload); + } - fprintf(stdout, "payload info\n"); - fprintf(stdout, " out size: 0x%x\n", cmd->send_cmd->out.size); - cel_entries = (void *)cmd->send_cmd->out.payload; - no_cel_entries = (cmd->send_cmd->out.size)/sizeof(struct cel_entry); - fprintf(stdout, " no_cel_entries size: %d\n", no_cel_entries); - for (int e = 0; e < no_cel_entries; ++e) { - fprintf(stdout, " cel_entry[%d] opcode: 0x%x, effect: 0x%x\n", e, - le16_to_cpu(cel_entries[e].opcode), - le16_to_cpu(cel_entries[e].effect)); - } + /* keep getting the data in chunks of payload max */ + bytes_read += cmd->send_cmd->out.size; + if (remaining_bytes >= cmd->send_cmd->out.size) + remaining_bytes -= cmd->send_cmd->out.size; + else + remaining_bytes = 0; + } while(remaining_bytes); out: cxl_cmd_unref(cmd); return rc; @@ -2342,6 +2359,7 @@ out: #define CXL_MEM_COMMAND_ID_GET_FW_INFO CXL_MEM_COMMAND_ID_RAW #define CXL_MEM_COMMAND_ID_GET_FW_INFO_OPCODE 512 +#define CXL_MEM_COMMAND_ID_GET_OS_INFO_OPCODE 0xcd03 #define CXL_MEM_COMMAND_ID_GET_FW_INFO_PAYLOAD_OUT_SIZE 80 @@ -2356,7 +2374,7 @@ struct cxl_mbox_get_fw_info_out { char slot_4_fw_rev[16]; } __attribute__((packed)); -CXL_EXPORT int cxl_memdev_get_fw_info(struct cxl_memdev *memdev) +CXL_EXPORT int cxl_memdev_get_fw_info(struct cxl_memdev *memdev, bool is_os_img) { struct cxl_cmd *cmd; struct cxl_mbox_get_fw_info_out *get_fw_info_out; @@ -2365,8 +2383,19 @@ CXL_EXPORT int cxl_memdev_get_fw_info(struct cxl_memdev *memdev) u8 active_slot; u8 staged_slot_mask; u8 staged_slot; + int opcode; + char *fw_name; + + //select vendor cci command if os image is specified, else default to cxl FW_INFO command + if (is_os_img) { + opcode = CXL_MEM_COMMAND_ID_GET_OS_INFO_OPCODE; + fw_name = "OS"; + } else { + opcode = CXL_MEM_COMMAND_ID_GET_FW_INFO_OPCODE; + fw_name = "FW"; + } - cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_GET_FW_INFO_OPCODE); + cmd = cxl_cmd_new_raw(memdev, opcode); if (!cmd) { fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", cxl_memdev_get_devname(memdev)); @@ -2401,17 +2430,17 @@ CXL_EXPORT int cxl_memdev_get_fw_info(struct cxl_memdev *memdev) staged_slot = get_fw_info_out->fw_slot_info & staged_slot_mask; staged_slot = staged_slot>>3; fprintf(stdout, "================================= get fw info ==================================\n"); - fprintf(stdout, "FW Slots Supported: %x\n", get_fw_info_out->fw_slots_supp); - fprintf(stdout, "Active FW Slot: %x\n", active_slot); + fprintf(stdout, "%s Slots Supported: %x\n", fw_name, get_fw_info_out->fw_slots_supp); + fprintf(stdout, "Active %s Slot: %x\n", fw_name, active_slot); if (staged_slot) { - fprintf(stdout, "Staged FW Slot: %x\n", staged_slot); + fprintf(stdout, "Staged %s Slot: %x\n", fw_name, staged_slot); } - fprintf(stdout, "FW Activation Capabilities: %x\n", get_fw_info_out->fw_activation_capas); - fprintf(stdout, "Slot 1 FW Revision: %s\n", get_fw_info_out->slot_1_fw_rev); - fprintf(stdout, "Slot 2 FW Revision: %s\n", get_fw_info_out->slot_2_fw_rev); - fprintf(stdout, "Slot 3 FW Revision: %s\n", get_fw_info_out->slot_3_fw_rev); - fprintf(stdout, "Slot 4 FW Revision: %s\n", get_fw_info_out->slot_4_fw_rev); + fprintf(stdout, "%s Activation Capabilities: %x\n", fw_name, get_fw_info_out->fw_activation_capas); + fprintf(stdout, "Slot 1 %s Revision: %s\n", fw_name, get_fw_info_out->slot_1_fw_rev); + fprintf(stdout, "Slot 2 %s Revision: %s\n", fw_name, get_fw_info_out->slot_2_fw_rev); + fprintf(stdout, "Slot 3 %s Revision: %s\n", fw_name, get_fw_info_out->slot_3_fw_rev); + fprintf(stdout, "Slot 4 %s Revision: %s\n", fw_name, get_fw_info_out->slot_4_fw_rev); out: cxl_cmd_unref(cmd); @@ -6301,8 +6330,8 @@ struct cxl_mbox_health_counters_get_out { __le32 cxl_mem_link_crc_errors; __le32 cxl_io_link_lcrc_errors; __le32 cxl_io_link_ecrc_errors; - __le32 num_ddr_single_ecc_errors; - __le32 num_ddr_double_ecc_errors; + __le32 num_ddr_correctable_ecc_errors; + __le32 num_ddr_uncorrectable_ecc_errors; __le32 link_recovery_events; __le32 time_in_throttled; __le32 over_temperature_warning_level_exceeded; @@ -6311,6 +6340,16 @@ struct cxl_mbox_health_counters_get_out { __le32 rx_retry_request; __le32 rcmd_qs0_hi_threshold_detect; __le32 rcmd_qs1_hi_threshold_detect; + __le32 num_pscan_correctable_ecc_errors; + __le32 num_pscan_uncorrectable_ecc_errors; + __le32 num_ddr_dimm0_correctable_ecc_errors; + __le32 num_ddr_dimm0_uncorrectable_ecc_errors; + __le32 num_ddr_dimm1_correctable_ecc_errors; + __le32 num_ddr_dimm1_uncorrectable_ecc_errors; + __le32 num_ddr_dimm2_correctable_ecc_errors; + __le32 num_ddr_dimm2_uncorrectable_ecc_errors; + __le32 num_ddr_dimm3_correctable_ecc_errors; + __le32 num_ddr_dimm3_uncorrectable_ecc_errors; } __attribute__((packed)); CXL_EXPORT int cxl_memdev_health_counters_get(struct cxl_memdev *memdev) @@ -6358,14 +6397,23 @@ CXL_EXPORT int cxl_memdev_health_counters_get(struct cxl_memdev *memdev) fprintf(stdout, "6: CXL_MEM_LINK_CRC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->cxl_mem_link_crc_errors)); fprintf(stdout, "7: CXL_IO_LINK_LCRC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->cxl_io_link_lcrc_errors)); fprintf(stdout, "8: CXL_IO_LINK_ECRC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->cxl_io_link_ecrc_errors)); - fprintf(stdout, "9: NUM_DDR_SINGLE_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_single_ecc_errors)); - fprintf(stdout, "10: NUM_DDR_DOUBLE_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_double_ecc_errors)); + fprintf(stdout, "9: NUM_DDR_COR_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_correctable_ecc_errors)); + fprintf(stdout, "10: NUM_DDR_UNCOR_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_uncorrectable_ecc_errors)); fprintf(stdout, "11: LINK_RECOVERY_EVENTS = %d\n", le32_to_cpu(health_counters_get_out->link_recovery_events)); fprintf(stdout, "12: TIME_IN_THROTTLED = %d\n", le32_to_cpu(health_counters_get_out->time_in_throttled)); fprintf(stdout, "13: RX_RETRY_REQUEST = %d\n", le32_to_cpu(health_counters_get_out->rx_retry_request)); fprintf(stdout, "14: RCMD_QS0_HI_THRESHOLD_DETECT = %d\n", le32_to_cpu(health_counters_get_out->rcmd_qs0_hi_threshold_detect)); fprintf(stdout, "15: RCMD_QS1_HI_THRESHOLD_DETECT = %d\n", le32_to_cpu(health_counters_get_out->rcmd_qs1_hi_threshold_detect)); - + fprintf(stdout, "16: NUM_PSCAN_COR_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_pscan_correctable_ecc_errors)); + fprintf(stdout, "17: NUM_PSCAN_UNCOR_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_pscan_uncorrectable_ecc_errors)); + fprintf(stdout, "18: NUM_DDR_DIMM0_COR_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_dimm0_correctable_ecc_errors)); + fprintf(stdout, "19: NUM_DDR_DIMM0_UNCOR_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_dimm0_uncorrectable_ecc_errors)); + fprintf(stdout, "20: NUM_DDR_DIMM1_COR_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_dimm1_correctable_ecc_errors)); + fprintf(stdout, "21: NUM_DDR_DIMM1_UNCOR_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_dimm1_uncorrectable_ecc_errors)); + fprintf(stdout, "22: NUM_DDR_DIMM2_COR_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_dimm2_correctable_ecc_errors)); + fprintf(stdout, "23: NUM_DDR_DIMM2_UNCOR_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_dimm2_uncorrectable_ecc_errors)); + fprintf(stdout, "24: NUM_DDR_DIMM3_COR_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_dimm3_correctable_ecc_errors)); + fprintf(stdout, "25: NUM_DDR_DIMM3_UNCOR_ECC_ERRORS = %d\n", le32_to_cpu(health_counters_get_out->num_ddr_dimm3_uncorrectable_ecc_errors)); out: cxl_cmd_unref(cmd); return rc; @@ -10123,3 +10171,4373 @@ out: cxl_cmd_unref(cmd); return rc; } + +#define MAX_PMIC 8 +#define PMIC_NAME_MAX_SIZE 20 + +struct pmic_data { + char pmic_name[PMIC_NAME_MAX_SIZE]; + float vin; + float vout; + float iout; + float powr; + float temp; +}; +struct cxl_pmic_vtmon_info_out { + struct pmic_data pmic_data[MAX_PMIC]; +} __attribute__((packed)); + +#define CXL_MEM_COMMAND_ID_PMIC_VTMON_INFO CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_PMIC_VTMON_INFO_OPCODE 0xFB00 +#define CXL_MEM_COMMAND_ID_PMIC_VTMON_INFO_PAYLOAD_IN_SIZE 0 + +CXL_EXPORT int cxl_memdev_pmic_vtmon_info(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_pmic_vtmon_info_out *pmic_vtmon_info; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_PMIC_VTMON_INFO_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + cinfo->size_in = CXL_MEM_COMMAND_ID_PMIC_VTMON_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d:\n%s\n", + cxl_memdev_get_devname(memdev), rc, DEVICE_ERRORS[rc]); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_PMIC_VTMON_INFO) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_PMIC_VTMON_INFO); + return -EINVAL; + } + + pmic_vtmon_info = (void *)cmd->send_cmd->out.payload; + fprintf(stdout, "=========================== PMIC VTMON SLOT INFO ============================\n"); + for (int i = 0; i < MAX_PMIC; i++) { + fprintf(stdout, "pmic name: %s\n", pmic_vtmon_info->pmic_data[i].pmic_name); + fprintf(stdout, "vin: %f\n", pmic_vtmon_info->pmic_data[i].vin); + fprintf(stdout, "vout: %f\n", pmic_vtmon_info->pmic_data[i].vout); + fprintf(stdout, "iout: %f\n", pmic_vtmon_info->pmic_data[i].iout); + fprintf(stdout, "powr: %f\n", pmic_vtmon_info->pmic_data[i].powr); + fprintf(stdout, "temp: %f\n", pmic_vtmon_info->pmic_data[i].temp); + } + +out: + cxl_cmd_unref(cmd); + return rc; +} + +/* DDR MARGIN */ +#define CXL_MEM_COMMAND_ID_DDR_MARGIN_SW_RUN CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_MARGIN_SW_RUN_OPCODE 0xFB0A +#define CXL_MEM_COMMAND_ID_DDR_MARGIN_SW_RUN_PAYLOAD_IN_SIZE 4 + +struct cxl_mbox_ddr_margin_run_in { + u8 slice_num; + u8 rd_wr_margin; + u8 ddr_id; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_ddr_margin_run(struct cxl_memdev *memdev, + u8 slice_num, u8 rd_wr_margin, u8 ddr_id) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_ddr_margin_run_in *ddr_margin_run_in; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_MARGIN_SW_RUN_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_DDR_MARGIN_SW_RUN_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + ddr_margin_run_in = (void *) cmd->send_cmd->in.payload; + + ddr_margin_run_in->slice_num = slice_num; + ddr_margin_run_in->rd_wr_margin = rd_wr_margin; + ddr_margin_run_in->ddr_id = ddr_id; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_MARGIN_SW_RUN) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_MARGIN_SW_RUN); + return -EINVAL; + } + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_DDR_MARGIN_SW_STATUS CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_MARGIN_SW_STATUS_OPCODE 0xFB0B + +struct cxl_ddr_margin_status_out { + int run_status; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_ddr_margin_status(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_ddr_margin_status_out *ddr_margin_status_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_MARGIN_SW_STATUS_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_MARGIN_SW_STATUS) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_MARGIN_SW_STATUS); + return -EINVAL; + } + ddr_margin_status_out = (void *)cmd->send_cmd->out.payload; + fprintf(stdout, "%s\n", ddr_margin_status_out->run_status ? + "DDR MARGIN IS RUNNING" : "DDR MARGIN IS NOT RUNNING/FINISHED"); + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_DDR_MARGIN_GET_SW CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_MARGIN_GET_SW_OPCODE 0xFB0C + +/* MAX_NUM_ROWS per BIT_COUNT should be in Sync with the FW Mbox DDR MARGIN code */ +#define MAX_NUM_ROWS 1024 +#define MAX_MARGIN_BIT_COUNT 8 + +struct ddr_margin_info +{ + uint32_t slicenumber; + uint32_t bitnumber; + int32_t vreflevel; + int margin_low; + int margin_high; + double min_delay_ps; + double max_delay_ps; +} __attribute__((packed));; + +struct cxl_ddr_margin_get_sw_out +{ + uint32_t row_count; + struct ddr_margin_info ddr_margin_slice_data[MAX_NUM_ROWS * MAX_MARGIN_BIT_COUNT]; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_ddr_margin_get(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_ddr_margin_get_sw_out *ddr_margin_get_sw_out; + int rc = 0; + uint32_t i; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_MARGIN_GET_SW_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_MARGIN_GET_SW) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_MARGIN_GET_SW); + return -EINVAL; + } + ddr_margin_get_sw_out = (struct cxl_ddr_margin_get_sw_out *)cmd->send_cmd->out.payload; + fprintf(stdout, "SliceNo,bitNo, VrefLv, MinDelay, MaxDelay, MinDly(ps), MaxDly(ps)\n"); + + for(i = 0; i < ddr_margin_get_sw_out->row_count; i++) + { + fprintf(stdout, "%d,%d,%d,%d,%d,%3.2f,%3.2f\n", + ddr_margin_get_sw_out->ddr_margin_slice_data[i].slicenumber, + ddr_margin_get_sw_out->ddr_margin_slice_data[i].bitnumber, + ddr_margin_get_sw_out->ddr_margin_slice_data[i].vreflevel, + ddr_margin_get_sw_out->ddr_margin_slice_data[i].margin_low, + ddr_margin_get_sw_out->ddr_margin_slice_data[i].margin_high, + ddr_margin_get_sw_out->ddr_margin_slice_data[i].min_delay_ps, + ddr_margin_get_sw_out->ddr_margin_slice_data[i].max_delay_ps); + } + +out: + cxl_cmd_unref(cmd); + return rc; +} + +/* DDR STATS START */ +#define CXL_MEM_COMMAND_ID_DDR_STATS_RUN CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_STATS_RUN_OPCODE 0xFB1B +#define CXL_MEM_COMMAND_ID_DDR_STATS_RUN_PAYLOAD_IN_SIZE 9 + +struct cxl_mbox_ddr_stats_run_in { + uint8_t ddr_id; + uint32_t monitor_time; + uint32_t loop_count; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_ddr_stats_run(struct cxl_memdev *memdev, + u8 ddr_id, uint32_t monitor_time, uint32_t loop_count) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_ddr_stats_run_in *ddr_stats_run_in; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_STATS_RUN_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_DDR_STATS_RUN_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + ddr_stats_run_in = (void *) cmd->send_cmd->in.payload; + + ddr_stats_run_in->ddr_id = ddr_id; + ddr_stats_run_in->monitor_time = monitor_time; + ddr_stats_run_in->loop_count = loop_count; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_STATS_RUN) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_STATS_RUN); + return -EINVAL; + } + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_DDR_STATS_STATUS CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_STATS_STATUS_OPCODE 0xFB1C + +struct cxl_ddr_stats_status_out { + int run_status; + uint32_t loop_count; +} __attribute__((packed)); + +/* DDR STATS STATUS */ +CXL_EXPORT int cxl_memdev_ddr_stats_status(struct cxl_memdev *memdev, int* run_status, uint32_t* loop_count) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_ddr_stats_status_out *ddr_stats_status_out; + + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_STATS_STATUS_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_STATS_STATUS) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_STATS_STATUS); + return -EINVAL; + } + ddr_stats_status_out = (void *)cmd->send_cmd->out.payload; + *run_status = ddr_stats_status_out->run_status; + *loop_count = ddr_stats_status_out->loop_count; + + fprintf(stdout, "%s\n", ddr_stats_status_out->run_status ? + "DDR STATS IS BUSY" : "DDR STATS IS NOT RUNNING/FINISHED"); + + fprintf(stdout, "Loop Count = %d\n", ddr_stats_status_out->loop_count); +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_DDR_STATS_GET CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_STATS_GET_OPCODE 0xFB1D + +#define NUM_BANK 16 +#define NUM_CS 4 + +struct dfi_cs_pm { + uint32_t mrw_cnt; + uint32_t refresh_cnt; + uint32_t act_cnt; + uint32_t write_cnt; + uint32_t read_cnt; + uint32_t pre_cnt; + uint32_t rr_cnt; + uint32_t ww_cnt; + uint32_t rw_cnt; +} __attribute__((packed)); + +struct dfi_cs_bank_pm { + uint32_t bank_act_cnt; + uint32_t bank_wr_cnt; + uint32_t bank_rd_cnt; + uint32_t bank_pre_cnt; +} __attribute__((packed)); + +struct dfi_mc_pm { + uint32_t cmd_queue_full_events; + uint32_t info_fifo_full_events; + uint32_t wrdata_hold_fifo_full_events; + uint32_t port_cmd_fifo0_full_events; + uint32_t port_wrresp_fifo0_full_events; + uint32_t port_wr_fifo0_full_events; + uint32_t port_rd_fifo0_full_events; + uint32_t port_cmd_fifo1_full_events; + uint32_t port_wrresp_fifo1_full_events; + uint32_t port_wr_fifo1_full_events; + uint32_t port_rd_fifo1_full_events; + uint32_t ecc_dataout_corrected; + uint32_t ecc_dataout_uncorrected; + uint32_t pd_ex; + uint32_t pd_en; + uint32_t srex; + uint32_t sren; + uint32_t write; + uint32_t read; + uint32_t rmw; + uint32_t bank_act; + uint32_t precharge; + uint32_t precharge_all; + uint32_t mrw; + uint32_t auto_ref; + uint32_t rw_auto_pre; + uint32_t zq_cal_short; + uint32_t zq_cal_long; + uint32_t same_addr_ww_collision; + uint32_t same_addr_wr_collision; + uint32_t same_addr_rw_collision; + uint32_t same_addr_rr_collision; +} __attribute__((packed)); + +struct ddr_pmon_data { + uint64_t fr_cnt; + uint32_t idle_cnt; + uint32_t rd_ot_cnt; + uint32_t wr_ot_cnt; + uint32_t wrd_ot_cnt; + uint32_t rd_cmd_cnt; + uint32_t rd_cmd_busy_cnt; + uint32_t wr_cmd_cnt; + uint32_t wr_cmd_busy_cnt; + uint32_t rd_data_cnt; + uint32_t rd_data_busy_cnt; + uint32_t wr_data_cnt; + uint32_t wr_data_busy_cnt; + uint64_t rd_avg_lat; + uint64_t wr_avg_lat; + uint32_t rd_trans_smpl_cnt; + uint32_t wr_trans_smpl_cnt; +} __attribute__((packed)); + +struct ddr_data { + struct ddr_pmon_data pmon; + struct dfi_cs_pm cs_pm[NUM_CS]; + struct dfi_cs_bank_pm cs_bank_pm[NUM_CS][NUM_BANK]; + struct dfi_mc_pm mc_pm; +} __attribute__((packed)); + +struct ddr_stats_data { + struct ddr_data stats; +} __attribute__((packed)); + +typedef struct ddr_stats_data ddr_stats_data_t; + +#define MAX_CXL_TRANSFER_SZ (16 * 1024) + +static void display_pmon_stats(ddr_stats_data_t* disp_stats, uint32_t loop_count) { + uint32_t loop; + fprintf(stderr,"PMON STATS:\n"); + fprintf(stderr, + "iteration, fr_cnt, idle_cnt, rd_ot_cnt, wr_ot_cnt, wrd_ot_cnt, " + "rd_cmd_cnt, rd_cmd_busy_cnt, wr_cmd_cnt, wr_cmd_busy_cnt, rd_data_cnt, " + "rd_data_busy_cnt, wr_data_cnt, wr_data_busy_cnt, " + "rd_avg_lat, wr_avg_lat, rd_trans_smpl_cnt, wr_trans_smpl_cnt\n"); + for (loop = 0; loop < loop_count; loop++) { + fprintf(stderr, + "[%d], %lu, %u, %u, %u, %u, " + "%u, %u, %u, %u, %u, " + "%u, %u, %u, " + "%lu, %lu, %u, %u\n", + loop, + disp_stats->stats.pmon.fr_cnt, + disp_stats->stats.pmon.idle_cnt, + disp_stats->stats.pmon.rd_ot_cnt, + disp_stats->stats.pmon.wr_ot_cnt, + disp_stats->stats.pmon.wrd_ot_cnt, + disp_stats->stats.pmon.rd_cmd_cnt, + disp_stats->stats.pmon.rd_cmd_busy_cnt, + disp_stats->stats.pmon.wr_cmd_cnt, + disp_stats->stats.pmon.wr_cmd_busy_cnt, + disp_stats->stats.pmon.rd_data_cnt, + disp_stats->stats.pmon.rd_data_busy_cnt, + disp_stats->stats.pmon.wr_data_cnt, + disp_stats->stats.pmon.wr_data_busy_cnt, + disp_stats->stats.pmon.rd_avg_lat, + disp_stats->stats.pmon.wr_avg_lat, + disp_stats->stats.pmon.rd_trans_smpl_cnt, + disp_stats->stats.pmon.wr_trans_smpl_cnt); + disp_stats++; + } + fprintf(stderr,"\n"); +} + +static void display_cs_pm_stats(ddr_stats_data_t* disp_stats, uint32_t loop_count) { + uint32_t rank, loop; + + fprintf(stderr, "CS PM STATS:\n"); + fprintf(stderr, + "iteration, rank, mrw_cnt, refresh_cnt, act_cnt, write_cnt, " + "read_cnt, pre_cnt, rr_cnt, ww_cnt, rw_cnt\n "); + + for (loop = 0; loop < loop_count; loop++) { + for (rank = 0; rank < NUM_CS; rank++) { + fprintf(stderr, + "[%d], %d, %u, %u, %u, %u, " + "%u, %u, %u, %u, %u\n", + loop, + rank, + disp_stats->stats.cs_pm[rank].mrw_cnt, + disp_stats->stats.cs_pm[rank].refresh_cnt, + disp_stats->stats.cs_pm[rank].act_cnt, + disp_stats->stats.cs_pm[rank].write_cnt, + disp_stats->stats.cs_pm[rank].read_cnt, + disp_stats->stats.cs_pm[rank].pre_cnt, + disp_stats->stats.cs_pm[rank].rr_cnt, + disp_stats->stats.cs_pm[rank].ww_cnt, + disp_stats->stats.cs_pm[rank].rw_cnt); + } + disp_stats++; + } + fprintf(stderr, "\n"); +} + +static void display_cs_bank_pm_stats(ddr_stats_data_t* disp_stats, uint32_t loop_count) { + uint32_t rank, bank, loop; + + fprintf(stderr, "CS BANK STATS:\n"); + fprintf(stderr, + "iteration, rank, bank, bank_act_cnt, bank_wr_cnt, bank_rd_cnt, bank_pre_cnt\n"); + for (loop = 0; loop < loop_count; loop++) { + for (rank = 0; rank < NUM_CS; rank++) { + for (bank = 0; bank < NUM_BANK; bank++) { + fprintf(stderr, + "[%d], %d, %d, %u, %u, %u, %u\n", + loop, + rank, + bank, + disp_stats->stats.cs_bank_pm[rank][bank].bank_act_cnt, + disp_stats->stats.cs_bank_pm[rank][bank].bank_wr_cnt, + disp_stats->stats.cs_bank_pm[rank][bank].bank_rd_cnt, + disp_stats->stats.cs_bank_pm[rank][bank].bank_pre_cnt); + } + } + disp_stats++; + } + fprintf(stderr, "\n"); +} + +static void display_mc_pm_stats(ddr_stats_data_t* disp_stats, uint32_t loop_count) { + uint32_t loop; + + fprintf(stderr, "PM STATS:\n"); + fprintf(stderr, + "iteration, cmd_queue_full_events, info_fifo_full_events, " + "wrdata_hold_fifo_full_events, port_cmd_fifo0_full_events, " + "port_wrresp_fifo0_full_events, port_wr_fifo0_full_events, " + "port_rd_fifo0_full_events, port_cmd_fifo1_full_events, " + "port_wrresp_fifo1_full_events, port_wr_fifo1_full_events, " + "port_rd_fifo1_full_events, ecc_dataout_corrected, " + "ecc_dataout_uncorrected, pd_ex, pd_en, srex, sren, " + "write, read, rmw, bank_act, precharge, precharge_all, " + "mrw, auto_ref, rw_auto_pre, zq_cal_short, zq_cal_long, " + "same_addr_ww_collision, same_addr_wr_collision, " + "same_addr_rw_collision, same_addr_rr_collision\n"); + + for (loop = 0; loop < loop_count; loop++) { + fprintf(stderr, + "[%d], %u, %u, " + "%u, %u, " + "%u, %u, " + "%u, %u, " + "%u, %u, " + "%u, %u, " + "%u, %u, %u, %u, %u," + "%u, %u, %u, %u, %u, %u," + "%u, %u, %u, %u, %u," + "%u, %u, " + "%u, %u\n", + loop, + disp_stats->stats.mc_pm.cmd_queue_full_events, + disp_stats->stats.mc_pm.info_fifo_full_events, + disp_stats->stats.mc_pm.wrdata_hold_fifo_full_events, + disp_stats->stats.mc_pm.port_cmd_fifo0_full_events, + disp_stats->stats.mc_pm.port_wrresp_fifo0_full_events, + disp_stats->stats.mc_pm.port_wr_fifo0_full_events, + disp_stats->stats.mc_pm.port_rd_fifo0_full_events, + disp_stats->stats.mc_pm.port_cmd_fifo1_full_events, + disp_stats->stats.mc_pm.port_wrresp_fifo1_full_events, + disp_stats->stats.mc_pm.port_wr_fifo1_full_events, + disp_stats->stats.mc_pm.port_rd_fifo1_full_events, + disp_stats->stats.mc_pm.ecc_dataout_corrected, + disp_stats->stats.mc_pm.ecc_dataout_uncorrected, + disp_stats->stats.mc_pm.pd_ex, + disp_stats->stats.mc_pm.pd_en, + disp_stats->stats.mc_pm.srex, + disp_stats->stats.mc_pm.sren, + disp_stats->stats.mc_pm.write, + disp_stats->stats.mc_pm.read, + disp_stats->stats.mc_pm.rmw, + disp_stats->stats.mc_pm.bank_act, + disp_stats->stats.mc_pm.precharge, + disp_stats->stats.mc_pm.precharge_all, + disp_stats->stats.mc_pm.mrw, + disp_stats->stats.mc_pm.auto_ref, + disp_stats->stats.mc_pm.rw_auto_pre, + disp_stats->stats.mc_pm.zq_cal_short, + disp_stats->stats.mc_pm.zq_cal_long, + disp_stats->stats.mc_pm.same_addr_ww_collision, + disp_stats->stats.mc_pm.same_addr_wr_collision, + disp_stats->stats.mc_pm.same_addr_rw_collision, + disp_stats->stats.mc_pm.same_addr_rr_collision); + disp_stats++; + } + fprintf(stderr, "\n"); +} + +struct cxl_ddr_stats_get_in { + uint32_t offset; + uint32_t transfer_sz; +} __attribute__((packed)); + +#define CXL_MEM_COMMAND_ID_DDR_STATS_GET_PAYLOAD_IN_SIZE 8 + +static int cxl_ddr_stats_get(struct cxl_memdev *memdev, unsigned char *dst, int offset, int bytes_to_cpy) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_ddr_stats_get_in *ddr_stats_get_in; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_STATS_GET_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_DDR_STATS_GET_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + ddr_stats_get_in = (void *) cmd->send_cmd->in.payload; + ddr_stats_get_in->offset = offset; + ddr_stats_get_in->transfer_sz = bytes_to_cpy; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_STATS_GET) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_STATS_GET); + return -EINVAL; + } + + memcpy(dst, (unsigned char*) cmd->send_cmd->out.payload, cmd->send_cmd->out.size); + + +out: + cxl_cmd_unref(cmd); + return rc; +} + +/* DDR GET STATS */ +CXL_EXPORT int cxl_memdev_ddr_stats_get(struct cxl_memdev *memdev) +{ + unsigned char *buf; + int total_bytes = 0, bytes_to_cpy = 0, bytes_copied = 0; + ddr_stats_data_t* ddr_stats_start; + int rc = 0; + int run_status; + uint32_t loop_count; + + rc = cxl_memdev_ddr_stats_status(memdev, &run_status, &loop_count); + if (rc < 0) + return rc; + + if (run_status) + return -EBUSY; + + total_bytes = sizeof(ddr_stats_data_t) * loop_count; + + buf =(unsigned char *)malloc(total_bytes); + ddr_stats_start = (ddr_stats_data_t*)buf; + + while(bytes_copied < total_bytes) + { + bytes_to_cpy = (total_bytes - bytes_copied) < MAX_CXL_TRANSFER_SZ ? + (total_bytes - bytes_copied) : MAX_CXL_TRANSFER_SZ; + rc = cxl_ddr_stats_get(memdev, buf + bytes_copied, bytes_copied, bytes_to_cpy); + bytes_copied = bytes_copied + bytes_to_cpy; + if (rc < 0) + goto out; + } + + display_pmon_stats(ddr_stats_start, loop_count); + display_cs_pm_stats(ddr_stats_start, loop_count); + display_cs_bank_pm_stats(ddr_stats_start, loop_count); + display_mc_pm_stats(ddr_stats_start, loop_count); +out: + free(buf); + return rc; +} + +/* REBOOT MODE SET */ +#define CXL_MEM_COMMAND_ID_REBOOT_MODE_SET CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_REBOOT_MODE_SET_OPCODE 0xFB0D +#define CXL_MEM_COMMAND_ID_REBOOT_MODE_SET_PAYLOAD_IN_SIZE 4 + +#define CXL_IO_MEM_MODE 0x0 +#define CXL_IO_MODE 0xCE + +struct cxl_mbox_reboot_mode_set_in { + u8 reboot_mode; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_reboot_mode_set(struct cxl_memdev *memdev, u8 reboot_mode) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_reboot_mode_set_in *reboot_mode_set_in; + int rc = 0; + + if ((reboot_mode != CXL_IO_MEM_MODE) && (reboot_mode != CXL_IO_MODE)) { + fprintf(stderr,"Invalid Reboot Mode"); + return -EINVAL; + } + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_REBOOT_MODE_SET_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_REBOOT_MODE_SET_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + reboot_mode_set_in = (void *) cmd->send_cmd->in.payload; + + reboot_mode_set_in->reboot_mode = reboot_mode; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_REBOOT_MODE_SET) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_REBOOT_MODE_SET); + return -EINVAL; + } + + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_CXL_CURR_BOOT_MODE_GET CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_CXL_CURR_BOOT_MODE_GET_OPCODE 0xFB0E + +struct cxl_curr_cxl_boot_mode_out +{ + uint8_t curr_cxl_boot; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_curr_cxl_boot_mode_get(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_curr_cxl_boot_mode_out *curr_cxl_boot_mode_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_CXL_CURR_BOOT_MODE_GET_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_CXL_CURR_BOOT_MODE_GET) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_CXL_CURR_BOOT_MODE_GET); + return -EINVAL; + } + + curr_cxl_boot_mode_out = (struct cxl_curr_cxl_boot_mode_out *)cmd->send_cmd->out.payload; + if (curr_cxl_boot_mode_out->curr_cxl_boot == CXL_IO_MEM_MODE) + fprintf(stdout, "CXL_IO_MEM_MODE\n"); + else if (curr_cxl_boot_mode_out->curr_cxl_boot == CXL_IO_MODE) + fprintf(stdout, "CXL_IO_MODE\n"); + else + fprintf(stdout, "Invalid Mode\n"); + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_PCIE_EYE_SW_RUN CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_PCIE_EYE_SW_RUN_OPCODE 0xFB02 +#define CXL_MEM_COMMAND_ID_PCIE_EYE_SW_RUN_PAYLOAD_IN_SIZE 4 + +struct cxl_mbox_pcie_eye_run_in { + u8 lane; + u8 sw_scan; + u8 ber; +} __attribute__((packed)); + +struct cxl_pcie_eye_run_out { + int pcie_eye_run_status; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_pcie_eye_run(struct cxl_memdev *memdev, + u8 lane, u8 sw_scan, u8 ber) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_pcie_eye_run_in *pcie_eye_run_in; + struct cxl_pcie_eye_run_out *pcie_eye_run_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_PCIE_EYE_SW_RUN_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_PCIE_EYE_SW_RUN_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + pcie_eye_run_in = (void *) cmd->send_cmd->in.payload; + + pcie_eye_run_in->lane = lane; + pcie_eye_run_in->sw_scan = sw_scan; + pcie_eye_run_in->ber = ber; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_PCIE_EYE_SW_RUN) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_PCIE_EYE_SW_RUN); + return -EINVAL; + } + + pcie_eye_run_out = (void *)cmd->send_cmd->out.payload; + if (!pcie_eye_run_out->pcie_eye_run_status) + fprintf(stdout, "pcie eye is running\n"); + else + fprintf(stdout, "pcie eye already running OR fault, error : %d\n", + pcie_eye_run_out->pcie_eye_run_status); +out: + cxl_cmd_unref(cmd); + return rc; + return 0; +} + +#define CXL_MEM_COMMAND_ID_PCIE_EYE_SW_STATUS CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_PCIE_EYE_SW_STATUS_OPCODE 0xFB03 + +struct cxl_pcie_eye_status_out { + int pcie_eye_status; + int error; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_pcie_eye_status(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_pcie_eye_status_out *pcie_eye_status_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_PCIE_EYE_SW_STATUS_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_PCIE_EYE_SW_STATUS) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_PCIE_EYE_SW_STATUS); + return -EINVAL; + } + pcie_eye_status_out = (void *)cmd->send_cmd->out.payload; + fprintf(stdout, "%s\n", pcie_eye_status_out->pcie_eye_status ? + "PCIE EYE SW IS RUNNING" : "PCIE EYE SW IS NOT RUNNING/FINISHED"); + if(pcie_eye_status_out->error) + fprintf(stdout, "pcie eye run error %d:\n", pcie_eye_status_out->error); + +out: + cxl_cmd_unref(cmd); + return rc; + return 0; +} + + +#define CXL_MEM_COMMAND_ID_PCIE_EYE_GET_SW CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_PCIE_EYE_GET_SW_OPCODE 0xFB04 + +#define NUM_EYESCOPE_HORIZ_VALS 40 +#define TOTAL_EYESCOPE_HORIZ_VALS ((NUM_EYESCOPE_HORIZ_VALS * 2) + 1) + +struct cxl_pcie_eye_get_sw_out { + char pcie_eye_data[TOTAL_EYESCOPE_HORIZ_VALS + 1]; +} __attribute__((packed)); + +struct cxl_pcie_eye_get_sw_in { + uint offset; +} __attribute__((packed)); + + +CXL_EXPORT int cxl_memdev_pcie_eye_get_sw(struct cxl_memdev *memdev, uint offset) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_pcie_eye_get_sw_in *pcie_eye_get_sw_in; + struct cxl_pcie_eye_get_sw_out *pcie_eye_get_sw_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_PCIE_EYE_GET_SW_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + pcie_eye_get_sw_in = (void *) cmd->send_cmd->in.payload; + pcie_eye_get_sw_in->offset = offset; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_PCIE_EYE_GET_SW) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_PCIE_EYE_GET_SW); + return -EINVAL; + } + pcie_eye_get_sw_out = (void *)cmd->send_cmd->out.payload; + fprintf(stdout, "%s\n", pcie_eye_get_sw_out->pcie_eye_data); + + +out: + cxl_cmd_unref(cmd); + return rc; + return 0; +} + +#define CXL_MEM_COMMAND_ID_PCIE_EYE_GET_HW CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_PCIE_EYE_GET_HW_OPCODE 0xFB05 + +struct eyescope_results { + double merged_horizontal_eye_left; + double merged_horizontal_eye_right; + double merged_vertical_eye_top; + double merged_vertical_eye_bottom; +}; + +struct rx_settings_t { + int iskew_signed; + int qskew_signed; + int dlev00_signed; + int dlev01_signed; + int dlev10_signed; + int dlev11_signed; + int irphase_signed; + int h1po; + int h1no; + int h1pe; + int h1ne; + int h2; + int h3; + int h4; + int h5; + int h6; + int h7; + int h8; + int h9; + int aeq; + int vga; + int appmd; + int rxrt; + int shd; + int step; + int wm; +}; + + +struct cxl_pcie_eye_get_hw_out { + struct eyescope_results eyescope_results; + struct rx_settings_t rx_settings_t; + int eyescope_request_status; +} __attribute__((packed)); + + +void display_rx_setttings(struct rx_settings_t *settings); +void display_rx_setttings(struct rx_settings_t *settings) +{ + fprintf(stdout, "rx_settings: \n"); + fprintf(stdout, "dlv0123 = [%d, %d, %d, %d],", settings->dlev00_signed, settings->dlev01_signed, + settings->dlev10_signed, settings->dlev11_signed); + fprintf(stdout, "*vga, aeq = [%d, %d],", settings->vga, settings->aeq); + fprintf(stdout, "h2-9 = [%d, %d, %d, %d, %d, %d, %d, %d],", + settings->h2, settings->h3, settings->h4, settings->h5, + settings->h6, settings->h7, settings->h8, settings->h9); + fprintf(stdout, "appmd, rxrt, shd, wm = [%d, %d, 'g%d', %d],", + settings->appmd, settings->rxrt, settings->shd, settings->wm); + fprintf(stdout, "h1ne/0, pe/o = [%d %d %d %d],", settings->h1ne, settings->h1no, + settings->h1pe, settings->h1po); + fprintf(stdout, "iskw, qskw = [%d %d]", settings->iskew_signed, settings->qskew_signed); + fprintf(stdout, "\n"); +} + +void display_merged_eye_results(struct eyescope_results *eyescope_results); +void display_merged_eye_results(struct eyescope_results *eyescope_results){ + + fprintf(stdout, "Merged Top (mV): %f\n", + eyescope_results->merged_vertical_eye_top); + fprintf(stdout, "Merged Bottom (mV): %f\n", + eyescope_results->merged_vertical_eye_bottom); + fprintf(stdout, "Merged Right Eye (UI): %f\n", + eyescope_results->merged_horizontal_eye_right); + fprintf(stdout, "Merged Left Eye (UI): %f\n", + eyescope_results->merged_horizontal_eye_left); +} + +CXL_EXPORT int cxl_memdev_pcie_eye_get_hw(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_pcie_eye_get_hw_out *pcie_eye_get_hw_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_PCIE_EYE_GET_HW_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_PCIE_EYE_GET_HW) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_PCIE_EYE_GET_HW); + return -EINVAL; + } + pcie_eye_get_hw_out = (void *)cmd->send_cmd->out.payload; + if (pcie_eye_get_hw_out->eyescope_request_status) { + fprintf(stdout, "eyescope request status: PASS\n"); + display_rx_setttings(&pcie_eye_get_hw_out->rx_settings_t); + display_merged_eye_results(&pcie_eye_get_hw_out->eyescope_results); + } else { + fprintf(stdout, "eyescope request status: FAIL\n"); + } + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_PCIE_EYE_SW_BER CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_PCIE_EYE_SW_BER_OPCODE 0xFB06 + +struct cxl_pcie_eye_get_sw_ber_out { + float horiz_margin; + float vert_margin; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_pcie_eye_get_sw_ber(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_pcie_eye_get_sw_ber_out *pcie_eye_get_sw_ber_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_PCIE_EYE_SW_BER_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: Read failed OR BER is not enabled, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_PCIE_EYE_SW_BER) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_PCIE_EYE_SW_BER); + return -EINVAL; + } + pcie_eye_get_sw_ber_out = (void *)cmd->send_cmd->out.payload; + fprintf(stdout, "Extrapolation for BER at 1e-12\n"); + if(pcie_eye_get_sw_ber_out->vert_margin > 18 && pcie_eye_get_sw_ber_out->horiz_margin > 0.2) { + fprintf(stdout, "Eye Height and width margins are > 0.2UI and 18mV, Test PASSED\n"); + fprintf(stdout, "Eye width margin at 1e-12 is %f UI\n", pcie_eye_get_sw_ber_out->horiz_margin); + fprintf(stdout, "Eye height margin at 1e-12 is %f mV\n", pcie_eye_get_sw_ber_out->vert_margin); + } else { + fprintf(stdout, "Eye Height and width margins are not greater than 0.2UI and 18mV, Test FAILED\n"); + } +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_GET_CXL_LINK_STATUS CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_GET_CXL_LINK_STATUS_OPCODE 0xFB07 + +char ltssm_state_name[][20] = +{ + "DETECT_QUIET", + "DETECT_ACT", + "POLL_ACTIVE", + "POLL_COMPLIANCE", + "POLL_CONFIG", + "PRE_DETECT_QUIET", + "DETECT_WAIT", + "CFG_LINKWD_START", + "CFG_LINKWD_ACEPT", + "CFG_LANENUM_WAIT", + "CFG_LANENUM_ACEPT", + "CFG_COMPLETE", + "CFG_IDLE", + "RCVRY_LOCK", + "RCVRY_SPEED", + "RCVRY_RCVRCFG", + "RCVRY_IDLE", + "L0", + "L0S", + "L123_SEND_EIDLE", + "L1_IDLE", + "L2_IDLE", + "L2_WAKE", + "DISABLED_ENTRY", + "DISABLED_IDLE", + "DISABLED", + "LPBK_ENTRY", + "LPBK_ACTIVE", + "LPBK_EXIT", + "LPBK_EXIT_TIMEOUT", + "HOT_RESET_ENTRY", + "HOT_RESET", + "RCVRY_EQ0", + "RCVRY_EQ1", + "RCVRY_EQ2", + "RCVRY_EQ3" +}; + +struct cxl_get_cxl_link_status_out { + float cxl_link_status; + uint32_t link_width; + uint32_t link_speed; + uint32_t ltssm_val; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_get_cxl_link_status(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_get_cxl_link_status_out *get_cxl_link_status_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_GET_CXL_LINK_STATUS_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: Read failed, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_GET_CXL_LINK_STATUS) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_GET_CXL_LINK_STATUS); + return -EINVAL; + } + get_cxl_link_status_out = (void *)cmd->send_cmd->out.payload; + fprintf(stdout, "Link is in CXL%0.1f mode\n", get_cxl_link_status_out->cxl_link_status); + fprintf(stdout, "Negotiated link width: x%d\n", get_cxl_link_status_out->link_width); + fprintf(stdout, "Negotiated link speed: Gen%d\n", get_cxl_link_status_out->link_speed); + fprintf(stdout, "ltssm state: %s, code 0x%x\n", ltssm_state_name[get_cxl_link_status_out->ltssm_val], get_cxl_link_status_out->ltssm_val); +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_GET_DEVICE_INFO CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_GET_DEVICE_INFO_OPCODE 0xFB08 + +struct cxl_get_device_info_out { + uint16_t device_id; + uint8_t revision_id; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_get_device_info(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_get_device_info_out *get_device_info_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_GET_DEVICE_INFO_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: Read failed, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_GET_DEVICE_INFO) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_GET_DEVICE_INFO); + return -EINVAL; + } + get_device_info_out = (void *)cmd->send_cmd->out.payload; + fprintf(stdout, "Device id: 0x%x\n", get_device_info_out->device_id); + fprintf(stdout, "Revision id: 0x%x\n", get_device_info_out->revision_id); +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_READ_DDR_TEMP CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_READ_DDR_TEMP_OPCODE 0xC531 +#define DDR_MAX_DIMM_CNT 4 + +struct ddr_dimm_temp_info { + uint8_t ddr_temp_valid; + uint8_t dimm_id; + uint8_t spd_idx; + uint8_t rsvd; + float dimm_temp; +}; + +struct cxl_read_ddr_temp_out { + struct ddr_dimm_temp_info ddr_dimm_temp_info[DDR_MAX_DIMM_CNT]; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_read_ddr_temp(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_read_ddr_temp_out *read_ddr_temp_out; + int rc = 0; + int idx; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_READ_DDR_TEMP_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: Read failed, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_READ_DDR_TEMP) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_READ_DDR_TEMP); + return -EINVAL; + } + read_ddr_temp_out = (void *)cmd->send_cmd->out.payload; + fprintf(stdout, "DDR DIMM temperature info:\n"); + for(idx = 0; idx < DDR_MAX_DIMM_CNT; idx++) { + fprintf(stdout, "dimm_id : 0x%x\n", read_ddr_temp_out->ddr_dimm_temp_info[idx].dimm_id); + fprintf(stdout, "spd_idx: 0x%x\n", read_ddr_temp_out->ddr_dimm_temp_info[idx].spd_idx); + fprintf(stdout, "dimm temp: %f\n", read_ddr_temp_out->ddr_dimm_temp_info[idx].dimm_temp); + fprintf(stdout, "ddr temperature is %s\n\n", read_ddr_temp_out->ddr_dimm_temp_info[idx].ddr_temp_valid ? "valid" : "invalid"); + } +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_CXL_HPA_TO_DPA CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_CXL_HPA_TO_DPA_OPCODE 0xFB14 +#define CXL_MEM_COMMAND_ID_CXL_HPA_TO_DPA_IN_PAYLOAD_SIZE sizeof(u64) + +CXL_EXPORT int cxl_memdev_cxl_hpa_to_dpa(struct cxl_memdev *memdev, u64 hpa_address) +{ + struct cxl_cmd *cmd; + struct cxl_command_info *cinfo; + struct cxl_mem_query_commands *query; + int rc = 0; + u64 *dpa_address_out; + u64 *hpa_address_in; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_CXL_HPA_TO_DPA_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_CXL_HPA_TO_DPA_IN_PAYLOAD_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + hpa_address_in = (void *)cmd->send_cmd->in.payload; + *hpa_address_in = hpa_address; + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: Read failed, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_CXL_HPA_TO_DPA) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_CXL_HPA_TO_DPA); + return -EINVAL; + } + dpa_address_out = (void*)cmd->send_cmd->out.payload; + fprintf(stdout, "dpa address:0x%lx\n", *dpa_address_out); + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_GET_CXL_MEMBRIDGE_ERRORS CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_GET_CXL_MEMBRIDGE_ERRORS_OPCODE 0xFB13 + +typedef enum { + WSTRB_PARITY_ERROR = 0, + WDATA_PARITY_ERROR, + RDATA_RRESP_PARITY_ERROR, + RDATA_RESP_RID_PARITY_ERROR, + RDATA_PARITY_ERROR, + R_RESP_PARITY_ERROR, + B_RESP_PARITY_ERROR, + AW_QOS_PARITY_ERROR, + AW_MISC_PARITY_ERROR, + AW_ID_PARITY_ERROR, + AW_ADDR_RANGE_PARITY_ERROR, + AW_ADDR_PARITY_ERROR, + AR_QOS_PARITY_ERROR, + AR_MISC_PARITY_ERROR, + AR_ID_PARITY_ERROR, + AR_ADDR_RANGE_PARITY_ERROR, + AR_ADDR_PARITY_ERROR, + AXI_B_ID_PARITY_ERROR, + AXI_B_PARITY_ERROR, + AXI_R_ID_PARITY_ERROR, + AXI_R_DATA_PARITY_ERROR, + AXI_R_PARITY_ERROR, + DDR_PARITY_ERROR_COUNT = 22, +} ddr_parity_errors; + +char *ddr_parity_error_strings[DDR_PARITY_ERROR_COUNT] = { + "WSTRB_PARITY_ERROR", + "WDATA_PARITY_ERROR", + "RDATA_RRESP_PARITY_ERROR", + "RDATA_RESP_RID_PARITY_ERROR", + "RDATA_PARITY_ERROR", + "R_RESP_PARITY_ERROR", + "B_RESP_PARITY_ERROR", + "AW_QOS_PARITY_ERROR", + "AW_MISC_PARITY_ERROR", + "AW_ID_PARITY_ERROR", + "AW_ADDR_RANGE_PARITY_ERROR", + "AW_ADDR_PARITY_ERROR", + "AR_QOS_PARITY_ERROR", + "AR_MISC_PARITY_ERROR", + "AR_ID_PARITY_ERROR", + "AR_ADDR_RANGE_PARITY_ERROR", + "AR_ADDR_PARITY_ERROR", + "AXI_B_ID_PARITY_ERROR", + "AXI_B_PARITY_ERROR", + "AXI_R_ID_PARITY_ERROR", + "AXI_R_DATA_PARITY_ERROR", + "AXI_R_PARITY_ERROR", +}; + +typedef enum { + S2M_NDR_FIFO = 0, + S2M_DRC_FIFO, + M2S_RWD_FIFO, + M2S_REQ_FIFO, + DDR1_W_REQ_FIFO, + DDR1_RDATA_RESP_FIFO, + DDR1_R_RESP_FIFO, + DDR1_B_RESP_FIFO, + DDR1_AW_REQ_FIFO, + DDR1_AR_REQ_FIFO, + DDR0_W_REQ_FIFO, + DDR0_RDATA_RESP_FIFO, + DDR0_R_RESP_FIFO, + DDR0_B_RESP_FIFO, + DDR0_AW_REQ_FIFO, + DDR0_AR_REQ_FIFO, + FIFO_ERROR_COUNT = 16, +} fifo_errors; + +char *fifo_error_strings[FIFO_ERROR_COUNT] = { + "S2M_NDR_FIFO", + "S2M_DRC_FIFO", + "M2S_RWD_FIFO", + "M2S_REQ_FIFO", + "DDR1_W_REQ_FIFO", + "DDR1_RDATA_RESP_FIFO", + "DDR1_R_RESP_FIFO", + "DDR1_B_RESP_FIFO", + "DDR1_AW_REQ_FIFO", + "DDR1_AR_REQ_FIFO", + "DDR0_W_REQ_FIFO", + "DDR0_RDATA_RESP_FIFO", + "DDR0_R_RESP_FIFO", + "DDR0_B_RESP_FIFO", + "DDR0_AW_REQ_FIFO", + "DDR0_AR_REQ_FIFO" +}; + +typedef enum { + NDR_TAG_PARITY_ERROR = 0, + NDR_RESP_PARITY_ERROR, + M2S_RWD_ECC_CHECK_ERR_MULTPL_FAIL, + M2S_RWD_ECC_CHECK_ERR_DETECT_FAIL, + M2S_REQ_ECC_CHECK_ERR_MULTPL_FAIL, + M2S_REQ_ECC_CHECK_ERR_DETECT_FAIL, + DRC_TAG_PARITY_ERROR, + DRC_RESP_PARITY_ERROR, + DRC_DATA_PARITY_ERROR, + AW_MST_RWD_PARITY_ERROR, + AR_MST_REQ_PARITY_ERROR, + M2S_REQ_DUP_ADDR_PARITY_ERROR, + M2S_RWD_DUP_ADDR_PARITY_ERROR, + PARITY_ERROR_COUNT = 13, +} parity_errors; + +char *parity_error_strings[PARITY_ERROR_COUNT] = { + "NDR_TAG_PARITY_ERROR", + "NDR_RESP_PARITY_ERROR", + "M2S_RWD_ECC_CHECK_ERR_MULTPL_FAIL", + "M2S_RWD_ECC_CHECK_ERR_DETECT_FAIL", + "M2S_REQ_ECC_CHECK_ERR_MULTPL_FAIL", + "M2S_REQ_ECC_CHECK_ERR_DETECT_FAIL", + "DRC_TAG_PARITY_ERROR", + "DRC_RESP_PARITY_ERROR", + "DRC_DATA_PARITY_ERROR", + "AW_MST_RWD_PARITY_ERROR", + "AR_MST_REQ_PARITY_ERROR", + "M2S_REQ_DUP_ADDR_PARITY_ERROR", + "M2S_RWD_DUP_ADDR_PARITY_ERROR", +}; + +typedef enum { + MST_M2S_RWD_ERR_MULTPL = 0, + MST_M2S_RWD_ERR_DETECT, + MST_M2S_REQ_ERR_MULTPL, + MST_M2S_REQ_ERR_DETECT, + POISON_RECEIVED_IN_RWD, + RWD_ADDRESS_INVALID, + REQ_ADDRESS_INVALID, + DDR1_RRESP_ERROR, + DDR1_BRESP_ERROR, + DDR0_RRESP_ERROR, + DDR0_BRESP_ERROR, + DDR1_RPARITY_ERROR, + DDR1_BPARITY_ERROR, + DDR0_RPARITY_ERROR, + DDR0_BPARITY_ERROR, + HDM_DEC1_ERR_NOT_COMMITED, + RX_DEINIT_TIMEOUT, + TX_DEINIT_TIMEOUT, + VIRAL, + DDR0_BRESP_DEC_ERROR, + DDR1_BRESP_DEC_ERROR, + DDR0_RRESP_DEC_ERROR, + DDR1_RRESP_DEC_ERROR, + MEMBRIDGE_COMMON_ERROR_COUNT = 23 +} membridge_common_errors; + +char *membridge_common_error_strings[MEMBRIDGE_COMMON_ERROR_COUNT] = { + "MST_M2S_RWD_ERR_MULTPL", + "MST_M2S_RWD_ERR_DETECT", + "MST_M2S_REQ_ERR_MULTPL", + "MST_M2S_REQ_ERR_DETECT", + "POISON_RECEIVED_IN_RWD", + "RWD_ADDRESS_INVALID", + "REQ_ADDRESS_INVALID", + "DDR1_RRESP_ERROR", + "DDR1_BRESP_ERROR", + "DDR0_RRESP_ERROR", + "DDR0_BRESP_ERROR", + "DDR1_RPARITY_ERROR", + "DDR1_BPARITY_ERROR", + "DDR0_RPARITY_ERROR", + "DDR0_BPARITY_ERROR", + "HDM_DEC1_ERR_NOT_COMMITED", + "RX_DEINIT_TIMEOUT", + "TX_DEINIT_TIMEOUT", + "VIRAL", + "DDR0_BRESP_DEC_ERROR", + "DDR1_BRESP_DEC_ERROR", + "DDR0_RRESP_DEC_ERROR", + "DDR1_RRESP_DEC_ERROR", +}; + +struct cxl_membridge_errors_out { + uint32_t fifo_overflow; + uint32_t fifo_overflows[FIFO_ERROR_COUNT]; + uint32_t fifo_underflow; + uint32_t fifo_underflows[FIFO_ERROR_COUNT]; + uint32_t ddr0_parity_error; + uint32_t ddr0_parity_errors[DDR_PARITY_ERROR_COUNT]; + uint32_t ddr1_parity_error; + uint32_t ddr1_parity_errors[DDR_PARITY_ERROR_COUNT]; + uint32_t parity_error; + uint32_t parity_errors[PARITY_ERROR_COUNT]; + uint32_t common_errors[MEMBRIDGE_COMMON_ERROR_COUNT]; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_get_cxl_membridge_errors(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_membridge_errors_out *get_cxl_membridge_errors_out; + int rc = 0; + int idx; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_GET_CXL_MEMBRIDGE_ERRORS_OPCODE); + + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + + if (rc != 0) { + fprintf(stderr, "%s: Read failed, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_GET_CXL_MEMBRIDGE_ERRORS) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_GET_CXL_MEMBRIDGE_ERRORS); + return -EINVAL; + } + + get_cxl_membridge_errors_out = (void *)cmd->send_cmd->out.payload; + fprintf(stdout, "fifo_overflow errors : %d\n", get_cxl_membridge_errors_out->fifo_overflow); + for(idx = 0; idx < FIFO_ERROR_COUNT; idx++) { + if (get_cxl_membridge_errors_out->fifo_overflows[idx] != 0) + fprintf(stdout, "%s : 0x%x\n", fifo_error_strings[idx], + get_cxl_membridge_errors_out->fifo_overflows[idx]); + } + + fprintf(stdout, "fifo_underflow errors : %d\n", get_cxl_membridge_errors_out->fifo_underflow); + for(idx = 0; idx < FIFO_ERROR_COUNT; idx++) { + if (get_cxl_membridge_errors_out->fifo_underflows[idx] != 0) + fprintf(stdout, "%s : 0x%x\n", fifo_error_strings[idx], + get_cxl_membridge_errors_out->fifo_underflows[idx]); + } + + fprintf(stdout, "ddr0 parity errors : %d\n", get_cxl_membridge_errors_out->ddr0_parity_error); + for(idx = 0; idx < DDR_PARITY_ERROR_COUNT; idx++) { + if (get_cxl_membridge_errors_out->ddr0_parity_errors[idx] != 0) + fprintf(stdout, "%s : 0x%x\n", ddr_parity_error_strings[idx], + get_cxl_membridge_errors_out->ddr0_parity_errors[idx]); + } + + fprintf(stdout, "ddr1 parity errors : %d\n", get_cxl_membridge_errors_out->ddr1_parity_error); + for(idx = 0; idx < DDR_PARITY_ERROR_COUNT; idx++) { + if (get_cxl_membridge_errors_out->ddr1_parity_errors[idx] != 0) + fprintf(stdout, "%s : 0x%x\n", ddr_parity_error_strings[idx], + get_cxl_membridge_errors_out->ddr1_parity_errors[idx]); + } + + fprintf(stdout, "membridge common errors :\n"); + for(idx = 0; idx < MEMBRIDGE_COMMON_ERROR_COUNT; idx++) { + if (get_cxl_membridge_errors_out->common_errors[idx] != 0) + fprintf(stdout, "%s : 0x%x\n", membridge_common_error_strings[idx], + get_cxl_membridge_errors_out->common_errors[idx]); + } + + fprintf(stdout, "parity errors : %d\n", get_cxl_membridge_errors_out->parity_error); + for(idx = 0; idx < PARITY_ERROR_COUNT; idx++) { + if (get_cxl_membridge_errors_out->parity_errors[idx] != 0) + fprintf(stdout, "%s : 0x%x\n", parity_error_strings[idx], + get_cxl_membridge_errors_out->parity_errors[idx]); + } + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_GET_DDR_BW CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_GET_DDR_BW_OPCODE 0xFB09 + +struct cxl_get_ddr_bw_in { + u32 timeout; + u32 iterations; +} __attribute__((packed)); + +typedef enum { + DDR_CTRL0 = 0, + DDR_CTRL1 = 1, + DDR_MAX_SUBSYS, +} ddr_subsys; + +struct cxl_get_ddr_bw_out { + float peak_bw[DDR_MAX_SUBSYS]; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_get_ddr_bw(struct cxl_memdev *memdev, u32 timeout, u32 iterations) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_get_ddr_bw_in *get_ddr_bw_in; + struct cxl_get_ddr_bw_out *get_ddr_bw_out; + float total_peak_bw = 0; + int rc = 0; + int i; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_GET_DDR_BW_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + get_ddr_bw_in = (void *) cmd->send_cmd->in.payload; + + get_ddr_bw_in->timeout = timeout; + get_ddr_bw_in->iterations = iterations; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: Read failed, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_GET_DDR_BW) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_GET_DDR_BW); + return -EINVAL; + } + get_ddr_bw_out = (void *)cmd->send_cmd->out.payload; + for(i = 0; i < DDR_MAX_SUBSYS; i++) { + fprintf(stdout, "ddr%d peak bandwidth = %f GB/s\n", i, get_ddr_bw_out->peak_bw[i]); + total_peak_bw += get_ddr_bw_out->peak_bw[i]; + } + fprintf(stdout, "total peak bandwidth = %f GB/s\n", total_peak_bw); +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_I2C_READ CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_I2C_READ_OPCODE 0xFB10 +#define I2C_MAX_SIZE_NUM_BYTES 128 + +struct cxl_i2c_read_in { + u16 slave_addr; + u8 reg_addr; + u8 num_bytes; +} __attribute__((packed)); + +struct cxl_i2c_read_out { + char buf[I2C_MAX_SIZE_NUM_BYTES]; + u8 num_bytes; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_i2c_read(struct cxl_memdev *memdev, u16 slave_addr, u8 reg_addr, u8 num_bytes) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_i2c_read_in *i2c_read_in; + struct cxl_i2c_read_out *i2c_read_out; + int rc = 0; + int i; + + if(num_bytes > I2C_MAX_SIZE_NUM_BYTES) { + fprintf(stderr, "%s: Max number of bytes supported is %d, cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), I2C_MAX_SIZE_NUM_BYTES, rc, strerror(-rc)); + return -EINVAL; + } + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_I2C_READ_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + i2c_read_in = (void *) cmd->send_cmd->in.payload; + + i2c_read_in->slave_addr = slave_addr; + i2c_read_in->reg_addr = reg_addr; + i2c_read_in->num_bytes= num_bytes; + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: Read failed, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_I2C_READ) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_I2C_READ); + return -EINVAL; + } + i2c_read_out = (void *)cmd->send_cmd->out.payload; + fprintf(stdout, "i2c read output:"); + for(i = 0; i < i2c_read_out->num_bytes; i++) { + fprintf(stdout, "0x%x\t", i2c_read_out->buf[i]); + } + fprintf(stdout, "\n"); + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_I2C_WRITE CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_I2C_WRITE_OPCODE 0xFB11 + +struct cxl_i2c_write_in { + u16 slave_addr; + u8 reg_addr; + u8 data; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_i2c_write(struct cxl_memdev *memdev, u16 slave_addr, u8 reg_addr, u8 data) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_i2c_write_in *i2c_write_in; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_I2C_WRITE_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + i2c_write_in = (void *) cmd->send_cmd->in.payload; + + i2c_write_in->slave_addr = slave_addr; + i2c_write_in->reg_addr = reg_addr; + i2c_write_in->data = data; + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: Read failed, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_I2C_WRITE) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_I2C_WRITE); + return -EINVAL; + } + fprintf(stdout, "i2c write success\n"); + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_GET_DDR_LATENCY CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_GET_DDR_LATENCY_OPCODE 0xFB12 + +struct ddr_lat_op { + uint64_t readlat; + uint64_t writelat; + uint32_t rdsamplecnt; + uint32_t wrsamplecnt; + float avg_rdlatency; + float avg_wrlatency; +}; + +struct cxl_get_ddr_latency_in { + u32 measure_time; +} __attribute__((packed)); + +struct cxl_get_ddr_latency_out { + struct ddr_lat_op ddr_lat_op[DDR_MAX_SUBSYS]; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_get_ddr_latency(struct cxl_memdev *memdev, u32 measure_time) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_get_ddr_latency_in *get_ddr_lat_in; + struct cxl_get_ddr_latency_out *get_ddr_lat_out; + int rc = 0; + int ddr_id; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_GET_DDR_LATENCY_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + get_ddr_lat_in = (void *) cmd->send_cmd->in.payload; + + get_ddr_lat_in->measure_time = measure_time; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: Read failed, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_GET_DDR_LATENCY) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_GET_DDR_LATENCY); + return -EINVAL; + } + get_ddr_lat_out = (void *)cmd->send_cmd->out.payload; + for(ddr_id = 0; ddr_id < DDR_MAX_SUBSYS; ddr_id++) { + fprintf(stdout, "\nDDR%d Latency:\n", ddr_id); + fprintf(stdout, + "readLat: %lu, rdSampleCnt: %u\n, writeLat: %lu, wrSampleCnt: %u\n", + get_ddr_lat_out->ddr_lat_op[ddr_id].readlat, + get_ddr_lat_out->ddr_lat_op[ddr_id].rdsamplecnt, + get_ddr_lat_out->ddr_lat_op[ddr_id].writelat, + get_ddr_lat_out->ddr_lat_op[ddr_id].wrsamplecnt); + + fprintf(stdout, "Average Latency:\n"); + fprintf(stdout, + "Avg Read Latency : %f ns \n Avg Write Latency : %f ns \n", + get_ddr_lat_out->ddr_lat_op[ddr_id].avg_rdlatency, + get_ddr_lat_out->ddr_lat_op[ddr_id].avg_wrlatency); + } +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_GET_DDR_ECC_ERR_INFO CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_GET_DDR_ECC_ERR_INFO_OPCODE 0xFB0F + +struct ddr_parity_err { + uint32_t parity_crit_bit2_cnt; /* Parity error on the address/control bus*/ + uint32_t parity_crit_bit1_cnt; /* Overlapping write data parity error */ + uint32_t parity_crit_bit0_cnt; /* Write data parity error */ +}; + +struct ddr_dfi_err { + uint32_t dfi_crit_bit5_cnt; /* DFI tINIT_COMPLETE value has timed out */ + uint32_t dfi_crit_bit2_cnt; /* Error received from the PHY on the DFI bus */ + + uint32_t dfi_warn_bit1_cnt; /* DFI PHY Master Interface error has occurred */ + uint32_t dfi_warn_bit0_cnt; /* DFI update error has occurred */ +}; + +struct ddr_crc_err { + uint32_t crc_crit_bit1_cnt; /* CA Parity or a CRC error happened during CRC + Retry. */ + uint32_t crc_crit_bit0_cnt; /* CRC error occurred on the write data bus */ +}; + +struct ddr_userif_err { + uint32_t + userif_crit_bit2_cnt; /* Error occurred on the port command channel. */ + uint32_t userif_crit_bit1_cnt; /* Multiple accesses outside the defined + PHYSICAL memory space have occurred. */ + uint32_t userif_crit_bit0_cnt; /* A Memory access outside the defined PHYSICAL + memory space has occurred */ +}; + +struct ddr_ecc_err { + uint32_t ecc_warn_bit6_cnt; /* One or more ECC writeback commands + could not be executed */ + uint32_t ecc_crit_bit3_cnt; /* Multiple uncorrectable ECC events + have been detected */ + uint32_t ecc_crit_bit2_cnt; /* A uncorrectable ECC event has been detected */ + uint32_t ecc_crit_bit8_cnt; /* An ECC correctable error has been detected in a + scrubbing read operation */ + uint32_t ecc_warn_bit1_cnt; /* Multiple correctable ECC events + have been detected */ + uint32_t ecc_warn_bit0_cnt; /* A correctable ECC event has been detected */ +}; + +struct ddr_controller_errors { + struct ddr_parity_err parity; + struct ddr_dfi_err dfi; + struct ddr_crc_err crc; + struct ddr_userif_err userif; + struct ddr_ecc_err ecc; +}; + +struct cxl_get_ddr_ecc_err_info_out { + struct ddr_controller_errors ddr_ctrl_err[DDR_MAX_SUBSYS]; +} __attribute__((packed)); + +void display_error_count(struct ddr_controller_errors *ddr_ctrl_err, ddr_subsys ddr_id); + +void display_error_count(struct ddr_controller_errors *ddr_ctrl_err, ddr_subsys ddr_id) { + if (ddr_ctrl_err[ddr_id].parity.parity_crit_bit2_cnt) { + fprintf(stdout, + "DDR-%d: FATAL: Parity error on the address/control bus " + "(parity_crit_bit2_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].parity.parity_crit_bit2_cnt); + } + if (ddr_ctrl_err[ddr_id].parity.parity_crit_bit1_cnt) { + fprintf(stdout, + "DDR-%d: FATAL: Overlapping write data parity error " + "(parity_crit_bit1_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].parity.parity_crit_bit1_cnt); + } + + if (ddr_ctrl_err[ddr_id].parity.parity_crit_bit0_cnt) { + fprintf(stdout, + "DDR-%d: FATAL: Write data parity error " + "(parity_crit_bit0_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].parity.parity_crit_bit0_cnt); + } + + if (ddr_ctrl_err[ddr_id].dfi.dfi_crit_bit5_cnt) { + fprintf(stdout, + "DDR-%d: FATAL: DFI tINIT_COMPLETE value has timed out " + "(dfi_crit_bit5_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].dfi.dfi_crit_bit5_cnt); + } + + if (ddr_ctrl_err[ddr_id].dfi.dfi_crit_bit2_cnt) { + fprintf(stdout, + "DDR-%d: FATAL : Error received from the PHY on the DFI bus " + "(dfi_crit_bit2_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].dfi.dfi_crit_bit2_cnt); + } + + if (ddr_ctrl_err[ddr_id].dfi.dfi_warn_bit1_cnt) { + fprintf(stdout, + "DDR-%d: WARN: DFI PHY Master Interface error has occurred " + "(dfi_warn_bit1_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].dfi.dfi_warn_bit1_cnt); + } + + if (ddr_ctrl_err[ddr_id].dfi.dfi_warn_bit0_cnt) { + fprintf(stdout, + "DDR-%d: WARN: DFI update error has occurred " + "(dfi_warn_bit0_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].dfi.dfi_warn_bit0_cnt); + } + + if (ddr_ctrl_err[ddr_id].crc.crc_crit_bit1_cnt) { + fprintf(stdout, + "DDR-%d: FATAL: CA Parity or a CRC error happened during CRC Retry " + "(crc_crit_bit1_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].crc.crc_crit_bit1_cnt); + } + + if (ddr_ctrl_err[ddr_id].crc.crc_crit_bit0_cnt) { + fprintf(stdout, + "DDR-%d: FATAL: CRC error occurred on the write data bus " + "(crc_crit_bit0_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].crc.crc_crit_bit0_cnt); + } + + if (ddr_ctrl_err[ddr_id].userif.userif_crit_bit2_cnt) { + fprintf(stdout, + "DDR-%d: FATAL: Error occurred on the port command channel " + "(userif_crit_bit2_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].userif.userif_crit_bit2_cnt); + } + if (ddr_ctrl_err[ddr_id].userif.userif_crit_bit1_cnt) { + fprintf(stdout, + "DDR-%d: FATAL: Multiple accesses outside the defined PHYSICAL " + "memory space have occurred " + "(userif_crit_bit1_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].userif.userif_crit_bit1_cnt); + } + + if (ddr_ctrl_err[ddr_id].userif.userif_crit_bit0_cnt) { + fprintf(stdout, + "DDR-%d: FATAL: A Memory access outside the defined PHYSICAL " + "memory space has occurred " + "(userif_crit_bit0_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].userif.userif_crit_bit0_cnt); + } + + if (ddr_ctrl_err[ddr_id].ecc.ecc_warn_bit6_cnt) { + fprintf(stdout, + "DDR-%d: WARN: One or more ECC writeback commands " + "could not be executed " + "(ecc_warn_bit6_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].ecc.ecc_warn_bit6_cnt); + } + + if (ddr_ctrl_err[ddr_id].ecc.ecc_crit_bit3_cnt) { + fprintf(stdout, + "DDR-%d:FATAL: Multiple uncorrectable ECC events have been detected " + "(ecc_crit_bit3_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].ecc.ecc_crit_bit3_cnt); + } + + if (ddr_ctrl_err[ddr_id].ecc.ecc_crit_bit2_cnt) { + fprintf(stdout, + "DDR-%d: FATAL: A uncorrectable ECC event has been detected " + "(ecc_crit_bit2_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].ecc.ecc_crit_bit2_cnt); + } + if (ddr_ctrl_err[ddr_id].ecc.ecc_crit_bit8_cnt) { + fprintf(stdout, + "DDR-%d: CRIT: An ECC correctable error has been detected " + "in a scrubbing read operation " + "(ecc_crit_bit8_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].ecc.ecc_crit_bit8_cnt); + } + + if (ddr_ctrl_err[ddr_id].ecc.ecc_warn_bit1_cnt) { + fprintf(stdout, + "DDR-%d: WARN: Multiple correctable ECC events have been detected " + "(ecc_warn_bit1_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].ecc.ecc_warn_bit1_cnt); + } + + if (ddr_ctrl_err[ddr_id].ecc.ecc_warn_bit0_cnt) { + fprintf(stdout, + "DDR-%d: WARN: A correctable ECC event has been detected " + "(ecc_warn_bit0_cnt= %u)\n", + ddr_id, + ddr_ctrl_err[ddr_id].ecc.ecc_warn_bit0_cnt); + } +} + +CXL_EXPORT int cxl_memdev_get_ddr_ecc_err_info(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_get_ddr_ecc_err_info_out *get_ddr_ecc_err_info_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_GET_DDR_ECC_ERR_INFO_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: Read failed, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_GET_DDR_ECC_ERR_INFO) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_GET_DDR_ECC_ERR_INFO); + return -EINVAL; + } + get_ddr_ecc_err_info_out = (void *)cmd->send_cmd->out.payload; + display_error_count(get_ddr_ecc_err_info_out->ddr_ctrl_err, DDR_CTRL0); + display_error_count(get_ddr_ecc_err_info_out->ddr_ctrl_err, DDR_CTRL1); + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_START_DDR_ECC_SCRUB CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_START_DDR_ECC_SCRUB_OPCODE 0xFB15 + +CXL_EXPORT int cxl_memdev_start_ddr_ecc_scrub(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_START_DDR_ECC_SCRUB_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: Read failed, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_START_DDR_ECC_SCRUB) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_START_DDR_ECC_SCRUB); + return -EINVAL; + } + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_DDR_ECC_SCRUB_STATUS CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_ECC_SCRUB_STATUS_OPCODE 0xFB16 + + +struct cxl_ddr_ecc_scrub_status_out { + int ecc_scrub_status[DDR_MAX_SUBSYS]; +} __attribute__((packed)); + + +CXL_EXPORT int cxl_memdev_ddr_ecc_scrub_status(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_ddr_ecc_scrub_status_out *ddr_ecc_scrub_status_out; + int rc = 0; + int subsys; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_ECC_SCRUB_STATUS_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_ECC_SCRUB_STATUS) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_ECC_SCRUB_STATUS); + return -EINVAL; + } + ddr_ecc_scrub_status_out = (void *)cmd->send_cmd->out.payload; + for(subsys = DDR_CTRL0; subsys < DDR_MAX_SUBSYS; subsys++) + { + fprintf(stdout, "DDR-%d %s\n", subsys, ddr_ecc_scrub_status_out->ecc_scrub_status[subsys] ? + "ECC SCRUB IS IN PROGRESS" : "DDR SCRUB IS NOT RUNNING/FINISHED"); + } + +out: + cxl_cmd_unref(cmd); + return rc; +} + +/* DDR CONTINUOUS SCRUB STATUS */ + +#define CXL_MEM_COMMAND_ID_DDR_CONT_SCRUB_STATUS CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_CONT_SCRUB_STATUS_OPCODE 0xFB28 + +struct cxl_ddr_cont_scrub_status_out { + uint32_t cont_scrub_status; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_ddr_cont_scrub_status(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_ddr_cont_scrub_status_out *ddr_cont_scrub_status_out; + int rc = 0; + int subsys; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_CONT_SCRUB_STATUS_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_CONT_SCRUB_STATUS) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_CONT_SCRUB_STATUS); + return -EINVAL; + } + ddr_cont_scrub_status_out = (void *)cmd->send_cmd->out.payload; + fprintf(stdout, "%s\n", ddr_cont_scrub_status_out->cont_scrub_status ? + "CONTINUOUS SCRUB IS ON" : "CONTINUOUS SCRUB IS OFF"); + +out: + cxl_cmd_unref(cmd); + return rc; +} + +/* DDR CONTINUOUS SCRUB SET */ +#define CXL_MEM_COMMAND_ID_DDR_CONT_SRUB_SET CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_CONT_SRUB_SET_OPCODE 0xFB29 +#define CXL_MEM_COMMAND_ID_DDR_CONT_SRUB_SET_PAYLOAD_IN_SIZE 4 + +struct cxl_mbox_ddr_cont_scrub_set_in { + uint32_t cont_scrub_status; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_ddr_cont_scrub_set(struct cxl_memdev *memdev, uint32_t cont_scrub_status) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_ddr_cont_scrub_set_in *ddr_cont_scrub_set_in; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_CONT_SRUB_SET_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_DDR_CONT_SRUB_SET_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + ddr_cont_scrub_set_in = (void *) cmd->send_cmd->in.payload; + + ddr_cont_scrub_set_in->cont_scrub_status = cont_scrub_status; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_CONT_SRUB_SET) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_CONT_SRUB_SET); + return -EINVAL; + } + + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_DDR_INIT_STATUS CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_INIT_STATUS_OPCODE 0xFB17 + +typedef enum { + DDR_INIT_INPROGRESS = 0, + DDR_INIT_PASSED = 1, + DDR_INIT_FAILED = -1, + DDR_INIT_FAILED_NO_CH0_DIMM0 = -2, + DDR_INIT_FAILED_UNKNOWN_DIMM = -3, +} ddr_status; + +typedef enum { + CH_0 = 0, + CH_1 = 1, + CH_NA = -1, +} f_channel_id; + +struct ddr_init_boot_status { + int8_t ddr_init_status; + int8_t failed_channel_id; + char failed_dimm_silk_screen; +}; + +struct cxl_ddr_init_status_out { +struct ddr_init_boot_status init_status; +} __packed; + +CXL_EXPORT int cxl_memdev_ddr_init_status(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_ddr_init_status_out *ddr_init_status_out; + int rc = 0; + int8_t status; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_INIT_STATUS_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_INIT_STATUS) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_INIT_STATUS); + return -EINVAL; + } + ddr_init_status_out = (void *)cmd->send_cmd->out.payload; + status = ddr_init_status_out->init_status.ddr_init_status; + switch (status) + { + case DDR_INIT_INPROGRESS: + fprintf(stdout, "DDR INIT IS IN PROGRESS\n"); + break; + case DDR_INIT_PASSED: + fprintf(stdout, "DDR INIT PASSED\n"); + break; + case DDR_INIT_FAILED: + fprintf(stdout, "DDR INIT FAILED for CH:%d DIMM:%c\n", + ddr_init_status_out->init_status.failed_channel_id, + ddr_init_status_out->init_status.failed_dimm_silk_screen); + + fprintf(stdout, "RECOVERY REMEDY: REPLACE CH:%d DIMM:%c and RE-TRY\n", + ddr_init_status_out->init_status.failed_channel_id, + ddr_init_status_out->init_status.failed_dimm_silk_screen); + break; + case DDR_INIT_FAILED_NO_CH0_DIMM0: + fprintf(stdout, "DDR INIT FAILED. CH:%d DIMM:%c is NOT PLUGGED IN\n", + ddr_init_status_out->init_status.failed_channel_id, + ddr_init_status_out->init_status.failed_dimm_silk_screen); + + fprintf(stdout, "RECOVERY REMEDY: PLUG IN CH:%d DIMM:%c\n", + ddr_init_status_out->init_status.failed_channel_id, + ddr_init_status_out->init_status.failed_dimm_silk_screen); + break; + case DDR_INIT_FAILED_UNKNOWN_DIMM: + fprintf(stdout, "DDR INIT FAILED. UN-SUPPORTED/UNKNOWN DIMM\n"); + fprintf(stdout, "RECOVERY REMEDY: PLUG IN SUPPORTED DIMMs\n"); + break; + default: + fprintf(stdout, "DDR INIT STATUS invalid\n"); + } + +out: + cxl_cmd_unref(cmd); + return rc; +} + +struct cxl_cmd_membridge_stats_out { + // mem transaction counters + uint64_t m2s_req_count; + uint64_t m2s_rwd_count; + uint64_t s2m_drs_count; + uint64_t s2m_ndr_count; + // HPA logs for poison & out-of-range + uint64_t rwd_first_poison_hpa_log; + uint64_t rwd_latest_poison_hpa_log; + uint64_t req_first_hpa_log; + uint64_t rwd_first_hpa_log; + // correctible errors counters + uint32_t mst_m2s_req_corr_err_count; + uint32_t mst_m2s_rwd_corr_err_count; + // membridge fifo full/empty status + uint32_t fifo_full_status; + uint32_t fifo_empty_status; + // credit counters + uint8_t m2s_rwd_credit_count; + uint8_t m2s_req_credit_count; + uint8_t s2m_ndr_credit_count; + uint8_t s2m_drc_credit_count; + // rx state machine status 0 + uint8_t rx_fsm_status_rx_deinit; + uint8_t rx_fsm_status_m2s_req; + uint8_t rx_fsm_status_m2s_rwd; + uint8_t rx_fsm_status_ddr0_ar_req; + uint8_t rx_fsm_status_ddr0_aw_req; + uint8_t rx_fsm_status_ddr0_w_req; + // rx state machine status 1 + uint8_t rx_fsm_status_ddr1_ar_req; + uint8_t rx_fsm_status_ddr1_aw_req; + uint8_t rx_fsm_status_ddr1_w_req; + // tx state machine status 0 + uint8_t tx_fsm_status_tx_deinit; + uint8_t tx_fsm_status_s2m_ndr; + uint8_t tx_fsm_status_s2m_drc; + // stat QoS TEL + uint8_t stat_qos_tel_dev_load_read; + uint8_t stat_qos_tel_dev_load_type2_read; + uint8_t stat_qos_tel_dev_load_write; + uint8_t resvd; +} __attribute__((packed)); + +#define CXL_MEM_COMMAND_ID_GET_CXL_MEMBRIDGE_STATS CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_GET_CXL_MEMBRIDGE_STATS_OPCODE 0xFB18 + +CXL_EXPORT int cxl_memdev_get_cxl_membridge_stats(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_cmd_membridge_stats_out *stats; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_GET_CXL_MEMBRIDGE_STATS_OPCODE); + + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + + if (rc != 0) { + fprintf(stderr, "%s: Read failed, firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_GET_CXL_MEMBRIDGE_STATS) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_GET_CXL_MEMBRIDGE_STATS); + return -EINVAL; + } + + stats = (void *)cmd->send_cmd->out.payload; + // print membridge statistics info + fprintf(stderr, "m2s_req_count: %lu\n", stats->m2s_req_count); + fprintf(stderr, "m2s_rwd_count: %lu\n", stats->m2s_rwd_count); + fprintf(stderr, "s2m_drs_count: %lu\n", stats->s2m_drs_count); + fprintf(stderr, "s2m_ndr_count: %lu\n", stats->s2m_ndr_count); + fprintf(stderr, "rwd_first_poison_hpa: 0x%lx\n", stats->rwd_first_poison_hpa_log); + fprintf(stderr, "rwd_latest_poison_hpa: 0x%lx\n", stats->rwd_latest_poison_hpa_log); + fprintf(stderr, "req_first_hpa_log: 0x%lx\n", stats->req_first_hpa_log); + fprintf(stderr, "rwd_first_hpa_log: 0x%lx\n", (u64)stats->rwd_first_hpa_log); + fprintf(stderr, "m2s_req_corr_err_count: %u\n", stats->mst_m2s_req_corr_err_count); + fprintf(stderr, "m2s_rwd_corr_err_count: %u\n", stats->mst_m2s_rwd_corr_err_count); + fprintf(stderr, "fifo_full_status: 0x%x\n", stats->fifo_full_status); + fprintf(stderr, "fifo_empty_status: 0x%x\n", stats->fifo_empty_status); + fprintf(stderr, "m2s_rwd_credit_count: %u\n", stats->m2s_rwd_credit_count); + fprintf(stderr, "m2s_req_credit_count: %u\n", stats->m2s_req_credit_count); + fprintf(stderr, "s2m_ndr_credit_count: %u\n", stats->s2m_ndr_credit_count); + fprintf(stderr, "s2m_drc_credit_count: %u\n", stats->s2m_drc_credit_count); + fprintf(stderr, "rx_status_rx_deinit: 0x%x\n", stats->rx_fsm_status_rx_deinit); + fprintf(stderr, "rx_status_m2s_req: 0x%x\n", stats->rx_fsm_status_m2s_req); + fprintf(stderr, "rx_status_m2s_rwd: 0x%x\n", stats->rx_fsm_status_m2s_rwd); + fprintf(stderr, "rx_status_ddr0_ar_req: 0x%x\n", stats->rx_fsm_status_ddr0_ar_req); + fprintf(stderr, "rx_status_ddr0_aw_req: 0x%x\n", stats->rx_fsm_status_ddr0_aw_req); + fprintf(stderr, "rx_status_ddr0_w_req: 0x%x\n", stats->rx_fsm_status_ddr0_w_req); + fprintf(stderr, "rx_status_ddr1_ar_req: 0x%x\n", stats->rx_fsm_status_ddr1_ar_req); + fprintf(stderr, "rx_status_ddr1_aw_req: 0x%x\n", stats->rx_fsm_status_ddr1_aw_req); + fprintf(stderr, "rx_status_ddr1_w_req: 0x%x\n", stats->rx_fsm_status_ddr1_w_req); + fprintf(stderr, "tx_status_tx_deinit: 0x%x\n", stats->tx_fsm_status_tx_deinit); + fprintf(stderr, "tx_status_s2m_ndr: 0x%x\n", stats->tx_fsm_status_s2m_ndr); + fprintf(stderr, "tx_status_s2m_drc: 0x%x\n", stats->tx_fsm_status_s2m_drc); + fprintf(stderr, "qos_tel_dev_load_read: %u\n", stats->stat_qos_tel_dev_load_read); + fprintf(stderr, "qos_tel_dev_load_type2_read:%u\n", stats->stat_qos_tel_dev_load_type2_read); + fprintf(stderr, "qos_tel_dev_load_write: %u\n", stats->stat_qos_tel_dev_load_write); + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_TRIGGER_COREDUMP CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_TRIGGER_COREDUMP_OPCODE 0xFB1A + +CXL_EXPORT int cxl_memdev_trigger_coredump(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_TRIGGER_COREDUMP_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_TRIGGER_COREDUMP) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_TRIGGER_COREDUMP); + return -EINVAL; + } + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_DDR_ERR_INJ_EN CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_ERR_INJ_EN_OPCODE 0xFB19 + + +struct cxl_ddr_err_inj_en_in { + uint32_t ddr_id; + uint32_t err_type; + uint64_t ecc_fwc_mask; +} __attribute__((packed)); + + +CXL_EXPORT int cxl_memdev_ddr_err_inj_en(struct cxl_memdev *memdev, u32 ddr_id, u32 err_type, u64 ecc_fwc_mask) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_ddr_err_inj_en_in *ddr_err_inj_en_in; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_ERR_INJ_EN_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + ddr_err_inj_en_in = (void *) cmd->send_cmd->in.payload; + ddr_err_inj_en_in->ddr_id = ddr_id; + ddr_err_inj_en_in->err_type = err_type; + ddr_err_inj_en_in->ecc_fwc_mask = ecc_fwc_mask; + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_ERR_INJ_EN) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_ERR_INJ_EN); + return -EINVAL; + } + fprintf(stderr, "Error injection enabled on DDR%d\n", ddr_id); + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_DDR_DIMM_LEVEL_TRAINING_STATUS CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_DIMM_LEVEL_TRAINING_STATUS_OPCODE 0xFB20 + +#define DDR_MAX_CS 4 +#define DDR_CS_DEVICE_MAX 18 +#define DDR_REG_MAX_NIBBLE 9 +#define DDR_MAX_SLICE 9 +#define DDR_MAX_SLICE_BIT 8 + +struct ddr_phy_pll_status { + uint32_t bs0_status; + uint32_t bs1_status; +}; + +struct ddr_wr_levelling_status { + uint32_t lower_nibble_err[DDR_REG_MAX_NIBBLE]; + uint32_t upper_nibble_err[DDR_REG_MAX_NIBBLE]; +}; + +struct ddr_read_gate_training_status { + uint32_t lower_nibble_min_err[DDR_REG_MAX_NIBBLE]; + uint32_t lower_nibble_max_err[DDR_REG_MAX_NIBBLE]; + uint32_t upper_nibble_min_err[DDR_REG_MAX_NIBBLE]; + uint32_t upper_nibble_max_err[DDR_REG_MAX_NIBBLE]; +}; + +struct ddr_margin_vref_data { + float lower_nibble_vref_low_volt[DDR_REG_MAX_NIBBLE]; + float lower_nibble_vref_high_volt[DDR_REG_MAX_NIBBLE]; + float upper_nibble_vref_low_volt[DDR_REG_MAX_NIBBLE]; + float upper_nibble_vref_high_volt[DDR_REG_MAX_NIBBLE]; +}; + +struct ddr_margin_write_dq_vref_data { + float vref_low_volt[DDR_CS_DEVICE_MAX]; + float vref_high_volt[DDR_CS_DEVICE_MAX]; +}; + +struct ddr_margin_write_dq_vref_data_cs { + float vref_low_volt_cs[DDR_MAX_CS][DDR_CS_DEVICE_MAX]; + float vref_high_volt_cs[DDR_MAX_CS][DDR_CS_DEVICE_MAX]; +}; + +struct ddr_margin_rdlvl_delay_dqs_rise_data { + uint32_t te_delay_data[DDR_MAX_SLICE][DDR_MAX_SLICE_BIT]; + uint32_t le_delay_data[DDR_MAX_SLICE][DDR_MAX_SLICE_BIT]; + float te_delay_time[DDR_MAX_SLICE][DDR_MAX_SLICE_BIT]; + float le_delay_time[DDR_MAX_SLICE][DDR_MAX_SLICE_BIT]; +}; + +struct ddr_margin_rdlvl_delay_dqs_fall_data { + uint32_t te_delay_data[DDR_MAX_SLICE][DDR_MAX_SLICE_BIT]; + uint32_t le_delay_data[DDR_MAX_SLICE][DDR_MAX_SLICE_BIT]; + float te_delay_time[DDR_MAX_SLICE][DDR_MAX_SLICE_BIT]; + float le_delay_time[DDR_MAX_SLICE][DDR_MAX_SLICE_BIT]; +}; + +struct ddr_margin_wrdqlvl_delay_data { + uint32_t te_delay_data[DDR_MAX_SLICE][DDR_MAX_SLICE_BIT]; + uint32_t le_delay_data[DDR_MAX_SLICE][DDR_MAX_SLICE_BIT]; + float te_delay_time[DDR_MAX_SLICE][DDR_MAX_SLICE_BIT]; + float le_delay_time[DDR_MAX_SLICE][DDR_MAX_SLICE_BIT]; +}; + +struct ddr_dimm_training_status { + struct ddr_phy_pll_status phy_pll_status; + struct ddr_wr_levelling_status wr_levl_status; + struct ddr_read_gate_training_status rd_gate_tr_status; + struct ddr_margin_vref_data vref_data; + struct ddr_margin_write_dq_vref_data wdq_vref_data; + struct ddr_margin_write_dq_vref_data_cs wdq_vref_data_cs; + struct ddr_margin_rdlvl_delay_dqs_rise_data rddqslvl_rise_data; + struct ddr_margin_rdlvl_delay_dqs_fall_data rddqslvl_fall_data; + struct ddr_margin_wrdqlvl_delay_data wrdqlvl_delay_data; + uint32_t err_status; +}; + +struct cxl_ddr_dimm_level_training_status_out { + struct ddr_dimm_training_status dimm_training_status[2]; +} __attribute__((packed)); + +void print_ddr_training_status(uint32_t instance, struct ddr_dimm_training_status *dimm_tr_status); +void print_read_gate_training_status(uint32_t instance, struct ddr_read_gate_training_status* rd_gate_tr_status); +void print_write_levelling_status(uint32_t instance, struct ddr_wr_levelling_status* wr_levl_status); +void print_ddr_phy_pll_status(uint32_t instance, struct ddr_phy_pll_status* phy_pll_status); +void print_ddr_training_status(uint32_t instance, struct ddr_dimm_training_status *dimm_tr_status); +void print_margin_vref_low_high(uint32_t instance, struct ddr_dimm_training_status *dimm_tr_status); +void print_margin_rdlvl_delay_window(int instance, struct ddr_dimm_training_status *dimm_tr_status); +void print_margin_wrdqlvl_delay_window(int instance, struct ddr_dimm_training_status *dimm_tr_status); +void print_err_status(int instance, struct ddr_dimm_training_status *dimm_tr_status); + +/* DDR phy pll status */ +void print_ddr_phy_pll_status(uint32_t instance, struct ddr_phy_pll_status* phy_pll_status) { + uint32_t read_data; + + read_data = phy_pll_status->bs0_status; + fprintf(stdout, "DDR%d PHY PLL Status: \n", instance); + fprintf(stdout, "\tOBS0: \n"); + fprintf(stdout, "\t\tPLL Lock Status = %d \n", (read_data & 1)); + fprintf(stdout, "\t\tReady = %d \n", ((read_data & 0x2) >> 1)); + fprintf(stdout, "\t\tLock assert count = 0x%x \n", ((read_data & 0x7F8) >> 3)); + + read_data = phy_pll_status->bs1_status; + fprintf(stdout, "\tOBS1: \n"); + fprintf(stdout, "\t\tPLL Lock Status = %d \n", (read_data & 1)); + fprintf(stdout, "\t\tReady = %d \n", ((read_data & 0x2) >> 1)); + fprintf(stdout, "\t\tLock assert count = 0x%x \n\n", ((read_data & 0x7F8) >> 3)); +} + +void print_write_levelling_status(uint32_t instance, struct ddr_wr_levelling_status* wr_levl_status) { + uint32_t read_data = 0; + int i = 0; + + fprintf(stdout, "\t\tBYTE# \t\t\t\t 0 \t 1 \t 2 \t 3 \t 4 \t 5 \t 6 \t 7 \t 8\n"); + read_data = wr_levl_status->lower_nibble_err[i++]; + fprintf(stdout, "\t\tLOWER NIBBLE ERROR FLAG \t %d", (read_data & 0x1000)>> 12); + read_data = wr_levl_status->lower_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x1000)>> 12); + read_data = wr_levl_status->lower_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x1000)>> 12); + read_data = wr_levl_status->lower_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x1000)>> 12); + read_data = wr_levl_status->lower_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x1000)>> 12); + read_data = wr_levl_status->lower_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x1000)>> 12); + read_data = wr_levl_status->lower_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x1000)>> 12); + read_data = wr_levl_status->lower_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x1000)>> 12); + read_data = wr_levl_status->lower_nibble_err[i++]; + fprintf(stdout, "\t %d\n", (read_data & 0x1000)>> 12); + + i = 0; + read_data = wr_levl_status->upper_nibble_err[i++]; + fprintf(stdout, "\t\tUPPER NIBBLE ERROR FLAG \t %d", (read_data & 0x4000)>> 14); + read_data = wr_levl_status->upper_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x4000)>> 14); + read_data = wr_levl_status->upper_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x4000)>> 14); + read_data = wr_levl_status->upper_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x4000)>> 14); + read_data = wr_levl_status->upper_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x4000)>> 14); + read_data = wr_levl_status->upper_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x4000)>> 14); + read_data = wr_levl_status->upper_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x4000)>> 14); + read_data = wr_levl_status->upper_nibble_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x4000)>> 14); + read_data = wr_levl_status->upper_nibble_err[i++]; + fprintf(stdout, "\t %d\n", (read_data & 0x4000)>> 14); +} + +void print_read_gate_training_status(uint32_t instance, struct ddr_read_gate_training_status* rd_gate_tr_status) +{ + uint32_t read_data = 0; + int i = 0; + + fprintf(stdout, "\t\tBYTE# \t\t\t\t 0 \t 1 \t 2 \t 3 \t 4 \t 5 \t 6 \t 7 \t 8\n"); + read_data = rd_gate_tr_status->lower_nibble_min_err[i++]; + fprintf(stdout, "\t\tLOWER NIBBLE MIN ERROR \t\t %d", (read_data & 0x80)>> 7); + read_data = rd_gate_tr_status->lower_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x80)>> 7); + read_data = rd_gate_tr_status->lower_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x80)>> 7); + read_data = rd_gate_tr_status->lower_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x80)>> 7); + read_data = rd_gate_tr_status->lower_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x80)>> 7); + read_data = rd_gate_tr_status->lower_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x80)>> 7); + read_data = rd_gate_tr_status->lower_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x80)>> 7); + read_data = rd_gate_tr_status->lower_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x80)>> 7); + read_data = rd_gate_tr_status->lower_nibble_min_err[i++]; + fprintf(stdout, "\t %d\n", (read_data & 0x80)>> 7); + + i = 0; + read_data = rd_gate_tr_status->lower_nibble_max_err[i++]; + fprintf(stdout, "\t\tLOWER NIBBLE MAX ERROR \t\t %d", (read_data & 0x100)>> 8); + read_data = rd_gate_tr_status->lower_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x100)>> 8); + read_data = rd_gate_tr_status->lower_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x100)>> 8); + read_data = rd_gate_tr_status->lower_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x100)>> 8); + read_data = rd_gate_tr_status->lower_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x100)>> 8); + read_data = rd_gate_tr_status->lower_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x100)>> 8); + read_data = rd_gate_tr_status->lower_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x100)>> 8); + read_data = rd_gate_tr_status->lower_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x100)>> 8); + read_data = rd_gate_tr_status->lower_nibble_max_err[i++]; + fprintf(stdout, "\t %d\n", (read_data & 0x100)>> 8); + + i = 0; + read_data = rd_gate_tr_status->upper_nibble_min_err[i++]; + fprintf(stdout, "\t\tUPPER NIBBLE MIN ERROR \t\t %d", (read_data & 0x200)>> 9); + read_data = rd_gate_tr_status->upper_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x200)>> 9); + read_data = rd_gate_tr_status->upper_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x200)>> 9); + read_data = rd_gate_tr_status->upper_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x200)>> 9); + read_data = rd_gate_tr_status->upper_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x200)>> 9); + read_data = rd_gate_tr_status->upper_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x200)>> 9); + read_data = rd_gate_tr_status->upper_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x200)>> 9); + read_data = rd_gate_tr_status->upper_nibble_min_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x200)>> 9); + read_data = rd_gate_tr_status->upper_nibble_min_err[i++]; + fprintf(stdout, "\t %d\n", (read_data & 0x200)>> 9); + + i = 0; + read_data = rd_gate_tr_status->upper_nibble_max_err[i++]; + fprintf(stdout, "\t\tUPPER NIBBLE MAX ERROR \t\t %d", (read_data & 0x400)>> 10); + read_data = rd_gate_tr_status->upper_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x400)>> 10); + read_data = rd_gate_tr_status->upper_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x400)>> 10); + read_data = rd_gate_tr_status->upper_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x400)>> 10); + read_data = rd_gate_tr_status->upper_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x400)>> 10); + read_data = rd_gate_tr_status->upper_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x400)>> 10); + read_data = rd_gate_tr_status->upper_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x400)>> 10); + read_data = rd_gate_tr_status->upper_nibble_max_err[i++]; + fprintf(stdout, "\t %d", (read_data & 0x400)>> 10); + read_data = rd_gate_tr_status->upper_nibble_max_err[i++]; + fprintf(stdout, "\t %d\n", (read_data & 0x400)>> 10); +} + +void print_ddr_training_status(uint32_t instance, struct ddr_dimm_training_status *dimm_tr_status) { + fprintf(stdout, "DDR%d TRAINING STATUS: \n", instance); + fprintf(stdout, "\tWRITE LEVELLING STATUS: \n"); + print_write_levelling_status(instance, &dimm_tr_status->wr_levl_status); + fprintf(stdout, "\n\tREAD GATE TRAINING STATUS: \n"); + print_read_gate_training_status(instance, &dimm_tr_status->rd_gate_tr_status); +} + +void print_margin_vref_low_high(uint32_t instance, struct ddr_dimm_training_status *dimm_tr_status) +{ + int i = 0, j = 0; + float vref_low_volt, vref_high_volt; + + fprintf(stdout, "DDR%d MARGIN VALUES:\n", instance); + fprintf(stdout, "\tREAD LEVEL VREF: \n"); + fprintf(stdout, "\t\t VREF_LOW VREF_LOW_VOLT(mV) VREF_HIGH VREF_HIGH_VOLT(mV) VREF_MARGIN(mV)\n"); + for(i=0; i<9; i++) + { + fprintf(stdout, "\t\tSlice%d Lower Nibble: ", i); + vref_low_volt = dimm_tr_status->vref_data.lower_nibble_vref_low_volt[i]; + fprintf(stdout, "%04.2f ", vref_low_volt); + vref_high_volt = dimm_tr_status->vref_data.lower_nibble_vref_high_volt[i]; + fprintf(stdout, "%04.2f ", vref_high_volt); + fprintf(stdout, "%0.2f\n", (vref_high_volt - vref_low_volt)); + + fprintf(stdout, "\t\tSlice%d Upper Nibble: ", i); + vref_low_volt = dimm_tr_status->vref_data.upper_nibble_vref_low_volt[i]; + fprintf(stdout, "%04.2f ", vref_low_volt); + vref_high_volt = dimm_tr_status->vref_data.upper_nibble_vref_high_volt[i]; + fprintf(stdout, "%04.2f ", vref_high_volt); + fprintf(stdout, "%0.2f\n\n", (vref_high_volt - vref_low_volt)); + } + fprintf(stdout, "\tWRITE DQ LEVEL VREF: \n"); + fprintf(stdout, "\t\t VREF_LOW VREF_LOW_VOLT(mV) VREF_HIGH VREF_HIGH_VOLT(mV) VREF_MARGIN(mV)\n"); + for(i=0; i<18; i++) + { + fprintf(stdout, "\t\tCS0 Device%d :\t", i); + vref_low_volt = dimm_tr_status->wdq_vref_data.vref_low_volt[i]; + fprintf(stdout, "%04.1f ", vref_low_volt); + vref_high_volt = dimm_tr_status->wdq_vref_data.vref_high_volt[i]; + fprintf(stdout, "%04.1f ", vref_high_volt); + fprintf(stdout, "%0.1f \n", (vref_high_volt - vref_low_volt)); + } + for(j=1; j<4; j++) + { + for(i=0; i<18; i++) + { + fprintf(stdout, "\t\tCS%d Device%d :\t", j, i); + vref_low_volt = dimm_tr_status->wdq_vref_data_cs.vref_low_volt_cs[j][i]; + fprintf(stdout, "%04.1f ", vref_low_volt); + vref_high_volt = dimm_tr_status->wdq_vref_data_cs.vref_high_volt_cs[j][i]; + fprintf(stdout, "%04.1f ", vref_high_volt); + fprintf(stdout, "%0.1f \n", (vref_high_volt - vref_low_volt)); + } + fprintf(stdout, "\n"); + } +} + +void print_margin_rdlvl_delay_window(int instance, struct ddr_dimm_training_status *dimm_tr_status) +{ + uint32_t te_delay_data = 0, le_delay_data = 0; + int i = 0, j = 0; + float te_delay_time, le_delay_time; + + printf("DDR%d Margin Delays: \n", instance); + printf("\tREAD DQSLEVEL RISE DELAY WINDOW: \n"); + printf("\t\t TE_DATA TE_DELAY(ns) LE_DATA LE_DELAY(ns) RD_RISE_DELAY(ns)\n"); + for(j=0; j<9; j++) + { + for(i=0; i<8; i++) + { + printf("\t\tSLICE%d BIT%d ", j, i); + te_delay_data = dimm_tr_status->rddqslvl_rise_data.te_delay_data[j][i]; + printf("%d ", te_delay_data); + te_delay_time = dimm_tr_status->rddqslvl_rise_data.te_delay_time[j][i]; + printf("%0.03f ", te_delay_time); + le_delay_data = dimm_tr_status->rddqslvl_rise_data.le_delay_data[j][i]; + printf("%02d ", le_delay_data); + le_delay_time = dimm_tr_status->rddqslvl_rise_data.le_delay_time[j][i]; + printf("%0.03f ", le_delay_time); + printf("%0.03f\n", (te_delay_time - le_delay_time)); + } + printf("\n"); + } + printf("\tREAD DQSLEVEL FALL DELAY WINDOW: \n"); + printf("\t\t TE_DATA TE_DELAY(ns) LE_DATA LE_DELAY(ns) RD_FALL_DELAY(ns)\n"); + for(j=0; j<9; j++) + { + for(i=0; i<8; i++) + { + printf("\t\tSLICE%d BIT%d ", j, i); + te_delay_data = dimm_tr_status->rddqslvl_fall_data.te_delay_data[j][i]; + printf("%d ", te_delay_data); + te_delay_time = dimm_tr_status->rddqslvl_fall_data.te_delay_time[j][i]; + printf("%0.03f ", te_delay_time); + le_delay_data = dimm_tr_status->rddqslvl_fall_data.le_delay_data[j][i]; + printf("%02d ", le_delay_data); + le_delay_time = dimm_tr_status->rddqslvl_fall_data.le_delay_time[j][i]; + printf("%0.03f ", le_delay_time); + printf("%0.03f\n", (te_delay_time - le_delay_time)); + } + printf("\n"); + } +} + +void print_margin_wrdqlvl_delay_window(int instance, struct ddr_dimm_training_status *dimm_tr_status) +{ + uint32_t te_delay_data = 0, le_delay_data = 0; + int i = 0, j = 0; + float te_delay_time, le_delay_time; + + printf("\tWRITE DQLEVEL DELAY WINDOW: \n"); + printf("\t\t TE_DATA TE_DELAY(ns) LE_DATA LE_DELAY(ns) WRDQLVL_DELAY(ns)\n"); + for(j=0; j<9; j++) + { + for(i=0; i<8; i++) + { + printf("\t\tSLICE%d BIT%d ", j, i); + te_delay_data = dimm_tr_status->wrdqlvl_delay_data.te_delay_data[j][i]; + printf("%d ", te_delay_data); + te_delay_time = dimm_tr_status->wrdqlvl_delay_data.te_delay_time[j][i]; + printf("%0.03f ", te_delay_time); + le_delay_data = dimm_tr_status->wrdqlvl_delay_data.le_delay_data[j][i]; + printf("%02d ", le_delay_data); + le_delay_time = dimm_tr_status->wrdqlvl_delay_data.le_delay_time[j][i]; + printf("%0.03f ", le_delay_time); + printf("%0.03f\n", (te_delay_time - le_delay_time)); + } + printf("\n"); + } +} + +void print_err_status(int instance, struct ddr_dimm_training_status *dimm_tr_status) +{ + uint32_t read_data = dimm_tr_status->err_status; + + fprintf(stdout, "DIMM %d Tranining status\n", instance); + fprintf(stdout, "\tWRLVL_ERR = %d\n", (read_data>>4)&0x1); + fprintf(stdout, "\tGTLVL_ERR = %d\n", (read_data>>3)&0x1); + fprintf(stdout, "\tRDLVL_ERR = %d\n", (read_data>>2)&0x1); + fprintf(stdout, "\tWDQLVL_ERR = %d\n", (read_data>>5)&0x1); + fprintf(stdout, "\tCA PARTIY ERR = %d\n", (read_data>>1)&0x1); +} + +CXL_EXPORT int cxl_memdev_ddr_dimm_level_training_status(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_ddr_dimm_level_training_status_out *dimm_tr_status; + int rc = 0; + int i; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_DIMM_LEVEL_TRAINING_STATUS_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_DIMM_LEVEL_TRAINING_STATUS) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_DIMM_LEVEL_TRAINING_STATUS); + return -EINVAL; + } + dimm_tr_status = (void *)cmd->send_cmd->out.payload; + for (i = DDR_CTRL0; i < DDR_MAX_SUBSYS; i++) { + fprintf(stdout, "dimm:%d level training status\n", i); + print_ddr_phy_pll_status(i, &dimm_tr_status->dimm_training_status[i].phy_pll_status); + print_ddr_training_status(i, &dimm_tr_status->dimm_training_status[i]); + print_margin_vref_low_high(i, &dimm_tr_status->dimm_training_status[i]); + print_margin_rdlvl_delay_window(i, &dimm_tr_status->dimm_training_status[i]); + print_margin_wrdqlvl_delay_window(i, &dimm_tr_status->dimm_training_status[i]); + print_err_status(i, &dimm_tr_status->dimm_training_status[i]); + } +out: + cxl_cmd_unref(cmd); + return rc; +} + +/* DDR PARAM SET */ +#define CXL_MEM_COMMAND_ID_DDR_PARAM_SET CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_PARAM_SET_OPCODE 0xFB1E +#define CXL_MEM_COMMAND_ID_DDR_PARAM_SET_PAYLOAD_IN_SIZE 4 + +struct ddr_interleave_options { + uint8_t ddr_interleave_sz; + uint8_t ddr_interleave_ctrl_choice; +} __attribute__((packed)); + + +struct cxl_mbox_ddr_param_set_in { + struct ddr_interleave_options ddr_inter; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_ddr_param_set(struct cxl_memdev *memdev, u32 ddr_interleave_sz, + u32 ddr_interleave_ctrl_choice) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_ddr_param_set_in *ddr_param_set_in; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_PARAM_SET_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_DDR_PARAM_SET_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + ddr_param_set_in = (void *) cmd->send_cmd->in.payload; + + ddr_param_set_in->ddr_inter.ddr_interleave_sz = ddr_interleave_sz; + ddr_param_set_in->ddr_inter.ddr_interleave_ctrl_choice = ddr_interleave_ctrl_choice; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_PARAM_SET) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_PARAM_SET); + return -EINVAL; + } + + +out: + cxl_cmd_unref(cmd); + return rc; +} + +/* DDR PARAM GET */ +#define CXL_MEM_COMMAND_ID_CXL_DDR_PARAM_GET CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_CXL_DDR_PARAM_GET_OPCODE 0xFB1F + +struct cxl_ddr_param_get_out +{ + struct ddr_interleave_options ddr_inter; +} __attribute__((packed)); + + +CXL_EXPORT int cxl_memdev_ddr_param_get(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_ddr_param_get_out *ddr_param_get_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_CXL_DDR_PARAM_GET_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_CXL_DDR_PARAM_GET) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_CXL_DDR_PARAM_GET); + return -EINVAL; + } + + ddr_param_get_out = (struct cxl_ddr_param_get_out *)cmd->send_cmd->out.payload; + fprintf(stdout, "ddr_interleave_sz: %d\n", ddr_param_get_out->ddr_inter.ddr_interleave_sz); + fprintf(stdout, "ddr_interleave_ctrl_choice: %d\n", ddr_param_get_out->ddr_inter.ddr_interleave_ctrl_choice); + +out: + cxl_cmd_unref(cmd); + return rc; +} + +/* CORE VOLTAGE SET */ +#define CXL_MEM_COMMAND_ID_CORE_VOLT_SET CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_CORE_VOLT_SET_OPCODE 0xFB26 +#define CXL_MEM_COMMAND_ID_CORE_VOLT_SET_PAYLOAD_IN_SIZE 4 + +struct cxl_mbox_core_volt_set_in { + float core_volt; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_core_volt_set(struct cxl_memdev *memdev, float core_volt) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_core_volt_set_in *core_volt_set_in; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_CORE_VOLT_SET_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_CORE_VOLT_SET_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + core_volt_set_in = (void *) cmd->send_cmd->in.payload; + + core_volt_set_in->core_volt = core_volt; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_CORE_VOLT_SET) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_CORE_VOLT_SET); + return -EINVAL; + } + + +out: + cxl_cmd_unref(cmd); + return rc; +} + +/* CORE VOLTAGE GET */ +#define CXL_MEM_COMMAND_ID_CXL_CORE_VOLT_GET CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_CXL_CORE_VOLT_GET_OPCODE 0xFB27 + +struct cxl_core_volt_get_out +{ + float core_volt; +} __attribute__((packed)); + + +CXL_EXPORT int cxl_memdev_core_volt_get(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_core_volt_get_out *core_volt_get_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_CXL_CORE_VOLT_GET_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_CXL_CORE_VOLT_GET) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_CXL_CORE_VOLT_GET); + return -EINVAL; + } + + core_volt_get_out = (struct cxl_core_volt_get_out *)cmd->send_cmd->out.payload; + fprintf(stdout, "Core Voltage: %f V\n", core_volt_get_out->core_volt); + +out: + cxl_cmd_unref(cmd); + return rc; +} + +#define CXL_MEM_COMMAND_ID_OEM_ERR_INJ_VIRAL CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_OEM_ERR_INJ_VIRAL_OPCODE 0xFB21 +#define CXL_MEM_COMMAND_ID_OEM_ERR_INJ_VIRAL_PAYLOAD_IN_SIZE 4 + +struct cxl_mbox_oem_err_inj_viral_in { + u32 viral_type; +} __attribute__((packed)); + + +CXL_EXPORT int cxl_memdev_oem_err_inj_viral(struct cxl_memdev *memdev, + u32 viral_type) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_oem_err_inj_viral_in *err_inj_viral_in; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_OEM_ERR_INJ_VIRAL_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_OEM_ERR_INJ_VIRAL_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + err_inj_viral_in = (void *) cmd->send_cmd->in.payload; + + err_inj_viral_in->viral_type = viral_type; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d:\n%s\n", + cxl_memdev_get_devname(memdev), rc, DEVICE_ERRORS[rc]); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_OEM_ERR_INJ_VIRAL) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_OEM_ERR_INJ_VIRAL); + return -EINVAL; + } + + +out: + cxl_cmd_unref(cmd); + return rc; + return 0; +} + +#define CXL_MEM_COMMAND_ID_ERR_INJ_LL_POISON CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_ERR_INJ_LL_POISON_OPCODE 0xFB22 +#define CXL_MEM_COMMAND_ID_ERR_INJ_LL_POISON_PAYLOAD_IN_SIZE 8 + +struct cxl_mbox_err_inj_ll_poison_in { + u32 en_dis; + u32 ll_err_type; +} __attribute__((packed)); + + +CXL_EXPORT int cxl_memdev_err_inj_ll_poison(struct cxl_memdev *memdev, + u32 en_dis, u32 ll_err_type) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_err_inj_ll_poison_in *err_inj_ll_poison_in; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_ERR_INJ_LL_POISON_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_ERR_INJ_LL_POISON_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + err_inj_ll_poison_in = (void *) cmd->send_cmd->in.payload; + + err_inj_ll_poison_in->ll_err_type = ll_err_type; + err_inj_ll_poison_in->en_dis = en_dis; + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d:\n%s\n", + cxl_memdev_get_devname(memdev), rc, DEVICE_ERRORS[rc]); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_ERR_INJ_LL_POISON) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_ERR_INJ_LL_POISON); + return -EINVAL; + } + + +out: + cxl_cmd_unref(cmd); + return rc; + return 0; +} + +#define CXL_MEM_COMMAND_ID_PCI_ERR_INJ CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_PCI_ERR_INJ_OPCODE 0xFB25 +#define CXL_MEM_COMMAND_ID_PCI_ERR_INJ_PAYLOAD_IN_SIZE 24 + +struct cxl_mbox_pci_err_inj_in { + u32 en_dis; + u32 err_type; + u32 err_subtype; + u32 count; + u32 opt_param1; + u32 opt_param2; +} __attribute__((packed)); + + +CXL_EXPORT int cxl_memdev_pci_err_inj(struct cxl_memdev *memdev, + u32 en_dis, + u32 err_type, + u32 err_subtype, + u32 count, + u32 opt_param1, + u32 opt_param2) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_pci_err_inj_in *pci_err_inj_in; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_PCI_ERR_INJ_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_PCI_ERR_INJ_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + pci_err_inj_in = (void *) cmd->send_cmd->in.payload; + pci_err_inj_in->en_dis = en_dis; + pci_err_inj_in->err_type = err_type; + pci_err_inj_in->err_subtype = err_subtype; + pci_err_inj_in->count = count; + pci_err_inj_in->opt_param1 = opt_param1; + pci_err_inj_in->opt_param2 = opt_param2; + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d:\n%s\n", + cxl_memdev_get_devname(memdev), rc, DEVICE_ERRORS[rc]); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_PCI_ERR_INJ) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_PCI_ERR_INJ); + return -EINVAL; + } + + +out: + cxl_cmd_unref(cmd); + return rc; + return 0; +} + +#define CXL_MEM_COMMAND_ID_READ_LTSSM_STATES CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_READ_LTSSM_STATES_OPCODE 0xFB01 +#define LTSSM_DUMP_SIZE 0x200 +#define LTSSM_EXPECTED_STATE 0x11 +#define LTSSM_STATE_DUMP_COUNT_MAX (LTSSM_DUMP_SIZE / 4) + +struct cxl_mbox_read_ltssm_states_out { + uint32_t ltssm_states[LTSSM_STATE_DUMP_COUNT_MAX]; +} __attribute__((packed)); + + +CXL_EXPORT int cxl_memdev_read_ltssm_states(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_read_ltssm_states_out *read_ltssm_states; + uint32_t *ltssm_val; + uint32_t offset = 0; + uint32_t curr_state; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_READ_LTSSM_STATES_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d:\n%s\n", + cxl_memdev_get_devname(memdev), rc, DEVICE_ERRORS[rc]); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_READ_LTSSM_STATES) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, CXL_MEM_COMMAND_ID_READ_LTSSM_STATES); + return -EINVAL; + } + + read_ltssm_states = (struct cxl_mbox_read_ltssm_states_out*)cmd->send_cmd->out.payload; + fprintf(stdout, "LTSSM STATE CHANGES\n"); + ltssm_val = read_ltssm_states->ltssm_states; + if ((ltssm_val[offset] == ltssm_val[offset + 1]) && (ltssm_val[offset + 1] == 0x0)) { + fprintf(stdout, "ltssm state changes are not collected\n"); + goto out; + } + while (offset < LTSSM_STATE_DUMP_COUNT_MAX) { + if ((ltssm_val[offset] == ltssm_val[offset + 1]) && (ltssm_val[offset + 1] == 0x0)) + break; + curr_state = ltssm_val[offset++]; + fprintf(stdout, + "ltssm state val = 0x%x, %s\n", + curr_state, + ltssm_state_name[curr_state]); + } + +out: + cxl_cmd_unref(cmd); + return rc; + return 0; +} + +/* DDR PAGE SELECT SET */ +#define CXL_MEM_COMMAND_ID_DDR_PAGE_SELECT_SET CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_DDR_PAGE_SELECT_SET_OPCODE 0xFB2A +#define CXL_MEM_COMMAND_ID_DDR_PAGE_SELECT_SET_PAYLOAD_IN_SIZE 4 + +struct page_policy_selection { + uint8_t page_policy_reg_val; +} __attribute__((packed)) page_policy_select; + + +struct cxl_mbox_handle_page_selection_in { + struct page_policy_selection pp_select; +} __attribute__((packed)); + + + +CXL_EXPORT int cxl_memdev_ddr_page_select_set(struct cxl_memdev *memdev, + u32 page_select_option) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_handle_page_selection_in *handle_page_selection_in; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DDR_PAGE_SELECT_SET_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* update payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_DDR_PAGE_SELECT_SET_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + handle_page_selection_in = (void *) cmd->send_cmd->in.payload; + + handle_page_selection_in->pp_select.page_policy_reg_val = page_select_option; + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + rc = -ENXIO; + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_DDR_PAGE_SELECT_SET) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_DDR_PAGE_SELECT_SET); + return -EINVAL; + } + +out: + cxl_cmd_unref(cmd); + return rc; +} + +/* DDR PAGE SELECT GET */ +#define CXL_MEM_COMMAND_ID_CXL_DDR_PAGE_SELECT_GET CXL_MEM_COMMAND_ID_RAW +#define CXL_MEM_COMMAND_ID_CXL_DDR_PAGE_SELECT_GET_OPCODE 0xFB2B + +struct cxl_mbox_handle_page_selection_out { + struct page_policy_selection pp_select; +} __attribute__((packed)); + +CXL_EXPORT int cxl_memdev_ddr_page_select_get(struct cxl_memdev *memdev) +{ + struct cxl_cmd *cmd; + struct cxl_mem_query_commands *query; + struct cxl_command_info *cinfo; + struct cxl_mbox_handle_page_selection_out *handle_page_selection_out; + int rc = 0; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_CXL_DDR_PAGE_SELECT_GET_OPCODE); + if (!cmd) { + fprintf(stderr, "%s: cxl_cmd_new_raw returned Null output\n", + cxl_memdev_get_devname(memdev)); + return -ENOMEM; + } + + query = cmd->query_cmd; + cinfo = &query->commands[cmd->query_idx]; + + /* used to force correct payload size */ + cinfo->size_in = CXL_MEM_COMMAND_ID_LOG_INFO_PAYLOAD_IN_SIZE; + if (cinfo->size_in > 0) { + cmd->input_payload = calloc(1, cinfo->size_in); + if (!cmd->input_payload) + return -ENOMEM; + cmd->send_cmd->in.payload = (u64)cmd->input_payload; + cmd->send_cmd->in.size = cinfo->size_in; + } + + rc = cxl_cmd_submit(cmd); + if (rc < 0) { + fprintf(stderr, "%s: cmd submission failed: %d (%s)\n", + cxl_memdev_get_devname(memdev), rc, strerror(-rc)); + goto out; + } + + rc = cxl_cmd_get_mbox_status(cmd); + if (rc != 0) { + fprintf(stderr, "%s: firmware status: %d\n", + cxl_memdev_get_devname(memdev), rc); + goto out; + } + + if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_CXL_DDR_PAGE_SELECT_GET) { + fprintf(stderr, "%s: invalid command id 0x%x (expecting 0x%x)\n", + cxl_memdev_get_devname(memdev), cmd->send_cmd->id, + CXL_MEM_COMMAND_ID_CXL_DDR_PAGE_SELECT_GET); + return -EINVAL; + } + + handle_page_selection_out = (struct cxl_mbox_handle_page_selection_out *)cmd->send_cmd->out.payload; + fprintf(stdout, "Page_Policy_Reg_Value is selected for %s\n", (handle_page_selection_out->pp_select.page_policy_reg_val)?"open":"close"); + +out: + cxl_cmd_unref(cmd); + return rc; +} diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index aaf2d65..e36b0d4 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -70,7 +70,7 @@ global: cxl_memdev_get_lsa; cxl_memdev_cmd_identify; cxl_memdev_get_supported_logs; - cxl_memdev_get_cel_log; + cxl_memdev_get_log; cxl_memdev_get_event_interrupt_policy; cxl_memdev_set_event_interrupt_policy; cxl_memdev_get_timestamp; @@ -169,4 +169,48 @@ global: cxl_memdev_dimm_spd_read; cxl_memdev_ddr_training_status; cxl_memdev_dimm_slot_info; + cxl_memdev_pmic_vtmon_info; + cxl_memdev_ddr_margin_run; + cxl_memdev_ddr_margin_status; + cxl_memdev_ddr_margin_get; + cxl_memdev_ddr_stats_run; + cxl_memdev_ddr_stats_status; + cxl_memdev_ddr_stats_get; + cxl_memdev_reboot_mode_set; + cxl_memdev_curr_cxl_boot_mode_get; + cxl_memdev_pcie_eye_run; + cxl_memdev_pcie_eye_status; + cxl_memdev_pcie_eye_get_sw; + cxl_memdev_pcie_eye_get_hw; + cxl_memdev_pcie_eye_get_sw_ber; + cxl_memdev_get_cxl_link_status; + cxl_memdev_get_device_info; + cxl_memdev_read_ddr_temp; + cxl_memdev_cxl_hpa_to_dpa; + cxl_memdev_get_cxl_membridge_errors; + cxl_memdev_get_ddr_bw; + cxl_memdev_get_ddr_latency; + cxl_memdev_i2c_read; + cxl_memdev_i2c_write; + cxl_memdev_get_ddr_ecc_err_info; + cxl_memdev_start_ddr_ecc_scrub; + cxl_memdev_ddr_ecc_scrub_status; + cxl_memdev_ddr_cont_scrub_status; + cxl_memdev_ddr_cont_scrub_set; + cxl_memdev_ddr_init_status; + cxl_memdev_get_cxl_membridge_stats; + cxl_memdev_trigger_coredump; + cxl_memdev_ddr_err_inj_en; + cxl_memdev_ddr_err_inj_en; + cxl_memdev_ddr_dimm_level_training_status; + cxl_memdev_ddr_param_set; + cxl_memdev_ddr_param_get; + cxl_memdev_core_volt_set; + cxl_memdev_core_volt_get; + cxl_memdev_oem_err_inj_viral; + cxl_memdev_err_inj_ll_poison; + cxl_memdev_pci_err_inj; + cxl_memdev_read_ltssm_states; + cxl_memdev_ddr_page_select_set; + cxl_memdev_ddr_page_select_get; } LIBCXL_3; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 6583af5..4084daa 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -3,6 +3,7 @@ #ifndef _LIBCXL_H_ #define _LIBCXL_H_ +#include #include #include #include @@ -57,13 +58,13 @@ int cxl_memdev_set_lsa(struct cxl_memdev *memdev, void *buf, size_t length, size_t offset); int cxl_memdev_cmd_identify(struct cxl_memdev *memdev); int cxl_memdev_device_info_get(struct cxl_memdev *memdev); -int cxl_memdev_get_fw_info(struct cxl_memdev *memdev); +int cxl_memdev_get_fw_info(struct cxl_memdev *memdev, bool is_os_img); int cxl_memdev_transfer_fw(struct cxl_memdev *memdev, u8 action, u8 slot, u32 offset, int size, unsigned char *data, u32 transfer_fw_opcode); int cxl_memdev_activate_fw(struct cxl_memdev *memdev, u8 action, u8 slot); int cxl_memdev_get_supported_logs(struct cxl_memdev *memdev); -int cxl_memdev_get_cel_log(struct cxl_memdev *memdev, const char *uuid); +int cxl_memdev_get_log(struct cxl_memdev *memdev, const char *uuid, const unsigned int data_size); int cxl_memdev_get_event_interrupt_policy(struct cxl_memdev *memdev); int cxl_memdev_set_event_interrupt_policy(struct cxl_memdev *memdev, u32 int_policy); int cxl_memdev_get_timestamp(struct cxl_memdev *memdev); @@ -236,6 +237,51 @@ int cxl_memdev_dimm_spd_read(struct cxl_memdev *memdev, u32 spd_id, u32 offset, u32 num_bytes); int cxl_memdev_ddr_training_status(struct cxl_memdev *memdev); int cxl_memdev_dimm_slot_info(struct cxl_memdev *memdev); +int cxl_memdev_pmic_vtmon_info(struct cxl_memdev *memdev); +int cxl_memdev_ddr_margin_run(struct cxl_memdev *memdev, u8 slice_num, u8 rd_wr_margin, u8 ddr_id); +int cxl_memdev_ddr_margin_status(struct cxl_memdev *memdev); +int cxl_memdev_ddr_margin_get(struct cxl_memdev *memdev); +int cxl_memdev_ddr_stats_run(struct cxl_memdev *memdev, u8 ddr_id, + u32 monitor_time, u32 loop_count); +int cxl_memdev_ddr_stats_status(struct cxl_memdev *memdev, int* run_status, uint32_t* loop_count); +int cxl_memdev_ddr_stats_get(struct cxl_memdev *memdev); +int cxl_memdev_reboot_mode_set(struct cxl_memdev *memdev, u8 reboot_mode); +int cxl_memdev_curr_cxl_boot_mode_get(struct cxl_memdev *memdev); +int cxl_memdev_pcie_eye_run(struct cxl_memdev *memdev, u8 lane, u8 sw_scan, u8 ber); +int cxl_memdev_pcie_eye_status(struct cxl_memdev *memdev); +int cxl_memdev_pcie_eye_get_sw(struct cxl_memdev *memdev, uint offset); +int cxl_memdev_pcie_eye_get_hw(struct cxl_memdev *memdev); +int cxl_memdev_pcie_eye_get_sw_ber(struct cxl_memdev *memdev); +int cxl_memdev_get_cxl_link_status(struct cxl_memdev *memdev); +int cxl_memdev_get_device_info(struct cxl_memdev *memdev); +int cxl_memdev_read_ddr_temp(struct cxl_memdev *memdev); +int cxl_memdev_cxl_hpa_to_dpa(struct cxl_memdev *memdev, u64 hpa_address); +int cxl_memdev_get_cxl_membridge_errors(struct cxl_memdev *memdev); +int cxl_memdev_get_ddr_bw(struct cxl_memdev *memdev, u32 timeout, u32 iterations); +int cxl_memdev_get_ddr_latency(struct cxl_memdev *memdev, u32 measure_time); +int cxl_memdev_i2c_read(struct cxl_memdev *memdev, u16 slave_addr, u8 reg_addr, u8 num_bytes); +int cxl_memdev_i2c_write(struct cxl_memdev *memdev, u16 slave_addr, u8 reg_addr, u8 data); +int cxl_memdev_get_ddr_ecc_err_info(struct cxl_memdev *memdev); +int cxl_memdev_start_ddr_ecc_scrub(struct cxl_memdev *memdev); +int cxl_memdev_ddr_ecc_scrub_status(struct cxl_memdev *memdev); +int cxl_memdev_ddr_cont_scrub_status(struct cxl_memdev *memdev); +int cxl_memdev_ddr_cont_scrub_set(struct cxl_memdev *memdev, u32 cont_scrub_status); +int cxl_memdev_ddr_init_status(struct cxl_memdev *memdev); +int cxl_memdev_get_cxl_membridge_stats(struct cxl_memdev *memdev); +int cxl_memdev_trigger_coredump(struct cxl_memdev *memdev); +int cxl_memdev_ddr_err_inj_en(struct cxl_memdev *memdev, u32 ddr_id, u32 err_type, u64 ecc_fwc_mask); +int cxl_memdev_ddr_dimm_level_training_status(struct cxl_memdev *memdev); +int cxl_memdev_ddr_param_set(struct cxl_memdev *memdev, u32 ddr_interleave_sz, + u32 ddr_interleave_ctrl_choice); +int cxl_memdev_ddr_param_get(struct cxl_memdev *memdev); +int cxl_memdev_core_volt_set(struct cxl_memdev *memdev, float core_volt); +int cxl_memdev_core_volt_get(struct cxl_memdev *memdev); +int cxl_memdev_oem_err_inj_viral(struct cxl_memdev *memdev, u32 viral_type); +int cxl_memdev_err_inj_ll_poison(struct cxl_memdev *memdev, u32 en_dis, u32 ll_err_type); +int cxl_memdev_pci_err_inj(struct cxl_memdev *memdev, u32 en_dis, u32 type, u32 err, u32 count, u32 opt1, u32 opt2); +int cxl_memdev_read_ltssm_states(struct cxl_memdev *memdev); +int cxl_memdev_ddr_page_select_set(struct cxl_memdev *memdev, u32 page_select_option); +int cxl_memdev_ddr_page_select_get(struct cxl_memdev *memdev); #define cxl_memdev_foreach(ctx, memdev) \ for (memdev = cxl_memdev_get_first(ctx); \ diff --git a/cxl/memdev.c b/cxl/memdev.c index fba1f75..2ba16d4 100644 --- a/cxl/memdev.c +++ b/cxl/memdev.c @@ -54,6 +54,10 @@ OPT_UINTEGER('s', "size", ¶m.len, "number of label bytes to operate"), \ OPT_UINTEGER('O', "offset", ¶m.offset, \ "offset into the label area to start operation") +u64 hpa_address; +#define HPA_OPTIONS() \ +OPT_U64('h', "hpa", &hpa_address, "host physical address") + static const struct option read_options[] = { BASE_OPTIONS(), LABEL_OPTIONS(), @@ -92,9 +96,17 @@ static struct _log_uuid { OPT_STRING('l', "log_uuid", &log_uuid.uuid, "log-uuid", \ "CEL Log UUID") -static const struct option cmd_get_cel_log_options[] = { +static struct _log_size { + u32 size; +} log_size; + +#define LOG_SIZE_OPTIONS() \ +OPT_UINTEGER('s', "log_size", &log_size.size, "log-size") + +static const struct option cmd_get_log_options[] = { BASE_OPTIONS(), LOG_UUID_OPTIONS(), + LOG_SIZE_OPTIONS(), OPT_END(), }; @@ -146,6 +158,13 @@ static struct _update_fw_params { bool verbose; } update_fw_params; +static struct _fw_img_params { + bool is_os; +} fw_img_params; + +#define FW_IMG_OPTIONS() \ +OPT_BOOLEAN('z', "osimage", &fw_img_params.is_os, "select OS(a.k.a boot1) image") + #define UPDATE_FW_OPTIONS() \ OPT_FILENAME('f', "file", &update_fw_params.filepath, "rom-file", \ "filepath to read ROM for firmware update"), \ @@ -156,6 +175,7 @@ OPT_BOOLEAN('m', "mock", &update_fw_params.mock, "For testing purposes. Mock tra static const struct option cmd_update_fw_options[] = { BASE_OPTIONS(), UPDATE_FW_OPTIONS(), + FW_IMG_OPTIONS(), OPT_END(), }; @@ -172,6 +192,7 @@ static const struct option cmd_device_info_get_options[] = { static const struct option cmd_get_fw_info_options[] = { BASE_OPTIONS(), + FW_IMG_OPTIONS(), OPT_END(), }; @@ -1909,6 +1930,403 @@ static const struct option cmd_dimm_slot_info_options[] = { OPT_END(), }; +static const struct option cmd_pmic_vtmon_info_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static struct _ddr_margin_run_params { + u32 slice_num; + u32 rd_wr_margin; + u32 ddr_id; + bool verbose; +} ddr_margin_run_params; + +#define DDR_MARGIN_RUN_OPTIONS() \ +OPT_UINTEGER('s', "slice_num", &ddr_margin_run_params.slice_num, "SLICE NUMBER"), \ +OPT_UINTEGER('m', "rd_wr_margin", &ddr_margin_run_params.rd_wr_margin, "RD/WR MARGIN"), \ +OPT_UINTEGER('i', "ddr_id", &ddr_margin_run_params.ddr_id, "DDR ID") + +static const struct option cmd_ddr_margin_run_options[] = { + BASE_OPTIONS(), + DDR_MARGIN_RUN_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_ddr_margin_status_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_ddr_margin_get_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static struct _ddr_stats_run_params { + u32 ddr_id; + u32 monitor_time; + u32 loop_count; + bool verbose; +} ddr_stats_run_params; + +#define DDR_STATS_RUN_OPTIONS() \ +OPT_UINTEGER('i', "ddr_id", &ddr_stats_run_params.ddr_id, "DDR ID"), \ +OPT_UINTEGER('m', "monitor_time", &ddr_stats_run_params.monitor_time, "MOINTOR TIME MSEC"), \ +OPT_UINTEGER('n', "loop_count", &ddr_stats_run_params.loop_count, "NUM ITERATION") + +static const struct option cmd_ddr_stats_run_options[] = { + BASE_OPTIONS(), + DDR_STATS_RUN_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_ddr_stats_get_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static struct _reboot_mode_set_params { + u32 reboot_mode; + bool verbose; +} reboot_mode_set_params; + +#define REBOOT_MODE_SET_OPTIONS() \ +OPT_UINTEGER('m', "reboot_mode", &reboot_mode_set_params.reboot_mode, "0:CXL-IO-MEM or 0xCE:CXL-IO") + +static const struct option cmd_reboot_mode_set_options[] = { + BASE_OPTIONS(), + REBOOT_MODE_SET_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_curr_cxl_boot_mode_get_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static struct _pcie_eye_run_params { + u32 lane; + u32 sw_scan; + u32 ber; + bool verbose; +} pcie_eye_run_params; + +#define PCIE_EYE_RUN_OPTIONS() \ +OPT_UINTEGER('l', "lane", &pcie_eye_run_params.lane, "LANE ID"), \ +OPT_UINTEGER('s', "sw_scan", &pcie_eye_run_params.sw_scan, "SW SCAN"), \ +OPT_UINTEGER('b', "ber", &pcie_eye_run_params.ber, "BER") + +static const struct option cmd_pcie_eye_run_options[] = { + BASE_OPTIONS(), + PCIE_EYE_RUN_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_pcie_eye_status_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static struct _pcie_eye_get_params { + u32 sw_scan; + u32 ber; + bool verbose; +} pcie_eye_get_params; + +#define PCIE_EYE_GET_OPTIONS() \ +OPT_UINTEGER('s', "sw_scan", &pcie_eye_get_params.sw_scan, "SW SCAN"), \ +OPT_UINTEGER('b', "ber", &pcie_eye_get_params.ber, "BER") + +static const struct option cmd_pcie_eye_get_options[] = { + BASE_OPTIONS(), + PCIE_EYE_GET_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_get_cxl_link_status_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_get_device_info_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_read_ddr_temp_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_cxl_hpa_to_dpa_options[] = { + BASE_OPTIONS(), + HPA_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_get_cxl_membridge_errors_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static struct _get_ddr_bw_params { + u32 timeout; + u32 iterations; + bool verbose; +} get_ddr_bw_params; + +#define GET_DDR_BW_OPTIONS() \ +OPT_UINTEGER('t', "temeout", &get_ddr_bw_params.timeout, "Timeout"), \ +OPT_UINTEGER('i', "iterations", &get_ddr_bw_params.iterations, "No Iterations") + +static const struct option cmd_get_ddr_bw_options[] = { + BASE_OPTIONS(), + GET_DDR_BW_OPTIONS(), + OPT_END(), +}; + +static struct _get_ddr_latency_params { + u32 measure_time; + bool verbose; +} get_ddr_latency_params; + +#define GET_DDR_LATENCY_OPTIONS() \ +OPT_UINTEGER('t', "measure time", &get_ddr_latency_params.measure_time, "Measure Time in msec") + +static const struct option cmd_get_ddr_latency_options[] = { + BASE_OPTIONS(), + GET_DDR_LATENCY_OPTIONS(), + OPT_END(), +}; + +static struct _i2c_read_params { + u32 slave_addr; + u32 reg_addr; + u32 num_bytes; + bool verbose; +} i2c_read_params; + +#define I2C_READ_OPTIONS() \ +OPT_UINTEGER('s', "slave_addr", &i2c_read_params.slave_addr, "Slave addr"), \ +OPT_UINTEGER('r', "reg_addr", &i2c_read_params.reg_addr, "Reg addr"), \ +OPT_UINTEGER('n', "num_bytes", &i2c_read_params.num_bytes, "Number of bytes") + +static const struct option cmd_i2c_read_options[] = { + BASE_OPTIONS(), + I2C_READ_OPTIONS(), + OPT_END(), +}; + +static struct _i2c_write_params { + u32 slave_addr; + u32 reg_addr; + u32 data; + bool verbose; +} i2c_write_params; + +#define I2C_WRITE_OPTIONS() \ +OPT_UINTEGER('s', "slave_addr", &i2c_write_params.slave_addr, "Slave addr"), \ +OPT_UINTEGER('r', "reg_addr", &i2c_write_params.reg_addr, "Reg addr"), \ +OPT_UINTEGER('d', "data", &i2c_write_params.data, "Data") + +static const struct option cmd_i2c_write_options[] = { + BASE_OPTIONS(), + I2C_WRITE_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_get_ddr_ecc_err_info_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_start_ddr_ecc_scrub_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_ddr_ecc_scrub_status_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_ddr_cont_scrub_status_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static struct _ddr_cont_scrub_set_params { + u32 cont_scrub_status; +} ddr_cont_scrub_set_params; + +#define DDR_CONT_SCRUB_SET_OPTIONS() \ +OPT_UINTEGER('i', "cont_scrub_status", &ddr_cont_scrub_set_params.cont_scrub_status, "Continuous Scrub ON:1 OFF: 0") + +static const struct option cmd_ddr_cont_scrub_set_options[] = { + BASE_OPTIONS(), + DDR_CONT_SCRUB_SET_OPTIONS(), + OPT_END(), +}; + + +static const struct option cmd_ddr_init_status_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_get_cxl_membridge_stats_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_trigger_coredump_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static struct _ddr_err_inj_en_params { + u32 ddr_id; + u32 err_type; + u64 ecc_fwc_mask; + bool verbose; +} ddr_err_inj_en_params; + +#define DDR_ERR_INJ_EN_OPTIONS() \ +OPT_UINTEGER('d', "ddr_id", &ddr_err_inj_en_params.ddr_id, "ddr id <0-DDR_CTRL0,1-DDR_CTRL1>"), \ +OPT_UINTEGER('t', "err_type", &ddr_err_inj_en_params.err_type, "error type\n\t\t\t0: AXI bus parity READ ADDR\n\t\t\t1: AXI bus parity WRITE ADDR\n\t\t\t2: AXI bus parity WRITE DATA\n\t\t\t3: CA bus parity\n\t\t\t4: ECC correctable\n\t\t\t5: ECC uncorrectable\n\t\t\t6: ECC SCRUB"), \ +OPT_U64('m', "ecc_fwc_mask", &ddr_err_inj_en_params.ecc_fwc_mask, "ecc fwc mask <35bit value, upto two bit set for correctable ecc error\n\t\t\tAtleast 4bits for uncoorectable ecc errors\n>") + +static const struct option cmd_ddr_err_inj_en_options[] = { + BASE_OPTIONS(), + DDR_ERR_INJ_EN_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_ddr_dimm_level_training_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static struct _ddr_set_params { + u32 ddr_interleave_sz; + u32 ddr_interleave_ctrl_choice; +} ddr_set_params; + +#define DDR_PARAM_SET_OPTIONS() \ + OPT_UINTEGER('m', "ddr_interleave_sz", &ddr_set_params.ddr_interleave_sz, "Intereleave SZ is: 2 pow m. Input the value of m as the Size"), \ + OPT_UINTEGER('n', "ddr_interleave_ctrl_choice", &ddr_set_params.ddr_interleave_ctrl_choice, "CTRL Choice: 1=DDR0 2=DDR1 3= DDR0 and DDR1") + +static const struct option cmd_ddr_param_set_options[] = { + BASE_OPTIONS(), + DDR_PARAM_SET_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_ddr_param_get_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static struct _ddr_core_volt_set_params { + u32 val1; + u32 val2; + u32 val3; +} ddr_core_volt_set_params; + +#define CORE_VOLT_SET_OPTIONS() \ +OPT_UINTEGER('i', "core_volt_val1", &ddr_core_volt_set_params.val1, "CORE Voltage val1.val2 val3"), \ +OPT_UINTEGER('m', "core_volt_val2", &ddr_core_volt_set_params.val2, "CORE Voltage val1.val2 val3"), \ +OPT_UINTEGER('n', "core_volt_val3", &ddr_core_volt_set_params.val3, "CORE Voltage val1.val2 val3") + +static const struct option cmd_core_volt_set_options[] = { + BASE_OPTIONS(), + CORE_VOLT_SET_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_core_volt_get_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static struct _oem_err_inj_viral_params { + u32 viral_type; + bool verbose; +} oem_err_inj_viral_params; + +#define OEM_ERR_INJ_VIRAL_OPTIONS() \ +OPT_UINTEGER('l', "viral_type", &oem_err_inj_viral_params.viral_type, "viral_type") + +static const struct option cmd_oem_err_inj_viral_options[] = { + BASE_OPTIONS(), + OEM_ERR_INJ_VIRAL_OPTIONS(), + OPT_END(), +}; + +static struct _err_inj_ll_poison_params { + u32 en_dis; + u32 ll_err_type; + bool verbose; +} err_inj_ll_poison_params; + +#define ERR_INJ_LL_POISON_OPTIONS() \ +OPT_UINTEGER('e', "en_dis", &err_inj_ll_poison_params.en_dis, "enable_disable 0=dis,1=en"), \ +OPT_UINTEGER('l', "ll_err_type", &err_inj_ll_poison_params.ll_err_type, "link level err type 0=mem-poison") + +static const struct option cmd_err_inj_ll_poison_options[] = { + BASE_OPTIONS(), + ERR_INJ_LL_POISON_OPTIONS(), + OPT_END(), +}; + +static struct _pci_err_in_params { + u32 en_dis; + u32 err_type; + u32 err_subtype; + u32 count; + u32 opt_param1; + u32 opt_param2; + bool verbose; +} pci_err_inj_params; + +#define PCI_ERR_INJ_OPTIONS() \ +OPT_UINTEGER('e', "en_dis", &pci_err_inj_params.en_dis, "enable_disable:\n\t0=disable inj\n\t1=enable inj"), \ +OPT_UINTEGER('l', "err_type", &pci_err_inj_params.err_type, "err inj type Group:\n\t0:CRC ERR\n\t1:SEQ NUM ERR\n\t2:DLLP ERR\n\t3:SYMBOL ERR\n\t4:FC CREDIT ERR\n\t5:Special TLP ERR\n"), \ +OPT_UINTEGER('s', "err_subtype", &pci_err_inj_params.err_subtype, "err inj sub-type:\n\tGroup-0:\n\t\t0 = TX_TLP_LCRC_ERR\n\t\t1 = TX_16B_CRC_ERR_ACK_NAK_DLLP\n\t\t2 = TX_16B_CRC_ERR_UPD_FC\n\t\t3 = TX_TLP_ECRC_ERR\n\t\t4 = TX_FCRC_ERR_TLP\n\t\t5 = TX_PARITY_TSOS_ERR\n\t\t6 = TX_PARITY_SKPOS_ERR\n\t\t8 = RX_LCRC_ERR\n\t\t11= RX_ECRC_ERR\n\n\tGroup-1:\n\t\t0 = TLP_ERR_SEQNUM\n\t\t1 = ACK_NAK_DLLP_ERR_SEQNUM\n\n\tGroup-2:\n\t\t0 = ACK_NACK_DLLP\n\t\t1 = UPD_FC_DLLP\n\t\t2 = NAK_DLLP\n\n\tGroup-3:\n\t\t0 = RSVD_OR_INVRT_SYNC_HDR\n\t\t1 = COM_PAD_TS1\n\t\t2 = COM_PAD_TS2\n\t\t3 = COM_FTS\n\t\t4 = COM_IDL\n\t\t5 = END_EDB\n\t\t6 = STP_SDP\n\t\t7 = COM_SKP\n\n\tGroup-4:\n\t\t0 = POSTED_TLP_HDR\n\t\t1 = NON_POSTED_TLP_HDR\n\t\t2 = CMPL_TLP_HDR\n\t\t4 = POSTED_TLP_DATA\n\t\t5 = NON_POSTED_TLP_DATA\n\n\tGroup-5:\n\t\t0 = DUPLICATE_DLLP\n\t\t1 = NULLIFIED_TLP\n"), \ +OPT_UINTEGER('c', "count", &pci_err_inj_params.count, "err inj count:\n\t1-255: count of err to inject\n\t0: continuous inj until disable\n"), \ +OPT_UINTEGER('x', "opt1", &pci_err_inj_params.opt_param1, "opt1: Optional Extra args1\n\tFor Group-1:Bad Sequence Number(2s compliment in hex): Min:0x1001, Max:0xfff\n\tFor Group-4:Bad update-FC credit val(2s compliment in hex): Min:0x1001, Max:0xfff\n\tFor other Groups: Pass value '0'\n"), \ +OPT_UINTEGER('y', "opt2", &pci_err_inj_params.opt_param2, "opt2: Optional Extra args2\n\tGroup-4::Target VC_NUMBER: Min:0, Max:7\n\tFor other Groups:Pass value '0'\n") + +static const struct option cmd_pci_err_inj_options[] = { + BASE_OPTIONS(), + PCI_ERR_INJ_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_read_ltssm_states_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static struct page_policy_selection { + int page_policy_reg_val; +} page_policy_select; + +#define DDR_PAGE_SELECT_SET_OPTIONS() \ + OPT_INTEGER('p', "page_policy_reg_val", &page_policy_select.page_policy_reg_val, "Value for page policy selection") + +static const struct option cmd_ddr_page_select_set_options[] = { + BASE_OPTIONS(), + DDR_PAGE_SELECT_SET_OPTIONS(), + OPT_END(), +}; + +static const struct option cmd_ddr_page_select_get_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + static int action_cmd_clear_event_records(struct cxl_memdev *memdev, struct action_context *actx) { u16 record_handle; @@ -2133,10 +2551,16 @@ static int action_cmd_update_fw(struct cxl_memdev *memdev, struct action_context } offset = 0; - if (update_fw_params.hbo) { - opcode = 0xCD01; // Pioneer vendor opcode for hbo-transfer-fw + + if (fw_img_params.is_os) { + printf("firmware update selected for OS Image\n"); + opcode = 0xCD04; // Vistara opcode for OS(boot1) image update } else { - opcode = 0x0201; // Spec defined transfer-fw + if (update_fw_params.hbo) { + opcode = 0xCD01; // Pioneer vendor opcode for hbo-transfer-fw + } else { + opcode = 0x0201; // Spec defined transfer-fw + } } for (int i = 0; i < num_blocks; i++) @@ -2248,15 +2672,15 @@ static int action_cmd_set_event_interrupt_policy(struct cxl_memdev *memdev, stru return cxl_memdev_set_event_interrupt_policy(memdev, interrupt_policy_params.policy); } -static int action_cmd_get_cel_log(struct cxl_memdev *memdev, struct action_context *actx) +static int action_cmd_get_log(struct cxl_memdev *memdev, struct action_context *actx) { if (cxl_memdev_is_active(memdev)) { - fprintf(stderr, "%s: memdev active, get_cel_log\n", + fprintf(stderr, "%s: memdev active, get_log\n", cxl_memdev_get_devname(memdev)); return -EBUSY; } - return cxl_memdev_get_cel_log(memdev, log_uuid.uuid); + return cxl_memdev_get_log(memdev, log_uuid.uuid, log_size.size); } static int action_cmd_get_supported_logs(struct cxl_memdev *memdev, struct action_context *actx) @@ -2358,7 +2782,7 @@ static int action_cmd_get_fw_info(struct cxl_memdev *memdev, struct action_conte return -EBUSY; } - return cxl_memdev_get_fw_info(memdev); + return cxl_memdev_get_fw_info(memdev, fw_img_params.is_os); } static int action_cmd_activate_fw(struct cxl_memdev *memdev, struct action_context *actx) @@ -3463,32 +3887,594 @@ static int action_cmd_dimm_slot_info(struct cxl_memdev *memdev, struct action_co return cxl_memdev_dimm_slot_info(memdev); } -static int action_write(struct cxl_memdev *memdev, struct action_context *actx) +static int action_cmd_pmic_vtmon_info(struct cxl_memdev *memdev, struct action_context *actx) { - size_t size = param.len, read_len; - unsigned char *buf; - int rc; + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort pmic_vtmon_info\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } - if (cxl_memdev_is_active(memdev)) { - fprintf(stderr, "%s is active, abort label write\n", - cxl_memdev_get_devname(memdev)); - return -EBUSY; - } + return cxl_memdev_pmic_vtmon_info(memdev); +} - if (!size) { - size_t lsa_size = cxl_memdev_get_lsa_size(memdev); +static int action_cmd_ddr_margin_run(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr_margin_run\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } - fseek(actx->f_in, 0L, SEEK_END); - size = ftell(actx->f_in); - fseek(actx->f_in, 0L, SEEK_SET); + return cxl_memdev_ddr_margin_run(memdev, ddr_margin_run_params.slice_num, + ddr_margin_run_params.rd_wr_margin, + ddr_margin_run_params.ddr_id); +} - if (size > lsa_size) { - fprintf(stderr, - "File size (%zu) greater than LSA size (%zu), aborting\n", - size, lsa_size); - return -EINVAL; - } - } +static int action_cmd_ddr_margin_status(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr_margin_status\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_ddr_margin_status(memdev); +} + +static int action_cmd_ddr_margin_get(struct cxl_memdev *memdev, + struct action_context *actx) +{ + int rc = 0; + + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr_margin_get\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + rc = cxl_memdev_ddr_margin_get(memdev); + if(rc) + { + fprintf(stderr, + "ddr_margin_get read failed"); + goto abort; + } + +abort: + return rc; +} + +static int action_cmd_ddr_stats_run(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr_stats_run\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_ddr_stats_run(memdev, ddr_stats_run_params.ddr_id, + ddr_stats_run_params.monitor_time, + ddr_stats_run_params.loop_count); +} + +static int action_cmd_ddr_stats_get(struct cxl_memdev *memdev, + struct action_context *actx) +{ + int rc = 0; + + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr_stats_get\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + rc = cxl_memdev_ddr_stats_get(memdev); + if(rc) + { + fprintf(stderr, + "ddr_stats_get read failed"); + goto abort; + } + +abort: + return rc; +} + +static int action_cmd_reboot_mode_set(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort reboot mode set\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_reboot_mode_set(memdev, reboot_mode_set_params.reboot_mode); +} + +static int action_cmd_curr_cxl_boot_mode_get(struct cxl_memdev *memdev, + struct action_context *actx) +{ + int rc = 0; + + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort curr cxl boot mode get\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + rc = cxl_memdev_curr_cxl_boot_mode_get(memdev); + if(rc) + { + fprintf(stderr, + "curr_cxl_boot_mode_get failed"); + goto abort; + } + +abort: + return rc; +} + +static int action_cmd_pcie_eye_run(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort pcie_eye_run\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_pcie_eye_run(memdev, pcie_eye_run_params.lane, + pcie_eye_run_params.sw_scan, + pcie_eye_run_params.ber); +} + +static int action_cmd_pcie_eye_status(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort pcie_eye_status\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_pcie_eye_status(memdev); +} + +static int action_cmd_pcie_eye_get(struct cxl_memdev *memdev, + struct action_context *actx) +{ + #define NUM_EYESCOPE_VERT_VALS 511 + #define TOTAL_EYESCOPE_VERT_VALS ((NUM_EYESCOPE_VERT_VALS * 2) + 1) + #define VERT_SKIP 15 + + int rc = 0; + + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort pcie_eye_get\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + if(pcie_eye_get_params.sw_scan) { + for (int i = 0; i < TOTAL_EYESCOPE_VERT_VALS; i += VERT_SKIP) { + rc = cxl_memdev_pcie_eye_get_sw(memdev, i); + if (rc != 0) + { + fprintf(stderr, + "pcie_eye_get read failed or sw_scan not enabled\n"); + goto abort; + } + } + if(pcie_eye_get_params.ber) { + rc = cxl_memdev_pcie_eye_get_sw_ber(memdev); + if (rc != 0) + { + fprintf(stderr, + "pcie_eye_get read failed OR BER is not enabled\n"); + goto abort; + } + } + } else { + rc = cxl_memdev_pcie_eye_get_hw(memdev); + if(rc) + { + fprintf(stderr, + "pcie_eye_get read failed hw scan not enabled"); + goto abort; + } + } +abort: + return rc; +} + +static int action_cmd_get_cxl_link_status(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort get_cxl_link_status\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_get_cxl_link_status(memdev); +} + +static int action_cmd_get_device_info(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort get_device_info\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_get_device_info(memdev); +} + +static int action_cmd_read_ddr_temp(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort read_ddr_temp\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_read_ddr_temp(memdev); +} + +static int action_cmd_cxl_hpa_to_dpa(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort hpa to dpa\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_cxl_hpa_to_dpa(memdev, hpa_address); +} + +static int action_cmd_get_cxl_membridge_errors(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort cxl membridge errors\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_get_cxl_membridge_errors(memdev); +} + +static int action_cmd_get_ddr_bw(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort get_ddr_bw\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_get_ddr_bw(memdev, get_ddr_bw_params.timeout, get_ddr_bw_params.iterations); +} + +static int action_cmd_get_ddr_latency(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort get_ddr_latency\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_get_ddr_latency(memdev, get_ddr_latency_params.measure_time); +} + +static int action_cmd_i2c_read(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort i2c_read\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_i2c_read(memdev, i2c_read_params.slave_addr, i2c_read_params.reg_addr, i2c_read_params.num_bytes); +} + +static int action_cmd_i2c_write(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort i2c_write\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_i2c_write(memdev, i2c_write_params.slave_addr, i2c_write_params.reg_addr, i2c_write_params.data); +} + +static int action_cmd_get_ddr_ecc_err_info(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort get-ddr-ecc-err-info\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_get_ddr_ecc_err_info(memdev); +} + +static int action_cmd_start_ddr_ecc_scrub(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort start-ddr-ecc-scrub\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_start_ddr_ecc_scrub(memdev); +} + +static int action_cmd_ddr_ecc_scrub_status(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr-ecc-scrub-status\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_ddr_ecc_scrub_status(memdev); +} + +static int action_cmd_ddr_cont_scrub_status(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr-cont-scrub-status\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_ddr_cont_scrub_status(memdev); +} + +static int action_cmd_ddr_cont_scrub_set(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr-cont-scrub-set\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_ddr_cont_scrub_set(memdev, + ddr_cont_scrub_set_params.cont_scrub_status); +} + +static int action_cmd_ddr_init_status(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr-init-status\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + return cxl_memdev_ddr_init_status(memdev); +} + +static int action_cmd_get_cxl_membridge_stats(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort cxl membridge stats\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + return cxl_memdev_get_cxl_membridge_stats(memdev); +} + +static int action_cmd_trigger_coredump(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr-ecc-scrub-status\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_trigger_coredump(memdev); +} + +static int action_cmd_ddr_err_inj_en(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr-err-inj-en\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_ddr_err_inj_en(memdev, ddr_err_inj_en_params.ddr_id, ddr_err_inj_en_params.err_type, ddr_err_inj_en_params.ecc_fwc_mask); +} + +static int action_cmd_ddr_dimm_level_training_status(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr-dimm-level-training-status\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_ddr_dimm_level_training_status(memdev); +} + +static int action_cmd_ddr_param_set(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr_param_set\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_ddr_param_set(memdev, ddr_set_params.ddr_interleave_sz, + ddr_set_params.ddr_interleave_ctrl_choice); +} + +static int action_cmd_ddr_param_get(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr_param_get\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_ddr_param_get(memdev); +} + +static int action_cmd_core_volt_set(struct cxl_memdev *memdev, + struct action_context *actx) +{ + float volt; + + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort core_volt_set\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + volt = ddr_core_volt_set_params.val1 + (ddr_core_volt_set_params.val2 / 10.0) + + (ddr_core_volt_set_params.val3 / 100.0); + + return cxl_memdev_core_volt_set(memdev, volt); +} + +static int action_cmd_core_volt_get(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort core_volt_get\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_core_volt_get(memdev); +} + +static int action_cmd_oem_err_inj_viral(struct cxl_memdev *memdev, struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort oem_err_inj_viral\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_oem_err_inj_viral(memdev, oem_err_inj_viral_params.viral_type); +} + +static int action_cmd_err_inj_ll_poison(struct cxl_memdev *memdev, struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort err_inj_ll_poison\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_err_inj_ll_poison(memdev, err_inj_ll_poison_params.en_dis, + err_inj_ll_poison_params.ll_err_type); +} + +static int action_cmd_pci_err_inj(struct cxl_memdev *memdev, struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort err_inj_ll_poison\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_pci_err_inj(memdev, pci_err_inj_params.en_dis, + pci_err_inj_params.err_type, + pci_err_inj_params.err_subtype, + pci_err_inj_params.count, + pci_err_inj_params.opt_param1, + pci_err_inj_params.opt_param2); +} + +static int action_cmd_read_ltssm_states(struct cxl_memdev *memdev, struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort read-ltssm-state-changes\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_read_ltssm_states(memdev); +} + + +static int action_cmd_ddr_page_select_set(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr_param_set\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_ddr_page_select_set(memdev, page_policy_select.page_policy_reg_val); +} + +static int action_cmd_ddr_page_select_get(struct cxl_memdev *memdev, + struct action_context *actx) +{ + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s: memdev active, abort ddr_param_get\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_ddr_page_select_get(memdev); +} + + +static int action_write(struct cxl_memdev *memdev, struct action_context *actx) +{ + size_t size = param.len, read_len; + unsigned char *buf; + int rc; + + if (cxl_memdev_is_active(memdev)) { + fprintf(stderr, "%s is active, abort label write\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + if (!size) { + size_t lsa_size = cxl_memdev_get_lsa_size(memdev); + + fseek(actx->f_in, 0L, SEEK_END); + size = ftell(actx->f_in); + fseek(actx->f_in, 0L, SEEK_SET); + + if (size > lsa_size) { + fprintf(stderr, + "File size (%zu) greater than LSA size (%zu), aborting\n", + size, lsa_size); + return -EINVAL; + } + } buf = calloc(1, size); if (!buf) @@ -3707,10 +4693,10 @@ int cmd_get_supported_logs(int argc, const char **argv, struct cxl_ctx *ctx) return rc >= 0 ? 0 : EXIT_FAILURE; } -int cmd_get_cel_log(int argc, const char **argv, struct cxl_ctx *ctx) +int cmd_get_log(int argc, const char **argv, struct cxl_ctx *ctx) { - int rc = memdev_action(argc, argv, ctx, action_cmd_get_cel_log, cmd_get_cel_log_options, - "cxl get-cel-log [..] []"); + int rc = memdev_action(argc, argv, ctx, action_cmd_get_log, cmd_get_log_options, + "cxl get-log [..] []"); return rc >= 0 ? 0 : EXIT_FAILURE; } @@ -4528,3 +5514,321 @@ int cmd_dimm_slot_info(int argc, const char **argv, struct cxl_ctx *ctx) return rc >= 0 ? 0 : EXIT_FAILURE; } + +int cmd_pmic_vtmon_info(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_pmic_vtmon_info, cmd_pmic_vtmon_info_options, + "cxl pmic-vtmon-info [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_margin_run(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_margin_run, cmd_ddr_margin_run_options, + "cxl ddr-margin-run [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_margin_status(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_margin_status, cmd_ddr_margin_status_options, + "cxl ddr-margin-status [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_margin_get(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_margin_get, cmd_ddr_margin_get_options, + "cxl ddr-margin-get [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_stats_run(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_stats_run, cmd_ddr_stats_run_options, + "cxl ddr-stats-run [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_stats_get(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_stats_get, cmd_ddr_stats_get_options, + "cxl ddr-stats-get [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_curr_cxl_boot_mode_get(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_curr_cxl_boot_mode_get, cmd_curr_cxl_boot_mode_get_options, + "cxl curr-cxl-boot-mode-get [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_reboot_mode_set(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_reboot_mode_set, cmd_reboot_mode_set_options, + "cxl reboot-mode-set [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_pcie_eye_run(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_pcie_eye_run, cmd_pcie_eye_run_options, + "cxl pcie-eye-run [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_pcie_eye_status(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_pcie_eye_status, cmd_pcie_eye_status_options, + "cxl pcie-eye-status [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_pcie_eye_get(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_pcie_eye_get, cmd_pcie_eye_get_options, + "cxl pcie-eye-get [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_get_cxl_link_status(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_get_cxl_link_status, cmd_get_cxl_link_status_options, + "cxl get_cxl_link_status [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_get_device_info(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_get_device_info, cmd_get_device_info_options, + "cxl get_device_info [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_read_ddr_temp(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_read_ddr_temp, cmd_read_ddr_temp_options, + "cxl read_ddr_temp [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_cxl_hpa_to_dpa(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_cxl_hpa_to_dpa, cmd_cxl_hpa_to_dpa_options, + "cxl hpa to dpa"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_get_cxl_membridge_errors(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_get_cxl_membridge_errors, cmd_get_cxl_membridge_errors_options, + "cxl get_cxl_membridge_errors"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_get_ddr_bw(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_get_ddr_bw, cmd_get_ddr_bw_options, + "cxl get-ddr-bw [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_get_ddr_latency(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_get_ddr_latency, cmd_get_ddr_latency_options, + "cxl get-ddr-latency [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_i2c_read(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_i2c_read, cmd_i2c_read_options, + "cxl i2c-read [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_i2c_write(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_i2c_write, cmd_i2c_write_options, + "cxl i2c-write [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_get_ddr_ecc_err_info(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_get_ddr_ecc_err_info, cmd_get_ddr_ecc_err_info_options, + "cxl get-ddr-ecc-err-info [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_start_ddr_ecc_scrub(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_start_ddr_ecc_scrub, cmd_start_ddr_ecc_scrub_options, + "cxl start-ddr-ecc-scrub [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_ecc_scrub_status(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_ecc_scrub_status, cmd_ddr_ecc_scrub_status_options, + "cxl ddr-ecc-scrub-status [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_cont_scrub_status(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_cont_scrub_status, cmd_ddr_cont_scrub_status_options, + "cxl ddr-cont-scrub-status [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_cont_scrub_set(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_cont_scrub_set, cmd_ddr_cont_scrub_set_options, + "cxl core_volt_set [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_init_status(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_init_status, cmd_ddr_init_status_options, + "cxl ddr-init-status [..] []"); + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_get_cxl_membridge_stats(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_get_cxl_membridge_stats, cmd_get_cxl_membridge_stats_options, + "cxl get_cxl_membridge_errors"); + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_trigger_coredump(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_trigger_coredump, cmd_trigger_coredump_options, + "cxl trigger-coredump [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_err_inj_en(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_err_inj_en, cmd_ddr_err_inj_en_options, + "cxl ddr-err-inj-en [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_dimm_level_training_status(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_dimm_level_training_status, cmd_ddr_dimm_level_training_options, + "cxl ddr-dimm-level-training-status [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_param_set(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_param_set, cmd_ddr_param_set_options, + "cxl ddr_param_set [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_param_get(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_param_get, cmd_ddr_param_get_options, + "cxl ddr_param_get [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_core_volt_set(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_core_volt_set, cmd_core_volt_set_options, + "cxl core_volt_set [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_core_volt_get(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_core_volt_get, cmd_core_volt_get_options, + "cxl core_volt_get [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_oem_err_inj_viral(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_oem_err_inj_viral, cmd_oem_err_inj_viral_options, + "cxl oem_err_inj_viral [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_err_inj_ll_poison(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_err_inj_ll_poison, cmd_err_inj_ll_poison_options, + "cxl err_inj_ll_poison [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_pci_err_inj(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_pci_err_inj, cmd_pci_err_inj_options, + "cxl pci_err_inj [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_read_ltssm_states(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_read_ltssm_states, cmd_read_ltssm_states_options, + "cxl read-ltssm-state-changes [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_page_select_set(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_page_select_set, cmd_ddr_page_select_set_options, + "cxl ddr-page-select-set < [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_ddr_page_select_get(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int rc = memdev_action(argc, argv, ctx, action_cmd_ddr_page_select_get, cmd_ddr_page_select_get_options, + "cxl ddr-page-select-get [..] []"); + + return rc >= 0 ? 0 : EXIT_FAILURE; +}