diff mbox

[rdma-core] libhns: Support flush cqe for hip08 in user space

Message ID 1532002997-7225-1-git-send-email-liuyixian@huawei.com (mailing list archive)
State Changes Requested
Delegated to: Leon Romanovsky
Headers show

Commit Message

Yixian Liu July 19, 2018, 12:23 p.m. UTC
The cqe should be flushed error completion status if an related
error is detected while poll cqe, post send or post recv.

Record doorbell is used to notify the head pointer of sq and rq
to the kernel.

Signed-off-by: Yixian Liu <liuyixian@huawei.com>
---
 kernel-headers/rdma/hns-abi.h    |  1 +
 providers/hns/hns_roce_u.h       |  1 +
 providers/hns/hns_roce_u_hw_v2.c | 53 ++++++++++++++++++++++++++++++++++++++++
 providers/hns/hns_roce_u_hw_v2.h |  1 +
 providers/hns/hns_roce_u_verbs.c | 24 +++++++++++++++---
 5 files changed, 77 insertions(+), 3 deletions(-)

Comments

Yuval Shaia July 20, 2018, 10:26 a.m. UTC | #1
On Thu, Jul 19, 2018 at 08:23:17PM +0800, Yixian Liu wrote:
> The cqe should be flushed error completion status if an related
> error is detected while poll cqe, post send or post recv.
> 
> Record doorbell is used to notify the head pointer of sq and rq
> to the kernel.
> 
> Signed-off-by: Yixian Liu <liuyixian@huawei.com>
> ---
>  kernel-headers/rdma/hns-abi.h    |  1 +
>  providers/hns/hns_roce_u.h       |  1 +
>  providers/hns/hns_roce_u_hw_v2.c | 53 ++++++++++++++++++++++++++++++++++++++++
>  providers/hns/hns_roce_u_hw_v2.h |  1 +
>  providers/hns/hns_roce_u_verbs.c | 24 +++++++++++++++---
>  5 files changed, 77 insertions(+), 3 deletions(-)
> 
> diff --git a/kernel-headers/rdma/hns-abi.h b/kernel-headers/rdma/hns-abi.h
> index 78613b6..c1f8773 100644
> --- a/kernel-headers/rdma/hns-abi.h
> +++ b/kernel-headers/rdma/hns-abi.h
> @@ -53,6 +53,7 @@ struct hns_roce_ib_create_qp {
>  	__u8    log_sq_stride;
>  	__u8    sq_no_prefetch;
>  	__u8    reserved[5];
> +	__aligned_u64 sdb_addr;
>  };
>  
>  struct hns_roce_ib_create_qp_resp {
> diff --git a/providers/hns/hns_roce_u.h b/providers/hns/hns_roce_u.h
> index 8426569..2b2070f 100644
> --- a/providers/hns/hns_roce_u.h
> +++ b/providers/hns/hns_roce_u.h
> @@ -211,6 +211,7 @@ struct hns_roce_qp {
>  	struct hns_roce_wq		sq;
>  	struct hns_roce_wq		rq;
>  	uint32_t			*rdb;
> +	uint32_t			*sdb;
>  	struct hns_roce_sge_ex		sge;
>  	unsigned int			next_sge;
>  	int				port_num;
> diff --git a/providers/hns/hns_roce_u_hw_v2.c b/providers/hns/hns_roce_u_hw_v2.c
> index ca59011..588a946 100644
> --- a/providers/hns/hns_roce_u_hw_v2.c
> +++ b/providers/hns/hns_roce_u_hw_v2.c
> @@ -237,6 +237,9 @@ static void hns_roce_v2_clear_qp(struct hns_roce_context *ctx, uint32_t qpn)
>  		ctx->qp_table[tind].table[qpn & ctx->qp_table_mask] = NULL;
>  }
>  
> +static int hns_roce_u_v2_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
> +				   int attr_mask);
> +
>  static int hns_roce_v2_poll_one(struct hns_roce_cq *cq,
>  				struct hns_roce_qp **cur_qp, struct ibv_wc *wc)
>  {
> @@ -248,6 +251,9 @@ static int hns_roce_v2_poll_one(struct hns_roce_cq *cq,
>  	struct hns_roce_v2_cqe *cqe = NULL;
>  	struct hns_roce_rinl_sge *sge_list;
>  	uint32_t opcode;
> +	struct ibv_qp_attr attr;
> +	int attr_mask;
> +	int ret;
>  
>  	/* According to CI, find the relative cqe */
>  	cqe = next_cqe_sw_v2(cq);
> @@ -314,6 +320,19 @@ static int hns_roce_v2_poll_one(struct hns_roce_cq *cq,
>  	if (roce_get_field(cqe->byte_4, CQE_BYTE_4_STATUS_M,
>  			   CQE_BYTE_4_STATUS_S) != HNS_ROCE_V2_CQE_SUCCESS) {
>  		hns_roce_v2_handle_error_cqe(cqe, wc);
> +
> +		/* flush cqe */
> +		if ((wc->status != IBV_WC_SUCCESS) &&
> +		    (wc->status != IBV_WC_WR_FLUSH_ERR)) {
> +			attr_mask = IBV_QP_STATE;
> +			attr.qp_state = IBV_QPS_ERR;
> +			ret = hns_roce_u_v2_modify_qp(&(*cur_qp)->ibv_qp,
> +						      &attr, attr_mask);
> +			if (ret) {
> +				fprintf(stderr, PFX "failed to modify qp!\n");

I do not understand why poll_one and got the honor of printing while
post_send and post_recv are not.

Is it because of caller taking care of it?

Suggesting consistency.

> +				return ret;
> +			}
> +		}
>  		return V2_CQ_OK;
>  	}
>  
> @@ -533,6 +552,8 @@ static int hns_roce_u_v2_post_send(struct ibv_qp *ibvqp, struct ibv_send_wr *wr,
>  	struct hns_roce_context *ctx = to_hr_ctx(ibvqp->context);
>  	struct hns_roce_rc_sq_wqe *rc_sq_wqe;
>  	struct hns_roce_v2_wqe_data_seg *dseg;
> +	struct ibv_qp_attr attr;
> +	int attr_mask;
>  
>  	pthread_spin_lock(&qp->sq.lock);
>  
> @@ -760,7 +781,22 @@ out:
>  		hns_roce_update_sq_db(ctx, qp->ibv_qp.qp_num, qp->sl,
>  				     qp->sq.head & ((qp->sq.wqe_cnt << 1) - 1));
>  
> +		if (qp->flags & HNS_ROCE_SUPPORT_SQ_RECORD_DB)
> +			*(qp->sdb) = qp->sq.head & 0xffff;
> +
>  		qp->next_sge = ind_sge;
> +
> +		if (ibvqp->state == IBV_QPS_ERR) {
> +			attr_mask = IBV_QP_STATE;
> +			attr.qp_state = IBV_QPS_ERR;
> +
> +			ret = hns_roce_u_v2_modify_qp(ibvqp, &attr, attr_mask);
> +			if (ret) {
> +				pthread_spin_unlock(&qp->sq.lock);
> +				*bad_wr = wr;
> +				return ret;
> +			}
> +		}
>  	}
>  
>  	pthread_spin_unlock(&qp->sq.lock);
> @@ -778,6 +814,8 @@ static int hns_roce_u_v2_post_recv(struct ibv_qp *ibvqp, struct ibv_recv_wr *wr,
>  	struct hns_roce_context *ctx = to_hr_ctx(ibvqp->context);
>  	struct hns_roce_v2_wqe_data_seg *dseg;
>  	struct hns_roce_rinl_sge *sge_list;
> +	struct ibv_qp_attr attr;
> +	int attr_mask;
>  	void *wqe;
>  	int i;
>  
> @@ -848,6 +886,18 @@ out:
>  		else
>  			hns_roce_update_rq_db(ctx, qp->ibv_qp.qp_num,
>  				     qp->rq.head & ((qp->rq.wqe_cnt << 1) - 1));
> +
> +		if (ibvqp->state == IBV_QPS_ERR) {
> +			attr_mask = IBV_QP_STATE;
> +			attr.qp_state = IBV_QPS_ERR;
> +
> +			ret = hns_roce_u_v2_modify_qp(ibvqp, &attr, attr_mask);
> +			if (ret) {
> +				pthread_spin_unlock(&qp->rq.lock);
> +				*bad_wr = wr;
> +				return ret;
> +			}
> +		}
>  	}
>  
>  	pthread_spin_unlock(&qp->rq.lock);
> @@ -991,6 +1041,9 @@ static int hns_roce_u_v2_destroy_qp(struct ibv_qp *ibqp)
>  	if (qp->rq.max_gs)
>  		hns_roce_free_db(to_hr_ctx(ibqp->context), qp->rdb,
>  				 HNS_ROCE_QP_TYPE_DB);
> +	if (qp->sq.max_gs)
> +		hns_roce_free_db(to_hr_ctx(ibqp->context), qp->sdb,
> +				 HNS_ROCE_QP_TYPE_DB);
>  
>  	hns_roce_free_buf(&qp->buf);
>  	if (qp->rq_rinl_buf.wqe_list) {
> diff --git a/providers/hns/hns_roce_u_hw_v2.h b/providers/hns/hns_roce_u_hw_v2.h
> index 84a7726..73b65bc 100644
> --- a/providers/hns/hns_roce_u_hw_v2.h
> +++ b/providers/hns/hns_roce_u_hw_v2.h
> @@ -42,6 +42,7 @@
>  
>  enum {
>  	HNS_ROCE_SUPPORT_RQ_RECORD_DB = 1 << 0,
> +	HNS_ROCE_SUPPORT_SQ_RECORD_DB = 1 << 1,
>  };
>  
>  enum {
> diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
> index 13b6d71..de9e7ab 100644
> --- a/providers/hns/hns_roce_u_verbs.c
> +++ b/providers/hns/hns_roce_u_verbs.c
> @@ -573,7 +573,7 @@ struct ibv_qp *hns_roce_u_create_qp(struct ibv_pd *pd,
>  
>  	if (hns_roce_alloc_qp_buf(pd, &attr->cap, attr->qp_type, qp)) {
>  		fprintf(stderr, "hns_roce_alloc_qp_buf failed!\n");
> -		goto err;
> +		goto err_buf;
>  	}
>  
>  	hns_roce_init_qp_indices(qp);
> @@ -585,10 +585,23 @@ struct ibv_qp *hns_roce_u_create_qp(struct ibv_pd *pd,
>  	}
>  
>  	if ((to_hr_dev(pd->context->device)->hw_version != HNS_ROCE_HW_VER1) &&
> +		attr->cap.max_send_sge) {
> +		qp->sdb = hns_roce_alloc_db(context, HNS_ROCE_QP_TYPE_DB);
> +		if (!qp->sdb) {
> +			fprintf(stderr, "alloc sdb buffer failed!\n");
> +			goto err_free;
> +		}
> +
> +		*(qp->sdb) = 0;
> +		cmd.sdb_addr = (uintptr_t)qp->sdb;
> +	} else
> +		cmd.sdb_addr = 0;
> +
> +	if ((to_hr_dev(pd->context->device)->hw_version != HNS_ROCE_HW_VER1) &&
>  	    attr->cap.max_recv_sge) {
>  		qp->rdb = hns_roce_alloc_db(context, HNS_ROCE_QP_TYPE_DB);
>  		if (!qp->rdb)
> -			goto err_free;
> +			goto err_sq_db;
>  
>  		*(qp->rdb) = 0;
>  		cmd.db_addr = (uintptr_t) qp->rdb;
> @@ -643,13 +656,18 @@ err_rq_db:
>  	    attr->cap.max_recv_sge)
>  		hns_roce_free_db(context, qp->rdb, HNS_ROCE_QP_TYPE_DB);
>  
> +err_sq_db:
> +	if ((to_hr_dev(pd->context->device)->hw_version != HNS_ROCE_HW_VER1) &&
> +	    attr->cap.max_send_sge)
> +		hns_roce_free_db(context, qp->sdb, HNS_ROCE_QP_TYPE_DB);
> +
>  err_free:
>  	free(qp->sq.wrid);
>  	if (qp->rq.wqe_cnt)
>  		free(qp->rq.wrid);
>  	hns_roce_free_buf(&qp->buf);
>  
> -err:
> +err_buf:
>  	free(qp);
>  
>  	return NULL;
> -- 
> 2.7.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Yixian Liu July 21, 2018, 7:53 a.m. UTC | #2
On 2018/7/20 18:26, Yuval Shaia wrote:
> On Thu, Jul 19, 2018 at 08:23:17PM +0800, Yixian Liu wrote:
>> The cqe should be flushed error completion status if an related
>> error is detected while poll cqe, post send or post recv.
>>
>> Record doorbell is used to notify the head pointer of sq and rq
>> to the kernel.
>>
>> Signed-off-by: Yixian Liu <liuyixian@huawei.com>
>> ---
>>  kernel-headers/rdma/hns-abi.h    |  1 +
>>  providers/hns/hns_roce_u.h       |  1 +
>>  providers/hns/hns_roce_u_hw_v2.c | 53 ++++++++++++++++++++++++++++++++++++++++
>>  providers/hns/hns_roce_u_hw_v2.h |  1 +
>>  providers/hns/hns_roce_u_verbs.c | 24 +++++++++++++++---
>>  5 files changed, 77 insertions(+), 3 deletions(-)
>>
>> diff --git a/kernel-headers/rdma/hns-abi.h b/kernel-headers/rdma/hns-abi.h
>> index 78613b6..c1f8773 100644
>> --- a/kernel-headers/rdma/hns-abi.h
>> +++ b/kernel-headers/rdma/hns-abi.h
>> @@ -53,6 +53,7 @@ struct hns_roce_ib_create_qp {
>>  	__u8    log_sq_stride;
>>  	__u8    sq_no_prefetch;
>>  	__u8    reserved[5];
>> +	__aligned_u64 sdb_addr;
>>  };
>>  
>>  struct hns_roce_ib_create_qp_resp {
>> diff --git a/providers/hns/hns_roce_u.h b/providers/hns/hns_roce_u.h
>> index 8426569..2b2070f 100644
>> --- a/providers/hns/hns_roce_u.h
>> +++ b/providers/hns/hns_roce_u.h
>> @@ -211,6 +211,7 @@ struct hns_roce_qp {
>>  	struct hns_roce_wq		sq;
>>  	struct hns_roce_wq		rq;
>>  	uint32_t			*rdb;
>> +	uint32_t			*sdb;
>>  	struct hns_roce_sge_ex		sge;
>>  	unsigned int			next_sge;
>>  	int				port_num;
>> diff --git a/providers/hns/hns_roce_u_hw_v2.c b/providers/hns/hns_roce_u_hw_v2.c
>> index ca59011..588a946 100644
>> --- a/providers/hns/hns_roce_u_hw_v2.c
>> +++ b/providers/hns/hns_roce_u_hw_v2.c
>> @@ -237,6 +237,9 @@ static void hns_roce_v2_clear_qp(struct hns_roce_context *ctx, uint32_t qpn)
>>  		ctx->qp_table[tind].table[qpn & ctx->qp_table_mask] = NULL;
>>  }
>>  
>> +static int hns_roce_u_v2_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
>> +				   int attr_mask);
>> +
>>  static int hns_roce_v2_poll_one(struct hns_roce_cq *cq,
>>  				struct hns_roce_qp **cur_qp, struct ibv_wc *wc)
>>  {
>> @@ -248,6 +251,9 @@ static int hns_roce_v2_poll_one(struct hns_roce_cq *cq,
>>  	struct hns_roce_v2_cqe *cqe = NULL;
>>  	struct hns_roce_rinl_sge *sge_list;
>>  	uint32_t opcode;
>> +	struct ibv_qp_attr attr;
>> +	int attr_mask;
>> +	int ret;
>>  
>>  	/* According to CI, find the relative cqe */
>>  	cqe = next_cqe_sw_v2(cq);
>> @@ -314,6 +320,19 @@ static int hns_roce_v2_poll_one(struct hns_roce_cq *cq,
>>  	if (roce_get_field(cqe->byte_4, CQE_BYTE_4_STATUS_M,
>>  			   CQE_BYTE_4_STATUS_S) != HNS_ROCE_V2_CQE_SUCCESS) {
>>  		hns_roce_v2_handle_error_cqe(cqe, wc);
>> +
>> +		/* flush cqe */
>> +		if ((wc->status != IBV_WC_SUCCESS) &&
>> +		    (wc->status != IBV_WC_WR_FLUSH_ERR)) {
>> +			attr_mask = IBV_QP_STATE;
>> +			attr.qp_state = IBV_QPS_ERR;
>> +			ret = hns_roce_u_v2_modify_qp(&(*cur_qp)->ibv_qp,
>> +						      &attr, attr_mask);
>> +			if (ret) {
>> +				fprintf(stderr, PFX "failed to modify qp!\n");
> 
> I do not understand why poll_one and got the honor of printing while
> post_send and post_recv are not.
> 
> Is it because of caller taking care of it?
> 
> Suggesting consistency.
> 

Hi Yuval,

Thanks for your comment! I will fix it and keep consistent in next version.

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/kernel-headers/rdma/hns-abi.h b/kernel-headers/rdma/hns-abi.h
index 78613b6..c1f8773 100644
--- a/kernel-headers/rdma/hns-abi.h
+++ b/kernel-headers/rdma/hns-abi.h
@@ -53,6 +53,7 @@  struct hns_roce_ib_create_qp {
 	__u8    log_sq_stride;
 	__u8    sq_no_prefetch;
 	__u8    reserved[5];
+	__aligned_u64 sdb_addr;
 };
 
 struct hns_roce_ib_create_qp_resp {
diff --git a/providers/hns/hns_roce_u.h b/providers/hns/hns_roce_u.h
index 8426569..2b2070f 100644
--- a/providers/hns/hns_roce_u.h
+++ b/providers/hns/hns_roce_u.h
@@ -211,6 +211,7 @@  struct hns_roce_qp {
 	struct hns_roce_wq		sq;
 	struct hns_roce_wq		rq;
 	uint32_t			*rdb;
+	uint32_t			*sdb;
 	struct hns_roce_sge_ex		sge;
 	unsigned int			next_sge;
 	int				port_num;
diff --git a/providers/hns/hns_roce_u_hw_v2.c b/providers/hns/hns_roce_u_hw_v2.c
index ca59011..588a946 100644
--- a/providers/hns/hns_roce_u_hw_v2.c
+++ b/providers/hns/hns_roce_u_hw_v2.c
@@ -237,6 +237,9 @@  static void hns_roce_v2_clear_qp(struct hns_roce_context *ctx, uint32_t qpn)
 		ctx->qp_table[tind].table[qpn & ctx->qp_table_mask] = NULL;
 }
 
+static int hns_roce_u_v2_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+				   int attr_mask);
+
 static int hns_roce_v2_poll_one(struct hns_roce_cq *cq,
 				struct hns_roce_qp **cur_qp, struct ibv_wc *wc)
 {
@@ -248,6 +251,9 @@  static int hns_roce_v2_poll_one(struct hns_roce_cq *cq,
 	struct hns_roce_v2_cqe *cqe = NULL;
 	struct hns_roce_rinl_sge *sge_list;
 	uint32_t opcode;
+	struct ibv_qp_attr attr;
+	int attr_mask;
+	int ret;
 
 	/* According to CI, find the relative cqe */
 	cqe = next_cqe_sw_v2(cq);
@@ -314,6 +320,19 @@  static int hns_roce_v2_poll_one(struct hns_roce_cq *cq,
 	if (roce_get_field(cqe->byte_4, CQE_BYTE_4_STATUS_M,
 			   CQE_BYTE_4_STATUS_S) != HNS_ROCE_V2_CQE_SUCCESS) {
 		hns_roce_v2_handle_error_cqe(cqe, wc);
+
+		/* flush cqe */
+		if ((wc->status != IBV_WC_SUCCESS) &&
+		    (wc->status != IBV_WC_WR_FLUSH_ERR)) {
+			attr_mask = IBV_QP_STATE;
+			attr.qp_state = IBV_QPS_ERR;
+			ret = hns_roce_u_v2_modify_qp(&(*cur_qp)->ibv_qp,
+						      &attr, attr_mask);
+			if (ret) {
+				fprintf(stderr, PFX "failed to modify qp!\n");
+				return ret;
+			}
+		}
 		return V2_CQ_OK;
 	}
 
@@ -533,6 +552,8 @@  static int hns_roce_u_v2_post_send(struct ibv_qp *ibvqp, struct ibv_send_wr *wr,
 	struct hns_roce_context *ctx = to_hr_ctx(ibvqp->context);
 	struct hns_roce_rc_sq_wqe *rc_sq_wqe;
 	struct hns_roce_v2_wqe_data_seg *dseg;
+	struct ibv_qp_attr attr;
+	int attr_mask;
 
 	pthread_spin_lock(&qp->sq.lock);
 
@@ -760,7 +781,22 @@  out:
 		hns_roce_update_sq_db(ctx, qp->ibv_qp.qp_num, qp->sl,
 				     qp->sq.head & ((qp->sq.wqe_cnt << 1) - 1));
 
+		if (qp->flags & HNS_ROCE_SUPPORT_SQ_RECORD_DB)
+			*(qp->sdb) = qp->sq.head & 0xffff;
+
 		qp->next_sge = ind_sge;
+
+		if (ibvqp->state == IBV_QPS_ERR) {
+			attr_mask = IBV_QP_STATE;
+			attr.qp_state = IBV_QPS_ERR;
+
+			ret = hns_roce_u_v2_modify_qp(ibvqp, &attr, attr_mask);
+			if (ret) {
+				pthread_spin_unlock(&qp->sq.lock);
+				*bad_wr = wr;
+				return ret;
+			}
+		}
 	}
 
 	pthread_spin_unlock(&qp->sq.lock);
@@ -778,6 +814,8 @@  static int hns_roce_u_v2_post_recv(struct ibv_qp *ibvqp, struct ibv_recv_wr *wr,
 	struct hns_roce_context *ctx = to_hr_ctx(ibvqp->context);
 	struct hns_roce_v2_wqe_data_seg *dseg;
 	struct hns_roce_rinl_sge *sge_list;
+	struct ibv_qp_attr attr;
+	int attr_mask;
 	void *wqe;
 	int i;
 
@@ -848,6 +886,18 @@  out:
 		else
 			hns_roce_update_rq_db(ctx, qp->ibv_qp.qp_num,
 				     qp->rq.head & ((qp->rq.wqe_cnt << 1) - 1));
+
+		if (ibvqp->state == IBV_QPS_ERR) {
+			attr_mask = IBV_QP_STATE;
+			attr.qp_state = IBV_QPS_ERR;
+
+			ret = hns_roce_u_v2_modify_qp(ibvqp, &attr, attr_mask);
+			if (ret) {
+				pthread_spin_unlock(&qp->rq.lock);
+				*bad_wr = wr;
+				return ret;
+			}
+		}
 	}
 
 	pthread_spin_unlock(&qp->rq.lock);
@@ -991,6 +1041,9 @@  static int hns_roce_u_v2_destroy_qp(struct ibv_qp *ibqp)
 	if (qp->rq.max_gs)
 		hns_roce_free_db(to_hr_ctx(ibqp->context), qp->rdb,
 				 HNS_ROCE_QP_TYPE_DB);
+	if (qp->sq.max_gs)
+		hns_roce_free_db(to_hr_ctx(ibqp->context), qp->sdb,
+				 HNS_ROCE_QP_TYPE_DB);
 
 	hns_roce_free_buf(&qp->buf);
 	if (qp->rq_rinl_buf.wqe_list) {
diff --git a/providers/hns/hns_roce_u_hw_v2.h b/providers/hns/hns_roce_u_hw_v2.h
index 84a7726..73b65bc 100644
--- a/providers/hns/hns_roce_u_hw_v2.h
+++ b/providers/hns/hns_roce_u_hw_v2.h
@@ -42,6 +42,7 @@ 
 
 enum {
 	HNS_ROCE_SUPPORT_RQ_RECORD_DB = 1 << 0,
+	HNS_ROCE_SUPPORT_SQ_RECORD_DB = 1 << 1,
 };
 
 enum {
diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
index 13b6d71..de9e7ab 100644
--- a/providers/hns/hns_roce_u_verbs.c
+++ b/providers/hns/hns_roce_u_verbs.c
@@ -573,7 +573,7 @@  struct ibv_qp *hns_roce_u_create_qp(struct ibv_pd *pd,
 
 	if (hns_roce_alloc_qp_buf(pd, &attr->cap, attr->qp_type, qp)) {
 		fprintf(stderr, "hns_roce_alloc_qp_buf failed!\n");
-		goto err;
+		goto err_buf;
 	}
 
 	hns_roce_init_qp_indices(qp);
@@ -585,10 +585,23 @@  struct ibv_qp *hns_roce_u_create_qp(struct ibv_pd *pd,
 	}
 
 	if ((to_hr_dev(pd->context->device)->hw_version != HNS_ROCE_HW_VER1) &&
+		attr->cap.max_send_sge) {
+		qp->sdb = hns_roce_alloc_db(context, HNS_ROCE_QP_TYPE_DB);
+		if (!qp->sdb) {
+			fprintf(stderr, "alloc sdb buffer failed!\n");
+			goto err_free;
+		}
+
+		*(qp->sdb) = 0;
+		cmd.sdb_addr = (uintptr_t)qp->sdb;
+	} else
+		cmd.sdb_addr = 0;
+
+	if ((to_hr_dev(pd->context->device)->hw_version != HNS_ROCE_HW_VER1) &&
 	    attr->cap.max_recv_sge) {
 		qp->rdb = hns_roce_alloc_db(context, HNS_ROCE_QP_TYPE_DB);
 		if (!qp->rdb)
-			goto err_free;
+			goto err_sq_db;
 
 		*(qp->rdb) = 0;
 		cmd.db_addr = (uintptr_t) qp->rdb;
@@ -643,13 +656,18 @@  err_rq_db:
 	    attr->cap.max_recv_sge)
 		hns_roce_free_db(context, qp->rdb, HNS_ROCE_QP_TYPE_DB);
 
+err_sq_db:
+	if ((to_hr_dev(pd->context->device)->hw_version != HNS_ROCE_HW_VER1) &&
+	    attr->cap.max_send_sge)
+		hns_roce_free_db(context, qp->sdb, HNS_ROCE_QP_TYPE_DB);
+
 err_free:
 	free(qp->sq.wrid);
 	if (qp->rq.wqe_cnt)
 		free(qp->rq.wrid);
 	hns_roce_free_buf(&qp->buf);
 
-err:
+err_buf:
 	free(qp);
 
 	return NULL;