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 5690793f71SDennis Dalessandro /** 57*2988ca08SMauro Carvalho Chehab * rvt_driver_mcast_init - init resources for multicast 5890793f71SDennis Dalessandro * @rdi: rvt dev struct 5990793f71SDennis Dalessandro * 6090793f71SDennis Dalessandro * This is per device that registers with rdmavt 6190793f71SDennis Dalessandro */ 624e74080bSDennis Dalessandro void rvt_driver_mcast_init(struct rvt_dev_info *rdi) 634e74080bSDennis Dalessandro { 644e74080bSDennis Dalessandro /* 654e74080bSDennis Dalessandro * Anything that needs setup for multicast on a per driver or per rdi 664e74080bSDennis Dalessandro * basis should be done in here. 674e74080bSDennis Dalessandro */ 684e74080bSDennis Dalessandro spin_lock_init(&rdi->n_mcast_grps_lock); 694e74080bSDennis Dalessandro } 704e74080bSDennis Dalessandro 714e74080bSDennis Dalessandro /** 72*2988ca08SMauro Carvalho Chehab * rvt_mcast_qp_alloc - alloc a struct to link a QP to mcast GID struct 734e74080bSDennis Dalessandro * @qp: the QP to link 744e74080bSDennis Dalessandro */ 754e74080bSDennis Dalessandro static struct rvt_mcast_qp *rvt_mcast_qp_alloc(struct rvt_qp *qp) 764e74080bSDennis Dalessandro { 774e74080bSDennis Dalessandro struct rvt_mcast_qp *mqp; 784e74080bSDennis Dalessandro 794e74080bSDennis Dalessandro mqp = kmalloc(sizeof(*mqp), GFP_KERNEL); 804e74080bSDennis Dalessandro if (!mqp) 814e74080bSDennis Dalessandro goto bail; 824e74080bSDennis Dalessandro 834e74080bSDennis Dalessandro mqp->qp = qp; 84b44980f8SSebastian Sanchez rvt_get_qp(qp); 854e74080bSDennis Dalessandro 864e74080bSDennis Dalessandro bail: 874e74080bSDennis Dalessandro return mqp; 884e74080bSDennis Dalessandro } 894e74080bSDennis Dalessandro 904e74080bSDennis Dalessandro static void rvt_mcast_qp_free(struct rvt_mcast_qp *mqp) 914e74080bSDennis Dalessandro { 924e74080bSDennis Dalessandro struct rvt_qp *qp = mqp->qp; 934e74080bSDennis Dalessandro 944e74080bSDennis Dalessandro /* Notify hfi1_destroy_qp() if it is waiting. */ 95b44980f8SSebastian Sanchez rvt_put_qp(qp); 964e74080bSDennis Dalessandro 974e74080bSDennis Dalessandro kfree(mqp); 984e74080bSDennis Dalessandro } 994e74080bSDennis Dalessandro 1004e74080bSDennis Dalessandro /** 101*2988ca08SMauro Carvalho Chehab * rvt_mcast_alloc - allocate the multicast GID structure 1024e74080bSDennis Dalessandro * @mgid: the multicast GID 103aad9ff97SMichael J. Ruhl * @lid: the muilticast LID (host order) 1044e74080bSDennis Dalessandro * 1054e74080bSDennis Dalessandro * A list of QPs will be attached to this structure. 1064e74080bSDennis Dalessandro */ 107aad9ff97SMichael J. Ruhl static struct rvt_mcast *rvt_mcast_alloc(union ib_gid *mgid, u16 lid) 1084e74080bSDennis Dalessandro { 1094e74080bSDennis Dalessandro struct rvt_mcast *mcast; 1104e74080bSDennis Dalessandro 1114e74080bSDennis Dalessandro mcast = kzalloc(sizeof(*mcast), GFP_KERNEL); 1124e74080bSDennis Dalessandro if (!mcast) 1134e74080bSDennis Dalessandro goto bail; 1144e74080bSDennis Dalessandro 115aad9ff97SMichael J. Ruhl mcast->mcast_addr.mgid = *mgid; 116aad9ff97SMichael J. Ruhl mcast->mcast_addr.lid = lid; 117aad9ff97SMichael J. Ruhl 1184e74080bSDennis Dalessandro INIT_LIST_HEAD(&mcast->qp_list); 1194e74080bSDennis Dalessandro init_waitqueue_head(&mcast->wait); 1204e74080bSDennis Dalessandro atomic_set(&mcast->refcount, 0); 1214e74080bSDennis Dalessandro 1224e74080bSDennis Dalessandro bail: 1234e74080bSDennis Dalessandro return mcast; 1244e74080bSDennis Dalessandro } 1254e74080bSDennis Dalessandro 1264e74080bSDennis Dalessandro static void rvt_mcast_free(struct rvt_mcast *mcast) 1274e74080bSDennis Dalessandro { 1284e74080bSDennis Dalessandro struct rvt_mcast_qp *p, *tmp; 1294e74080bSDennis Dalessandro 1304e74080bSDennis Dalessandro list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) 1314e74080bSDennis Dalessandro rvt_mcast_qp_free(p); 1324e74080bSDennis Dalessandro 1334e74080bSDennis Dalessandro kfree(mcast); 1344e74080bSDennis Dalessandro } 1354e74080bSDennis Dalessandro 1364e74080bSDennis Dalessandro /** 137aad9ff97SMichael J. Ruhl * rvt_mcast_find - search the global table for the given multicast GID/LID 138aad9ff97SMichael J. Ruhl * NOTE: It is valid to have 1 MLID with multiple MGIDs. It is not valid 139aad9ff97SMichael J. Ruhl * to have 1 MGID with multiple MLIDs. 1404e74080bSDennis Dalessandro * @ibp: the IB port structure 1414e74080bSDennis Dalessandro * @mgid: the multicast GID to search for 142aad9ff97SMichael J. Ruhl * @lid: the multicast LID portion of the multicast address (host order) 1434e74080bSDennis Dalessandro * 1444e74080bSDennis Dalessandro * The caller is responsible for decrementing the reference count if found. 14590793f71SDennis Dalessandro * 14690793f71SDennis Dalessandro * Return: NULL if not found. 1474e74080bSDennis Dalessandro */ 148aad9ff97SMichael J. Ruhl struct rvt_mcast *rvt_mcast_find(struct rvt_ibport *ibp, union ib_gid *mgid, 149aad9ff97SMichael J. Ruhl u16 lid) 1504e74080bSDennis Dalessandro { 1514e74080bSDennis Dalessandro struct rb_node *n; 1524e74080bSDennis Dalessandro unsigned long flags; 1534e74080bSDennis Dalessandro struct rvt_mcast *found = NULL; 1544e74080bSDennis Dalessandro 1554e74080bSDennis Dalessandro spin_lock_irqsave(&ibp->lock, flags); 1564e74080bSDennis Dalessandro n = ibp->mcast_tree.rb_node; 1574e74080bSDennis Dalessandro while (n) { 1584e74080bSDennis Dalessandro int ret; 1594e74080bSDennis Dalessandro struct rvt_mcast *mcast; 1604e74080bSDennis Dalessandro 1614e74080bSDennis Dalessandro mcast = rb_entry(n, struct rvt_mcast, rb_node); 1624e74080bSDennis Dalessandro 163aad9ff97SMichael J. Ruhl ret = memcmp(mgid->raw, mcast->mcast_addr.mgid.raw, 164aad9ff97SMichael J. Ruhl sizeof(*mgid)); 1654e74080bSDennis Dalessandro if (ret < 0) { 1664e74080bSDennis Dalessandro n = n->rb_left; 1674e74080bSDennis Dalessandro } else if (ret > 0) { 1684e74080bSDennis Dalessandro n = n->rb_right; 1694e74080bSDennis Dalessandro } else { 170aad9ff97SMichael J. Ruhl /* MGID/MLID must match */ 171aad9ff97SMichael J. Ruhl if (mcast->mcast_addr.lid == lid) { 1724e74080bSDennis Dalessandro atomic_inc(&mcast->refcount); 1734e74080bSDennis Dalessandro found = mcast; 174aad9ff97SMichael J. Ruhl } 1754e74080bSDennis Dalessandro break; 1764e74080bSDennis Dalessandro } 1774e74080bSDennis Dalessandro } 1784e74080bSDennis Dalessandro spin_unlock_irqrestore(&ibp->lock, flags); 1794e74080bSDennis Dalessandro return found; 1804e74080bSDennis Dalessandro } 1814e74080bSDennis Dalessandro EXPORT_SYMBOL(rvt_mcast_find); 1824e74080bSDennis Dalessandro 1834e74080bSDennis Dalessandro /** 184*2988ca08SMauro Carvalho Chehab * rvt_mcast_add - insert mcast GID into table and attach QP struct 1854e74080bSDennis Dalessandro * @mcast: the mcast GID table 1864e74080bSDennis Dalessandro * @mqp: the QP to attach 1874e74080bSDennis Dalessandro * 18890793f71SDennis Dalessandro * Return: zero if both were added. Return EEXIST if the GID was already in 1894e74080bSDennis Dalessandro * the table but the QP was added. Return ESRCH if the QP was already 190aad9ff97SMichael J. Ruhl * attached and neither structure was added. Return EINVAL if the MGID was 191aad9ff97SMichael J. Ruhl * found, but the MLID did NOT match. 1924e74080bSDennis Dalessandro */ 1934e74080bSDennis Dalessandro static int rvt_mcast_add(struct rvt_dev_info *rdi, struct rvt_ibport *ibp, 1944e74080bSDennis Dalessandro struct rvt_mcast *mcast, struct rvt_mcast_qp *mqp) 1954e74080bSDennis Dalessandro { 1964e74080bSDennis Dalessandro struct rb_node **n = &ibp->mcast_tree.rb_node; 1974e74080bSDennis Dalessandro struct rb_node *pn = NULL; 1984e74080bSDennis Dalessandro int ret; 1994e74080bSDennis Dalessandro 2004e74080bSDennis Dalessandro spin_lock_irq(&ibp->lock); 2014e74080bSDennis Dalessandro 2024e74080bSDennis Dalessandro while (*n) { 2034e74080bSDennis Dalessandro struct rvt_mcast *tmcast; 2044e74080bSDennis Dalessandro struct rvt_mcast_qp *p; 2054e74080bSDennis Dalessandro 2064e74080bSDennis Dalessandro pn = *n; 2074e74080bSDennis Dalessandro tmcast = rb_entry(pn, struct rvt_mcast, rb_node); 2084e74080bSDennis Dalessandro 209aad9ff97SMichael J. Ruhl ret = memcmp(mcast->mcast_addr.mgid.raw, 210aad9ff97SMichael J. Ruhl tmcast->mcast_addr.mgid.raw, 211aad9ff97SMichael J. Ruhl sizeof(mcast->mcast_addr.mgid)); 2124e74080bSDennis Dalessandro if (ret < 0) { 2134e74080bSDennis Dalessandro n = &pn->rb_left; 2144e74080bSDennis Dalessandro continue; 2154e74080bSDennis Dalessandro } 2164e74080bSDennis Dalessandro if (ret > 0) { 2174e74080bSDennis Dalessandro n = &pn->rb_right; 2184e74080bSDennis Dalessandro continue; 2194e74080bSDennis Dalessandro } 2204e74080bSDennis Dalessandro 221aad9ff97SMichael J. Ruhl if (tmcast->mcast_addr.lid != mcast->mcast_addr.lid) { 222aad9ff97SMichael J. Ruhl ret = EINVAL; 223aad9ff97SMichael J. Ruhl goto bail; 224aad9ff97SMichael J. Ruhl } 225aad9ff97SMichael J. Ruhl 2264e74080bSDennis Dalessandro /* Search the QP list to see if this is already there. */ 2274e74080bSDennis Dalessandro list_for_each_entry_rcu(p, &tmcast->qp_list, list) { 2284e74080bSDennis Dalessandro if (p->qp == mqp->qp) { 2294e74080bSDennis Dalessandro ret = ESRCH; 2304e74080bSDennis Dalessandro goto bail; 2314e74080bSDennis Dalessandro } 2324e74080bSDennis Dalessandro } 2334e74080bSDennis Dalessandro if (tmcast->n_attached == 2344e74080bSDennis Dalessandro rdi->dparms.props.max_mcast_qp_attach) { 2354e74080bSDennis Dalessandro ret = ENOMEM; 2364e74080bSDennis Dalessandro goto bail; 2374e74080bSDennis Dalessandro } 2384e74080bSDennis Dalessandro 2394e74080bSDennis Dalessandro tmcast->n_attached++; 2404e74080bSDennis Dalessandro 2414e74080bSDennis Dalessandro list_add_tail_rcu(&mqp->list, &tmcast->qp_list); 2424e74080bSDennis Dalessandro ret = EEXIST; 2434e74080bSDennis Dalessandro goto bail; 2444e74080bSDennis Dalessandro } 2454e74080bSDennis Dalessandro 2464e74080bSDennis Dalessandro spin_lock(&rdi->n_mcast_grps_lock); 2474e74080bSDennis Dalessandro if (rdi->n_mcast_grps_allocated == rdi->dparms.props.max_mcast_grp) { 2484e74080bSDennis Dalessandro spin_unlock(&rdi->n_mcast_grps_lock); 2494e74080bSDennis Dalessandro ret = ENOMEM; 2504e74080bSDennis Dalessandro goto bail; 2514e74080bSDennis Dalessandro } 2524e74080bSDennis Dalessandro 2534e74080bSDennis Dalessandro rdi->n_mcast_grps_allocated++; 2544e74080bSDennis Dalessandro spin_unlock(&rdi->n_mcast_grps_lock); 2554e74080bSDennis Dalessandro 2564e74080bSDennis Dalessandro mcast->n_attached++; 2574e74080bSDennis Dalessandro 2584e74080bSDennis Dalessandro list_add_tail_rcu(&mqp->list, &mcast->qp_list); 2594e74080bSDennis Dalessandro 2604e74080bSDennis Dalessandro atomic_inc(&mcast->refcount); 2614e74080bSDennis Dalessandro rb_link_node(&mcast->rb_node, pn, n); 2624e74080bSDennis Dalessandro rb_insert_color(&mcast->rb_node, &ibp->mcast_tree); 2634e74080bSDennis Dalessandro 2644e74080bSDennis Dalessandro ret = 0; 2654e74080bSDennis Dalessandro 2664e74080bSDennis Dalessandro bail: 2674e74080bSDennis Dalessandro spin_unlock_irq(&ibp->lock); 2684e74080bSDennis Dalessandro 2694e74080bSDennis Dalessandro return ret; 2704e74080bSDennis Dalessandro } 2714e74080bSDennis Dalessandro 27290793f71SDennis Dalessandro /** 27390793f71SDennis Dalessandro * rvt_attach_mcast - attach a qp to a multicast group 27490793f71SDennis Dalessandro * @ibqp: Infiniband qp 2754f9a3018SRandy Dunlap * @gid: multicast guid 27690793f71SDennis Dalessandro * @lid: multicast lid 27790793f71SDennis Dalessandro * 27890793f71SDennis Dalessandro * Return: 0 on success 27990793f71SDennis Dalessandro */ 2809fa25171SDennis Dalessandro int rvt_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 2819fa25171SDennis Dalessandro { 2824e74080bSDennis Dalessandro struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 2834e74080bSDennis Dalessandro struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 2844e74080bSDennis Dalessandro struct rvt_ibport *ibp = rdi->ports[qp->port_num - 1]; 2854e74080bSDennis Dalessandro struct rvt_mcast *mcast; 2864e74080bSDennis Dalessandro struct rvt_mcast_qp *mqp; 2874e74080bSDennis Dalessandro int ret = -ENOMEM; 2884e74080bSDennis Dalessandro 2894e74080bSDennis Dalessandro if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) 2904e74080bSDennis Dalessandro return -EINVAL; 2914e74080bSDennis Dalessandro 2924e74080bSDennis Dalessandro /* 2934e74080bSDennis Dalessandro * Allocate data structures since its better to do this outside of 2944e74080bSDennis Dalessandro * spin locks and it will most likely be needed. 2954e74080bSDennis Dalessandro */ 296aad9ff97SMichael J. Ruhl mcast = rvt_mcast_alloc(gid, lid); 2974e74080bSDennis Dalessandro if (!mcast) 2984e74080bSDennis Dalessandro return -ENOMEM; 2994e74080bSDennis Dalessandro 3004e74080bSDennis Dalessandro mqp = rvt_mcast_qp_alloc(qp); 3014e74080bSDennis Dalessandro if (!mqp) 3024e74080bSDennis Dalessandro goto bail_mcast; 3034e74080bSDennis Dalessandro 3044e74080bSDennis Dalessandro switch (rvt_mcast_add(rdi, ibp, mcast, mqp)) { 3054e74080bSDennis Dalessandro case ESRCH: 3064e74080bSDennis Dalessandro /* Neither was used: OK to attach the same QP twice. */ 3074e74080bSDennis Dalessandro ret = 0; 3084e74080bSDennis Dalessandro goto bail_mqp; 3094e74080bSDennis Dalessandro case EEXIST: /* The mcast wasn't used */ 3104e74080bSDennis Dalessandro ret = 0; 3114e74080bSDennis Dalessandro goto bail_mcast; 3124e74080bSDennis Dalessandro case ENOMEM: 3134e74080bSDennis Dalessandro /* Exceeded the maximum number of mcast groups. */ 3144e74080bSDennis Dalessandro ret = -ENOMEM; 3154e74080bSDennis Dalessandro goto bail_mqp; 316aad9ff97SMichael J. Ruhl case EINVAL: 317aad9ff97SMichael J. Ruhl /* Invalid MGID/MLID pair */ 318aad9ff97SMichael J. Ruhl ret = -EINVAL; 319aad9ff97SMichael J. Ruhl goto bail_mqp; 3204e74080bSDennis Dalessandro default: 3214e74080bSDennis Dalessandro break; 3224e74080bSDennis Dalessandro } 3234e74080bSDennis Dalessandro 3244e74080bSDennis Dalessandro return 0; 3254e74080bSDennis Dalessandro 3264e74080bSDennis Dalessandro bail_mqp: 3274e74080bSDennis Dalessandro rvt_mcast_qp_free(mqp); 3284e74080bSDennis Dalessandro 3294e74080bSDennis Dalessandro bail_mcast: 3304e74080bSDennis Dalessandro rvt_mcast_free(mcast); 3314e74080bSDennis Dalessandro 3324e74080bSDennis Dalessandro return ret; 3339fa25171SDennis Dalessandro } 3349fa25171SDennis Dalessandro 33590793f71SDennis Dalessandro /** 33690793f71SDennis Dalessandro * rvt_detach_mcast - remove a qp from a multicast group 33790793f71SDennis Dalessandro * @ibqp: Infiniband qp 3384f9a3018SRandy Dunlap * @gid: multicast guid 33990793f71SDennis Dalessandro * @lid: multicast lid 34090793f71SDennis Dalessandro * 34190793f71SDennis Dalessandro * Return: 0 on success 34290793f71SDennis Dalessandro */ 3439fa25171SDennis Dalessandro int rvt_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 3449fa25171SDennis Dalessandro { 3454e74080bSDennis Dalessandro struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 3464e74080bSDennis Dalessandro struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 3474e74080bSDennis Dalessandro struct rvt_ibport *ibp = rdi->ports[qp->port_num - 1]; 3484e74080bSDennis Dalessandro struct rvt_mcast *mcast = NULL; 3494e74080bSDennis Dalessandro struct rvt_mcast_qp *p, *tmp, *delp = NULL; 3504e74080bSDennis Dalessandro struct rb_node *n; 3514e74080bSDennis Dalessandro int last = 0; 3524e74080bSDennis Dalessandro int ret = 0; 3534e74080bSDennis Dalessandro 354f9586abfSAlex Estrin if (ibqp->qp_num <= 1) 3554e74080bSDennis Dalessandro return -EINVAL; 3564e74080bSDennis Dalessandro 3574e74080bSDennis Dalessandro spin_lock_irq(&ibp->lock); 3584e74080bSDennis Dalessandro 3594e74080bSDennis Dalessandro /* Find the GID in the mcast table. */ 3604e74080bSDennis Dalessandro n = ibp->mcast_tree.rb_node; 3614e74080bSDennis Dalessandro while (1) { 3624e74080bSDennis Dalessandro if (!n) { 3634e74080bSDennis Dalessandro spin_unlock_irq(&ibp->lock); 3644e74080bSDennis Dalessandro return -EINVAL; 3654e74080bSDennis Dalessandro } 3664e74080bSDennis Dalessandro 3674e74080bSDennis Dalessandro mcast = rb_entry(n, struct rvt_mcast, rb_node); 368aad9ff97SMichael J. Ruhl ret = memcmp(gid->raw, mcast->mcast_addr.mgid.raw, 369aad9ff97SMichael J. Ruhl sizeof(*gid)); 370aad9ff97SMichael J. Ruhl if (ret < 0) { 3714e74080bSDennis Dalessandro n = n->rb_left; 372aad9ff97SMichael J. Ruhl } else if (ret > 0) { 3734e74080bSDennis Dalessandro n = n->rb_right; 374aad9ff97SMichael J. Ruhl } else { 375aad9ff97SMichael J. Ruhl /* MGID/MLID must match */ 376aad9ff97SMichael J. Ruhl if (mcast->mcast_addr.lid != lid) { 377aad9ff97SMichael J. Ruhl spin_unlock_irq(&ibp->lock); 378aad9ff97SMichael J. Ruhl return -EINVAL; 379aad9ff97SMichael J. Ruhl } 3804e74080bSDennis Dalessandro break; 3814e74080bSDennis Dalessandro } 382aad9ff97SMichael J. Ruhl } 3834e74080bSDennis Dalessandro 3844e74080bSDennis Dalessandro /* Search the QP list. */ 3854e74080bSDennis Dalessandro list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) { 3864e74080bSDennis Dalessandro if (p->qp != qp) 3874e74080bSDennis Dalessandro continue; 3884e74080bSDennis Dalessandro /* 3894e74080bSDennis Dalessandro * We found it, so remove it, but don't poison the forward 3904e74080bSDennis Dalessandro * link until we are sure there are no list walkers. 3914e74080bSDennis Dalessandro */ 3924e74080bSDennis Dalessandro list_del_rcu(&p->list); 3934e74080bSDennis Dalessandro mcast->n_attached--; 3944e74080bSDennis Dalessandro delp = p; 3954e74080bSDennis Dalessandro 3964e74080bSDennis Dalessandro /* If this was the last attached QP, remove the GID too. */ 3974e74080bSDennis Dalessandro if (list_empty(&mcast->qp_list)) { 3984e74080bSDennis Dalessandro rb_erase(&mcast->rb_node, &ibp->mcast_tree); 3994e74080bSDennis Dalessandro last = 1; 4004e74080bSDennis Dalessandro } 4014e74080bSDennis Dalessandro break; 4024e74080bSDennis Dalessandro } 4034e74080bSDennis Dalessandro 4044e74080bSDennis Dalessandro spin_unlock_irq(&ibp->lock); 4054e74080bSDennis Dalessandro /* QP not attached */ 4064e74080bSDennis Dalessandro if (!delp) 4074e74080bSDennis Dalessandro return -EINVAL; 4084e74080bSDennis Dalessandro 4094e74080bSDennis Dalessandro /* 4104e74080bSDennis Dalessandro * Wait for any list walkers to finish before freeing the 4114e74080bSDennis Dalessandro * list element. 4124e74080bSDennis Dalessandro */ 4134e74080bSDennis Dalessandro wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1); 4144e74080bSDennis Dalessandro rvt_mcast_qp_free(delp); 4154e74080bSDennis Dalessandro 4164e74080bSDennis Dalessandro if (last) { 4174e74080bSDennis Dalessandro atomic_dec(&mcast->refcount); 4184e74080bSDennis Dalessandro wait_event(mcast->wait, !atomic_read(&mcast->refcount)); 4194e74080bSDennis Dalessandro rvt_mcast_free(mcast); 4204e74080bSDennis Dalessandro spin_lock_irq(&rdi->n_mcast_grps_lock); 4214e74080bSDennis Dalessandro rdi->n_mcast_grps_allocated--; 4224e74080bSDennis Dalessandro spin_unlock_irq(&rdi->n_mcast_grps_lock); 4234e74080bSDennis Dalessandro } 4244e74080bSDennis Dalessandro 4254e74080bSDennis Dalessandro return 0; 4264e74080bSDennis Dalessandro } 4274e74080bSDennis Dalessandro 42890793f71SDennis Dalessandro /** 429*2988ca08SMauro Carvalho Chehab * rvt_mcast_tree_empty - determine if any qps are attached to any mcast group 43090793f71SDennis Dalessandro * @rdi: rvt dev struct 43190793f71SDennis Dalessandro * 43290793f71SDennis Dalessandro * Return: in use count 43390793f71SDennis Dalessandro */ 4344e74080bSDennis Dalessandro int rvt_mcast_tree_empty(struct rvt_dev_info *rdi) 4354e74080bSDennis Dalessandro { 4364e74080bSDennis Dalessandro int i; 4374e74080bSDennis Dalessandro int in_use = 0; 4384e74080bSDennis Dalessandro 4394e74080bSDennis Dalessandro for (i = 0; i < rdi->dparms.nports; i++) 4404e74080bSDennis Dalessandro if (rdi->ports[i]->mcast_tree.rb_node) 4414e74080bSDennis Dalessandro in_use++; 4424e74080bSDennis Dalessandro return in_use; 4439fa25171SDennis Dalessandro } 444