#2 71.1-4.2: Patch SPD decoding and dimm_slot_info CCI command support
Merged a year ago by anitazha. Opened a year ago by anitazha.

@@ -0,0 +1,428 @@ 

+ From c5d4db8ba7b2f3964f12bcde5d8fa5f27aa6c500 Mon Sep 17 00:00:00 2001

+ From: Hiral Patel <patelhiral@fb.com>

+ 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; i<cmd->send_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; i<cmd->send_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 <mem0> [<mem1>..<memN>] [<options>]");

+ +

+ +  return rc >= 0 ? 0 : EXIT_FAILURE;

+ +}

+ -- 

+ 2.39.2

+ 

+ 

+ From 86dc9d17c940b400bee7452121e64419e858cc8d Mon Sep 17 00:00:00 2001

+ From: Hiral Patel <patelhiral@fb.com>

+ 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 <xrg@meta.com>

+ 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

+ 

file modified
+6 -1
@@ -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 @@ 

  # 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 @@ 

  

  

  %changelog

+ * Thu Feb 23 2023 Anita Zhang <the.anitazha@gmail.com> - 71.1-4.2

+ - Patch SPD decoding and dimm_slot_info CCI command support

+ 

  * Fri Feb  3 2023 Anita Zhang <the.anitazha@gmail.com> - 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)

no initial comment

Pull-Request has been merged by anitazha

a year ago