From: Valentine Fatiev <valentinef@nvidia.com>
Subject: [PATCH] BACKPORT: drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c

Change-Id: I55bc9a084b59711b27a8d0ba4d0f556011e7291f
---
 .../net/ethernet/mellanox/mlx5/core/lag/lag.c | 210 +++++++++++++++++-
 1 file changed, 202 insertions(+), 8 deletions(-)

--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -34,13 +34,26 @@
 #include <linux/mlx5/driver.h>
 #include <linux/mlx5/eswitch.h>
 #include <linux/mlx5/vport.h>
-#include <net/bonding.h>
 #include "lib/devcom.h"
 #include "mlx5_core.h"
 #include "eswitch.h"
-#include "lag.h"
-#include "mp.h"
 #include "esw/acl/ofld.h"
+#ifdef MLX_USE_LAG_COMPAT
+#define MLX_IMPL_LAG_EVENTS
+#include <linux/device.h>
+#include <net/rtnetlink.h>
+#include <net/sock.h>
+#include "en.h"
+#endif
+
+#include <net/bonding.h>
+
+#if defined(MLX_USE_LAG_COMPAT) || defined(HAVE_LAG_TX_TYPE)
+#define MLX_LAG_SUPPORTED
+#endif
+
+#ifdef MLX_LAG_SUPPORTED
+#include "lag.h"
 
 enum {
 	MLX5_LAG_EGRESS_PORT_1 = 1,
@@ -51,7 +64,94 @@ enum {
  * under it).
  */
 static DEFINE_SPINLOCK(lag_lock);
+#endif
+
+#ifdef MLX_USE_LAG_COMPAT
+#undef  register_netdevice_notifier
+#undef  unregister_netdevice_notifier
+#define register_netdevice_notifier            mlx5_lag_compat_register_netdev_notifier
+#define unregister_netdevice_notifier          mlx5_lag_compat_unregister_netdev_notifier
+#undef register_netdevice_notifier_rh
+#undef unregister_netdevice_notifier_rh
+#define register_netdevice_notifier_rh          mlx5_lag_compat_register_netdev_notifier
+#define unregister_netdevice_notifier_rh        mlx5_lag_compat_unregister_netdev_notifier
+
+#undef  netdev_notifier_info_to_dev
+#define netdev_notifier_info_to_dev            netdev_notifier_info_to_dev_v2
+
+#define MLX5_LAG_COMPAT_MAX_LAGDEVS            0x8
+
+static int mlx5_lag_netdev_event(struct notifier_block *this,
+                                unsigned long event, void *ptr);
+
+static struct mlx5_lag *mlx5_lag_compat_ldevs[MLX5_LAG_COMPAT_MAX_LAGDEVS] = {};
+static int mlx5_lag_compat_reg_ldevs = 0;
+
+static void mlx5_lag_compat_netdev_event(unsigned long event, void *ptr)
+{
+       struct mlx5_lag *ldev;
+       int i;
+
+       for (i = 0; i < MLX5_LAG_COMPAT_MAX_LAGDEVS; ++i) {
+               ldev = mlx5_lag_compat_ldevs[i];
+               if (!ldev)
+                       continue;
+               mlx5_lag_netdev_event(&ldev->nb, event, ptr);
+       }
+}
+
+static int mlx5_lag_compat_register_netdev_notifier(struct notifier_block *nb)
+{
+       struct mlx5_lag *ldev = container_of(nb, struct mlx5_lag, nb);
+       int err = 0, i;
+
+       if (!mlx5_lag_compat_reg_ldevs)
+               mlx_lag_compat_events_open(mlx5_lag_compat_netdev_event);
+
+       rtnl_lock();
+       for (i = 0; i < MLX5_LAG_COMPAT_MAX_LAGDEVS; ++i) {
+               if (mlx5_lag_compat_ldevs[i])
+                       continue;
+
+               mlx5_lag_compat_ldevs[i] = ldev;
+               break;
+       }
+
+       if (i == MLX5_LAG_COMPAT_MAX_LAGDEVS) {
+               err = -EINVAL;
+               goto unlock;
+       }
+
+       ++mlx5_lag_compat_reg_ldevs;
+
+unlock:
+       rtnl_unlock();
+       return err;
+}
+
+static void mlx5_lag_compat_unregister_netdev_notifier(struct notifier_block *nb)
+{
+       struct mlx5_lag *ldev = container_of(nb, struct mlx5_lag, nb);
+       int i;
+
+       rtnl_lock();
+       for (i = 0; i < MLX5_LAG_COMPAT_MAX_LAGDEVS; ++i) {
+               if (mlx5_lag_compat_ldevs[i] != ldev)
+                       continue;
+
+               mlx5_lag_compat_ldevs[i] = NULL;
+               break;
+       }
+
+       --mlx5_lag_compat_reg_ldevs;
+       rtnl_unlock();
+
+       if (!mlx5_lag_compat_reg_ldevs)
+               mlx_lag_compat_events_close();
+}
+#endif
 
+#ifdef MLX_LAG_SUPPORTED
 static u8 lag_active_port_bits(struct mlx5_lag *ldev)
 {
 	u8 enabled_ports[MLX5_MAX_PORTS] = {};
@@ -108,24 +208,33 @@ static int mlx5_cmd_modify_lag(struct ml
 
 	return mlx5_cmd_exec_in(dev, modify_lag, in);
 }
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 
 int mlx5_cmd_create_vport_lag(struct mlx5_core_dev *dev)
 {
+#ifndef MLX_LAG_SUPPORTED
+	return -EOPNOTSUPP;
+#else
 	u32 in[MLX5_ST_SZ_DW(create_vport_lag_in)] = {};
 
 	MLX5_SET(create_vport_lag_in, in, opcode, MLX5_CMD_OP_CREATE_VPORT_LAG);
 
 	return mlx5_cmd_exec_in(dev, create_vport_lag, in);
+#endif /* #ifndef MLX_LAG_SUPPORTED */
 }
 EXPORT_SYMBOL(mlx5_cmd_create_vport_lag);
 
 int mlx5_cmd_destroy_vport_lag(struct mlx5_core_dev *dev)
 {
+#ifndef MLX_LAG_SUPPORTED
+	return -EOPNOTSUPP;
+#else
 	u32 in[MLX5_ST_SZ_DW(destroy_vport_lag_in)] = {};
 
 	MLX5_SET(destroy_vport_lag_in, in, opcode, MLX5_CMD_OP_DESTROY_VPORT_LAG);
 
 	return mlx5_cmd_exec_in(dev, destroy_vport_lag, in);
+#endif /* #ifndef MLX_LAG_SUPPORTED */
 }
 EXPORT_SYMBOL(mlx5_cmd_destroy_vport_lag);
 
@@ -207,7 +316,11 @@ static void mlx5_ldev_free(struct kref *
 	struct mlx5_lag *ldev = container_of(ref, struct mlx5_lag, ref);
 
 	if (ldev->nb.notifier_call)
+#ifdef HAVE_UNREGISTER_NETDEVICE_NOTIFIER_NET
 		unregister_netdevice_notifier_net(&init_net, &ldev->nb);
+#else
+		unregister_netdevice_notifier(&ldev->nb);
+#endif
 	mlx5_lag_mp_cleanup(ldev);
 	cancel_delayed_work_sync(&ldev->bond_work);
 	destroy_workqueue(ldev->wq);
@@ -245,7 +358,11 @@ static struct mlx5_lag *mlx5_lag_dev_all
 	INIT_DELAYED_WORK(&ldev->bond_work, mlx5_do_bond_work);
 
 	ldev->nb.notifier_call = mlx5_lag_netdev_event;
+#ifdef HAVE_UNREGISTER_NETDEVICE_NOTIFIER_NET
 	if (register_netdevice_notifier_net(&init_net, &ldev->nb)) {
+#else
+		if (register_netdevice_notifier(&ldev->nb)) {
+#endif
 		ldev->nb.notifier_call = NULL;
 		mlx5_core_err(dev, "Failed to register LAG netdev notifier\n");
 	}
@@ -264,11 +381,11 @@ int mlx5_lag_dev_get_netdev_idx(struct m
 				struct net_device *ndev)
 {
 	int i;
-
+#ifdef MLX_LAG_SUPPORTED
 	for (i = 0; i < ldev->ports; i++)
 		if (ldev->pf[i].netdev == ndev)
 			return i;
-
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 	return -ENOENT;
 }
 
@@ -859,6 +976,7 @@ static void mlx5_do_bond(struct mlx5_lag
 			dev0->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
 			mlx5_rescan_drivers_locked(dev0);
 
+#ifdef CONFIG_MLX5_ESWITCH
 			err = mlx5_eswitch_reload_reps(dev0->priv.eswitch);
 			if (!err)
 				err = mlx5_eswitch_reload_reps(dev1->priv.eswitch);
@@ -873,6 +991,7 @@ static void mlx5_do_bond(struct mlx5_lag
 				mlx5_core_err(dev0, "Failed to enable lag\n");
 				return;
 			}
+#endif
 		}
 	} else if (do_bond && __mlx5_lag_is_active(ldev)) {
 		mlx5_modify_lag(ldev, &tracker);
@@ -933,8 +1052,12 @@ static bool mlx5_lag_eval_bonding_conds(
 	struct slave *slave;
 	bool changed = false;
 	
-	rcu_read_lock();
-	for_each_netdev_in_bond_rcu(upper, ndev_tmp) {
+#ifdef for_each_netdev_in_bond_rcu
+        rcu_read_lock();
+        for_each_netdev_in_bond_rcu(upper, ndev_tmp) {
+#else
+       for_each_netdev_in_bond(upper, ndev_tmp) {
+#endif
 		idx = mlx5_lag_dev_get_netdev_idx(ldev, ndev_tmp);
 		if (idx >= 0) {
 			slave = bond_slave_get_rcu(ndev_tmp);
@@ -945,8 +1068,9 @@ static bool mlx5_lag_eval_bonding_conds(
 
 		num_slaves++;
 	}
+#ifdef for_each_netdev_in_bond_rcu
 	rcu_read_unlock();
-
+#endif
 	/* None of this lagdev's netdevs are slaves of this master. */
 	if (!(bond_status & GENMASK(ldev->ports - 1, 0)))
 		return false;
@@ -975,13 +1099,23 @@ static bool mlx5_lag_eval_bonding_conds(
 
 	if (!mlx5_lag_is_ready(ldev)) {
 		if (info)
+#ifdef HAVE_NETDEV_NOTIFIER_INFO_EXTACK
 			NL_SET_ERR_MSG_MOD(info->info.extack,
 					"Can't activate LAG offload, PF is configured with more than 64 VFs");
+#else
+                       netdev_warn(upper,
+                                   "Can't activate LAG offload, PF is configured with more than 64 VFs\n");
+#endif
 	}
 	else if (!mode_supported) {
 		if (info)
+#ifdef HAVE_NETDEV_NOTIFIER_INFO_EXTACK
 			NL_SET_ERR_MSG_MOD(info->info.extack,
 					"Can't activate LAG offload, TX type isn't supported");
+#else
+                       netdev_warn(upper,
+                                   "Can't activate LAG offload, TX type isn't supported\n");
+#endif
 	}
 
 	return changed;
@@ -1004,7 +1138,9 @@ static bool mlx5_handle_changeupper_even
 
 		if (lag_upper_info) {
 			tx_type = lag_upper_info->tx_type;
+#ifdef HAVE_INFO_HASH_TYPE
 			tracker->hash_type = lag_upper_info->hash_type;
+#endif
 		}
 	}
 
@@ -1271,6 +1407,7 @@ static int __mlx5_lag_dev_add_mdev(struc
 
 void mlx5_lag_remove_mdev(struct mlx5_core_dev *dev)
 {
+#ifdef MLX_LAG_SUPPORTED
 	struct mlx5_lag *ldev;
 
 	ldev = mlx5_lag_dev(dev);
@@ -1291,10 +1428,12 @@ recheck:
 	mlx5_ldev_remove_mdev(ldev, dev);
 	mutex_unlock(&ldev->lock);
 	mlx5_ldev_put(ldev);
+#endif /* #ifndef MLX_LAG_SUPPORTED */
 }
 
 void mlx5_lag_add_mdev(struct mlx5_core_dev *dev)
 {
+#ifdef MLX_LAG_SUPPORTED
 	int err;
 
 	if (!mlx5_lag_is_supported(dev))
@@ -1310,11 +1449,13 @@ recheck:
 		goto recheck;
 	}
 	mlx5_ldev_add_debugfs(dev);
+#endif /* #ifndef MLX_LAG_SUPPORTED */
 }
 
 void mlx5_lag_remove_netdev(struct mlx5_core_dev *dev,
 			    struct net_device *netdev)
 {
+#ifdef MLX_LAG_SUPPORTED
 	struct mlx5_lag *ldev;
 	bool lag_is_active;
 
@@ -1334,12 +1475,14 @@ void mlx5_lag_remove_netdev(struct mlx5_
 
 	if (lag_is_active)
 		mlx5_queue_bond_work(ldev, 0);
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 }
 
 /* Must be called with intf_mutex held */
 void mlx5_lag_add_netdev(struct mlx5_core_dev *dev,
 			 struct net_device *netdev)
 {
+#ifdef MLX_LAG_SUPPORTED
 	struct mlx5_lag *ldev;
 	int i;
 
@@ -1359,10 +1502,14 @@ void mlx5_lag_add_netdev(struct mlx5_cor
 
 	mutex_unlock(&ldev->lock);
 	mlx5_lag_update_trackers(ldev);
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 }
 
 bool mlx5_lag_is_roce(struct mlx5_core_dev *dev)
 {
+#ifndef MLX_LAG_SUPPORTED
+       return false;
+#else
 	struct mlx5_lag *ldev;
 	unsigned long flags;
 	bool res;
@@ -1373,11 +1520,15 @@ bool mlx5_lag_is_roce(struct mlx5_core_d
 	spin_unlock_irqrestore(&lag_lock, flags);
 
 	return res;
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 }
 EXPORT_SYMBOL(mlx5_lag_is_roce);
 
 bool mlx5_lag_is_active(struct mlx5_core_dev *dev)
 {
+#ifndef MLX_LAG_SUPPORTED
+	return false;
+#else
 	struct mlx5_lag *ldev;
 	unsigned long flags;
 	bool res;
@@ -1388,6 +1539,7 @@ bool mlx5_lag_is_active(struct mlx5_core
 	spin_unlock_irqrestore(&lag_lock, flags);
 
 	return res;
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 }
 EXPORT_SYMBOL(mlx5_lag_is_active);
 
@@ -1409,6 +1561,9 @@ EXPORT_SYMBOL(mlx5_lag_mode_is_hash);
 
 bool mlx5_lag_is_master(struct mlx5_core_dev *dev)
 {
+#ifndef MLX_LAG_SUPPORTED
+	return false;
+#else
 	struct mlx5_lag *ldev;
 	unsigned long flags;
 	bool res;
@@ -1420,11 +1575,15 @@ bool mlx5_lag_is_master(struct mlx5_core
 	spin_unlock_irqrestore(&lag_lock, flags);
 
 	return res;
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 }
 EXPORT_SYMBOL(mlx5_lag_is_master);
 
 bool mlx5_lag_is_sriov(struct mlx5_core_dev *dev)
 {
+#ifndef MLX_LAG_SUPPORTED
+        return false;
+#else
 	struct mlx5_lag *ldev;
 	unsigned long flags;
 	bool res;
@@ -1435,11 +1594,15 @@ bool mlx5_lag_is_sriov(struct mlx5_core_
 	spin_unlock_irqrestore(&lag_lock, flags);
 
 	return res;
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 }
 EXPORT_SYMBOL(mlx5_lag_is_sriov);
 
 bool mlx5_lag_is_mpesw(struct mlx5_core_dev *dev)
 {
+#ifndef MLX_LAG_SUPPORTED
+        return false;
+#else
 	struct mlx5_lag *ldev;
 	unsigned long flags;
 	bool res;
@@ -1449,6 +1612,7 @@ bool mlx5_lag_is_mpesw(struct mlx5_core_
 	res  = ldev && ldev->flags & MLX5_LAG_FLAG_MULTI_PORT_ESW;
 	spin_unlock_irqrestore(&lag_lock, flags);
 
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 	return res;
 }
 EXPORT_SYMBOL(mlx5_lag_is_mpesw);
@@ -1470,6 +1634,7 @@ EXPORT_SYMBOL(mlx5_lag_is_shared_fdb);
 
 void mlx5_lag_disable_change(struct mlx5_core_dev *dev)
 {
+#ifdef MLX_LAG_SUPPORTED
 	struct mlx5_lag *ldev;
 
 	ldev = mlx5_lag_dev(dev);
@@ -1485,10 +1650,12 @@ void mlx5_lag_disable_change(struct mlx5
 
 	mutex_unlock(&ldev->lock);
 	mlx5_dev_list_unlock();
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 }
 
 void mlx5_lag_enable_change(struct mlx5_core_dev *dev)
 {
+#ifdef MLX_LAG_SUPPORTED
 	struct mlx5_lag *ldev;
 
 	ldev = mlx5_lag_dev(dev);
@@ -1499,10 +1666,14 @@ void mlx5_lag_enable_change(struct mlx5_
 	ldev->mode_changes_in_progress--;
 	mutex_unlock(&ldev->lock);
 	mlx5_queue_bond_work(ldev, 0);
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 }
 
 struct net_device *mlx5_lag_get_roce_netdev(struct mlx5_core_dev *dev)
 {
+#ifndef MLX_LAG_SUPPORTED
+       return NULL;
+#else
 	struct net_device *ndev = NULL;
 	struct mlx5_lag *ldev;
 	unsigned long flags;
@@ -1530,12 +1701,16 @@ unlock:
 	spin_unlock_irqrestore(&lag_lock, flags);
 
 	return ndev;
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 }
 EXPORT_SYMBOL(mlx5_lag_get_roce_netdev);
 
 u8 mlx5_lag_get_slave_port(struct mlx5_core_dev *dev,
 			   struct net_device *slave)
 {
+#ifndef MLX_LAG_SUPPORTED
+       return 0;
+#else
 	struct mlx5_lag *ldev;
 	unsigned long flags;
 	u8 port = 0;
@@ -1558,6 +1733,7 @@ u8 mlx5_lag_get_slave_port(struct mlx5_c
 unlock:
 	spin_unlock_irqrestore(&lag_lock, flags);
 	return port;
+#endif /* #ifndef MLX_LAG_SUPPORTED */
 }
 EXPORT_SYMBOL(mlx5_lag_get_slave_port);
 
@@ -1575,6 +1751,9 @@ EXPORT_SYMBOL(mlx5_lag_get_num_ports);
 
 struct mlx5_core_dev *mlx5_lag_get_peer_mdev(struct mlx5_core_dev *dev)
 {
+#ifndef MLX_LAG_SUPPORTED
+       return NULL;
+#else
 	struct mlx5_core_dev *peer_dev = NULL;
 	struct mlx5_lag *ldev;
 	unsigned long flags;
@@ -1591,6 +1770,7 @@ struct mlx5_core_dev *mlx5_lag_get_peer_
 unlock:
 	spin_unlock_irqrestore(&lag_lock, flags);
 	return peer_dev;
+#endif /* #ifndef MLX_LAG_SUPPORTED */
 }
 EXPORT_SYMBOL(mlx5_lag_get_peer_mdev);
 
@@ -1601,7 +1781,9 @@ int mlx5_lag_query_cong_counters(struct
 {
 	int outlen = MLX5_ST_SZ_BYTES(query_cong_statistics_out);
 	struct mlx5_core_dev **mdev;
+#ifdef MLX_LAG_SUPPORTED
 	struct mlx5_lag *ldev;
+#endif
 	unsigned long flags;
 	int num_ports;
 	int ret = 0;
@@ -1620,6 +1802,7 @@ int mlx5_lag_query_cong_counters(struct
 
 	memset(values, 0, sizeof(*values) * num_counters);
 
+#ifdef MLX_LAG_SUPPORTED
 	spin_lock_irqsave(&lag_lock, flags);
 	ldev = mlx5_lag_dev(dev);
 	if (ldev && __mlx5_lag_is_active(ldev)) {
@@ -1631,6 +1814,10 @@ int mlx5_lag_query_cong_counters(struct
 		mdev[MLX5_LAG_P1] = dev;
 	}
 	spin_unlock_irqrestore(&lag_lock, flags);
+#else
+	num_ports = 1;
+	mdev[0] = dev;
+#endif
 
 	for (i = 0; i < num_ports; ++i) {
 		u32 in[MLX5_ST_SZ_DW(query_cong_statistics_in)] = {};
@@ -1666,7 +1853,9 @@ int mlx5_lag_modify_cong_params(struct m
 				void *in, int in_size)
 {
 	struct mlx5_core_dev **mdev;
+#ifdef MLX_LAG_SUPPORTED
 	struct mlx5_lag *ldev;
+#endif
 	unsigned long flags;
 	int num_ports;
 	int ret = 0;
@@ -1676,6 +1865,7 @@ int mlx5_lag_modify_cong_params(struct m
 	if (!mdev)
 		return -ENOMEM;
 
+#ifdef MLX_LAG_SUPPORTED
 	spin_lock_irqsave(&lag_lock, flags);
 	ldev = mlx5_lag_dev(dev);
 	if (ldev && __mlx5_lag_is_active(ldev)) {
@@ -1687,6 +1877,10 @@ int mlx5_lag_modify_cong_params(struct m
 		mdev[0] = dev;
 	}
 	spin_unlock_irqrestore(&lag_lock, flags);
+#else
+	num_ports = 1;
+	mdev[0] = dev;
+#endif
 
 	for (i = 0; i < num_ports; i++) {
 		ret = mlx5_cmd_modify_cong_params(mdev[i], in, in_size);
