[PATCH 12/15] RDMA/hbl: direct verbs support

Omer Shpigelman oshpigelman at habana.ai
Thu Jun 13 08:22:05 UTC 2024


Add direct verbs (DV) uAPI.
The added operations are:
query_port: query vendor specific port attributes.
set_port_ex: set port extended settings.
usr_fifo: set user FIFO object for triggering HW doorbells.
encap: set port encapsulation (UDP/IPv4).

Signed-off-by: Omer Shpigelman <oshpigelman at habana.ai>
Co-developed-by: Abhilash K V <kvabhilash at habana.ai>
Signed-off-by: Abhilash K V <kvabhilash at habana.ai>
Co-developed-by: Andrey Agranovich <aagranovich at habana.ai>
Signed-off-by: Andrey Agranovich <aagranovich at habana.ai>
Co-developed-by: Bharat Jauhari <bjauhari at habana.ai>
Signed-off-by: Bharat Jauhari <bjauhari at habana.ai>
Co-developed-by: David Meriin <dmeriin at habana.ai>
Signed-off-by: David Meriin <dmeriin at habana.ai>
Co-developed-by: Sagiv Ozeri <sozeri at habana.ai>
Signed-off-by: Sagiv Ozeri <sozeri at habana.ai>
Co-developed-by: Zvika Yehudai <zyehudai at habana.ai>
Signed-off-by: Zvika Yehudai <zyehudai at habana.ai>
---
 drivers/infiniband/hw/hbl/Kconfig           |   1 +
 drivers/infiniband/hw/hbl/Makefile          |   4 +
 drivers/infiniband/hw/hbl/hbl_encap.c       | 216 +++++++++++++++++
 drivers/infiniband/hw/hbl/hbl_main.c        |  15 ++
 drivers/infiniband/hw/hbl/hbl_query_port.c  |  96 ++++++++
 drivers/infiniband/hw/hbl/hbl_set_port_ex.c |  96 ++++++++
 drivers/infiniband/hw/hbl/hbl_usr_fifo.c    | 252 ++++++++++++++++++++
 7 files changed, 680 insertions(+)
 create mode 100644 drivers/infiniband/hw/hbl/hbl_encap.c
 create mode 100644 drivers/infiniband/hw/hbl/hbl_query_port.c
 create mode 100644 drivers/infiniband/hw/hbl/hbl_set_port_ex.c
 create mode 100644 drivers/infiniband/hw/hbl/hbl_usr_fifo.c

diff --git a/drivers/infiniband/hw/hbl/Kconfig b/drivers/infiniband/hw/hbl/Kconfig
index 90c865a82540..db09ecb3968a 100644
--- a/drivers/infiniband/hw/hbl/Kconfig
+++ b/drivers/infiniband/hw/hbl/Kconfig
@@ -6,6 +6,7 @@
 config INFINIBAND_HBL
 	tristate "HabanaLabs (an Intel Company) InfiniBand driver"
 	depends on NETDEVICES && ETHERNET && PCI && INET
+	depends on INFINIBAND_USER_ACCESS
 	select HABANA_CN
 	help
 	  This driver enables InfiniBand functionality for the network
diff --git a/drivers/infiniband/hw/hbl/Makefile b/drivers/infiniband/hw/hbl/Makefile
index 659d4bbfec0f..86f53ca6b9d5 100644
--- a/drivers/infiniband/hw/hbl/Makefile
+++ b/drivers/infiniband/hw/hbl/Makefile
@@ -6,3 +6,7 @@
 obj-$(CONFIG_INFINIBAND_HBL) := habanalabs_ib.o
 
 habanalabs_ib-y += hbl_main.o hbl_verbs.o
