IB/ipath: Fix a race where s_last is updated without lock held

There is a small window where a send work queue entry could be
overwritten by ib_post_send() because s_last is updated before the
entry is read.

This patch closes the window by acquiring the lock and updating
the last send work queue entry index after reading the wr_id.

Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index 4b6b7ee..54c61a9 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -630,11 +630,8 @@
 void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
 			 enum ib_wc_status status)
 {
-	u32 last = qp->s_last;
-
-	if (++last == qp->s_size)
-		last = 0;
-	qp->s_last = last;
+	unsigned long flags;
+	u32 last;
 
 	/* See ch. 11.2.4.1 and 10.7.3.1 */
 	if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
@@ -658,4 +655,11 @@
 		wc.port_num = 0;
 		ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
 	}
+
+	spin_lock_irqsave(&qp->s_lock, flags);
+	last = qp->s_last;
+	if (++last >= qp->s_size)
+		last = 0;
+	qp->s_last = last;
+	spin_unlock_irqrestore(&qp->s_lock, flags);
 }