1/* 2 * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved. 3 * Copyright (c) 2005, 2006 PathScale, 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 <linux/rculist.h> 35#include <linux/sched.h> 36#include <linux/slab.h> 37 38#include "ipath_verbs.h" 39 40/* 41 * Global table of GID to attached QPs. 42 * The table is global to all ipath devices since a send from one QP/device 43 * needs to be locally routed to any locally attached QPs on the same 44 * or different device. 45 */ 46static struct rb_root mcast_tree; 47static DEFINE_SPINLOCK(mcast_lock); 48 49/** 50 * ipath_mcast_qp_alloc - alloc a struct to link a QP to mcast GID struct 51 * @qp: the QP to link 52 */ 53static struct ipath_mcast_qp *ipath_mcast_qp_alloc(struct ipath_qp *qp) 54{ 55 struct ipath_mcast_qp *mqp; 56 57 mqp = kmalloc(sizeof *mqp, GFP_KERNEL); 58 if (!mqp) 59 goto bail; 60 61 mqp->qp = qp; 62 atomic_inc(&qp->refcount); 63 64bail: 65 return mqp; 66} 67 68static void ipath_mcast_qp_free(struct ipath_mcast_qp *mqp) 69{ 70 struct ipath_qp *qp = mqp->qp; 71 72 /* Notify ipath_destroy_qp() if it is waiting. */ 73 if (atomic_dec_and_test(&qp->refcount)) 74 wake_up(&qp->wait); 75 76 kfree(mqp); 77} 78 79/** 80 * ipath_mcast_alloc - allocate the multicast GID structure 81 * @mgid: the multicast GID 82 * 83 * A list of QPs will be attached to this structure. 84 */ 85static struct ipath_mcast *ipath_mcast_alloc(union ib_gid *mgid) 86{ 87 struct ipath_mcast *mcast; 88 89 mcast = kmalloc(sizeof *mcast, GFP_KERNEL); 90 if (!mcast) 91 goto bail; 92 93 mcast->mgid = *mgid; 94 INIT_LIST_HEAD(&mcast->qp_list); 95 init_waitqueue_head(&mcast->wait); 96 atomic_set(&mcast->refcount, 0); 97 mcast->n_attached = 0; 98 99bail: 100 return mcast; 101} 102 103static void ipath_mcast_free(struct ipath_mcast *mcast) 104{ 105 struct ipath_mcast_qp *p, *tmp; 106 107 list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) 108 ipath_mcast_qp_free(p); 109 110 kfree(mcast); 111} 112 113/** 114 * ipath_mcast_find - search the global table for the given multicast GID 115 * @mgid: the multicast GID to search for 116 * 117 * Returns NULL if not found. 118 * 119 * The caller is responsible for decrementing the reference count if found. 120 */ 121struct ipath_mcast *ipath_mcast_find(union ib_gid *mgid) 122{ 123 struct rb_node *n; 124 unsigned long flags; 125 struct ipath_mcast *mcast; 126 127 spin_lock_irqsave(&mcast_lock, flags); 128 n = mcast_tree.rb_node; 129 while (n) { 130 int ret; 131 132 mcast = rb_entry(n, struct ipath_mcast, rb_node); 133 134 ret = memcmp(mgid->raw, mcast->mgid.raw, 135 sizeof(union ib_gid)); 136 if (ret < 0) 137 n = n->rb_left; 138 else if (ret > 0) 139 n = n->rb_right; 140 else { 141 atomic_inc(&mcast->refcount); 142 spin_unlock_irqrestore(&mcast_lock, flags); 143 goto bail; 144 } 145 } 146 spin_unlock_irqrestore(&mcast_lock, flags); 147 148 mcast = NULL; 149 150bail: 151 return mcast; 152} 153 154/** 155 * ipath_mcast_add - insert mcast GID into table and attach QP struct 156 * @mcast: the mcast GID table 157 * @mqp: the QP to attach 158 * 159 * Return zero if both were added. Return EEXIST if the GID was already in 160 * the table but the QP was added. Return ESRCH if the QP was already 161 * attached and neither structure was added. 162 */ 163static int ipath_mcast_add(struct ipath_ibdev *dev, 164 struct ipath_mcast *mcast, 165 struct ipath_mcast_qp *mqp) 166{ 167 struct rb_node **n = &mcast_tree.rb_node; 168 struct rb_node *pn = NULL; 169 int ret; 170 171 spin_lock_irq(&mcast_lock); 172 173 while (*n) { 174 struct ipath_mcast *tmcast; 175 struct ipath_mcast_qp *p; 176 177 pn = *n; 178 tmcast = rb_entry(pn, struct ipath_mcast, rb_node); 179 180 ret = memcmp(mcast->mgid.raw, tmcast->mgid.raw, 181 sizeof(union ib_gid)); 182 if (ret < 0) { 183 n = &pn->rb_left; 184 continue; 185 } 186 if (ret > 0) { 187 n = &pn->rb_right; 188 continue; 189 } 190 191 /* Search the QP list to see if this is already there. */ 192 list_for_each_entry_rcu(p, &tmcast->qp_list, list) { 193 if (p->qp == mqp->qp) { 194 ret = ESRCH; 195 goto bail; 196 } 197 } 198 if (tmcast->n_attached == ib_ipath_max_mcast_qp_attached) { 199 ret = ENOMEM; 200 goto bail; 201 } 202 203 tmcast->n_attached++; 204 205 list_add_tail_rcu(&mqp->list, &tmcast->qp_list); 206 ret = EEXIST; 207 goto bail; 208 } 209 210 spin_lock(&dev->n_mcast_grps_lock); 211 if (dev->n_mcast_grps_allocated == ib_ipath_max_mcast_grps) { 212 spin_unlock(&dev->n_mcast_grps_lock); 213 ret = ENOMEM; 214 goto bail; 215 } 216 217 dev->n_mcast_grps_allocated++; 218 spin_unlock(&dev->n_mcast_grps_lock); 219 220 mcast->n_attached++; 221 222 list_add_tail_rcu(&mqp->list, &mcast->qp_list); 223 224 atomic_inc(&mcast->refcount); 225 rb_link_node(&mcast->rb_node, pn, n); 226 rb_insert_color(&mcast->rb_node, &mcast_tree); 227 228 ret = 0; 229 230bail: 231 spin_unlock_irq(&mcast_lock); 232 233 return ret; 234} 235 236int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 237{ 238 struct ipath_qp *qp = to_iqp(ibqp); 239 struct ipath_ibdev *dev = to_idev(ibqp->device); 240 struct ipath_mcast *mcast; 241 struct ipath_mcast_qp *mqp; 242 int ret; 243 244 /* 245 * Allocate data structures since its better to do this outside of 246 * spin locks and it will most likely be needed. 247 */ 248 mcast = ipath_mcast_alloc(gid); 249 if (mcast == NULL) { 250 ret = -ENOMEM; 251 goto bail; 252 } 253 mqp = ipath_mcast_qp_alloc(qp); 254 if (mqp == NULL) { 255 ipath_mcast_free(mcast); 256 ret = -ENOMEM; 257 goto bail; 258 } 259 switch (ipath_mcast_add(dev, mcast, mqp)) { 260 case ESRCH: 261 /* Neither was used: can't attach the same QP twice. */ 262 ipath_mcast_qp_free(mqp); 263 ipath_mcast_free(mcast); 264 ret = -EINVAL; 265 goto bail; 266 case EEXIST: /* The mcast wasn't used */ 267 ipath_mcast_free(mcast); 268 break; 269 case ENOMEM: 270 /* Exceeded the maximum number of mcast groups. */ 271 ipath_mcast_qp_free(mqp); 272 ipath_mcast_free(mcast); 273 ret = -ENOMEM; 274 goto bail; 275 default: 276 break; 277 } 278 279 ret = 0; 280 281bail: 282 return ret; 283} 284 285int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 286{ 287 struct ipath_qp *qp = to_iqp(ibqp); 288 struct ipath_ibdev *dev = to_idev(ibqp->device); 289 struct ipath_mcast *mcast = NULL; 290 struct ipath_mcast_qp *p, *tmp; 291 struct rb_node *n; 292 int last = 0; 293 int ret; 294 295 spin_lock_irq(&mcast_lock); 296 297 /* Find the GID in the mcast table. */ 298 n = mcast_tree.rb_node; 299 while (1) { 300 if (n == NULL) { 301 spin_unlock_irq(&mcast_lock); 302 ret = -EINVAL; 303 goto bail; 304 } 305 306 mcast = rb_entry(n, struct ipath_mcast, rb_node); 307 ret = memcmp(gid->raw, mcast->mgid.raw, 308 sizeof(union ib_gid)); 309 if (ret < 0) 310 n = n->rb_left; 311 else if (ret > 0) 312 n = n->rb_right; 313 else 314 break; 315 } 316 317 /* Search the QP list. */ 318 list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) { 319 if (p->qp != qp) 320 continue; 321 /* 322 * We found it, so remove it, but don't poison the forward 323 * link until we are sure there are no list walkers. 324 */ 325 list_del_rcu(&p->list); 326 mcast->n_attached--; 327 328 /* If this was the last attached QP, remove the GID too. */ 329 if (list_empty(&mcast->qp_list)) { 330 rb_erase(&mcast->rb_node, &mcast_tree); 331 last = 1; 332 } 333 break; 334 } 335 336 spin_unlock_irq(&mcast_lock); 337 338 if (p) { 339 /* 340 * Wait for any list walkers to finish before freeing the 341 * list element. 342 */ 343 wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1); 344 ipath_mcast_qp_free(p); 345 } 346 if (last) { 347 atomic_dec(&mcast->refcount); 348 wait_event(mcast->wait, !atomic_read(&mcast->refcount)); 349 ipath_mcast_free(mcast); 350 spin_lock_irq(&dev->n_mcast_grps_lock); 351 dev->n_mcast_grps_allocated--; 352 spin_unlock_irq(&dev->n_mcast_grps_lock); 353 } 354 355 ret = 0; 356 357bail: 358 return ret; 359} 360 361int ipath_mcast_tree_empty(void) 362{ 363 return mcast_tree.rb_node == NULL; 364} 365