[PATCH ethtool-next 0/8] ethtool: Add support for CMIS diagnostic information

STALE1740d

14 messages, 3 authors, 2021-12-02 · open the first message on its own page

[PATCH ethtool-next 0/8] ethtool: Add support for CMIS diagnostic information

From: Ido Schimmel <hidden>
Date: 2021-11-23 17:41:25

From: Ido Schimmel <idosch@nvidia.com>

This patchset extends ethtool(8) to retrieve, parse and print CMIS
diagnostic information. This information includes module-level monitors
(e.g., temperature, voltage), channel-level monitors (e.g., Tx optical
power) and related thresholds and flags.

ethtool(8) already supports SFF-8636 (e.g., QSFP) and SFF-8472 (e.g.,
SFP) diagnostic information, but until recently CMIS diagnostic
information was unavailable to ethtool(8) as it resides in optional and
banked pages.

Testing
=======

Build tested each patch with the following configuration options:

netlink | pretty-dump
--------|------------
v       | v
x       | x
v       | x
x       | v

Except fields that were added, no difference in output before and after
the patchset. Tested with both PC and AOC QSFP-DD modules.

No reports from AddressSanitizer / valgrind.

Patchset overview
=================

Patches #1-#2 are small preparations.

Patches #3-#4 retrieve (over netlink) and initialize the optional and
banked pages in the CMIS memory map. These pages contain the previously
mentioned diagnostic information.

Patch #5 parses and prints the CMIS diagnostic information in a similar
fashion to the way it is done for SFF-8636.

Patches #6-#7 print a few additional fields from the CMIS EEPROM dump.
The examples contain an ethtool command that is supported by the kernel,
but not yet by ethtool(8). It will be sent as a follow-up patchset.

Patch #8 prints the equivalent module-level fields for SFF-8636.

Ido Schimmel (8):
  sff-8636: Use an SFF-8636 specific define for maximum number of
    channels
  sff-common: Move OFFSET_TO_U16_PTR() to common header file
  cmis: Initialize Page 02h in memory map
  cmis: Initialize Banked Page 11h in memory map
  cmis: Parse and print diagnostic information
  cmis: Print Module State and Fault Cause
  cmis: Print Module-Level Controls
  sff-8636: Print Power set and Power override bits

 cmis.c       | 611 ++++++++++++++++++++++++++++++++++++++++++++++++---
 cmis.h       | 107 +++++++++
 qsfp.c       |  16 +-
 qsfp.h       |   2 +-
 sff-common.h |   6 +-
 5 files changed, 702 insertions(+), 40 deletions(-)

-- 
2.31.1

[PATCH ethtool-next 1/8] sff-8636: Use an SFF-8636 specific define for maximum number of channels

From: Ido Schimmel <hidden>
Date: 2021-11-23 17:41:27

From: Ido Schimmel <idosch@nvidia.com>

'MAX_CHANNEL_NUM' is defined in the common SFF code as 4 and used to set
the size of the per-channel diagnostics array in the common 'sff_diags'
structure.

The CMIS parsing code is also going to use the structure, but it can
have up to 32 channels, unlike SFF-8636 that only has 4.

Therefore, set 'MAX_CHANNEL_NUM' to 32 and change the SFF-8636 code to
use an SFF-8636 specific define instead of the common 'MAX_CHANNEL_NUM'.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 qsfp.c       | 9 +++++----
 sff-common.h | 2 +-
 2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/qsfp.c b/qsfp.c
