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