mthca_mcg.c revision 5ceb74557c71465cf8f6fda050aac00e53f9ad3d
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 42struct mthca_mgm { 43 __be32 next_gid_index; 44 u32 reserved[3]; 45 u8 gid[16]; 46 __be32 qp[MTHCA_QP_PER_MGM]; 47}; 48 49static 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 */ 66static 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 140int 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 if (down_interruptible(&dev->mcg_table.sem)) { 158 err = -EINTR; 159 goto err_sem; 160 } 161 162 err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); 163 if (err) 164 goto out; 165 166 if (index != -1) { 167 if (!memcmp(mgm->gid, zero_gid, 16)) 168 memcpy(mgm->gid, gid->raw, 16); 169 } else { 170 link = 1; 171 172 index = mthca_alloc(&dev->mcg_table.alloc); 173 if (index == -1) { 174 mthca_err(dev, "No AMGM entries left\n"); 175 err = -ENOMEM; 176 goto out; 177 } 178 179 err = mthca_READ_MGM(dev, index, mailbox, &status); 180 if (err) 181 goto out; 182 if (status) { 183 mthca_err(dev, "READ_MGM returned status %02x\n", status); 184 err = -EINVAL; 185 goto out; 186 } 187 memset(mgm, 0, sizeof *mgm); 188 memcpy(mgm->gid, gid->raw, 16); 189 } 190 191 for (i = 0; i < MTHCA_QP_PER_MGM; ++i) 192 if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) { 193 mthca_dbg(dev, "QP %06x already a member of MGM\n", 194 ibqp->qp_num); 195 err = 0; 196 goto out; 197 } else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) { 198 mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31)); 199 break; 200 } 201 202 if (i == MTHCA_QP_PER_MGM) { 203 mthca_err(dev, "MGM at index %x is full.\n", index); 204 err = -ENOMEM; 205 goto out; 206 } 207 208 err = mthca_WRITE_MGM(dev, index, mailbox, &status); 209 if (err) 210 goto out; 211 if (status) { 212 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 213 err = -EINVAL; 214 goto out; 215 } 216 217 if (!link) 218 goto out; 219 220 err = mthca_READ_MGM(dev, prev, mailbox, &status); 221 if (err) 222 goto out; 223 if (status) { 224 mthca_err(dev, "READ_MGM returned status %02x\n", status); 225 err = -EINVAL; 226 goto out; 227 } 228 229 mgm->next_gid_index = cpu_to_be32(index << 6); 230 231 err = mthca_WRITE_MGM(dev, prev, mailbox, &status); 232 if (err) 233 goto out; 234 if (status) { 235 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 236 err = -EINVAL; 237 } 238 239 out: 240 if (err && link && index != -1) { 241 BUG_ON(index < dev->limits.num_mgms); 242 mthca_free(&dev->mcg_table.alloc, index); 243 } 244 up(&dev->mcg_table.sem); 245 err_sem: 246 mthca_free_mailbox(dev, mailbox); 247 return err; 248} 249 250int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 251{ 252 struct mthca_dev *dev = to_mdev(ibqp->device); 253 struct mthca_mailbox *mailbox; 254 struct mthca_mgm *mgm; 255 u16 hash; 256 int prev, index; 257 int i, loc; 258 int err; 259 u8 status; 260 261 mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 262 if (IS_ERR(mailbox)) 263 return PTR_ERR(mailbox); 264 mgm = mailbox->buf; 265 266 if (down_interruptible(&dev->mcg_table.sem)) { 267 err = -EINTR; 268 goto err_sem; 269 } 270 271 err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); 272 if (err) 273 goto out; 274 275 if (index == -1) { 276 mthca_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " 277 "not found\n", 278 be16_to_cpu(((__be16 *) gid->raw)[0]), 279 be16_to_cpu(((__be16 *) gid->raw)[1]), 280 be16_to_cpu(((__be16 *) gid->raw)[2]), 281 be16_to_cpu(((__be16 *) gid->raw)[3]), 282 be16_to_cpu(((__be16 *) gid->raw)[4]), 283 be16_to_cpu(((__be16 *) gid->raw)[5]), 284 be16_to_cpu(((__be16 *) gid->raw)[6]), 285 be16_to_cpu(((__be16 *) gid->raw)[7])); 286 err = -EINVAL; 287 goto out; 288 } 289 290 for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) { 291 if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) 292 loc = i; 293 if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) 294 break; 295 } 296 297 if (loc == -1) { 298 mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num); 299 err = -EINVAL; 300 goto out; 301 } 302 303 mgm->qp[loc] = mgm->qp[i - 1]; 304 mgm->qp[i - 1] = 0; 305 306 err = mthca_WRITE_MGM(dev, index, mailbox, &status); 307 if (err) 308 goto out; 309 if (status) { 310 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 311 err = -EINVAL; 312 goto out; 313 } 314 315 if (i != 1) 316 goto out; 317 318 if (prev == -1) { 319 /* Remove entry from MGM */ 320 int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6; 321 if (amgm_index_to_free) { 322 err = mthca_READ_MGM(dev, amgm_index_to_free, 323 mailbox, &status); 324 if (err) 325 goto out; 326 if (status) { 327 mthca_err(dev, "READ_MGM returned status %02x\n", 328 status); 329 err = -EINVAL; 330 goto out; 331 } 332 } else 333 memset(mgm->gid, 0, 16); 334 335 err = mthca_WRITE_MGM(dev, index, mailbox, &status); 336 if (err) 337 goto out; 338 if (status) { 339 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 340 err = -EINVAL; 341 goto out; 342 } 343 if (amgm_index_to_free) { 344 BUG_ON(amgm_index_to_free < dev->limits.num_mgms); 345 mthca_free(&dev->mcg_table.alloc, amgm_index_to_free); 346 } 347 } else { 348 /* Remove entry from AMGM */ 349 int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; 350 err = mthca_READ_MGM(dev, prev, mailbox, &status); 351 if (err) 352 goto out; 353 if (status) { 354 mthca_err(dev, "READ_MGM returned status %02x\n", status); 355 err = -EINVAL; 356 goto out; 357 } 358 359 mgm->next_gid_index = cpu_to_be32(curr_next_index << 6); 360 361 err = mthca_WRITE_MGM(dev, prev, mailbox, &status); 362 if (err) 363 goto out; 364 if (status) { 365 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 366 err = -EINVAL; 367 goto out; 368 } 369 BUG_ON(index < dev->limits.num_mgms); 370 mthca_free(&dev->mcg_table.alloc, index); 371 } 372 373 out: 374 up(&dev->mcg_table.sem); 375 err_sem: 376 mthca_free_mailbox(dev, mailbox); 377 return err; 378} 379 380int __devinit mthca_init_mcg_table(struct mthca_dev *dev) 381{ 382 int err; 383 int table_size = dev->limits.num_mgms + dev->limits.num_amgms; 384 385 err = mthca_alloc_init(&dev->mcg_table.alloc, 386 table_size, 387 table_size - 1, 388 dev->limits.num_mgms); 389 if (err) 390 return err; 391 392 init_MUTEX(&dev->mcg_table.sem); 393 394 return 0; 395} 396 397void __devexit mthca_cleanup_mcg_table(struct mthca_dev *dev) 398{ 399 mthca_alloc_cleanup(&dev->mcg_table.alloc); 400} 401