Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / infiniband / hw / mthca / mthca_mcg.c
index 70a6553..47ca8a9 100644 (file)
  */
 
 #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 +64,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 +92,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 +127,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 +149,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 +173,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 +181,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 +202,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 +223,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 +234,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 +255,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 +297,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 +309,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 +326,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 +334,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 +350,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 +360,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 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);
 }