index e7c2f51cd9c6..58c4c4775e9b 100644
--- a/qsfp.c
+++ b/qsfp.c
@@ -71,6 +71,7 @@ struct sff8636_memory_map {
 
 #define SFF8636_PAGE_SIZE	0x80
 #define SFF8636_I2C_ADDRESS	0x50
+#define SFF8636_MAX_CHANNEL_NUM	4
 
 #define MAX_DESC_SIZE	42
 
@@ -761,7 +762,7 @@ static void sff8636_dom_parse(const struct sff8636_memory_map *map,
 
 out:
 	/* Channel Specific Data */
-	for (i = 0; i < MAX_CHANNEL_NUM; i++) {
+	for (i = 0; i < SFF8636_MAX_CHANNEL_NUM; i++) {
 		u8 rx_power_offset, tx_bias_offset;
 		u8 tx_power_offset;
 
@@ -832,13 +833,13 @@ static void sff8636_show_dom(const struct sff8636_memory_map *map)
 	printf("\t%-41s : %s\n", "Alarm/warning flags implemented",
 		(sd.supports_alarms ? "Yes" : "No"));
 
-	for (i = 0; i < MAX_CHANNEL_NUM; i++) {
+	for (i = 0; i < SFF8636_MAX_CHANNEL_NUM; i++) {
 		snprintf(power_string, MAX_DESC_SIZE, "%s (Channel %d)",
 					"Laser tx bias current", i+1);
 		PRINT_BIAS(power_string, sd.scd[i].bias_cur);
 	}
 
-	for (i = 0; i < MAX_CHANNEL_NUM; i++) {
+	for (i = 0; i < SFF8636_MAX_CHANNEL_NUM; i++) {
 		snprintf(power_string, MAX_DESC_SIZE, "%s (Channel %d)",
 					"Transmit avg optical power", i+1);
 		PRINT_xX_PWR(power_string, sd.scd[i].tx_power);
@@ -849,7 +850,7 @@ static void sff8636_show_dom(const struct sff8636_memory_map *map)
 	else
 		rx_power_string = "Rcvr signal avg optical power";
 
-	for (i = 0; i < MAX_CHANNEL_NUM; i++) {
+	for (i = 0; i < SFF8636_MAX_CHANNEL_NUM; i++) {
 		snprintf(power_string, MAX_DESC_SIZE, "%s(Channel %d)",
 					rx_power_string, i+1);
 		PRINT_xX_PWR(power_string, sd.scd[i].rx_power);
diff --git a/sff-common.h b/sff-common.h
index 2183f41ff9c9..aab306e0b74f 100644
--- a/sff-common.h
+++ b/sff-common.h
@@ -160,7 +160,7 @@ struct sff_channel_diags {
 /* Module Monitoring Fields */
 struct sff_diags {
 
-#define MAX_CHANNEL_NUM 4
+#define MAX_CHANNEL_NUM 32
 #define LWARN 0
 #define HWARN 1
 #define LALRM 2
-- 
2.31.1

[PATCH ethtool-next 2/8] sff-common: Move OFFSET_TO_U16_PTR() to common header file

From: Ido Schimmel <hidden>
Date: 2021-11-23 17:41:30

From: Ido Schimmel <idosch@nvidia.com>

The define is also useful for CMIS, so move it from SFF-8636 to the
common header file.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 qsfp.c       | 1 -
 sff-common.h | 4 ++--
 2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/qsfp.c b/qsfp.c
index 58c4c4775e9b..b3c9e1516af9 100644
--- a/qsfp.c
+++ b/qsfp.c
@@ -700,7 +700,6 @@ sff8636_show_wavelength_or_copper_compliance(const struct sff8636_memory_map *ma
  * Second byte are 1/256th of degree, which are added to the dec part.
  */
 #define SFF8636_OFFSET_TO_TEMP(offset) ((__s16)OFFSET_TO_U16(offset))
-#define OFFSET_TO_U16_PTR(ptr, offset) (ptr[offset] << 8 | ptr[(offset) + 1])
 
 static void sff8636_dom_parse(const struct sff8636_memory_map *map,
 			      struct sff_diags *sd)
diff --git a/sff-common.h b/sff-common.h
index aab306e0b74f..9e323008ba19 100644
--- a/sff-common.h
+++ b/sff-common.h
@@ -126,8 +126,8 @@
 #define  SFF8024_ENCODING_PAM4			0x08
 
 /* Most common case: 16-bit unsigned integer in a certain unit */
-#define OFFSET_TO_U16(offset) \
-		(id[offset] << 8 | id[(offset) + 1])
+#define OFFSET_TO_U16_PTR(ptr, offset) (ptr[offset] << 8 | ptr[(offset) + 1])
+#define OFFSET_TO_U16(offset) OFFSET_TO_U16_PTR(id, offset)
 
 # define PRINT_xX_PWR(string, var)                             \
 		printf("\t%-41s : %.4f mW / %.2f dBm\n", (string),         \
-- 
2.31.1

[PATCH ethtool-next 3/8] cmis: Initialize Page 02h in memory map

From: Ido Schimmel <hidden>
Date: 2021-11-23 17:41:31

From: Ido Schimmel <idosch@nvidia.com>

Page 02h stores module and lane thresholds that are going to be parsed
and displayed in subsequent patches.

Request it via the 'MODULE_EEPROM_GET' netlink message and initialize it
in the memory map.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 cmis.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/cmis.c b/cmis.c
index 4798fd4c7d68..55b9d1b959cd 100644
--- a/cmis.c
+++ b/cmis.c
@@ -17,9 +17,10 @@
 
 struct cmis_memory_map {
 	const __u8 *lower_memory;
-	const __u8 *upper_memory[1][2];	/* Bank, Page */
+	const __u8 *upper_memory[1][3];	/* Bank, Page */
 #define page_00h upper_memory[0x0][0x0]
 #define page_01h upper_memory[0x0][0x1]
+#define page_02h upper_memory[0x0][0x2]
 };
 
 #define CMIS_PAGE_SIZE		0x80
@@ -423,8 +424,8 @@ cmis_memory_map_init_pages(struct cmd_context *ctx,
 		return ret;
 	map->page_00h = request.data - CMIS_PAGE_SIZE;
 
-	/* Page 01h is only present when the module memory model is paged and
-	 * not flat.
+	/* Pages 01h and 02h are only present when the module memory model is
+	 * paged and not flat.
 	 */
 	if (map->lower_memory[CMIS_MEMORY_MODEL_OFFSET] &
 	    CMIS_MEMORY_MODEL_MASK)
@@ -436,6 +437,12 @@ cmis_memory_map_init_pages(struct cmd_context *ctx,
 		return ret;
 	map->page_01h = request.data - CMIS_PAGE_SIZE;
 
+	cmis_request_init(&request, 0, 0x2, CMIS_PAGE_SIZE);
+	ret = nl_get_eeprom_page(ctx, &request);
+	if (ret < 0)
+		return ret;
+	map->page_02h = request.data - CMIS_PAGE_SIZE;
+
 	return 0;
 }
 
-- 
2.31.1

[PATCH ethtool-next 4/8] cmis: Initialize Banked Page 11h in memory map

From: Ido Schimmel <hidden>
Date: 2021-11-23 17:41:33

From: Ido Schimmel <idosch@nvidia.com>

Banked Page 11h stores, among other things, lane-specific flags and
monitors that are going to be parsed and displayed in subsequent
patches.

Request it via the 'MODULE_EEPROM_GET' netlink message and initialize it
in the memory map.

Only initialize it in supported Banks.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 cmis.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
 cmis.h |  7 +++++++
 2 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/cmis.c b/cmis.c
index 55b9d1b959cd..83ced4d253ae 100644
--- a/cmis.c
+++ b/cmis.c
@@ -15,9 +15,17 @@
 #include "cmis.h"
 #include "netlink/extapi.h"
 
+/* The maximum number of supported Banks. Relevant documents:
+ * [1] CMIS Rev. 5, page. 128, section 8.4.4, Table 8-40
+ */
+#define CMIS_MAX_BANKS	4
+
+/* We are not parsing further than Page 11h. */
+#define CMIS_MAX_PAGES	18
+
 struct cmis_memory_map {
 	const __u8 *lower_memory;
-	const __u8 *upper_memory[1][3];	/* Bank, Page */
+	const __u8 *upper_memory[CMIS_MAX_BANKS][CMIS_MAX_PAGES];
 #define page_00h upper_memory[0x0][0x0]
 #define page_01h upper_memory[0x0][0x1]
 #define page_02h upper_memory[0x0][0x2]
@@ -399,12 +407,33 @@ static void cmis_request_init(struct ethtool_module_eeprom *request, u8 bank,
 	request->data = NULL;
 }
 
+static int cmis_num_banks_get(const struct cmis_memory_map *map,
+			      int *p_num_banks)
+{
+	switch (map->page_01h[CMIS_PAGES_ADVER_OFFSET] &
+		CMIS_BANKS_SUPPORTED_MASK) {
+	case CMIS_BANK_0_SUPPORTED:
+		*p_num_banks = 1;
+		break;
+	case CMIS_BANK_0_1_SUPPORTED:
+		*p_num_banks = 2;
+		break;
+	case CMIS_BANK_0_3_SUPPORTED:
+		*p_num_banks = 4;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int
 cmis_memory_map_init_pages(struct cmd_context *ctx,
 			   struct cmis_memory_map *map)
 {
 	struct ethtool_module_eeprom request;
-	int ret;
+	int num_banks, i, ret;
 
 	/* Lower Memory and Page 00h are always present.
 	 *
@@ -443,6 +472,22 @@ cmis_memory_map_init_pages(struct cmd_context *ctx,
 		return ret;
 	map->page_02h = request.data - CMIS_PAGE_SIZE;
 
+	/* Bank 0 of Page 11h provides lane-specific registers for the first 8
+	 * lanes, and each additional Banks provides support for an additional
+	 * 8 lanes. Only initialize supported Banks.
+	 */
+	ret = cmis_num_banks_get(map, &num_banks);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < num_banks; i++) {
+		cmis_request_init(&request, i, 0x11, CMIS_PAGE_SIZE);
+		ret = nl_get_eeprom_page(ctx, &request);
+		if (ret < 0)
+			return ret;
+		map->upper_memory[i][0x11] = request.data - CMIS_PAGE_SIZE;
+	}
+
 	return 0;
 }
 
diff --git a/cmis.h b/cmis.h
index 911491dc5c8f..8d90a04756ad 100644
--- a/cmis.h
+++ b/cmis.h
@@ -114,6 +114,13 @@
 #define CMIS_WAVELENGTH_TOL_MSB			0x8C
 #define CMIS_WAVELENGTH_TOL_LSB			0x8D
 
+/* Supported Pages Advertising (Page 1) */
+#define CMIS_PAGES_ADVER_OFFSET			0x8E
+#define CMIS_BANKS_SUPPORTED_MASK		0x03
+#define CMIS_BANK_0_SUPPORTED			0x00
+#define CMIS_BANK_0_1_SUPPORTED			0x01
+#define CMIS_BANK_0_3_SUPPORTED			0x02
+
 /* Signal integrity controls */
 #define CMIS_SIG_INTEG_TX_OFFSET		0xA1
 #define CMIS_SIG_INTEG_RX_OFFSET		0xA2
-- 
2.31.1

[PATCH ethtool-next 5/8] cmis: Parse and print diagnostic information

From: Ido Schimmel <hidden>
Date: 2021-11-23 17:41:37

From: Ido Schimmel <idosch@nvidia.com>

Like SFF-8636, CMIS has module-level monitors such as temperature and
voltage and channel-level monitors such as Tx optical power.

These monitors have thresholds and flags that are set when the monitors
cross the thresholds.

Print and parse these values in a similar fashion to SFF-8636.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 cmis.c | 466 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
 cmis.h |  79 ++++++++++
 2 files changed, 518 insertions(+), 27 deletions(-)
diff --git a/cmis.c b/cmis.c
index 83ced4d253ae..d7b7097139b3 100644
--- a/cmis.c
+++ b/cmis.c
@@ -19,6 +19,8 @@
  * [1] CMIS Rev. 5, page. 128, section 8.4.4, Table 8-40
  */
 #define CMIS_MAX_BANKS	4
+#define CMIS_CHANNELS_PER_BANK	8
+#define CMIS_MAX_CHANNEL_NUM	(CMIS_MAX_BANKS * CMIS_CHANNELS_PER_BANK)
 
 /* We are not parsing further than Page 11h. */
 #define CMIS_MAX_PAGES	18
@@ -34,6 +36,80 @@ struct cmis_memory_map {
 #define CMIS_PAGE_SIZE		0x80
 #define CMIS_I2C_ADDRESS	0x50
 
+static struct {
+	const char *str;
+	int offset;
+	__u8 value;	/* Alarm is on if (offset & value) != 0. */
+} cmis_aw_mod_flags[] = {
+	{ "Module temperature high alarm",
+	  CMIS_TEMP_AW_OFFSET, CMIS_TEMP_HALARM_STATUS },
+	{ "Module temperature low alarm",
+	  CMIS_TEMP_AW_OFFSET, CMIS_TEMP_LALARM_STATUS },
+	{ "Module temperature high warning",
+	  CMIS_TEMP_AW_OFFSET, CMIS_TEMP_HWARN_STATUS },
+	{ "Module temperature low warning",
+	  CMIS_TEMP_AW_OFFSET, CMIS_TEMP_LWARN_STATUS },
+
+	{ "Module voltage high alarm",
+	  CMIS_VCC_AW_OFFSET, CMIS_VCC_HALARM_STATUS },
+	{ "Module voltage low alarm",
+	  CMIS_VCC_AW_OFFSET, CMIS_VCC_LALARM_STATUS },
+	{ "Module voltage high warning",
+	  CMIS_VCC_AW_OFFSET, CMIS_VCC_HWARN_STATUS },
+	{ "Module voltage low warning",
+	  CMIS_VCC_AW_OFFSET, CMIS_VCC_LWARN_STATUS },
+
+	{ NULL, 0, 0 },
+};
+
+static struct {
+	const char *fmt_str;
+	int offset;
+	int adver_offset;	/* In Page 01h. */
+	__u8 adver_value;	/* Supported if (offset & value) != 0. */
+} cmis_aw_chan_flags[] = {
+	{ "Laser bias current high alarm   (Chan %d)",
+	  CMIS_TX_BIAS_AW_HALARM_OFFSET,
+	  CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_BIAS_MON_MASK },
+	{ "Laser bias current low alarm    (Chan %d)",
+	  CMIS_TX_BIAS_AW_LALARM_OFFSET,
+	  CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_BIAS_MON_MASK },
+	{ "Laser bias current high warning (Chan %d)",
+	  CMIS_TX_BIAS_AW_HWARN_OFFSET,
+	  CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_BIAS_MON_MASK },
+	{ "Laser bias current low warning  (Chan %d)",
+	  CMIS_TX_BIAS_AW_LWARN_OFFSET,
+	  CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_BIAS_MON_MASK },
+
+	{ "Laser tx power high alarm   (Channel %d)",
+	  CMIS_TX_PWR_AW_HALARM_OFFSET,
+	  CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_PWR_MON_MASK },
+	{ "Laser tx power low alarm    (Channel %d)",
+	  CMIS_TX_PWR_AW_LALARM_OFFSET,
+	  CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_PWR_MON_MASK },
+	{ "Laser tx power high warning (Channel %d)",
+	  CMIS_TX_PWR_AW_HWARN_OFFSET,
+	  CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_PWR_MON_MASK },
+	{ "Laser tx power low warning  (Channel %d)",
+	  CMIS_TX_PWR_AW_LWARN_OFFSET,
+	  CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_PWR_MON_MASK },
+
+	{ "Laser rx power high alarm   (Channel %d)",
+	  CMIS_RX_PWR_AW_HALARM_OFFSET,
+	  CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_RX_PWR_MON_MASK },
+	{ "Laser rx power low alarm    (Channel %d)",
+	  CMIS_RX_PWR_AW_LALARM_OFFSET,
+	  CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_RX_PWR_MON_MASK },
+	{ "Laser rx power high warning (Channel %d)",
+	  CMIS_RX_PWR_AW_HWARN_OFFSET,
+	  CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_RX_PWR_MON_MASK },
+	{ "Laser rx power low warning  (Channel %d)",
+	  CMIS_RX_PWR_AW_LWARN_OFFSET,
+	  CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_RX_PWR_MON_MASK },
+
+	{ NULL, 0, 0, 0 },
+};
+
 static void cmis_show_identifier(const struct cmis_memory_map *map)
 {
 	sff8024_show_identifier(map->lower_memory, CMIS_ID_OFFSET);
@@ -277,32 +353,6 @@ static void cmis_show_mit_compliance(const struct cmis_memory_map *map)
 	}
 }
 
-/*
- * 2-byte internal temperature conversions:
- * First byte is a signed 8-bit integer, which is the temp decimal part
- * Second byte is a multiple of 1/256th of a degree, which is added to
- * the dec part.
- */
-#define OFFSET_TO_TEMP(offset) ((__s16)OFFSET_TO_U16(offset))
-
-/**
- * Print relevant module level monitoring values. Relevant documents:
- * [1] CMIS Rev. 3:
- * --> pag. 50, section 1.7.2.4, Table 22
- *
- * [2] CMIS Rev. 4:
- * --> pag. 84, section 8.2.4, Table 8-6
- */
-static void cmis_show_mod_lvl_monitors(const struct cmis_memory_map *map)
-{
-	const __u8 *id = map->lower_memory;
-
-	PRINT_TEMP("Module temperature",
-		   OFFSET_TO_TEMP(CMIS_CURR_TEMP_OFFSET));
-	PRINT_VCC("Module voltage",
-		  OFFSET_TO_U16(CMIS_CURR_VCC_OFFSET));
-}
-
 /**
  * Print relevant info about the maximum supported fiber media length
  * for each type of fiber media at the maximum module-supported bit rate.
@@ -352,6 +402,368 @@ static void cmis_show_vendor_info(const struct cmis_memory_map *map)
 			       CMIS_CLEI_END_OFFSET, "CLEI code");
 }
 
+static void cmis_parse_dom_power_type(const struct cmis_memory_map *map,
+				      struct sff_diags *sd)
+{
+	sd->rx_power_type = map->page_01h[CMIS_DIAG_TYPE_OFFSET] &
+			    CMIS_RX_PWR_TYPE_MASK;
+	sd->tx_power_type = map->page_01h[CMIS_DIAG_CHAN_ADVER_OFFSET] &
+			    CMIS_TX_PWR_MON_MASK;
+}
+
+static void cmis_parse_dom_mod_lvl_monitors(const struct cmis_memory_map *map,
+					    struct sff_diags *sd)
+{
+	sd->sfp_voltage[MCURR] = OFFSET_TO_U16_PTR(map->lower_memory,
+						   CMIS_CURR_VCC_OFFSET);
+	sd->sfp_temp[MCURR] = (__s16)OFFSET_TO_U16_PTR(map->lower_memory,
+						       CMIS_CURR_TEMP_OFFSET);
+}
+
+static void cmis_parse_dom_mod_lvl_thresh(const struct cmis_memory_map *map,
+					  struct sff_diags *sd)
+{
+	/* Page is not present in IOCTL path. */
+	if (!map->page_02h)
+		return;
+	sd->supports_alarms = 1;
+
+	sd->sfp_voltage[HALRM] = OFFSET_TO_U16_PTR(map->page_02h,
+						   CMIS_VCC_HALRM_OFFSET);
+	sd->sfp_voltage[LALRM] = OFFSET_TO_U16_PTR(map->page_02h,
+						   CMIS_VCC_LALRM_OFFSET);
+	sd->sfp_voltage[HWARN] = OFFSET_TO_U16_PTR(map->page_02h,
+						   CMIS_VCC_HWARN_OFFSET);
+	sd->sfp_voltage[LWARN] = OFFSET_TO_U16_PTR(map->page_02h,
+						   CMIS_VCC_LWARN_OFFSET);
+
+	sd->sfp_temp[HALRM] = (__s16)OFFSET_TO_U16_PTR(map->page_02h,
+						       CMIS_TEMP_HALRM_OFFSET);
+	sd->sfp_temp[LALRM] = (__s16)OFFSET_TO_U16_PTR(map->page_02h,
+						       CMIS_TEMP_LALRM_OFFSET);
+	sd->sfp_temp[HWARN] = (__s16)OFFSET_TO_U16_PTR(map->page_02h,
+						       CMIS_TEMP_HWARN_OFFSET);
+	sd->sfp_temp[LWARN] = (__s16)OFFSET_TO_U16_PTR(map->page_02h,
+						       CMIS_TEMP_LWARN_OFFSET);
+}
+
+static __u8 cmis_tx_bias_mul(const struct cmis_memory_map *map)
+{
+	switch (map->page_01h[CMIS_DIAG_CHAN_ADVER_OFFSET] &
+		CMIS_TX_BIAS_MUL_MASK) {
+	case CMIS_TX_BIAS_MUL_1:
+		return 0;
+	case CMIS_TX_BIAS_MUL_2:
+		return 1;
+	case CMIS_TX_BIAS_MUL_4:
+		return 2;
+	}
+
+	return 0;
+}
+
+static void
+cmis_parse_dom_chan_lvl_monitors_bank(const struct cmis_memory_map *map,
+				      struct sff_diags *sd, int bank)
+{
+	const __u8 *page_11h = map->upper_memory[bank][0x11];
+	int i;
+
+	if (!page_11h)
+		return;
+
+	for (i = 0; i < CMIS_CHANNELS_PER_BANK; i++) {
+		__u8 tx_bias_offset, rx_power_offset, tx_power_offset;
+		int chan = bank * CMIS_CHANNELS_PER_BANK + i;
+		__u8 bias_mul = cmis_tx_bias_mul(map);
+
+		tx_bias_offset = CMIS_TX_BIAS_OFFSET + i * sizeof(__u16);
+		rx_power_offset = CMIS_RX_PWR_OFFSET + i * sizeof(__u16);
+		tx_power_offset = CMIS_TX_PWR_OFFSET + i * sizeof(__u16);
+
+		sd->scd[chan].bias_cur = OFFSET_TO_U16_PTR(page_11h,
+							   tx_bias_offset);
+		sd->scd[chan].bias_cur >>= bias_mul;
+		sd->scd[chan].rx_power = OFFSET_TO_U16_PTR(page_11h,
+							   rx_power_offset);
+		sd->scd[chan].tx_power = OFFSET_TO_U16_PTR(page_11h,
+							   tx_power_offset);
+	}
+}
+
+static void cmis_parse_dom_chan_lvl_monitors(const struct cmis_memory_map *map,
+					     struct sff_diags *sd)
+{
+	int i;
+
+	for (i = 0; i < CMIS_MAX_BANKS; i++)
+		cmis_parse_dom_chan_lvl_monitors_bank(map, sd, i);
+}
+
+static void cmis_parse_dom_chan_lvl_thresh(const struct cmis_memory_map *map,
+					   struct sff_diags *sd)
+{
+	__u8 bias_mul = cmis_tx_bias_mul(map);
+
+	if (!map->page_02h)
+		return;
+
+	sd->bias_cur[HALRM] = OFFSET_TO_U16_PTR(map->page_02h,
+						CMIS_TX_BIAS_HALRM_OFFSET);
+	sd->bias_cur[HALRM] >>= bias_mul;
+	sd->bias_cur[LALRM] = OFFSET_TO_U16_PTR(map->page_02h,
+						CMIS_TX_BIAS_LALRM_OFFSET);
+	sd->bias_cur[LALRM] >>= bias_mul;
+	sd->bias_cur[HWARN] = OFFSET_TO_U16_PTR(map->page_02h,
+						CMIS_TX_BIAS_HWARN_OFFSET);
+	sd->bias_cur[HWARN] >>= bias_mul;
+	sd->bias_cur[LWARN] = OFFSET_TO_U16_PTR(map->page_02h,
+						CMIS_TX_BIAS_LWARN_OFFSET);
+	sd->bias_cur[LWARN] >>= bias_mul;
+
+	sd->tx_power[HALRM] = OFFSET_TO_U16_PTR(map->page_02h,
+						CMIS_TX_PWR_HALRM_OFFSET);
+	sd->tx_power[LALRM] = OFFSET_TO_U16_PTR(map->page_02h,
+						CMIS_TX_PWR_LALRM_OFFSET);
+	sd->tx_power[HWARN] = OFFSET_TO_U16_PTR(map->page_02h,
+						CMIS_TX_PWR_HWARN_OFFSET);
+	sd->tx_power[LWARN] = OFFSET_TO_U16_PTR(map->page_02h,
+						CMIS_TX_PWR_LWARN_OFFSET);
+
+	sd->rx_power[HALRM] = OFFSET_TO_U16_PTR(map->page_02h,
+						CMIS_RX_PWR_HALRM_OFFSET);
+	sd->rx_power[LALRM] = OFFSET_TO_U16_PTR(map->page_02h,
+						CMIS_RX_PWR_LALRM_OFFSET);
+	sd->rx_power[HWARN] = OFFSET_TO_U16_PTR(map->page_02h,
+						CMIS_RX_PWR_HWARN_OFFSET);
+	sd->rx_power[LWARN] = OFFSET_TO_U16_PTR(map->page_02h,
+						CMIS_RX_PWR_LWARN_OFFSET);
+}
+
+static void cmis_parse_dom(const struct cmis_memory_map *map,
+			   struct sff_diags *sd)
+{
+	cmis_parse_dom_power_type(map, sd);
+	cmis_parse_dom_mod_lvl_monitors(map, sd);
+	cmis_parse_dom_mod_lvl_thresh(map, sd);
+	cmis_parse_dom_chan_lvl_monitors(map, sd);
+	cmis_parse_dom_chan_lvl_thresh(map, sd);
+}
+
+/* Print module-level monitoring values. Relevant documents:
+ * [1] CMIS Rev. 5, page 110, section 8.2.5, Table 8-9
+ */
+static void cmis_show_dom_mod_lvl_monitors(const struct sff_diags *sd)
+{
+	PRINT_TEMP("Module temperature", sd->sfp_temp[MCURR]);
+	PRINT_VCC("Module voltage", sd->sfp_voltage[MCURR]);
+}
+
+/* Print channel Tx laser bias current. Relevant documents:
+ * [1] CMIS Rev. 5, page 165, section 8.9.4, Table 8-79
+ */
+static void
+cmis_show_dom_chan_lvl_tx_bias_bank(const struct cmis_memory_map *map,
+				    const struct sff_diags *sd, int bank)
+{
+	const __u8 *page_11h = map->upper_memory[bank][0x11];
+	int i;
+
+	if (!page_11h)
+		return;
+
+	for (i = 0; i < CMIS_CHANNELS_PER_BANK; i++) {
+		int chan = bank * CMIS_CHANNELS_PER_BANK + i;
+		char fmt_str[80];
+
+		snprintf(fmt_str, 80, "%s (Channel %d)",
+			 "Laser tx bias current", chan + 1);
+		PRINT_BIAS(fmt_str, sd->scd[chan].bias_cur);
+	}
+}
+
+static void cmis_show_dom_chan_lvl_tx_bias(const struct cmis_memory_map *map,
+					   const struct sff_diags *sd)
+{
+	int i;
+
+	if(!(map->page_01h[CMIS_DIAG_CHAN_ADVER_OFFSET] &
+	     CMIS_TX_BIAS_MON_MASK))
+		return;
+
+	for (i = 0; i < CMIS_MAX_BANKS; i++)
+		cmis_show_dom_chan_lvl_tx_bias_bank(map, sd, i);
+}
+
+/* Print channel Tx average optical power. Relevant documents:
+ * [1] CMIS Rev. 5, page 165, section 8.9.4, Table 8-79
+ */
+static void
+cmis_show_dom_chan_lvl_tx_power_bank(const struct cmis_memory_map *map,
+				     const struct sff_diags *sd, int bank)
+{
+	const __u8 *page_11h = map->upper_memory[bank][0x11];
+	int i;
+
+	if (!page_11h)
+		return;
+
+	for (i = 0; i < CMIS_CHANNELS_PER_BANK; i++) {
+		int chan = bank * CMIS_CHANNELS_PER_BANK + i;
+		char fmt_str[80];
+
+		snprintf(fmt_str, 80, "%s (Channel %d)",
+			 "Transmit avg optical power", chan + 1);
+		PRINT_xX_PWR(fmt_str, sd->scd[chan].tx_power);
+	}
+}
+
+static void cmis_show_dom_chan_lvl_tx_power(const struct cmis_memory_map *map,
+					    const struct sff_diags *sd)
+{
+	int i;
+
+	if (!sd->tx_power_type)
+		return;
+
+	for (i = 0; i < CMIS_MAX_BANKS; i++)
+		cmis_show_dom_chan_lvl_tx_power_bank(map, sd, i);
+}
+
+/* Print channel Rx input optical power. Relevant documents:
+ * [1] CMIS Rev. 5, page 165, section 8.9.4, Table 8-79
+ */
+static void
+cmis_show_dom_chan_lvl_rx_power_bank(const struct cmis_memory_map *map,
+				     const struct sff_diags *sd, int bank)
+{
+	const __u8 *page_11h = map->upper_memory[bank][0x11];
+	int i;
+
+	if (!page_11h)
+		return;
+
+	for (i = 0; i < CMIS_CHANNELS_PER_BANK; i++) {
+		int chan = bank * CMIS_CHANNELS_PER_BANK + i;
+		char *rx_power_str;
+		char fmt_str[80];
+
+		if (!sd->rx_power_type)
+			rx_power_str = "Receiver signal OMA";
+		else
+			rx_power_str = "Rcvr signal avg optical power";
+
+		snprintf(fmt_str, 80, "%s (Channel %d)", rx_power_str,
+			 chan + 1);
+		PRINT_xX_PWR(fmt_str, sd->scd[chan].rx_power);
+	}
+}
+
+static void cmis_show_dom_chan_lvl_rx_power(const struct cmis_memory_map *map,
+					    const struct sff_diags *sd)
+{
+	int i;
+
+	if(!(map->page_01h[CMIS_DIAG_CHAN_ADVER_OFFSET] & CMIS_RX_PWR_MON_MASK))
+		return;
+
+	for (i = 0; i < CMIS_MAX_BANKS; i++)
+		cmis_show_dom_chan_lvl_rx_power_bank(map, sd, i);
+}
+
+static void cmis_show_dom_chan_lvl_monitors(const struct cmis_memory_map *map,
+					    const struct sff_diags *sd)
+{
+	cmis_show_dom_chan_lvl_tx_bias(map, sd);
+	cmis_show_dom_chan_lvl_tx_power(map, sd);
+	cmis_show_dom_chan_lvl_rx_power(map, sd);
+}
+
+/* Print module-level flags. Relevant documents:
+ * [1] CMIS Rev. 5, page 109, section 8.2.4, Table 8-8
+ */
+static void cmis_show_dom_mod_lvl_flags(const struct cmis_memory_map *map)
+{
+	int i;
+
+	for (i = 0; cmis_aw_mod_flags[i].str; i++) {
+		printf("\t%-41s : %s\n", cmis_aw_mod_flags[i].str,
+		       map->lower_memory[cmis_aw_mod_flags[i].offset] &
+		       cmis_aw_mod_flags[i].value ? "On" : "Off");
+	}
+}
+
+/* Print channel-level flags. Relevant documents:
+ * [1] CMIS Rev. 5, page 162, section 8.9.3, Table 8-77
+ * [1] CMIS Rev. 5, page 164, section 8.9.3, Table 8-78
+ */
+static void cmis_show_dom_chan_lvl_flags_chan(const struct cmis_memory_map *map,
+					      int bank, int chan)
+{
+	const __u8 *page_11h = map->upper_memory[bank][0x11];
+	int i;
+
+	for (i = 0; cmis_aw_chan_flags[i].fmt_str; i++) {
+		char str[80];
+
+		if (!(map->page_01h[cmis_aw_chan_flags[i].adver_offset] &
+		      cmis_aw_chan_flags[i].adver_value))
+			continue;
+
+		snprintf(str, 80, cmis_aw_chan_flags[i].fmt_str, chan + 1);
+		printf("\t%-41s : %s\n", str,
+		       page_11h[cmis_aw_chan_flags[i].offset] & chan ?
+		       "On" : "Off");
+	}
+}
+
+static void
+cmis_show_dom_chan_lvl_flags_bank(const struct cmis_memory_map *map,
+				  int bank)
+{
+	const __u8 *page_11h = map->upper_memory[bank][0x11];
+	int i;
+
+	if (!page_11h)
+		return;
+
+	for (i = 0; i < CMIS_CHANNELS_PER_BANK; i++) {
+		int chan = bank * CMIS_CHANNELS_PER_BANK + i;
+
+		cmis_show_dom_chan_lvl_flags_chan(map, bank, chan);
+	}
+}
+
+static void cmis_show_dom_chan_lvl_flags(const struct cmis_memory_map *map)
+{
+	int i;
+
+	for (i = 0; i < CMIS_MAX_BANKS; i++)
+		cmis_show_dom_chan_lvl_flags_bank(map, i);
+}
+
+
+static void cmis_show_dom(const struct cmis_memory_map *map)
+{
+	struct sff_diags sd = {};
+
+	/* Diagnostic information is only relevant when the module memory
+	 * model is paged and not flat.
+	 */
+	if (map->lower_memory[CMIS_MEMORY_MODEL_OFFSET] &
+	    CMIS_MEMORY_MODEL_MASK)
+		return;
+
+	cmis_parse_dom(map, &sd);
+
+	cmis_show_dom_mod_lvl_monitors(&sd);
+	cmis_show_dom_chan_lvl_monitors(map, &sd);
+	cmis_show_dom_mod_lvl_flags(map);
+	cmis_show_dom_chan_lvl_flags(map);
+	if (sd.supports_alarms)
+		sff_show_thresholds(sd);
+}
+
 static void cmis_show_all_common(const struct cmis_memory_map *map)
 {
 	cmis_show_identifier(map);
@@ -360,10 +772,10 @@ static void cmis_show_all_common(const struct cmis_memory_map *map)
 	cmis_show_cbl_asm_len(map);
 	cmis_show_sig_integrity(map);
 	cmis_show_mit_compliance(map);
-	cmis_show_mod_lvl_monitors(map);
 	cmis_show_link_len(map);
 	cmis_show_vendor_info(map);
 	cmis_show_rev_compliance(map);
+	cmis_show_dom(map);
 }
 
 static void cmis_memory_map_init_buf(struct cmis_memory_map *map,
diff --git a/cmis.h b/cmis.h
index 8d90a04756ad..310697b0ef32 100644
--- a/cmis.h
+++ b/cmis.h
@@ -7,6 +7,18 @@
 #define CMIS_MEMORY_MODEL_OFFSET		0x02
 #define CMIS_MEMORY_MODEL_MASK			0x80
 
+/* Module Flags (Page 0) */
+#define CMIS_VCC_AW_OFFSET			0x09
+#define CMIS_VCC_LWARN_STATUS			0x80
+#define CMIS_VCC_HWARN_STATUS			0x40
+#define CMIS_VCC_LALARM_STATUS			0x20
+#define CMIS_VCC_HALARM_STATUS			0x10
+#define CMIS_TEMP_AW_OFFSET			0x09
+#define CMIS_TEMP_LWARN_STATUS			0x08
+#define CMIS_TEMP_HWARN_STATUS			0x04
+#define CMIS_TEMP_LALARM_STATUS			0x02
+#define CMIS_TEMP_HALARM_STATUS			0x01
+
 #define CMIS_MODULE_TYPE_OFFSET			0x55
 #define CMIS_MT_MMF				0x01
 #define CMIS_MT_SMF				0x02
@@ -121,10 +133,77 @@
 #define CMIS_BANK_0_1_SUPPORTED			0x01
 #define CMIS_BANK_0_3_SUPPORTED			0x02
 
+/* Module Characteristics Advertising (Page 1) */
+#define CMIS_DIAG_TYPE_OFFSET			0x97
+#define CMIS_RX_PWR_TYPE_MASK			0x10
+
+/* Supported Monitors Advertisement (Page 1) */
+#define CMIS_DIAG_CHAN_ADVER_OFFSET		0xA0
+#define CMIS_TX_BIAS_MON_MASK			0x01
+#define CMIS_TX_PWR_MON_MASK			0x02
+#define CMIS_RX_PWR_MON_MASK			0x04
+#define CMIS_TX_BIAS_MUL_MASK			0x18
+#define CMIS_TX_BIAS_MUL_1			0x00
+#define CMIS_TX_BIAS_MUL_2			0x08
+#define CMIS_TX_BIAS_MUL_4			0x10
+
 /* Signal integrity controls */
 #define CMIS_SIG_INTEG_TX_OFFSET		0xA1
 #define CMIS_SIG_INTEG_RX_OFFSET		0xA2
 
+/*-----------------------------------------------------------------------
+ * Upper Memory Page 0x02: Optional Page that informs about module-defined
+ * thresholds for module-level and lane-specific threshold crossing monitors.
+ */
+
+/* Module-Level Monitor Thresholds (Page 2) */
+#define CMIS_TEMP_HALRM_OFFSET			0x80
+#define CMIS_TEMP_LALRM_OFFSET			0x82
+#define CMIS_TEMP_HWARN_OFFSET			0x84
+#define CMIS_TEMP_LWARN_OFFSET			0x86
+#define CMIS_VCC_HALRM_OFFSET			0x88
+#define CMIS_VCC_LALRM_OFFSET			0x8A
+#define CMIS_VCC_HWARN_OFFSET			0x8C
+#define CMIS_VCC_LWARN_OFFSET			0x8E
+
+/* Lane-Related Monitor Thresholds (Page 2) */
+#define CMIS_TX_PWR_HALRM_OFFSET		0xB0
+#define CMIS_TX_PWR_LALRM_OFFSET		0xB2
+#define CMIS_TX_PWR_HWARN_OFFSET		0xB4
+#define CMIS_TX_PWR_LWARN_OFFSET		0xB6
+#define CMIS_TX_BIAS_HALRM_OFFSET		0xB8
+#define CMIS_TX_BIAS_LALRM_OFFSET		0xBA
+#define CMIS_TX_BIAS_HWARN_OFFSET		0xBC
+#define CMIS_TX_BIAS_LWARN_OFFSET		0xBE
+#define CMIS_RX_PWR_HALRM_OFFSET		0xC0
+#define CMIS_RX_PWR_LALRM_OFFSET		0xC2
+#define CMIS_RX_PWR_HWARN_OFFSET		0xC4
+#define CMIS_RX_PWR_LWARN_OFFSET		0xC6
+
+/*-----------------------------------------------------------------------
+ * Upper Memory Page 0x11: Optional Page that contains lane dynamic status
+ * bytes.
+ */
+
+/* Media Lane-Specific Flags (Page 0x11) */
+#define CMIS_TX_PWR_AW_HALARM_OFFSET		0x8B
+#define CMIS_TX_PWR_AW_LALARM_OFFSET		0x8C
+#define CMIS_TX_PWR_AW_HWARN_OFFSET		0x8D
+#define CMIS_TX_PWR_AW_LWARN_OFFSET		0x8E
+#define CMIS_TX_BIAS_AW_HALARM_OFFSET		0x8F
+#define CMIS_TX_BIAS_AW_LALARM_OFFSET		0x90
+#define CMIS_TX_BIAS_AW_HWARN_OFFSET		0x91
+#define CMIS_TX_BIAS_AW_LWARN_OFFSET		0x92
+#define CMIS_RX_PWR_AW_HALARM_OFFSET		0x95
+#define CMIS_RX_PWR_AW_LALARM_OFFSET		0x96
+#define CMIS_RX_PWR_AW_HWARN_OFFSET		0x97
+#define CMIS_RX_PWR_AW_LWARN_OFFSET		0x98
+
+/* Media Lane-Specific Monitors (Page 0x11) */
+#define CMIS_TX_PWR_OFFSET			0x9A
+#define CMIS_TX_BIAS_OFFSET			0xAA
+#define CMIS_RX_PWR_OFFSET			0xBA
+
 #define YESNO(x) (((x) != 0) ? "Yes" : "No")
 #define ONOFF(x) (((x) != 0) ? "On" : "Off")
 
-- 
2.31.1

[PATCH ethtool-next 6/8] cmis: Print Module State and Fault Cause

From: Ido Schimmel <hidden>
Date: 2021-11-23 17:41:38

From: Ido Schimmel <idosch@nvidia.com>

Print the CMIS Module State when dumping EEPROM contents via the '-m'
option. It can be used, for example, to test module power mode settings.

Example output:

 # ethtool -m swp11
 Identifier                                : 0x18 (QSFP-DD Double Density 8X Pluggable Transceiver (INF-8628))
 ...
 Module State                              : 0x03 (ModuleReady)

 # ethtool --set-module swp11 power-mode-policy auto

 # ethtool -m swp11
 Identifier                                : 0x18 (QSFP-DD Double Density 8X Pluggable Transceiver (INF-8628))
 ...
 Module State                              : 0x01 (ModuleLowPwr)

In case the module is in fault state, print the CMIS Module Fault Cause.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 cmis.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 cmis.h | 16 ++++++++++++++
 2 files changed, 86 insertions(+)
diff --git a/cmis.c b/cmis.c
index d7b7097139b3..a32cc9f8b1f6 100644
--- a/cmis.c
+++ b/cmis.c
@@ -402,6 +402,74 @@ static void cmis_show_vendor_info(const struct cmis_memory_map *map)
 			       CMIS_CLEI_END_OFFSET, "CLEI code");
 }
 
+/* Print the current Module State. Relevant documents:
+ * [1] CMIS Rev. 5, pag. 57, section 6.3.2.2, Figure 6-3
+ * [2] CMIS Rev. 5, pag. 60, section 6.3.2.3, Figure 6-4
+ * [3] CMIS Rev. 5, pag. 107, section 8.2.2, Table 8-6
+ */
+static void cmis_show_mod_state(const struct cmis_memory_map *map)
+{
+	__u8 mod_state;
+
+	mod_state = (map->lower_memory[CMIS_MODULE_STATE_OFFSET] &
+		     CMIS_MODULE_STATE_MASK) >> 1;
+	printf("\t%-41s : 0x%02x", "Module State", mod_state);
+	switch (mod_state) {
+	case CMIS_MODULE_STATE_MODULE_LOW_PWR:
+		printf(" (ModuleLowPwr)\n");
+		break;
+	case CMIS_MODULE_STATE_MODULE_PWR_UP:
+		printf(" (ModulePwrUp)\n");
+		break;
+	case CMIS_MODULE_STATE_MODULE_READY:
+		printf(" (ModuleReady)\n");
+		break;
+	case CMIS_MODULE_STATE_MODULE_PWR_DN:
+		printf(" (ModulePwrDn)\n");
+		break;
+	case CMIS_MODULE_STATE_MODULE_FAULT:
+		printf(" (ModuleFault)\n");
+		break;
+	default:
+		printf(" (reserved or unknown)\n");
+		break;
+	}
+}
+
+/* Print the Module Fault Information. Relevant documents:
+ * [1] CMIS Rev. 5, pag. 64, section 6.3.2.12
+ * [2] CMIS Rev. 5, pag. 115, section 8.2.10, Table 8-15
+ */
+static void cmis_show_mod_fault_cause(const struct cmis_memory_map *map)
+{
+	__u8 mod_state, fault_cause;
+
+	mod_state = (map->lower_memory[CMIS_MODULE_STATE_OFFSET] &
+		     CMIS_MODULE_STATE_MASK) >> 1;
+	if (mod_state != CMIS_MODULE_STATE_MODULE_FAULT)
+		return;
+
+	fault_cause = map->lower_memory[CMIS_MODULE_FAULT_OFFSET];
+	printf("\t%-41s : 0x%02x", "Module Fault Cause", fault_cause);
+	switch (fault_cause) {
+	case CMIS_MODULE_FAULT_NO_FAULT:
+		printf(" (No fault detected / not supported)\n");
+		break;
+	case CMIS_MODULE_FAULT_TEC_RUNAWAY:
+		printf(" (TEC runaway)\n");
+		break;
+	case CMIS_MODULE_FAULT_DATA_MEM_CORRUPTED:
+		printf(" (Data memory corrupted)\n");
+		break;
+	case CMIS_MODULE_FAULT_PROG_MEM_CORRUPTED:
+		printf(" (Program memory corrupted)\n");
+		break;
+	default:
+		printf(" (reserved or unknown)\n");
+		break;
+	}
+}
+
 static void cmis_parse_dom_power_type(const struct cmis_memory_map *map,
 				      struct sff_diags *sd)
 {
@@ -775,6 +843,8 @@ static void cmis_show_all_common(const struct cmis_memory_map *map)
 	cmis_show_link_len(map);
 	cmis_show_vendor_info(map);
 	cmis_show_rev_compliance(map);
+	cmis_show_mod_state(map);
+	cmis_show_mod_fault_cause(map);
 	cmis_show_dom(map);
 }
 
diff --git a/cmis.h b/cmis.h
index 310697b0ef32..2c67ad5640ab 100644
--- a/cmis.h
+++ b/cmis.h
@@ -7,6 +7,15 @@
 #define CMIS_MEMORY_MODEL_OFFSET		0x02
 #define CMIS_MEMORY_MODEL_MASK			0x80
 
+/* Global Status Information (Page 0) */
+#define CMIS_MODULE_STATE_OFFSET		0x03
+#define CMIS_MODULE_STATE_MASK			0x0E
+#define CMIS_MODULE_STATE_MODULE_LOW_PWR	0x01
+#define CMIS_MODULE_STATE_MODULE_PWR_UP		0x02
+#define CMIS_MODULE_STATE_MODULE_READY		0x03
+#define CMIS_MODULE_STATE_MODULE_PWR_DN		0x04
+#define CMIS_MODULE_STATE_MODULE_FAULT		0x05
+
 /* Module Flags (Page 0) */
 #define CMIS_VCC_AW_OFFSET			0x09
 #define CMIS_VCC_LWARN_STATUS			0x80
@@ -27,6 +36,13 @@
 #define CMIS_CURR_TEMP_OFFSET			0x0E
 #define CMIS_CURR_VCC_OFFSET			0x10
 
+/* Module Fault Information (Page 0) */
+#define CMIS_MODULE_FAULT_OFFSET		0x29
+#define CMIS_MODULE_FAULT_NO_FAULT		0x00
+#define CMIS_MODULE_FAULT_TEC_RUNAWAY		0x01
+#define CMIS_MODULE_FAULT_DATA_MEM_CORRUPTED	0x02
+#define CMIS_MODULE_FAULT_PROG_MEM_CORRUPTED	0x03
+
 #define CMIS_CTOR_OFFSET			0xCB
 
 /* Vendor related information (Page 0) */
-- 
2.31.1

[PATCH ethtool-next 7/8] cmis: Print Module-Level Controls

From: Ido Schimmel <hidden>
Date: 2021-11-23 17:41:40

From: Ido Schimmel <idosch@nvidia.com>

Print the CMIS Module-Level Controls when dumping EEPROM contents via
the '-m' option. It can be used to understand low power mode enforcement
by the host.

Example output:

 # ethtool -m swp11
 Identifier                                : 0x18 (QSFP-DD Double Density 8X Pluggable Transceiver (INF-8628))
 ...
 Module State                              : 0x03 (ModuleReady)
 LowPwrAllowRequestHW                      : Off
 LowPwrRequestSW                           : Off
 ...
 Transmit avg optical power (Channel 1)    : 1.3222 mW / 1.21 dBm
 Transmit avg optical power (Channel 2)    : 1.2666 mW / 1.03 dBm
 Transmit avg optical power (Channel 3)    : 1.2860 mW / 1.09 dBm
 Transmit avg optical power (Channel 4)    : 1.2988 mW / 1.14 dBm
 Transmit avg optical power (Channel 5)    : 1.2828 mW / 1.08 dBm
 Transmit avg optical power (Channel 6)    : 1.2913 mW / 1.11 dBm
 Transmit avg optical power (Channel 7)    : 1.2636 mW / 1.02 dBm
 Transmit avg optical power (Channel 8)    : 1.3408 mW / 1.27 dBm
 Transmit avg optical power (Channel 9)    : 1.3222 mW / 1.21 dBm
 Transmit avg optical power (Channel 10)   : 1.2666 mW / 1.03 dBm
 Transmit avg optical power (Channel 11)   : 1.2860 mW / 1.09 dBm
 Transmit avg optical power (Channel 12)   : 1.2988 mW / 1.14 dBm
 Transmit avg optical power (Channel 13)   : 1.2828 mW / 1.08 dBm
 Transmit avg optical power (Channel 14)   : 1.2913 mW / 1.11 dBm
 Transmit avg optical power (Channel 15)   : 1.2636 mW / 1.02 dBm
 Transmit avg optical power (Channel 16)   : 1.3408 mW / 1.27 dBm
 Rcvr signal avg optical power (Channel 1) : 1.1351 mW / 0.55 dBm
 Rcvr signal avg optical power (Channel 2) : 1.1603 mW / 0.65 dBm
 Rcvr signal avg optical power (Channel 3) : 1.1529 mW / 0.62 dBm
 Rcvr signal avg optical power (Channel 4) : 1.1670 mW / 0.67 dBm
 Rcvr signal avg optical power (Channel 5) : 1.1759 mW / 0.70 dBm
 Rcvr signal avg optical power (Channel 6) : 1.1744 mW / 0.70 dBm
 Rcvr signal avg optical power (Channel 7) : 1.1188 mW / 0.49 dBm
 Rcvr signal avg optical power (Channel 8) : 1.1640 mW / 0.66 dBm
 Rcvr signal avg optical power (Channel 9) : 1.1351 mW / 0.55 dBm
 Rcvr signal avg optical power (Channel 10) : 1.1603 mW / 0.65 dBm
 Rcvr signal avg optical power (Channel 11) : 1.1529 mW / 0.62 dBm
 Rcvr signal avg optical power (Channel 12) : 1.1670 mW / 0.67 dBm
 Rcvr signal avg optical power (Channel 13) : 1.1759 mW / 0.70 dBm
 Rcvr signal avg optical power (Channel 14) : 1.1744 mW / 0.70 dBm
 Rcvr signal avg optical power (Channel 15) : 1.1188 mW / 0.49 dBm
 Rcvr signal avg optical power (Channel 16) : 1.1640 mW / 0.66 dBm

 # ethtool --set-module swp11 power-mode-policy auto

 # ethtool -m swp11
 Identifier                                : 0x18 (QSFP-DD Double Density 8X Pluggable Transceiver (INF-8628))
 ...
 Module State                              : 0x01 (ModuleLowPwr)
 LowPwrAllowRequestHW                      : Off
 LowPwrRequestSW                           : On
 ...
 Transmit avg optical power (Channel 1)    : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 2)    : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 3)    : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 4)    : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 5)    : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 6)    : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 7)    : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 8)    : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 9)    : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 10)   : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 11)   : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 12)   : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 13)   : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 14)   : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 15)   : 0.0001 mW / -40.00 dBm
 Transmit avg optical power (Channel 16)   : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 1) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 2) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 3) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 4) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 5) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 6) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 7) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 8) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 9) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 10) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 11) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 12) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 13) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 14) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 15) : 0.0001 mW / -40.00 dBm
 Rcvr signal avg optical power (Channel 16) : 0.0001 mW / -40.00 dBm

 # ethtool --set-module swp11 power-mode-policy high

 # ethtool -m swp11
 Identifier                                : 0x18 (QSFP-DD Double Density 8X Pluggable Transceiver (INF-8628))
 ...
 Module State                              : 0x03 (ModuleReady)
 LowPwrAllowRequestHW                      : Off
 LowPwrRequestSW                           : Off
 ...
 Transmit avg optical power (Channel 1)    : 1.3690 mW / 1.36 dBm
 Transmit avg optical power (Channel 2)    : 1.3036 mW / 1.15 dBm
 Transmit avg optical power (Channel 3)    : 1.3358 mW / 1.26 dBm
 Transmit avg optical power (Channel 4)    : 1.3509 mW / 1.31 dBm
 Transmit avg optical power (Channel 5)    : 1.3193 mW / 1.20 dBm
 Transmit avg optical power (Channel 6)    : 1.3314 mW / 1.24 dBm
 Transmit avg optical power (Channel 7)    : 1.3042 mW / 1.15 dBm
 Transmit avg optical power (Channel 8)    : 1.3919 mW / 1.44 dBm
 Transmit avg optical power (Channel 9)    : 1.3690 mW / 1.36 dBm
 Transmit avg optical power (Channel 10)   : 1.3036 mW / 1.15 dBm
 Transmit avg optical power (Channel 11)   : 1.3358 mW / 1.26 dBm
 Transmit avg optical power (Channel 12)   : 1.3509 mW / 1.31 dBm
 Transmit avg optical power (Channel 13)   : 1.3193 mW / 1.20 dBm
 Transmit avg optical power (Channel 14)   : 1.3314 mW / 1.24 dBm
 Transmit avg optical power (Channel 15)   : 1.3042 mW / 1.15 dBm
 Transmit avg optical power (Channel 16)   : 1.3919 mW / 1.44 dBm
 Rcvr signal avg optical power (Channel 1) : 1.1299 mW / 0.53 dBm
 Rcvr signal avg optical power (Channel 2) : 1.1566 mW / 0.63 dBm
 Rcvr signal avg optical power (Channel 3) : 1.1484 mW / 0.60 dBm
 Rcvr signal avg optical power (Channel 4) : 1.1655 mW / 0.67 dBm
 Rcvr signal avg optical power (Channel 5) : 1.1751 mW / 0.70 dBm
 Rcvr signal avg optical power (Channel 6) : 1.1595 mW / 0.64 dBm
 Rcvr signal avg optical power (Channel 7) : 1.1158 mW / 0.48 dBm
 Rcvr signal avg optical power (Channel 8) : 1.1595 mW / 0.64 dBm
 Rcvr signal avg optical power (Channel 9) : 1.1299 mW / 0.53 dBm
 Rcvr signal avg optical power (Channel 10) : 1.1566 mW / 0.63 dBm
 Rcvr signal avg optical power (Channel 11) : 1.1484 mW / 0.60 dBm
 Rcvr signal avg optical power (Channel 12) : 1.1655 mW / 0.67 dBm
 Rcvr signal avg optical power (Channel 13) : 1.1751 mW / 0.70 dBm
 Rcvr signal avg optical power (Channel 14) : 1.1595 mW / 0.64 dBm
 Rcvr signal avg optical power (Channel 15) : 1.1158 mW / 0.48 dBm
 Rcvr signal avg optical power (Channel 16) : 1.1595 mW / 0.64 dBm

