From 99e1e64edab954ce1895d83a3d6f4317bc12c444 Mon Sep 17 00:00:00 2001
From: Yixing Liu <liuyixing1@huawei.com>
Date: Wed, 12 Apr 2023 17:01:09 +0800
Subject: [PATCH] libhns: Support congestion control algorithm configuration

driver inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I6N1G4

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

Added the use of direct verbs to implement QP-level
user-configurable congestion control algorithms. Among them,
the user mode driver mainly provides interfaces for users to
choose, and the kernel mode driver is responsible for filling
the resources of different algorithms and providing the
supported algorithm types for user mode.

At the same time, provide a direct verbs interface for users to
query the type of congestion control algorithm.

Signed-off-by: Yixing Liu <liuyixing1@huawei.com>
Reviewed-by: Yangyang Li <liyangyang20@huawei.com>
---
 providers/hns/hns_roce_u.c       |   1 +
 providers/hns/hns_roce_u.h       |   6 ++
 providers/hns/hns_roce_u_verbs.c | 107 +++++++++++++++++++++++++++++--
 providers/hns/hnsdv.h            |  22 +++++++
 providers/hns/libhns.map         |   1 +
 5 files changed, 131 insertions(+), 6 deletions(-)

diff --git a/providers/hns/hns_roce_u.c b/providers/hns/hns_roce_u.c
index 3d29838..87f9ed8 100644
--- a/providers/hns/hns_roce_u.c
+++ b/providers/hns/hns_roce_u.c
@@ -299,6 +299,7 @@ static struct verbs_context *hns_roce_alloc_context(struct ibv_device *ibdev,
 		goto err_free;
 
 	hr_dev->mac_type = resp.mac_type;
+	hr_dev->congest_type = resp.congest_type;
 
 	if (!resp.cqe_size)
 		context->cqe_size = HNS_ROCE_CQE_SIZE;
diff --git a/providers/hns/hns_roce_u.h b/providers/hns/hns_roce_u.h
index 76c7adb..41e9599 100644
--- a/providers/hns/hns_roce_u.h
+++ b/providers/hns/hns_roce_u.h
@@ -172,6 +172,7 @@ struct hns_roce_device {
 	const struct hns_roce_u_hw	*u_hw;
 	int				hw_version;
 	uint8_t				mac_type;
+	uint8_t				congest_type;
 };
 
 struct hns_roce_buf {
@@ -230,6 +231,11 @@ struct hns_roce_v2_reset_state {
 	uint32_t is_reset;
 };
 
+struct hns_roce_cmd_flag {
+	uint32_t create_flags;
+	uint32_t congest_type_flags;
+};
+
 struct hns_roce_context {
 	struct verbs_context		ibv_ctx;
 	void				*uar;
diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
index 282ab74..499735c 100644
--- a/providers/hns/hns_roce_u_verbs.c
+++ b/providers/hns/hns_roce_u_verbs.c
@@ -89,10 +89,10 @@ int hns_roce_u_query_device(struct ibv_context *context,
 			    struct ibv_device_attr_ex *attr, size_t attr_size)
 {
 	struct ib_uverbs_ex_query_device_resp resp;
+	unsigned int major, minor, sub_minor;
 	size_t resp_size = sizeof(resp);
-	int ret;
 	uint64_t raw_fw_ver;
-	unsigned int major, minor, sub_minor;
+	int ret;
 
 	ret = ibv_cmd_query_device_any(context, input, attr, attr_size, &resp,
 				       &resp_size);
@@ -110,6 +110,27 @@ int hns_roce_u_query_device(struct ibv_context *context,
 	return 0;
 }
 
+int hnsdv_query_device(struct ibv_context *context,
+		       struct hnsdv_context *attrs_out)
+{
+	struct hns_roce_device *hr_dev = to_hr_dev(context->device);
+
+	if (!hr_dev) {
+		verbs_err(verbs_get_ctx(context), "not a HNS RoCE device!\n");
+		return EOPNOTSUPP;
+	}
+
+	if (!attrs_out)
+		return EINVAL;
+
+	memset(attrs_out, 0, sizeof(*attrs_out));
+
+	attrs_out->comp_mask |= HNSDV_CONTEXT_MASK_CONGEST_TYPE;
+	attrs_out->congest_type = hr_dev->congest_type;
+
+	return 0;
+}
+
 int hns_roce_u_query_port(struct ibv_context *context, uint8_t port,
 			  struct ibv_port_attr *attr)
 {
@@ -956,6 +977,67 @@ int hns_roce_u_destroy_srq(struct ibv_srq *ibv_srq)
 	return 0;
 }
 
+enum {
+	HNSDV_QP_SUP_COMP_MASK = HNSDV_QP_INIT_ATTR_MASK_QP_CREATE_FLAGS |
+				 HNSDV_QP_INIT_ATTR_MASK_QP_CONGEST_TYPE,
+};
+
+static int check_qp_congest_type(struct hns_roce_context *ctx,
+				 struct hnsdv_qp_init_attr *hns_attr,
+				 struct hns_roce_cmd_flag *cmd_flag)
+{
+	struct hns_roce_device *hr_dev = to_hr_dev(ctx->ibv_ctx.context.device);
+
+	if (!check_comp_mask(hns_attr->congest_type, hr_dev->congest_type)) {
+		verbs_err(&ctx->ibv_ctx, "unsupported congest type 0x%x.\n",
+			  hns_attr->congest_type);
+		return -EOPNOTSUPP;
+	}
+
+	switch (hns_attr->congest_type) {
+	case HNSDV_QP_CREATE_ENABLE_DCQCN:
+		cmd_flag->congest_type_flags |= HNS_ROCE_CREATE_QP_FLAGS_DCQCN;
+		break;
+	case HNSDV_QP_CREATE_ENABLE_LDCP:
+		cmd_flag->congest_type_flags |= HNS_ROCE_CREATE_QP_FLAGS_LDCP;
+		break;
+	case HNSDV_QP_CREATE_ENABLE_HC3:
+		cmd_flag->congest_type_flags |= HNS_ROCE_CREATE_QP_FLAGS_HC3;
+		break;
+	case HNSDV_QP_CREATE_ENABLE_DIP:
+		cmd_flag->congest_type_flags |= HNS_ROCE_CREATE_QP_FLAGS_DIP;
+		break;
+	default:
+		verbs_err(&ctx->ibv_ctx,
+			  "unsupported congestion control algorithm configuration.\n");
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int check_hnsdv_qp_attr(struct hns_roce_context *ctx,
+			       struct hnsdv_qp_init_attr *hns_attr,
+			       struct hns_roce_cmd_flag *cmd_flag)
+{
+	int ret;
+
+	if (!hns_attr)
+		return 0;
+
+	if (!check_comp_mask(hns_attr->comp_mask, HNSDV_QP_SUP_COMP_MASK)) {
+		verbs_err(&ctx->ibv_ctx, "invalid hnsdv comp_mask 0x%x.\n",
+			  hns_attr->comp_mask);
+		return -EINVAL;
+	}
+
+	ret = check_qp_congest_type(ctx, hns_attr, cmd_flag);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 enum {
 	CREATE_QP_SUP_COMP_MASK = IBV_QP_INIT_ATTR_PD | IBV_QP_INIT_ATTR_XRCD |
 				  IBV_QP_INIT_ATTR_SEND_OPS_FLAGS,
@@ -1050,7 +1132,9 @@ static int verify_qp_create_cap(struct hns_roce_context *ctx,
 }
 
 static int verify_qp_create_attr(struct hns_roce_context *ctx,
-				 struct ibv_qp_init_attr_ex *attr)
+				 struct ibv_qp_init_attr_ex *attr,
+				 struct hnsdv_qp_init_attr *hns_attr,
+				 struct hns_roce_cmd_flag *cmd_flag)
 {
 	int ret;
 
@@ -1058,6 +1142,10 @@ static int verify_qp_create_attr(struct hns_roce_context *ctx,
 	if (ret)
 		return ret;
 
+	ret = check_hnsdv_qp_attr(ctx, hns_attr, cmd_flag);
+	if (ret)
+		return ret;
+
 	return verify_qp_create_cap(ctx, attr);
 }
 
@@ -1452,7 +1540,8 @@ static int hns_roce_store_qp(struct hns_roce_context *ctx,
 static int qp_exec_create_cmd(struct ibv_qp_init_attr_ex *attr,
 			      struct hns_roce_qp *qp,
 			      struct hns_roce_context *ctx,
-			      uint64_t *dwqe_mmap_key)
+			      uint64_t *dwqe_mmap_key,
+			      struct hns_roce_cmd_flag *cmd_flag)
 {
 	struct hns_roce_create_qp_ex_resp resp_ex = {};
 	struct hns_roce_create_qp_ex cmd_ex = {};
@@ -1464,6 +1553,11 @@ static int qp_exec_create_cmd(struct ibv_qp_init_attr_ex *attr,
 	cmd_ex.log_sq_stride = qp->sq.wqe_shift;
 	cmd_ex.log_sq_bb_count = hr_ilog32(qp->sq.wqe_cnt);
 
+	if (cmd_flag->congest_type_flags) {
+		cmd_ex.comp_mask |= HNS_ROCE_CREATE_QP_MASK_CONGEST_TYPE;
+		cmd_ex.congest_type_flags = cmd_flag->congest_type_flags;
+	}
+
 	ret = ibv_cmd_create_qp_ex2(&ctx->ibv_ctx.context, &qp->verbs_qp, attr,
 				    &cmd_ex.ibv_cmd, sizeof(cmd_ex),
 				    &resp_ex.ibv_resp, sizeof(resp_ex));
@@ -1543,11 +1637,12 @@ static struct ibv_qp *create_qp(struct ibv_context *ibv_ctx,
 				struct hnsdv_qp_init_attr *hns_attr)
 {
 	struct hns_roce_context *context = to_hr_ctx(ibv_ctx);
+	struct hns_roce_cmd_flag cmd_flag = {};
 	struct hns_roce_qp *qp;
 	uint64_t dwqe_mmap_key;
 	int ret;
 
-	ret = verify_qp_create_attr(context, attr);
+	ret = verify_qp_create_attr(context, attr, hns_attr, &cmd_flag);
 	if (ret)
 		goto err;
 
@@ -1567,7 +1662,7 @@ static struct ibv_qp *create_qp(struct ibv_context *ibv_ctx,
 	if (ret)
 		goto err_buf;
 
-	ret = qp_exec_create_cmd(attr, qp, context, &dwqe_mmap_key);
+	ret = qp_exec_create_cmd(attr, qp, context, &dwqe_mmap_key, &cmd_flag);
 	if (ret)
 		goto err_cmd;
 
diff --git a/providers/hns/hnsdv.h b/providers/hns/hnsdv.h
index cfe1611..e15b428 100644
--- a/providers/hns/hnsdv.h
+++ b/providers/hns/hnsdv.h
@@ -45,19 +45,41 @@ enum hnsdv_qp_create_flags {
 	HNSDV_QP_CREATE_ENABLE_DCA_MODE = 1 << 0,
 };
 
+enum hnsdv_qp_congest_ctrl_type {
+	HNSDV_QP_CREATE_ENABLE_DCQCN = 1 << 0,
+	HNSDV_QP_CREATE_ENABLE_LDCP = 1 << 1,
+	HNSDV_QP_CREATE_ENABLE_HC3 = 1 << 2,
+	HNSDV_QP_CREATE_ENABLE_DIP = 1 << 3,
+};
+
 enum hnsdv_qp_init_attr_mask {
 	HNSDV_QP_INIT_ATTR_MASK_QP_CREATE_FLAGS	= 1 << 0,
+	HNSDV_QP_INIT_ATTR_MASK_QP_CONGEST_TYPE	= 1 << 1,
 };
 
 struct hnsdv_qp_init_attr {
 	uint64_t comp_mask;	/* Use enum hnsdv_qp_init_attr_mask */
 	uint32_t create_flags;	/* Use enum hnsdv_qp_create_flags */
+	uint8_t congest_type; /* Use enum hnsdv_qp_congest_ctrl_type */
 };
 
 struct ibv_qp *hnsdv_create_qp(struct ibv_context *context,
 			       struct ibv_qp_init_attr_ex *qp_attr,
 			       struct hnsdv_qp_init_attr *hns_qp_attr);
 
+enum hnsdv_query_context_comp_mask {
+	HNSDV_CONTEXT_MASK_CONGEST_TYPE = 1 << 0,
+};
+
+struct hnsdv_context {
+	uint64_t comp_mask; /* use enum hnsdv_query_context_comp_mask */
+	uint64_t flags;
+	uint8_t congest_type; /* Use enum hnsdv_qp_congest_ctrl_type */
+};
+
+int hnsdv_query_device(struct ibv_context *ctx_in,
+		       struct hnsdv_context *attrs_out);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/providers/hns/libhns.map b/providers/hns/libhns.map
index aed491c..ebf28eb 100644
--- a/providers/hns/libhns.map
+++ b/providers/hns/libhns.map
@@ -5,5 +5,6 @@ HNS_1.0 {
 		hnsdv_is_supported;
 		hnsdv_open_device;
 		hnsdv_create_qp;
+		hnsdv_query_device;
 	local: *;
 };
-- 
2.25.1

