From 64933c92842d34190c8cda9a864505d0558d3f5f Mon Sep 17 00:00:00 2001
From: Chengchang Tang <tangchengchang@huawei.com>
Date: Mon, 30 Oct 2023 16:59:22 +0800
Subject: [PATCH] libhns: Support write with notify

driver inclusion
category: feature
bugzilla: https://gitee.com/src-openeuler/rdma-core/issues/I8C6X4

---------------------------------------------------------------

This patch supports write with notify operation.

To use this operation, you need to configure the CQ to enable write
with notify and bind the CQ to the corresponding RQ.

The address of notify depends on the notify_idx configured by the
user.  This index will point to the notify mem array configured by
the kernel ULP.

Signed-off-by: Chengchang Tang <tangchengchang@huawei.com>
---
 providers/hns/hns_roce_u_hw_v2.c | 23 +++++++++++++++++++++++
 providers/hns/hns_roce_u_hw_v2.h |  1 +
 providers/hns/hns_roce_u_verbs.c | 32 ++++++++++++++++++++++++++++++--
 providers/hns/hnsdv.h            | 17 ++++++++++++++++-
 providers/hns/libhns.map         |  1 +
 5 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/providers/hns/hns_roce_u_hw_v2.c b/providers/hns/hns_roce_u_hw_v2.c
index ab6d652..495fbcb 100644
--- a/providers/hns/hns_roce_u_hw_v2.c
+++ b/providers/hns/hns_roce_u_hw_v2.c
@@ -2993,6 +2993,29 @@ static void wr_start(struct ibv_qp_ex *ibv_qp)
 	qp->err = 0;
 }
 
