mlxsw: spectrum: Add sanity checks into module info get
authorJiri Pirko <jiri@mellanox.com>
Thu, 31 Oct 2019 09:42:14 +0000 (11:42 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 31 Oct 2019 17:54:47 +0000 (10:54 -0700)
Driver assumes certain values in the PMLP register. Add checks that
verify that PMLP register provides fitting values.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Shalom Toledo <shalomt@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum.c

index 68f1461d9919a863345e291ab178d5f6f4776538..938803cd29cab4572abaee35caa9d5fc40a5b6fd 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/inetdevice.h>
 #include <linux/netlink.h>
 #include <linux/jhash.h>
+#include <linux/log2.h>
 #include <net/switchdev.h>
 #include <net/pkt_cls.h>
 #include <net/tc_act/tc_mirred.h>
@@ -753,14 +754,48 @@ mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                              struct mlxsw_sp_port_mapping *port_mapping)
 {
        char pmlp_pl[MLXSW_REG_PMLP_LEN];
+       bool separate_rxtx;
+       u8 module;
+       u8 width;
        int err;
+       int i;
 
        mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
        err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
        if (err)
                return err;
-       port_mapping->module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
-       port_mapping->width = mlxsw_reg_pmlp_width_get(pmlp_pl);
+       module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
+       width = mlxsw_reg_pmlp_width_get(pmlp_pl);
+       separate_rxtx = mlxsw_reg_pmlp_rxtx_get(pmlp_pl);
+
+       if (width && !is_power_of_2(width)) {
+               dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: width value is not power of 2\n",
+                       local_port);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < width; i++) {
+               if (mlxsw_reg_pmlp_module_get(pmlp_pl, i) != module) {
+                       dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: contains multiple modules\n",
+                               local_port);
+                       return -EINVAL;
+               }
+               if (separate_rxtx &&
+                   mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) !=
+                   mlxsw_reg_pmlp_rx_lane_get(pmlp_pl, i)) {
+                       dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are different\n",
+                               local_port);
+                       return -EINVAL;
+               }
+               if (mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) != i) {
+                       dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are not sequential\n",
+                               local_port);
+                       return -EINVAL;
+               }
+       }
+
+       port_mapping->module = module;
+       port_mapping->width = width;
        port_mapping->lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0);
        return 0;
 }