mthca_mcg.c revision 225736
1219131Srwatson/* 2219131Srwatson * Copyright (c) 2004 Topspin Communications. All rights reserved. 3219131Srwatson * 4219131Srwatson * This software is available to you under a choice of one of two 5219131Srwatson * licenses. You may choose to be licensed under the terms of the GNU 6219131Srwatson * General Public License (GPL) Version 2, available from the file 7219131Srwatson * COPYING in the main directory of this source tree, or the 8219131Srwatson * OpenIB.org BSD license below: 9219131Srwatson * 10219131Srwatson * Redistribution and use in source and binary forms, with or 11219131Srwatson * without modification, are permitted provided that the following 12219131Srwatson * conditions are met: 13219131Srwatson * 14219131Srwatson * - Redistributions of source code must retain the above 15219131Srwatson * copyright notice, this list of conditions and the following 16219131Srwatson * disclaimer. 17219131Srwatson * 18219131Srwatson * - Redistributions in binary form must reproduce the above 19219131Srwatson * copyright notice, this list of conditions and the following 20219131Srwatson * disclaimer in the documentation and/or other materials 21219131Srwatson * provided with the distribution. 22219131Srwatson * 23219131Srwatson * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219131Srwatson * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219131Srwatson * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219131Srwatson * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219131Srwatson * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219131Srwatson * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219131Srwatson * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219131Srwatson * SOFTWARE. 31219131Srwatson */ 32219131Srwatson 33219131Srwatson#include <linux/string.h> 34219131Srwatson#include <linux/slab.h> 35219131Srwatson 36219131Srwatson#include "mthca_dev.h" 37219131Srwatson#include "mthca_cmd.h" 38219131Srwatson 39219131Srwatsonstruct mthca_mgm { 40219131Srwatson __be32 next_gid_index; 41219131Srwatson u32 reserved[3]; 42219131Srwatson u8 gid[16]; 43219131Srwatson __be32 qp[MTHCA_QP_PER_MGM]; 44219131Srwatson}; 45219131Srwatson 46219131Srwatsonstatic const u8 zero_gid[16]; /* automatically initialized to 0 */ 47219131Srwatson 48219131Srwatson/* 49219131Srwatson * Caller must hold MCG table semaphore. gid and mgm parameters must 50219131Srwatson * be properly aligned for command interface. 51219131Srwatson * 52219131Srwatson * Returns 0 unless a firmware command error occurs. 53219131Srwatson * 54219131Srwatson * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 55219131Srwatson * and *mgm holds MGM entry. 56219131Srwatson * 57219131Srwatson * if GID is found in AMGM, *index = index in AMGM, *prev = index of 58219131Srwatson * previous entry in hash chain and *mgm holds AMGM entry. 59219131Srwatson * 60219131Srwatson * If no AMGM exists for given gid, *index = -1, *prev = index of last 61219131Srwatson * entry in hash chain and *mgm holds end of hash chain. 62219131Srwatson */ 63219131Srwatsonstatic int find_mgm(struct mthca_dev *dev, 64219131Srwatson u8 *gid, struct mthca_mailbox *mgm_mailbox, 65219131Srwatson u16 *hash, int *prev, int *index) 66219131Srwatson{ 67219131Srwatson struct mthca_mailbox *mailbox; 68219131Srwatson struct mthca_mgm *mgm = mgm_mailbox->buf; 69219131Srwatson u8 *mgid; 70219131Srwatson int err; 71219131Srwatson u8 status; 72219131Srwatson 73219131Srwatson mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 74219131Srwatson if (IS_ERR(mailbox)) 75219131Srwatson return -ENOMEM; 76219131Srwatson mgid = mailbox->buf; 77219131Srwatson 78219131Srwatson memcpy(mgid, gid, 16); 79219131Srwatson 80219131Srwatson err = mthca_MGID_HASH(dev, mailbox, hash, &status); 81250154Sjilles if (err) 82219131Srwatson goto out; 83219131Srwatson if (status) { 84219131Srwatson mthca_err(dev, "MGID_HASH returned status %02x\n", status); 85219131Srwatson err = -EINVAL; 86219131Srwatson goto out; 87219131Srwatson } 88219131Srwatson 89219131Srwatson if (0) 90219131Srwatson mthca_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash); 91219131Srwatson 92219131Srwatson *index = *hash; 93219131Srwatson *prev = -1; 94219131Srwatson 95219131Srwatson do { 96219131Srwatson err = mthca_READ_MGM(dev, *index, mgm_mailbox, &status); 97219131Srwatson if (err) 98219131Srwatson goto out; 99219131Srwatson if (status) { 100219131Srwatson mthca_err(dev, "READ_MGM returned status %02x\n", status); 101219131Srwatson err = -EINVAL; 102219131Srwatson goto out; 103219131Srwatson } 104247667Spjd 105219131Srwatson if (!memcmp(mgm->gid, zero_gid, 16)) { 106247667Spjd if (*index != *hash) { 107219131Srwatson mthca_err(dev, "Found zero MGID in AMGM.\n"); 108219131Srwatson err = -EINVAL; 109219131Srwatson } 110219131Srwatson goto out; 111219131Srwatson } 112247602Spjd 113247602Spjd if (!memcmp(mgm->gid, gid, 16)) 114219131Srwatson goto out; 115247602Spjd 116247602Spjd *prev = *index; 117255219Spjd *index = be32_to_cpu(mgm->next_gid_index) >> 6; 118247602Spjd } while (*index); 119219131Srwatson 120219131Srwatson *index = -1; 121219131Srwatson 122219131Srwatson out: 123255374Spjd mthca_free_mailbox(dev, mailbox); 124219131Srwatson return err; 125219131Srwatson} 126219131Srwatson 127219131Srwatsonint mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 128219131Srwatson{ 129219131Srwatson struct mthca_dev *dev = to_mdev(ibqp->device); 130219131Srwatson struct mthca_mailbox *mailbox; 131219131Srwatson struct mthca_mgm *mgm; 132219131Srwatson u16 hash; 133247667Spjd int index, prev; 134219131Srwatson int link = 0; 135247667Spjd int i; 136219131Srwatson int err; 137219131Srwatson u8 status; 138219131Srwatson 139219131Srwatson mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 140219131Srwatson if (IS_ERR(mailbox)) 141219131Srwatson return PTR_ERR(mailbox); 142219131Srwatson mgm = mailbox->buf; 143219131Srwatson 144219131Srwatson mutex_lock(&dev->mcg_table.mutex); 145219131Srwatson 146219131Srwatson err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); 147219131Srwatson if (err) 148219131Srwatson goto out; 149219131Srwatson 150219131Srwatson if (index != -1) { 151219131Srwatson if (!memcmp(mgm->gid, zero_gid, 16)) 152219131Srwatson memcpy(mgm->gid, gid->raw, 16); 153219131Srwatson } else { 154219131Srwatson link = 1; 155219131Srwatson 156219131Srwatson index = mthca_alloc(&dev->mcg_table.alloc); 157219131Srwatson if (index == -1) { 158219131Srwatson mthca_err(dev, "No AMGM entries left\n"); 159219131Srwatson err = -ENOMEM; 160219131Srwatson goto out; 161219131Srwatson } 162219131Srwatson 163219131Srwatson err = mthca_READ_MGM(dev, index, mailbox, &status); 164219131Srwatson if (err) 165219131Srwatson goto out; 166219131Srwatson if (status) { 167219131Srwatson mthca_err(dev, "READ_MGM returned status %02x\n", status); 168219131Srwatson err = -EINVAL; 169219131Srwatson goto out; 170219131Srwatson } 171219131Srwatson memset(mgm, 0, sizeof *mgm); 172219131Srwatson memcpy(mgm->gid, gid->raw, 16); 173219131Srwatson } 174219131Srwatson 175219131Srwatson for (i = 0; i < MTHCA_QP_PER_MGM; ++i) 176219131Srwatson if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) { 177219131Srwatson mthca_dbg(dev, "QP %06x already a member of MGM\n", 178219131Srwatson ibqp->qp_num); 179219131Srwatson err = 0; 180219131Srwatson goto out; 181219131Srwatson } else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) { 182219131Srwatson mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31)); 183219131Srwatson break; 184219131Srwatson } 185219131Srwatson 186219131Srwatson if (i == MTHCA_QP_PER_MGM) { 187219131Srwatson mthca_err(dev, "MGM at index %x is full.\n", index); 188219131Srwatson err = -ENOMEM; 189219131Srwatson goto out; 190219131Srwatson } 191219131Srwatson 192219131Srwatson err = mthca_WRITE_MGM(dev, index, mailbox, &status); 193219131Srwatson if (err) 194219131Srwatson goto out; 195219131Srwatson if (status) { 196219131Srwatson mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 197219131Srwatson err = -EINVAL; 198219131Srwatson goto out; 199219131Srwatson } 200224852Srwatson 201219131Srwatson if (!link) 202219131Srwatson goto out; 203219131Srwatson 204219131Srwatson err = mthca_READ_MGM(dev, prev, mailbox, &status); 205219131Srwatson if (err) 206219131Srwatson goto out; 207219131Srwatson if (status) { 208219131Srwatson mthca_err(dev, "READ_MGM returned status %02x\n", status); 209219131Srwatson err = -EINVAL; 210219131Srwatson goto out; 211219131Srwatson } 212219131Srwatson 213219131Srwatson mgm->next_gid_index = cpu_to_be32(index << 6); 214219131Srwatson 215219131Srwatson err = mthca_WRITE_MGM(dev, prev, mailbox, &status); 216219131Srwatson if (err) 217219131Srwatson goto out; 218219131Srwatson if (status) { 219219131Srwatson mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 220219131Srwatson err = -EINVAL; 221219131Srwatson } 222219131Srwatson 223219131Srwatson out: 224219131Srwatson if (err && link && index != -1) { 225219131Srwatson BUG_ON(index < dev->limits.num_mgms); 226219131Srwatson mthca_free(&dev->mcg_table.alloc, index); 227219131Srwatson } 228219131Srwatson mutex_unlock(&dev->mcg_table.mutex); 229219131Srwatson 230219131Srwatson mthca_free_mailbox(dev, mailbox); 231219131Srwatson return err; 232219131Srwatson} 233219131Srwatson 234219131Srwatsonint mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) 235219131Srwatson{ 236219131Srwatson struct mthca_dev *dev = to_mdev(ibqp->device); 237219131Srwatson struct mthca_mailbox *mailbox; 238219131Srwatson struct mthca_mgm *mgm; 239219131Srwatson u16 hash; 240219131Srwatson int prev, index; 241219131Srwatson int i, loc; 242219131Srwatson int err; 243247602Spjd u8 status; 244219131Srwatson 245219131Srwatson mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); 246219131Srwatson if (IS_ERR(mailbox)) 247219131Srwatson return PTR_ERR(mailbox); 248219131Srwatson mgm = mailbox->buf; 249219131Srwatson 250219131Srwatson mutex_lock(&dev->mcg_table.mutex); 251219131Srwatson 252219131Srwatson err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); 253219131Srwatson if (err) 254219131Srwatson goto out; 255219131Srwatson 256219131Srwatson if (index == -1) { 257219131Srwatson mthca_err(dev, "MGID %pI6 not found\n", gid->raw); 258219131Srwatson err = -EINVAL; 259219131Srwatson goto out; 260219131Srwatson } 261219131Srwatson 262219131Srwatson for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) { 263219131Srwatson if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) 264219131Srwatson loc = i; 265219131Srwatson if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) 266219131Srwatson break; 267219131Srwatson } 268219131Srwatson 269219131Srwatson if (loc == -1) { 270219131Srwatson mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num); 271219131Srwatson err = -EINVAL; 272219131Srwatson goto out; 273219131Srwatson } 274219131Srwatson 275219131Srwatson mgm->qp[loc] = mgm->qp[i - 1]; 276219131Srwatson mgm->qp[i - 1] = 0; 277219131Srwatson 278219131Srwatson err = mthca_WRITE_MGM(dev, index, mailbox, &status); 279219131Srwatson if (err) 280219131Srwatson goto out; 281219131Srwatson if (status) { 282219131Srwatson mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 283219131Srwatson err = -EINVAL; 284219131Srwatson goto out; 285219131Srwatson } 286219131Srwatson 287219131Srwatson if (i != 1) 288219131Srwatson goto out; 289219131Srwatson 290219131Srwatson if (prev == -1) { 291219131Srwatson /* Remove entry from MGM */ 292219131Srwatson int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6; 293219131Srwatson if (amgm_index_to_free) { 294219131Srwatson err = mthca_READ_MGM(dev, amgm_index_to_free, 295219131Srwatson mailbox, &status); 296219131Srwatson if (err) 297219131Srwatson goto out; 298219131Srwatson if (status) { 299219131Srwatson mthca_err(dev, "READ_MGM returned status %02x\n", 300219131Srwatson status); 301219131Srwatson err = -EINVAL; 302219131Srwatson goto out; 303219131Srwatson } 304219131Srwatson } else 305219131Srwatson memset(mgm->gid, 0, 16); 306219131Srwatson 307219131Srwatson err = mthca_WRITE_MGM(dev, index, mailbox, &status); 308219131Srwatson if (err) 309219131Srwatson goto out; 310219131Srwatson if (status) { 311219131Srwatson mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 312219131Srwatson err = -EINVAL; 313219131Srwatson goto out; 314219131Srwatson } 315219131Srwatson if (amgm_index_to_free) { 316219131Srwatson BUG_ON(amgm_index_to_free < dev->limits.num_mgms); 317219131Srwatson mthca_free(&dev->mcg_table.alloc, amgm_index_to_free); 318219131Srwatson } 319219131Srwatson } else { 320219131Srwatson /* Remove entry from AMGM */ 321247602Spjd int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; 322247602Spjd err = mthca_READ_MGM(dev, prev, mailbox, &status); 323219131Srwatson if (err) 324247602Spjd goto out; 325219131Srwatson if (status) { 326219131Srwatson mthca_err(dev, "READ_MGM returned status %02x\n", status); 327219131Srwatson err = -EINVAL; 328219131Srwatson goto out; 329219131Srwatson } 330219131Srwatson 331219131Srwatson mgm->next_gid_index = cpu_to_be32(curr_next_index << 6); 332219131Srwatson 333219131Srwatson err = mthca_WRITE_MGM(dev, prev, mailbox, &status); 334219131Srwatson if (err) 335219131Srwatson goto out; 336219131Srwatson if (status) { 337219131Srwatson mthca_err(dev, "WRITE_MGM returned status %02x\n", status); 338243610Spjd err = -EINVAL; 339243610Spjd goto out; 340243610Spjd } 341243610Spjd BUG_ON(index < dev->limits.num_mgms); 342243610Spjd mthca_free(&dev->mcg_table.alloc, index); 343219131Srwatson } 344219131Srwatson 345219131Srwatson out: 346219131Srwatson mutex_unlock(&dev->mcg_table.mutex); 347219131Srwatson 348219131Srwatson mthca_free_mailbox(dev, mailbox); 349219131Srwatson return err; 350219131Srwatson} 351219131Srwatson 352219131Srwatsonint mthca_init_mcg_table(struct mthca_dev *dev) 353219131Srwatson{ 354219131Srwatson int err; 355219131Srwatson int table_size = dev->limits.num_mgms + dev->limits.num_amgms; 356219131Srwatson 357219131Srwatson err = mthca_alloc_init(&dev->mcg_table.alloc, 358219131Srwatson table_size, 359219131Srwatson table_size - 1, 360219131Srwatson dev->limits.num_mgms); 361219131Srwatson if (err) 362219131Srwatson return err; 363219131Srwatson 364219131Srwatson mutex_init(&dev->mcg_table.mutex); 365219131Srwatson 366219131Srwatson return 0; 367219131Srwatson} 368219131Srwatson 369219131Srwatsonvoid mthca_cleanup_mcg_table(struct mthca_dev *dev) 370219131Srwatson{ 371219131Srwatson mthca_alloc_cleanup(&dev->mcg_table.alloc); 372219131Srwatson} 373219131Srwatson