1 /* 2 * Copyright (c) 2004 Topspin Communications. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * 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 OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 * 32 * $Id: mthca_mcg.c 1349 2004-12-16 21:09:43Z roland $ 33 */ 34 35 #include <linux/string.h> 36 #include <linux/slab.h> 37 38 #include "mthca_dev.h" 39 #include "mthca_cmd.h" 40 41 struct mthca_mgm { 42 __be32 next_gid_index; 43 u32 reserved[3]; 44 u8 gid[16]; 45 __be32 qp[MTHCA_QP_PER_MGM]; 46 }; 47 48 static const u8 zero_gid[16]; /* automatically initialized to 0 */ 49 50 /* 51 * Caller must hold MCG table semaphore. gid and mgm parameters must 52 * be properly aligned for command interface. 53 * 54 * Returns 0 unless a firmware command error occurs. 55 * 56 * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 57 * and *mgm holds MGM entry. 58 * 59 * if GID is found in AMGM, *index = index in AMGM, *prev = index of 60 * previous entry in hash chain and *mgm holds AMGM entry. 61 * 62 * If no AMGM exists for given gid, *index = -1, *prev = index of last 63 * entry in hash chain and *mgm holds end of hash chain. 64 */ 65 static int find_mgm(struct mthca_dev *dev, 66 u8 *gid, struct mthca_mailbox *mgm_mailbox, 67 u16 *hash, int *prev, int *index) 68 { 69 struct mthca_mailbox *mailbox; 70 struct mthca_mgm *mgm = mgm_mailbox->buf; 71 u8 *mgid; 72 int err; 73 u8 status; 74 75 mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 76 if (IS_ERR(mailbox)) 77 return -ENOMEM; 78 mgid = mailbox->buf; 79 80 memcpy(mgid, gid, 16); 81 82 err = mthca_MGID_HASH(dev, mailbox, hash, &status); 83 if (err) 84 goto out; 85 if (status) { 86 mthca_err(dev, "MGID_HASH returned status %02x\n", status); 87 err = -EINVAL; 88 goto out; 89 } 90 91 if (0) 92 mthca_dbg(dev, "Hash for %04x:%04x:%04x:%04x:" 93 "%04x:%04x:%04x:%04x is %04x\n", 94 be16_to_cpu(((__be16 *) gid)[0]), 95 be16_to_cpu(((__be16 *) gid)[1]), 96 be16_to_cpu(((__be16 *) gid)[2]), 97 be16_to_cpu(((__be16 *) gid)[3]), 98 be16_to_cpu(((__be16 *) gid)[4]), 99 be16_to_cpu(((__be16 *) gid)[5]), 100 be16_to_cpu(((__be16 *) gid)[6]), 101 be16_to_cpu(((__be16 *) gid)[7]), 102 *hash); 103 104 *index = *hash; 105 *prev = -1; 106 107 do { 108 err = mthca_READ_MGM(dev, *index, mgm_mailbox, &status); 109 if (err) 110 goto out; 111 if (status) { 112 mthca_err(dev, "READ_MGM returned status %02x\n", status); 113 err = -EINVAL; 114 goto out; 115 } 116 117 if (!memcmp(mgm->gid, zero_gid, 16)) { 118 if (*index != *hash) { 119 mthca_err(dev, "Found zero MGID in AMGM.\n"); 120 err = -EINVAL; 121 } 122 goto out; 123 } 124 125 if (!memcmp(mgm->gid, gid, 16)) 126 goto out; 127 128 *prev = *index; 129 *index = be32_to_cpu(mgm->next_gid_index) >> 6; 130 } while (*index); 131 132 *index = -1; 133 134 out: 135 mthca_free_mailbox(dev, mailbox); 136 return err; 137 } 138 139 int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 140 { 141 struct mthca_dev *dev = to_mdev(ibqp->device); 142 struct mthca_mailbox *mailbox; 143 struct mthca_mgm *mgm; 144 u16 hash; 145 int index, prev; 146 int link = 0; 147 int i; 148 int err; 149 u8 status; 150 151 mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 152 if (IS_ERR(mailbox)) 153 return PTR_ERR(mailbox); 154 mgm = mailbox->buf; 155 156 mutex_lock(&dev->mcg_table.mutex); 157 158 err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); 159 if (err) 160 goto out; 161 162 if (index != -1) { 163 if (!memcmp(mgm->gid, zero_gid, 16)) 164 memcpy(mgm->gid, gid->raw, 16); 165 } else { 166 link = 1; 167 168 index = mthca_alloc(&dev->mcg_table.alloc); 169 if (index == -1) { 170 mthca_err(dev, "No AMGM entries left\n"); 171 err = -ENOMEM; 172 goto out; 173 } 174 175 err = mthca_READ_MGM(dev, index, mailbox, &status); 176 if (err) 177 goto out; 178 if (status) { 179 mthca_err(dev, "READ_MGM returned status %02x\n", status); 180 err = -EINVAL; 181 goto out; 182 } 183 memset(mgm, 0, sizeof *mgm); 184 memcpy(mgm->gid, gid->raw, 16); 185 } 186 187 for (i = 0; i < MTHCA_QP_PER_MGM; ++i) 188 if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) { 189 mthca_dbg(dev, "QP %06x already a member of MGM\n", 190 ibqp->qp_num); 191 err = 0; 192 goto out; 193 } else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) { 194 mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31)); 195 break; 196 } 197 198 if (i == MTHCA_QP_PER_MGM) { 199 mthca_err(dev, "MGM at index %x is full.\n", index); 200 err = -ENOMEM; 201 goto out; 202 } 203 204 err = mthca_WRITE_MGM(dev, index, mailbox, &status); 205 if (err) 206 goto out; 207 if (status) { 208 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 209 err = -EINVAL; 210 goto out; 211 } 212 213 if (!link) 214 goto out; 215 216 err = mthca_READ_MGM(dev, prev, mailbox, &status); 217 if (err) 218 goto out; 219 if (status) { 220 mthca_err(dev, "READ_MGM returned status %02x\n", status); 221 err = -EINVAL; 222 goto out; 223 } 224 225 mgm->next_gid_index = cpu_to_be32(index << 6); 226 227 err = mthca_WRITE_MGM(dev, prev, mailbox, &status); 228 if (err) 229 goto out; 230 if (status) { 231 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 232 err = -EINVAL; 233 } 234 235 out: 236 if (err && link && index != -1) { 237 BUG_ON(index < dev->limits.num_mgms); 238 mthca_free(&dev->mcg_table.alloc, index); 239 } 240 mutex_unlock(&dev->mcg_table.mutex); 241 242 mthca_free_mailbox(dev, mailbox); 243 return err; 244 } 245 246 int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 247 { 248 struct mthca_dev *dev = to_mdev(ibqp->device); 249 struct mthca_mailbox *mailbox; 250 struct mthca_mgm *mgm; 251 u16 hash; 252 int prev, index; 253 int i, loc; 254 int err; 255 u8 status; 256 257 mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 258 if (IS_ERR(mailbox)) 259 return PTR_ERR(mailbox); 260 mgm = mailbox->buf; 261 262 mutex_lock(&dev->mcg_table.mutex); 263 264 err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); 265 if (err) 266 goto out; 267 268 if (index == -1) { 269 mthca_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " 270 "not found\n", 271 be16_to_cpu(((__be16 *) gid->raw)[0]), 272 be16_to_cpu(((__be16 *) gid->raw)[1]), 273 be16_to_cpu(((__be16 *) gid->raw)[2]), 274 be16_to_cpu(((__be16 *) gid->raw)[3]), 275 be16_to_cpu(((__be16 *) gid->raw)[4]), 276 be16_to_cpu(((__be16 *) gid->raw)[5]), 277 be16_to_cpu(((__be16 *) gid->raw)[6]), 278 be16_to_cpu(((__be16 *) gid->raw)[7])); 279 err = -EINVAL; 280 goto out; 281 } 282 283 for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) { 284 if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) 285 loc = i; 286 if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) 287 break; 288 } 289 290 if (loc == -1) { 291 mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num); 292 err = -EINVAL; 293 goto out; 294 } 295 296 mgm->qp[loc] = mgm->qp[i - 1]; 297 mgm->qp[i - 1] = 0; 298 299 err = mthca_WRITE_MGM(dev, index, mailbox, &status); 300 if (err) 301 goto out; 302 if (status) { 303 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 304 err = -EINVAL; 305 goto out; 306 } 307 308 if (i != 1) 309 goto out; 310 311 if (prev == -1) { 312 /* Remove entry from MGM */ 313 int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6; 314 if (amgm_index_to_free) { 315 err = mthca_READ_MGM(dev, amgm_index_to_free, 316 mailbox, &status); 317 if (err) 318 goto out; 319 if (status) { 320 mthca_err(dev, "READ_MGM returned status %02x\n", 321 status); 322 err = -EINVAL; 323 goto out; 324 } 325 } else 326 memset(mgm->gid, 0, 16); 327 328 err = mthca_WRITE_MGM(dev, index, mailbox, &status); 329 if (err) 330 goto out; 331 if (status) { 332 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 333 err = -EINVAL; 334 goto out; 335 } 336 if (amgm_index_to_free) { 337 BUG_ON(amgm_index_to_free < dev->limits.num_mgms); 338 mthca_free(&dev->mcg_table.alloc, amgm_index_to_free); 339 } 340 } else { 341 /* Remove entry from AMGM */ 342 int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; 343 err = mthca_READ_MGM(dev, prev, mailbox, &status); 344 if (err) 345 goto out; 346 if (status) { 347 mthca_err(dev, "READ_MGM returned status %02x\n", status); 348 err = -EINVAL; 349 goto out; 350 } 351 352 mgm->next_gid_index = cpu_to_be32(curr_next_index << 6); 353 354 err = mthca_WRITE_MGM(dev, prev, mailbox, &status); 355 if (err) 356 goto out; 357 if (status) { 358 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 359 err = -EINVAL; 360 goto out; 361 } 362 BUG_ON(index < dev->limits.num_mgms); 363 mthca_free(&dev->mcg_table.alloc, index); 364 } 365 366 out: 367 mutex_unlock(&dev->mcg_table.mutex); 368 369 mthca_free_mailbox(dev, mailbox); 370 return err; 371 } 372 373 int mthca_init_mcg_table(struct mthca_dev *dev) 374 { 375 int err; 376 int table_size = dev->limits.num_mgms + dev->limits.num_amgms; 377 378 err = mthca_alloc_init(&dev->mcg_table.alloc, 379 table_size, 380 table_size - 1, 381 dev->limits.num_mgms); 382 if (err) 383 return err; 384 385 mutex_init(&dev->mcg_table.mutex); 386 387 return 0; 388 } 389 390 void mthca_cleanup_mcg_table(struct mthca_dev *dev) 391 { 392 mthca_alloc_cleanup(&dev->mcg_table.alloc); 393 } 394