Commit 9b873778 authored by Vadim Pasternak's avatar Vadim Pasternak Committed by David S. Miller

mlxsw: core: Fix wrong SFP EEPROM reading for upper pages 1-3

Fix wrong reading of upper pages for SFP EEPROM. According to "Memory
Organization" figure in SFF-8472 spec: When reading upper pages 1, 2 and
3 the offset should be set relative to zero and I2C high address 0x51
[1010001X (A2h)] is to be used.

Fixes: a45bfb5a ("mlxsw: core: Extend QSFP EEPROM size for ethtool")
Signed-off-by: default avatarVadim Pasternak <vadimp@mellanox.com>
Reviewed-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent eea9f73e
...@@ -45,7 +45,7 @@ static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id, ...@@ -45,7 +45,7 @@ static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id,
static int static int
mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module,
u16 offset, u16 size, void *data, u16 offset, u16 size, void *data,
unsigned int *p_read_size) bool qsfp, unsigned int *p_read_size)
{ {
char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE]; char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE];
char mcia_pl[MLXSW_REG_MCIA_LEN]; char mcia_pl[MLXSW_REG_MCIA_LEN];
...@@ -54,6 +54,10 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, ...@@ -54,6 +54,10 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module,
int status; int status;
int err; int err;
/* MCIA register accepts buffer size <= 48. Page of size 128 should be
* read by chunks of size 48, 48, 32. Align the size of the last chunk
* to avoid reading after the end of the page.
*/
size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE); size = min_t(u16, size, MLXSW_REG_MCIA_EEPROM_SIZE);
if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH && if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH &&
...@@ -63,18 +67,25 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, ...@@ -63,18 +67,25 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module,
i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW; i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW;
if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) { if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) {
page = MLXSW_REG_MCIA_PAGE_GET(offset); if (qsfp) {
offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page; /* When reading upper pages 1, 2 and 3 the offset
/* When reading upper pages 1, 2 and 3 the offset starts at * starts at 128. Please refer to "QSFP+ Memory Map"
* 128. Please refer to "QSFP+ Memory Map" figure in SFF-8436 * figure in SFF-8436 specification for graphical
* specification for graphical depiction. * depiction.
* MCIA register accepts buffer size <= 48. Page of size 128 */
* should be read by chunks of size 48, 48, 32. Align the size page = MLXSW_REG_MCIA_PAGE_GET(offset);
* of the last chunk to avoid reading after the end of the offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page;
* page. if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
*/ size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset;
if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) } else {
size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset; /* When reading upper pages 1, 2 and 3 the offset
* starts at 0 and I2C high address is used. Please refer
* refer to "Memory Organization" figure in SFF-8472
* specification for graphical depiction.
*/
i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH;
offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH;
}
} }
mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr); mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr);
...@@ -166,7 +177,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, ...@@ -166,7 +177,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module,
int err; int err;
err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset, err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset,
module_info, &read_size); module_info, false, &read_size);
if (err) if (err)
return err; return err;
...@@ -197,7 +208,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, ...@@ -197,7 +208,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module,
/* Verify if transceiver provides diagnostic monitoring page */ /* Verify if transceiver provides diagnostic monitoring page */
err = mlxsw_env_query_module_eeprom(mlxsw_core, module, err = mlxsw_env_query_module_eeprom(mlxsw_core, module,
SFP_DIAGMON, 1, &diag_mon, SFP_DIAGMON, 1, &diag_mon,
&read_size); false, &read_size);
if (err) if (err)
return err; return err;
...@@ -225,17 +236,22 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev, ...@@ -225,17 +236,22 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev,
int offset = ee->offset; int offset = ee->offset;
unsigned int read_size; unsigned int read_size;
int i = 0; int i = 0;
bool qsfp;
int err; int err;
if (!ee->len) if (!ee->len)
return -EINVAL; return -EINVAL;
memset(data, 0, ee->len); memset(data, 0, ee->len);
/* Validate module identifier value. */
err = mlxsw_env_validate_cable_ident(mlxsw_core, module, &qsfp);
if (err)
return err;
while (i < ee->len) { while (i < ee->len) {
err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset, err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset,
ee->len - i, data + i, ee->len - i, data + i,
&read_size); qsfp, &read_size);
if (err) { if (err) {
netdev_err(netdev, "Eeprom query failed\n"); netdev_err(netdev, "Eeprom query failed\n");
return err; return err;
......
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