1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ 3 4 #include <linux/netdevice.h> 5 #include <net/nexthop.h> 6 #include "lag/lag.h" 7 #include "eswitch.h" 8 #include "lib/mlx5.h" 9 10 void mlx5_mpesw_work(struct work_struct *work) 11 { 12 struct mlx5_lag *ldev = container_of(work, struct mlx5_lag, mpesw_work); 13 14 mutex_lock(&ldev->lock); 15 mlx5_disable_lag(ldev); 16 mutex_unlock(&ldev->lock); 17 } 18 19 static void mlx5_lag_disable_mpesw(struct mlx5_core_dev *dev) 20 { 21 struct mlx5_lag *ldev = dev->priv.lag; 22 23 if (!queue_work(ldev->wq, &ldev->mpesw_work)) 24 mlx5_core_warn(dev, "failed to queue work\n"); 25 } 26 27 void mlx5_lag_del_mpesw_rule(struct mlx5_core_dev *dev) 28 { 29 struct mlx5_lag *ldev = dev->priv.lag; 30 31 if (!ldev) 32 return; 33 34 mutex_lock(&ldev->lock); 35 if (!atomic_dec_return(&ldev->lag_mpesw.mpesw_rule_count) && 36 ldev->mode == MLX5_LAG_MODE_MPESW) 37 mlx5_lag_disable_mpesw(dev); 38 mutex_unlock(&ldev->lock); 39 } 40 41 int mlx5_lag_add_mpesw_rule(struct mlx5_core_dev *dev) 42 { 43 struct mlx5_lag *ldev = dev->priv.lag; 44 int err = 0; 45 46 if (!ldev) 47 return 0; 48 49 mutex_lock(&ldev->lock); 50 if (atomic_add_return(1, &ldev->lag_mpesw.mpesw_rule_count) != 1) 51 goto out; 52 53 if (ldev->mode != MLX5_LAG_MODE_NONE) { 54 err = -EINVAL; 55 goto out; 56 } 57 58 err = mlx5_activate_lag(ldev, NULL, MLX5_LAG_MODE_MPESW, false); 59 if (err) 60 mlx5_core_warn(dev, "Failed to create LAG in MPESW mode (%d)\n", err); 61 62 out: 63 mutex_unlock(&ldev->lock); 64 return err; 65 } 66 67 int mlx5_lag_do_mirred(struct mlx5_core_dev *mdev, struct net_device *out_dev) 68 { 69 struct mlx5_lag *ldev = mdev->priv.lag; 70 71 if (!netif_is_bond_master(out_dev) || !ldev) 72 return 0; 73 74 mutex_lock(&ldev->lock); 75 if (ldev->mode == MLX5_LAG_MODE_MPESW) { 76 mutex_unlock(&ldev->lock); 77 return -EOPNOTSUPP; 78 } 79 mutex_unlock(&ldev->lock); 80 return 0; 81 } 82 83 bool mlx5_lag_mpesw_is_activated(struct mlx5_core_dev *dev) 84 { 85 bool ret; 86 87 ret = dev->priv.lag && dev->priv.lag->mode == MLX5_LAG_MODE_MPESW; 88 return ret; 89 } 90 91 void mlx5_lag_mpesw_init(struct mlx5_lag *ldev) 92 { 93 INIT_WORK(&ldev->mpesw_work, mlx5_mpesw_work); 94 atomic_set(&ldev->lag_mpesw.mpesw_rule_count, 0); 95 } 96 97 void mlx5_lag_mpesw_cleanup(struct mlx5_lag *ldev) 98 { 99 cancel_delayed_work_sync(&ldev->bond_work); 100 } 101