19fa25171SDennis Dalessandro /* 2fe314195SDennis Dalessandro * Copyright(c) 2016 Intel Corporation. 39fa25171SDennis Dalessandro * 49fa25171SDennis Dalessandro * This file is provided under a dual BSD/GPLv2 license. When using or 59fa25171SDennis Dalessandro * redistributing this file, you may do so under either license. 69fa25171SDennis Dalessandro * 79fa25171SDennis Dalessandro * GPL LICENSE SUMMARY 89fa25171SDennis Dalessandro * 99fa25171SDennis Dalessandro * This program is free software; you can redistribute it and/or modify 109fa25171SDennis Dalessandro * it under the terms of version 2 of the GNU General Public License as 119fa25171SDennis Dalessandro * published by the Free Software Foundation. 129fa25171SDennis Dalessandro * 139fa25171SDennis Dalessandro * This program is distributed in the hope that it will be useful, but 149fa25171SDennis Dalessandro * WITHOUT ANY WARRANTY; without even the implied warranty of 159fa25171SDennis Dalessandro * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 169fa25171SDennis Dalessandro * General Public License for more details. 179fa25171SDennis Dalessandro * 189fa25171SDennis Dalessandro * BSD LICENSE 199fa25171SDennis Dalessandro * 209fa25171SDennis Dalessandro * Redistribution and use in source and binary forms, with or without 219fa25171SDennis Dalessandro * modification, are permitted provided that the following conditions 229fa25171SDennis Dalessandro * are met: 239fa25171SDennis Dalessandro * 249fa25171SDennis Dalessandro * - Redistributions of source code must retain the above copyright 259fa25171SDennis Dalessandro * notice, this list of conditions and the following disclaimer. 269fa25171SDennis Dalessandro * - Redistributions in binary form must reproduce the above copyright 279fa25171SDennis Dalessandro * notice, this list of conditions and the following disclaimer in 289fa25171SDennis Dalessandro * the documentation and/or other materials provided with the 299fa25171SDennis Dalessandro * distribution. 309fa25171SDennis Dalessandro * - Neither the name of Intel Corporation nor the names of its 319fa25171SDennis Dalessandro * contributors may be used to endorse or promote products derived 329fa25171SDennis Dalessandro * from this software without specific prior written permission. 339fa25171SDennis Dalessandro * 349fa25171SDennis Dalessandro * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 359fa25171SDennis Dalessandro * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 369fa25171SDennis Dalessandro * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 379fa25171SDennis Dalessandro * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 389fa25171SDennis Dalessandro * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 399fa25171SDennis Dalessandro * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 409fa25171SDennis Dalessandro * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 419fa25171SDennis Dalessandro * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 429fa25171SDennis Dalessandro * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 439fa25171SDennis Dalessandro * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 449fa25171SDennis Dalessandro * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 459fa25171SDennis Dalessandro * 469fa25171SDennis Dalessandro */ 479fa25171SDennis Dalessandro 484e74080bSDennis Dalessandro #include <linux/slab.h> 494e74080bSDennis Dalessandro #include <linux/sched.h> 504e74080bSDennis Dalessandro #include <linux/rculist.h> 514e74080bSDennis Dalessandro #include <rdma/rdma_vt.h> 524e74080bSDennis Dalessandro #include <rdma/rdmavt_qp.h> 534e74080bSDennis Dalessandro 549fa25171SDennis Dalessandro #include "mcast.h" 559fa25171SDennis Dalessandro 564e74080bSDennis Dalessandro void rvt_driver_mcast_init(struct rvt_dev_info *rdi) 574e74080bSDennis Dalessandro { 584e74080bSDennis Dalessandro /* 594e74080bSDennis Dalessandro * Anything that needs setup for multicast on a per driver or per rdi 604e74080bSDennis Dalessandro * basis should be done in here. 614e74080bSDennis Dalessandro */ 624e74080bSDennis Dalessandro spin_lock_init(&rdi->n_mcast_grps_lock); 634e74080bSDennis Dalessandro } 644e74080bSDennis Dalessandro 654e74080bSDennis Dalessandro /** 664e74080bSDennis Dalessandro * mcast_qp_alloc - alloc a struct to link a QP to mcast GID struct 674e74080bSDennis Dalessandro * @qp: the QP to link 684e74080bSDennis Dalessandro */ 694e74080bSDennis Dalessandro static struct rvt_mcast_qp *rvt_mcast_qp_alloc(struct rvt_qp *qp) 704e74080bSDennis Dalessandro { 714e74080bSDennis Dalessandro struct rvt_mcast_qp *mqp; 724e74080bSDennis Dalessandro 734e74080bSDennis Dalessandro mqp = kmalloc(sizeof(*mqp), GFP_KERNEL); 744e74080bSDennis Dalessandro if (!mqp) 754e74080bSDennis Dalessandro goto bail; 764e74080bSDennis Dalessandro 774e74080bSDennis Dalessandro mqp->qp = qp; 784e74080bSDennis Dalessandro atomic_inc(&qp->refcount); 794e74080bSDennis Dalessandro 804e74080bSDennis Dalessandro bail: 814e74080bSDennis Dalessandro return mqp; 824e74080bSDennis Dalessandro } 834e74080bSDennis Dalessandro 844e74080bSDennis Dalessandro static void rvt_mcast_qp_free(struct rvt_mcast_qp *mqp) 854e74080bSDennis Dalessandro { 864e74080bSDennis Dalessandro struct rvt_qp *qp = mqp->qp; 874e74080bSDennis Dalessandro 884e74080bSDennis Dalessandro /* Notify hfi1_destroy_qp() if it is waiting. */ 894e74080bSDennis Dalessandro if (atomic_dec_and_test(&qp->refcount)) 904e74080bSDennis Dalessandro wake_up(&qp->wait); 914e74080bSDennis Dalessandro 924e74080bSDennis Dalessandro kfree(mqp); 934e74080bSDennis Dalessandro } 944e74080bSDennis Dalessandro 954e74080bSDennis Dalessandro /** 964e74080bSDennis Dalessandro * mcast_alloc - allocate the multicast GID structure 974e74080bSDennis Dalessandro * @mgid: the multicast GID 984e74080bSDennis Dalessandro * 994e74080bSDennis Dalessandro * A list of QPs will be attached to this structure. 1004e74080bSDennis Dalessandro */ 1014e74080bSDennis Dalessandro static struct rvt_mcast *rvt_mcast_alloc(union ib_gid *mgid) 1024e74080bSDennis Dalessandro { 1034e74080bSDennis Dalessandro struct rvt_mcast *mcast; 1044e74080bSDennis Dalessandro 1054e74080bSDennis Dalessandro mcast = kzalloc(sizeof(*mcast), GFP_KERNEL); 1064e74080bSDennis Dalessandro if (!mcast) 1074e74080bSDennis Dalessandro goto bail; 1084e74080bSDennis Dalessandro 1094e74080bSDennis Dalessandro mcast->mgid = *mgid; 1104e74080bSDennis Dalessandro INIT_LIST_HEAD(&mcast->qp_list); 1114e74080bSDennis Dalessandro init_waitqueue_head(&mcast->wait); 1124e74080bSDennis Dalessandro atomic_set(&mcast->refcount, 0); 1134e74080bSDennis Dalessandro 1144e74080bSDennis Dalessandro bail: 1154e74080bSDennis Dalessandro return mcast; 1164e74080bSDennis Dalessandro } 1174e74080bSDennis Dalessandro 1184e74080bSDennis Dalessandro static void rvt_mcast_free(struct rvt_mcast *mcast) 1194e74080bSDennis Dalessandro { 1204e74080bSDennis Dalessandro struct rvt_mcast_qp *p, *tmp; 1214e74080bSDennis Dalessandro 1224e74080bSDennis Dalessandro list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) 1234e74080bSDennis Dalessandro rvt_mcast_qp_free(p); 1244e74080bSDennis Dalessandro 1254e74080bSDennis Dalessandro kfree(mcast); 1264e74080bSDennis Dalessandro } 1274e74080bSDennis Dalessandro 1284e74080bSDennis Dalessandro /** 1294e74080bSDennis Dalessandro * rvt_mcast_find - search the global table for the given multicast GID 1304e74080bSDennis Dalessandro * @ibp: the IB port structure 1314e74080bSDennis Dalessandro * @mgid: the multicast GID to search for 1324e74080bSDennis Dalessandro * 1334e74080bSDennis Dalessandro * Returns NULL if not found. 1344e74080bSDennis Dalessandro * 1354e74080bSDennis Dalessandro * The caller is responsible for decrementing the reference count if found. 1364e74080bSDennis Dalessandro */ 1374e74080bSDennis Dalessandro struct rvt_mcast *rvt_mcast_find(struct rvt_ibport *ibp, union ib_gid *mgid) 1384e74080bSDennis Dalessandro { 1394e74080bSDennis Dalessandro struct rb_node *n; 1404e74080bSDennis Dalessandro unsigned long flags; 1414e74080bSDennis Dalessandro struct rvt_mcast *found = NULL; 1424e74080bSDennis Dalessandro 1434e74080bSDennis Dalessandro spin_lock_irqsave(&ibp->lock, flags); 1444e74080bSDennis Dalessandro n = ibp->mcast_tree.rb_node; 1454e74080bSDennis Dalessandro while (n) { 1464e74080bSDennis Dalessandro int ret; 1474e74080bSDennis Dalessandro struct rvt_mcast *mcast; 1484e74080bSDennis Dalessandro 1494e74080bSDennis Dalessandro mcast = rb_entry(n, struct rvt_mcast, rb_node); 1504e74080bSDennis Dalessandro 1514e74080bSDennis Dalessandro ret = memcmp(mgid->raw, mcast->mgid.raw, 1524e74080bSDennis Dalessandro sizeof(union ib_gid)); 1534e74080bSDennis Dalessandro if (ret < 0) { 1544e74080bSDennis Dalessandro n = n->rb_left; 1554e74080bSDennis Dalessandro } else if (ret > 0) { 1564e74080bSDennis Dalessandro n = n->rb_right; 1574e74080bSDennis Dalessandro } else { 1584e74080bSDennis Dalessandro atomic_inc(&mcast->refcount); 1594e74080bSDennis Dalessandro found = mcast; 1604e74080bSDennis Dalessandro break; 1614e74080bSDennis Dalessandro } 1624e74080bSDennis Dalessandro } 1634e74080bSDennis Dalessandro spin_unlock_irqrestore(&ibp->lock, flags); 1644e74080bSDennis Dalessandro return found; 1654e74080bSDennis Dalessandro } 1664e74080bSDennis Dalessandro EXPORT_SYMBOL(rvt_mcast_find); 1674e74080bSDennis Dalessandro 1684e74080bSDennis Dalessandro /** 1694e74080bSDennis Dalessandro * mcast_add - insert mcast GID into table and attach QP struct 1704e74080bSDennis Dalessandro * @mcast: the mcast GID table 1714e74080bSDennis Dalessandro * @mqp: the QP to attach 1724e74080bSDennis Dalessandro * 1734e74080bSDennis Dalessandro * Return zero if both were added. Return EEXIST if the GID was already in 1744e74080bSDennis Dalessandro * the table but the QP was added. Return ESRCH if the QP was already 1754e74080bSDennis Dalessandro * attached and neither structure was added. 1764e74080bSDennis Dalessandro */ 1774e74080bSDennis Dalessandro static int rvt_mcast_add(struct rvt_dev_info *rdi, struct rvt_ibport *ibp, 1784e74080bSDennis Dalessandro struct rvt_mcast *mcast, struct rvt_mcast_qp *mqp) 1794e74080bSDennis Dalessandro { 1804e74080bSDennis Dalessandro struct rb_node **n = &ibp->mcast_tree.rb_node; 1814e74080bSDennis Dalessandro struct rb_node *pn = NULL; 1824e74080bSDennis Dalessandro int ret; 1834e74080bSDennis Dalessandro 1844e74080bSDennis Dalessandro spin_lock_irq(&ibp->lock); 1854e74080bSDennis Dalessandro 1864e74080bSDennis Dalessandro while (*n) { 1874e74080bSDennis Dalessandro struct rvt_mcast *tmcast; 1884e74080bSDennis Dalessandro struct rvt_mcast_qp *p; 1894e74080bSDennis Dalessandro 1904e74080bSDennis Dalessandro pn = *n; 1914e74080bSDennis Dalessandro tmcast = rb_entry(pn, struct rvt_mcast, rb_node); 1924e74080bSDennis Dalessandro 1934e74080bSDennis Dalessandro ret = memcmp(mcast->mgid.raw, tmcast->mgid.raw, 1944e74080bSDennis Dalessandro sizeof(union ib_gid)); 1954e74080bSDennis Dalessandro if (ret < 0) { 1964e74080bSDennis Dalessandro n = &pn->rb_left; 1974e74080bSDennis Dalessandro continue; 1984e74080bSDennis Dalessandro } 1994e74080bSDennis Dalessandro if (ret > 0) { 2004e74080bSDennis Dalessandro n = &pn->rb_right; 2014e74080bSDennis Dalessandro continue; 2024e74080bSDennis Dalessandro } 2034e74080bSDennis Dalessandro 2044e74080bSDennis Dalessandro /* Search the QP list to see if this is already there. */ 2054e74080bSDennis Dalessandro list_for_each_entry_rcu(p, &tmcast->qp_list, list) { 2064e74080bSDennis Dalessandro if (p->qp == mqp->qp) { 2074e74080bSDennis Dalessandro ret = ESRCH; 2084e74080bSDennis Dalessandro goto bail; 2094e74080bSDennis Dalessandro } 2104e74080bSDennis Dalessandro } 2114e74080bSDennis Dalessandro if (tmcast->n_attached == 2124e74080bSDennis Dalessandro rdi->dparms.props.max_mcast_qp_attach) { 2134e74080bSDennis Dalessandro ret = ENOMEM; 2144e74080bSDennis Dalessandro goto bail; 2154e74080bSDennis Dalessandro } 2164e74080bSDennis Dalessandro 2174e74080bSDennis Dalessandro tmcast->n_attached++; 2184e74080bSDennis Dalessandro 2194e74080bSDennis Dalessandro list_add_tail_rcu(&mqp->list, &tmcast->qp_list); 2204e74080bSDennis Dalessandro ret = EEXIST; 2214e74080bSDennis Dalessandro goto bail; 2224e74080bSDennis Dalessandro } 2234e74080bSDennis Dalessandro 2244e74080bSDennis Dalessandro spin_lock(&rdi->n_mcast_grps_lock); 2254e74080bSDennis Dalessandro if (rdi->n_mcast_grps_allocated == rdi->dparms.props.max_mcast_grp) { 2264e74080bSDennis Dalessandro spin_unlock(&rdi->n_mcast_grps_lock); 2274e74080bSDennis Dalessandro ret = ENOMEM; 2284e74080bSDennis Dalessandro goto bail; 2294e74080bSDennis Dalessandro } 2304e74080bSDennis Dalessandro 2314e74080bSDennis Dalessandro rdi->n_mcast_grps_allocated++; 2324e74080bSDennis Dalessandro spin_unlock(&rdi->n_mcast_grps_lock); 2334e74080bSDennis Dalessandro 2344e74080bSDennis Dalessandro mcast->n_attached++; 2354e74080bSDennis Dalessandro 2364e74080bSDennis Dalessandro list_add_tail_rcu(&mqp->list, &mcast->qp_list); 2374e74080bSDennis Dalessandro 2384e74080bSDennis Dalessandro atomic_inc(&mcast->refcount); 2394e74080bSDennis Dalessandro rb_link_node(&mcast->rb_node, pn, n); 2404e74080bSDennis Dalessandro rb_insert_color(&mcast->rb_node, &ibp->mcast_tree); 2414e74080bSDennis Dalessandro 2424e74080bSDennis Dalessandro ret = 0; 2434e74080bSDennis Dalessandro 2444e74080bSDennis Dalessandro bail: 2454e74080bSDennis Dalessandro spin_unlock_irq(&ibp->lock); 2464e74080bSDennis Dalessandro 2474e74080bSDennis Dalessandro return ret; 2484e74080bSDennis Dalessandro } 2494e74080bSDennis Dalessandro 2509fa25171SDennis Dalessandro int rvt_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 2519fa25171SDennis Dalessandro { 2524e74080bSDennis Dalessandro struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 2534e74080bSDennis Dalessandro struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 2544e74080bSDennis Dalessandro struct rvt_ibport *ibp = rdi->ports[qp->port_num - 1]; 2554e74080bSDennis Dalessandro struct rvt_mcast *mcast; 2564e74080bSDennis Dalessandro struct rvt_mcast_qp *mqp; 2574e74080bSDennis Dalessandro int ret = -ENOMEM; 2584e74080bSDennis Dalessandro 2594e74080bSDennis Dalessandro if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) 2604e74080bSDennis Dalessandro return -EINVAL; 2614e74080bSDennis Dalessandro 2624e74080bSDennis Dalessandro /* 2634e74080bSDennis Dalessandro * Allocate data structures since its better to do this outside of 2644e74080bSDennis Dalessandro * spin locks and it will most likely be needed. 2654e74080bSDennis Dalessandro */ 2664e74080bSDennis Dalessandro mcast = rvt_mcast_alloc(gid); 2674e74080bSDennis Dalessandro if (!mcast) 2684e74080bSDennis Dalessandro return -ENOMEM; 2694e74080bSDennis Dalessandro 2704e74080bSDennis Dalessandro mqp = rvt_mcast_qp_alloc(qp); 2714e74080bSDennis Dalessandro if (!mqp) 2724e74080bSDennis Dalessandro goto bail_mcast; 2734e74080bSDennis Dalessandro 2744e74080bSDennis Dalessandro switch (rvt_mcast_add(rdi, ibp, mcast, mqp)) { 2754e74080bSDennis Dalessandro case ESRCH: 2764e74080bSDennis Dalessandro /* Neither was used: OK to attach the same QP twice. */ 2774e74080bSDennis Dalessandro ret = 0; 2784e74080bSDennis Dalessandro goto bail_mqp; 2794e74080bSDennis Dalessandro case EEXIST: /* The mcast wasn't used */ 2804e74080bSDennis Dalessandro ret = 0; 2814e74080bSDennis Dalessandro goto bail_mcast; 2824e74080bSDennis Dalessandro case ENOMEM: 2834e74080bSDennis Dalessandro /* Exceeded the maximum number of mcast groups. */ 2844e74080bSDennis Dalessandro ret = -ENOMEM; 2854e74080bSDennis Dalessandro goto bail_mqp; 2864e74080bSDennis Dalessandro default: 2874e74080bSDennis Dalessandro break; 2884e74080bSDennis Dalessandro } 2894e74080bSDennis Dalessandro 2904e74080bSDennis Dalessandro return 0; 2914e74080bSDennis Dalessandro 2924e74080bSDennis Dalessandro bail_mqp: 2934e74080bSDennis Dalessandro rvt_mcast_qp_free(mqp); 2944e74080bSDennis Dalessandro 2954e74080bSDennis Dalessandro bail_mcast: 2964e74080bSDennis Dalessandro rvt_mcast_free(mcast); 2974e74080bSDennis Dalessandro 2984e74080bSDennis Dalessandro return ret; 2999fa25171SDennis Dalessandro } 3009fa25171SDennis Dalessandro 3019fa25171SDennis Dalessandro int rvt_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 3029fa25171SDennis Dalessandro { 3034e74080bSDennis Dalessandro struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 3044e74080bSDennis Dalessandro struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 3054e74080bSDennis Dalessandro struct rvt_ibport *ibp = rdi->ports[qp->port_num - 1]; 3064e74080bSDennis Dalessandro struct rvt_mcast *mcast = NULL; 3074e74080bSDennis Dalessandro struct rvt_mcast_qp *p, *tmp, *delp = NULL; 3084e74080bSDennis Dalessandro struct rb_node *n; 3094e74080bSDennis Dalessandro int last = 0; 3104e74080bSDennis Dalessandro int ret = 0; 3114e74080bSDennis Dalessandro 3124e74080bSDennis Dalessandro if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) 3134e74080bSDennis Dalessandro return -EINVAL; 3144e74080bSDennis Dalessandro 3154e74080bSDennis Dalessandro spin_lock_irq(&ibp->lock); 3164e74080bSDennis Dalessandro 3174e74080bSDennis Dalessandro /* Find the GID in the mcast table. */ 3184e74080bSDennis Dalessandro n = ibp->mcast_tree.rb_node; 3194e74080bSDennis Dalessandro while (1) { 3204e74080bSDennis Dalessandro if (!n) { 3214e74080bSDennis Dalessandro spin_unlock_irq(&ibp->lock); 3224e74080bSDennis Dalessandro return -EINVAL; 3234e74080bSDennis Dalessandro } 3244e74080bSDennis Dalessandro 3254e74080bSDennis Dalessandro mcast = rb_entry(n, struct rvt_mcast, rb_node); 3264e74080bSDennis Dalessandro ret = memcmp(gid->raw, mcast->mgid.raw, 3274e74080bSDennis Dalessandro sizeof(union ib_gid)); 3284e74080bSDennis Dalessandro if (ret < 0) 3294e74080bSDennis Dalessandro n = n->rb_left; 3304e74080bSDennis Dalessandro else if (ret > 0) 3314e74080bSDennis Dalessandro n = n->rb_right; 3324e74080bSDennis Dalessandro else 3334e74080bSDennis Dalessandro break; 3344e74080bSDennis Dalessandro } 3354e74080bSDennis Dalessandro 3364e74080bSDennis Dalessandro /* Search the QP list. */ 3374e74080bSDennis Dalessandro list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) { 3384e74080bSDennis Dalessandro if (p->qp != qp) 3394e74080bSDennis Dalessandro continue; 3404e74080bSDennis Dalessandro /* 3414e74080bSDennis Dalessandro * We found it, so remove it, but don't poison the forward 3424e74080bSDennis Dalessandro * link until we are sure there are no list walkers. 3434e74080bSDennis Dalessandro */ 3444e74080bSDennis Dalessandro list_del_rcu(&p->list); 3454e74080bSDennis Dalessandro mcast->n_attached--; 3464e74080bSDennis Dalessandro delp = p; 3474e74080bSDennis Dalessandro 3484e74080bSDennis Dalessandro /* If this was the last attached QP, remove the GID too. */ 3494e74080bSDennis Dalessandro if (list_empty(&mcast->qp_list)) { 3504e74080bSDennis Dalessandro rb_erase(&mcast->rb_node, &ibp->mcast_tree); 3514e74080bSDennis Dalessandro last = 1; 3524e74080bSDennis Dalessandro } 3534e74080bSDennis Dalessandro break; 3544e74080bSDennis Dalessandro } 3554e74080bSDennis Dalessandro 3564e74080bSDennis Dalessandro spin_unlock_irq(&ibp->lock); 3574e74080bSDennis Dalessandro /* QP not attached */ 3584e74080bSDennis Dalessandro if (!delp) 3594e74080bSDennis Dalessandro return -EINVAL; 3604e74080bSDennis Dalessandro 3614e74080bSDennis Dalessandro /* 3624e74080bSDennis Dalessandro * Wait for any list walkers to finish before freeing the 3634e74080bSDennis Dalessandro * list element. 3644e74080bSDennis Dalessandro */ 3654e74080bSDennis Dalessandro wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1); 3664e74080bSDennis Dalessandro rvt_mcast_qp_free(delp); 3674e74080bSDennis Dalessandro 3684e74080bSDennis Dalessandro if (last) { 3694e74080bSDennis Dalessandro atomic_dec(&mcast->refcount); 3704e74080bSDennis Dalessandro wait_event(mcast->wait, !atomic_read(&mcast->refcount)); 3714e74080bSDennis Dalessandro rvt_mcast_free(mcast); 3724e74080bSDennis Dalessandro spin_lock_irq(&rdi->n_mcast_grps_lock); 3734e74080bSDennis Dalessandro rdi->n_mcast_grps_allocated--; 3744e74080bSDennis Dalessandro spin_unlock_irq(&rdi->n_mcast_grps_lock); 3754e74080bSDennis Dalessandro } 3764e74080bSDennis Dalessandro 3774e74080bSDennis Dalessandro return 0; 3784e74080bSDennis Dalessandro } 3794e74080bSDennis Dalessandro 3804e74080bSDennis Dalessandro int rvt_mcast_tree_empty(struct rvt_dev_info *rdi) 3814e74080bSDennis Dalessandro { 3824e74080bSDennis Dalessandro int i; 3834e74080bSDennis Dalessandro int in_use = 0; 3844e74080bSDennis Dalessandro 3854e74080bSDennis Dalessandro for (i = 0; i < rdi->dparms.nports; i++) 3864e74080bSDennis Dalessandro if (rdi->ports[i]->mcast_tree.rb_node) 3874e74080bSDennis Dalessandro in_use++; 3884e74080bSDennis Dalessandro return in_use; 3899fa25171SDennis Dalessandro } 390