In the above example, the LowPwrRequestHW signal is ignored and low
power mode is controlled via software only.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 cmis.c | 15 +++++++++++++++
 cmis.h |  5 +++++
 2 files changed, 20 insertions(+)
diff --git a/cmis.c b/cmis.c
index a32cc9f8b1f6..d0b62728e998 100644
--- a/cmis.c
+++ b/cmis.c
@@ -470,6 +470,20 @@ static void cmis_show_mod_fault_cause(const struct cmis_memory_map *map)
 	}
 }
 
+/* Print the current Module-Level Controls. Relevant documents:
+ * [1] CMIS Rev. 5, pag. 58, section 6.3.2.2, Table 6-12
+ * [2] CMIS Rev. 5, pag. 111, section 8.2.6, Table 8-10
+ */
+static void cmis_show_mod_lvl_controls(const struct cmis_memory_map *map)
+{
+	printf("\t%-41s : ", "LowPwrAllowRequestHW");
+	printf("%s\n", ONOFF(map->lower_memory[CMIS_MODULE_CONTROL_OFFSET] &
+			     CMIS_LOW_PWR_ALLOW_REQUEST_HW_MASK));
+	printf("\t%-41s : ", "LowPwrRequestSW");
+	printf("%s\n", ONOFF(map->lower_memory[CMIS_MODULE_CONTROL_OFFSET] &
+			     CMIS_LOW_PWR_REQUEST_SW_MASK));
+}
+
 static void cmis_parse_dom_power_type(const struct cmis_memory_map *map,
 				      struct sff_diags *sd)
 {
@@ -845,6 +859,7 @@ static void cmis_show_all_common(const struct cmis_memory_map *map)
 	cmis_show_rev_compliance(map);
 	cmis_show_mod_state(map);
 	cmis_show_mod_fault_cause(map);
+	cmis_show_mod_lvl_controls(map);
 	cmis_show_dom(map);
 }
 
