Denis Kirjanov ebb326
From 2f7126038cc52b506702bdc7056f36298b8a28ce Mon Sep 17 00:00:00 2001
Denis Kirjanov ebb326
From: Vladyslav Tarasiuk <vladyslavt@nvidia.com>
Denis Kirjanov ebb326
Date: Sun, 9 May 2021 09:43:18 +0300
Denis Kirjanov ebb326
Subject: [PATCH 16/19] net/mlx4: Fix EEPROM dump support
Denis Kirjanov ebb326
Git-commit: db825feefc6868896fed5e361787ba3bee2fd906
Denis Kirjanov ebb326
Patch-mainline: v5.13-rc4
Denis Kirjanov ebb326
References: git-fixes
Denis Kirjanov ebb326
Denis Kirjanov ebb326
Fix SFP and QSFP* EEPROM queries by setting i2c_address, offset and page
Denis Kirjanov ebb326
number correctly. For SFP set the following params:
Denis Kirjanov ebb326
- I2C address for offsets 0-255 is 0x50. For 256-511 - 0x51.
Denis Kirjanov ebb326
- Page number is zero.
Denis Kirjanov ebb326
- Offset is 0-255.
Denis Kirjanov ebb326
Denis Kirjanov ebb326
At the same time, QSFP* parameters are different:
Denis Kirjanov ebb326
- I2C address is always 0x50.
Denis Kirjanov ebb326
- Page number is not limited to zero.
Denis Kirjanov ebb326
- Offset is 0-255 for page zero and 128-255 for others.
Denis Kirjanov ebb326
Denis Kirjanov ebb326
To set parameters accordingly to cable used, implement function to query
Denis Kirjanov ebb326
module ID and implement respective helper functions to set parameters
Denis Kirjanov ebb326
correctly.
Denis Kirjanov ebb326
Denis Kirjanov ebb326
Fixes: 135dd9594f12 ("net/mlx4_en: ethtool, Remove unsupported SFP EEPROM high pages query")
Denis Kirjanov ebb326
Signed-off-by: Vladyslav Tarasiuk <vladyslavt@nvidia.com>
Denis Kirjanov ebb326
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Denis Kirjanov ebb326
Signed-off-by: David S. Miller <davem@davemloft.net>
Denis Kirjanov ebb326
Signed-off-by: Denis Kirjanov <denis.kirjanov@suse.com>
Denis Kirjanov ebb326
---
Denis Kirjanov ebb326
 drivers/net/ethernet/mellanox/mlx4/en_ethtool.c |   4 +-
Denis Kirjanov ebb326
 drivers/net/ethernet/mellanox/mlx4/port.c       | 107 +++++++++++++++++++++++-
Denis Kirjanov ebb326
 2 files changed, 104 insertions(+), 7 deletions(-)
Denis Kirjanov ebb326
Denis Kirjanov ebb326
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
Denis Kirjanov ebb326
index 7a99eb1572fd..6a005014d46a 100644
Denis Kirjanov ebb326
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
Denis Kirjanov ebb326
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
Denis Kirjanov ebb326
@@ -2011,8 +2011,6 @@ static int mlx4_en_set_tunable(struct net_device *dev,
Denis Kirjanov ebb326
 	return ret;
Denis Kirjanov ebb326
 }
Denis Kirjanov ebb326
 
Denis Kirjanov ebb326
-#define MLX4_EEPROM_PAGE_LEN 256
Denis Kirjanov ebb326
-
Denis Kirjanov ebb326
 static int mlx4_en_get_module_info(struct net_device *dev,
Denis Kirjanov ebb326
 				   struct ethtool_modinfo *modinfo)
