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, struct mlx4_cmd_mailbox *mgm_mailbox, 99 u16 *hash, int *prev, int *index) 100{ 101 struct mlx4_cmd_mailbox *mailbox; 102 struct mlx4_mgm *mgm = mgm_mailbox->buf; 103 u8 *mgid; 104 int err; 105 106 mailbox = mlx4_alloc_cmd_mailbox(dev); 107 if (IS_ERR(mailbox)) 108 return -ENOMEM; 109 mgid = mailbox->buf; 110 111 memcpy(mgid, gid, 16); 112 113 err = mlx4_MGID_HASH(dev, mailbox, hash); 114 mlx4_free_cmd_mailbox(dev, mailbox); 115 if (err) 116 return err; 117 118 if (0) 119 mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash); 120 121 *index = *hash; 122 *prev = -1; 123 124 do { 125 err = mlx4_READ_MCG(dev, *index, mgm_mailbox); 126 if (err) 127 return err; 128 129 if (!memcmp(mgm->gid, zero_gid, 16)) { 130 if (*index != *hash) { 131 mlx4_err(dev, "Found zero MGID in AMGM.\n"); 132 err = -EINVAL; 133 } 134 return err; 135 } 136 137 if (!memcmp(mgm->gid, gid, 16)) 138 return err; 139 140 *prev = *index; 141 *index = be32_to_cpu(mgm->next_gid_index) >> 6; 142 } while (*index); 143 144 *index = -1; 145 return err; 146} 147 148int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], 149 int block_mcast_loopback) 150{ 151 struct mlx4_priv *priv = mlx4_priv(dev); 152 struct mlx4_cmd_mailbox *mailbox; 153 struct mlx4_mgm *mgm; 154 u32 members_count; 155 u16 hash; 156 int index, prev; 157 int link = 0; 158 int i; 159 int err; 160 161 mailbox = mlx4_alloc_cmd_mailbox(dev); 162 if (IS_ERR(mailbox)) 163 return PTR_ERR(mailbox); 164 mgm = mailbox->buf; 165 166 mutex_lock(&priv->mcg_table.mutex); 167 168 err = find_mgm(dev, gid, mailbox, &hash, &prev, &index); 169 if (err) 170 goto out; 171 172 if (index != -1) { 173 if (!memcmp(mgm->gid, zero_gid, 16)) 174 memcpy(mgm->gid, gid, 16); 175 } else { 176 link = 1; 177 178 index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap); 179 if (index == -1) { 180 mlx4_err(dev, "No AMGM entries left\n"); 181 err = -ENOMEM; 182 goto out; 183 } 184 index += dev->caps.num_mgms; 185 186 memset(mgm, 0, sizeof *mgm); 187 memcpy(mgm->gid, gid, 16); 188 } 189 190 members_count = be32_to_cpu(mgm->members_count); 191 if (members_count == MLX4_QP_PER_MGM) { 192 mlx4_err(dev, "MGM at index %x is full.\n", index); 193 err = -ENOMEM; 194 goto out; 195 } 196 197 for (i = 0; i < members_count; ++i) 198 if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { 199 mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn); 200 err = 0; 201 goto out; 202 } 203 204 if (block_mcast_loopback) 205 mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) | 206 (1U << MGM_BLCK_LB_BIT)); 207 else 208 mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK); 209 210 mgm->members_count = cpu_to_be32(members_count); 211 212 err = mlx4_WRITE_MCG(dev, index, mailbox); 213 if (err) 214 goto out; 215 216 if (!link) 217 goto out; 218 219 err = mlx4_READ_MCG(dev, prev, mailbox); 220 if (err) 221 goto out; 222 223 mgm->next_gid_index = cpu_to_be32(index << 6); 224 225 err = mlx4_WRITE_MCG(dev, prev, mailbox); 226 if (err) 227 goto out; 228 229out: 230 if (err && link && index != -1) { 231 if (index < dev->caps.num_mgms) 232 mlx4_warn(dev, "Got AMGM index %d < %d", 233 index, dev->caps.num_mgms); 234 else 235 mlx4_bitmap_free(&priv->mcg_table.bitmap, 236 index - dev->caps.num_mgms); 237 } 238 mutex_unlock(&priv->mcg_table.mutex); 239 240 mlx4_free_cmd_mailbox(dev, mailbox); 241 return err; 242} 243EXPORT_SYMBOL_GPL(mlx4_multicast_attach); 244 245int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]) 246{ 247 struct mlx4_priv *priv = mlx4_priv(dev); 248 struct mlx4_cmd_mailbox *mailbox; 249 struct mlx4_mgm *mgm; 250 u32 members_count; 251 u16 hash; 252 int prev, index; 253 int i, loc; 254 int err; 255 256 mailbox = mlx4_alloc_cmd_mailbox(dev); 257 if (IS_ERR(mailbox)) 258 return PTR_ERR(mailbox); 259 mgm = mailbox->buf; 260 261 mutex_lock(&priv->mcg_table.mutex); 262 263 err = find_mgm(dev, gid, mailbox, &hash, &prev, &index); 264 if (err) 265 goto out; 266 267 if (index == -1) { 268 mlx4_err(dev, "MGID %pI6 not found\n", gid); 269 err = -EINVAL; 270 goto out; 271 } 272 273 members_count = be32_to_cpu(mgm->members_count); 274 for (loc = -1, i = 0; i < members_count; ++i) 275 if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) 276 loc = i; 277 278 if (loc == -1) { 279 mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn); 280 err = -EINVAL; 281 goto out; 282 } 283 284 285 mgm->members_count = cpu_to_be32(--members_count); 286 mgm->qp[loc] = mgm->qp[i - 1]; 287 mgm->qp[i - 1] = 0; 288 289 if (i != 1) { 290 err = mlx4_WRITE_MCG(dev, index, mailbox); 291 goto out; 292 } 293 294 if (prev == -1) { 295 /* Remove entry from MGM */ 296 int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; 297 if (amgm_index) { 298 err = mlx4_READ_MCG(dev, amgm_index, mailbox); 299 if (err) 300 goto out; 301 } else 302 memset(mgm->gid, 0, 16); 303 304 err = mlx4_WRITE_MCG(dev, index, mailbox); 305 if (err) 306 goto out; 307 308 if (amgm_index) { 309 if (amgm_index < dev->caps.num_mgms) 310 mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d", 311 index, amgm_index, dev->caps.num_mgms); 312 else 313 mlx4_bitmap_free(&priv->mcg_table.bitmap, 314 amgm_index - dev->caps.num_mgms); 315 } 316 } else { 317 /* Remove entry from AMGM */ 318 int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; 319 err = mlx4_READ_MCG(dev, prev, mailbox); 320 if (err) 321 goto out; 322 323 mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); 324 325 err = mlx4_WRITE_MCG(dev, prev, mailbox); 326 if (err) 327 goto out; 328 329 if (index < dev->caps.num_mgms) 330 mlx4_warn(dev, "entry %d had next AMGM index %d < %d", 331 prev, index, dev->caps.num_mgms); 332 else 333 mlx4_bitmap_free(&priv->mcg_table.bitmap, 334 index - dev->caps.num_mgms); 335 } 336 337out: 338 mutex_unlock(&priv->mcg_table.mutex); 339 340 mlx4_free_cmd_mailbox(dev, mailbox); 341 return err; 342} 343EXPORT_SYMBOL_GPL(mlx4_multicast_detach); 344 345int mlx4_init_mcg_table(struct mlx4_dev *dev) 346{ 347 struct mlx4_priv *priv = mlx4_priv(dev); 348 int err; 349 350 err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms, 351 dev->caps.num_amgms - 1, 0, 0); 352 if (err) 353 return err; 354 355 mutex_init(&priv->mcg_table.mutex); 356 357 return 0; 358} 359 360void mlx4_cleanup_mcg_table(struct mlx4_dev *dev) 361{ 362 mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap); 363} 364