lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1664326724-1415-3-git-send-email-michael.chan@broadcom.com>
Date:   Tue, 27 Sep 2022 20:58:40 -0400
From:   Michael Chan <michael.chan@...adcom.com>
To:     davem@...emloft.net
Cc:     netdev@...r.kernel.org, kuba@...nel.org, edumazet@...gle.com,
        pabeni@...hat.com, gospo@...adcom.com, vikas.gupta@...adcom.com
Subject: [PATCH net-next 2/6] bnxt_en: add support for QSFP optional EEPROM data

From: Edwin Peer <edwin.peer@...adcom.com>

SFF 8636 defines several optional pages. This patch adds support up to
and including page 3. The ethtool offset needs to be mapped onto the
appropriate device page and I2C address, which is handled differently
depending on module type. The necessary linear offset to raw page
mapping is performed based on a table that is configured according to
the module capabilities.

Signed-off-by: Edwin Peer <edwin.peer@...adcom.com>
Signed-off-by: Michael Chan <michael.chan@...adcom.com>
---
 drivers/net/ethernet/broadcom/bnxt/bnxt.h     |   5 +
 .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 120 +++++++++++++++---
 2 files changed, 108 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index b1b17f911300..c54f8c9ab3ad 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -2206,6 +2206,11 @@ struct bnxt {
 #define SFF_MODULE_ID_QSFP			0xc
 #define SFF_MODULE_ID_QSFP_PLUS			0xd
 #define SFF_MODULE_ID_QSFP28			0x11
+#define SFF8636_FLATMEM_OFFSET			0x2
+#define SFF8636_FLATMEM_MASK			0x4
+#define SFF8636_OPT_PAGES_OFFSET		0xc3
+#define SFF8636_PAGE1_MASK			0x40
+#define SFF8636_PAGE2_MASK			0x80
 #define BNXT_MAX_PHY_I2C_RESP_SIZE		64
 
 static inline u32 bnxt_tx_avail(struct bnxt *bp, struct bnxt_tx_ring_info *txr)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index f57e524c7e30..6596dca94c3d 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -3220,7 +3220,9 @@ static int bnxt_get_module_info(struct net_device *dev,
 			break;
 		case SFF_MODULE_ID_QSFP28:
 			modinfo->type = ETH_MODULE_SFF_8636;
-			modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
+			modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN;
+			if (data[SFF8636_FLATMEM_OFFSET] & SFF8636_FLATMEM_MASK)
+				modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
 			break;
 		default:
 			rc = -EOPNOTSUPP;
@@ -3234,32 +3236,116 @@ static int bnxt_get_module_eeprom(struct net_device *dev,
 				  struct ethtool_eeprom *eeprom,
 				  u8 *data)
 {
+	u8 pg_addr[5] = { I2C_DEV_ADDR_A0, I2C_DEV_ADDR_A0 };
+	u16 offset = eeprom->offset, length = eeprom->len;
+	u8 module_info[SFF_DIAG_SUPPORT_OFFSET + 1];
 	struct bnxt *bp = netdev_priv(dev);
-	u16  start = eeprom->offset, length = eeprom->len;
+	u8 page = offset >> 7;
+	u8 max_pages = 2;
 	int rc = 0;
 
-	memset(data, 0, eeprom->len);
+	rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0, 0,
+					      SFF_DIAG_SUPPORT_OFFSET + 1,
+					      module_info);
+	if (rc)
+		return rc;
+
+	switch (module_info[0]) {
+	case SFF_MODULE_ID_SFP:
+		if (module_info[SFF_DIAG_SUPPORT_OFFSET]) {
+			pg_addr[2] = I2C_DEV_ADDR_A2;
+			pg_addr[3] = I2C_DEV_ADDR_A2;
+			max_pages = 4;
+		}
+		break;
+	case SFF_MODULE_ID_QSFP28: {
+		u8 opt_pages;
 
-	/* Read A0 portion of the EEPROM */
-	if (start < ETH_MODULE_SFF_8436_LEN) {
-		if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN)
-			length = ETH_MODULE_SFF_8436_LEN - start;
 		rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0,
-						      start, length, data);
+						      SFF8636_OPT_PAGES_OFFSET,
+						      1, &opt_pages);
 		if (rc)
 			return rc;
-		start += length;
-		data += length;
-		length = eeprom->len - length;
+
+		if (opt_pages & SFF8636_PAGE1_MASK) {
+			pg_addr[2] = I2C_DEV_ADDR_A0;
+			max_pages = 3;
+		}
+		if (opt_pages & SFF8636_PAGE2_MASK) {
+			pg_addr[3] = I2C_DEV_ADDR_A0;
+			max_pages = 4;
+		}
+		if (~module_info[SFF8636_FLATMEM_OFFSET] & SFF8636_FLATMEM_MASK) {
+			pg_addr[4] = I2C_DEV_ADDR_A0;
+			max_pages = 5;
+		}
+		break;
 	}
+	default:
+		break;
+	}
+
+	memset(data, 0, eeprom->len);
 