Denis Kirjanov ebb326
 {
Denis Kirjanov ebb326
@@ -2047,7 +2045,7 @@ static int mlx4_en_get_module_info(struct net_device *dev,
Denis Kirjanov ebb326
 		break;
Denis Kirjanov ebb326
 	case MLX4_MODULE_ID_SFP:
Denis Kirjanov ebb326
 		modinfo->type = ETH_MODULE_SFF_8472;
Denis Kirjanov ebb326
-		modinfo->eeprom_len = MLX4_EEPROM_PAGE_LEN;
Denis Kirjanov ebb326
+		modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
Denis Kirjanov ebb326
 		break;
Denis Kirjanov ebb326
 	default:
Denis Kirjanov ebb326
 		return -EINVAL;
Denis Kirjanov ebb326
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
Denis Kirjanov ebb326
index ba6ac31a339d..256a06b3c096 100644
Denis Kirjanov ebb326
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
Denis Kirjanov ebb326
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
Denis Kirjanov ebb326
@@ -1973,6 +1973,7 @@ EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
Denis Kirjanov ebb326
 #define I2C_ADDR_LOW  0x50
Denis Kirjanov ebb326
 #define I2C_ADDR_HIGH 0x51
Denis Kirjanov ebb326
 #define I2C_PAGE_SIZE 256
Denis Kirjanov ebb326
+#define I2C_HIGH_PAGE_SIZE 128
Denis Kirjanov ebb326
 
Denis Kirjanov ebb326
 /* Module Info Data */
Denis Kirjanov ebb326
 struct mlx4_cable_info {
Denis Kirjanov ebb326
@@ -2026,6 +2027,88 @@ static inline const char *cable_info_mad_err_str(u16 mad_status)
Denis Kirjanov ebb326
 	return "Unknown Error";
Denis Kirjanov ebb326
 }
Denis Kirjanov ebb326
 
Denis Kirjanov ebb326
+static int mlx4_get_module_id(struct mlx4_dev *dev, u8 port, u8 *module_id)
Denis Kirjanov ebb326
+{
Denis Kirjanov ebb326
+	struct mlx4_cmd_mailbox *inbox, *outbox;
Denis Kirjanov ebb326
+	struct mlx4_mad_ifc *inmad, *outmad;
Denis Kirjanov ebb326
+	struct mlx4_cable_info *cable_info;
Denis Kirjanov ebb326
+	int ret;
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
+	inbox = mlx4_alloc_cmd_mailbox(dev);
Denis Kirjanov ebb326
+	if (IS_ERR(inbox))
Denis Kirjanov ebb326
+		return PTR_ERR(inbox);
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
+	outbox = mlx4_alloc_cmd_mailbox(dev);
Denis Kirjanov ebb326
+	if (IS_ERR(outbox)) {
Denis Kirjanov ebb326
+		mlx4_free_cmd_mailbox(dev, inbox);
Denis Kirjanov ebb326
+		return PTR_ERR(outbox);
Denis Kirjanov ebb326
+	}
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
+	inmad = (struct mlx4_mad_ifc *)(inbox->buf);
Denis Kirjanov ebb326
+	outmad = (struct mlx4_mad_ifc *)(outbox->buf);
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
+	inmad->method = 0x1; /* Get */
Denis Kirjanov ebb326
+	inmad->class_version = 0x1;
Denis Kirjanov ebb326
+	inmad->mgmt_class = 0x1;
Denis Kirjanov ebb326
+	inmad->base_version = 0x1;
Denis Kirjanov ebb326
+	inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
+	cable_info = (struct mlx4_cable_info *)inmad->data;
Denis Kirjanov ebb326
+	cable_info->dev_mem_address = 0;
Denis Kirjanov ebb326
+	cable_info->page_num = 0;
Denis Kirjanov ebb326
+	cable_info->i2c_addr = I2C_ADDR_LOW;
Denis Kirjanov ebb326
+	cable_info->size = cpu_to_be16(1);
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
+	ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
Denis Kirjanov ebb326
+			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
Denis Kirjanov ebb326
+			   MLX4_CMD_NATIVE);
Denis Kirjanov ebb326
+	if (ret)
Denis Kirjanov ebb326
+		goto out;
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
+	if (be16_to_cpu(outmad->status)) {
Denis Kirjanov ebb326
+		/* Mad returned with bad status */
Denis Kirjanov ebb326
+		ret = be16_to_cpu(outmad->status);
Denis Kirjanov ebb326
+		mlx4_warn(dev,
Denis Kirjanov ebb326
+			  "MLX4_CMD_MAD_IFC Get Module ID attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n",
Denis Kirjanov ebb326
+			  0xFF60, port, I2C_ADDR_LOW, 0, 1, ret,
Denis Kirjanov ebb326
+			  cable_info_mad_err_str(ret));
Denis Kirjanov ebb326
+		ret = -ret;
Denis Kirjanov ebb326
+		goto out;
Denis Kirjanov ebb326
+	}
Denis Kirjanov ebb326
+	cable_info = (struct mlx4_cable_info *)outmad->data;
Denis Kirjanov ebb326
+	*module_id = cable_info->data[0];
Denis Kirjanov ebb326
+out:
Denis Kirjanov ebb326
+	mlx4_free_cmd_mailbox(dev, inbox);
Denis Kirjanov ebb326
+	mlx4_free_cmd_mailbox(dev, outbox);
Denis Kirjanov ebb326
+	return ret;
Denis Kirjanov ebb326
+}
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
+static void mlx4_sfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset)
Denis Kirjanov ebb326
+{
Denis Kirjanov ebb326
+	*i2c_addr = I2C_ADDR_LOW;
Denis Kirjanov ebb326
+	*page_num = 0;
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
+	if (*offset < I2C_PAGE_SIZE)
Denis Kirjanov ebb326
+		return;
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
+	*i2c_addr = I2C_ADDR_HIGH;
Denis Kirjanov ebb326
+	*offset -= I2C_PAGE_SIZE;
Denis Kirjanov ebb326
+}
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
+static void mlx4_qsfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset)
Denis Kirjanov ebb326
+{
Denis Kirjanov ebb326
+	/* Offsets 0-255 belong to page 0.
Denis Kirjanov ebb326
+	 * Offsets 256-639 belong to pages 01, 02, 03.
Denis Kirjanov ebb326
+	 * For example, offset 400 is page 02: 1 + (400 - 256) / 128 = 2
Denis Kirjanov ebb326
+	 */
Denis Kirjanov ebb326
+	if (*offset < I2C_PAGE_SIZE)
Denis Kirjanov ebb326
+		*page_num = 0;
Denis Kirjanov ebb326
+	else
Denis Kirjanov ebb326
+		*page_num = 1 + (*offset - I2C_PAGE_SIZE) / I2C_HIGH_PAGE_SIZE;
Denis Kirjanov ebb326
+	*i2c_addr = I2C_ADDR_LOW;
Denis Kirjanov ebb326
+	*offset -= *page_num * I2C_HIGH_PAGE_SIZE;
Denis Kirjanov ebb326
+}
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
 /**
Denis Kirjanov ebb326
  * mlx4_get_module_info - Read cable module eeprom data
Denis Kirjanov ebb326
  * @dev: mlx4_dev.
Denis Kirjanov ebb326
@@ -2045,12 +2128,30 @@ int mlx4_get_module_info(struct mlx4_dev *dev, u8 port,
Denis Kirjanov ebb326
 	struct mlx4_cmd_mailbox *inbox, *outbox;
Denis Kirjanov ebb326
 	struct mlx4_mad_ifc *inmad, *outmad;
Denis Kirjanov ebb326
 	struct mlx4_cable_info *cable_info;
Denis Kirjanov ebb326
-	u16 i2c_addr;
Denis Kirjanov ebb326
+	u8 module_id, i2c_addr, page_num;
Denis Kirjanov ebb326
 	int ret;
Denis Kirjanov ebb326
 
Denis Kirjanov ebb326
 	if (size > MODULE_INFO_MAX_READ)
Denis Kirjanov ebb326
 		size = MODULE_INFO_MAX_READ;
Denis Kirjanov ebb326
 
Denis Kirjanov ebb326
+	ret = mlx4_get_module_id(dev, port, &module_id);
Denis Kirjanov ebb326
+	if (ret)
Denis Kirjanov ebb326
+		return ret;
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
+	switch (module_id) {
Denis Kirjanov ebb326
+	case MLX4_MODULE_ID_SFP:
Denis Kirjanov ebb326
+		mlx4_sfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
Denis Kirjanov ebb326
+		break;
Denis Kirjanov ebb326
+	case MLX4_MODULE_ID_QSFP:
Denis Kirjanov ebb326
+	case MLX4_MODULE_ID_QSFP_PLUS:
Denis Kirjanov ebb326
+	case MLX4_MODULE_ID_QSFP28:
Denis Kirjanov ebb326
+		mlx4_qsfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
Denis Kirjanov ebb326
+		break;
Denis Kirjanov ebb326
+	default:
Denis Kirjanov ebb326
+		mlx4_err(dev, "Module ID not recognized: %#x\n", module_id);
Denis Kirjanov ebb326
+		return -EINVAL;
Denis Kirjanov ebb326
+	}
Denis Kirjanov ebb326
+
Denis Kirjanov ebb326
 	inbox = mlx4_alloc_cmd_mailbox(dev);
Denis Kirjanov ebb326
 	if (IS_ERR(inbox))
Denis Kirjanov ebb326
 		return PTR_ERR(inbox);
Denis Kirjanov ebb326
@@ -2076,11 +2177,9 @@ int mlx4_get_module_info(struct mlx4_dev *dev, u8 port,
Denis Kirjanov ebb326
 		 */
Denis Kirjanov ebb326
 		size -= offset + size - I2C_PAGE_SIZE;
Denis Kirjanov ebb326
 
Denis Kirjanov ebb326
-	i2c_addr = I2C_ADDR_LOW;
Denis Kirjanov ebb326
-
Denis Kirjanov ebb326
 	cable_info = (struct mlx4_cable_info *)inmad->data;
Denis Kirjanov ebb326
 	cable_info->dev_mem_address = cpu_to_be16(offset);
Denis Kirjanov ebb326
-	cable_info->page_num = 0;
Denis Kirjanov ebb326
+	cable_info->page_num = page_num;
Denis Kirjanov ebb326
 	cable_info->i2c_addr = i2c_addr;
Denis Kirjanov ebb326
 	cable_info->size = cpu_to_be16(size);
Denis Kirjanov ebb326
 
Denis Kirjanov ebb326
-- 
Denis Kirjanov ebb326
2.16.4
Denis Kirjanov ebb326