From f1211b2ec7e1ce05136b97330b211c04dfe058f6 Mon Sep 17 00:00:00 2001 From: Wei Lin Guay Date: Mon, 31 Oct 2016 20:38:25 +0100 Subject: [PATCH] sif: cq: use refcnt to disable/enable cq polling 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 Reviewed-by: Knut Omang --- drivers/infiniband/hw/sif/sif_cq.c | 1 + drivers/infiniband/hw/sif/sif_int_user.h | 1 + drivers/infiniband/hw/sif/sif_r3.c | 29 ++++++++++++++---------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/hw/sif/sif_cq.c b/drivers/infiniband/hw/sif/sif_cq.c index 19f796cab38e..92204edbdb75 100644 --- a/drivers/infiniband/hw/sif/sif_cq.c +++ b/drivers/infiniband/hw/sif/sif_cq.c @@ -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); diff --git a/drivers/infiniband/hw/sif/sif_int_user.h b/drivers/infiniband/hw/sif/sif_int_user.h index 0fd6fe33d7b3..1ca4364c9617 100644 --- a/drivers/infiniband/hw/sif/sif_int_user.h +++ b/drivers/infiniband/hw/sif/sif_int_user.h @@ -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 diff --git a/drivers/infiniband/hw/sif/sif_r3.c b/drivers/infiniband/hw/sif/sif_r3.c index f7be78b83fbe..9a76c7342aa9 100644 --- a/drivers/infiniband/hw/sif/sif_r3.c +++ b/drivers/infiniband/hw/sif/sif_r3.c @@ -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); -- 2.50.1