1/* 2 * Copyright (c) 2006, 2007 Cisco Systems, Inc. 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/init.h> 34#include <linux/string.h> 35#include <linux/slab.h> 36 37#include <linux/mlx4/cmd.h> 38 39#include "mlx4.h" 40 41struct mlx4_mgm { 42 __be32 next_gid_index; 43 __be32 members_count; 44 u32 reserved[2]; 45 u8 gid[16]; 46 __be32 qp[MLX4_QP_PER_MGM]; 47}; 48 49static const u8 zero_gid[16]; /* automatically initialized to 0 */ 50 51static int mlx4_READ_MCG(struct mlx4_dev *dev, int index, 52 struct mlx4_cmd_mailbox *mailbox) 53{ 54 return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG, 55 MLX4_CMD_TIME_CLASS_A); 56} 57 58static int mlx4_WRITE_MCG(struct mlx4_dev *dev, int index, 59 struct mlx4_cmd_mailbox *mailbox) 60{ 61 return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG, 62 MLX4_CMD_TIME_CLASS_A); 63} 64 65static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, 66 u16 *hash) 67{ 68 u64 imm; 69 int err; 70 71 err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, 0, MLX4_CMD_MGID_HASH, 72 MLX4_CMD_TIME_CLASS_A); 73 74 if (!err) 75 *hash = imm; 76 77 return err; 78} 79 80/* 81 * Caller must hold MCG table semaphore. gid and mgm parameters must 82 * be properly aligned for command interface. 83 * 84 * Returns 0 unless a firmware command error occurs. 85 * 86 * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 87 * and *mgm holds MGM entry. 88 * 89 * if GID is found in AMGM, *index = index in AMGM, *prev = index of 90 * previous entry in hash chain and *mgm holds AMGM entry. 91 * 92 * If no AMGM exists for given gid, *index = -1, *prev = index of last 93 * entry in hash chain and *mgm holds end of hash chain. 94 */ 95static int find_mgm(struct mlx4_dev *dev, 96 u8 *gid, struct mlx4_cmd_mailbox *mgm_mailbox, 97 u16 *hash, int *prev, int *index) 98{ 99 struct mlx4_cmd_mailbox *mailbox; 100 struct mlx4_mgm *mgm = mgm_mailbox->buf; 101 u8 *mgid; 102 int err; 103 104 mailbox = mlx4_alloc_cmd_mailbox(dev); 105 if (IS_ERR(mailbox)) 106 return -ENOMEM; 107 mgid = mailbox->buf; 108 109 memcpy(mgid, gid, 16); 110 111 err = mlx4_MGID_HASH(dev, mailbox, hash); 112 mlx4_free_cmd_mailbox(dev, mailbox); 113 if (err) 114 return err; 115 116 if (0) 117 mlx4_dbg(dev, "Hash for %04x:%04x:%04x:%04x:" 118 "%04x:%04x:%04x:%04x is %04x\n", 119 be16_to_cpu(((__be16 *) gid)[0]), 120 be16_to_cpu(((__be16 *) gid)[1]), 121 be16_to_cpu(((__be16 *) gid)[2]), 122 be16_to_cpu(((__be16 *) gid)[3]), 123 be16_to_cpu(((__be16 *) gid)[4]), 124 be16_to_cpu(((__be16 *) gid)[5]), 125 be16_to_cpu(((__be16 *) gid)[6]), 126 be16_to_cpu(((__be16 *) gid)[7]), 127 *hash); 128 129 *index = *hash; 130 *prev = -1; 131 132 do { 133 err = mlx4_READ_MCG(dev, *index, mgm_mailbox); 134 if (err) 135 return err; 136 137 if (!memcmp(mgm->gid, zero_gid, 16)) { 138 if (*index != *hash) { 139 mlx4_err(dev, "Found zero MGID in AMGM.\n"); 140 err = -EINVAL; 141 } 142 return err; 143 } 144 145 if (!memcmp(mgm->gid, gid, 16)) 146 return err; 147 148 *prev = *index; 149 *index = be32_to_cpu(mgm->next_gid_index) >> 6; 150 } while (*index); 151 152 *index = -1; 153 return err; 154} 155 156int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]) 157{ 158 struct mlx4_priv *priv = mlx4_priv(dev); 159 struct mlx4_cmd_mailbox *mailbox; 160 struct mlx4_mgm *mgm; 161 u32 members_count; 162 u16 hash; 163 int index, prev; 164 int link = 0; 165 int i; 166 int err; 167 168 mailbox = mlx4_alloc_cmd_mailbox(dev); 169 if (IS_ERR(mailbox)) 170 return PTR_ERR(mailbox); 171 mgm = mailbox->buf; 172 173 mutex_lock(&priv->mcg_table.mutex); 174 175 err = find_mgm(dev, gid, mailbox, &hash, &prev, &index); 176 if (err) 177 goto out; 178 179 if (index != -1) { 180 if (!memcmp(mgm->gid, zero_gid, 16)) 181 memcpy(mgm->gid, gid, 16); 182 } else { 183 link = 1; 184 185 index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap); 186 if (index == -1) { 187 mlx4_err(dev, "No AMGM entries left\n"); 188 err = -ENOMEM; 189 goto out; 190 } 191 index += dev->caps.num_mgms; 192 193 err = mlx4_READ_MCG(dev, index, mailbox); 194 if (err) 195 goto out; 196 197 memset(mgm, 0, sizeof *mgm); 198 memcpy(mgm->gid, gid, 16); 199 } 200 201 members_count = be32_to_cpu(mgm->members_count); 202 if (members_count == MLX4_QP_PER_MGM) { 203 mlx4_err(dev, "MGM at index %x is full.\n", index); 204 err = -ENOMEM; 205 goto out; 206 } 207 208 for (i = 0; i < members_count; ++i) 209 if (mgm->qp[i] == cpu_to_be32(qp->qpn)) { 210 mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn); 211 err = 0; 212 goto out; 213 } 214 215 mgm->qp[members_count++] = cpu_to_be32(qp->qpn); 216 mgm->members_count = cpu_to_be32(members_count); 217 218 err = mlx4_WRITE_MCG(dev, index, mailbox); 219 if (err) 220 goto out; 221 222 if (!link) 223 goto out; 224 225 err = mlx4_READ_MCG(dev, prev, mailbox); 226 if (err) 227 goto out; 228 229 mgm->next_gid_index = cpu_to_be32(index << 6); 230 231 err = mlx4_WRITE_MCG(dev, prev, mailbox); 232 if (err) 233 goto out; 234 235out: 236 if (err && link && index != -1) { 237 if (index < dev->caps.num_mgms) 238 mlx4_warn(dev, "Got AMGM index %d < %d", 239 index, dev->caps.num_mgms); 240 else 241 mlx4_bitmap_free(&priv->mcg_table.bitmap, 242 index - dev->caps.num_mgms); 243 } 244 mutex_unlock(&priv->mcg_table.mutex); 245 246 mlx4_free_cmd_mailbox(dev, mailbox); 247 return err; 248} 249EXPORT_SYMBOL_GPL(mlx4_multicast_attach); 250 251int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]) 252{ 253 struct mlx4_priv *priv = mlx4_priv(dev); 254 struct mlx4_cmd_mailbox *mailbox; 255 struct mlx4_mgm *mgm; 256 u32 members_count; 257 u16 hash; 258 int prev, index; 259 int i, loc; 260 int err; 261 262 mailbox = mlx4_alloc_cmd_mailbox(dev); 263 if (IS_ERR(mailbox)) 264 return PTR_ERR(mailbox); 265 mgm = mailbox->buf; 266 267 mutex_lock(&priv->mcg_table.mutex); 268 269 err = find_mgm(dev, gid, mailbox, &hash, &prev, &index); 270 if (err) 271 goto out; 272 273 if (index == -1) { 274 mlx4_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " 275 "not found\n", 276 be16_to_cpu(((__be16 *) gid)[0]), 277 be16_to_cpu(((__be16 *) gid)[1]), 278 be16_to_cpu(((__be16 *) gid)[2]), 279 be16_to_cpu(((__be16 *) gid)[3]), 280 be16_to_cpu(((__be16 *) gid)[4]), 281 be16_to_cpu(((__be16 *) gid)[5]), 282 be16_to_cpu(((__be16 *) gid)[6]), 283 be16_to_cpu(((__be16 *) gid)[7])); 284 err = -EINVAL; 285 goto out; 286 } 287 288 members_count = be32_to_cpu(mgm->members_count); 289 for (loc = -1, i = 0; i < members_count; ++i) 290 if (mgm->qp[i] == cpu_to_be32(qp->qpn)) 291 loc = i; 292 293 if (loc == -1) { 294 mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn); 295 err = -EINVAL; 296 goto out; 297 } 298 299 300 mgm->members_count = cpu_to_be32(--members_count); 301 mgm->qp[loc] = mgm->qp[i - 1]; 302 mgm->qp[i - 1] = 0; 303 304 err = mlx4_WRITE_MCG(dev, index, mailbox); 305 if (err) 306 goto out; 307 308 if (i != 1) 309 goto out; 310 311 if (prev == -1) { 312 /* Remove entry from MGM */ 313 int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; 314 if (amgm_index) { 315 err = mlx4_READ_MCG(dev, amgm_index, mailbox); 316 if (err) 317 goto out; 318 } else 319 memset(mgm->gid, 0, 16); 320 321 err = mlx4_WRITE_MCG(dev, index, mailbox); 322 if (err) 323 goto out; 324 325 if (amgm_index) { 326 if (amgm_index < dev->caps.num_mgms) 327 mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d", 328 index, amgm_index, dev->caps.num_mgms); 329 else 330 mlx4_bitmap_free(&priv->mcg_table.bitmap, 331 amgm_index - dev->caps.num_mgms); 332 } 333 } else { 334 /* Remove entry from AMGM */ 335 int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; 336 err = mlx4_READ_MCG(dev, prev, mailbox); 337 if (err) 338 goto out; 339 340 mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); 341 342 err = mlx4_WRITE_MCG(dev, prev, mailbox); 343 if (err) 344 goto out; 345 346 if (index < dev->caps.num_mgms) 347 mlx4_warn(dev, "entry %d had next AMGM index %d < %d", 348 prev, index, dev->caps.num_mgms); 349 else 350 mlx4_bitmap_free(&priv->mcg_table.bitmap, 351 index - dev->caps.num_mgms); 352 } 353 354out: 355 mutex_unlock(&priv->mcg_table.mutex); 356 357 mlx4_free_cmd_mailbox(dev, mailbox); 358 return err; 359} 360EXPORT_SYMBOL_GPL(mlx4_multicast_detach); 361 362int __devinit mlx4_init_mcg_table(struct mlx4_dev *dev) 363{ 364 struct mlx4_priv *priv = mlx4_priv(dev); 365 int err; 366 367 err = mlx4_bitmap_init(&priv->mcg_table.bitmap, 368 dev->caps.num_amgms, dev->caps.num_amgms - 1, 0); 369 if (err) 370 return err; 371 372 mutex_init(&priv->mcg_table.mutex); 373 374 return 0; 375} 376 377void mlx4_cleanup_mcg_table(struct mlx4_dev *dev) 378{ 379 mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap); 380} 381