diff --git a/cmis.h b/cmis.h
index 2c67ad5640ab..46797081f13c 100644
--- a/cmis.h
+++ b/cmis.h
@@ -36,6 +36,11 @@
 #define CMIS_CURR_TEMP_OFFSET			0x0E
 #define CMIS_CURR_VCC_OFFSET			0x10
 
+/* Module Global Controls (Page 0) */
+#define CMIS_MODULE_CONTROL_OFFSET		0x1A
+#define CMIS_LOW_PWR_ALLOW_REQUEST_HW_MASK	0x40
+#define CMIS_LOW_PWR_REQUEST_SW_MASK		0x10
+
 /* Module Fault Information (Page 0) */
 #define CMIS_MODULE_FAULT_OFFSET		0x29
 #define CMIS_MODULE_FAULT_NO_FAULT		0x00
-- 
2.31.1

[PATCH ethtool-next 8/8] sff-8636: Print Power set and Power override bits

From: Ido Schimmel <hidden>
Date: 2021-11-23 17:41:42

From: Ido Schimmel <idosch@nvidia.com>

Print the SFF-8636 Power set and Power override bits when dumping EEPROM
contents via the '-m' option. They can be used to understand low power
mode enforcement by the host.

The 'SFF8636_LOW_PWR_MODE' define is renamed to 'SFF8636_LOW_PWR_SET' to
reflect its naming in the standard for QSFP+/QSFP28.

