]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sif: SQ: Adding synchronization between wa4074 and post_send
authorWei Lin Guay <wei.lin.guay@oracle.com>
Thu, 23 Jun 2016 19:11:42 +0000 (21:11 +0200)
committerKnut Omang <knut.omang@oracle.com>
Sun, 3 Jul 2016 14:44:12 +0000 (16:44 +0200)
Orabug: 23607042

In pre_process_wa4074, the SQ lock must be held before corrupting
the checksum in the SQ entry. Besides, use inverse the checksum
value rather than setting it to 0.

Another missing case of acquiring of SQ lock is before generating
the completion.  The SQ lock is only held to access the sq_sw->last_seq
to avoid generating completion before post send is completed. If this
case happen, it might cause the completion to be generated using the old
wc_id.

Signed-off-by: Wei Lin Guay <wei.lin.guay@oracle.com>
Reviewed-by: Knut Omang <knut.omang@oracle.com>
drivers/infiniband/hw/sif/sif_r3.c

index 8a94598704119e1d04711551be135994243940ea..0a2d05e08c1b560aa39c517483ac596e19eb5e25 100644 (file)
@@ -490,6 +490,7 @@ int pre_process_wa4074(struct sif_dev *sdev, struct sif_qp *qp)
        struct psif_sq_entry *sqe;
        u16 head;
        int len;
+       unsigned long flags;
        struct sif_cq *cq = (sq && sq->cq_idx >= 0) ? get_sif_cq(sdev, sq->cq_idx) : NULL;
        struct sif_cq_sw *cq_sw = cq ? get_sif_cq_sw(sdev, cq->index) : NULL;
 
@@ -506,12 +507,14 @@ int pre_process_wa4074(struct sif_dev *sdev, struct sif_qp *qp)
        if (len <= 0)
                return -1;
 
+       spin_lock_irqsave(&sq->lock, flags);
        while (len) {
                head++;
                sqe = get_sq_entry(sq, head);
-               set_psif_wr__checksum(&sqe->wr, 0);
+               set_psif_wr__checksum(&sqe->wr, ~get_psif_wr__checksum(&sqe->wr));
                len--;
        }
+       spin_unlock_irqrestore(&sq->lock, flags);
        if (cq)
                set_bit(CQ_POLLING_NOT_ALLOWED, &cq_sw->flags);
 
@@ -527,7 +530,8 @@ int post_process_wa4074(struct sif_dev *sdev, struct sif_qp *qp)
        struct sif_sq_sw *sq_sw = sq ? get_sif_sq_sw(sdev, qp->qp_idx) : NULL;
        struct psif_qp lqqp;
        bool last_seq_set = false;
-       u16 last_seq, fence_seq;
+       u16 last_seq, fence_seq, last_gen_seq;
+       unsigned long flags;
        DECLARE_SIF_CQE_POLL(sdev, lcqe);
        int ret = 0;
        bool need_gen_fence_completion = true;
@@ -663,10 +667,19 @@ int post_process_wa4074(struct sif_dev *sdev, struct sif_qp *qp)
                goto check_in_flight_and_return;
        }
 
-       sif_log(sdev, SIF_WCE_V, "generate completion from %x to %x",
-               last_seq, sq_sw->last_seq);
 flush_sq_again:
-       for (; (!GREATER_16(last_seq, sq_sw->last_seq)); ++last_seq) {
+       /* We need lock here to retrieve the sq_sw->last_seq
+        * to make sure that post_send with sq_sw->last_seq is
+        * completed before generating a sq_flush_cqe.
+        */
+       spin_lock_irqsave(&sq->lock, flags);
+       last_gen_seq = sq_sw->last_seq;
+       spin_unlock_irqrestore(&sq->lock, flags);
+
+       sif_log(sdev, SIF_WCE_V, "generate completion from %x to %x",
+               last_seq, last_gen_seq);
+
+       for (; (!GREATER_16(last_seq, last_gen_seq)); ++last_seq) {
                sif_log(sdev, SIF_WCE_V, "generate completion %x",
                        last_seq);
 
@@ -713,11 +726,8 @@ flush_sq_again:
        sq_sw->trusted_seq = last_seq;
 
 check_in_flight_and_return:
-       if (test_and_clear_bit(FLUSH_SQ_IN_FLIGHT, &sq_sw->flags)) {
-               sif_log(sdev, SIF_WCE_V, "in-flight:generate completion from %x to %x",
-                       last_seq, sq_sw->last_seq);
+       if (test_and_clear_bit(FLUSH_SQ_IN_FLIGHT, &sq_sw->flags))
                goto flush_sq_again;
-       }
 
 err_post_wa4074:
        clear_bit(CQ_POLLING_NOT_ALLOWED, &cq_sw->flags);