From 88d66ac7fcf72826e2b90548ab307fee506f44b9 Mon Sep 17 00:00:00 2001 From: Anita Zhang Date: Feb 24 2023 03:26:39 +0000 Subject: 71.1-4.2: Patch SPD decoding and dimm_slot_info CCI command support --- diff --git a/SOURCES/elake-c5d4db-7fcbe3.patch b/SOURCES/elake-c5d4db-7fcbe3.patch new file mode 100644 index 0000000..f4d9738 --- /dev/null +++ b/SOURCES/elake-c5d4db-7fcbe3.patch @@ -0,0 +1,428 @@ +From c5d4db8ba7b2f3964f12bcde5d8fa5f27aa6c500 Mon Sep 17 00:00:00 2001 +From: Hiral Patel +Date: Sat, 18 Feb 2023 01:03:11 -0800 +Subject: [PATCH 1/3] Added SPD decoding and dimm_slot_info CCI command support + +--- + cxl/builtin.h | 1 + + cxl/cxl.c | 1 + + cxl/lib/libcxl.c | 154 +++++++++++++++++++++++++++++++++++---------- + cxl/lib/libcxl.sym | 1 + + cxl/libcxl.h | 1 + + cxl/memdev.c | 24 +++++++ + 6 files changed, 149 insertions(+), 33 deletions(-) + +diff --git a/cxl/builtin.h b/cxl/builtin.h +index ca8be68..5775f4a 100644 +--- a/cxl/builtin.h ++++ b/cxl/builtin.h +@@ -115,4 +115,5 @@ int cmd_osa_misc_trig_cfg(int argc, const char **argv, struct cxl_ctx *ctx); + 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); + #endif /* _CXL_BUILTIN_H_ */ +diff --git a/cxl/cxl.c b/cxl/cxl.c +index e5b5732..4b430b5 100644 +--- a/cxl/cxl.c ++++ b/cxl/cxl.c +@@ -171,6 +171,7 @@ static struct cmd_struct commands[] = { + { "osa-data-read", .c_fn = cmd_osa_data_read }, + { "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 }, + }; + + int main(int argc, const char **argv) +diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c +index cd9fcb5..a65f14a 100644 +--- a/cxl/lib/libcxl.c ++++ b/cxl/lib/libcxl.c +@@ -9646,6 +9646,26 @@ struct cxl_mbox_dimm_spd_read_in { + __le32 num_bytes; + } __attribute__((packed)); + ++#define SPD_MODULE_SERIAL_NUMBER_LEN (328 - 325 + 1) // 4 Bytes ++ ++void static ++IntToString (u8 *String, u8 *Integer, u8 SizeInByte) { ++ u8 Index; ++ ++ for (Index = 0; Index < SizeInByte; Index++) { ++ *(String + Index * 2) = (*(Integer + Index) >> 4) & 0x0F; ++ *(String + Index * 2 + 1) = *(Integer + Index) & 0x0F; ++ } ++ for (Index = 0; Index < (SizeInByte * 2); Index++) { ++ if (*(String + Index) >= 0x0A) { ++ *(String + Index) += 0x37; ++ } else { ++ *(String + Index) += 0x30; ++ } ++ } ++ *(String + SizeInByte * 2) = 0x0; ++} ++ + static char * decode_ddr4_module_type(u8 *bytes) { + char *type; + switch (bytes[3]) { +@@ -9670,23 +9690,17 @@ static float ddr4_mtb_ftb_calc(unsigned char b1, signed char b2) { + return b1 * mtb + b2 * ftb; + } + +-static void decode_ddr4_module_speed(u8 *bytes, float *ddr_clock, int *pc4_speed) { ++static int decode_ddr4_module_speed(u8 *bytes) { + float ctime; + float ddrclk; +- int tbits, pcclk; + + ctime = ddr4_mtb_ftb_calc(bytes[18], bytes[125]); + ddrclk = 2 * (1000 / ctime); +- tbits = 8 << (bytes[13] & 7); +- +- pcclk = ddrclk * tbits / 8; +- pcclk -= pcclk % 100; + +- if (ddr_clock) { *ddr_clock = (int)ddrclk; } +- if (pc4_speed) { *pc4_speed = pcclk; } ++ return ddrclk; + } + +-static double decode_ddr4_module_size(u8 *bytes) { ++static int decode_ddr4_module_size(u8 *bytes) { + double size; + int sdrcap = 256 << (bytes[4] & 15); + int buswidth = 8 << (bytes[13] & 7); +@@ -9696,19 +9710,7 @@ static double decode_ddr4_module_size(u8 *bytes) { + + if (signal_loading == 2) lranks_per_dimm *= ((bytes[6] >> 4) & 7) + 1; + size = sdrcap / 8 * buswidth / sdrwidth * lranks_per_dimm; +- return size; +-} +- +- +-static char * decode_ddr4_module_detail(u8 *bytes) { +- char *type_detail = malloc(256); +- float ddr_clock; +- int pc4_speed; +- if (type_detail) { +- decode_ddr4_module_speed(bytes, &ddr_clock, &pc4_speed); +- snprintf(type_detail, 255, "DDR4-%.0f (PC4-%d)", ddr_clock, pc4_speed); +- } +- return type_detail; ++ return (int) size/1024; + } + + static char * decode_ddr4_manufacturer(u8 *bytes){ +@@ -9729,7 +9731,7 @@ static char * decode_ddr4_manufacturer(u8 *bytes){ + manufacturer = NULL; + return manufacturer; + } +- manufacturer = (char *) vendors[bank][index]; ++ manufacturer = (char *) vendors[bank][index-1]; + return manufacturer; + } + +@@ -9776,8 +9778,8 @@ static int decode_ram_type(u8 *bytes) { + + static const char *ram_types[] = {"Unknown", "Direct Rambus", "Rambus", "FPM DRAM", + "EDO", "Pipelined Nibble", "SDR SDRAM", "Multiplexed ROM", +- "DDR SGRAM", "DDR SDRAM", "DDR2 SDRAM", "DDR3 SDRAM", +- "DDR4 SDRAM"}; ++ "DDR SGRAM", "DDR SDRAM", "DDR2", "DDR3", ++ "DDR4"}; + + CXL_EXPORT int cxl_memdev_dimm_spd_read(struct cxl_memdev *memdev, + u32 spd_id, u32 offset, u32 num_bytes) +@@ -9787,7 +9789,9 @@ CXL_EXPORT int cxl_memdev_dimm_spd_read(struct cxl_memdev *memdev, + struct cxl_command_info *cinfo; + struct cxl_mbox_dimm_spd_read_in *dimm_spd_read_in; + u8 *dimm_spd_read_out; ++ u8 serial[9]; + int rc = 0; ++ int buswidth; + RamType ram_type; + + cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DIMM_SPD_READ_OPCODE); +@@ -9838,6 +9842,7 @@ CXL_EXPORT int cxl_memdev_dimm_spd_read(struct cxl_memdev *memdev, + + dimm_spd_read_out = (u8*)cmd->send_cmd->out.payload; + ram_type = decode_ram_type(dimm_spd_read_out); ++ + fprintf(stdout, "=========================== DIMM SPD READ Data ============================\n"); + fprintf(stdout, "Output Payload:"); + for(int i=0; isend_cmd->out.size; i++){ +@@ -9850,15 +9855,25 @@ CXL_EXPORT int cxl_memdev_dimm_spd_read(struct cxl_memdev *memdev, + fprintf(stdout, "%02x ", dimm_spd_read_out[i]); + } + } ++ + // Decoding SPD data for only DDR4 SDRAM. +- if (ram_type == DDR4_SDRAM) { +- fprintf(stdout, "\n\n"); +- fprintf(stdout, "DDR RAM Type: %s\n", ram_types[ram_type]); +- fprintf(stdout, "DDR Module Type: %s\n", decode_ddr4_module_type(dimm_spd_read_out)); +- fprintf(stdout, "DDR Module Size: %1f\n", decode_ddr4_module_size(dimm_spd_read_out)); +- fprintf(stdout, "DDR Module Detail: %s\n", decode_ddr4_module_detail(dimm_spd_read_out)); +- fprintf(stdout, "DDR Manufacturer: %s\n", decode_ddr4_manufacturer(dimm_spd_read_out)); +- } ++ ++ buswidth = 8 << (dimm_spd_read_out[13] & 7); ++ ++ fprintf(stdout, "Total Width: %s\n", "TBD"); ++ fprintf(stdout, "Data Width: %d bits\n", buswidth); ++ fprintf(stdout, "Size: %d GB\n", decode_ddr4_module_size(dimm_spd_read_out)); ++ fprintf(stdout, "Form Factor: %s\n", "TBD"); ++ fprintf(stdout, "Set: %s\n", "TBD"); ++ fprintf(stdout, "Locator: %s\n", "DIMM_X"); ++ fprintf(stdout, "Bank Locator: %s\n", "_Node1_ChannelX_DimmX"); ++ fprintf(stdout, "Type: %s\n", ram_types[ram_type]); ++ fprintf(stdout, "Type Detail: %s\n", decode_ddr4_module_type(dimm_spd_read_out)); ++ fprintf(stdout, "Speed: %d MT/s\n", decode_ddr4_module_speed(dimm_spd_read_out)); ++ fprintf(stdout, "Manufacturer: %s\n", decode_ddr4_manufacturer(dimm_spd_read_out)); ++ IntToString(serial, &dimm_spd_read_out[325], SPD_MODULE_SERIAL_NUMBER_LEN); ++ fprintf(stdout, "Serial Number: %s\n", serial); ++ fprintf(stdout, "Asset Tag: %s\n", "TBD"); + + out: + cxl_cmd_unref(cmd); +@@ -9946,3 +9961,76 @@ out: + cxl_cmd_unref(cmd); + return rc; + } ++ ++#define CXL_MEM_COMMAND_ID_DIMM_SLOT_INFO CXL_MEM_COMMAND_ID_RAW ++#define CXL_MEM_COMMAND_ID_DIMM_SLOT_INFO_OPCODE 0xC520 ++#define CXL_MEM_COMMAND_ID_DIMM_SLOT_INFO_PAYLOAD_IN_SIZE 0 ++ ++CXL_EXPORT int cxl_memdev_dimm_slot_info(struct cxl_memdev *memdev) ++{ ++ struct cxl_cmd *cmd; ++ struct cxl_mem_query_commands *query; ++ struct cxl_command_info *cinfo; ++ u8 *dimm_slot_info; ++ int rc = 0; ++ int offset = 0; ++ ++ ++ cmd = cxl_cmd_new_raw(memdev, CXL_MEM_COMMAND_ID_DIMM_SLOT_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_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_DIMM_SLOT_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_DIMM_SLOT_INFO); ++ return -EINVAL; ++ } ++ ++ dimm_slot_info = (u8*)cmd->send_cmd->out.payload; ++ fprintf(stdout, "=========================== DIMM SLOT INFO ============================\n"); ++ fprintf(stdout, "Output Payload:\n"); ++ for(int i=0; isend_cmd->out.size; i++){ ++ if (i % 16 == 0) ++ { ++ fprintf(stdout, "\n%04x %02x ", i+offset, dimm_slot_info[i]); ++ } ++ else ++ { ++ fprintf(stdout, "%02x ", dimm_slot_info[i]); ++ } ++ } ++ fprintf(stdout, "\n"); ++out: ++ cxl_cmd_unref(cmd); ++ return rc; ++} +diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym +index e68bd89..aaf2d65 100644 +--- a/cxl/lib/libcxl.sym ++++ b/cxl/lib/libcxl.sym +@@ -168,4 +168,5 @@ global: + cxl_memdev_osa_data_read; + cxl_memdev_dimm_spd_read; + cxl_memdev_ddr_training_status; ++ cxl_memdev_dimm_slot_info; + } LIBCXL_3; +diff --git a/cxl/libcxl.h b/cxl/libcxl.h +index 498de7d..0c24579 100644 +--- a/cxl/libcxl.h ++++ b/cxl/libcxl.h +@@ -235,6 +235,7 @@ int cxl_memdev_osa_data_read(struct cxl_memdev *memdev, u8 cxl_mem_id, + 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); + + #define cxl_memdev_foreach(ctx, memdev) \ + for (memdev = cxl_memdev_get_first(ctx); \ +diff --git a/cxl/memdev.c b/cxl/memdev.c +index d3a6f67..64ba7e0 100644 +--- a/cxl/memdev.c ++++ b/cxl/memdev.c +@@ -1895,6 +1895,11 @@ static const struct option cmd_ddr_training_status_options[] = { + OPT_END(), + }; + ++static const struct option cmd_dimm_slot_info_options[] = { ++ BASE_OPTIONS(), ++ OPT_END(), ++}; ++ + static int action_cmd_clear_event_records(struct cxl_memdev *memdev, struct action_context *actx) + { + u16 record_handle; +@@ -3438,6 +3443,17 @@ static int action_cmd_ddr_training_status(struct cxl_memdev *memdev, struct acti + return cxl_memdev_ddr_training_status(memdev); + } + ++static int action_cmd_dimm_slot_info(struct cxl_memdev *memdev, struct action_context *actx) ++{ ++ if (cxl_memdev_is_active(memdev)) { ++ fprintf(stderr, "%s: memdev active, abort dimm_slot_info\n", ++ cxl_memdev_get_devname(memdev)); ++ return -EBUSY; ++ } ++ ++ return cxl_memdev_dimm_slot_info(memdev); ++} ++ + static int action_write(struct cxl_memdev *memdev, struct action_context *actx) + { + size_t size = param.len, read_len; +@@ -4495,3 +4511,11 @@ int cmd_ddr_training_status(int argc, const char **argv, struct cxl_ctx *ctx) + + return rc >= 0 ? 0 : EXIT_FAILURE; + } ++ ++int cmd_dimm_slot_info(int argc, const char **argv, struct cxl_ctx *ctx) ++{ ++ int rc = memdev_action(argc, argv, ctx, action_cmd_dimm_slot_info, cmd_dimm_slot_info_options, ++ "cxl ddr-slot-info [..] []"); ++ ++ return rc >= 0 ? 0 : EXIT_FAILURE; ++} +-- +2.39.2 + + +From 86dc9d17c940b400bee7452121e64419e858cc8d Mon Sep 17 00:00:00 2001 +From: Hiral Patel +Date: Sat, 18 Feb 2023 01:10:13 -0800 +Subject: [PATCH 2/3] fix stdout format + +--- + cxl/lib/libcxl.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c +index a65f14a..2a1b6f6 100644 +--- a/cxl/lib/libcxl.c ++++ b/cxl/lib/libcxl.c +@@ -9855,6 +9855,7 @@ CXL_EXPORT int cxl_memdev_dimm_spd_read(struct cxl_memdev *memdev, + fprintf(stdout, "%02x ", dimm_spd_read_out[i]); + } + } ++ fprintf(stdout, "\n\n"); + + // Decoding SPD data for only DDR4 SDRAM. + +-- +2.39.2 + + +From 7fcbe3d7dc7eff5673baf2c55ec7f59e68a3bda6 Mon Sep 17 00:00:00 2001 +From: Panos Christeas +Date: Mon, 20 Feb 2023 15:39:16 +0000 +Subject: [PATCH 3/3] add separator between SPD payload and decoding + +Summary: +Printing the SPD decoding would be on the same last line of hex payload, +giving the parser a headache. +Just add a separator + +Test Plan: +before: +``` + cxl dimm-spd-read mem0 -s 0 -o 0 -n 512 +=========================== DIMM SPD READ Data ============================ +Output Payload: +0000 23 11 0c 01 85 ... +... +01f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Total Width: TBD +Data Width: 64 bits +Size: ... + +``` + +After: +``` +========================= DIMM SPD READ Data ============================ +Output Payload: +0000 23 11 0c 01 85 ... +... +01f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +====== DIMM SPD DECODE ============ +Total Width: TBD +Data Width: 64 bits +Size: ... +Form Factor: TBD +Set: TBD +Locator: ... +``` + +Reviewers: + +Subscribers: + +Tasks: + +Tags: +--- + cxl/lib/libcxl.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c +index 2a1b6f6..8d39d2c 100644 +--- a/cxl/lib/libcxl.c ++++ b/cxl/lib/libcxl.c +@@ -9861,6 +9861,7 @@ CXL_EXPORT int cxl_memdev_dimm_spd_read(struct cxl_memdev *memdev, + + buswidth = 8 << (dimm_spd_read_out[13] & 7); + ++ fprintf(stdout, "\n\n====== DIMM SPD DECODE ============\n"); + fprintf(stdout, "Total Width: %s\n", "TBD"); + fprintf(stdout, "Data Width: %d bits\n", buswidth); + fprintf(stdout, "Size: %d GB\n", decode_ddr4_module_size(dimm_spd_read_out)); +-- +2.39.2 + diff --git a/SPECS/ndctl.spec b/SPECS/ndctl.spec index 959d09e..6fbaa01 100644 --- a/SPECS/ndctl.spec +++ b/SPECS/ndctl.spec @@ -1,6 +1,6 @@ Name: ndctl Version: 71.1 -Release: 4.1%{?dist} +Release: 4.2%{?dist} Summary: Manage "libnvdimm" subsystem devices (Non-volatile Memory) License: GPLv2 Group: System Environment/Base @@ -11,6 +11,8 @@ Source0: https://github.com/pmem/%{name}/archive/v%{version}.tar.gz#/%{name}-%{v # https://github.com/elake/ndctl diff from 71.1 (ea014c0) to main (3ff031d) # This was generated with `git diff` because `git format-patch` doesn't handle the merges well Patch0: elake-diff-ea014c0-3ff031d.patch +# Normal patch generated from `git format-patch` +Patch1: elake-c5d4db-7fcbe3.patch %else Patch0: modprobe-link-user-keyring-before-loadkeys.patch Patch1: fb13dfb-zero_info_block-skip-seed-devices.patch @@ -231,6 +233,9 @@ make check %changelog +* Thu Feb 23 2023 Anita Zhang - 71.1-4.2 +- Patch SPD decoding and dimm_slot_info CCI command support + * Fri Feb 3 2023 Anita Zhang - 71.1-4.1 - Patch 71.1 with diff between ea014c0..3ff031d from elake/ndctl fork for hs+fb - Sync changes from rhel/ndctl.spec (autogenerated by the GitHub Makefile)