File Index
Files and directories
Sign in
FILE

mpesw.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c C
  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 "esw/acl/ofld.h"
  9#include "lib/events.h"
 10
 11static void mlx5_mpesw_metadata_cleanup(struct mlx5_lag *ldev)
 12{
 13	struct mlx5_core_dev *dev;
 14	struct mlx5_eswitch *esw;
 15	u32 pf_metadata;
 16	int i;
 17
 18	mlx5_ldev_for_each(i, 0, ldev) {
 19		dev = ldev->pf[i].dev;
 20		esw = dev->priv.eswitch;
 21		pf_metadata = ldev->lag_mpesw.pf_metadata[i];
 22		if (!pf_metadata)
 23			continue;
 24		mlx5_esw_acl_ingress_vport_metadata_update(esw, MLX5_VPORT_UPLINK, 0);
 25		mlx5_notifier_call_chain(dev->priv.events, MLX5_DEV_EVENT_MULTIPORT_ESW,
 26					 (void *)0);
 27		mlx5_esw_match_metadata_free(esw, pf_metadata);
 28		ldev->lag_mpesw.pf_metadata[i] = 0;
 29	}
 30}
 31
 32static int mlx5_mpesw_metadata_set(struct mlx5_lag *ldev)
 33{
 34	struct mlx5_core_dev *dev;
 35	struct mlx5_eswitch *esw;
 36	u32 pf_metadata;
 37	int i, err;
 38
 39	mlx5_ldev_for_each(i, 0, ldev) {
 40		dev = ldev->pf[i].dev;
 41		esw = dev->priv.eswitch;
 42		pf_metadata = mlx5_esw_match_metadata_alloc(esw);
 43		if (!pf_metadata) {
 44			err = -ENOSPC;
 45			goto err_metadata;
 46		}
 47
 48		ldev->lag_mpesw.pf_metadata[i] = pf_metadata;
 49		err = mlx5_esw_acl_ingress_vport_metadata_update(esw, MLX5_VPORT_UPLINK,
 50								 pf_metadata);
 51		if (err)
 52			goto err_metadata;
 53	}
 54
 55	mlx5_ldev_for_each(i, 0, ldev) {
 56		dev = ldev->pf[i].dev;
 57		mlx5_notifier_call_chain(dev->priv.events, MLX5_DEV_EVENT_MULTIPORT_ESW,
 58					 (void *)0);
 59	}
 60
 61	return 0;
 62
 63err_metadata:
 64	mlx5_mpesw_metadata_cleanup(ldev);
 65	return err;
 66}
 67
 68static int mlx5_lag_enable_mpesw(struct mlx5_lag *ldev)
 69{
 70	struct mlx5_core_dev *dev0;
 71	int err;
 72	int idx;
 73	int i;
 74
 75	if (ldev->mode == MLX5_LAG_MODE_MPESW)
 76		return 0;
 77
 78	if (ldev->mode != MLX5_LAG_MODE_NONE)
 79		return -EINVAL;
 80
 81	idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1);
 82	if (idx < 0)
 83		return -EINVAL;
 84
 85	dev0 = ldev->pf[idx].dev;
 86	if (mlx5_eswitch_mode(dev0) != MLX5_ESWITCH_OFFLOADS ||
 87	    !MLX5_CAP_PORT_SELECTION(dev0, port_select_flow_table) ||
 88	    !MLX5_CAP_GEN(dev0, create_lag_when_not_master_up) ||
 89	    !mlx5_lag_check_prereq(ldev) ||
 90	    !mlx5_lag_shared_fdb_supported(ldev))
 91		return -EOPNOTSUPP;
 92
 93	err = mlx5_mpesw_metadata_set(ldev);
 94	if (err)
 95		return err;
 96
 97	mlx5_lag_remove_devices(ldev);
 98
 99	err = mlx5_activate_lag(ldev, NULL, MLX5_LAG_MODE_MPESW, true);
