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