fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / infiniband / hw / mthca / mthca_mcg.c
index 70a6553..a8ad072 100644 (file)
  * $Id: mthca_mcg.c 1349 2004-12-16 21:09:43Z roland $
  */
 
-#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
 
 #include "mthca_dev.h"
 #include "mthca_cmd.h"
 
-enum {
-       MTHCA_QP_PER_MGM = 4 * (MTHCA_MGM_ENTRY_SIZE / 16 - 2)
-};
-
 struct mthca_mgm {
-       u32 next_gid_index;
-       u32 reserved[3];
-       u8  gid[16];
-       u32 qp[MTHCA_QP_PER_MGM];
+       __be32 next_gid_index;
+       u32    reserved[3];
+       u8     gid[16];
+       __be32 qp[MTHCA_QP_PER_MGM];
 };
 
 static const u8 zero_gid[16];  /* automatically initialized to 0 */
@@ -66,22 +63,23 @@ static const u8 zero_gid[16];       /* automatically initialized to 0 */
  * entry in hash chain and *mgm holds end of hash chain.
  */
 static int find_mgm(struct mthca_dev *dev,
-                   u8 *gid, struct mthca_mgm *mgm,
+                   u8 *gid, struct mthca_mailbox *mgm_mailbox,
                    u16 *hash, int *prev, int *index)
 {
-       void *mailbox;
+       struct mthca_mailbox *mailbox;
+       struct mthca_mgm *mgm = mgm_mailbox->buf;
        u8 *mgid;
        int err;
        u8 status;
 
-       mailbox = kmalloc(16 + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
-       if (!mailbox)
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
                return -ENOMEM;
-       mgid = MAILBOX_ALIGN(mailbox);
+       mgid = mailbox->buf;
 
        memcpy(mgid, gid, 16);
 
-       err = mthca_MGID_HASH(dev, mgid, hash, &status);
+       err = mthca_MGID_HASH(dev, mailbox, hash, &status);
        if (err)
                goto out;
        if (status) {
@@ -93,22 +91,27 @@ static int find_mgm(struct mthca_dev *dev,
        if (0)
                mthca_dbg(dev, "Hash for %04x:%04x:%04x:%04x:"
                          "%04x:%04x:%04x:%04x is %04x\n",
-                         be16_to_cpu(((u16 *) gid)[0]), be16_to_cpu(((u16 *) gid)[1]),
-                         be16_to_cpu(((u16 *) gid)[2]), be16_to_cpu(((u16 *) gid)[3]),
-                         be16_to_cpu(((u16 *) gid)[4]), be16_to_cpu(((u16 *) gid)[5]),
-                         be16_to_cpu(((u16 *) gid)[6]), be16_to_cpu(((u16 *) gid)[7]),
+                         be16_to_cpu(((__be16 *) gid)[0]),
+                         be16_to_cpu(((__be16 *) gid)[1]),
+                         be16_to_cpu(((__be16 *) gid)[2]),
+                         be16_to_cpu(((__be16 *) gid)[3]),
+                         be16_to_cpu(((__be16 *) gid)[4]),
+                         be16_to_cpu(((__be16 *) gid)[5]),
+                         be16_to_cpu(((__be16 *) gid)[6]),
+                         be16_to_cpu(((__be16 *) gid)[7]),
                          *hash);
 
        *index = *hash;
        *prev  = -1;
 
        do {
-               err = mthca_READ_MGM(dev, *index, mgm, &status);
+               err = mthca_READ_MGM(dev, *index, mgm_mailbox, &status);
                if (err)
                        goto out;
                if (status) {
                        mthca_err(dev, "READ_MGM returned status %02x\n", status);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto out;
                }
 
                if (!memcmp(mgm->gid, zero_gid, 16)) {
@@ -123,20 +126,20 @@ static int find_mgm(struct mthca_dev *dev,
                        goto out;
 
                *prev = *index;
-               *index = be32_to_cpu(mgm->next_gid_index) >> 5;
+               *index = be32_to_cpu(mgm->next_gid_index) >> 6;
        } while (*index);
 
        *index = -1;
 
  out:
-       kfree(mailbox);
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
 int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 {
        struct mthca_dev *dev = to_mdev(ibqp->device);
-       void *mailbox;
+       struct mthca_mailbox *mailbox;
        struct mthca_mgm *mgm;
        u16 hash;
        int index, prev;
@@ -145,15 +148,14 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        int err;
        u8 status;
 
-       mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
-       if (!mailbox)
-               return -ENOMEM;
-       mgm = MAILBOX_ALIGN(mailbox);
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       mgm = mailbox->buf;
 
-       if (down_interruptible(&dev->mcg_table.sem))
-               return -EINTR;
+       mutex_lock(&dev->mcg_table.mutex);
 
-       err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
+       err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
        if (err)
                goto out;
 
@@ -170,7 +172,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                        goto out;
                }
 
-               err = mthca_READ_MGM(dev, index, mgm, &status);
+               err = mthca_READ_MGM(dev, index, mailbox, &status);
                if (err)
                        goto out;
                if (status) {
@@ -178,13 +180,17 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                        err = -EINVAL;
                        goto out;
                }
-
+               memset(mgm, 0, sizeof *mgm);
                memcpy(mgm->gid, gid->raw, 16);
-               mgm->next_gid_index = 0;
        }
 
        for (i = 0; i < MTHCA_QP_PER_MGM; ++i)
-               if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) {
+               if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) {
+                       mthca_dbg(dev, "QP %06x already a member of MGM\n",
+                                 ibqp->qp_num);
+                       err = 0;
+                       goto out;
+               } else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) {
                        mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31));
                        break;
                }
@@ -195,18 +201,19 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                goto out;
        }
 
