diff --git a/SOURCES/facebookexperimental-diff-ffc9245-40fc652.patch b/SOURCES/facebookexperimental-diff-ffc9245-40fc652.patch
new file mode 100644
index 0000000..ca43613
--- /dev/null
+++ b/SOURCES/facebookexperimental-diff-ffc9245-40fc652.patch
@@ -0,0 +1,6383 @@
+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 <mem0> [<mem1>..<memN>] [<options>]");
++	int rc = memdev_action(argc, argv, ctx, action_cmd_get_log, cmd_get_log_options,
++			"cxl get-log <mem0> [<mem1>..<memN>] [<options>]");
+ 
+ 	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 <stdbool.h>
+ #include <stdarg.h>
+ #include <unistd.h>
+ #include <sys/types.h>
+@@ -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", &param.len, "number of label bytes to operate"), \
+ OPT_UINTEGER('O', "offset", &param.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:<CRC Error>\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:<SEQ NUM Error>\n\t\t0 = TLP_ERR_SEQNUM\n\t\t1 = ACK_NAK_DLLP_ERR_SEQNUM\n\n\tGroup-2:<DLLP Error>\n\t\t0 = ACK_NACK_DLLP\n\t\t1 = UPD_FC_DLLP\n\t\t2 = NAK_DLLP\n\n\tGroup-3:<Symbol Error>\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:<FC Credit Error>\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:<Special TLP Error>\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:<FC Credit Error>: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 <mem0> [<mem1>..<memN>] [<options>]");
++  int rc = memdev_action(argc, argv, ctx, action_cmd_get_log, cmd_get_log_options,
++      "cxl get-log <mem0> [<mem1>..<memN>] [<options>]");
+ 
+   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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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  <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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  <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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  <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <<mem0> [<mem1>..<memN>] [<options>]");
++
++  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 <mem0> [<mem1>..<memN>] [<options>]");
++
++  return rc >= 0 ? 0 : EXIT_FAILURE;
++}
diff --git a/SPECS/ndctl.spec b/SPECS/ndctl.spec
index 3843277..f9fb0c8 100644
--- a/SPECS/ndctl.spec
+++ b/SPECS/ndctl.spec
@@ -1,6 +1,6 @@
 Name:		ndctl
 Version:	71.1
-Release:	8.1%{?dist}
+Release:	8.2%{?dist}
 Summary:	Manage "libnvdimm" subsystem devices (Non-volatile Memory)
 License:	GPLv2
 Url:		https://github.com/pmem/ndctl
@@ -14,6 +14,7 @@ Patch0:         elake-diff-ea014c0-3ff031d.patch
 Patch1:         elake-c5d4db-7fcbe3.patch
 # Another `git diff` patch
 Patch2:         elake-diff-bafc29a0-df411ebe.patch
+Patch3:         facebookexperimental-diff-ffc9245-40fc652.patch
 %else
 Patch0: 0003-ndctl-test-Fix-btt-expect-table-compile-warning.patch
 Patch1: 0004-ndctl-test-Cleanup-unnecessary-out-label.patch
@@ -410,6 +411,9 @@ make check
 
 
 %changelog
+* Sun May 19 2024 Anita Zhang <the.anitazha@gmail.com> - 71.1-8.2
+- Patch ffc9245..40fc652 from facebookexperimental/ndctl for hs+fb
+
 * Fri Aug 04 2023 Anita Zhang <the.anitazha@gmail.com> - 71.1-8.1
 - Sync 71.1-8 from c9 branch.
 - Patch bafc29a0..df411ebe from elake/ndctl fork for hs+fb