]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sif: cq: use refcnt to disable/enable cq polling
authorWei Lin Guay <wei.lin.guay@oracle.com>
Mon, 31 Oct 2016 19:38:25 +0000 (20:38 +0100)
committerKnut Omang <knut.omang@oracle.com>
Fri, 11 Nov 2016 16:36:58 +0000 (17:36 +0100)
Due to a hardware bug, sifdrv must clean up the cq
before it is being polled by the user. Thus, sifdrv
uses CQ_POLLING_NOT_ALLOWED bitmask to disable/enable
cq polling.

Nevertheless, the bit mask operation is not sufficient in
a shared cq scenario (many qps to one cq). The cq clean up
is performed by each qp and it might be performed concurrently.
As a result, the cq polling might be enabled before all qps
have clean up the cq.

Thus, this patch uses refcnt to disable/enable cq polling.
The CQ_POLLING_NOT_ALLOWED bitmask is kept in order to have
backward compatibility in the user library.

Orabug: 25038731

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

index 19f796cab38e1e90ac0ad9aefe709f1e1512d443..92204edbdb753cd68ee72044517d528c549067e1 100644 (file)
@@ -285,6 +285,7 @@ struct sif_cq *create_cq(struct sif_pd *pd, int entries,
        memset(&lcq_sw, 0, sizeof(lcq_sw));
        lcq_sw.head_indx = cq_sw->next_seq;
        copy_conv_to_hw(&cq_sw->d, &lcq_sw, sizeof(lcq_sw));
+       atomic_set(&cq_sw->cleanup_refcnt, 0);
 
        spin_lock_init(&cq->lock);
 
index 0fd6fe33d7b32acbc965f5364b02d0da549653e4..1ca4364c96174242a20f8baa4b8405b0504f7372 100644 (file)
@@ -83,6 +83,7 @@ struct sif_cq_sw {
        __u32 miss_cnt;         /* Number of in-flight completions observed by poll_cq */
        __u32 miss_occ;         /* Number of times 1 or more in-flight completions was seen */
        unsigned long flags;    /* Flags, using unsigned long due to test_set/test_and_set_bit */
+       atomic_t cleanup_refcnt;/* A refcnt to enable/disable cq polling. */
 };
 
 #endif
index f7be78b83fbec31786d1a2816f5249ccbcc01fa8..9a76c7342aa9a77393dc230f19f9fc4d081f7f4d 100644 (file)
@@ -504,12 +504,15 @@ int pre_process_wa4074(struct sif_dev *sdev, struct sif_qp *qp)
        if (qp->flags & SIF_QPF_NO_EVICT)
                return 0; /* do-not-evict QPs don't have any SQs */
 
-       if (unlikely(!sq)) {
-               sif_log(sdev, SIF_INFO, "sq not defined for qp %d (type %s)",
+       if (unlikely(!sq || !cq)) {
+               sif_log(sdev, SIF_INFO, "sq/cq not defined for qp %d (type %s)",
                        qp->qp_idx, string_enum_psif_qp_trans(qp->type));
                return -1;
        }
 
+       set_bit(CQ_POLLING_NOT_ALLOWED, &cq_sw->flags);
+       atomic_inc(&cq_sw->cleanup_refcnt);
+
        len = outstanding_wqes(sdev, qp, &head);
        if (len <= 0)
                return -1;
@@ -523,9 +526,6 @@ int pre_process_wa4074(struct sif_dev *sdev, struct sif_qp *qp)
        }
        atomic64_add(len, &sdev->wa_stats.wa4074[WRS_CSUM_CORR_WA4074_CNT]);
        spin_unlock_irqrestore(&sq->lock, flags);
-       if (cq)
-               set_bit(CQ_POLLING_NOT_ALLOWED, &cq_sw->flags);
-
        atomic64_inc(&sdev->wa_stats.wa4074[PRE_WA4074_CNT]);
 
        return 0;
@@ -578,9 +578,6 @@ int post_process_wa4074(struct sif_dev *sdev, struct sif_qp *qp)
                return ret;
        }
 
-       if ((sq_sw->last_seq - sq_sw->head_seq) == 0)
-               goto err_post_wa4074;
-
        /* if SQ has been flushed before, continue to generate
         * the remaining completions.
         */
@@ -590,11 +587,18 @@ int post_process_wa4074(struct sif_dev *sdev, struct sif_qp *qp)
                goto flush_sq_again;
        }
 
+       /* if there is nothing to clean-up, decrement the refcnt.
+        * This is needed as pre_process_wa4074 has increment the refcnt.
+        */
+       if ((sq_sw->last_seq - sq_sw->head_seq) == 0) {
+               if (atomic_dec_and_test(&cq_sw->cleanup_refcnt))
+                       clear_bit(CQ_POLLING_NOT_ALLOWED, &cq_sw->flags);
+               goto err_post_wa4074;
+       }
+
        copy_conv_to_sw(&lqqp, &qp->d, sizeof(lqqp));
        last_seq = READ_ONCE(sq_sw->last_seq);
 
-       set_bit(CQ_POLLING_NOT_ALLOWED, &cq_sw->flags);
-
        sif_log(sdev, SIF_WCE_V, "sq_retry_seq %x sq_seq %x last_seq %x head_seq %x",
                lqqp.state.retry_sq_seq, lqqp.state.sq_seq, sq_sw->last_seq, sq_sw->head_seq);
 
@@ -654,6 +658,7 @@ int post_process_wa4074(struct sif_dev *sdev, struct sif_qp *qp)
 
                if (!last_seq_set) {
                        sif_log(sdev, SIF_INFO, "failed to generate a completion to cq");
+                       ret = -EFAULT;
                        goto err_post_wa4074;
                }
 
@@ -674,7 +679,8 @@ int post_process_wa4074(struct sif_dev *sdev, struct sif_qp *qp)
        last_seq = walk_and_update_cqes(sdev, qp, sq_sw->head_seq + 1, sq_sw->last_seq);
        sq_sw->trusted_seq = last_seq;
 
-       clear_bit(CQ_POLLING_NOT_ALLOWED, &cq_sw->flags);
+       if (atomic_dec_and_test(&cq_sw->cleanup_refcnt))
+               clear_bit(CQ_POLLING_NOT_ALLOWED, &cq_sw->flags);
 
        if (GREATER_16(last_seq, sq_sw->last_seq)) {
                sif_log(sdev, SIF_WCE_V, "last seq %x > sq_sw->last_seq %x\n", last_seq, sq_sw->last_seq);
@@ -766,7 +772,6 @@ check_in_flight_and_return:
                goto flush_sq_again;
 
 err_post_wa4074:
-       clear_bit(CQ_POLLING_NOT_ALLOWED, &cq_sw->flags);
        clear_bit(FLUSH_SQ_IN_FLIGHT, &sq_sw->flags);
        clear_bit(FLUSH_SQ_IN_PROGRESS, &sq_sw->flags);