brintos

brintos / linux-shallow public Read only

0
0
Text · 7.9 KiB · 6304ae8 Raw
336 lines · c
1/*2 * Copyright (c) 2004 Topspin Communications.  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 */32 33#include <linux/string.h>34#include <linux/gfp.h>35 36#include "mthca_dev.h"37#include "mthca_cmd.h"38 39struct mthca_mgm {40	__be32 next_gid_index;41	u32    reserved[3];42	u8     gid[16];43	__be32 qp[MTHCA_QP_PER_MGM];44};45 46static const u8 zero_gid[16];	/* automatically initialized to 0 */47 48/*49 * Caller must hold MCG table semaphore.  gid and mgm parameters must50 * be properly aligned for command interface.51 *52 *  Returns 0 unless a firmware command error occurs.53 *54 * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -155 * and *mgm holds MGM entry.56 *57 * if GID is found in AMGM, *index = index in AMGM, *prev = index of58 * previous entry in hash chain and *mgm holds AMGM entry.59 *60 * If no AMGM exists for given gid, *index = -1, *prev = index of last61 * entry in hash chain and *mgm holds end of hash chain.62 */63static int find_mgm(struct mthca_dev *dev,64		    u8 *gid, struct mthca_mailbox *mgm_mailbox,65		    u16 *hash, int *prev, int *index)66{67	struct mthca_mailbox *mailbox;68	struct mthca_mgm *mgm = mgm_mailbox->buf;69	u8 *mgid;70	int err;71 72	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);73	if (IS_ERR(mailbox))74		return -ENOMEM;75	mgid = mailbox->buf;76 77	memcpy(mgid, gid, 16);78 79	err = mthca_MGID_HASH(dev, mailbox, hash);80	if (err) {81		mthca_err(dev, "MGID_HASH failed (%d)\n", err);82		goto out;83	}84 85	if (0)86		mthca_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash);87 88	*index = *hash;89	*prev  = -1;90 91	do {92		err = mthca_READ_MGM(dev, *index, mgm_mailbox);93		if (err) {94			mthca_err(dev, "READ_MGM failed (%d)\n", err);95			goto out;96		}97 98		if (!memcmp(mgm->gid, zero_gid, 16)) {99			if (*index != *hash) {100				mthca_err(dev, "Found zero MGID in AMGM.\n");101				err = -EINVAL;102			}103			goto out;104		}105 106		if (!memcmp(mgm->gid, gid, 16))107			goto out;108 109		*prev = *index;110		*index = be32_to_cpu(mgm->next_gid_index) >> 6;111	} while (*index);112 113	*index = -1;114 115 out:116	mthca_free_mailbox(dev, mailbox);117	return err;118}119 120int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)121{122	struct mthca_dev *dev = to_mdev(ibqp->device);123	struct mthca_mailbox *mailbox;124	struct mthca_mgm *mgm;125	u16 hash;126	int index, prev;127	int link = 0;128	int i;129	int err;130 131	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);132	if (IS_ERR(mailbox))133		return PTR_ERR(mailbox);134	mgm = mailbox->buf;135 136	mutex_lock(&dev->mcg_table.mutex);137 138	err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);139	if (err)140		goto out;141 142	if (index != -1) {143		if (!memcmp(mgm->gid, zero_gid, 16))144			memcpy(mgm->gid, gid->raw, 16);145	} else {146		link = 1;147 148		index = mthca_alloc(&dev->mcg_table.alloc);149		if (index == -1) {150			mthca_err(dev, "No AMGM entries left\n");151			err = -ENOMEM;152			goto out;153		}154 155		err = mthca_READ_MGM(dev, index, mailbox);156		if (err) {157			mthca_err(dev, "READ_MGM failed (%d)\n", err);158			goto out;159		}160		memset(mgm, 0, sizeof *mgm);161		memcpy(mgm->gid, gid->raw, 16);162	}163 164	for (i = 0; i < MTHCA_QP_PER_MGM; ++i)165		if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) {166			mthca_dbg(dev, "QP %06x already a member of MGM\n",167				  ibqp->qp_num);168			err = 0;169			goto out;170		} else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) {171			mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31));172			break;173		}174 175	if (i == MTHCA_QP_PER_MGM) {176		mthca_err(dev, "MGM at index %x is full.\n", index);177		err = -ENOMEM;178		goto out;179	}180 181	err = mthca_WRITE_MGM(dev, index, mailbox);182	if (err) {183		mthca_err(dev, "WRITE_MGM failed %d\n", err);184		err = -EINVAL;185		goto out;186	}187 188	if (!link)189		goto out;190 191	err = mthca_READ_MGM(dev, prev, mailbox);192	if (err) {193		mthca_err(dev, "READ_MGM failed %d\n", err);194		goto out;195	}196 197	mgm->next_gid_index = cpu_to_be32(index << 6);198 199	err = mthca_WRITE_MGM(dev, prev, mailbox);200	if (err)201		mthca_err(dev, "WRITE_MGM returned %d\n", err);202 203 out:204	if (err && link && index != -1) {205		BUG_ON(index < dev->limits.num_mgms);206		mthca_free(&dev->mcg_table.alloc, index);207	}208	mutex_unlock(&dev->mcg_table.mutex);209 210	mthca_free_mailbox(dev, mailbox);211	return err;212}213 214int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)215{216	struct mthca_dev *dev = to_mdev(ibqp->device);217	struct mthca_mailbox *mailbox;218	struct mthca_mgm *mgm;219	u16 hash;220	int prev, index;221	int i, loc;222	int err;223 224	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);225	if (IS_ERR(mailbox))226		return PTR_ERR(mailbox);227	mgm = mailbox->buf;228 229	mutex_lock(&dev->mcg_table.mutex);230 231	err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);232	if (err)233		goto out;234 235	if (index == -1) {236		mthca_err(dev, "MGID %pI6 not found\n", gid->raw);237		err = -EINVAL;238		goto out;239	}240 241	for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) {242		if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31)))243			loc = i;244		if (!(mgm->qp[i] & cpu_to_be32(1 << 31)))245			break;246	}247 248	if (loc == -1) {249		mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num);250		err = -EINVAL;251		goto out;252	}253 254	mgm->qp[loc]   = mgm->qp[i - 1];255	mgm->qp[i - 1] = 0;256 257	err = mthca_WRITE_MGM(dev, index, mailbox);258	if (err) {259		mthca_err(dev, "WRITE_MGM returned %d\n", err);260		goto out;261	}262 263	if (i != 1)264		goto out;265 266	if (prev == -1) {267		/* Remove entry from MGM */268		int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6;269		if (amgm_index_to_free) {270			err = mthca_READ_MGM(dev, amgm_index_to_free,271					     mailbox);272			if (err) {273				mthca_err(dev, "READ_MGM returned %d\n", err);274				goto out;275			}276		} else277			memset(mgm->gid, 0, 16);278 279		err = mthca_WRITE_MGM(dev, index, mailbox);280		if (err) {281			mthca_err(dev, "WRITE_MGM returned %d\n", err);282			goto out;283		}284		if (amgm_index_to_free) {285			BUG_ON(amgm_index_to_free < dev->limits.num_mgms);286			mthca_free(&dev->mcg_table.alloc, amgm_index_to_free);287		}288	} else {289		/* Remove entry from AMGM */290		int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;291		err = mthca_READ_MGM(dev, prev, mailbox);292		if (err) {293			mthca_err(dev, "READ_MGM returned %d\n", err);294			goto out;295		}296 297		mgm->next_gid_index = cpu_to_be32(curr_next_index << 6);298 299		err = mthca_WRITE_MGM(dev, prev, mailbox);300		if (err) {301			mthca_err(dev, "WRITE_MGM returned %d\n", err);302			goto out;303		}304		BUG_ON(index < dev->limits.num_mgms);305		mthca_free(&dev->mcg_table.alloc, index);306	}307 308 out:309	mutex_unlock(&dev->mcg_table.mutex);310 311	mthca_free_mailbox(dev, mailbox);312	return err;313}314 315int mthca_init_mcg_table(struct mthca_dev *dev)316{317	int err;318	int table_size = dev->limits.num_mgms + dev->limits.num_amgms;319 320	err = mthca_alloc_init(&dev->mcg_table.alloc,321			       table_size,322			       table_size - 1,323			       dev->limits.num_mgms);324	if (err)325		return err;326 327	mutex_init(&dev->mcg_table.mutex);328 329	return 0;330}331 332void mthca_cleanup_mcg_table(struct mthca_dev *dev)333{334	mthca_alloc_cleanup(&dev->mcg_table.alloc);335}336