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