u32 eth_proto_admin;
        u32 eth_proto_lp;
        u32 eth_proto_oper;
+       u8 an_disable_admin;
+       u8 an_status;
        int err;
 
        err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1);
                goto err_query_ptys;
        }
 
-       eth_proto_cap   = MLX5_GET(ptys_reg, out, eth_proto_capability);
-       eth_proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin);
-       eth_proto_oper  = MLX5_GET(ptys_reg, out, eth_proto_oper);
-       eth_proto_lp    = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise);
+       eth_proto_cap    = MLX5_GET(ptys_reg, out, eth_proto_capability);
+       eth_proto_admin  = MLX5_GET(ptys_reg, out, eth_proto_admin);
+       eth_proto_oper   = MLX5_GET(ptys_reg, out, eth_proto_oper);
+       eth_proto_lp     = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise);
+       an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
+       an_status        = MLX5_GET(ptys_reg, out, an_status);
 
        ethtool_link_ksettings_zero_link_mode(link_ksettings, supported);
        ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
        link_ksettings->base.port = get_connector_port(eth_proto_oper);
        get_lp_advertising(eth_proto_lp, link_ksettings);
 
+       if (an_status == MLX5_AN_COMPLETE)
+               ethtool_link_ksettings_add_link_mode(link_ksettings,
+                                                    lp_advertising, Autoneg);
+
+       link_ksettings->base.autoneg = an_disable_admin ? AUTONEG_DISABLE :
+                                                         AUTONEG_ENABLE;
+       ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
+                                            Autoneg);
+       if (!an_disable_admin)
+               ethtool_link_ksettings_add_link_mode(link_ksettings,
+                                                    advertising, Autoneg);
+
 err_query_ptys:
        return err;
 }
 {
        struct mlx5e_priv *priv    = netdev_priv(netdev);
        struct mlx5_core_dev *mdev = priv->mdev;
+       u32 eth_proto_cap, eth_proto_admin;
+       bool an_changes = false;
+       u8 an_disable_admin;
+       u8 an_disable_cap;
+       bool an_disable;
        u32 link_modes;
+       u8 an_status;
        u32 speed;
-       u32 eth_proto_cap, eth_proto_admin;
        int err;
 
        speed = link_ksettings->base.speed;
                goto out;
        }
 
-       if (link_modes == eth_proto_admin)
+       mlx5_query_port_autoneg(mdev, MLX5_PTYS_EN, &an_status,
+                               &an_disable_cap, &an_disable_admin);
+
+       an_disable = link_ksettings->base.autoneg == AUTONEG_DISABLE;
+       an_changes = ((!an_disable && an_disable_admin) ||
+                     (an_disable && !an_disable_admin));
+
+       if (!an_changes && link_modes == eth_proto_admin)
                goto out;
 
-       mlx5_set_port_proto(mdev, link_modes, MLX5_PTYS_EN);
+       mlx5_set_port_ptys(mdev, an_disable, link_modes, MLX5_PTYS_EN);
        mlx5_toggle_port_link(mdev);
 
 out:
 
 }
 EXPORT_SYMBOL_GPL(mlx5_query_port_proto_oper);
 
-int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
-                       int proto_mask)
+int mlx5_set_port_ptys(struct mlx5_core_dev *dev, bool an_disable,
+                      u32 proto_admin, int proto_mask)
 {
-       u32 in[MLX5_ST_SZ_DW(ptys_reg)];
        u32 out[MLX5_ST_SZ_DW(ptys_reg)];
+       u32 in[MLX5_ST_SZ_DW(ptys_reg)];
+       u8 an_disable_admin;
+       u8 an_disable_cap;
+       u8 an_status;
+
+       mlx5_query_port_autoneg(dev, proto_mask, &an_status,
+                               &an_disable_cap, &an_disable_admin);
+       if (!an_disable_cap && an_disable)
+               return -EPERM;
 
        memset(in, 0, sizeof(in));
 
        MLX5_SET(ptys_reg, in, local_port, 1);
+       MLX5_SET(ptys_reg, in, an_disable_admin, an_disable);
        MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
        if (proto_mask == MLX5_PTYS_EN)
                MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
        return mlx5_core_access_reg(dev, in, sizeof(in), out,
                                    sizeof(out), MLX5_REG_PTYS, 0, 1);
 }
-EXPORT_SYMBOL_GPL(mlx5_set_port_proto);
+EXPORT_SYMBOL_GPL(mlx5_set_port_ptys);
 
 /* This function should be used after setting a port register only */
 void mlx5_toggle_port_link(struct mlx5_core_dev *dev)
 }
 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
 
+void mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask,
+                            u8 *an_status,
+                            u8 *an_disable_cap, u8 *an_disable_admin)
+{
+       u32 out[MLX5_ST_SZ_DW(ptys_reg)];
+
+       *an_status = 0;
+       *an_disable_cap = 0;
+       *an_disable_admin = 0;
+
+       if (mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1))
+               return;
+
+       *an_status = MLX5_GET(ptys_reg, out, an_status);
+       *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap);
+       *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
+}
+EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg);
+
 int mlx5_max_tc(struct mlx5_core_dev *mdev)
 {
        u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
 
        MLX5_MODULE_ID_QSFP28           = 0x11,
 };
 
+enum mlx5_an_status {
+       MLX5_AN_UNAVAILABLE = 0,
+       MLX5_AN_COMPLETE    = 1,
+       MLX5_AN_FAILED      = 2,
+       MLX5_AN_LINK_UP     = 3,
+       MLX5_AN_LINK_DOWN   = 4,
+};
+
 #define MLX5_EEPROM_MAX_BYTES                  32
 #define MLX5_EEPROM_IDENTIFIER_BYTE_MASK       0x000000ff
 #define MLX5_I2C_ADDR_LOW              0x50
 int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev,
                               u8 *proto_oper, int proto_mask,
                               u8 local_port);
-int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
-                       int proto_mask);
+int mlx5_set_port_ptys(struct mlx5_core_dev *dev, bool an_disable,
+                      u32 proto_admin, int proto_mask);
 void mlx5_toggle_port_link(struct mlx5_core_dev *dev);
 int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
                               enum mlx5_port_status status);
 int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
                                 enum mlx5_port_status *status);
 int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration);
+void mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask,
+                            u8 *an_status,
+                            u8 *an_disable_cap, u8 *an_disable_admin);
 
 int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port);
 void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu, u8 port);