Commit db825fee authored by Vladyslav Tarasiuk's avatar Vladyslav Tarasiuk Committed by David S. Miller

net/mlx4: Fix EEPROM dump support

Fix SFP and QSFP* EEPROM queries by setting i2c_address, offset and page
number correctly. For SFP set the following params:
- I2C address for offsets 0-255 is 0x50. For 256-511 - 0x51.
- Page number is zero.
- Offset is 0-255.

At the same time, QSFP* parameters are different:
- I2C address is always 0x50.
- Page number is not limited to zero.
- Offset is 0-255 for page zero and 128-255 for others.

To set parameters accordingly to cable used, implement function to query
module ID and implement respective helper functions to set parameters
correctly.

Fixes: 135dd959 ("net/mlx4_en: ethtool, Remove unsupported SFP EEPROM high pages query")
Signed-off-by: default avatarVladyslav Tarasiuk <vladyslavt@nvidia.com>
Signed-off-by: default avatarTariq Toukan <tariqt@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a269333f
...@@ -2027,8 +2027,6 @@ static int mlx4_en_set_tunable(struct net_device *dev, ...@@ -2027,8 +2027,6 @@ static int mlx4_en_set_tunable(struct net_device *dev,
return ret; return ret;
} }
#define MLX4_EEPROM_PAGE_LEN 256
static int mlx4_en_get_module_info(struct net_device *dev, static int mlx4_en_get_module_info(struct net_device *dev,
struct ethtool_modinfo *modinfo) struct ethtool_modinfo *modinfo)
{ {
...@@ -2063,7 +2061,7 @@ static int mlx4_en_get_module_info(struct net_device *dev, ...@@ -2063,7 +2061,7 @@ static int mlx4_en_get_module_info(struct net_device *dev,
break; break;
case MLX4_MODULE_ID_SFP: case MLX4_MODULE_ID_SFP:
modinfo->type = ETH_MODULE_SFF_8472; modinfo->type = ETH_MODULE_SFF_8472;
modinfo->eeprom_len = MLX4_EEPROM_PAGE_LEN; modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
break; break;
default: default:
return -EINVAL; return -EINVAL;
......
...@@ -1973,6 +1973,7 @@ EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); ...@@ -1973,6 +1973,7 @@ EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
#define I2C_ADDR_LOW 0x50 #define I2C_ADDR_LOW 0x50
#define I2C_ADDR_HIGH 0x51 #define I2C_ADDR_HIGH 0x51
#define I2C_PAGE_SIZE 256 #define I2C_PAGE_SIZE 256
#define I2C_HIGH_PAGE_SIZE 128
/* Module Info Data */ /* Module Info Data */
struct mlx4_cable_info { struct mlx4_cable_info {
...@@ -2026,6 +2027,88 @@ static inline const char *cable_info_mad_err_str(u16 mad_status) ...@@ -2026,6 +2027,88 @@ static inline const char *cable_info_mad_err_str(u16 mad_status)
return "Unknown Error"; return "Unknown Error";
} }
static int mlx4_get_module_id(struct mlx4_dev *dev, u8 port, u8 *module_id)
{
struct mlx4_cmd_mailbox *inbox, *outbox;
struct mlx4_mad_ifc *inmad, *outmad;
struct mlx4_cable_info *cable_info;
int ret;
inbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(inbox))
return PTR_ERR(inbox);
outbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(outbox)) {
mlx4_free_cmd_mailbox(dev, inbox);
return PTR_ERR(outbox);
}
inmad = (struct mlx4_mad_ifc *)(inbox->buf);
outmad = (struct mlx4_mad_ifc *)(outbox->buf);
inmad->method = 0x1; /* Get */
inmad->class_version = 0x1;
inmad->mgmt_class = 0x1;
inmad->base_version = 0x1;
inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */
cable_info = (struct mlx4_cable_info *)inmad->data;
cable_info->dev_mem_address = 0;
cable_info->page_num = 0;
cable_info->i2c_addr = I2C_ADDR_LOW;
cable_info->size = cpu_to_be16(1);
ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
MLX4_CMD_NATIVE);
if (ret)
goto out;
if (be16_to_cpu(outmad->status)) {
/* Mad returned with bad status */
ret = be16_to_cpu(outmad->status);
mlx4_warn(dev,
"MLX4_CMD_MAD_IFC Get Module ID attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n",
0xFF60, port, I2C_ADDR_LOW, 0, 1, ret,
cable_info_mad_err_str(ret));
ret = -ret;
goto out;
}
cable_info = (struct mlx4_cable_info *)outmad->data;
*module_id = cable_info->data[0];
out:
mlx4_free_cmd_mailbox(dev, inbox);
mlx4_free_cmd_mailbox(dev, outbox);
return ret;
}
static void mlx4_sfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset)
{
*i2c_addr = I2C_ADDR_LOW;
*page_num = 0;
if (*offset < I2C_PAGE_SIZE)
return;
*i2c_addr = I2C_ADDR_HIGH;
*offset -= I2C_PAGE_SIZE;
}
static void mlx4_qsfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset)
{
/* Offsets 0-255 belong to page 0.
* Offsets 256-639 belong to pages 01, 02, 03.
* For example, offset 400 is page 02: 1 + (400 - 256) / 128 = 2
*/
if (*offset < I2C_PAGE_SIZE)
*page_num = 0;
else
*page_num = 1 + (*offset - I2C_PAGE_SIZE) / I2C_HIGH_PAGE_SIZE;
*i2c_addr = I2C_ADDR_LOW;
*offset -= *page_num * I2C_HIGH_PAGE_SIZE;
}
/** /**
* mlx4_get_module_info - Read cable module eeprom data * mlx4_get_module_info - Read cable module eeprom data
* @dev: mlx4_dev. * @dev: mlx4_dev.
...@@ -2045,12 +2128,30 @@ int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, ...@@ -2045,12 +2128,30 @@ int mlx4_get_module_info(struct mlx4_dev *dev, u8 port,
struct mlx4_cmd_mailbox *inbox, *outbox; struct mlx4_cmd_mailbox *inbox, *outbox;
struct mlx4_mad_ifc *inmad, *outmad; struct mlx4_mad_ifc *inmad, *outmad;
struct mlx4_cable_info *cable_info; struct mlx4_cable_info *cable_info;
u16 i2c_addr; u8 module_id, i2c_addr, page_num;
int ret; int ret;
if (size > MODULE_INFO_MAX_READ) if (size > MODULE_INFO_MAX_READ)
size = MODULE_INFO_MAX_READ; size = MODULE_INFO_MAX_READ;
ret = mlx4_get_module_id(dev, port, &module_id);
if (ret)
return ret;
switch (module_id) {
case MLX4_MODULE_ID_SFP:
mlx4_sfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
break;
case MLX4_MODULE_ID_QSFP:
case MLX4_MODULE_ID_QSFP_PLUS:
case MLX4_MODULE_ID_QSFP28:
mlx4_qsfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
break;
default:
mlx4_err(dev, "Module ID not recognized: %#x\n", module_id);
return -EINVAL;
}
inbox = mlx4_alloc_cmd_mailbox(dev); inbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(inbox)) if (IS_ERR(inbox))
return PTR_ERR(inbox); return PTR_ERR(inbox);
...@@ -2076,11 +2177,9 @@ int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, ...@@ -2076,11 +2177,9 @@ int mlx4_get_module_info(struct mlx4_dev *dev, u8 port,
*/ */
size -= offset + size - I2C_PAGE_SIZE; size -= offset + size - I2C_PAGE_SIZE;
i2c_addr = I2C_ADDR_LOW;
cable_info = (struct mlx4_cable_info *)inmad->data; cable_info = (struct mlx4_cable_info *)inmad->data;
cable_info->dev_mem_address = cpu_to_be16(offset); cable_info->dev_mem_address = cpu_to_be16(offset);
cable_info->page_num = 0; cable_info->page_num = page_num;
cable_info->i2c_addr = i2c_addr; cable_info->i2c_addr = i2c_addr;
cable_info->size = cpu_to_be16(size); cable_info->size = cpu_to_be16(size);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment