1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* 3 * Copyright (c) 2018 Mellanox Technologies. All rights reserved. 4 */ 5 6 #include <linux/mlx5/vport.h> 7 #include "ib_rep.h" 8 #include "srq.h" 9 10 static int 11 mlx5_ib_set_vport_rep(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) 12 { 13 struct mlx5_ib_dev *ibdev; 14 int vport_index; 15 16 ibdev = mlx5_ib_get_uplink_ibdev(dev->priv.eswitch); 17 vport_index = ibdev->free_port++; 18 19 ibdev->port[vport_index].rep = rep; 20 write_lock(&ibdev->port[vport_index].roce.netdev_lock); 21 ibdev->port[vport_index].roce.netdev = 22 mlx5_ib_get_rep_netdev(dev->priv.eswitch, rep->vport); 23 write_unlock(&ibdev->port[vport_index].roce.netdev_lock); 24 25 return 0; 26 } 27 28 static int 29 mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) 30 { 31 int num_ports = MLX5_TOTAL_VPORTS(dev); 32 const struct mlx5_ib_profile *profile; 33 struct mlx5_ib_dev *ibdev; 34 int vport_index; 35 36 if (rep->vport == MLX5_VPORT_UPLINK) 37 profile = &uplink_rep_profile; 38 else 39 return mlx5_ib_set_vport_rep(dev, rep); 40 41 ibdev = ib_alloc_device(mlx5_ib_dev, ib_dev); 42 if (!ibdev) 43 return -ENOMEM; 44 45 ibdev->port = kcalloc(num_ports, sizeof(*ibdev->port), 46 GFP_KERNEL); 47 if (!ibdev->port) { 48 ib_dealloc_device(&ibdev->ib_dev); 49 return -ENOMEM; 50 } 51 52 ibdev->is_rep = true; 53 vport_index = ibdev->free_port++; 54 ibdev->port[vport_index].rep = rep; 55 ibdev->port[vport_index].roce.netdev = 56 mlx5_ib_get_rep_netdev(dev->priv.eswitch, rep->vport); 57 ibdev->mdev = dev; 58 ibdev->num_ports = num_ports; 59 60 if (!__mlx5_ib_add(ibdev, profile)) 61 return -EINVAL; 62 63 rep->rep_data[REP_IB].priv = ibdev; 64 65 return 0; 66 } 67 68 static void 69 mlx5_ib_vport_rep_unload(struct mlx5_eswitch_rep *rep) 70 { 71 struct mlx5_ib_dev *dev; 72 73 if (!rep->rep_data[REP_IB].priv || 74 rep->vport != MLX5_VPORT_UPLINK) 75 return; 76 77 dev = mlx5_ib_rep_to_dev(rep); 78 __mlx5_ib_remove(dev, dev->profile, MLX5_IB_STAGE_MAX); 79 rep->rep_data[REP_IB].priv = NULL; 80 } 81 82 static void *mlx5_ib_vport_get_proto_dev(struct mlx5_eswitch_rep *rep) 83 { 84 return mlx5_ib_rep_to_dev(rep); 85 } 86 87 static const struct mlx5_eswitch_rep_ops rep_ops = { 88 .load = mlx5_ib_vport_rep_load, 89 .unload = mlx5_ib_vport_rep_unload, 90 .get_proto_dev = mlx5_ib_vport_get_proto_dev, 91 }; 92 93 void mlx5_ib_register_vport_reps(struct mlx5_core_dev *mdev) 94 { 95 struct mlx5_eswitch *esw = mdev->priv.eswitch; 96 97 mlx5_eswitch_register_vport_reps(esw, &rep_ops, REP_IB); 98 } 99 100 void mlx5_ib_unregister_vport_reps(struct mlx5_core_dev *mdev) 101 { 102 struct mlx5_eswitch *esw = mdev->priv.eswitch; 103 104 mlx5_eswitch_unregister_vport_reps(esw, REP_IB); 105 } 106 107 u8 mlx5_ib_eswitch_mode(struct mlx5_eswitch *esw) 108 { 109 return mlx5_eswitch_mode(esw); 110 } 111 112 struct mlx5_ib_dev *mlx5_ib_get_rep_ibdev(struct mlx5_eswitch *esw, 113 u16 vport_num) 114 { 115 return mlx5_eswitch_get_proto_dev(esw, vport_num, REP_IB); 116 } 117 118 struct net_device *mlx5_ib_get_rep_netdev(struct mlx5_eswitch *esw, 119 u16 vport_num) 120 { 121 return mlx5_eswitch_get_proto_dev(esw, vport_num, REP_ETH); 122 } 123 124 struct mlx5_ib_dev *mlx5_ib_get_uplink_ibdev(struct mlx5_eswitch *esw) 125 { 126 return mlx5_eswitch_uplink_get_proto_dev(esw, REP_IB); 127 } 128 129 struct mlx5_eswitch_rep *mlx5_ib_vport_rep(struct mlx5_eswitch *esw, 130 u16 vport_num) 131 { 132 return mlx5_eswitch_vport_rep(esw, vport_num); 133 } 134 135 struct mlx5_flow_handle *create_flow_rule_vport_sq(struct mlx5_ib_dev *dev, 136 struct mlx5_ib_sq *sq, 137 u16 port) 138 { 139 struct mlx5_eswitch *esw = dev->mdev->priv.eswitch; 140 struct mlx5_eswitch_rep *rep; 141 142 if (!dev->is_rep || !port) 143 return NULL; 144 145 if (!dev->port[port - 1].rep) 146 return ERR_PTR(-EINVAL); 147 148 rep = dev->port[port - 1].rep; 149 150 return mlx5_eswitch_add_send_to_vport_rule(esw, rep->vport, 151 sq->base.mqp.qpn); 152 } 153