Example output:

 # ethtool -m swp13
 Identifier                                : 0x11 (QSFP28)
 ...
 Extended identifier description           : 5.0W max. Power consumption,  High Power Class (> 3.5 W) enabled
 Power set                                 : Off
 Power override                            : On
 ...
 Transmit avg optical power (Channel 1)    : 0.7633 mW / -1.17 dBm
 Transmit avg optical power (Channel 2)    : 0.7649 mW / -1.16 dBm
 Transmit avg optical power (Channel 3)    : 0.7696 mW / -1.14 dBm
 Transmit avg optical power (Channel 4)    : 0.7739 mW / -1.11 dBm
 Rcvr signal avg optical power(Channel 1)  : 0.9240 mW / -0.34 dBm
 Rcvr signal avg optical power(Channel 2)  : 0.9129 mW / -0.40 dBm
 Rcvr signal avg optical power(Channel 3)  : 0.9194 mW / -0.36 dBm
 Rcvr signal avg optical power(Channel 4)  : 0.8708 mW / -0.60 dBm

 # ethtool --set-module swp13 power-mode-policy auto

 # ethtool -m swp13
 Identifier                                : 0x11 (QSFP28)
 ...
 Extended identifier description           : 5.0W max. Power consumption,  High Power Class (> 3.5 W) not enabled
 Power set                                 : On
 Power override                            : On
 ...
 Transmit avg optical power (Channel 1)    : 0.0000 mW / -inf dBm
 Transmit avg optical power (Channel 2)    : 0.0000 mW / -inf dBm
 Transmit avg optical power (Channel 3)    : 0.0000 mW / -inf dBm
 Transmit avg optical power (Channel 4)    : 0.0000 mW / -inf dBm
 Rcvr signal avg optical power(Channel 1)  : 0.0000 mW / -inf dBm
 Rcvr signal avg optical power(Channel 2)  : 0.0000 mW / -inf dBm
 Rcvr signal avg optical power(Channel 3)  : 0.0000 mW / -inf dBm
 Rcvr signal avg optical power(Channel 4)  : 0.0000 mW / -inf dBm

 # ethtool --set-module swp13 power-mode-policy high

 # ethtool -m swp13
 Identifier                                : 0x11 (QSFP28)
 ...
 Extended identifier description           : 5.0W max. Power consumption,  High Power Class (> 3.5 W) enabled
 Power set                                 : Off
 Power override                            : On
 ...
 Transmit avg optical power (Channel 1)    : 0.7733 mW / -1.12 dBm
 Transmit avg optical power (Channel 2)    : 0.7754 mW / -1.10 dBm
 Transmit avg optical power (Channel 3)    : 0.7885 mW / -1.03 dBm
 Transmit avg optical power (Channel 4)    : 0.7886 mW / -1.03 dBm
 Rcvr signal avg optical power(Channel 1)  : 0.9248 mW / -0.34 dBm
 Rcvr signal avg optical power(Channel 2)  : 0.9129 mW / -0.40 dBm
 Rcvr signal avg optical power(Channel 3)  : 0.9187 mW / -0.37 dBm
 Rcvr signal avg optical power(Channel 4)  : 0.8785 mW / -0.56 dBm

