IB/mthca: Fix posting lists of 256 receive requests to SRQ for Tavor
[safe/jmp/linux-2.6] / drivers / infiniband / hw / mthca / mthca_srq.c
index 47a6a75..b292fef 100644 (file)
@@ -192,7 +192,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
 
        /* Sanity check SRQ size before proceeding */
        if (attr->max_wr  > dev->limits.max_srq_wqes ||
-           attr->max_sge > dev->limits.max_sg)
+           attr->max_sge > dev->limits.max_srq_sge)
                return -EINVAL;
 
        srq->max      = attr->max_wr;
@@ -205,6 +205,10 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
        ds = max(64UL,
                 roundup_pow_of_two(sizeof (struct mthca_next_seg) +
                                    srq->max_gs * sizeof (struct mthca_data_seg)));
+
+       if (!mthca_is_memfree(dev) && (ds > dev->limits.max_desc_sz))
+               return -EINVAL;
+
        srq->wqe_shift = long_log2(ds);
 
        srq->srqn = mthca_alloc(&dev->srq_table.alloc);
@@ -237,7 +241,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
                goto err_out_mailbox;
 
        spin_lock_init(&srq->lock);
-       atomic_set(&srq->refcount, 1);
+       srq->refcount = 1;
        init_waitqueue_head(&srq->wait);
 
        if (mthca_is_memfree(dev))
@@ -304,6 +308,17 @@ err_out:
        return err;
 }
 
+static inline int get_srq_refcount(struct mthca_dev *dev, struct mthca_srq *srq)
+{
+       int c;
+
+       spin_lock_irq(&dev->srq_table.lock);
+       c = srq->refcount;
+       spin_unlock_irq(&dev->srq_table.lock);
+
+       return c;
+}
+
 void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq)
 {
        struct mthca_mailbox *mailbox;
@@ -325,10 +340,10 @@ void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq)
        spin_lock_irq(&dev->srq_table.lock);
        mthca_array_clear(&dev->srq_table.srq,
                          srq->srqn & (dev->limits.num_srqs - 1));
+       --srq->refcount;
        spin_unlock_irq(&dev->srq_table.lock);
 
-       atomic_dec(&srq->refcount);
-       wait_event(srq->wait, !atomic_read(&srq->refcount));
+       wait_event(srq->wait, !get_srq_refcount(dev, srq));
 
        if (!srq->ibsrq.uobject) {
                mthca_free_srq_buf(dev, srq);
@@ -354,6 +369,8 @@ int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
                return -EINVAL;
 
        if (attr_mask & IB_SRQ_LIMIT) {
+               if (attr->srq_limit > srq->max)
+                       return -EINVAL;
                ret = mthca_ARM_SRQ(dev, srq->srqn, attr->srq_limit, &status);
                if (ret)
                        return ret;
@@ -408,7 +425,7 @@ void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
        spin_lock(&dev->srq_table.lock);
        srq = mthca_array_get(&dev->srq_table.srq, srqn & (dev->limits.num_srqs - 1));
        if (srq)
-               atomic_inc(&srq->refcount);
+               ++srq->refcount;
        spin_unlock(&dev->srq_table.lock);
 
        if (!srq) {
@@ -425,8 +442,10 @@ void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
        srq->ibsrq.event_handler(&event, srq->ibsrq.srq_context);
 
 out:
-       if (atomic_dec_and_test(&srq->refcount))
+       spin_lock(&dev->srq_table.lock);
+       if (!--srq->refcount)
                wake_up(&srq->wait);
+       spin_unlock(&dev->srq_table.lock);
 }
 
 /*
@@ -471,26 +490,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
 
        first_ind = srq->first_free;
 
-       for (nreq = 0; wr; ++nreq, wr = wr->next) {
-               if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
-                       nreq = 0;
-
-                       doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift);
-                       doorbell[1] = cpu_to_be32(srq->srqn << 8);
-
-                       /*
-                        * Make sure that descriptors are written
-                        * before doorbell is rung.
-                        */
-                       wmb();
-
-                       mthca_write64(doorbell,
-                                     dev->kar + MTHCA_RECEIVE_DOORBELL,
-                                     MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
-
-                       first_ind = srq->first_free;
-               }
-
+       for (nreq = 0; wr; wr = wr->next) {
                ind = srq->first_free;
 
                if (ind < 0) {
@@ -550,6 +550,26 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
 
                srq->wrid[ind]  = wr->wr_id;
                srq->first_free = next_ind;
+
+               ++nreq;
+               if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
+                       nreq = 0;
+
+                       doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift);
+                       doorbell[1] = cpu_to_be32(srq->srqn << 8);
+
+                       /*
+                        * Make sure that descriptors are written
+                        * before doorbell is rung.
+                        */
+                       wmb();
+
+                       mthca_write64(doorbell,
+                                     dev->kar + MTHCA_RECEIVE_DOORBELL,
+                                     MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+
+                       first_ind = srq->first_free;
+               }
        }
 
        if (likely(nreq)) {
@@ -654,6 +674,31 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
        return err;
 }
 
+int mthca_max_srq_sge(struct mthca_dev *dev)
+{
+       if (mthca_is_memfree(dev))
+               return dev->limits.max_sg;
+
+       /*
+        * SRQ allocations are based on powers of 2 for Tavor,
+        * (although they only need to be multiples of 16 bytes).
+        *
+        * Therefore, we need to base the max number of sg entries on
+        * the largest power of 2 descriptor size that is <= to the
+        * actual max WQE descriptor size, rather than return the
+        * max_sg value given by the firmware (which is based on WQE
+        * sizes as multiples of 16, not powers of 2).
+        *
+        * If SRQ implementation is changed for Tavor to be based on
+        * multiples of 16, the calculation below can be deleted and
+        * the FW max_sg value returned.
+        */
+       return min_t(int, dev->limits.max_sg,
+                    ((1 << (fls(dev->limits.max_desc_sz) - 1)) -
+                     sizeof (struct mthca_next_seg)) /
+                    sizeof (struct mthca_data_seg));
+}
+
 int __devinit mthca_init_srq_table(struct mthca_dev *dev)
 {
        int err;
@@ -678,7 +723,7 @@ int __devinit mthca_init_srq_table(struct mthca_dev *dev)
        return err;
 }
 
-void __devexit mthca_cleanup_srq_table(struct mthca_dev *dev)
+void mthca_cleanup_srq_table(struct mthca_dev *dev)
 {
        if (!(dev->mthca_flags & MTHCA_FLAG_SRQ))
                return;