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

Change-Id: Ica934efdd5b6a495f6765af1c8028cfa3546031f
---
 .../net/ethernet/mellanox/mlx5/core/lag/lag.c | 186 +++++++++++++++++-
 1 file changed, 180 insertions(+), 6 deletions(-)

--- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
@@ -31,7 +31,6 @@
  */
 
 #include <linux/netdevice.h>
-#include <net/bonding.h>
 #include <linux/mlx5/driver.h>
 #include <linux/mlx5/eswitch.h>
 #include <linux/mlx5/vport.h>
@@ -39,8 +38,20 @@
 #include "mlx5_core.h"
 #include "eswitch.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>
+
+#define MLX_LAG_SUPPORTED
+
+#ifdef MLX_LAG_SUPPORTED
 #include "lag.h"
-#include "mp.h"
 #include "mpesw.h"
 
 enum {
@@ -53,6 +64,92 @@ 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
 
 static int get_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags)
 {
@@ -65,6 +162,7 @@ static int get_port_sel_mode(enum mlx5_l
 	return MLX5_LAG_PORT_SELECT_MODE_QUEUE_AFFINITY;
 }
 
+#ifdef MLX_LAG_SUPPORTED
 static u8 lag_active_port_bits(struct mlx5_lag *ldev)
 {
 	u8 enabled_ports[MLX5_MAX_PORTS] = {};
@@ -127,24 +225,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);
 
@@ -226,7 +333,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);
@@ -264,7 +375,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");
 	}
@@ -285,11 +400,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;
 }
 
@@ -971,6 +1086,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
 			for (i = 0; i < ldev->ports; i++) {
 				err = mlx5_eswitch_reload_ib_reps(ldev->pf[i].dev->priv.eswitch);
 				if (err)
@@ -987,6 +1103,7 @@ static void mlx5_do_bond(struct mlx5_lag
 				mlx5_core_err(dev0, "Failed to enable lag\n");
 				return;
 			}
+#endif
 		}
 	} else if (mlx5_lag_should_modify_lag(ldev, do_bond)) {
 		mlx5_modify_lag(ldev, &tracker);
@@ -1077,8 +1194,12 @@ static int mlx5_handle_changeupper_event
 	 * of our netdevs, we should unbond).
 	 */
 
-	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);
@@ -1089,7 +1210,9 @@ static int mlx5_handle_changeupper_event
 
 		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)))
@@ -1340,6 +1463,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);
@@ -1360,10 +1484,12 @@ recheck:
 	mlx5_ldev_remove_mdev(ldev, dev);
 	mutex_unlock(&ldev->lock);
 	mlx5_ldev_put(ldev);
+#endif /* #ifdef 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))
@@ -1382,11 +1508,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;
 
@@ -1403,11 +1531,13 @@ void mlx5_lag_remove_netdev(struct mlx5_
 
 	if (lag_is_active)
 		mlx5_queue_bond_work(ldev, 0);
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 }
 
 void mlx5_lag_add_netdev(struct mlx5_core_dev *dev,
 			 struct net_device *netdev)
 {
+#ifdef MLX_LAG_SUPPORTED
 	struct mlx5_lag *ldev;
 	int i;
 
@@ -1426,10 +1556,14 @@ void mlx5_lag_add_netdev(struct mlx5_cor
 		set_bit(MLX5_LAG_FLAG_NDEVS_READY, &ldev->state_flags);
 	mutex_unlock(&ldev->lock);
 	mlx5_queue_bond_work(ldev, 0);
+#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;
@@ -1440,11 +1574,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;
@@ -1455,11 +1593,15 @@ 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);
 
 bool mlx5_lag_mode_is_hash(struct mlx5_core_dev *dev)
 {
+#ifndef MLX_LAG_SUPPORTED
+	return false;
+#else
 	struct mlx5_lag *ldev;
 	unsigned long flags;
 	bool res = 0;
@@ -1471,11 +1613,15 @@ bool mlx5_lag_mode_is_hash(struct mlx5_c
 	spin_unlock_irqrestore(&lag_lock, flags);
 
 	return res;
+#endif /* #ifdef MLX_LAG_SUPPORTED */
 }
 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;
@@ -1487,11 +1633,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;
@@ -1502,6 +1652,7 @@ 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);
 
@@ -1522,6 +1673,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);
@@ -1537,10 +1689,12 @@ void mlx5_lag_disable_change(struct mlx5
 
 	mutex_unlock(&ldev->lock);
 	mlx5_devcom_comp_unlock(dev->priv.hca_devcom_comp);
+#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);
@@ -1551,10 +1705,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;
@@ -1582,12 +1740,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;
@@ -1610,6 +1772,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);
 
@@ -1627,6 +1790,9 @@ EXPORT_SYMBOL(mlx5_lag_get_num_ports);
 
 struct mlx5_core_dev *mlx5_lag_get_next_peer_mdev(struct mlx5_core_dev *dev, int *i)
 {
+#ifndef MLX_LAG_SUPPORTED
+       return NULL;
+#else
 	struct mlx5_core_dev *peer_dev = NULL;
 	struct mlx5_lag *ldev;
 	unsigned long flags;
@@ -1654,6 +1820,7 @@ struct mlx5_core_dev *mlx5_lag_get_next_
 unlock:
 	spin_unlock_irqrestore(&lag_lock, flags);
 	return peer_dev;
+#endif /* #ifndef MLX_LAG_SUPPORTED */
 }
 EXPORT_SYMBOL(mlx5_lag_get_next_peer_mdev);
 
@@ -1664,7 +1831,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;
@@ -1683,6 +1852,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)) {
@@ -1694,6 +1864,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)] = {};
