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