In the above example, the LPMode signal is ignored (Power override is
always on) and low power mode is controlled via software only.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 qsfp.c | 6 ++++++
 qsfp.h | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/qsfp.c b/qsfp.c
index b3c9e1516af9..57aac86bd5f6 100644
--- a/qsfp.c
+++ b/qsfp.c
@@ -268,6 +268,12 @@ static void sff8636_show_ext_identifier(const struct sff8636_memory_map *map)
 		printf(" High Power Class (> 3.5 W) enabled\n");
 	else
 		printf(" High Power Class (> 3.5 W) not enabled\n");
+	printf("\t%-41s : ", "Power set");
+	printf("%s\n", ONOFF(map->lower_memory[SFF8636_PWR_MODE_OFFSET] &
+			     SFF8636_LOW_PWR_SET));
+	printf("\t%-41s : ", "Power override");
+	printf("%s\n", ONOFF(map->lower_memory[SFF8636_PWR_MODE_OFFSET] &
+			     SFF8636_PWR_OVERRIDE));
 }
 
 static void sff8636_show_connector(const struct sff8636_memory_map *map)
diff --git a/qsfp.h b/qsfp.h
index 1d8f24b5cbc2..aabf09fdc623 100644
--- a/qsfp.h
+++ b/qsfp.h
@@ -180,7 +180,7 @@
 
 #define	SFF8636_PWR_MODE_OFFSET		0x5D
 #define	 SFF8636_HIGH_PWR_ENABLE		(1 << 2)
