Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
0003  *
0004  * This software is available to you under a choice of one of two
0005  * licenses.  You may choose to be licensed under the terms of the GNU
0006  * General Public License (GPL) Version 2, available from the file
0007  * COPYING in the main directory of this source tree, or the
0008  * OpenIB.org BSD license below:
0009  *
0010  *     Redistribution and use in source and binary forms, with or
0011  *     without modification, are permitted provided that the following
0012  *     conditions are met:
0013  *
0014  *      - Redistributions of source code must retain the above
0015  *        copyright notice, this list of conditions and the following
0016  *        disclaimer.
0017  *
0018  *      - Redistributions in binary form must reproduce the above
0019  *        copyright notice, this list of conditions and the following
0020  *        disclaimer in the documentation and/or other materials
0021  *        provided with the distribution.
0022  *
0023  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0024  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0025  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0026  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0027  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0028  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0029  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0030  * SOFTWARE.
0031  */
0032 
0033 #include <linux/string.h>
0034 #include <linux/gfp.h>
0035 
0036 #include "mthca_dev.h"
0037 #include "mthca_cmd.h"
0038 
0039 struct mthca_mgm {
0040     __be32 next_gid_index;
0041     u32    reserved[3];
0042     u8     gid[16];
0043     __be32 qp[MTHCA_QP_PER_MGM];
0044 };
0045 
0046 static const u8 zero_gid[16];   /* automatically initialized to 0 */
0047 
0048 /*
0049  * Caller must hold MCG table semaphore.  gid and mgm parameters must
0050  * be properly aligned for command interface.
0051  *
0052  *  Returns 0 unless a firmware command error occurs.
0053  *
0054  * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1
0055  * and *mgm holds MGM entry.
0056  *
0057  * if GID is found in AMGM, *index = index in AMGM, *prev = index of
0058  * previous entry in hash chain and *mgm holds AMGM entry.
0059  *
0060  * If no AMGM exists for given gid, *index = -1, *prev = index of last
0061  * entry in hash chain and *mgm holds end of hash chain.
0062  */
0063 static int find_mgm(struct mthca_dev *dev,
0064             u8 *gid, struct mthca_mailbox *mgm_mailbox,
0065             u16 *hash, int *prev, int *index)
0066 {
0067     struct mthca_mailbox *mailbox;
0068     struct mthca_mgm *mgm = mgm_mailbox->buf;
0069     u8 *mgid;
0070     int err;
0071 
0072     mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
0073     if (IS_ERR(mailbox))
0074         return -ENOMEM;
0075     mgid = mailbox->buf;
0076 
0077     memcpy(mgid, gid, 16);
0078 
0079     err = mthca_MGID_HASH(dev, mailbox, hash);
0080     if (err) {
0081         mthca_err(dev, "MGID_HASH failed (%d)\n", err);
0082         goto out;
0083     }
0084 
0085     if (0)
0086         mthca_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash);
0087 
0088     *index = *hash;
0089     *prev  = -1;
0090 
0091     do {
0092         err = mthca_READ_MGM(dev, *index, mgm_mailbox);
0093         if (err) {
0094             mthca_err(dev, "READ_MGM failed (%d)\n", err);
0095             goto out;
0096         }
0097 
0098         if (!memcmp(mgm->gid, zero_gid, 16)) {
0099             if (*index != *hash) {
0100                 mthca_err(dev, "Found zero MGID in AMGM.\n");
0101                 err = -EINVAL;
0102             }
0103             goto out;
0104         }
0105 
0106         if (!memcmp(mgm->gid, gid, 16))
0107             goto out;
0108 
0109         *prev = *index;
0110         *index = be32_to_cpu(mgm->next_gid_index) >> 6;
0111     } while (*index);
0112 
0113     *index = -1;
0114 
0115  out:
0116     mthca_free_mailbox(dev, mailbox);
0117     return err;
0118 }
0119 
0120 int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
0121 {
0122     struct mthca_dev *dev = to_mdev(ibqp->device);
0123     struct mthca_mailbox *mailbox;
0124     struct mthca_mgm *mgm;
0125     u16 hash;
0126     int index, prev;
0127     int link = 0;
0128     int i;
0129     int err;
0130 
0131     mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
0132     if (IS_ERR(mailbox))
0133         return PTR_ERR(mailbox);
0134     mgm = mailbox->buf;
0135 
0136     mutex_lock(&dev->mcg_table.mutex);
0137 
0138     err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
0139     if (err)
0140         goto out;
0141 
0142     if (index != -1) {
0143         if (!memcmp(mgm->gid, zero_gid, 16))
0144             memcpy(mgm->gid, gid->raw, 16);
0145     } else {
0146         link = 1;
0147 
0148         index = mthca_alloc(&dev->mcg_table.alloc);
0149         if (index == -1) {
0150             mthca_err(dev, "No AMGM entries left\n");
0151             err = -ENOMEM;
0152             goto out;
0153         }
0154 
0155         err = mthca_READ_MGM(dev, index, mailbox);
0156         if (err) {
0157             mthca_err(dev, "READ_MGM failed (%d)\n", err);
0158             goto out;
0159         }
0160         memset(mgm, 0, sizeof *mgm);
0161         memcpy(mgm->gid, gid->raw, 16);
0162     }
0163 
0164     for (i = 0; i < MTHCA_QP_PER_MGM; ++i)
0165         if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) {
0166             mthca_dbg(dev, "QP %06x already a member of MGM\n",
0167                   ibqp->qp_num);
0168             err = 0;
0169             goto out;
0170         } else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) {
0171             mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31));
0172             break;
0173         }
0174 
0175     if (i == MTHCA_QP_PER_MGM) {
0176         mthca_err(dev, "MGM at index %x is full.\n", index);
0177         err = -ENOMEM;
0178         goto out;
0179     }
0180 
0181     err = mthca_WRITE_MGM(dev, index, mailbox);
0182     if (err) {
0183         mthca_err(dev, "WRITE_MGM failed %d\n", err);
0184         err = -EINVAL;
0185         goto out;
0186     }
0187 
0188     if (!link)
0189         goto out;
0190 
0191     err = mthca_READ_MGM(dev, prev, mailbox);
0192     if (err) {
0193         mthca_err(dev, "READ_MGM failed %d\n", err);
0194         goto out;
0195     }
0196 
0197     mgm->next_gid_index = cpu_to_be32(index << 6);
0198 
0199     err = mthca_WRITE_MGM(dev, prev, mailbox);
0200     if (err)
0201         mthca_err(dev, "WRITE_MGM returned %d\n", err);
0202 
0203  out:
0204     if (err && link && index != -1) {
0205         BUG_ON(index < dev->limits.num_mgms);
0206         mthca_free(&dev->mcg_table.alloc, index);
0207     }
0208     mutex_unlock(&dev->mcg_table.mutex);
0209 
0210     mthca_free_mailbox(dev, mailbox);
0211     return err;
0212 }
0213 
0214 int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
0215 {
0216     struct mthca_dev *dev = to_mdev(ibqp->device);
0217     struct mthca_mailbox *mailbox;
0218     struct mthca_mgm *mgm;
0219     u16 hash;
0220     int prev, index;
0221     int i, loc;
0222     int err;
0223 
0224     mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
0225     if (IS_ERR(mailbox))
0226         return PTR_ERR(mailbox);
0227     mgm = mailbox->buf;
0228 
0229     mutex_lock(&dev->mcg_table.mutex);
0230 
0231     err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
0232     if (err)
0233         goto out;
0234 
0235     if (index == -1) {
0236         mthca_err(dev, "MGID %pI6 not found\n", gid->raw);
0237         err = -EINVAL;
0238         goto out;
0239     }
0240 
0241     for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) {
0242         if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31)))
0243             loc = i;
0244         if (!(mgm->qp[i] & cpu_to_be32(1 << 31)))
0245             break;
0246     }
0247 
0248     if (loc == -1) {
0249         mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num);
0250         err = -EINVAL;
0251         goto out;
0252     }
0253 
0254     mgm->qp[loc]   = mgm->qp[i - 1];
0255     mgm->qp[i - 1] = 0;
0256 
0257     err = mthca_WRITE_MGM(dev, index, mailbox);
0258     if (err) {
0259         mthca_err(dev, "WRITE_MGM returned %d\n", err);
0260         goto out;
0261     }
0262 
0263     if (i != 1)
0264         goto out;
0265 
0266     if (prev == -1) {
0267         /* Remove entry from MGM */
0268         int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6;
0269         if (amgm_index_to_free) {
0270             err = mthca_READ_MGM(dev, amgm_index_to_free,
0271                          mailbox);
0272             if (err) {
0273                 mthca_err(dev, "READ_MGM returned %d\n", err);
0274                 goto out;
0275             }
0276         } else
0277             memset(mgm->gid, 0, 16);
0278 
0279         err = mthca_WRITE_MGM(dev, index, mailbox);
0280         if (err) {
0281             mthca_err(dev, "WRITE_MGM returned %d\n", err);
0282             goto out;
0283         }
0284         if (amgm_index_to_free) {
0285             BUG_ON(amgm_index_to_free < dev->limits.num_mgms);
0286             mthca_free(&dev->mcg_table.alloc, amgm_index_to_free);
0287         }
0288     } else {
0289         /* Remove entry from AMGM */
0290         int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
0291         err = mthca_READ_MGM(dev, prev, mailbox);
0292         if (err) {
0293             mthca_err(dev, "READ_MGM returned %d\n", err);
0294             goto out;
0295         }
0296 
0297         mgm->next_gid_index = cpu_to_be32(curr_next_index << 6);
0298 
0299         err = mthca_WRITE_MGM(dev, prev, mailbox);
0300         if (err) {
0301             mthca_err(dev, "WRITE_MGM returned %d\n", err);
0302             goto out;
0303         }
0304         BUG_ON(index < dev->limits.num_mgms);
0305         mthca_free(&dev->mcg_table.alloc, index);
0306     }
0307 
0308  out:
0309     mutex_unlock(&dev->mcg_table.mutex);
0310 
0311     mthca_free_mailbox(dev, mailbox);
0312     return err;
0313 }
0314 
0315 int mthca_init_mcg_table(struct mthca_dev *dev)
0316 {
0317     int err;
0318     int table_size = dev->limits.num_mgms + dev->limits.num_amgms;
0319 
0320     err = mthca_alloc_init(&dev->mcg_table.alloc,
0321                    table_size,
0322                    table_size - 1,
0323                    dev->limits.num_mgms);
0324     if (err)
0325         return err;
0326 
0327     mutex_init(&dev->mcg_table.mutex);
0328 
0329     return 0;
0330 }
0331 
0332 void mthca_cleanup_mcg_table(struct mthca_dev *dev)
0333 {
0334     mthca_alloc_cleanup(&dev->mcg_table.alloc);
0335 }