+
+habanalabs_ib-$(CONFIG_INFINIBAND_USER_ACCESS) += hbl_encap.o hbl_query_port.o \
+                                                  hbl_set_port_ex.o \
+                                                  hbl_usr_fifo.o
diff --git a/drivers/infiniband/hw/hbl/hbl_encap.c b/drivers/infiniband/hw/hbl/hbl_encap.c
new file mode 100644
index 000000000000..bcc198059664
--- /dev/null
+++ b/drivers/infiniband/hw/hbl/hbl_encap.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2022-2024 HabanaLabs, Ltd.
+ * Copyright (C) 2023-2024, Intel Corporation.
+ * All Rights Reserved.
+ */
+
+#include "hbl.h"
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
+#include <rdma/uverbs_ioctl.h>
+#include <linux/net/intel/cni.h>
+
+#include <rdma/uverbs_ioctl.h>
+#include <uapi/rdma/hbl_user_ioctl_cmds.h>
+
+#define UVERBS_MODULE_NAME hbl
+#include <rdma/uverbs_named_ioctl.h>
+
+struct hbl_encap {
+	u32 port_num;
+	u32 encap_num;
+};
+
+static int UVERBS_HANDLER(HBL_IB_METHOD_ENCAP_CREATE)(struct uverbs_attr_bundle *attrs)
+{
+	struct hbl_cni_user_encap_alloc_out alloc_encap_out = {};
+	struct hbl_cni_user_encap_alloc_in alloc_encap_in = {};
+	struct hbl_cni_user_encap_unset_in unset_encap_in = {};
+	struct hbl_cni_user_encap_set_in set_encap_in = {};
+	struct hbl_uapi_encap_create_out out = {};
+	struct hbl_uapi_encap_create_in in = {};
+	u32 port, tnl_hdr_size, encap_num;
+	struct hbl_ib_aux_ops *aux_ops;
+	struct hbl_encap *encap_pdata;
+	struct hbl_ib_ucontext *hctx;
+	struct hbl_aux_dev *aux_dev;
+	struct hbl_ib_device *hdev;
+	struct ib_device *ibdev;
+	struct ib_uobject *uobj;
+	u64 tnl_hdr_ptr;
+	u8 encap_type;
+	int rc;
+
+	hctx = to_hbl_ib_ucontext(ib_uverbs_get_ucontext(attrs));
+	if (IS_ERR(hctx))
+		return PTR_ERR(hctx);
+
+	uobj = uverbs_attr_get_uobject(attrs, HBL_IB_ATTR_ENCAP_CREATE_HANDLE);
+	hdev = to_hbl_ib_dev(hctx->ibucontext.device);
+	ibdev = &hdev->ibdev;
+	aux_dev = hdev->aux_dev;
+	aux_ops = aux_dev->aux_ops;
+
+	rc = uverbs_copy_from(&in, attrs, HBL_IB_ATTR_ENCAP_CREATE_IN);
+	if (rc)
+		return rc;
+
+	rc = ib_to_hbl_port_num(hdev, in.port_num, &port);
+	if (rc) {
+		hbl_ibdev_dbg(ibdev, "invalid IB port %u\n", in.port_num);
+		return rc;
+	}
+
+	if (!(hctx->ports_mask & BIT(port))) {
+		hbl_ibdev_dbg(ibdev, "port %d is not part of the context's ports mask 0x%llx\n",
+			      port, hctx->ports_mask);
+		return -EINVAL;
+	}
+
+	encap_pdata = kzalloc(sizeof(*encap_pdata), GFP_KERNEL);
+	if (!encap_pdata)
+		return -ENOMEM;
+
+	encap_type = in.encap_type;
+
+	alloc_encap_in.port = port;
+	rc = aux_ops->cmd_ctrl(aux_dev, hctx->cn_ctx, HBL_CNI_OP_USER_ENCAP_ALLOC, &alloc_encap_in,
+			       &alloc_encap_out);
+	if (rc) {
+		hbl_ibdev_dbg(ibdev, "failed to alloc encap for port %d\n", port);
+		goto err_free_pdata;
+	}
+
+	encap_num = alloc_encap_out.id;
+
+	if (encap_type != HBL_CNI_ENCAP_NONE) {
+		tnl_hdr_ptr = in.tnl_hdr_ptr;
+		tnl_hdr_size = in.tnl_hdr_size;
+	} else {
+		tnl_hdr_ptr = 0;
+		tnl_hdr_size = 0;
+	}
+
+	encap_pdata->port_num = port;
+	encap_pdata->encap_num = encap_num;
+
+	set_encap_in.tnl_hdr_ptr = tnl_hdr_ptr;
+	set_encap_in.tnl_hdr_size = tnl_hdr_size;
+	set_encap_in.port = port;
+	set_encap_in.id = encap_num;
+	set_encap_in.encap_type = encap_type;
+
+	switch (encap_type) {
+	case HBL_CNI_ENCAP_NONE:
+		set_encap_in.ipv4_addr = in.ipv4_addr;
+		break;
+	case HBL_CNI_ENCAP_OVER_UDP:
+		set_encap_in.udp_dst_port = in.udp_dst_port;
+		break;
+	case HBL_CNI_ENCAP_OVER_IPV4:
+		set_encap_in.ip_proto = in.ip_proto;
+		break;
+	default:
+		break;
+	}
+
+	rc = aux_ops->cmd_ctrl(aux_dev, hctx->cn_ctx, HBL_CNI_OP_USER_ENCAP_SET, &set_encap_in,
+			       NULL);
+	if (rc) {
+		hbl_ibdev_dbg(ibdev, "failed to set encap for port %d\n", port);
+		goto err_encap_unset;
+	}
+
+	out.encap_num = encap_num;
+	uobj->object = encap_pdata;
+
+	rc = uverbs_copy_to_struct_or_zero(attrs, HBL_IB_ATTR_ENCAP_CREATE_OUT, &out, sizeof(out));
+	if (rc)
+		goto err_encap_unset;
+
+	return 0;
+
+err_encap_unset:
+	unset_encap_in.port = port;
+	unset_encap_in.id = encap_num;
+
+	if (aux_ops->cmd_ctrl(aux_dev, hctx->cn_ctx, HBL_CNI_OP_USER_ENCAP_UNSET, &unset_encap_in,
+			      NULL))
+		hbl_ibdev_dbg(ibdev, "failed to unset encap for port %d, encap_num %d\n", port,
+			      encap_num);
+
+err_free_pdata:
+	kfree(encap_pdata);
+
+	return rc;
+}
+
+static int hbl_free_encap(struct ib_uobject *uobject, enum rdma_remove_reason why,
+			  struct uverbs_attr_bundle *attrs)
+{
+	struct hbl_cni_user_encap_unset_in unset_encap_in = {};
+	struct hbl_ib_aux_ops *aux_ops;
+	struct hbl_encap *encap_pdata;
+	struct hbl_ib_ucontext *hctx;
+	struct hbl_aux_dev *aux_dev;
+	struct hbl_ib_device *hdev;
+	struct ib_device *ibdev;
+	int rc;
+
+	hctx = to_hbl_ib_ucontext(ib_uverbs_get_ucontext(attrs));
+	if (IS_ERR(hctx))
+		return PTR_ERR(hctx);
+
+	encap_pdata = uobject->object;
+	hdev = to_hbl_ib_dev(hctx->ibucontext.device);
+	ibdev = &hdev->ibdev;
+	aux_dev = hdev->aux_dev;
+	aux_ops = aux_dev->aux_ops;
+
+	unset_encap_in.port = encap_pdata->port_num;
+	unset_encap_in.id = encap_pdata->encap_num;
+	if (aux_ops->device_operational(aux_dev)) {
+		rc = aux_ops->cmd_ctrl(aux_dev, hctx->cn_ctx, HBL_CNI_OP_USER_ENCAP_UNSET,
+				       &unset_encap_in, NULL);
+		if (rc) {
+			hbl_ibdev_dbg(ibdev, "failed to unset encap for port %d, id %d\n",
+				      unset_encap_in.port, unset_encap_in.id);
+			return rc;
+		}
+	}
+
+	kfree(encap_pdata);
+
+	return 0;
+}
+
+DECLARE_UVERBS_NAMED_METHOD(
+	HBL_IB_METHOD_ENCAP_CREATE,
+	UVERBS_ATTR_IDR(HBL_IB_ATTR_ENCAP_CREATE_HANDLE,
+			HBL_IB_OBJECT_ENCAP,
+			UVERBS_ACCESS_NEW,
+			UA_MANDATORY),
+	UVERBS_ATTR_PTR_IN(HBL_IB_ATTR_ENCAP_CREATE_IN,
+			   UVERBS_ATTR_STRUCT(struct hbl_uapi_encap_create_in, reserved),
+			   UA_MANDATORY),
+	UVERBS_ATTR_PTR_OUT(HBL_IB_ATTR_ENCAP_CREATE_OUT,
+			    UVERBS_ATTR_STRUCT(struct hbl_uapi_encap_create_out, reserved),
+			    UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_METHOD_DESTROY(
+	HBL_IB_METHOD_ENCAP_DESTROY,
+	UVERBS_ATTR_IDR(HBL_IB_ATTR_ENCAP_DESTROY_HANDLE,
+			HBL_IB_OBJECT_ENCAP,
+			UVERBS_ACCESS_DESTROY,
+			UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_OBJECT(HBL_IB_OBJECT_ENCAP,
+			    UVERBS_TYPE_ALLOC_IDR(hbl_free_encap),
+			    &UVERBS_METHOD(HBL_IB_METHOD_ENCAP_CREATE),
+			    &UVERBS_METHOD(HBL_IB_METHOD_ENCAP_DESTROY));
+
+const struct uapi_definition hbl_encap_defs[] = {
+	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(HBL_IB_OBJECT_ENCAP),
+	{},
+};
diff --git a/drivers/infiniband/hw/hbl/hbl_main.c b/drivers/infiniband/hw/hbl/hbl_main.c
index 98d3ed46bfe2..6bee35695a06 100644
--- a/drivers/infiniband/hw/hbl/hbl_main.c
+++ b/drivers/infiniband/hw/hbl/hbl_main.c
@@ -22,6 +22,16 @@ MODULE_LICENSE("GPL");
 
 #define MTU_DEFAULT	SZ_4K
 
+static const struct uapi_definition hbl_defs[] = {
+#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
+	UAPI_DEF_CHAIN(hbl_usr_fifo_defs),
+	UAPI_DEF_CHAIN(hbl_set_port_ex_defs),
+	UAPI_DEF_CHAIN(hbl_query_port_defs),
+	UAPI_DEF_CHAIN(hbl_encap_defs),
+#endif
+	{}
+};
+
 static void hbl_ib_port_event(struct ib_device *ibdev, u32 port_num, enum ib_event_type reason)
 {
 	struct ib_event event;
@@ -166,6 +176,11 @@ static int hbl_ib_dev_init(struct hbl_ib_device *hdev)
 
 	ib_set_device_ops(ibdev, &hbl_ib_dev_ops);
 
+	if (IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS))
+		ibdev->driver_def = hbl_defs;
+	else
+		dev_info(hdev->dev, "IB user access is disabled\n");
+
 	/* The CN driver might start calling the aux functions after registering the device so set
 	 * the callbacks here.
 	 */
diff --git a/drivers/infiniband/hw/hbl/hbl_query_port.c b/drivers/infiniband/hw/hbl/hbl_query_port.c
new file mode 100644
index 000000000000..1882507b0b58
--- /dev/null
+++ b/drivers/infiniband/hw/hbl/hbl_query_port.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2022-2024 HabanaLabs, Ltd.
+ * Copyright (C) 2023-2024, Intel Corporation.
+ * All Rights Reserved.
+ */
+
+#include "hbl.h"
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
+#include <rdma/uverbs_ioctl.h>
+#include <linux/net/intel/cni.h>
+
+#include <rdma/uverbs_ioctl.h>
+#include <uapi/rdma/hbl_user_ioctl_cmds.h>
+#include <uapi/rdma/hbl_user_ioctl_verbs.h>
+
+#define UVERBS_MODULE_NAME hbl
+#include <rdma/uverbs_named_ioctl.h>
+
+static int UVERBS_HANDLER(HBL_IB_METHOD_QUERY_PORT)(struct uverbs_attr_bundle *attrs)
+{
+	struct hbl_cni_get_user_app_params_out app_params_out = {};
+	struct hbl_cni_get_user_app_params_in app_params_in = {};
+	struct hbl_uapi_query_port_out out = {};
+	struct hbl_uapi_query_port_in in = {};
+	struct hbl_ib_aux_ops *aux_ops;
+	struct hbl_ib_ucontext *hctx;
+	struct hbl_aux_dev *aux_dev;
+	struct hbl_ib_device *hdev;
+	struct ib_device *ibdev;
+	int rc;
+
+	hctx = to_hbl_ib_ucontext(ib_uverbs_get_ucontext(attrs));
+	if (IS_ERR(hctx))
+		return PTR_ERR(hctx);
+
+	hdev = to_hbl_ib_dev(hctx->ibucontext.device);
+	ibdev = &hdev->ibdev;
+	aux_dev = hdev->aux_dev;
+	aux_ops = aux_dev->aux_ops;
+
+	rc = uverbs_copy_from(&in, attrs, HBL_IB_ATTR_QUERY_PORT_IN);
+	if (rc)
+		return rc;
+
+	rc = ib_to_hbl_port_num(hdev, in.port_num, &app_params_in.port);
+	if (rc) {
+		hbl_ibdev_dbg(ibdev, "invalid IB port %u\n", in.port_num);
+		return rc;
+	}
+
+	if (!(hctx->ports_mask & BIT(app_params_in.port))) {
+		hbl_ibdev_dbg(ibdev, "port %d is not part of the context's ports mask 0x%llx\n",
+			      app_params_in.port, hctx->ports_mask);
+		return -EINVAL;
+	}
+
+	rc = aux_ops->cmd_ctrl(aux_dev, hctx->cn_ctx, HBL_CNI_OP_GET_USER_APP_PARAMS,
+			       &app_params_in, &app_params_out);
+	if (rc) {
+		hbl_ibdev_dbg(ibdev, "failed to get user params for port %d\n", app_params_in.port);
+		return rc;
+	}
+
+	out.max_num_of_qps = app_params_out.max_num_of_qps;
+	out.num_allocated_qps = app_params_out.num_allocated_qps;
+	out.max_allocated_qp_num = app_params_out.max_allocated_qp_idx;
+	out.max_cq_size = app_params_out.max_cq_size;
+	out.advanced = app_params_out.advanced;
+	out.max_num_of_cqs = app_params_out.max_num_of_cqs;
+	out.max_num_of_usr_fifos = app_params_out.max_num_of_db_fifos;
+	out.max_num_of_encaps = app_params_out.max_num_of_encaps;
+	out.nic_macro_idx = app_params_out.nic_macro_idx;
+	out.nic_phys_port_idx = app_params_out.nic_phys_port_idx;
+
+	rc = uverbs_copy_to_struct_or_zero(attrs, HBL_IB_ATTR_QUERY_PORT_OUT, &out, sizeof(out));
+
+	return rc;
+}
+
+DECLARE_UVERBS_NAMED_METHOD(
+	HBL_IB_METHOD_QUERY_PORT,
+	UVERBS_ATTR_PTR_IN(HBL_IB_ATTR_QUERY_PORT_IN,
+			   UVERBS_ATTR_STRUCT(struct hbl_uapi_query_port_in, reserved),
+			   UA_MANDATORY),
+	UVERBS_ATTR_PTR_OUT(HBL_IB_ATTR_QUERY_PORT_OUT,
+			    UVERBS_ATTR_STRUCT(struct hbl_uapi_query_port_out, reserved),
+			    UA_MANDATORY));
+
+DECLARE_UVERBS_GLOBAL_METHODS(HBL_IB_OBJECT_QUERY_PORT, &UVERBS_METHOD(HBL_IB_METHOD_QUERY_PORT));
+
+const struct uapi_definition hbl_query_port_defs[] = {
+	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(HBL_IB_OBJECT_QUERY_PORT),
+	{},
+};
diff --git a/drivers/infiniband/hw/hbl/hbl_set_port_ex.c b/drivers/infiniband/hw/hbl/hbl_set_port_ex.c
new file mode 100644
index 000000000000..15b509506cca
--- /dev/null
+++ b/drivers/infiniband/hw/hbl/hbl_set_port_ex.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2022-2024 HabanaLabs, Ltd.
+ * Copyright (C) 2023-2024, Intel Corporation.
+ * All Rights Reserved.
+ */
+
+#include "hbl.h"
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
+#include <rdma/uverbs_ioctl.h>
+#include <linux/net/intel/cni.h>
+
+#include <rdma/uverbs_ioctl.h>
+#include <uapi/rdma/hbl_user_ioctl_cmds.h>
+#include <uapi/rdma/hbl_user_ioctl_verbs.h>
+
+#define UVERBS_MODULE_NAME hbl
+#include <rdma/uverbs_named_ioctl.h>
+
+static int UVERBS_HANDLER(HBL_IB_METHOD_SET_PORT_EX)(struct uverbs_attr_bundle *attrs)
+{
+	struct hbl_ib_port_init_params port_init_params = {};
+	struct hbl_uapi_set_port_ex_in in = {};
+	struct hbl_ib_ucontext *hctx;
+	struct hbl_ib_device *hdev;
+	struct ib_device *ibdev;
+	u32 hbl_port;
+	int rc, i;
+
+	hctx = to_hbl_ib_ucontext(ib_uverbs_get_ucontext(attrs));
+	if (IS_ERR(hctx))
+		return PTR_ERR(hctx);
+
+	hdev = to_hbl_ib_dev(hctx->ibucontext.device);
+	ibdev = &hdev->ibdev;
+
+	rc = uverbs_copy_from(&in, attrs, HBL_IB_ATTR_SET_PORT_EX_IN);
+	if (rc)
+		return rc;
+
+	rc = ib_to_hbl_port_num(hdev, in.port_num, &hbl_port);
+	if (rc) {
+		hbl_ibdev_dbg(ibdev, "invalid IB port %u\n", in.port_num);
+		return rc;
+	}
+
+	if (!(hctx->ports_mask & BIT(hbl_port))) {
+		hbl_ibdev_dbg(ibdev, "port %d is not part of the context's ports mask 0x%llx\n",
+			      hbl_port, hctx->ports_mask);
+		return -EINVAL;
+	}
+
+	if (!in.qp_wq_bp_offs && in.qp_wq_bp_offs_cnt > 0)
+		return -EINVAL;
+
+	port_init_params.hbl_port_num = hbl_port;
+
+	for (i = 0; i < HBL_IB_WQ_ARRAY_TYPE_MAX; i++) {
+		port_init_params.wq_arr_attr[i].max_num_of_wqs =
+						in.wq_arr_attr[i].max_num_of_wqs;
+		port_init_params.wq_arr_attr[i].max_num_of_wqes_in_wq =
+						in.wq_arr_attr[i].max_num_of_wqes_in_wq;
+		port_init_params.wq_arr_attr[i].mem_id = in.wq_arr_attr[i].mem_id;
+		port_init_params.wq_arr_attr[i].swq_granularity =
+						in.wq_arr_attr[i].swq_granularity;
+	}
+
+	if (copy_from_user(port_init_params.qp_wq_bp_offs, u64_to_user_ptr(in.qp_wq_bp_offs),
+			   sizeof(port_init_params.qp_wq_bp_offs[0]) *
+			   min((u32)HBL_IB_MAX_BP_OFFS, in.qp_wq_bp_offs_cnt)))
+		return -EFAULT;
+
+	port_init_params.advanced = in.advanced;
+	port_init_params.adaptive_timeout_en = in.adaptive_timeout_en;
+
+	rc = hbl_ib_port_init(hctx, &port_init_params);
+	if (rc)
+		hbl_ibdev_dbg(ibdev, "failed(%d) to set port %u extended params\n", rc, hbl_port);
+
+	return rc;
+}
+
+DECLARE_UVERBS_NAMED_METHOD(
+	HBL_IB_METHOD_SET_PORT_EX,
+	UVERBS_ATTR_PTR_IN(HBL_IB_ATTR_SET_PORT_EX_IN,
+			   UVERBS_ATTR_STRUCT(struct hbl_uapi_set_port_ex_in, reserved3),
+			   UA_MANDATORY));
+
+DECLARE_UVERBS_GLOBAL_METHODS(HBL_IB_OBJECT_SET_PORT_EX,
+			      &UVERBS_METHOD(HBL_IB_METHOD_SET_PORT_EX));
+
+const struct uapi_definition hbl_set_port_ex_defs[] = {
+	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(HBL_IB_OBJECT_SET_PORT_EX),
+	{},
+};
diff --git a/drivers/infiniband/hw/hbl/hbl_usr_fifo.c b/drivers/infiniband/hw/hbl/hbl_usr_fifo.c
new file mode 100644
index 000000000000..37f387a99f40
--- /dev/null
+++ b/drivers/infiniband/hw/hbl/hbl_usr_fifo.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2022-2024 HabanaLabs, Ltd.
+ * Copyright (C) 2023-2024, Intel Corporation.
+ * All Rights Reserved.
+ */
+
+#include "hbl.h"
+#include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
+#include <rdma/uverbs_ioctl.h>
+#include <linux/net/intel/cni.h>
+
+#include <rdma/uverbs_ioctl.h>
+#include <uapi/rdma/hbl_user_ioctl_cmds.h>
+#include <uapi/rdma/hbl_user_ioctl_verbs.h>
+
+#define UVERBS_MODULE_NAME hbl
+#include <rdma/uverbs_named_ioctl.h>
+
+/**
+ * struct hbl_usr_fifo - This structure will be stored inside the uobject.
+ * @ci_entry: The rdma_user_mmap_entry for the mapped ci.
+ * @regs_entry: The rdma_user_mmap_entry for the mapped registers.
+ * @port: The port of this fifo.
+ * @id: The id of this fifo.
+ */
+struct hbl_usr_fifo {
+	struct rdma_user_mmap_entry *ci_entry;
+	struct rdma_user_mmap_entry *regs_entry;
+	u32 port;
+	u32 id;
+};
+
+static void user_fifo_mmap_entry_remove(struct hbl_usr_fifo *usr_fifo)
+{
+	rdma_user_mmap_entry_remove(usr_fifo->regs_entry);
+	if (usr_fifo->ci_entry)
+		rdma_user_mmap_entry_remove(usr_fifo->ci_entry);
+}
+
+static int user_fifo_mmap_entry_setup(struct hbl_ib_device *dev, struct hbl_ib_ucontext *hctx,
+				      struct hbl_usr_fifo *usr_fifo,
+				      struct hbl_uapi_usr_fifo_create_out *out)
+{
+	if (out->ci_handle) {
+		usr_fifo->ci_entry = hbl_ib_user_mmap_entry_insert(&hctx->ibucontext,
+								   out->ci_handle,
+								   PAGE_SIZE, &out->ci_handle);
+		if (IS_ERR(usr_fifo->ci_entry))
+			return PTR_ERR(usr_fifo->ci_entry);
+	}
+
+	usr_fifo->regs_entry = hbl_ib_user_mmap_entry_insert(&hctx->ibucontext, out->regs_handle,
+							     PAGE_SIZE, &out->regs_handle);
+	if (IS_ERR(usr_fifo->regs_entry))
+		goto err_free_ci;
+
+	return 0;
+
+err_free_ci:
+	if (usr_fifo->ci_entry)
+		rdma_user_mmap_entry_remove(usr_fifo->ci_entry);
+
+	return PTR_ERR(usr_fifo->regs_entry);
+}
+
+static int UVERBS_HANDLER(HBL_IB_METHOD_USR_FIFO_OBJ_CREATE)(struct uverbs_attr_bundle *attrs)
+{
+	struct hbl_cni_alloc_user_db_fifo_out alloc_db_fifo_out = {};
+	struct hbl_cni_alloc_user_db_fifo_in alloc_db_fifo_in = {};
+	struct hbl_cni_user_db_fifo_unset_in db_fifo_unset_in = {};
+	struct hbl_cni_user_db_fifo_set_out db_fifo_set_out = {};
+	struct hbl_cni_user_db_fifo_set_in db_fifo_set_in = {};
+	struct hbl_uapi_usr_fifo_create_out out = {};
+	struct hbl_uapi_usr_fifo_create_in in = {};
+	struct hbl_usr_fifo *usr_fifo_pdata;
+	struct hbl_ib_aux_ops *aux_ops;
+	struct hbl_ib_ucontext *hctx;
+	struct hbl_aux_dev *aux_dev;
+	struct hbl_ib_device *hdev;
+	struct ib_device *ibdev;
+	struct ib_uobject *uobj;
+	u32 port, id;
+	u8 mode;
+	int rc;
+
+	hctx = to_hbl_ib_ucontext(ib_uverbs_get_ucontext(attrs));
+	if (IS_ERR(hctx))
+		return PTR_ERR(hctx);
+
+	uobj = uverbs_attr_get_uobject(attrs, HBL_IB_ATTR_USR_FIFO_CREATE_HANDLE);
+	hdev = to_hbl_ib_dev(hctx->ibucontext.device);
+	ibdev = &hdev->ibdev;
+	aux_dev = hdev->aux_dev;
+	aux_ops = aux_dev->aux_ops;
+
+	rc = uverbs_copy_from(&in, attrs, HBL_IB_ATTR_USR_FIFO_CREATE_IN);
+	if (rc)
+		return rc;
+
+	rc = ib_to_hbl_port_num(hdev, in.port_num, &port);
+	if (rc) {
+		hbl_ibdev_dbg(ibdev, "invalid IB port %u\n", in.port_num);
+		return rc;
+	}
+
+	if (!(hctx->ports_mask & BIT(port))) {
+		hbl_ibdev_dbg(ibdev, "port %d is not part of the context's ports mask 0x%llx\n",
+			      port, hctx->ports_mask);
+		return -EINVAL;
+	}
+
+	usr_fifo_pdata = kzalloc(sizeof(*usr_fifo_pdata), GFP_KERNEL);
+	if (!usr_fifo_pdata)
+		return -ENOMEM;
+
+	mode = in.mode;
+
+	alloc_db_fifo_in.port = port;
+	alloc_db_fifo_in.id_hint = in.usr_fifo_num_hint;
+
+	rc = aux_ops->cmd_ctrl(aux_dev, hctx->cn_ctx, HBL_CNI_OP_ALLOC_USER_DB_FIFO,
+			       &alloc_db_fifo_in, &alloc_db_fifo_out);
+	if (rc) {
+		hbl_ibdev_dbg(ibdev, "failed to alloc db fifo, port %d\n", port);
+		goto err_free_pdata;
+	}
+
+	id = alloc_db_fifo_out.id;
+
+	usr_fifo_pdata->port = port;
+	usr_fifo_pdata->id = id;
+
+	db_fifo_set_in.port = port;
+	db_fifo_set_in.id = id;
+	db_fifo_set_in.mode = mode;
+
+	rc = aux_ops->cmd_ctrl(aux_dev, hctx->cn_ctx, HBL_CNI_OP_USER_DB_FIFO_SET, &db_fifo_set_in,
+			       &db_fifo_set_out);
+	if (rc) {
+		hbl_ibdev_dbg(ibdev, "failed to set db fifo %d, port %d\n", id, port);
+		goto err_usr_fifo_unset;
+	}
+
+	out.usr_fifo_num = id;
+	out.ci_handle = db_fifo_set_out.ci_handle;
+	out.regs_handle = db_fifo_set_out.regs_handle;
+	out.regs_offset = db_fifo_set_out.regs_offset;
+	out.size = db_fifo_set_out.fifo_size;
+	out.bp_thresh = db_fifo_set_out.fifo_bp_thresh;
+
+	rc = user_fifo_mmap_entry_setup(hdev, hctx, usr_fifo_pdata, &out);
+	if (rc)
+		goto err_usr_fifo_unset;
+
+	uobj->object = usr_fifo_pdata;
+
+	rc = uverbs_copy_to_struct_or_zero(attrs, HBL_IB_ATTR_USR_FIFO_CREATE_OUT, &out,
+					   sizeof(out));
+	if (rc)
+		goto err_remove_mmap_entries;
+
+	return 0;
+
+err_remove_mmap_entries:
+	user_fifo_mmap_entry_remove(usr_fifo_pdata);
+
+err_usr_fifo_unset:
+	db_fifo_unset_in.port = port;
+	db_fifo_unset_in.id = id;
+
+	if (aux_ops->cmd_ctrl(aux_dev, hctx->cn_ctx, HBL_CNI_OP_USER_DB_FIFO_UNSET,
+			      &db_fifo_unset_in, NULL))
+		hbl_ibdev_dbg(ibdev, "failed to unset db fifo %d, port %d\n", id, port);
+
+err_free_pdata:
+	kfree(usr_fifo_pdata);
+	return rc;
+}
+
+static int hbl_free_usr_fifo(struct ib_uobject *uobject, enum rdma_remove_reason why,
+			     struct uverbs_attr_bundle *attrs)
+{
+	struct hbl_cni_user_db_fifo_unset_in db_fifo_unset_in = {};
+	struct hbl_usr_fifo *usr_fifo_pdata;
+	struct hbl_ib_aux_ops *aux_ops;
+	struct hbl_ib_ucontext *hctx;
+	struct hbl_aux_dev *aux_dev;
+	struct hbl_ib_device *hdev;
+	struct ib_device *ibdev;
+	int rc;
+
+	hctx = to_hbl_ib_ucontext(ib_uverbs_get_ucontext(attrs));
+	if (IS_ERR(hctx))
+		return PTR_ERR(hctx);
+
+	usr_fifo_pdata = uobject->object;
+	hdev = to_hbl_ib_dev(hctx->ibucontext.device);
+	ibdev = &hdev->ibdev;
+	aux_dev = hdev->aux_dev;
+	aux_ops = aux_dev->aux_ops;
+
+	db_fifo_unset_in.port = usr_fifo_pdata->port;
+	db_fifo_unset_in.id = usr_fifo_pdata->id;
+
+	user_fifo_mmap_entry_remove(usr_fifo_pdata);
+
+	if (aux_ops->device_operational(aux_dev)) {
+		rc = aux_ops->cmd_ctrl(aux_dev, hctx->cn_ctx, HBL_CNI_OP_USER_DB_FIFO_UNSET,
+				       &db_fifo_unset_in, NULL);
+		if (rc) {
+			hbl_ibdev_dbg(ibdev, "failed to unset db fifo %d, port %d\n",
+				      usr_fifo_pdata->id, usr_fifo_pdata->port);
+			return rc;
+		}
+	}
+
+	kfree(usr_fifo_pdata);
+
+	return 0;
+}
+
+DECLARE_UVERBS_NAMED_METHOD(
+	HBL_IB_METHOD_USR_FIFO_OBJ_CREATE,
+	UVERBS_ATTR_IDR(HBL_IB_ATTR_USR_FIFO_CREATE_HANDLE,
+			HBL_IB_OBJECT_USR_FIFO,
+			UVERBS_ACCESS_NEW,
+			UA_MANDATORY),
+	UVERBS_ATTR_PTR_IN(HBL_IB_ATTR_USR_FIFO_CREATE_IN,
+			   UVERBS_ATTR_STRUCT(struct hbl_uapi_usr_fifo_create_in, reserved3),
+			   UA_MANDATORY),
+	UVERBS_ATTR_PTR_OUT(HBL_IB_ATTR_USR_FIFO_CREATE_OUT,
+			    UVERBS_ATTR_STRUCT(struct hbl_uapi_usr_fifo_create_out, bp_thresh),
+			    UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_METHOD_DESTROY(
+	HBL_IB_METHOD_USR_FIFO_OBJ_DESTROY,
+	UVERBS_ATTR_IDR(HBL_IB_ATTR_USR_FIFO_DESTROY_HANDLE,
+			HBL_IB_OBJECT_USR_FIFO,
+			UVERBS_ACCESS_DESTROY,
+			UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_OBJECT(HBL_IB_OBJECT_USR_FIFO,
+			    UVERBS_TYPE_ALLOC_IDR(hbl_free_usr_fifo),
+			    &UVERBS_METHOD(HBL_IB_METHOD_USR_FIFO_OBJ_CREATE),
+			    &UVERBS_METHOD(HBL_IB_METHOD_USR_FIFO_OBJ_DESTROY));
+
+const struct uapi_definition hbl_usr_fifo_defs[] = {
+	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(HBL_IB_OBJECT_USR_FIFO),
+	{},
+};
-- 
2.34.1



More information about the dri-devel mailing list