| From e3a57a771f7b79f8de4ed299a8d91f545d001930 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sun, 14 Jun 2020 17:31:26 +0300 |
| Subject: net/mlx5: Fix eeprom support for SFP module |
| |
| From: Eran Ben Elisha <eranbe@mellanox.com> |
| |
| [ Upstream commit 47afbdd2fa4c5775c383ba376a3d1da7d7f694dc ] |
| |
| Fix eeprom SFP query support by setting i2c_addr, offset and page number |
| correctly. Unlike QSFP modules, SFP eeprom params are as follow: |
| - i2c_addr is 0x50 for offset 0 - 255 and 0x51 for offset 256 - 511. |
| - Page number is always zero. |
| - Page offset is always relative to zero. |
| |
| As part of eeprom query, query the module ID (SFP / QSFP*) via helper |
| function to set the params accordingly. |
| |
| In addition, change mlx5_qsfp_eeprom_page() input type to be u16 to avoid |
| unnecessary casting. |
| |
| Fixes: a708fb7b1f8d ("net/mlx5e: ethtool, Add support for EEPROM high pages query") |
| Signed-off-by: Eran Ben Elisha <eranbe@mellanox.com> |
| Signed-off-by: Huy Nguyen <huyn@mellanox.com> |
| Signed-off-by: Saeed Mahameed <saeedm@mellanox.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| .../net/ethernet/mellanox/mlx5/core/port.c | 93 +++++++++++++++---- |
| 1 file changed, 77 insertions(+), 16 deletions(-) |
| |
| diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c |
| index cc262b30aed53..dc589322940c5 100644 |
| --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c |
| +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c |
| @@ -293,7 +293,40 @@ static int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num) |
| return 0; |
| } |
| |
| -static int mlx5_eeprom_page(int offset) |
| +static int mlx5_query_module_id(struct mlx5_core_dev *dev, int module_num, |
| + u8 *module_id) |
| +{ |
| + u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {}; |
| + u32 out[MLX5_ST_SZ_DW(mcia_reg)]; |
| + int err, status; |
| + u8 *ptr; |
| + |
| + MLX5_SET(mcia_reg, in, i2c_device_address, MLX5_I2C_ADDR_LOW); |
| + MLX5_SET(mcia_reg, in, module, module_num); |
| + MLX5_SET(mcia_reg, in, device_address, 0); |
| + MLX5_SET(mcia_reg, in, page_number, 0); |
| + MLX5_SET(mcia_reg, in, size, 1); |
| + MLX5_SET(mcia_reg, in, l, 0); |
| + |
| + err = mlx5_core_access_reg(dev, in, sizeof(in), out, |
| + sizeof(out), MLX5_REG_MCIA, 0, 0); |
| + if (err) |
| + return err; |
| + |
| + status = MLX5_GET(mcia_reg, out, status); |
| + if (status) { |
| + mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n", |
| + status); |
| + return -EIO; |
| + } |
| + ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0); |
| + |
| + *module_id = ptr[0]; |
| + |
| + return 0; |
| +} |
| + |
| +static int mlx5_qsfp_eeprom_page(u16 offset) |
| { |
| if (offset < MLX5_EEPROM_PAGE_LENGTH) |
| /* Addresses between 0-255 - page 00 */ |
| @@ -307,7 +340,7 @@ static int mlx5_eeprom_page(int offset) |
| MLX5_EEPROM_HIGH_PAGE_LENGTH); |
| } |
| |
| -static int mlx5_eeprom_high_page_offset(int page_num) |
| +static int mlx5_qsfp_eeprom_high_page_offset(int page_num) |
| { |
| if (!page_num) /* Page 0 always start from low page */ |
| return 0; |
| @@ -316,35 +349,62 @@ static int mlx5_eeprom_high_page_offset(int page_num) |
| return page_num * MLX5_EEPROM_HIGH_PAGE_LENGTH; |
| } |
| |
| +static void mlx5_qsfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset) |
| +{ |
| + *i2c_addr = MLX5_I2C_ADDR_LOW; |
| + *page_num = mlx5_qsfp_eeprom_page(*offset); |
| + *offset -= mlx5_qsfp_eeprom_high_page_offset(*page_num); |
| +} |
| + |
| +static void mlx5_sfp_eeprom_params_set(u16 *i2c_addr, int *page_num, u16 *offset) |
| +{ |
| + *i2c_addr = MLX5_I2C_ADDR_LOW; |
| + *page_num = 0; |
| + |
| + if (*offset < MLX5_EEPROM_PAGE_LENGTH) |
| + return; |
| + |
| + *i2c_addr = MLX5_I2C_ADDR_HIGH; |
| + *offset -= MLX5_EEPROM_PAGE_LENGTH; |
| +} |
| + |
| int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, |
| u16 offset, u16 size, u8 *data) |
| { |
| - int module_num, page_num, status, err; |
| + int module_num, status, err, page_num = 0; |
| + u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {}; |
| u32 out[MLX5_ST_SZ_DW(mcia_reg)]; |
| - u32 in[MLX5_ST_SZ_DW(mcia_reg)]; |
| - u16 i2c_addr; |
| - void *ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0); |
| + u16 i2c_addr = 0; |
| + u8 module_id; |
| + void *ptr; |
| |
| err = mlx5_query_module_num(dev, &module_num); |
| if (err) |
| return err; |
| |
| - memset(in, 0, sizeof(in)); |
| - size = min_t(int, size, MLX5_EEPROM_MAX_BYTES); |
| - |
| - /* Get the page number related to the given offset */ |
| - page_num = mlx5_eeprom_page(offset); |
| + err = mlx5_query_module_id(dev, module_num, &module_id); |
| + if (err) |
| + return err; |
| |
| - /* Set the right offset according to the page number, |
| - * For page_num > 0, relative offset is always >= 128 (high page). |
| - */ |
| - offset -= mlx5_eeprom_high_page_offset(page_num); |
| + switch (module_id) { |
| + case MLX5_MODULE_ID_SFP: |
| + mlx5_sfp_eeprom_params_set(&i2c_addr, &page_num, &offset); |
| + break; |
| + case MLX5_MODULE_ID_QSFP: |
| + case MLX5_MODULE_ID_QSFP_PLUS: |
| + case MLX5_MODULE_ID_QSFP28: |
| + mlx5_qsfp_eeprom_params_set(&i2c_addr, &page_num, &offset); |
| + break; |
| + default: |
| + mlx5_core_err(dev, "Module ID not recognized: 0x%x\n", module_id); |
| + return -EINVAL; |
| + } |
| |
| if (offset + size > MLX5_EEPROM_PAGE_LENGTH) |
| /* Cross pages read, read until offset 256 in low page */ |
| size -= offset + size - MLX5_EEPROM_PAGE_LENGTH; |
| |
| - i2c_addr = MLX5_I2C_ADDR_LOW; |
| + size = min_t(int, size, MLX5_EEPROM_MAX_BYTES); |
| |
| MLX5_SET(mcia_reg, in, l, 0); |
| MLX5_SET(mcia_reg, in, module, module_num); |
| @@ -365,6 +425,7 @@ int mlx5_query_module_eeprom(struct mlx5_core_dev *dev, |
| return -EIO; |
| } |
| |
| + ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0); |
| memcpy(data, ptr, size); |
| |
| return size; |
| -- |
| 2.25.1 |
| |