Blame SOURCES/0031-cmis-Parse-and-print-diagnostic-information.patch

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