Path: blob/master/drivers/infiniband/hw/qib/qib_verbs_mcast.c
15112 views
/*1* Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.2* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.3*4* This software is available to you under a choice of one of two5* licenses. You may choose to be licensed under the terms of the GNU6* General Public License (GPL) Version 2, available from the file7* COPYING in the main directory of this source tree, or the8* OpenIB.org BSD license below:9*10* Redistribution and use in source and binary forms, with or11* without modification, are permitted provided that the following12* conditions are met:13*14* - Redistributions of source code must retain the above15* copyright notice, this list of conditions and the following16* disclaimer.17*18* - Redistributions in binary form must reproduce the above19* copyright notice, this list of conditions and the following20* disclaimer in the documentation and/or other materials21* provided with the distribution.22*23* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30* SOFTWARE.31*/3233#include <linux/rculist.h>3435#include "qib.h"3637/**38* qib_mcast_qp_alloc - alloc a struct to link a QP to mcast GID struct39* @qp: the QP to link40*/41static struct qib_mcast_qp *qib_mcast_qp_alloc(struct qib_qp *qp)42{43struct qib_mcast_qp *mqp;4445mqp = kmalloc(sizeof *mqp, GFP_KERNEL);46if (!mqp)47goto bail;4849mqp->qp = qp;50atomic_inc(&qp->refcount);5152bail:53return mqp;54}5556static void qib_mcast_qp_free(struct qib_mcast_qp *mqp)57{58struct qib_qp *qp = mqp->qp;5960/* Notify qib_destroy_qp() if it is waiting. */61if (atomic_dec_and_test(&qp->refcount))62wake_up(&qp->wait);6364kfree(mqp);65}6667/**68* qib_mcast_alloc - allocate the multicast GID structure69* @mgid: the multicast GID70*71* A list of QPs will be attached to this structure.72*/73static struct qib_mcast *qib_mcast_alloc(union ib_gid *mgid)74{75struct qib_mcast *mcast;7677mcast = kmalloc(sizeof *mcast, GFP_KERNEL);78if (!mcast)79goto bail;8081mcast->mgid = *mgid;82INIT_LIST_HEAD(&mcast->qp_list);83init_waitqueue_head(&mcast->wait);84atomic_set(&mcast->refcount, 0);85mcast->n_attached = 0;8687bail:88return mcast;89}9091static void qib_mcast_free(struct qib_mcast *mcast)92{93struct qib_mcast_qp *p, *tmp;9495list_for_each_entry_safe(p, tmp, &mcast->qp_list, list)96qib_mcast_qp_free(p);9798kfree(mcast);99}100101/**102* qib_mcast_find - search the global table for the given multicast GID103* @ibp: the IB port structure104* @mgid: the multicast GID to search for105*106* Returns NULL if not found.107*108* The caller is responsible for decrementing the reference count if found.109*/110struct qib_mcast *qib_mcast_find(struct qib_ibport *ibp, union ib_gid *mgid)111{112struct rb_node *n;113unsigned long flags;114struct qib_mcast *mcast;115116spin_lock_irqsave(&ibp->lock, flags);117n = ibp->mcast_tree.rb_node;118while (n) {119int ret;120121mcast = rb_entry(n, struct qib_mcast, rb_node);122123ret = memcmp(mgid->raw, mcast->mgid.raw,124sizeof(union ib_gid));125if (ret < 0)126n = n->rb_left;127else if (ret > 0)128n = n->rb_right;129else {130atomic_inc(&mcast->refcount);131spin_unlock_irqrestore(&ibp->lock, flags);132goto bail;133}134}135spin_unlock_irqrestore(&ibp->lock, flags);136137mcast = NULL;138139bail:140return mcast;141}142143/**144* qib_mcast_add - insert mcast GID into table and attach QP struct145* @mcast: the mcast GID table146* @mqp: the QP to attach147*148* Return zero if both were added. Return EEXIST if the GID was already in149* the table but the QP was added. Return ESRCH if the QP was already150* attached and neither structure was added.151*/152static int qib_mcast_add(struct qib_ibdev *dev, struct qib_ibport *ibp,153struct qib_mcast *mcast, struct qib_mcast_qp *mqp)154{155struct rb_node **n = &ibp->mcast_tree.rb_node;156struct rb_node *pn = NULL;157int ret;158159spin_lock_irq(&ibp->lock);160161while (*n) {162struct qib_mcast *tmcast;163struct qib_mcast_qp *p;164165pn = *n;166tmcast = rb_entry(pn, struct qib_mcast, rb_node);167168ret = memcmp(mcast->mgid.raw, tmcast->mgid.raw,169sizeof(union ib_gid));170if (ret < 0) {171n = &pn->rb_left;172continue;173}174if (ret > 0) {175n = &pn->rb_right;176continue;177}178179/* Search the QP list to see if this is already there. */180list_for_each_entry_rcu(p, &tmcast->qp_list, list) {181if (p->qp == mqp->qp) {182ret = ESRCH;183goto bail;184}185}186if (tmcast->n_attached == ib_qib_max_mcast_qp_attached) {187ret = ENOMEM;188goto bail;189}190191tmcast->n_attached++;192193list_add_tail_rcu(&mqp->list, &tmcast->qp_list);194ret = EEXIST;195goto bail;196}197198spin_lock(&dev->n_mcast_grps_lock);199if (dev->n_mcast_grps_allocated == ib_qib_max_mcast_grps) {200spin_unlock(&dev->n_mcast_grps_lock);201ret = ENOMEM;202goto bail;203}204205dev->n_mcast_grps_allocated++;206spin_unlock(&dev->n_mcast_grps_lock);207208mcast->n_attached++;209210list_add_tail_rcu(&mqp->list, &mcast->qp_list);211212atomic_inc(&mcast->refcount);213rb_link_node(&mcast->rb_node, pn, n);214rb_insert_color(&mcast->rb_node, &ibp->mcast_tree);215216ret = 0;217218bail:219spin_unlock_irq(&ibp->lock);220221return ret;222}223224int qib_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)225{226struct qib_qp *qp = to_iqp(ibqp);227struct qib_ibdev *dev = to_idev(ibqp->device);228struct qib_ibport *ibp;229struct qib_mcast *mcast;230struct qib_mcast_qp *mqp;231int ret;232233if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) {234ret = -EINVAL;235goto bail;236}237238/*239* Allocate data structures since its better to do this outside of240* spin locks and it will most likely be needed.241*/242mcast = qib_mcast_alloc(gid);243if (mcast == NULL) {244ret = -ENOMEM;245goto bail;246}247mqp = qib_mcast_qp_alloc(qp);248if (mqp == NULL) {249qib_mcast_free(mcast);250ret = -ENOMEM;251goto bail;252}253ibp = to_iport(ibqp->device, qp->port_num);254switch (qib_mcast_add(dev, ibp, mcast, mqp)) {255case ESRCH:256/* Neither was used: OK to attach the same QP twice. */257qib_mcast_qp_free(mqp);258qib_mcast_free(mcast);259break;260261case EEXIST: /* The mcast wasn't used */262qib_mcast_free(mcast);263break;264265case ENOMEM:266/* Exceeded the maximum number of mcast groups. */267qib_mcast_qp_free(mqp);268qib_mcast_free(mcast);269ret = -ENOMEM;270goto bail;271272default:273break;274}275276ret = 0;277278bail:279return ret;280}281282int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)283{284struct qib_qp *qp = to_iqp(ibqp);285struct qib_ibdev *dev = to_idev(ibqp->device);286struct qib_ibport *ibp = to_iport(ibqp->device, qp->port_num);287struct qib_mcast *mcast = NULL;288struct qib_mcast_qp *p, *tmp;289struct rb_node *n;290int last = 0;291int ret;292293if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) {294ret = -EINVAL;295goto bail;296}297298spin_lock_irq(&ibp->lock);299300/* Find the GID in the mcast table. */301n = ibp->mcast_tree.rb_node;302while (1) {303if (n == NULL) {304spin_unlock_irq(&ibp->lock);305ret = -EINVAL;306goto bail;307}308309mcast = rb_entry(n, struct qib_mcast, rb_node);310ret = memcmp(gid->raw, mcast->mgid.raw,311sizeof(union ib_gid));312if (ret < 0)313n = n->rb_left;314else if (ret > 0)315n = n->rb_right;316else317break;318}319320/* Search the QP list. */321list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) {322if (p->qp != qp)323continue;324/*325* We found it, so remove it, but don't poison the forward326* link until we are sure there are no list walkers.327*/328list_del_rcu(&p->list);329mcast->n_attached--;330331/* If this was the last attached QP, remove the GID too. */332if (list_empty(&mcast->qp_list)) {333rb_erase(&mcast->rb_node, &ibp->mcast_tree);334last = 1;335}336break;337}338339spin_unlock_irq(&ibp->lock);340341if (p) {342/*343* Wait for any list walkers to finish before freeing the344* list element.345*/346wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1);347qib_mcast_qp_free(p);348}349if (last) {350atomic_dec(&mcast->refcount);351wait_event(mcast->wait, !atomic_read(&mcast->refcount));352qib_mcast_free(mcast);353spin_lock_irq(&dev->n_mcast_grps_lock);354dev->n_mcast_grps_allocated--;355spin_unlock_irq(&dev->n_mcast_grps_lock);356}357358ret = 0;359360bail:361return ret;362}363364int qib_mcast_tree_empty(struct qib_ibport *ibp)365{366return ibp->mcast_tree.rb_node == NULL;367}368369370