0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
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];
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
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
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
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 }