net/mlx4_en: Adding support of turning off link autonegotiation via ethtool
authorAriel Levkovich <lariel@mellanox.com>
Sun, 29 Jan 2017 16:56:17 +0000 (18:56 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 30 Jan 2017 20:26:42 +0000 (15:26 -0500)
This feature will allow the user to disable auto negotiation
on the port for mlx4 devices while setting the speed is limited
to 1GbE speeds.
Other speeds will not be accepted in autoneg off mode.

This functionality is permitted providing that the firmware
is compatible with this feature.
The above is determined by querying a new dedicated capability
bit in the device.

Signed-off-by: Ariel Levkovich <lariel@mellanox.com>
Signed-off-by: Tariq Toukan <tariqt@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
include/linux/mlx4/device.h

index 785757f1768777871f5c6f997c82d2b72931436d..ca730d4abbb4bde8b80d635d7e86a0669480e20e 100644 (file)
@@ -902,6 +902,7 @@ mlx4_en_set_link_ksettings(struct net_device *dev,
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_ptys_reg ptys_reg;
        __be32 proto_admin;
+       u8 cur_autoneg;
        int ret;
 
        u32 ptys_adv = ethtool2ptys_link_modes(
@@ -931,10 +932,21 @@ mlx4_en_set_link_ksettings(struct net_device *dev,
                return 0;
        }
 
-       proto_admin = link_ksettings->base.autoneg == AUTONEG_ENABLE ?
-               cpu_to_be32(ptys_adv) :
-               speed_set_ptys_admin(priv, speed,
-                                    ptys_reg.eth_proto_cap);
+       cur_autoneg = ptys_reg.flags & MLX4_PTYS_AN_DISABLE_ADMIN ?
+                               AUTONEG_DISABLE : AUTONEG_ENABLE;
+
+       if (link_ksettings->base.autoneg == AUTONEG_DISABLE) {
+               proto_admin = speed_set_ptys_admin(priv, speed,
+                                                  ptys_reg.eth_proto_cap);
+               if ((be32_to_cpu(proto_admin) &
+                    (MLX4_PROT_MASK(MLX4_1000BASE_CX_SGMII) |
+                     MLX4_PROT_MASK(MLX4_1000BASE_KX))) &&
+                   (ptys_reg.flags & MLX4_PTYS_AN_DISABLE_CAP))
+                       ptys_reg.flags |= MLX4_PTYS_AN_DISABLE_ADMIN;
+       } else {
+               proto_admin = cpu_to_be32(ptys_adv);
+               ptys_reg.flags &= ~MLX4_PTYS_AN_DISABLE_ADMIN;
+       }
 
        proto_admin &= ptys_reg.eth_proto_cap;
        if (!proto_admin) {
@@ -942,7 +954,9 @@ mlx4_en_set_link_ksettings(struct net_device *dev,
                return -EINVAL; /* nothing to change due to bad input */
        }
 
-       if (proto_admin == ptys_reg.eth_proto_admin)
+       if ((proto_admin == ptys_reg.eth_proto_admin) &&
+           ((ptys_reg.flags & MLX4_PTYS_AN_DISABLE_CAP) &&
+            (link_ksettings->base.autoneg == cur_autoneg)))
                return 0; /* Nothing to change */
 
        en_dbg(DRV, priv, "mlx4_ACCESS_PTYS_REG SET: ptys_reg.eth_proto_admin = 0x%x\n",
index 6533c16e27ad7fb03926286ec94055d26b26f615..c3ac945b27596c84518c771c210420eebae89649 100644 (file)
@@ -1539,8 +1539,13 @@ enum mlx4_ptys_proto {
        MLX4_PTYS_EN = 1<<2,
 };
 
+enum mlx4_ptys_flags {
+       MLX4_PTYS_AN_DISABLE_CAP   = 1 << 5,
+       MLX4_PTYS_AN_DISABLE_ADMIN = 1 << 6,
+};
+
 struct mlx4_ptys_reg {
-       u8 resrvd1;
+       u8 flags;
        u8 local_port;
        u8 resrvd2;
        u8 proto_mask;