-       err = mthca_WRITE_MGM(dev, index, mgm, &status);
+       err = mthca_WRITE_MGM(dev, index, mailbox, &status);
        if (err)
                goto out;
        if (status) {
                mthca_err(dev, "WRITE_MGM returned status %02x\n", status);
                err = -EINVAL;
+               goto out;
        }
 
        if (!link)
                goto out;
 
-       err = mthca_READ_MGM(dev, prev, mgm, &status);
+       err = mthca_READ_MGM(dev, prev, mailbox, &status);
        if (err)
                goto out;
        if (status) {
@@ -215,9 +222,9 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                goto out;
        }
 
-       mgm->next_gid_index = cpu_to_be32(index << 5);
+       mgm->next_gid_index = cpu_to_be32(index << 6);
 
-       err = mthca_WRITE_MGM(dev, prev, mgm, &status);
+       err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
        if (err)
                goto out;
        if (status) {
@@ -226,15 +233,20 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        }
 
  out:
-       up(&dev->mcg_table.sem);
-       kfree(mailbox);
+       if (err && link && index != -1) {
+               BUG_ON(index < dev->limits.num_mgms);
+               mthca_free(&dev->mcg_table.alloc, index);
+       }
+       mutex_unlock(&dev->mcg_table.mutex);
+
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
 int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 {
        struct mthca_dev *dev = to_mdev(ibqp->device);
-       void *mailbox;
+       struct mthca_mailbox *mailbox;
        struct mthca_mgm *mgm;
        u16 hash;
        int prev, index;
@@ -242,29 +254,28 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        int err;
        u8 status;
 
-       mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
-       if (!mailbox)
-               return -ENOMEM;
-       mgm = MAILBOX_ALIGN(mailbox);
+       mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+       mgm = mailbox->buf;
 
-       if (down_interruptible(&dev->mcg_table.sem))
-               return -EINTR;
+       mutex_lock(&dev->mcg_table.mutex);
 
-       err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
+       err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
        if (err)
                goto out;
 
        if (index == -1) {
                mthca_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
                          "not found\n",
-                         be16_to_cpu(((u16 *) gid->raw)[0]),
-                         be16_to_cpu(((u16 *) gid->raw)[1]),
-                         be16_to_cpu(((u16 *) gid->raw)[2]),
-                         be16_to_cpu(((u16 *) gid->raw)[3]),
-                         be16_to_cpu(((u16 *) gid->raw)[4]),
-                         be16_to_cpu(((u16 *) gid->raw)[5]),
-                         be16_to_cpu(((u16 *) gid->raw)[6]),
-                         be16_to_cpu(((u16 *) gid->raw)[7]));
+                         be16_to_cpu(((__be16 *) gid->raw)[0]),
+                         be16_to_cpu(((__be16 *) gid->raw)[1]),
+                         be16_to_cpu(((__be16 *) gid->raw)[2]),
+                         be16_to_cpu(((__be16 *) gid->raw)[3]),
+                         be16_to_cpu(((__be16 *) gid->raw)[4]),
+                         be16_to_cpu(((__be16 *) gid->raw)[5]),
+                         be16_to_cpu(((__be16 *) gid->raw)[6]),
+                         be16_to_cpu(((__be16 *) gid->raw)[7]));
                err = -EINVAL;
                goto out;
        }
