IB/ipath: Fix lost UD send work request
authorRalph Campbell <ralph.campbell@qlogic.com>
Fri, 15 Aug 2008 18:23:47 +0000 (11:23 -0700)
committerRoland Dreier <rolandd@cisco.com>
Fri, 15 Aug 2008 18:23:47 +0000 (11:23 -0700)
If a UD QP has some work requests queued to be sent by the DMA engine
followed by a local loopback work request, we have to wait for the
previous work requests to finish or the completion for the local
loopback work request would be generated out of order.  The problem
was that the work request queue pointer was already updated so that
the request would not be processed when the DMA queue drained.

Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/hw/ipath/ipath_ud.c

index 36aa242c487c4d582d39d94b86e53377466455ef..729446f56aab580d2ffcd7200a124d22ea6e7c3e 100644 (file)
@@ -267,6 +267,7 @@ int ipath_make_ud_req(struct ipath_qp *qp)
        u16 lrh0;
        u16 lid;
        int ret = 0;
+       int next_cur;
 
        spin_lock_irqsave(&qp->s_lock, flags);
 
@@ -290,8 +291,9 @@ int ipath_make_ud_req(struct ipath_qp *qp)
                goto bail;
 
        wqe = get_swqe_ptr(qp, qp->s_cur);
-       if (++qp->s_cur >= qp->s_size)
-               qp->s_cur = 0;
+       next_cur = qp->s_cur + 1;
+       if (next_cur >= qp->s_size)
+               next_cur = 0;
 
        /* Construct the header. */
        ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr;
@@ -315,6 +317,7 @@ int ipath_make_ud_req(struct ipath_qp *qp)
                                qp->s_flags |= IPATH_S_WAIT_DMA;
                                goto bail;
                        }
+                       qp->s_cur = next_cur;
                        spin_unlock_irqrestore(&qp->s_lock, flags);
                        ipath_ud_loopback(qp, wqe);
                        spin_lock_irqsave(&qp->s_lock, flags);
@@ -323,6 +326,7 @@ int ipath_make_ud_req(struct ipath_qp *qp)
                }
        }
 
+       qp->s_cur = next_cur;
        extra_bytes = -wqe->length & 3;
        nwords = (wqe->length + extra_bytes) >> 2;