100	if (err) {
101		mlx5_core_warn(dev0, "Failed to create LAG in MPESW mode (%d)\n", err);
102		goto err_add_devices;
103	}
104
105	dev0->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
106	mlx5_rescan_drivers_locked(dev0);
107	mlx5_ldev_for_each(i, 0, ldev) {
108		err = mlx5_eswitch_reload_ib_reps(ldev->pf[i].dev->priv.eswitch);
109		if (err)
110			goto err_rescan_drivers;
111	}
112
113	return 0;
114
115err_rescan_drivers:
116	dev0->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
117	mlx5_rescan_drivers_locked(dev0);
118	mlx5_deactivate_lag(ldev);
119err_add_devices:
120	mlx5_lag_add_devices(ldev);
121	mlx5_ldev_for_each(i, 0, ldev)
122		mlx5_eswitch_reload_ib_reps(ldev->pf[i].dev->priv.eswitch);
123	mlx5_mpesw_metadata_cleanup(ldev);
124	return err;
125}
126
127void mlx5_lag_disable_mpesw(struct mlx5_lag *ldev)
128{
129	if (ldev->mode == MLX5_LAG_MODE_MPESW) {
130		mlx5_mpesw_metadata_cleanup(ldev);
131		mlx5_disable_lag(ldev);
132	}
133}
134
135static void mlx5_mpesw_work(struct work_struct *work)
136{
137	struct mlx5_mpesw_work_st *mpesww = container_of(work, struct mlx5_mpesw_work_st, work);
138	struct mlx5_devcom_comp_dev *devcom;
139	struct mlx5_lag *ldev = mpesww->lag;
140
141	devcom = mlx5_lag_get_devcom_comp(ldev);
142	if (!devcom)
143		return;
144
145	mlx5_devcom_comp_lock(devcom);
146	mutex_lock(&ldev->lock);
147	if (ldev->mode_changes_in_progress) {
148		mpesww->result = -EAGAIN;
149		goto unlock;
150	}
151
152	if (mpesww->op == MLX5_MPESW_OP_ENABLE)
153		mpesww->result = mlx5_lag_enable_mpesw(ldev);
154	else if (mpesww->op == MLX5_MPESW_OP_DISABLE)
155		mlx5_lag_disable_mpesw(ldev);
156unlock:
157	mutex_unlock(&ldev->lock);
158	mlx5_devcom_comp_unlock(devcom);
159	complete(&mpesww->comp);
160}
161
162static int mlx5_lag_mpesw_queue_work(struct mlx5_core_dev *dev,
163				     enum mpesw_op op)
164{
165	struct mlx5_lag *ldev = mlx5_lag_dev(dev);
166	struct mlx5_mpesw_work_st *work;
167	int err = 0;
168
169	if (!ldev)
170		return 0;
171
172	work = kzalloc(sizeof(*work), GFP_KERNEL);
173	if (!work)
174		return -ENOMEM;
175
176	INIT_WORK(&work->work, mlx5_mpesw_work);
177	init_completion(&work->comp);
178	work->op = op;
179	work->lag = ldev;
180
181	if (!queue_work(ldev->wq, &work->work)) {
182		mlx5_core_warn(dev, "failed to queue mpesw work\n");
183		err = -EINVAL;
184		goto out;
185	}
186	wait_for_completion(&work->comp);
187	err = work->result;
188out:
189	kfree(work);
190	return err;
191}
192
193void mlx5_lag_mpesw_disable(struct mlx5_core_dev *dev)
194{
195	mlx5_lag_mpesw_queue_work(dev, MLX5_MPESW_OP_DISABLE);
196}
197
198int mlx5_lag_mpesw_enable(struct mlx5_core_dev *dev)
199{
200	return mlx5_lag_mpesw_queue_work(dev, MLX5_MPESW_OP_ENABLE);
201}
202
203int mlx5_lag_mpesw_do_mirred(struct mlx5_core_dev *mdev,
204			     struct net_device *out_dev,
205			     struct netlink_ext_ack *extack)
206{
207	struct mlx5_lag *ldev = mlx5_lag_dev(mdev);
208
209	if (!netif_is_bond_master(out_dev) || !ldev)
210		return 0;
211
212	if (ldev->mode != MLX5_LAG_MODE_MPESW)
213		return 0;
214
215	NL_SET_ERR_MSG_MOD(extack, "can't forward to bond in mpesw mode");
216	return -EOPNOTSUPP;
217}
218
219bool mlx5_lag_is_mpesw(struct mlx5_core_dev *dev)
220{
221	struct mlx5_lag *ldev = mlx5_lag_dev(dev);
222
223	return ldev && ldev->mode == MLX5_LAG_MODE_MPESW;
224}
225EXPORT_SYMBOL(mlx5_lag_is_mpesw);
~/ Read-only file preview.