1 /* 2 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. 3 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the 9 * OpenIB.org BSD license below: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34 #include "rxe.h" 35 #include "rxe_loc.h" 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 43 if (rxe->attr.max_mcast_qp_attach == 0) { 44 err = -EINVAL; 45 goto err1; 46 } 47 48 grp = rxe_pool_get_key(&rxe->mc_grp_pool, mgid); 49 if (grp) 50 goto done; 51 52 grp = rxe_alloc(&rxe->mc_grp_pool); 53 if (!grp) { 54 err = -ENOMEM; 55 goto err1; 56 } 57 58 INIT_LIST_HEAD(&grp->qp_list); 59 spin_lock_init(&grp->mcg_lock); 60 grp->rxe = rxe; 61 62 rxe_add_key(grp, mgid); 63 64 err = rxe->ifc_ops->mcast_add(rxe, mgid); 65 if (err) 66 goto err2; 67 68 done: 69 *grp_p = grp; 70 return 0; 71 72 err2: 73 rxe_drop_ref(grp); 74 err1: 75 return err; 76 } 77 78 int rxe_mcast_add_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp, 79 struct rxe_mc_grp *grp) 80 { 81 int err; 82 struct rxe_mc_elem *elem; 83 84 /* check to see of the qp is already a member of the group */ 85 spin_lock_bh(&qp->grp_lock); 86 spin_lock_bh(&grp->mcg_lock); 87 list_for_each_entry(elem, &grp->qp_list, qp_list) { 88 if (elem->qp == qp) { 89 err = 0; 90 goto out; 91 } 92 } 93 94 if (grp->num_qp >= rxe->attr.max_mcast_qp_attach) { 95 err = -ENOMEM; 96 goto out; 97 } 98 99 elem = rxe_alloc(&rxe->mc_elem_pool); 100 if (!elem) { 101 err = -ENOMEM; 102 goto out; 103 } 104 105 /* each qp holds a ref on the grp */ 106 rxe_add_ref(grp); 107 108 grp->num_qp++; 109 elem->qp = qp; 110 elem->grp = grp; 111 112 list_add(&elem->qp_list, &grp->qp_list); 113 list_add(&elem->grp_list, &qp->grp_list); 114 115 err = 0; 116 out: 117 spin_unlock_bh(&grp->mcg_lock); 118 spin_unlock_bh(&qp->grp_lock); 119 return err; 120 } 121 122 int rxe_mcast_drop_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp, 123 union ib_gid *mgid) 124 { 125 struct rxe_mc_grp *grp; 126 struct rxe_mc_elem *elem, *tmp; 127 128 grp = rxe_pool_get_key(&rxe->mc_grp_pool, mgid); 129 if (!grp) 130 goto err1; 131 132 spin_lock_bh(&qp->grp_lock); 133 spin_lock_bh(&grp->mcg_lock); 134 135 list_for_each_entry_safe(elem, tmp, &grp->qp_list, qp_list) { 136 if (elem->qp == qp) { 137 list_del(&elem->qp_list); 138 list_del(&elem->grp_list); 139 grp->num_qp--; 140 141 spin_unlock_bh(&grp->mcg_lock); 142 spin_unlock_bh(&qp->grp_lock); 143 rxe_drop_ref(elem); 144 rxe_drop_ref(grp); /* ref held by QP */ 145 rxe_drop_ref(grp); /* ref from get_key */ 146 return 0; 147 } 148 } 149 150 spin_unlock_bh(&grp->mcg_lock); 151 spin_unlock_bh(&qp->grp_lock); 152 rxe_drop_ref(grp); /* ref from get_key */ 153 err1: 154 return -EINVAL; 155 } 156 157 void rxe_drop_all_mcast_groups(struct rxe_qp *qp) 158 { 159 struct rxe_mc_grp *grp; 160 struct rxe_mc_elem *elem; 161 162 while (1) { 163 spin_lock_bh(&qp->grp_lock); 164 if (list_empty(&qp->grp_list)) { 165 spin_unlock_bh(&qp->grp_lock); 166 break; 167 } 168 elem = list_first_entry(&qp->grp_list, struct rxe_mc_elem, 169 grp_list); 170 list_del(&elem->grp_list); 171 spin_unlock_bh(&qp->grp_lock); 172 173 grp = elem->grp; 174 spin_lock_bh(&grp->mcg_lock); 175 list_del(&elem->qp_list); 176 grp->num_qp--; 177 spin_unlock_bh(&grp->mcg_lock); 178 rxe_drop_ref(grp); 179 rxe_drop_ref(elem); 180 } 181 } 182 183 void rxe_mc_cleanup(void *arg) 184 { 185 struct rxe_mc_grp *grp = arg; 186 struct rxe_dev *rxe = grp->rxe; 187 188 rxe_drop_key(grp); 189 rxe->ifc_ops->mcast_delete(rxe, &grp->mgid); 190 } 191