1*d164bf64SCai Huoqing // SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
29fa25171SDennis Dalessandro /*
3fe314195SDennis Dalessandro * Copyright(c) 2016 Intel Corporation.
49fa25171SDennis Dalessandro */
59fa25171SDennis Dalessandro
64e74080bSDennis Dalessandro #include <linux/slab.h>
74e74080bSDennis Dalessandro #include <linux/sched.h>
84e74080bSDennis Dalessandro #include <linux/rculist.h>
94e74080bSDennis Dalessandro #include <rdma/rdma_vt.h>
104e74080bSDennis Dalessandro #include <rdma/rdmavt_qp.h>
114e74080bSDennis Dalessandro
129fa25171SDennis Dalessandro #include "mcast.h"
139fa25171SDennis Dalessandro
1490793f71SDennis Dalessandro /**
152988ca08SMauro Carvalho Chehab * rvt_driver_mcast_init - init resources for multicast
1690793f71SDennis Dalessandro * @rdi: rvt dev struct
1790793f71SDennis Dalessandro *
1890793f71SDennis Dalessandro * This is per device that registers with rdmavt
1990793f71SDennis Dalessandro */
rvt_driver_mcast_init(struct rvt_dev_info * rdi)204e74080bSDennis Dalessandro void rvt_driver_mcast_init(struct rvt_dev_info *rdi)
214e74080bSDennis Dalessandro {
224e74080bSDennis Dalessandro /*
234e74080bSDennis Dalessandro * Anything that needs setup for multicast on a per driver or per rdi
244e74080bSDennis Dalessandro * basis should be done in here.
254e74080bSDennis Dalessandro */
264e74080bSDennis Dalessandro spin_lock_init(&rdi->n_mcast_grps_lock);
274e74080bSDennis Dalessandro }
284e74080bSDennis Dalessandro
294e74080bSDennis Dalessandro /**
302988ca08SMauro Carvalho Chehab * rvt_mcast_qp_alloc - alloc a struct to link a QP to mcast GID struct
314e74080bSDennis Dalessandro * @qp: the QP to link
324e74080bSDennis Dalessandro */
rvt_mcast_qp_alloc(struct rvt_qp * qp)334e74080bSDennis Dalessandro static struct rvt_mcast_qp *rvt_mcast_qp_alloc(struct rvt_qp *qp)
344e74080bSDennis Dalessandro {
354e74080bSDennis Dalessandro struct rvt_mcast_qp *mqp;
364e74080bSDennis Dalessandro
374e74080bSDennis Dalessandro mqp = kmalloc(sizeof(*mqp), GFP_KERNEL);
384e74080bSDennis Dalessandro if (!mqp)
394e74080bSDennis Dalessandro goto bail;
404e74080bSDennis Dalessandro
414e74080bSDennis Dalessandro mqp->qp = qp;
42b44980f8SSebastian Sanchez rvt_get_qp(qp);
434e74080bSDennis Dalessandro
444e74080bSDennis Dalessandro bail:
454e74080bSDennis Dalessandro return mqp;
464e74080bSDennis Dalessandro }
474e74080bSDennis Dalessandro
rvt_mcast_qp_free(struct rvt_mcast_qp * mqp)484e74080bSDennis Dalessandro static void rvt_mcast_qp_free(struct rvt_mcast_qp *mqp)
494e74080bSDennis Dalessandro {
504e74080bSDennis Dalessandro struct rvt_qp *qp = mqp->qp;
514e74080bSDennis Dalessandro
524e74080bSDennis Dalessandro /* Notify hfi1_destroy_qp() if it is waiting. */
53b44980f8SSebastian Sanchez rvt_put_qp(qp);
544e74080bSDennis Dalessandro
554e74080bSDennis Dalessandro kfree(mqp);
564e74080bSDennis Dalessandro }
574e74080bSDennis Dalessandro
584e74080bSDennis Dalessandro /**
592988ca08SMauro Carvalho Chehab * rvt_mcast_alloc - allocate the multicast GID structure
604e74080bSDennis Dalessandro * @mgid: the multicast GID
61aad9ff97SMichael J. Ruhl * @lid: the muilticast LID (host order)
624e74080bSDennis Dalessandro *
634e74080bSDennis Dalessandro * A list of QPs will be attached to this structure.
644e74080bSDennis Dalessandro */
rvt_mcast_alloc(union ib_gid * mgid,u16 lid)65aad9ff97SMichael J. Ruhl static struct rvt_mcast *rvt_mcast_alloc(union ib_gid *mgid, u16 lid)
664e74080bSDennis Dalessandro {
674e74080bSDennis Dalessandro struct rvt_mcast *mcast;
684e74080bSDennis Dalessandro
694e74080bSDennis Dalessandro mcast = kzalloc(sizeof(*mcast), GFP_KERNEL);
704e74080bSDennis Dalessandro if (!mcast)
714e74080bSDennis Dalessandro goto bail;
724e74080bSDennis Dalessandro
73aad9ff97SMichael J. Ruhl mcast->mcast_addr.mgid = *mgid;
74aad9ff97SMichael J. Ruhl mcast->mcast_addr.lid = lid;
75aad9ff97SMichael J. Ruhl
764e74080bSDennis Dalessandro INIT_LIST_HEAD(&mcast->qp_list);
774e74080bSDennis Dalessandro init_waitqueue_head(&mcast->wait);
784e74080bSDennis Dalessandro atomic_set(&mcast->refcount, 0);
794e74080bSDennis Dalessandro
804e74080bSDennis Dalessandro bail:
814e74080bSDennis Dalessandro return mcast;
824e74080bSDennis Dalessandro }
834e74080bSDennis Dalessandro
rvt_mcast_free(struct rvt_mcast * mcast)844e74080bSDennis Dalessandro static void rvt_mcast_free(struct rvt_mcast *mcast)
854e74080bSDennis Dalessandro {
864e74080bSDennis Dalessandro struct rvt_mcast_qp *p, *tmp;
874e74080bSDennis Dalessandro
884e74080bSDennis Dalessandro list_for_each_entry_safe(p, tmp, &mcast->qp_list, list)
894e74080bSDennis Dalessandro rvt_mcast_qp_free(p);
904e74080bSDennis Dalessandro
914e74080bSDennis Dalessandro kfree(mcast);
924e74080bSDennis Dalessandro }
934e74080bSDennis Dalessandro
944e74080bSDennis Dalessandro /**
95aad9ff97SMichael J. Ruhl * rvt_mcast_find - search the global table for the given multicast GID/LID
96aad9ff97SMichael J. Ruhl * NOTE: It is valid to have 1 MLID with multiple MGIDs. It is not valid
97aad9ff97SMichael J. Ruhl * to have 1 MGID with multiple MLIDs.
984e74080bSDennis Dalessandro * @ibp: the IB port structure
994e74080bSDennis Dalessandro * @mgid: the multicast GID to search for
100aad9ff97SMichael J. Ruhl * @lid: the multicast LID portion of the multicast address (host order)
1014e74080bSDennis Dalessandro *
1024e74080bSDennis Dalessandro * The caller is responsible for decrementing the reference count if found.
10390793f71SDennis Dalessandro *
10490793f71SDennis Dalessandro * Return: NULL if not found.
1054e74080bSDennis Dalessandro */
rvt_mcast_find(struct rvt_ibport * ibp,union ib_gid * mgid,u16 lid)106aad9ff97SMichael J. Ruhl struct rvt_mcast *rvt_mcast_find(struct rvt_ibport *ibp, union ib_gid *mgid,
107aad9ff97SMichael J. Ruhl u16 lid)
1084e74080bSDennis Dalessandro {
1094e74080bSDennis Dalessandro struct rb_node *n;
1104e74080bSDennis Dalessandro unsigned long flags;
1114e74080bSDennis Dalessandro struct rvt_mcast *found = NULL;
1124e74080bSDennis Dalessandro
1134e74080bSDennis Dalessandro spin_lock_irqsave(&ibp->lock, flags);
1144e74080bSDennis Dalessandro n = ibp->mcast_tree.rb_node;
1154e74080bSDennis Dalessandro while (n) {
1164e74080bSDennis Dalessandro int ret;
1174e74080bSDennis Dalessandro struct rvt_mcast *mcast;
1184e74080bSDennis Dalessandro
1194e74080bSDennis Dalessandro mcast = rb_entry(n, struct rvt_mcast, rb_node);
1204e74080bSDennis Dalessandro
121aad9ff97SMichael J. Ruhl ret = memcmp(mgid->raw, mcast->mcast_addr.mgid.raw,
122aad9ff97SMichael J. Ruhl sizeof(*mgid));
1234e74080bSDennis Dalessandro if (ret < 0) {
1244e74080bSDennis Dalessandro n = n->rb_left;
1254e74080bSDennis Dalessandro } else if (ret > 0) {
1264e74080bSDennis Dalessandro n = n->rb_right;
1274e74080bSDennis Dalessandro } else {
128aad9ff97SMichael J. Ruhl /* MGID/MLID must match */
129aad9ff97SMichael J. Ruhl if (mcast->mcast_addr.lid == lid) {
1304e74080bSDennis Dalessandro atomic_inc(&mcast->refcount);
1314e74080bSDennis Dalessandro found = mcast;
132aad9ff97SMichael J. Ruhl }
1334e74080bSDennis Dalessandro break;
1344e74080bSDennis Dalessandro }
1354e74080bSDennis Dalessandro }
1364e74080bSDennis Dalessandro spin_unlock_irqrestore(&ibp->lock, flags);
1374e74080bSDennis Dalessandro return found;
1384e74080bSDennis Dalessandro }
1394e74080bSDennis Dalessandro EXPORT_SYMBOL(rvt_mcast_find);
1404e74080bSDennis Dalessandro
14100d25ff6SLee Jones /*
1422988ca08SMauro Carvalho Chehab * rvt_mcast_add - insert mcast GID into table and attach QP struct
1434e74080bSDennis Dalessandro * @mcast: the mcast GID table
1444e74080bSDennis Dalessandro * @mqp: the QP to attach
1454e74080bSDennis Dalessandro *
14690793f71SDennis Dalessandro * Return: zero if both were added. Return EEXIST if the GID was already in
1474e74080bSDennis Dalessandro * the table but the QP was added. Return ESRCH if the QP was already
148aad9ff97SMichael J. Ruhl * attached and neither structure was added. Return EINVAL if the MGID was
149aad9ff97SMichael J. Ruhl * found, but the MLID did NOT match.
1504e74080bSDennis Dalessandro */
rvt_mcast_add(struct rvt_dev_info * rdi,struct rvt_ibport * ibp,struct rvt_mcast * mcast,struct rvt_mcast_qp * mqp)1514e74080bSDennis Dalessandro static int rvt_mcast_add(struct rvt_dev_info *rdi, struct rvt_ibport *ibp,
1524e74080bSDennis Dalessandro struct rvt_mcast *mcast, struct rvt_mcast_qp *mqp)
1534e74080bSDennis Dalessandro {
1544e74080bSDennis Dalessandro struct rb_node **n = &ibp->mcast_tree.rb_node;
1554e74080bSDennis Dalessandro struct rb_node *pn = NULL;
1564e74080bSDennis Dalessandro int ret;
1574e74080bSDennis Dalessandro
1584e74080bSDennis Dalessandro spin_lock_irq(&ibp->lock);
1594e74080bSDennis Dalessandro
1604e74080bSDennis Dalessandro while (*n) {
1614e74080bSDennis Dalessandro struct rvt_mcast *tmcast;
1624e74080bSDennis Dalessandro struct rvt_mcast_qp *p;
1634e74080bSDennis Dalessandro
1644e74080bSDennis Dalessandro pn = *n;
1654e74080bSDennis Dalessandro tmcast = rb_entry(pn, struct rvt_mcast, rb_node);
1664e74080bSDennis Dalessandro
167aad9ff97SMichael J. Ruhl ret = memcmp(mcast->mcast_addr.mgid.raw,
168aad9ff97SMichael J. Ruhl tmcast->mcast_addr.mgid.raw,
169aad9ff97SMichael J. Ruhl sizeof(mcast->mcast_addr.mgid));
1704e74080bSDennis Dalessandro if (ret < 0) {
1714e74080bSDennis Dalessandro n = &pn->rb_left;
1724e74080bSDennis Dalessandro continue;
1734e74080bSDennis Dalessandro }
1744e74080bSDennis Dalessandro if (ret > 0) {
1754e74080bSDennis Dalessandro n = &pn->rb_right;
1764e74080bSDennis Dalessandro continue;
1774e74080bSDennis Dalessandro }
1784e74080bSDennis Dalessandro
179aad9ff97SMichael J. Ruhl if (tmcast->mcast_addr.lid != mcast->mcast_addr.lid) {
180aad9ff97SMichael J. Ruhl ret = EINVAL;
181aad9ff97SMichael J. Ruhl goto bail;
182aad9ff97SMichael J. Ruhl }
183aad9ff97SMichael J. Ruhl
1844e74080bSDennis Dalessandro /* Search the QP list to see if this is already there. */
1854e74080bSDennis Dalessandro list_for_each_entry_rcu(p, &tmcast->qp_list, list) {
1864e74080bSDennis Dalessandro if (p->qp == mqp->qp) {
1874e74080bSDennis Dalessandro ret = ESRCH;
1884e74080bSDennis Dalessandro goto bail;
1894e74080bSDennis Dalessandro }
1904e74080bSDennis Dalessandro }
1914e74080bSDennis Dalessandro if (tmcast->n_attached ==
1924e74080bSDennis Dalessandro rdi->dparms.props.max_mcast_qp_attach) {
1934e74080bSDennis Dalessandro ret = ENOMEM;
1944e74080bSDennis Dalessandro goto bail;
1954e74080bSDennis Dalessandro }
1964e74080bSDennis Dalessandro
1974e74080bSDennis Dalessandro tmcast->n_attached++;
1984e74080bSDennis Dalessandro
1994e74080bSDennis Dalessandro list_add_tail_rcu(&mqp->list, &tmcast->qp_list);
2004e74080bSDennis Dalessandro ret = EEXIST;
2014e74080bSDennis Dalessandro goto bail;
2024e74080bSDennis Dalessandro }
2034e74080bSDennis Dalessandro
2044e74080bSDennis Dalessandro spin_lock(&rdi->n_mcast_grps_lock);
2054e74080bSDennis Dalessandro if (rdi->n_mcast_grps_allocated == rdi->dparms.props.max_mcast_grp) {
2064e74080bSDennis Dalessandro spin_unlock(&rdi->n_mcast_grps_lock);
2074e74080bSDennis Dalessandro ret = ENOMEM;
2084e74080bSDennis Dalessandro goto bail;
2094e74080bSDennis Dalessandro }
2104e74080bSDennis Dalessandro
2114e74080bSDennis Dalessandro rdi->n_mcast_grps_allocated++;
2124e74080bSDennis Dalessandro spin_unlock(&rdi->n_mcast_grps_lock);
2134e74080bSDennis Dalessandro
2144e74080bSDennis Dalessandro mcast->n_attached++;
2154e74080bSDennis Dalessandro
2164e74080bSDennis Dalessandro list_add_tail_rcu(&mqp->list, &mcast->qp_list);
2174e74080bSDennis Dalessandro
2184e74080bSDennis Dalessandro atomic_inc(&mcast->refcount);
2194e74080bSDennis Dalessandro rb_link_node(&mcast->rb_node, pn, n);
2204e74080bSDennis Dalessandro rb_insert_color(&mcast->rb_node, &ibp->mcast_tree);
2214e74080bSDennis Dalessandro
2224e74080bSDennis Dalessandro ret = 0;
2234e74080bSDennis Dalessandro
2244e74080bSDennis Dalessandro bail:
2254e74080bSDennis Dalessandro spin_unlock_irq(&ibp->lock);
2264e74080bSDennis Dalessandro
2274e74080bSDennis Dalessandro return ret;
2284e74080bSDennis Dalessandro }
2294e74080bSDennis Dalessandro
23090793f71SDennis Dalessandro /**
23190793f71SDennis Dalessandro * rvt_attach_mcast - attach a qp to a multicast group
23290793f71SDennis Dalessandro * @ibqp: Infiniband qp
2334f9a3018SRandy Dunlap * @gid: multicast guid
23490793f71SDennis Dalessandro * @lid: multicast lid
23590793f71SDennis Dalessandro *
23690793f71SDennis Dalessandro * Return: 0 on success
23790793f71SDennis Dalessandro */
rvt_attach_mcast(struct ib_qp * ibqp,union ib_gid * gid,u16 lid)2389fa25171SDennis Dalessandro int rvt_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
2399fa25171SDennis Dalessandro {
2404e74080bSDennis Dalessandro struct rvt_qp *qp = ibqp_to_rvtqp(ibqp);
2414e74080bSDennis Dalessandro struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device);
2424e74080bSDennis Dalessandro struct rvt_ibport *ibp = rdi->ports[qp->port_num - 1];
2434e74080bSDennis Dalessandro struct rvt_mcast *mcast;
2444e74080bSDennis Dalessandro struct rvt_mcast_qp *mqp;
2454e74080bSDennis Dalessandro int ret = -ENOMEM;
2464e74080bSDennis Dalessandro
2474e74080bSDennis Dalessandro if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET)
2484e74080bSDennis Dalessandro return -EINVAL;
2494e74080bSDennis Dalessandro
2504e74080bSDennis Dalessandro /*
2514e74080bSDennis Dalessandro * Allocate data structures since its better to do this outside of
2524e74080bSDennis Dalessandro * spin locks and it will most likely be needed.
2534e74080bSDennis Dalessandro */
254aad9ff97SMichael J. Ruhl mcast = rvt_mcast_alloc(gid, lid);
2554e74080bSDennis Dalessandro if (!mcast)
2564e74080bSDennis Dalessandro return -ENOMEM;
2574e74080bSDennis Dalessandro
2584e74080bSDennis Dalessandro mqp = rvt_mcast_qp_alloc(qp);
2594e74080bSDennis Dalessandro if (!mqp)
2604e74080bSDennis Dalessandro goto bail_mcast;
2614e74080bSDennis Dalessandro
2624e74080bSDennis Dalessandro switch (rvt_mcast_add(rdi, ibp, mcast, mqp)) {
2634e74080bSDennis Dalessandro case ESRCH:
2644e74080bSDennis Dalessandro /* Neither was used: OK to attach the same QP twice. */
2654e74080bSDennis Dalessandro ret = 0;
2664e74080bSDennis Dalessandro goto bail_mqp;
2674e74080bSDennis Dalessandro case EEXIST: /* The mcast wasn't used */
2684e74080bSDennis Dalessandro ret = 0;
2694e74080bSDennis Dalessandro goto bail_mcast;
2704e74080bSDennis Dalessandro case ENOMEM:
2714e74080bSDennis Dalessandro /* Exceeded the maximum number of mcast groups. */
2724e74080bSDennis Dalessandro ret = -ENOMEM;
2734e74080bSDennis Dalessandro goto bail_mqp;
274aad9ff97SMichael J. Ruhl case EINVAL:
275aad9ff97SMichael J. Ruhl /* Invalid MGID/MLID pair */
276aad9ff97SMichael J. Ruhl ret = -EINVAL;
277aad9ff97SMichael J. Ruhl goto bail_mqp;
2784e74080bSDennis Dalessandro default:
2794e74080bSDennis Dalessandro break;
2804e74080bSDennis Dalessandro }
2814e74080bSDennis Dalessandro
2824e74080bSDennis Dalessandro return 0;
2834e74080bSDennis Dalessandro
2844e74080bSDennis Dalessandro bail_mqp:
2854e74080bSDennis Dalessandro rvt_mcast_qp_free(mqp);
2864e74080bSDennis Dalessandro
2874e74080bSDennis Dalessandro bail_mcast:
2884e74080bSDennis Dalessandro rvt_mcast_free(mcast);
2894e74080bSDennis Dalessandro
2904e74080bSDennis Dalessandro return ret;
2919fa25171SDennis Dalessandro }
2929fa25171SDennis Dalessandro
29390793f71SDennis Dalessandro /**
29490793f71SDennis Dalessandro * rvt_detach_mcast - remove a qp from a multicast group
29590793f71SDennis Dalessandro * @ibqp: Infiniband qp
2964f9a3018SRandy Dunlap * @gid: multicast guid
29790793f71SDennis Dalessandro * @lid: multicast lid
29890793f71SDennis Dalessandro *
29990793f71SDennis Dalessandro * Return: 0 on success
30090793f71SDennis Dalessandro */
rvt_detach_mcast(struct ib_qp * ibqp,union ib_gid * gid,u16 lid)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
312f9586abfSAlex Estrin if (ibqp->qp_num <= 1)
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);
326aad9ff97SMichael J. Ruhl ret = memcmp(gid->raw, mcast->mcast_addr.mgid.raw,
327aad9ff97SMichael J. Ruhl sizeof(*gid));
328aad9ff97SMichael J. Ruhl if (ret < 0) {
3294e74080bSDennis Dalessandro n = n->rb_left;
330aad9ff97SMichael J. Ruhl } else if (ret > 0) {
3314e74080bSDennis Dalessandro n = n->rb_right;
332aad9ff97SMichael J. Ruhl } else {
333aad9ff97SMichael J. Ruhl /* MGID/MLID must match */
334aad9ff97SMichael J. Ruhl if (mcast->mcast_addr.lid != lid) {
335aad9ff97SMichael J. Ruhl spin_unlock_irq(&ibp->lock);
336aad9ff97SMichael J. Ruhl return -EINVAL;
337aad9ff97SMichael J. Ruhl }
3384e74080bSDennis Dalessandro break;
3394e74080bSDennis Dalessandro }
340aad9ff97SMichael J. Ruhl }
3414e74080bSDennis Dalessandro
3424e74080bSDennis Dalessandro /* Search the QP list. */
3434e74080bSDennis Dalessandro list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) {
3444e74080bSDennis Dalessandro if (p->qp != qp)
3454e74080bSDennis Dalessandro continue;
3464e74080bSDennis Dalessandro /*
3474e74080bSDennis Dalessandro * We found it, so remove it, but don't poison the forward
3484e74080bSDennis Dalessandro * link until we are sure there are no list walkers.
3494e74080bSDennis Dalessandro */
3504e74080bSDennis Dalessandro list_del_rcu(&p->list);
3514e74080bSDennis Dalessandro mcast->n_attached--;
3524e74080bSDennis Dalessandro delp = p;
3534e74080bSDennis Dalessandro
3544e74080bSDennis Dalessandro /* If this was the last attached QP, remove the GID too. */
3554e74080bSDennis Dalessandro if (list_empty(&mcast->qp_list)) {
3564e74080bSDennis Dalessandro rb_erase(&mcast->rb_node, &ibp->mcast_tree);
3574e74080bSDennis Dalessandro last = 1;
3584e74080bSDennis Dalessandro }
3594e74080bSDennis Dalessandro break;
3604e74080bSDennis Dalessandro }
3614e74080bSDennis Dalessandro
3624e74080bSDennis Dalessandro spin_unlock_irq(&ibp->lock);
3634e74080bSDennis Dalessandro /* QP not attached */
3644e74080bSDennis Dalessandro if (!delp)
3654e74080bSDennis Dalessandro return -EINVAL;
3664e74080bSDennis Dalessandro
3674e74080bSDennis Dalessandro /*
3684e74080bSDennis Dalessandro * Wait for any list walkers to finish before freeing the
3694e74080bSDennis Dalessandro * list element.
3704e74080bSDennis Dalessandro */
3714e74080bSDennis Dalessandro wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1);
3724e74080bSDennis Dalessandro rvt_mcast_qp_free(delp);
3734e74080bSDennis Dalessandro
3744e74080bSDennis Dalessandro if (last) {
3754e74080bSDennis Dalessandro atomic_dec(&mcast->refcount);
3764e74080bSDennis Dalessandro wait_event(mcast->wait, !atomic_read(&mcast->refcount));
3774e74080bSDennis Dalessandro rvt_mcast_free(mcast);
3784e74080bSDennis Dalessandro spin_lock_irq(&rdi->n_mcast_grps_lock);
3794e74080bSDennis Dalessandro rdi->n_mcast_grps_allocated--;
3804e74080bSDennis Dalessandro spin_unlock_irq(&rdi->n_mcast_grps_lock);
3814e74080bSDennis Dalessandro }
3824e74080bSDennis Dalessandro
3834e74080bSDennis Dalessandro return 0;
3844e74080bSDennis Dalessandro }
3854e74080bSDennis Dalessandro
38690793f71SDennis Dalessandro /**
3872988ca08SMauro Carvalho Chehab * rvt_mcast_tree_empty - determine if any qps are attached to any mcast group
38890793f71SDennis Dalessandro * @rdi: rvt dev struct
38990793f71SDennis Dalessandro *
39090793f71SDennis Dalessandro * Return: in use count
39190793f71SDennis Dalessandro */
rvt_mcast_tree_empty(struct rvt_dev_info * rdi)3924e74080bSDennis Dalessandro int rvt_mcast_tree_empty(struct rvt_dev_info *rdi)
3934e74080bSDennis Dalessandro {
3944e74080bSDennis Dalessandro int i;
3954e74080bSDennis Dalessandro int in_use = 0;
3964e74080bSDennis Dalessandro
3974e74080bSDennis Dalessandro for (i = 0; i < rdi->dparms.nports; i++)
3984e74080bSDennis Dalessandro if (rdi->ports[i]->mcast_tree.rb_node)
3994e74080bSDennis Dalessandro in_use++;
4004e74080bSDennis Dalessandro return in_use;
4019fa25171SDennis Dalessandro }
402