-	/* Read A2 portion of the EEPROM */
-	if (length) {
-		start -= ETH_MODULE_SFF_8436_LEN;
-		rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 0,
-						      start, length, data);
+	/* Read the two 128B base pages in a single pass, since they are
+	 * always supported and both sourced from I2C_DEV_ADDR_A0. Then,
+	 * read individual 128B or 256B chunks as appropriate, according
+	 * to the mappings defined in pg_addr[], which is setup based on
+	 * module capabilities.
+	 *
+	 * The first two pages are both numbered page zero, lower page 0
+	 * and upper page 0 respectively. Raw device pages are numbered
+	 * sequentially thereafter. For SFP modules, reads are always
+	 * from page zero. In this case, the A2 base address is used in
+	 * lieu of the page number to signal reading the upper 256B, with
+	 * offsets relative to the base of this larger I2C region.
+	 *
+	 * Note there may be gaps in the linear ethtool mapping that are
+	 * not backed by raw module pages. Reads to such pages should not
+	 * be attempted because the HWRM call would fail. The caller will
+	 * simply see the preinitialized zeroes in these holes.
+	 *
+	 * Also note, the implementation below depends on pages mapped as
+	 * I2C_DEV_ADDR_A2 in pg_addr[] appearing as 256B aligned pairs.
+	 * This constraint means that it doesn't matter whether the even
+	 * or odd page is used in determining the I2C base address of a
+	 * given region. This allows for larger chunk sizes to be read
+	 * for A2 pages and happens to correspond nicely with the memory
+	 * maps of all currently supported modules. The optional 128B
+	 * A0 pages need to be read relative to an offset of 128B, which
+	 * is where they appear in module memory maps, while the 256B A2
+	 * page pair regions are interpreted by firmware relative to
+	 * offset 0.
+	 */
+	offset &= 0xff;
+	while (length && page < max_pages) {
+		u8 raw_page = page ? page - 1 : 0;
+		u16 chunk;
+
+		if (pg_addr[page] == I2C_DEV_ADDR_A2)
+			raw_page = 0;
+		else if (page)
+			offset |= 0x80;
+		chunk = min_t(u16, length, 256 - offset);
+
+		if (pg_addr[page]) {
+			rc = bnxt_read_sfp_module_eeprom_info(bp, pg_addr[page],
+							      raw_page, offset,
+							      chunk, data);
+			if (rc)
+				return rc;
+		}
+
+		data += chunk;
+		length -= chunk;
+		offset = 0;
+		page += 1 + (chunk > 128);
 	}
-	return rc;
+
+	if (length)
+		return -EINVAL;
+
+	return 0;
 }
 
 static int bnxt_nway_reset(struct net_device *dev)
-- 
2.18.1


Download attachment "smime.p7s" of type "application/pkcs7-signature" (4209 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