From: Vadim Pasternak <vad...@mellanox.com>

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: a45bfb5a5070 ("mlxsw: core: Extend QSFP EEPROM size for ethtool")
Signed-off-by: Vadim Pasternak <vad...@mellanox.com>
Reviewed-by: Jiri Pirko <j...@mellanox.com>
Signed-off-by: Ido Schimmel <ido...@mellanox.com>
---
 .../net/ethernet/mellanox/mlxsw/core_env.c    | 48 ++++++++++++-------
 1 file changed, 32 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c 
b/drivers/net/ethernet/mellanox/mlxsw/core_env.c
index 08215fed193d..a7d86df7123f 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c
@@ -45,7 +45,7 @@ static int mlxsw_env_validate_cable_ident(struct mlxsw_core 
*core, int id,
 static int
 mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module,
                              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 mcia_pl[MLXSW_REG_MCIA_LEN];
@@ -54,6 +54,10 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, 
int module,
        int status;
        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);
 
        if (offset < MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH &&
@@ -63,18 +67,25 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core 
*mlxsw_core, int module,
 
        i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW;
        if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) {
-               page = MLXSW_REG_MCIA_PAGE_GET(offset);
-               offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page;
-               /* When reading upper pages 1, 2 and 3 the offset starts at
-                * 128. Please refer to "QSFP+ Memory Map" figure in SFF-8436
-                * specification for graphical depiction.
-                * 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.
-                */
-               if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
-                       size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset;
+               if (qsfp) {
+                       /* When reading upper pages 1, 2 and 3 the offset
+                        * starts at 128. Please refer to "QSFP+ Memory Map"
+                        * figure in SFF-8436 specification for graphical
+                        * depiction.
+                        */
+                       page = MLXSW_REG_MCIA_PAGE_GET(offset);
+                       offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page;
+                       if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH)
+                               size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - 
offset;
+               } else {
+                       /* 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);
@@ -166,7 +177,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core 
*mlxsw_core, int module,
        int err;
 
        err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset,
-                                           module_info, &read_size);
+                                           module_info, false, &read_size);
        if (err)
                return err;
 
@@ -197,7 +208,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core 
*mlxsw_core, int module,
                /* Verify if transceiver provides diagnostic monitoring page */
                err = mlxsw_env_query_module_eeprom(mlxsw_core, module,
                                                    SFP_DIAGMON, 1, &diag_mon,
-                                                   &read_size);
+                                                   false, &read_size);
                if (err)
                        return err;
 
@@ -225,17 +236,22 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev,
        int offset = ee->offset;
        unsigned int read_size;
        int i = 0;
+       bool qsfp;
        int err;
 
        if (!ee->len)
                return -EINVAL;
 
        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) {
                err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset,
                                                    ee->len - i, data + i,
-                                                   &read_size);
+                                                   qsfp, &read_size);
                if (err) {
                        netdev_err(netdev, "Eeprom query failed\n");
                        return err;
-- 
2.26.2

Reply via email to