@@ -285,7 +296,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        mgm->qp[loc]   = mgm->qp[i - 1];
        mgm->qp[i - 1] = 0;
 
-       err = mthca_WRITE_MGM(dev, index, mgm, &status);
+       err = mthca_WRITE_MGM(dev, index, mailbox, &status);
        if (err)
                goto out;
        if (status) {
@@ -297,14 +308,12 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
        if (i != 1)
                goto out;
 
-       goto out;
-
        if (prev == -1) {
                /* Remove entry from MGM */
-               if (be32_to_cpu(mgm->next_gid_index) >> 5) {
-                       err = mthca_READ_MGM(dev,
-                                            be32_to_cpu(mgm->next_gid_index) >> 5,
-                                            mgm, &status);
+               int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6;
+               if (amgm_index_to_free) {
+                       err = mthca_READ_MGM(dev, amgm_index_to_free,
+                                            mailbox, &status);
                        if (err)
                                goto out;
                        if (status) {
@@ -316,7 +325,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                } else
                        memset(mgm->gid, 0, 16);
 
-               err = mthca_WRITE_MGM(dev, index, mgm, &status);
+               err = mthca_WRITE_MGM(dev, index, mailbox, &status);
                if (err)
                        goto out;
                if (status) {
@@ -324,10 +333,14 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                        err = -EINVAL;
                        goto out;
                }
+               if (amgm_index_to_free) {
+                       BUG_ON(amgm_index_to_free < dev->limits.num_mgms);
+                       mthca_free(&dev->mcg_table.alloc, amgm_index_to_free);
+               }
        } else {
                /* Remove entry from AMGM */
-               index = be32_to_cpu(mgm->next_gid_index) >> 5;
-               err = mthca_READ_MGM(dev, prev, mgm, &status);
+               int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6;
+               err = mthca_READ_MGM(dev, prev, mailbox, &status);
                if (err)
                        goto out;
                if (status) {
@@ -336,9 +349,9 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                        goto out;
                }
 
-               mgm->next_gid_index = cpu_to_be32(index << 5);
+               mgm->next_gid_index = cpu_to_be32(curr_next_index << 6);
 
-               err = mthca_WRITE_MGM(dev, prev, mgm, &status);
+               err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
                if (err)
                        goto out;
                if (status) {
@@ -346,31 +359,35 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
                        err = -EINVAL;
                        goto out;
                }
+               BUG_ON(index < dev->limits.num_mgms);
+               mthca_free(&dev->mcg_table.alloc, index);
        }
 
  out:
-       up(&dev->mcg_table.sem);
-       kfree(mailbox);
+       mutex_unlock(&dev->mcg_table.mutex);
+
+       mthca_free_mailbox(dev, mailbox);
        return err;
 }
 
-int __devinit mthca_init_mcg_table(struct mthca_dev *dev)
+int mthca_init_mcg_table(struct mthca_dev *dev)
 {
        int err;
+       int table_size = dev->limits.num_mgms + dev->limits.num_amgms;
 
        err = mthca_alloc_init(&dev->mcg_table.alloc,
-                              dev->limits.num_amgms,
-                              dev->limits.num_amgms - 1,
-                              0);
+                              table_size,
+                              table_size - 1,
+                              dev->limits.num_mgms);
        if (err)
                return err;
 
-       init_MUTEX(&dev->mcg_table.sem);
+       mutex_init(&dev->mcg_table.mutex);
 
        return 0;
 }
 
-void __devexit mthca_cleanup_mcg_table(struct mthca_dev *dev)
+void mthca_cleanup_mcg_table(struct mthca_dev *dev)
 {
        mthca_alloc_cleanup(&dev->mcg_table.alloc);
 }