linux/drivers/infiniband/hw/mthca/mthca_mcg.c
<<
>>
Prefs
   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/gfp.h>
  35
  36#include "mthca_dev.h"
  37#include "mthca_cmd.h"
  38
  39struct mthca_mgm {
  40        __be32 next_gid_index;
  41        u32    reserved[3];
  42        u8     gid[16];
  43        __be32 qp[MTHCA_QP_PER_MGM];
  44};
  45
  46static 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 */
  63static 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
  72        mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
  73        if (IS_ERR(mailbox))
  74                return -ENOMEM;
  75        mgid = mailbox->buf;
  76
  77        memcpy(mgid, gid, 16);
  78
  79        err = mthca_MGID_HASH(dev, mailbox, hash);
  80        if (err) {
  81                mthca_err(dev, "MGID_HASH failed (%d)\n", err);
  82                goto out;
  83        }
  84
  85        if (0)
  86                mthca_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash);
  87
  88        *index = *hash;
  89        *prev  = -1;
  90
  91        do {
  92                err = mthca_READ_MGM(dev, *index, mgm_mailbox);
  93                if (err) {
  94                        mthca_err(dev, "READ_MGM failed (%d)\n", err);
  95                        goto out;
  96                }
  97
  98                if (!memcmp(mgm->gid, zero_gid, 16)) {
  99                        if (*index != *hash) {
 100                                mthca_err(dev, "Found zero MGID in AMGM.\n");
 101                                err = -EINVAL;
 102                        }
 103                        goto out;
 104                }
 105
 106                if (!memcmp(mgm->gid, gid, 16))
 107                        goto out;
 108
 109                *prev = *index;
 110                *index = be32_to_cpu(mgm->next_gid_index) >> 6;
 111        } while (*index);
 112
 113        *index = -1;
 114
 115 out:
 116        mthca_free_mailbox(dev, mailbox);
 117        return err;
 118}
 119
 120int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 121{
 122        struct mthca_dev *dev = to_mdev(ibqp->device);
 123        struct mthca_mailbox *mailbox;
 124        struct mthca_mgm *mgm;
 125        u16 hash;
 126        int index, prev;
 127        int link = 0;
 128        int i;
 129        int err;
 130
 131        mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 132        if (IS_ERR(mailbox))
 133                return PTR_ERR(mailbox);
 134        mgm = mailbox->buf;
 135
 136        mutex_lock(&dev->mcg_table.mutex);
 137
 138        err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
 139        if (err)
 140                goto out;
 141
 142        if (index != -1) {
 143                if (!memcmp(mgm->gid, zero_gid, 16))
 144                        memcpy(mgm->gid, gid->raw, 16);
 145        } else {
 146                link = 1;
 147
 148                index = mthca_alloc(&dev->mcg_table.alloc);
 149                if (index == -1) {
 150                        mthca_err(dev, "No AMGM entries left\n");
 151                        err = -ENOMEM;
 152                        goto out;
 153                }
 154
 155                err = mthca_READ_MGM(dev, index, mailbox);
 156                if (err) {
 157                        mthca_err(dev, "READ_MGM failed (%d)\n", err);
 158                        goto out;
 159                }
 160                memset(mgm, 0, sizeof *mgm);
 161                memcpy(mgm->gid, gid->raw, 16);
 162        }
 163
 164        for (i = 0; i < MTHCA_QP_PER_MGM; ++i)
 165                if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) {
 166                        mthca_dbg(dev, "QP %06x already a member of MGM\n",
 167                                  ibqp->qp_num);
 168                        err = 0;
 169                        goto out;
 170                } else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) {
 171                        mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31));
 172                        break;
 173                }
 174
 175        if (i == MTHCA_QP_PER_MGM) {
 176                mthca_err(dev, "MGM at index %x is full.\n", index);
 177                err = -ENOMEM;
 178                goto out;
 179        }
 180
 181        err = mthca_WRITE_MGM(dev, index, mailbox);
 182        if (err) {
 183                mthca_err(dev, "WRITE_MGM failed %d\n", err);
 184                err = -EINVAL;
 185                goto out;
 186        }
 187
 188        if (!link)
 189                goto out;
 190
 191        err = mthca_READ_MGM(dev, prev, mailbox);
 192        if (err) {
 193                mthca_err(dev, "READ_MGM failed %d\n", err);
 194                goto out;
 195        }
 196
 197        mgm->next_gid_index = cpu_to_be32(index << 6);
 198
 199        err = mthca_WRITE_MGM(dev, prev, mailbox);
 200        if (err)
 201                mthca_err(dev, "WRITE_MGM returned %d\n", err);
 202
 203 out:
 204        if (err && link && index != -1) {
 205                BUG_ON(index < dev->limits.num_mgms);
 206                mthca_free(&dev->mcg_table.alloc, index);
 207        }
 208        mutex_unlock(&dev->mcg_table.mutex);
 209
 210        mthca_free_mailbox(dev, mailbox);
 211        return err;
 212}
 213
 214int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 215{
 216        struct mthca_dev *dev = to_mdev(ibqp->device);
 217        struct mthca_mailbox *mailbox;
 218        struct mthca_mgm *mgm;
 219        u16 hash;
 220        int prev, index;
 221        int i, loc;
 222        int err;
 223
 224        mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 225        if (IS_ERR(mailbox))
 226                return PTR_ERR(mailbox);
 227        mgm = mailbox->buf;
 228
 229        mutex_lock(&dev->mcg_table.mutex);
 230
 231        err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
 232        if (err)
 233                goto out;
 234
 235        if (index == -1) {
 236                mthca_err(dev, "MGID %pI6 not found\n", gid->raw);
 237                err = -EINVAL;
 238                goto out;
 239        }
 240
 241        for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) {
 242                if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31)))
 243                        loc = i;
 244                if (!(mgm->qp[i] & cpu_to_be32(1 << 31)))
 245                        break;
 246        }
 247
 248        if (loc == -1) {
 249                mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num);
 250                err = -EINVAL;
 251                goto out;
 252        }
 253
 254        mgm->qp[loc]   = mgm->qp[i - 1];
 255        mgm->qp[i - 1] = 0;
 256
 257        err = mthca_WRITE_MGM(dev, index, mailbox);
 258        if (err) {
 259                mthca_err(dev, "WRITE_MGM returned %d\n", err);
 260                goto out;
 261        }
 262
 263        if (i != 1)
 264                goto out;
 265
 266        if (prev == -1) {
 267                /* Remove entry from MGM */
 268                int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6;
 269                if (amgm_index_to_free) {
 270                        err = mthca_READ_MGM(dev, amgm_index_to_free,
 271                                             mailbox);
 272                        if (err) {
 273                                mthca_err(dev, "READ_MGM returned %d\n", err);
 274                                goto out;
 275                        }
 276                } else
 277                        memset(mgm->gid, 0, 16);
 278
 279                err = mthca_WRITE_MGM(dev, index, mailbox);
 280                if (err) {
 281                        mthca_err(dev, "WRITE_MGM returned %d\n", err);
 282                        goto out;
 283                }
 284                if (amgm_index_to_free) {
 285                        BUG_ON(amgm_index_to_free < dev->limits.num_mgms);
 286                        mthca_free(&dev->mcg_table.alloc, amgm_index_to_free);
 287                }
 288        } else {
 289                /* Remove entry from AMGM */
 290                int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
 291                err = mthca_READ_MGM(dev, prev, mailbox);
 292                if (err) {
 293                        mthca_err(dev, "READ_MGM returned %d\n", err);
 294                        goto out;
 295                }
 296
 297                mgm->next_gid_index = cpu_to_be32(curr_next_index << 6);
 298
 299                err = mthca_WRITE_MGM(dev, prev, mailbox);
 300                if (err) {
 301                        mthca_err(dev, "WRITE_MGM returned %d\n", err);
 302                        goto out;
 303                }
 304                BUG_ON(index < dev->limits.num_mgms);
 305                mthca_free(&dev->mcg_table.alloc, index);
 306        }
 307
 308 out:
 309        mutex_unlock(&dev->mcg_table.mutex);
 310
 311        mthca_free_mailbox(dev, mailbox);
 312        return err;
 313}
 314
 315int mthca_init_mcg_table(struct mthca_dev *dev)
 316{
 317        int err;
 318        int table_size = dev->limits.num_mgms + dev->limits.num_amgms;
 319
 320        err = mthca_alloc_init(&dev->mcg_table.alloc,
 321                               table_size,
 322                               table_size - 1,
 323                               dev->limits.num_mgms);
 324        if (err)
 325                return err;
 326
 327        mutex_init(&dev->mcg_table.mutex);
 328
 329        return 0;
 330}
 331
 332void mthca_cleanup_mcg_table(struct mthca_dev *dev)
 333{
 334        mthca_alloc_cleanup(&dev->mcg_table.alloc);
 335}
 336