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 return -EINVAL; 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) >> 5; 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 if (down_interruptible(&dev->mcg_table.sem)) 157 return -EINTR; 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 185 memcpy(mgm->gid, gid->raw, 16); 186 mgm->next_gid_index = 0; 187 } 188 189 for (i = 0; i < MTHCA_QP_PER_MGM; ++i) 190 if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) { 191 mthca_dbg(dev, "QP %06x already a member of MGM\n", 192 ibqp->qp_num); 193 err = 0; 194 goto out; 195 } else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) { 196 mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31)); 197 break; 198 } 199 200 if (i == MTHCA_QP_PER_MGM) { 201 mthca_err(dev, "MGM at index %x is full.\n", index); 202 err = -ENOMEM; 203 goto out; 204 } 205 206 err = mthca_WRITE_MGM(dev, index, mailbox, &status); 207 if (err) 208 goto out; 209 if (status) { 210 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 211 err = -EINVAL; 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 << 5); 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 up(&dev->mcg_table.sem); 238 mthca_free_mailbox(dev, mailbox); 239 return err; 240 } 241 242 int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 243 { 244 struct mthca_dev *dev = to_mdev(ibqp->device); 245 struct mthca_mailbox *mailbox; 246 struct mthca_mgm *mgm; 247 u16 hash; 248 int prev, index; 249 int i, loc; 250 int err; 251 u8 status; 252 253 mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 254 if (IS_ERR(mailbox)) 255 return PTR_ERR(mailbox); 256 mgm = mailbox->buf; 257 258 if (down_interruptible(&dev->mcg_table.sem)) 259 return -EINTR; 260 261 err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); 262 if (err) 263 goto out; 264 265 if (index == -1) { 266 mthca_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " 267 "not found\n", 268 be16_to_cpu(((__be16 *) gid->raw)[0]), 269 be16_to_cpu(((__be16 *) gid->raw)[1]), 270 be16_to_cpu(((__be16 *) gid->raw)[2]), 271 be16_to_cpu(((__be16 *) gid->raw)[3]), 272 be16_to_cpu(((__be16 *) gid->raw)[4]), 273 be16_to_cpu(((__be16 *) gid->raw)[5]), 274 be16_to_cpu(((__be16 *) gid->raw)[6]), 275 be16_to_cpu(((__be16 *) gid->raw)[7])); 276 err = -EINVAL; 277 goto out; 278 } 279 280 for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) { 281 if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) 282 loc = i; 283 if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) 284 break; 285 } 286 287 if (loc == -1) { 288 mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num); 289 err = -EINVAL; 290 goto out; 291 } 292 293 mgm->qp[loc] = mgm->qp[i - 1]; 294 mgm->qp[i - 1] = 0; 295 296 err = mthca_WRITE_MGM(dev, index, mailbox, &status); 297 if (err) 298 goto out; 299 if (status) { 300 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 301 err = -EINVAL; 302 goto out; 303 } 304 305 if (i != 1) 306 goto out; 307 308 goto out; 309 310 if (prev == -1) { 311 /* Remove entry from MGM */ 312 if (be32_to_cpu(mgm->next_gid_index) >> 5) { 313 err = mthca_READ_MGM(dev, 314 be32_to_cpu(mgm->next_gid_index) >> 5, 315 mailbox, &status); 316 if (err) 317 goto out; 318 if (status) { 319 mthca_err(dev, "READ_MGM returned status %02x\n", 320 status); 321 err = -EINVAL; 322 goto out; 323 } 324 } else 325 memset(mgm->gid, 0, 16); 326 327 err = mthca_WRITE_MGM(dev, index, mailbox, &status); 328 if (err) 329 goto out; 330 if (status) { 331 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 332 err = -EINVAL; 333 goto out; 334 } 335 } else { 336 /* Remove entry from AMGM */ 337 index = be32_to_cpu(mgm->next_gid_index) >> 5; 338 err = mthca_READ_MGM(dev, prev, mailbox, &status); 339 if (err) 340 goto out; 341 if (status) { 342 mthca_err(dev, "READ_MGM returned status %02x\n", status); 343 err = -EINVAL; 344 goto out; 345 } 346 347 mgm->next_gid_index = cpu_to_be32(index << 5); 348 349 err = mthca_WRITE_MGM(dev, prev, mailbox, &status); 350 if (err) 351 goto out; 352 if (status) { 353 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 354 err = -EINVAL; 355 goto out; 356 } 357 } 358 359 out: 360 up(&dev->mcg_table.sem); 361 mthca_free_mailbox(dev, mailbox); 362 return err; 363 } 364 365 int __devinit mthca_init_mcg_table(struct mthca_dev *dev) 366 { 367 int err; 368 369 err = mthca_alloc_init(&dev->mcg_table.alloc, 370 dev->limits.num_amgms, 371 dev->limits.num_amgms - 1, 372 0); 373 if (err) 374 return err; 375 376 init_MUTEX(&dev->mcg_table.sem); 377 378 return 0; 379 } 380 381 void __devexit mthca_cleanup_mcg_table(struct mthca_dev *dev) 382 { 383 mthca_alloc_cleanup(&dev->mcg_table.alloc); 384 } 385