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)
