ib_rep.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2. /*
  3. * Copyright (c) 2018 Mellanox Technologies. All rights reserved.
  4. */
  5. #include <linux/mlx5/vport.h>
  6. #include "ib_rep.h"
  7. #include "srq.h"
  8. static int
  9. mlx5_ib_set_vport_rep(struct mlx5_core_dev *dev,
  10. struct mlx5_eswitch_rep *rep,
  11. int vport_index)
  12. {
  13. struct mlx5_ib_dev *ibdev;
  14. ibdev = mlx5_eswitch_uplink_get_proto_dev(dev->priv.eswitch, REP_IB);
  15. if (!ibdev)
  16. return -EINVAL;
  17. ibdev->port[vport_index].rep = rep;
  18. rep->rep_data[REP_IB].priv = ibdev;
  19. write_lock(&ibdev->port[vport_index].roce.netdev_lock);
  20. ibdev->port[vport_index].roce.netdev =
  21. mlx5_ib_get_rep_netdev(rep->esw, rep->vport);
  22. write_unlock(&ibdev->port[vport_index].roce.netdev_lock);
  23. return 0;
  24. }
  25. static void mlx5_ib_register_peer_vport_reps(struct mlx5_core_dev *mdev);
  26. static int
  27. mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
  28. {
  29. u32 num_ports = mlx5_eswitch_get_total_vports(dev);
  30. const struct mlx5_ib_profile *profile;
  31. struct mlx5_core_dev *peer_dev;
  32. struct mlx5_ib_dev *ibdev;
  33. u32 peer_num_ports;
  34. int vport_index;
  35. int ret;
  36. vport_index = rep->vport_index;
  37. if (mlx5_lag_is_shared_fdb(dev)) {
  38. peer_dev = mlx5_lag_get_peer_mdev(dev);
  39. peer_num_ports = mlx5_eswitch_get_total_vports(peer_dev);
  40. if (mlx5_lag_is_master(dev)) {
  41. /* Only 1 ib port is the representor for both uplinks */
  42. num_ports += peer_num_ports - 1;
  43. } else {
  44. if (rep->vport == MLX5_VPORT_UPLINK)
  45. return 0;
  46. vport_index += peer_num_ports;
  47. dev = peer_dev;
  48. }
  49. }
  50. if (rep->vport == MLX5_VPORT_UPLINK)
  51. profile = &raw_eth_profile;
  52. else
  53. return mlx5_ib_set_vport_rep(dev, rep, vport_index);
  54. ibdev = ib_alloc_device(mlx5_ib_dev, ib_dev);
  55. if (!ibdev)
  56. return -ENOMEM;
  57. ibdev->port = kcalloc(num_ports, sizeof(*ibdev->port),
  58. GFP_KERNEL);
  59. if (!ibdev->port) {
  60. ret = -ENOMEM;
  61. goto fail_port;
  62. }
  63. ibdev->is_rep = true;
  64. vport_index = rep->vport_index;
  65. ibdev->port[vport_index].rep = rep;
  66. ibdev->port[vport_index].roce.netdev =
  67. mlx5_ib_get_rep_netdev(dev->priv.eswitch, rep->vport);
  68. ibdev->mdev = dev;
  69. ibdev->num_ports = num_ports;
  70. ret = __mlx5_ib_add(ibdev, profile);
  71. if (ret)
  72. goto fail_add;
  73. rep->rep_data[REP_IB].priv = ibdev;
  74. if (mlx5_lag_is_shared_fdb(dev))
  75. mlx5_ib_register_peer_vport_reps(dev);
  76. return 0;
  77. fail_add:
  78. kfree(ibdev->port);
  79. fail_port:
  80. ib_dealloc_device(&ibdev->ib_dev);
  81. return ret;
  82. }
  83. static void *mlx5_ib_rep_to_dev(struct mlx5_eswitch_rep *rep)
  84. {
  85. return rep->rep_data[REP_IB].priv;
  86. }
  87. static void
  88. mlx5_ib_vport_rep_unload(struct mlx5_eswitch_rep *rep)
  89. {
  90. struct mlx5_core_dev *mdev = mlx5_eswitch_get_core_dev(rep->esw);
  91. struct mlx5_ib_dev *dev = mlx5_ib_rep_to_dev(rep);
  92. int vport_index = rep->vport_index;
  93. struct mlx5_ib_port *port;
  94. if (WARN_ON(!mdev))
  95. return;
  96. if (mlx5_lag_is_shared_fdb(mdev) &&
  97. !mlx5_lag_is_master(mdev)) {
  98. struct mlx5_core_dev *peer_mdev;
  99. if (rep->vport == MLX5_VPORT_UPLINK)
  100. return;
  101. peer_mdev = mlx5_lag_get_peer_mdev(mdev);
  102. vport_index += mlx5_eswitch_get_total_vports(peer_mdev);
  103. }
  104. if (!dev)
  105. return;
  106. port = &dev->port[vport_index];
  107. write_lock(&port->roce.netdev_lock);
  108. port->roce.netdev = NULL;
  109. write_unlock(&port->roce.netdev_lock);
  110. rep->rep_data[REP_IB].priv = NULL;
  111. port->rep = NULL;
  112. if (rep->vport == MLX5_VPORT_UPLINK) {
  113. struct mlx5_core_dev *peer_mdev;
  114. struct mlx5_eswitch *esw;
  115. if (mlx5_lag_is_shared_fdb(mdev)) {
  116. peer_mdev = mlx5_lag_get_peer_mdev(mdev);
  117. esw = peer_mdev->priv.eswitch;
  118. mlx5_eswitch_unregister_vport_reps(esw, REP_IB);
  119. }
  120. __mlx5_ib_remove(dev, dev->profile, MLX5_IB_STAGE_MAX);
  121. }
  122. }
  123. static const struct mlx5_eswitch_rep_ops rep_ops = {
  124. .load = mlx5_ib_vport_rep_load,
  125. .unload = mlx5_ib_vport_rep_unload,
  126. .get_proto_dev = mlx5_ib_rep_to_dev,
  127. };
  128. static void mlx5_ib_register_peer_vport_reps(struct mlx5_core_dev *mdev)
  129. {
  130. struct mlx5_core_dev *peer_mdev = mlx5_lag_get_peer_mdev(mdev);
  131. struct mlx5_eswitch *esw;
  132. if (!peer_mdev)
  133. return;
  134. esw = peer_mdev->priv.eswitch;
  135. mlx5_eswitch_register_vport_reps(esw, &rep_ops, REP_IB);
  136. }
  137. struct net_device *mlx5_ib_get_rep_netdev(struct mlx5_eswitch *esw,
  138. u16 vport_num)
  139. {
  140. return mlx5_eswitch_get_proto_dev(esw, vport_num, REP_ETH);
  141. }
  142. struct mlx5_flow_handle *create_flow_rule_vport_sq(struct mlx5_ib_dev *dev,
  143. struct mlx5_ib_sq *sq,
  144. u32 port)
  145. {
  146. struct mlx5_eswitch *esw = dev->mdev->priv.eswitch;
  147. struct mlx5_eswitch_rep *rep;
  148. if (!dev->is_rep || !port)
  149. return NULL;
  150. if (!dev->port[port - 1].rep)
  151. return ERR_PTR(-EINVAL);
  152. rep = dev->port[port - 1].rep;
  153. return mlx5_eswitch_add_send_to_vport_rule(esw, esw, rep, sq->base.mqp.qpn);
  154. }
  155. static int mlx5r_rep_probe(struct auxiliary_device *adev,
  156. const struct auxiliary_device_id *id)
  157. {
  158. struct mlx5_adev *idev = container_of(adev, struct mlx5_adev, adev);
  159. struct mlx5_core_dev *mdev = idev->mdev;
  160. struct mlx5_eswitch *esw;
  161. esw = mdev->priv.eswitch;
  162. mlx5_eswitch_register_vport_reps(esw, &rep_ops, REP_IB);
  163. return 0;
  164. }
  165. static void mlx5r_rep_remove(struct auxiliary_device *adev)
  166. {
  167. struct mlx5_adev *idev = container_of(adev, struct mlx5_adev, adev);
  168. struct mlx5_core_dev *mdev = idev->mdev;
  169. struct mlx5_eswitch *esw;
  170. esw = mdev->priv.eswitch;
  171. mlx5_eswitch_unregister_vport_reps(esw, REP_IB);
  172. }
  173. static const struct auxiliary_device_id mlx5r_rep_id_table[] = {
  174. { .name = MLX5_ADEV_NAME ".rdma-rep", },
  175. {},
  176. };
  177. MODULE_DEVICE_TABLE(auxiliary, mlx5r_rep_id_table);
  178. static struct auxiliary_driver mlx5r_rep_driver = {
  179. .name = "rep",
  180. .probe = mlx5r_rep_probe,
  181. .remove = mlx5r_rep_remove,
  182. .id_table = mlx5r_rep_id_table,
  183. };
  184. int mlx5r_rep_init(void)
  185. {
  186. return auxiliary_driver_register(&mlx5r_rep_driver);
  187. }
  188. void mlx5r_rep_cleanup(void)
  189. {
  190. auxiliary_driver_unregister(&mlx5r_rep_driver);
  191. }