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_if[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_if[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_if[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 void mlx5_ib_register_vport_reps(struct mlx5_core_dev *mdev) 88 { 89 struct mlx5_eswitch *esw = mdev->priv.eswitch; 90 struct mlx5_eswitch_rep_if rep_if = {}; 91 92 rep_if.load = mlx5_ib_vport_rep_load; 93 rep_if.unload = mlx5_ib_vport_rep_unload; 94 rep_if.get_proto_dev = mlx5_ib_vport_get_proto_dev; 95 96 mlx5_eswitch_register_vport_reps(esw, &rep_if, REP_IB); 97 } 98 99 void mlx5_ib_unregister_vport_reps(struct mlx5_core_dev *mdev) 100 { 101 struct mlx5_eswitch *esw = mdev->priv.eswitch; 102 103 mlx5_eswitch_unregister_vport_reps(esw, REP_IB); 104 } 105 106 u8 mlx5_ib_eswitch_mode(struct mlx5_eswitch *esw) 107 { 108 return mlx5_eswitch_mode(esw); 109 } 110 111 struct mlx5_ib_dev *mlx5_ib_get_rep_ibdev(struct mlx5_eswitch *esw, 112 int vport_index) 113 { 114 return mlx5_eswitch_get_proto_dev(esw, vport_index, REP_IB); 115 } 116 117 struct net_device *mlx5_ib_get_rep_netdev(struct mlx5_eswitch *esw, 118 int vport_index) 119 { 120 return mlx5_eswitch_get_proto_dev(esw, vport_index, REP_ETH); 121 } 122 123 struct mlx5_ib_dev *mlx5_ib_get_uplink_ibdev(struct mlx5_eswitch *esw) 124 { 125 return mlx5_eswitch_uplink_get_proto_dev(esw, REP_IB); 126 } 127 128 struct mlx5_eswitch_rep *mlx5_ib_vport_rep(struct mlx5_eswitch *esw, int vport) 129 { 130 return mlx5_eswitch_vport_rep(esw, vport); 131 } 132 133 struct mlx5_flow_handle *create_flow_rule_vport_sq(struct mlx5_ib_dev *dev, 134 struct mlx5_ib_sq *sq, 135 u16 port) 136 { 137 struct mlx5_eswitch *esw = dev->mdev->priv.eswitch; 138 struct mlx5_eswitch_rep *rep; 139 140 if (!dev->is_rep || !port) 141 return NULL; 142 143 if (!dev->port[port - 1].rep) 144 return ERR_PTR(-EINVAL); 145 146 rep = dev->port[port - 1].rep; 147 148 return mlx5_eswitch_add_send_to_vport_rule(esw, rep->vport, 149 sq->base.mqp.qpn); 150 } 151