-#define	 SFF8636_LOW_PWR_MODE			(1 << 1)
+#define	 SFF8636_LOW_PWR_SET			(1 << 1)
 #define	 SFF8636_PWR_OVERRIDE			(1 << 0)
 
 #define	SFF8636_TX_APP_SELECT_4_OFFSET	0x5E
-- 
2.31.1

Re: [PATCH ethtool-next 0/8] ethtool: Add support for CMIS diagnostic information

From: Michal Kubecek <hidden>
Date: 2021-12-02 21:45:23

On Tue, Nov 23, 2021 at 07:40:54PM +0200, Ido Schimmel wrote:
From: Ido Schimmel <idosch@nvidia.com>

This patchset extends ethtool(8) to retrieve, parse and print CMIS
diagnostic information. This information includes module-level monitors
(e.g., temperature, voltage), channel-level monitors (e.g., Tx optical
power) and related thresholds and flags.

ethtool(8) already supports SFF-8636 (e.g., QSFP) and SFF-8472 (e.g.,
SFP) diagnostic information, but until recently CMIS diagnostic
information was unavailable to ethtool(8) as it resides in optional and
banked pages.

Testing
=======

Build tested each patch with the following configuration options:

netlink | pretty-dump
--------|------------
v       | v
x       | x
v       | x
x       | v

