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 <oshpigel...@habana.ai>
Co-developed-by: Abhilash K V <kvabhil...@habana.ai>
Signed-off-by: Abhilash K V <kvabhil...@habana.ai>
Co-developed-by: Andrey Agranovich <aagranov...@habana.ai>
Signed-off-by: Andrey Agranovich <aagranov...@habana.ai>
Co-developed-by: Bharat Jauhari <bjauh...@habana.ai>
Signed-off-by: Bharat Jauhari <bjauh...@habana.ai>
Co-developed-by: David Meriin <dmer...@habana.ai>
Signed-off-by: David Meriin <dmer...@habana.ai>
Co-developed-by: Sagiv Ozeri <soz...@habana.ai>
Signed-off-by: Sagiv Ozeri <soz...@habana.ai>
Co-developed-by: Zvika Yehudai <zyehu...@habana.ai>
Signed-off-by: Zvika Yehudai <zyehu...@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

Reply via email to