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 /* caller should hold mc_grp_pool->pool_lock */ 11 static struct rxe_mc_grp *create_grp(struct rxe_dev *rxe, 12 struct rxe_pool *pool, 13 union ib_gid *mgid) 14 { 15 int err; 16 struct rxe_mc_grp *grp; 17 18 grp = rxe_alloc_locked(&rxe->mc_grp_pool); 19 if (!grp) 20 return ERR_PTR(-ENOMEM); 21 22 INIT_LIST_HEAD(&grp->qp_list); 23 spin_lock_init(&grp->mcg_lock); 24 grp->rxe = rxe; 25 rxe_add_key_locked(grp, mgid); 26 27 err = rxe_mcast_add(rxe, mgid); 28 if (unlikely(err)) { 29 rxe_drop_key_locked(grp); 30 rxe_drop_ref(grp); 31 return ERR_PTR(err); 32 } 33 34 return grp; 35 } 36 37 int rxe_mcast_get_grp(struct rxe_dev *rxe, union ib_gid *mgid, 38 struct rxe_mc_grp **grp_p) 39 { 40 int err; 41 struct rxe_mc_grp *grp; 42 struct rxe_pool *pool = &rxe->mc_grp_pool; 43 44 if (rxe->attr.max_mcast_qp_attach == 0) 45 return -EINVAL; 46 47 write_lock_bh(&pool->pool_lock); 48 49 grp = rxe_pool_get_key_locked(pool, mgid); 50 if (grp) 51 goto done; 52 53 grp = create_grp(rxe, pool, mgid); 54 if (IS_ERR(grp)) { 55 write_unlock_bh(&pool->pool_lock); 56 err = PTR_ERR(grp); 57 return err; 58 } 59 60 done: 61 write_unlock_bh(&pool->pool_lock); 62 *grp_p = grp; 63 return 0; 64 } 65 66 int rxe_mcast_add_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp, 67 struct rxe_mc_grp *grp) 68 { 69 int err; 70 struct rxe_mc_elem *elem; 71 72 /* check to see of the qp is already a member of the group */ 73 spin_lock_bh(&qp->grp_lock); 74 spin_lock_bh(&grp->mcg_lock); 75 list_for_each_entry(elem, &grp->qp_list, qp_list) { 76 if (elem->qp == qp) { 77 err = 0; 78 goto out; 79 } 80 } 81 82 if (grp->num_qp >= rxe->attr.max_mcast_qp_attach) { 83 err = -ENOMEM; 84 goto out; 85 } 86 87 elem = rxe_alloc_locked(&rxe->mc_elem_pool); 88 if (!elem) { 89 err = -ENOMEM; 90 goto out; 91 } 92 93 /* each qp holds a ref on the grp */ 94 rxe_add_ref(grp); 95 96 grp->num_qp++; 97 elem->qp = qp; 98 elem->grp = grp; 99 100 list_add(&elem->qp_list, &grp->qp_list); 101 list_add(&elem->grp_list, &qp->grp_list); 102 103 err = 0; 104 out: 105 spin_unlock_bh(&grp->mcg_lock); 106 spin_unlock_bh(&qp->grp_lock); 107 return err; 108 } 109 110 int rxe_mcast_drop_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp, 111 union ib_gid *mgid) 112 { 113 struct rxe_mc_grp *grp; 114 struct rxe_mc_elem *elem, *tmp; 115 116 grp = rxe_pool_get_key(&rxe->mc_grp_pool, mgid); 117 if (!grp) 118 goto err1; 119 120 spin_lock_bh(&qp->grp_lock); 121 spin_lock_bh(&grp->mcg_lock); 122 123 list_for_each_entry_safe(elem, tmp, &grp->qp_list, qp_list) { 124 if (elem->qp == qp) { 125 list_del(&elem->qp_list); 126 list_del(&elem->grp_list); 127 grp->num_qp--; 128 129 spin_unlock_bh(&grp->mcg_lock); 130 spin_unlock_bh(&qp->grp_lock); 131 rxe_drop_ref(elem); 132 rxe_drop_ref(grp); /* ref held by QP */ 133 rxe_drop_ref(grp); /* ref from get_key */ 134 return 0; 135 } 136 } 137 138 spin_unlock_bh(&grp->mcg_lock); 139 spin_unlock_bh(&qp->grp_lock); 140 rxe_drop_ref(grp); /* ref from get_key */ 141 err1: 142 return -EINVAL; 143 } 144 145 void rxe_drop_all_mcast_groups(struct rxe_qp *qp) 146 { 147 struct rxe_mc_grp *grp; 148 struct rxe_mc_elem *elem; 149 150 while (1) { 151 spin_lock_bh(&qp->grp_lock); 152 if (list_empty(&qp->grp_list)) { 153 spin_unlock_bh(&qp->grp_lock); 154 break; 155 } 156 elem = list_first_entry(&qp->grp_list, struct rxe_mc_elem, 157 grp_list); 158 list_del(&elem->grp_list); 159 spin_unlock_bh(&qp->grp_lock); 160 161 grp = elem->grp; 162 spin_lock_bh(&grp->mcg_lock); 163 list_del(&elem->qp_list); 164 grp->num_qp--; 165 spin_unlock_bh(&grp->mcg_lock); 166 rxe_drop_ref(grp); 167 rxe_drop_ref(elem); 168 } 169 } 170 171 void rxe_mc_cleanup(struct rxe_pool_elem *elem) 172 { 173 struct rxe_mc_grp *grp = container_of(elem, typeof(*grp), elem); 174 struct rxe_dev *rxe = grp->rxe; 175 176 rxe_drop_key(grp); 177 rxe_mcast_delete(rxe, &grp->mgid); 178 } 179