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