xref: /openbmc/linux/drivers/infiniband/hw/mlx5/ib_rep.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1c1191a19SLeon Romanovsky // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2fc385b7aSMark Bloch /*
3fc385b7aSMark Bloch  * Copyright (c) 2018 Mellanox Technologies. All rights reserved.
4fc385b7aSMark Bloch  */
5fc385b7aSMark Bloch 
6b05af6aaSBodong Wang #include <linux/mlx5/vport.h>
7fc385b7aSMark Bloch #include "ib_rep.h"
8f3da6577SLeon Romanovsky #include "srq.h"
9fc385b7aSMark Bloch 
10fc385b7aSMark Bloch static int
mlx5_ib_set_vport_rep(struct mlx5_core_dev * dev,struct mlx5_eswitch_rep * rep,int vport_index)11c446d9daSMark Bloch mlx5_ib_set_vport_rep(struct mlx5_core_dev *dev,
12c446d9daSMark Bloch 		      struct mlx5_eswitch_rep *rep,
13c446d9daSMark Bloch 		      int vport_index)
1426628e2dSMark Bloch {
1526628e2dSMark Bloch 	struct mlx5_ib_dev *ibdev;
1626628e2dSMark Bloch 
1704b222f9SLeon Romanovsky 	ibdev = mlx5_eswitch_uplink_get_proto_dev(dev->priv.eswitch, REP_IB);
18c446d9daSMark Bloch 	if (!ibdev)
19c446d9daSMark Bloch 		return -EINVAL;
2026628e2dSMark Bloch 
2126628e2dSMark Bloch 	ibdev->port[vport_index].rep = rep;
22b8ca1238SBodong Wang 	rep->rep_data[REP_IB].priv = ibdev;
2326628e2dSMark Bloch 	write_lock(&ibdev->port[vport_index].roce.netdev_lock);
2426628e2dSMark Bloch 	ibdev->port[vport_index].roce.netdev =
25658cfcebSMark Bloch 		mlx5_ib_get_rep_netdev(rep->esw, rep->vport);
2626628e2dSMark Bloch 	write_unlock(&ibdev->port[vport_index].roce.netdev_lock);
2726628e2dSMark Bloch 
2826628e2dSMark Bloch 	return 0;
2926628e2dSMark Bloch }
3026628e2dSMark Bloch 
31c446d9daSMark Bloch static void mlx5_ib_register_peer_vport_reps(struct mlx5_core_dev *mdev);
32c446d9daSMark Bloch 
mlx5_ib_num_ports_update(struct mlx5_core_dev * dev,u32 * num_ports)33*222dd185SShay Drory static void mlx5_ib_num_ports_update(struct mlx5_core_dev *dev, u32 *num_ports)
34*222dd185SShay Drory {
35*222dd185SShay Drory 	struct mlx5_core_dev *peer_dev;
36*222dd185SShay Drory 	int i;
37*222dd185SShay Drory 
38*222dd185SShay Drory 	mlx5_lag_for_each_peer_mdev(dev, peer_dev, i) {
39*222dd185SShay Drory 		u32 peer_num_ports = mlx5_eswitch_get_total_vports(peer_dev);
40*222dd185SShay Drory 
41*222dd185SShay Drory 		if (mlx5_lag_is_mpesw(peer_dev))
42*222dd185SShay Drory 			*num_ports += peer_num_ports;
43*222dd185SShay Drory 		else
44*222dd185SShay Drory 			/* Only 1 ib port is the representor for all uplinks */
45*222dd185SShay Drory 			*num_ports += peer_num_ports - 1;
46*222dd185SShay Drory 	}
47*222dd185SShay Drory }
48*222dd185SShay Drory 
4926628e2dSMark Bloch static int
mlx5_ib_vport_rep_load(struct mlx5_core_dev * dev,struct mlx5_eswitch_rep * rep)50fc385b7aSMark Bloch mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
51fc385b7aSMark Bloch {
521fb7f897SMark Bloch 	u32 num_ports = mlx5_eswitch_get_total_vports(dev);
53*222dd185SShay Drory 	struct mlx5_core_dev *lag_master = dev;
54f0666f1fSBodong Wang 	const struct mlx5_ib_profile *profile;
55c446d9daSMark Bloch 	struct mlx5_core_dev *peer_dev;
56b5ca15adSMark Bloch 	struct mlx5_ib_dev *ibdev;
57*222dd185SShay Drory 	int new_uplink = false;
5826628e2dSMark Bloch 	int vport_index;
5993f82444SLeon Romanovsky 	int ret;
60*222dd185SShay Drory 	int i;
61b5ca15adSMark Bloch 
62c446d9daSMark Bloch 	vport_index = rep->vport_index;
63c446d9daSMark Bloch 
64c446d9daSMark Bloch 	if (mlx5_lag_is_shared_fdb(dev)) {
65c446d9daSMark Bloch 		if (mlx5_lag_is_master(dev)) {
66*222dd185SShay Drory 			mlx5_ib_num_ports_update(dev, &num_ports);
67c446d9daSMark Bloch 		} else {
6827f9e0ccSMark Bloch 			if (rep->vport == MLX5_VPORT_UPLINK) {
6927f9e0ccSMark Bloch 				if (!mlx5_lag_is_mpesw(dev))
70c446d9daSMark Bloch 					return 0;
71*222dd185SShay Drory 				new_uplink = true;
7227f9e0ccSMark Bloch 			}
73*222dd185SShay Drory 			mlx5_lag_for_each_peer_mdev(dev, peer_dev, i) {
74*222dd185SShay Drory 				u32 peer_n_ports = mlx5_eswitch_get_total_vports(peer_dev);
7527f9e0ccSMark Bloch 
76*222dd185SShay Drory 				if (mlx5_lag_is_master(peer_dev))
77*222dd185SShay Drory 					lag_master = peer_dev;
78*222dd185SShay Drory 				else if (!mlx5_lag_is_mpesw(dev))
79*222dd185SShay Drory 				/* Only 1 ib port is the representor for all uplinks */
80*222dd185SShay Drory 					peer_n_ports--;
81*222dd185SShay Drory 
82*222dd185SShay Drory 				if (mlx5_get_dev_index(peer_dev) < mlx5_get_dev_index(dev))
83*222dd185SShay Drory 					vport_index += peer_n_ports;
84*222dd185SShay Drory 			}
85c446d9daSMark Bloch 		}
86c446d9daSMark Bloch 	}
87c446d9daSMark Bloch 
88*222dd185SShay Drory 	if (rep->vport == MLX5_VPORT_UPLINK && !new_uplink)
89b5a498baSMichael Guralnik 		profile = &raw_eth_profile;
90f0666f1fSBodong Wang 	else
91*222dd185SShay Drory 		return mlx5_ib_set_vport_rep(lag_master, rep, vport_index);
92f0666f1fSBodong Wang 
93459cc69fSLeon Romanovsky 	ibdev = ib_alloc_device(mlx5_ib_dev, ib_dev);
94b5ca15adSMark Bloch 	if (!ibdev)
95b5ca15adSMark Bloch 		return -ENOMEM;
96b5ca15adSMark Bloch 
97da796ccbSMark Bloch 	ibdev->port = kcalloc(num_ports, sizeof(*ibdev->port),
98da796ccbSMark Bloch 			      GFP_KERNEL);
99da796ccbSMark Bloch 	if (!ibdev->port) {
10093f82444SLeon Romanovsky 		ret = -ENOMEM;
10193f82444SLeon Romanovsky 		goto fail_port;
102da796ccbSMark Bloch 	}
103da796ccbSMark Bloch 
1046a4d00beSMark Bloch 	ibdev->is_rep = true;
1052f69e591SBodong Wang 	vport_index = rep->vport_index;
10626628e2dSMark Bloch 	ibdev->port[vport_index].rep = rep;
10726628e2dSMark Bloch 	ibdev->port[vport_index].roce.netdev =
108*222dd185SShay Drory 		mlx5_ib_get_rep_netdev(lag_master->priv.eswitch, rep->vport);
109*222dd185SShay Drory 	ibdev->mdev = lag_master;
110da796ccbSMark Bloch 	ibdev->num_ports = num_ports;
111da796ccbSMark Bloch 
11293f82444SLeon Romanovsky 	ret = __mlx5_ib_add(ibdev, profile);
11393f82444SLeon Romanovsky 	if (ret)
11493f82444SLeon Romanovsky 		goto fail_add;
115b5ca15adSMark Bloch 
1168693115aSParav Pandit 	rep->rep_data[REP_IB].priv = ibdev;
117*222dd185SShay Drory 	if (mlx5_lag_is_shared_fdb(lag_master))
118*222dd185SShay Drory 		mlx5_ib_register_peer_vport_reps(lag_master);
119b5ca15adSMark Bloch 
120fc385b7aSMark Bloch 	return 0;
12193f82444SLeon Romanovsky 
12293f82444SLeon Romanovsky fail_add:
12393f82444SLeon Romanovsky 	kfree(ibdev->port);
12493f82444SLeon Romanovsky fail_port:
12593f82444SLeon Romanovsky 	ib_dealloc_device(&ibdev->ib_dev);
12693f82444SLeon Romanovsky 	return ret;
127fc385b7aSMark Bloch }
128fc385b7aSMark Bloch 
mlx5_ib_rep_to_dev(struct mlx5_eswitch_rep * rep)12904b222f9SLeon Romanovsky static void *mlx5_ib_rep_to_dev(struct mlx5_eswitch_rep *rep)
13004b222f9SLeon Romanovsky {
13104b222f9SLeon Romanovsky 	return rep->rep_data[REP_IB].priv;
13204b222f9SLeon Romanovsky }
13304b222f9SLeon Romanovsky 
134fc385b7aSMark Bloch static void
mlx5_ib_vport_rep_unload(struct mlx5_eswitch_rep * rep)135fc385b7aSMark Bloch mlx5_ib_vport_rep_unload(struct mlx5_eswitch_rep *rep)
136fc385b7aSMark Bloch {
137c446d9daSMark Bloch 	struct mlx5_core_dev *mdev = mlx5_eswitch_get_core_dev(rep->esw);
138b8ca1238SBodong Wang 	struct mlx5_ib_dev *dev = mlx5_ib_rep_to_dev(rep);
139c446d9daSMark Bloch 	int vport_index = rep->vport_index;
140b8ca1238SBodong Wang 	struct mlx5_ib_port *port;
141*222dd185SShay Drory 	int i;
142b5ca15adSMark Bloch 
143c446d9daSMark Bloch 	if (WARN_ON(!mdev))
144c446d9daSMark Bloch 		return;
145c446d9daSMark Bloch 
146c446d9daSMark Bloch 	if (!dev)
147c446d9daSMark Bloch 		return;
148c446d9daSMark Bloch 
149*222dd185SShay Drory 	if (mlx5_lag_is_shared_fdb(mdev) &&
150*222dd185SShay Drory 	    !mlx5_lag_is_master(mdev)) {
151*222dd185SShay Drory 		if (rep->vport == MLX5_VPORT_UPLINK && !mlx5_lag_is_mpesw(mdev))
152*222dd185SShay Drory 			return;
153*222dd185SShay Drory 		for (i = 0; i < dev->num_ports; i++) {
154*222dd185SShay Drory 			if (dev->port[i].rep == rep)
155*222dd185SShay Drory 				break;
156*222dd185SShay Drory 		}
157*222dd185SShay Drory 		if (WARN_ON(i == dev->num_ports))
158*222dd185SShay Drory 			return;
159*222dd185SShay Drory 		vport_index = i;
160*222dd185SShay Drory 	}
161*222dd185SShay Drory 
162c446d9daSMark Bloch 	port = &dev->port[vport_index];
163b8ca1238SBodong Wang 	write_lock(&port->roce.netdev_lock);
164b8ca1238SBodong Wang 	port->roce.netdev = NULL;
165b8ca1238SBodong Wang 	write_unlock(&port->roce.netdev_lock);
1668693115aSParav Pandit 	rep->rep_data[REP_IB].priv = NULL;
167b8ca1238SBodong Wang 	port->rep = NULL;
168b8ca1238SBodong Wang 
169c446d9daSMark Bloch 	if (rep->vport == MLX5_VPORT_UPLINK) {
170c446d9daSMark Bloch 
171962825e5SShay Drory 		if (mlx5_lag_is_shared_fdb(mdev) && !mlx5_lag_is_master(mdev))
172962825e5SShay Drory 			return;
173962825e5SShay Drory 
174c446d9daSMark Bloch 		if (mlx5_lag_is_shared_fdb(mdev)) {
175*222dd185SShay Drory 			struct mlx5_core_dev *peer_mdev;
176*222dd185SShay Drory 			struct mlx5_eswitch *esw;
177*222dd185SShay Drory 
178*222dd185SShay Drory 			mlx5_lag_for_each_peer_mdev(mdev, peer_mdev, i) {
179c446d9daSMark Bloch 				esw = peer_mdev->priv.eswitch;
180c446d9daSMark Bloch 				mlx5_eswitch_unregister_vport_reps(esw, REP_IB);
181c446d9daSMark Bloch 			}
182*222dd185SShay Drory 		}
183b8ca1238SBodong Wang 		__mlx5_ib_remove(dev, dev->profile, MLX5_IB_STAGE_MAX);
184fc385b7aSMark Bloch 	}
185c446d9daSMark Bloch }
186fc385b7aSMark Bloch 
1878693115aSParav Pandit static const struct mlx5_eswitch_rep_ops rep_ops = {
1888693115aSParav Pandit 	.load = mlx5_ib_vport_rep_load,
1898693115aSParav Pandit 	.unload = mlx5_ib_vport_rep_unload,
19004b222f9SLeon Romanovsky 	.get_proto_dev = mlx5_ib_rep_to_dev,
1918693115aSParav Pandit };
1928693115aSParav Pandit 
mlx5_ib_register_peer_vport_reps(struct mlx5_core_dev * mdev)193c446d9daSMark Bloch static void mlx5_ib_register_peer_vport_reps(struct mlx5_core_dev *mdev)
194c446d9daSMark Bloch {
195*222dd185SShay Drory 	struct mlx5_core_dev *peer_mdev;
196c446d9daSMark Bloch 	struct mlx5_eswitch *esw;
197*222dd185SShay Drory 	int i;
198c446d9daSMark Bloch 
199*222dd185SShay Drory 	mlx5_lag_for_each_peer_mdev(mdev, peer_mdev, i) {
200c446d9daSMark Bloch 		esw = peer_mdev->priv.eswitch;
201c446d9daSMark Bloch 		mlx5_eswitch_register_vport_reps(esw, &rep_ops, REP_IB);
202c446d9daSMark Bloch 	}
203*222dd185SShay Drory }
204c446d9daSMark Bloch 
mlx5_ib_get_rep_netdev(struct mlx5_eswitch * esw,u16 vport_num)205fc385b7aSMark Bloch struct net_device *mlx5_ib_get_rep_netdev(struct mlx5_eswitch *esw,
20602f3afd9SParav Pandit 					  u16 vport_num)
207fc385b7aSMark Bloch {
20802f3afd9SParav Pandit 	return mlx5_eswitch_get_proto_dev(esw, vport_num, REP_ETH);
209fc385b7aSMark Bloch }
210fc385b7aSMark Bloch 
create_flow_rule_vport_sq(struct mlx5_ib_dev * dev,struct mlx5_ib_sq * sq,u32 port)211d5ed8ac3SMark Bloch struct mlx5_flow_handle *create_flow_rule_vport_sq(struct mlx5_ib_dev *dev,
212d5ed8ac3SMark Bloch 						   struct mlx5_ib_sq *sq,
2131fb7f897SMark Bloch 						   u32 port)
214b96c9ddeSMark Bloch {
215b96c9ddeSMark Bloch 	struct mlx5_eswitch *esw = dev->mdev->priv.eswitch;
216d5ed8ac3SMark Bloch 	struct mlx5_eswitch_rep *rep;
217b96c9ddeSMark Bloch 
218d5ed8ac3SMark Bloch 	if (!dev->is_rep || !port)
219d5ed8ac3SMark Bloch 		return NULL;
220b96c9ddeSMark Bloch 
221d5ed8ac3SMark Bloch 	if (!dev->port[port - 1].rep)
222d5ed8ac3SMark Bloch 		return ERR_PTR(-EINVAL);
223d5ed8ac3SMark Bloch 
224d5ed8ac3SMark Bloch 	rep = dev->port[port - 1].rep;
225d5ed8ac3SMark Bloch 
226979bf468SMark Bloch 	return mlx5_eswitch_add_send_to_vport_rule(esw, esw, rep, sq->base.mqp.qpn);
227b96c9ddeSMark Bloch }
22893f82444SLeon Romanovsky 
mlx5r_rep_probe(struct auxiliary_device * adev,const struct auxiliary_device_id * id)22993f82444SLeon Romanovsky static int mlx5r_rep_probe(struct auxiliary_device *adev,
23093f82444SLeon Romanovsky 			   const struct auxiliary_device_id *id)
23193f82444SLeon Romanovsky {
23293f82444SLeon Romanovsky 	struct mlx5_adev *idev = container_of(adev, struct mlx5_adev, adev);
23393f82444SLeon Romanovsky 	struct mlx5_core_dev *mdev = idev->mdev;
23493f82444SLeon Romanovsky 	struct mlx5_eswitch *esw;
23593f82444SLeon Romanovsky 
23693f82444SLeon Romanovsky 	esw = mdev->priv.eswitch;
23793f82444SLeon Romanovsky 	mlx5_eswitch_register_vport_reps(esw, &rep_ops, REP_IB);
23893f82444SLeon Romanovsky 	return 0;
23993f82444SLeon Romanovsky }
24093f82444SLeon Romanovsky 
mlx5r_rep_remove(struct auxiliary_device * adev)24193f82444SLeon Romanovsky static void mlx5r_rep_remove(struct auxiliary_device *adev)
24293f82444SLeon Romanovsky {
24393f82444SLeon Romanovsky 	struct mlx5_adev *idev = container_of(adev, struct mlx5_adev, adev);
24493f82444SLeon Romanovsky 	struct mlx5_core_dev *mdev = idev->mdev;
24593f82444SLeon Romanovsky 	struct mlx5_eswitch *esw;
24693f82444SLeon Romanovsky 
24793f82444SLeon Romanovsky 	esw = mdev->priv.eswitch;
24893f82444SLeon Romanovsky 	mlx5_eswitch_unregister_vport_reps(esw, REP_IB);
24993f82444SLeon Romanovsky }
25093f82444SLeon Romanovsky 
25193f82444SLeon Romanovsky static const struct auxiliary_device_id mlx5r_rep_id_table[] = {
25293f82444SLeon Romanovsky 	{ .name = MLX5_ADEV_NAME ".rdma-rep", },
25393f82444SLeon Romanovsky 	{},
25493f82444SLeon Romanovsky };
25593f82444SLeon Romanovsky 
25693f82444SLeon Romanovsky MODULE_DEVICE_TABLE(auxiliary, mlx5r_rep_id_table);
25793f82444SLeon Romanovsky 
25893f82444SLeon Romanovsky static struct auxiliary_driver mlx5r_rep_driver = {
25993f82444SLeon Romanovsky 	.name = "rep",
26093f82444SLeon Romanovsky 	.probe = mlx5r_rep_probe,
26193f82444SLeon Romanovsky 	.remove = mlx5r_rep_remove,
26293f82444SLeon Romanovsky 	.id_table = mlx5r_rep_id_table,
26393f82444SLeon Romanovsky };
26493f82444SLeon Romanovsky 
mlx5r_rep_init(void)26593f82444SLeon Romanovsky int mlx5r_rep_init(void)
26693f82444SLeon Romanovsky {
26793f82444SLeon Romanovsky 	return auxiliary_driver_register(&mlx5r_rep_driver);
26893f82444SLeon Romanovsky }
26993f82444SLeon Romanovsky 
mlx5r_rep_cleanup(void)27093f82444SLeon Romanovsky void mlx5r_rep_cleanup(void)
27193f82444SLeon Romanovsky {
27293f82444SLeon Romanovsky 	auxiliary_driver_unregister(&mlx5r_rep_driver);
27393f82444SLeon Romanovsky }
274