mthca_mcg.c revision ed878458eeff9754d66f1b0325df6ebbfcdce668
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 40enum { 41 MTHCA_QP_PER_MGM = 4 * (MTHCA_MGM_ENTRY_SIZE / 16 - 2) 42}; 43 44struct mthca_mgm { 45 u32 next_gid_index; 46 u32 reserved[3]; 47 u8 gid[16]; 48 u32 qp[MTHCA_QP_PER_MGM]; 49}; 50 51static const u8 zero_gid[16]; /* automatically initialized to 0 */ 52 53/* 54 * Caller must hold MCG table semaphore. gid and mgm parameters must 55 * be properly aligned for command interface. 56 * 57 * Returns 0 unless a firmware command error occurs. 58 * 59 * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 60 * and *mgm holds MGM entry. 61 * 62 * if GID is found in AMGM, *index = index in AMGM, *prev = index of 63 * previous entry in hash chain and *mgm holds AMGM entry. 64 * 65 * If no AMGM exists for given gid, *index = -1, *prev = index of last 66 * entry in hash chain and *mgm holds end of hash chain. 67 */ 68static int find_mgm(struct mthca_dev *dev, 69 u8 *gid, struct mthca_mailbox *mgm_mailbox, 70 u16 *hash, int *prev, int *index) 71{ 72 struct mthca_mailbox *mailbox; 73 struct mthca_mgm *mgm = mgm_mailbox->buf; 74 u8 *mgid; 75 int err; 76 u8 status; 77 78 mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 79 if (IS_ERR(mailbox)) 80 return -ENOMEM; 81 mgid = mailbox->buf; 82 83 memcpy(mgid, gid, 16); 84 85 err = mthca_MGID_HASH(dev, mailbox, hash, &status); 86 if (err) 87 goto out; 88 if (status) { 89 mthca_err(dev, "MGID_HASH returned status %02x\n", status); 90 err = -EINVAL; 91 goto out; 92 } 93 94 if (0) 95 mthca_dbg(dev, "Hash for %04x:%04x:%04x:%04x:" 96 "%04x:%04x:%04x:%04x is %04x\n", 97 be16_to_cpu(((u16 *) gid)[0]), be16_to_cpu(((u16 *) gid)[1]), 98 be16_to_cpu(((u16 *) gid)[2]), be16_to_cpu(((u16 *) gid)[3]), 99 be16_to_cpu(((u16 *) gid)[4]), be16_to_cpu(((u16 *) gid)[5]), 100 be16_to_cpu(((u16 *) gid)[6]), be16_to_cpu(((u16 *) 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(1 << 31))) { 189 mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31)); 190 break; 191 } 192 193 if (i == MTHCA_QP_PER_MGM) { 194 mthca_err(dev, "MGM at index %x is full.\n", index); 195 err = -ENOMEM; 196 goto out; 197 } 198 199 err = mthca_WRITE_MGM(dev, index, mailbox, &status); 200 if (err) 201 goto out; 202 if (status) { 203 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 204 err = -EINVAL; 205 } 206 207 if (!link) 208 goto out; 209 210 err = mthca_READ_MGM(dev, prev, mailbox, &status); 211 if (err) 212 goto out; 213 if (status) { 214 mthca_err(dev, "READ_MGM returned status %02x\n", status); 215 err = -EINVAL; 216 goto out; 217 } 218 219 mgm->next_gid_index = cpu_to_be32(index << 5); 220 221 err = mthca_WRITE_MGM(dev, prev, mailbox, &status); 222 if (err) 223 goto out; 224 if (status) { 225 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 226 err = -EINVAL; 227 } 228 229 out: 230 up(&dev->mcg_table.sem); 231 mthca_free_mailbox(dev, mailbox); 232 return err; 233} 234 235int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 236{ 237 struct mthca_dev *dev = to_mdev(ibqp->device); 238 struct mthca_mailbox *mailbox; 239 struct mthca_mgm *mgm; 240 u16 hash; 241 int prev, index; 242 int i, loc; 243 int err; 244 u8 status; 245 246 mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 247 if (IS_ERR(mailbox)) 248 return PTR_ERR(mailbox); 249 mgm = mailbox->buf; 250 251 if (down_interruptible(&dev->mcg_table.sem)) 252 return -EINTR; 253 254 err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); 255 if (err) 256 goto out; 257 258 if (index == -1) { 259 mthca_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " 260 "not found\n", 261 be16_to_cpu(((u16 *) gid->raw)[0]), 262 be16_to_cpu(((u16 *) gid->raw)[1]), 263 be16_to_cpu(((u16 *) gid->raw)[2]), 264 be16_to_cpu(((u16 *) gid->raw)[3]), 265 be16_to_cpu(((u16 *) gid->raw)[4]), 266 be16_to_cpu(((u16 *) gid->raw)[5]), 267 be16_to_cpu(((u16 *) gid->raw)[6]), 268 be16_to_cpu(((u16 *) gid->raw)[7])); 269 err = -EINVAL; 270 goto out; 271 } 272 273 for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) { 274 if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) 275 loc = i; 276 if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) 277 break; 278 } 279 280 if (loc == -1) { 281 mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num); 282 err = -EINVAL; 283 goto out; 284 } 285 286 mgm->qp[loc] = mgm->qp[i - 1]; 287 mgm->qp[i - 1] = 0; 288 289 err = mthca_WRITE_MGM(dev, index, mailbox, &status); 290 if (err) 291 goto out; 292 if (status) { 293 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 294 err = -EINVAL; 295 goto out; 296 } 297 298 if (i != 1) 299 goto out; 300 301 goto out; 302 303 if (prev == -1) { 304 /* Remove entry from MGM */ 305 if (be32_to_cpu(mgm->next_gid_index) >> 5) { 306 err = mthca_READ_MGM(dev, 307 be32_to_cpu(mgm->next_gid_index) >> 5, 308 mailbox, &status); 309 if (err) 310 goto out; 311 if (status) { 312 mthca_err(dev, "READ_MGM returned status %02x\n", 313 status); 314 err = -EINVAL; 315 goto out; 316 } 317 } else 318 memset(mgm->gid, 0, 16); 319 320 err = mthca_WRITE_MGM(dev, index, mailbox, &status); 321 if (err) 322 goto out; 323 if (status) { 324 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 325 err = -EINVAL; 326 goto out; 327 } 328 } else { 329 /* Remove entry from AMGM */ 330 index = be32_to_cpu(mgm->next_gid_index) >> 5; 331 err = mthca_READ_MGM(dev, prev, mailbox, &status); 332 if (err) 333 goto out; 334 if (status) { 335 mthca_err(dev, "READ_MGM returned status %02x\n", status); 336 err = -EINVAL; 337 goto out; 338 } 339 340 mgm->next_gid_index = cpu_to_be32(index << 5); 341 342 err = mthca_WRITE_MGM(dev, prev, mailbox, &status); 343 if (err) 344 goto out; 345 if (status) { 346 mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 347 err = -EINVAL; 348 goto out; 349 } 350 } 351 352 out: 353 up(&dev->mcg_table.sem); 354 mthca_free_mailbox(dev, mailbox); 355 return err; 356} 357 358int __devinit mthca_init_mcg_table(struct mthca_dev *dev) 359{ 360 int err; 361 362 err = mthca_alloc_init(&dev->mcg_table.alloc, 363 dev->limits.num_amgms, 364 dev->limits.num_amgms - 1, 365 0); 366 if (err) 367 return err; 368 369 init_MUTEX(&dev->mcg_table.sem); 370 371 return 0; 372} 373 374void __devexit mthca_cleanup_mcg_table(struct mthca_dev *dev) 375{ 376 mthca_alloc_cleanup(&dev->mcg_table.alloc); 377} 378