linux/drivers/net/mlx4/mcg.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
   3 * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
   4 *
   5 * This software is available to you under a choice of one of two
   6 * licenses.  You may choose to be licensed under the terms of the GNU
   7 * General Public License (GPL) Version 2, available from the file
   8 * COPYING in the main directory of this source tree, or the
   9 * OpenIB.org BSD license below:
  10 *
  11 *     Redistribution and use in source and binary forms, with or
  12 *     without modification, are permitted provided that the following
  13 *     conditions are met:
  14 *
  15 *      - Redistributions of source code must retain the above
  16 *        copyright notice, this list of conditions and the following
  17 *        disclaimer.
  18 *
  19 *      - Redistributions in binary form must reproduce the above
  20 *        copyright notice, this list of conditions and the following
  21 *        disclaimer in the documentation and/or other materials
  22 *        provided with the distribution.
  23 *
  24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  31 * SOFTWARE.
  32 */
  33
  34#include <linux/string.h>
  35
  36#include <linux/mlx4/cmd.h>
  37
  38#include "mlx4.h"
  39
  40#define MGM_QPN_MASK       0x00FFFFFF
  41#define MGM_BLCK_LB_BIT    30
  42
  43struct mlx4_mgm {
  44        __be32                  next_gid_index;
  45        __be32                  members_count;
  46        u32                     reserved[2];
  47        u8                      gid[16];
  48        __be32                  qp[MLX4_QP_PER_MGM];
  49};
  50
  51static const u8 zero_gid[16];   /* automatically initialized to 0 */
  52
  53static int mlx4_READ_MCG(struct mlx4_dev *dev, int index,
  54                         struct mlx4_cmd_mailbox *mailbox)
  55{
  56        return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG,
  57                            MLX4_CMD_TIME_CLASS_A);
  58}
  59
  60static int mlx4_WRITE_MCG(struct mlx4_dev *dev, int index,
  61                          struct mlx4_cmd_mailbox *mailbox)
  62{
  63        return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG,
  64                        MLX4_CMD_TIME_CLASS_A);
  65}
  66
  67static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
  68                          u16 *hash)
  69{
  70        u64 imm;
  71        int err;
  72
  73        err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, 0, MLX4_CMD_MGID_HASH,
  74                           MLX4_CMD_TIME_CLASS_A);
  75
  76        if (!err)
  77                *hash = imm;
  78
  79        return err;
  80}
  81
  82/*
  83 * Caller must hold MCG table semaphore.  gid and mgm parameters must
  84 * be properly aligned for command interface.
  85 *
  86 *  Returns 0 unless a firmware command error occurs.
  87 *
  88 * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1
  89 * and *mgm holds MGM entry.
  90 *
  91 * if GID is found in AMGM, *index = index in AMGM, *prev = index of
  92 * previous entry in hash chain and *mgm holds AMGM entry.
  93 *
  94 * If no AMGM exists for given gid, *index = -1, *prev = index of last
  95 * entry in hash chain and *mgm holds end of hash chain.
  96 */
  97static int find_mgm(struct mlx4_dev *dev,
  98                    u8 *gid, enum mlx4_protocol protocol,
  99                    struct mlx4_cmd_mailbox *mgm_mailbox,
 100                    u16 *hash, int *prev, int *index)
 101{
 102        struct mlx4_cmd_mailbox *mailbox;
 103        struct mlx4_mgm *mgm = mgm_mailbox->buf;
 104        u8 *mgid;
 105        int err;
 106
 107        mailbox = mlx4_alloc_cmd_mailbox(dev);
 108        if (IS_ERR(mailbox))
 109                return -ENOMEM;
 110        mgid = mailbox->buf;
 111
 112        memcpy(mgid, gid, 16);
 113
 114        err = mlx4_MGID_HASH(dev, mailbox, hash);
 115        mlx4_free_cmd_mailbox(dev, mailbox);
 116        if (err)
 117                return err;
 118
 119        if (0)
 120                mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash);
 121
 122        *index = *hash;
 123        *prev  = -1;
 124
 125        do {
 126                err = mlx4_READ_MCG(dev, *index, mgm_mailbox);
 127                if (err)
 128                        return err;
 129
 130                if (!memcmp(mgm->gid, zero_gid, 16)) {
 131                        if (*index != *hash) {
 132                                mlx4_err(dev, "Found zero MGID in AMGM.\n");
 133                                err = -EINVAL;
 134                        }
 135                        return err;
 136                }
 137
 138                if (!memcmp(mgm->gid, gid, 16) &&
 139                    be32_to_cpu(mgm->members_count) >> 30 == protocol)
 140                        return err;
 141
 142                *prev = *index;
 143                *index = be32_to_cpu(mgm->next_gid_index) >> 6;
 144        } while (*index);
 145
 146        *index = -1;
 147        return err;
 148}
 149
 150int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
 151                          int block_mcast_loopback, enum mlx4_protocol protocol)
 152{
 153        struct mlx4_priv *priv = mlx4_priv(dev);
 154        struct mlx4_cmd_mailbox *mailbox;
 155        struct mlx4_mgm *mgm;
 156        u32 members_count;
 157        u16 hash;
 158        int index, prev;
 159        int link = 0;
 160        int i;
 161        int err;
 162
 163        mailbox = mlx4_alloc_cmd_mailbox(dev);
 164        if (IS_ERR(mailbox))
 165                return PTR_ERR(mailbox);
 166        mgm = mailbox->buf;
 167
 168        mutex_lock(&priv->mcg_table.mutex);
 169
 170        err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index);
 171        if (err)
 172                goto out;
 173
 174        if (index != -1) {
 175                if (!memcmp(mgm->gid, zero_gid, 16))
 176                        memcpy(mgm->gid, gid, 16);
 177        } else {
 178                link = 1;
 179
 180                index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap);
 181                if (index == -1) {
 182                        mlx4_err(dev, "No AMGM entries left\n");
 183                        err = -ENOMEM;
 184                        goto out;
 185                }
 186                index += dev->caps.num_mgms;
 187
 188                memset(mgm, 0, sizeof *mgm);
 189                memcpy(mgm->gid, gid, 16);
 190        }
 191
 192        members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
 193        if (members_count == MLX4_QP_PER_MGM) {
 194                mlx4_err(dev, "MGM at index %x is full.\n", index);
 195                err = -ENOMEM;
 196                goto out;
 197        }
 198
 199        for (i = 0; i < members_count; ++i)
 200                if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
 201                        mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn);
 202                        err = 0;
 203                        goto out;
 204                }
 205
 206        if (block_mcast_loopback)
 207                mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) |
 208                                                       (1U << MGM_BLCK_LB_BIT));
 209        else
 210                mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK);
 211
 212        mgm->members_count = cpu_to_be32(members_count | (u32) protocol << 30);
 213
 214        err = mlx4_WRITE_MCG(dev, index, mailbox);
 215        if (err)
 216                goto out;
 217
 218        if (!link)
 219                goto out;
 220
 221        err = mlx4_READ_MCG(dev, prev, mailbox);
 222        if (err)
 223                goto out;
 224
 225        mgm->next_gid_index = cpu_to_be32(index << 6);
 226
 227        err = mlx4_WRITE_MCG(dev, prev, mailbox);
 228        if (err)
 229                goto out;
 230
 231out:
 232        if (err && link && index != -1) {
 233                if (index < dev->caps.num_mgms)
 234                        mlx4_warn(dev, "Got AMGM index %d < %d",
 235                                  index, dev->caps.num_mgms);
 236                else
 237                        mlx4_bitmap_free(&priv->mcg_table.bitmap,
 238                                         index - dev->caps.num_mgms);
 239        }
 240        mutex_unlock(&priv->mcg_table.mutex);
 241
 242        mlx4_free_cmd_mailbox(dev, mailbox);
 243        return err;
 244}
 245EXPORT_SYMBOL_GPL(mlx4_multicast_attach);
 246
 247int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
 248                          enum mlx4_protocol protocol)
 249{
 250        struct mlx4_priv *priv = mlx4_priv(dev);
 251        struct mlx4_cmd_mailbox *mailbox;
 252        struct mlx4_mgm *mgm;
 253        u32 members_count;
 254        u16 hash;
 255        int prev, index;
 256        int i, loc;
 257        int err;
 258
 259        mailbox = mlx4_alloc_cmd_mailbox(dev);
 260        if (IS_ERR(mailbox))
 261                return PTR_ERR(mailbox);
 262        mgm = mailbox->buf;
 263
 264        mutex_lock(&priv->mcg_table.mutex);
 265
 266        err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index);
 267        if (err)
 268                goto out;
 269
 270        if (index == -1) {
 271                mlx4_err(dev, "MGID %pI6 not found\n", gid);
 272                err = -EINVAL;
 273                goto out;
 274        }
 275
 276        members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
 277        for (loc = -1, i = 0; i < members_count; ++i)
 278                if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn)
 279                        loc = i;
 280
 281        if (loc == -1) {
 282                mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);
 283                err = -EINVAL;
 284                goto out;
 285        }
 286
 287
 288        mgm->members_count = cpu_to_be32(--members_count | (u32) protocol << 30);
 289        mgm->qp[loc]       = mgm->qp[i - 1];
 290        mgm->qp[i - 1]     = 0;
 291
 292        if (i != 1) {
 293                err = mlx4_WRITE_MCG(dev, index, mailbox);
 294                goto out;
 295        }
 296
 297        if (prev == -1) {
 298                /* Remove entry from MGM */
 299                int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;
 300                if (amgm_index) {
 301                        err = mlx4_READ_MCG(dev, amgm_index, mailbox);
 302                        if (err)
 303                                goto out;
 304                } else
 305                        memset(mgm->gid, 0, 16);
 306
 307                err = mlx4_WRITE_MCG(dev, index, mailbox);
 308                if (err)
 309                        goto out;
 310
 311                if (amgm_index) {
 312                        if (amgm_index < dev->caps.num_mgms)
 313                                mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d",
 314                                          index, amgm_index, dev->caps.num_mgms);
 315                        else
 316                                mlx4_bitmap_free(&priv->mcg_table.bitmap,
 317                                                 amgm_index - dev->caps.num_mgms);
 318                }
 319        } else {
 320                /* Remove entry from AMGM */
 321                int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
 322                err = mlx4_READ_MCG(dev, prev, mailbox);
 323                if (err)
 324                        goto out;
 325
 326                mgm->next_gid_index = cpu_to_be32(cur_next_index << 6);
 327
 328                err = mlx4_WRITE_MCG(dev, prev, mailbox);
 329                if (err)
 330                        goto out;
 331
 332                if (index < dev->caps.num_mgms)
 333                        mlx4_warn(dev, "entry %d had next AMGM index %d < %d",
 334                                  prev, index, dev->caps.num_mgms);
 335                else
 336                        mlx4_bitmap_free(&priv->mcg_table.bitmap,
 337                                         index - dev->caps.num_mgms);
 338        }
 339
 340out:
 341        mutex_unlock(&priv->mcg_table.mutex);
 342
 343        mlx4_free_cmd_mailbox(dev, mailbox);
 344        return err;
 345}
 346EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
 347
 348int mlx4_init_mcg_table(struct mlx4_dev *dev)
 349{
 350        struct mlx4_priv *priv = mlx4_priv(dev);
 351        int err;
 352
 353        err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms,
 354                               dev->caps.num_amgms - 1, 0, 0);
 355        if (err)
 356                return err;
 357
 358        mutex_init(&priv->mcg_table.mutex);
 359
 360        return 0;
 361}
 362
 363void mlx4_cleanup_mcg_table(struct mlx4_dev *dev)
 364{
 365        mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap);
 366}
 367