+void hnsdv_wr_write_notify(struct ibv_qp_ex *ibv_qp, uint32_t rkey,
+			   uint64_t remote_addr, uint32_t offset, uint8_t value)
+{
+#define NOTIFY_OFFSET_MASK GENMASK(23, 2)
+#define NOTIFY_VAL_SHIFT 24
+	struct hns_roce_rc_sq_wqe *wqe;
+	struct hns_roce_qp *qp;
+
+	if (!ibv_qp)
+		return;
+
+	qp = to_hr_qp(&ibv_qp->qp_base);
+	wqe = init_rc_wqe(qp, ibv_qp->wr_id,
+			  HNS_ROCE_WQE_OP_RDMA_WRITE_WITH_NOTIFY);
+	if (unlikely(!wqe))
+		return;
+
+	wqe->va = htole64(remote_addr);
+	wqe->rkey = htole32(rkey);
+	wqe->immtdata = htole32(((uint32_t)value << NOTIFY_VAL_SHIFT) |
+				(offset & NOTIFY_OFFSET_MASK));
+}
+
 static int wr_complete(struct ibv_qp_ex *ibv_qp)
 {
 	struct hns_roce_context *ctx = to_hr_ctx(ibv_qp->qp_base.context);
diff --git a/providers/hns/hns_roce_u_hw_v2.h b/providers/hns/hns_roce_u_hw_v2.h
index 50a920f..fa83bbe 100644
--- a/providers/hns/hns_roce_u_hw_v2.h
+++ b/providers/hns/hns_roce_u_hw_v2.h
@@ -61,6 +61,7 @@ enum {
 	HNS_ROCE_WQE_OP_ATOMIC_MASK_FETCH_AND_ADD = 0x9,
 	HNS_ROCE_WQE_OP_FAST_REG_PMR = 0xa,
 	HNS_ROCE_WQE_OP_BIND_MW_TYPE = 0xc,
+	HNS_ROCE_WQE_OP_RDMA_WRITE_WITH_NOTIFY = 0x16,
 	HNS_ROCE_WQE_OP_MASK = 0x1f
 };
 
diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
index 2ad9ea0..5e46f89 100644
--- a/providers/hns/hns_roce_u_verbs.c
+++ b/providers/hns/hns_roce_u_verbs.c
@@ -476,9 +476,26 @@ enum {
 };
 
 enum {
-	HNSDV_CQ_SUP_CREATE_FLAGS = HNSDV_CQ_CREATE_ENABLE_POE_MODE,
+	HNSDV_CQ_SUP_CREATE_FLAGS = HNSDV_CQ_CREATE_ENABLE_POE_MODE |
+				    HNSDV_CQ_CREATE_ENABLE_NOTIFY,
 };
 
+static int verify_notify_attr(struct hns_roce_context *ctx,
+			      struct hnsdv_cq_init_attr *hns_cq_attr)
+{
+	if (!(hns_cq_attr->comp_mask & HNSDV_CQ_INIT_ATTR_MASK_CREATE_FLAGS) ||
+	    !(hns_cq_attr->create_flags & HNSDV_CQ_CREATE_ENABLE_NOTIFY))
+		return 0;
+
+	if (hns_cq_attr->notify_mode >= HNSDV_CQ_NOTIFY_MODE_GUARD) {
+		verbs_err(&ctx->ibv_ctx, "Invalid notify mode %u\n",
+			  hns_cq_attr->notify_mode);
+		return EINVAL;
+	}
+
+	return 0;
+}
+
 static int verify_hnsdv_cq_create_attr(struct hns_roce_context *ctx,
 				       struct hnsdv_cq_init_attr *hns_cq_attr)
 {
@@ -499,7 +516,7 @@ static int verify_hnsdv_cq_create_attr(struct hns_roce_context *ctx,
 		return EOPNOTSUPP;
 	}
 
-	return 0;
+	return verify_notify_attr(ctx, hns_cq_attr);
 }
 
 static int verify_cq_create_attr(struct ibv_cq_init_attr_ex *attr,
@@ -551,6 +568,12 @@ static void set_hnsdv_cq_attr(struct hns_roce_ib_create_cq *cmd_drv,
 		cmd_drv->create_flags |= HNS_ROCE_CREATE_CQ_FLAGS_POE_MODE;
 		cmd_drv->poe_channel = hns_cq_attr->poe_channel;
 	}
+
+	if (hns_cq_attr->create_flags & HNSDV_CQ_CREATE_ENABLE_NOTIFY) {
+		cmd_drv->create_flags |= HNS_ROCE_CREATE_CQ_FLAGS_WRITE_WITH_NOTIFY;
+		cmd_drv->notify_mode = hns_cq_attr->notify_mode;
+		cmd_drv->notify_idx = hns_cq_attr->notify_idx;
+	}
 }
 
 static int check_hnsdv_cq_flags(struct hnsdv_cq_init_attr *hns_cq_attr,
@@ -562,6 +585,11 @@ static int check_hnsdv_cq_flags(struct hnsdv_cq_init_attr *hns_cq_attr,
 	if ((hns_cq_attr->create_flags & HNSDV_CQ_CREATE_ENABLE_POE_MODE) &&
 			!(cq->flags & HNS_ROCE_CQ_FLAG_POE_EN))
 		return EOPNOTSUPP;
+
+	if ((hns_cq_attr->create_flags & HNSDV_CQ_CREATE_ENABLE_NOTIFY) &&
+			!(cq->flags & HNS_ROCE_CQ_FLAG_NOTIFY_EN))
+		return EOPNOTSUPP;
+
 	return 0;
 }
 
diff --git a/providers/hns/hnsdv.h b/providers/hns/hnsdv.h
index 98c68fd..7d95db4 100644
--- a/providers/hns/hnsdv.h
+++ b/providers/hns/hnsdv.h
@@ -100,13 +100,24 @@ enum hnsdv_cq_init_attr_mask {
 
 enum hnsdv_cq_create_flags {
 	HNSDV_CQ_CREATE_ENABLE_POE_MODE = 1 << 0,
+	HNSDV_CQ_CREATE_ENABLE_NOTIFY = 1 << 1,
+};
+
+enum hnsdv_cq_notify_mode {
+	HNSDV_CQ_NOTIFY_MODE_64B_ALIGN = 0,
+	HNSDV_CQ_NOTIFY_MODE_4B_ALIGN = 1,
+	HNSDV_CQ_NOTIFY_MODE_DDR_64B_ALIGN = 2,
+	HNSDV_CQ_NOTIFY_MODE_DDR_4B_ALIGN = 3,
+	HNSDV_CQ_NOTIFY_MODE_GUARD = 4, /* Invalid for user */
 };
 
 struct hnsdv_cq_init_attr {
 	uint64_t comp_mask; /* Use enum hnsdv_cq_init_attr_mask */
 	uint64_t create_flags; /* Use enum hnsdv_cq_create_flags */
 	uint8_t poe_channel; /* poe channel to use */
-	uint8_t reserved[7];
+	uint8_t notify_mode;
+	uint16_t notify_idx;
+	uint32_t reserved;
 };
 
 struct ibv_cq_ex *hnsdv_create_cq_ex(struct ibv_context *context,
@@ -116,6 +127,10 @@ struct ibv_cq_ex *hnsdv_create_cq_ex(struct ibv_context *context,
 /* used in stars mode */
 void hnsdv_update_sq_ci(struct ibv_qp *qp, uint32_t inc_idx);
 
+/* write with notify */
+void hnsdv_wr_write_notify(struct ibv_qp_ex *qpex, uint32_t rkey,
+			uint64_t remote_addr, uint32_t offset, uint8_t value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/providers/hns/libhns.map b/providers/hns/libhns.map
index 27efc83..74d85e1 100644
--- a/providers/hns/libhns.map
+++ b/providers/hns/libhns.map
@@ -8,5 +8,6 @@ HNS_1.0 {
 		hnsdv_query_device;
 		hnsdv_create_cq_ex;
 		hnsdv_update_sq_ci;
+		hnsdv_wr_write_notify;
 	local: *;
 };
-- 
2.25.1

