1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* 3 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. 4 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. 5 */ 6 7 #include "rxe.h" 8 #include "rxe_loc.h" 9 10 int rxe_mcast_get_grp(struct rxe_dev *rxe, union ib_gid *mgid, 11 struct rxe_mc_grp **grp_p) 12 { 13 int err; 14 struct rxe_mc_grp *grp; 15 16 if (rxe->attr.max_mcast_qp_attach == 0) { 17 err = -EINVAL; 18 goto err1; 19 } 20 21 grp = rxe_pool_get_key(&rxe->mc_grp_pool, mgid); 22 if (grp) 23 goto done; 24 25 grp = rxe_alloc(&rxe->mc_grp_pool); 26 if (!grp) { 27 err = -ENOMEM; 28 goto err1; 29 } 30 31 INIT_LIST_HEAD(&grp->qp_list); 32 spin_lock_init(&grp->mcg_lock); 33 grp->rxe = rxe; 34 35 rxe_add_key(grp, mgid); 36 37 err = rxe_mcast_add(rxe, mgid); 38 if (err) 39 goto err2; 40 41 done: 42 *grp_p = grp; 43 return 0; 44 45 err2: 46 rxe_drop_ref(grp); 47 err1: 48 return err; 49 } 50 51 int rxe_mcast_add_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp, 52 struct rxe_mc_grp *grp) 53 { 54 int err; 55 struct rxe_mc_elem *elem; 56 57 /* check to see of the qp is already a member of the group */ 58 spin_lock_bh(&qp->grp_lock); 59 spin_lock_bh(&grp->mcg_lock); 60 list_for_each_entry(elem, &grp->qp_list, qp_list) { 61 if (elem->qp == qp) { 62 err = 0; 63 goto out; 64 } 65 } 66 67 if (grp->num_qp >= rxe->attr.max_mcast_qp_attach) { 68 err = -ENOMEM; 69 goto out; 70 } 71 72 elem = rxe_alloc(&rxe->mc_elem_pool); 73 if (!elem) { 74 err = -ENOMEM; 75 goto out; 76 } 77 78 /* each qp holds a ref on the grp */ 79 rxe_add_ref(grp); 80 81 grp->num_qp++; 82 elem->qp = qp; 83 elem->grp = grp; 84 85 list_add(&elem->qp_list, &grp->qp_list); 86 list_add(&elem->grp_list, &qp->grp_list); 87 88 err = 0; 89 out: 90 spin_unlock_bh(&grp->mcg_lock); 91 spin_unlock_bh(&qp->grp_lock); 92 return err; 93 } 94 95 int rxe_mcast_drop_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp, 96 union ib_gid *mgid) 97 { 98 struct rxe_mc_grp *grp; 99 struct rxe_mc_elem *elem, *tmp; 100 101 grp = rxe_pool_get_key(&rxe->mc_grp_pool, mgid); 102 if (!grp) 103 goto err1; 104 105 spin_lock_bh(&qp->grp_lock); 106 spin_lock_bh(&grp->mcg_lock); 107 108 list_for_each_entry_safe(elem, tmp, &grp->qp_list, qp_list) { 109 if (elem->qp == qp) { 110 list_del(&elem->qp_list); 111 list_del(&elem->grp_list); 112 grp->num_qp--; 113 114 spin_unlock_bh(&grp->mcg_lock); 115 spin_unlock_bh(&qp->grp_lock); 116 rxe_drop_ref(elem); 117 rxe_drop_ref(grp); /* ref held by QP */ 118 rxe_drop_ref(grp); /* ref from get_key */ 119 return 0; 120 } 121 } 122 123 spin_unlock_bh(&grp->mcg_lock); 124 spin_unlock_bh(&qp->grp_lock); 125 rxe_drop_ref(grp); /* ref from get_key */ 126 err1: 127 return -EINVAL; 128 } 129 130 void rxe_drop_all_mcast_groups(struct rxe_qp *qp) 131 { 132 struct rxe_mc_grp *grp; 133 struct rxe_mc_elem *elem; 134 135 while (1) { 136 spin_lock_bh(&qp->grp_lock); 137 if (list_empty(&qp->grp_list)) { 138 spin_unlock_bh(&qp->grp_lock); 139 break; 140 } 141 elem = list_first_entry(&qp->grp_list, struct rxe_mc_elem, 142 grp_list); 143 list_del(&elem->grp_list); 144 spin_unlock_bh(&qp->grp_lock); 145 146 grp = elem->grp; 147 spin_lock_bh(&grp->mcg_lock); 148 list_del(&elem->qp_list); 149 grp->num_qp--; 150 spin_unlock_bh(&grp->mcg_lock); 151 rxe_drop_ref(grp); 152 rxe_drop_ref(elem); 153 } 154 } 155 156 void rxe_mc_cleanup(struct rxe_pool_entry *arg) 157 { 158 struct rxe_mc_grp *grp = container_of(arg, typeof(*grp), pelem); 159 struct rxe_dev *rxe = grp->rxe; 160 161 rxe_drop_key(grp); 162 rxe_mcast_delete(rxe, &grp->mgid); 163 } 164