]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
mlxsw: core: Fix wrong SFP EEPROM reading for upper pages 1-3
authorVadim Pasternak <vadimp@mellanox.com>
Fri, 17 Jul 2020 19:01:43 +0000 (22:01 +0300)
committerDavid S. Miller <davem@davemloft.net>
Sat, 18 Jul 2020 02:07:26 +0000 (19:07 -0700)
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 <vadimp@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/core_env.c

index 08215fed193d309c64bf18286d2881afe4948527..a7d86df7123ff2ee4b3b9674eb56b5360ed28b1d 100644 (file)
@@ -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;