Except fields that were added, no difference in output before and after
the patchset. Tested with both PC and AOC QSFP-DD modules.

No reports from AddressSanitizer / valgrind.

Patchset overview
=================

Patches #1-#2 are small preparations.

Patches #3-#4 retrieve (over netlink) and initialize the optional and
banked pages in the CMIS memory map. These pages contain the previously
mentioned diagnostic information.

Patch #5 parses and prints the CMIS diagnostic information in a similar
fashion to the way it is done for SFF-8636.

Patches #6-#7 print a few additional fields from the CMIS EEPROM dump.
The examples contain an ethtool command that is supported by the kernel,
but not yet by ethtool(8). It will be sent as a follow-up patchset.

Patch #8 prints the equivalent module-level fields for SFF-8636.
The series looks good to me and I'm ready to merge it but as it is
marked "ethtool-next", I better make sure: is it OK to merge it into
master branch (targeting ethtool 5.16)? In other words, do I see
correctly that it does not depend on any features that would be missing
in 5.16 kernel?

Michal

Re: [PATCH ethtool-next 0/8] ethtool: Add support for CMIS diagnostic information

From: Ido Schimmel <hidden>
Date: 2021-12-02 21:53:05

On Thu, Dec 02, 2021 at 10:45:18PM +0100, Michal Kubecek wrote:
The series looks good to me and I'm ready to merge it but as it is
marked "ethtool-next", I better make sure: is it OK to merge it into
master branch (targeting ethtool 5.16)? In other words, do I see
correctly that it does not depend on any features that would be missing
in 5.16 kernel?
Yes

Re: [PATCH ethtool-next 2/8] sff-common: Move OFFSET_TO_U16_PTR() to common header file

From: Michal Kubecek <hidden>
Date: 2021-12-02 21:55:11

On Tue, Nov 23, 2021 at 07:40:56PM +0200, Ido Schimmel wrote:
quoted hunk
From: Ido Schimmel <idosch@nvidia.com>

The define is also useful for CMIS, so move it from SFF-8636 to the
common header file.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 qsfp.c       | 1 -
 sff-common.h | 4 ++--
 2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/qsfp.c b/qsfp.c
index 58c4c4775e9b..b3c9e1516af9 100644
--- a/qsfp.c
+++ b/qsfp.c
@@ -700,7 +700,6 @@ sff8636_show_wavelength_or_copper_compliance(const struct sff8636_memory_map *ma
  * Second byte are 1/256th of degree, which are added to the dec part.
  */
 #define SFF8636_OFFSET_TO_TEMP(offset) ((__s16)OFFSET_TO_U16(offset))
-#define OFFSET_TO_U16_PTR(ptr, offset) (ptr[offset] << 8 | ptr[(offset) + 1])
 
 static void sff8636_dom_parse(const struct sff8636_memory_map *map,
 			      struct sff_diags *sd)
diff --git a/sff-common.h b/sff-common.h
index aab306e0b74f..9e323008ba19 100644
--- a/sff-common.h
+++ b/sff-common.h
@@ -126,8 +126,8 @@
 #define  SFF8024_ENCODING_PAM4			0x08
 
 /* Most common case: 16-bit unsigned integer in a certain unit */
-#define OFFSET_TO_U16(offset) \
-		(id[offset] << 8 | id[(offset) + 1])
+#define OFFSET_TO_U16_PTR(ptr, offset) (ptr[offset] << 8 | ptr[(offset) + 1])
+#define OFFSET_TO_U16(offset) OFFSET_TO_U16_PTR(id, offset)
I'm aware that you are just moving an old piece of code around so this
is rather meant as a tip for a future cleanup: OFFSET_TO_U16_PTR() does
not really need to be a macro so an inline function would be cleaner
(and type safe). OFFSET_TO_U16() is only used in 4 places, AFAICS, so
it is IMHO questionable if it is worth the worse readability.

Michal
 
 # define PRINT_xX_PWR(string, var)                             \
 		printf("\t%-41s : %.4f mW / %.2f dBm\n", (string),         \
-- 
2.31.1

Re: [PATCH ethtool-next 0/8] ethtool: Add support for CMIS diagnostic information

From: patchwork-bot+netdevbpf@kernel.org
Date: 2021-12-02 22:00:28

Hello:

This series was applied to ethtool/ethtool.git (master)
by Michal Kubecek [off-list ref]:

On Tue, 23 Nov 2021 19:40:54 +0200 you wrote:
From: Ido Schimmel <idosch@nvidia.com>

This patchset extends ethtool(8) to retrieve, parse and print CMIS
diagnostic information. This information includes module-level monitors
(e.g., temperature, voltage), channel-level monitors (e.g., Tx optical
power) and related thresholds and flags.

[...]
Here is the summary with links:
  - [ethtool-next,1/8] sff-8636: Use an SFF-8636 specific define for maximum number of channels
    https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/commit/?id=73091cd94023
  - [ethtool-next,2/8] sff-common: Move OFFSET_TO_U16_PTR() to common header file
    https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/commit/?id=837c1662ebd6
  - [ethtool-next,3/8] cmis: Initialize Page 02h in memory map
    https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/commit/?id=8658852e0ef7
  - [ethtool-next,4/8] cmis: Initialize Banked Page 11h in memory map
    https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/commit/?id=27b42a92286b
  - [ethtool-next,5/8] cmis: Parse and print diagnostic information
    https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/commit/?id=340d88ee1289
  - [ethtool-next,6/8] cmis: Print Module State and Fault Cause
    https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/commit/?id=eae6a99f3d13
  - [ethtool-next,7/8] cmis: Print Module-Level Controls
    https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/commit/?id=82012f2dbfeb
  - [ethtool-next,8/8] sff-8636: Print Power set and Power override bits
    https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/commit/?id=d7b100713f73

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html

Re: [PATCH ethtool-next 0/8] ethtool: Add support for CMIS diagnostic information

From: Michal Kubecek <hidden>
Date: 2021-12-02 22:01:16

On Thu, Dec 02, 2021 at 11:52:59PM +0200, Ido Schimmel wrote:
On Thu, Dec 02, 2021 at 10:45:18PM +0100, Michal Kubecek wrote:
quoted
The series looks good to me and I'm ready to merge it but as it is
marked "ethtool-next", I better make sure: is it OK to merge it into
master branch (targeting ethtool 5.16)? In other words, do I see
correctly that it does not depend on any features that would be missing
in 5.16 kernel?
Yes
Thank you. The series is merged into master branch now.

Michal
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help