common/mlx5: optimize cache list object memory
[dpdk.git] / drivers / common / mlx5 / mlx5_devx_cmds.c
index 6c6f439..63ae958 100644 (file)
@@ -1,5 +1,6 @@
-// SPDX-License-Identifier: BSD-3-Clause
-/* Copyright 2018 Mellanox Technologies, Ltd */
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Mellanox Technologies, Ltd
+ */
 
 #include <unistd.h>
 
@@ -9,10 +10,9 @@
 
 #include "mlx5_prm.h"
 #include "mlx5_devx_cmds.h"
-#include "mlx5_common_utils.h"
+#include "mlx5_common_log.h"
 #include "mlx5_malloc.h"
 
-
 /**
  * Perform read access to the registers. Reads data from register
  * and writes ones to the specified buffer.
@@ -61,7 +61,7 @@ mlx5_devx_cmd_register_read(void *ctx, uint16_t reg_id, uint32_t arg,
        if (status) {
                int syndrome = MLX5_GET(access_register_out, out, syndrome);
 
-               DRV_LOG(DEBUG, "Failed to access NIC register 0x%X, "
+               DRV_LOG(DEBUG, "Failed to read access NIC register 0x%X, "
                               "status %x, syndrome = %x",
                               reg_id, status, syndrome);
                return -1;
@@ -74,6 +74,70 @@ error:
        return rc;
 }
 
+/**
+ * Perform write access to the registers.
+ *
+ * @param[in] ctx
+ *   Context returned from mlx5 open_device() glue function.
+ * @param[in] reg_id
+ *   Register identifier according to the PRM.
+ * @param[in] arg
+ *   Register access auxiliary parameter according to the PRM.
+ * @param[out] data
+ *   Pointer to the buffer containing data to write.
+ * @param[in] dw_cnt
+ *   Buffer size in double words (32bit units).
+ *
+ * @return
+ *   0 on success, a negative value otherwise.
+ */
+int
+mlx5_devx_cmd_register_write(void *ctx, uint16_t reg_id, uint32_t arg,
+                            uint32_t *data, uint32_t dw_cnt)
+{
+       uint32_t in[MLX5_ST_SZ_DW(access_register_in) +
+                   MLX5_ACCESS_REGISTER_DATA_DWORD_MAX] = {0};
+       uint32_t out[MLX5_ST_SZ_DW(access_register_out)] = {0};
+       int status, rc;
+       void *ptr;
+
+       MLX5_ASSERT(data && dw_cnt);
+       MLX5_ASSERT(dw_cnt <= MLX5_ACCESS_REGISTER_DATA_DWORD_MAX);
+       if (dw_cnt > MLX5_ACCESS_REGISTER_DATA_DWORD_MAX) {
+               DRV_LOG(ERR, "Data to write exceeds max size");
+               return -1;
+       }
+       MLX5_SET(access_register_in, in, opcode,
+                MLX5_CMD_OP_ACCESS_REGISTER_USER);
+       MLX5_SET(access_register_in, in, op_mod,
+                MLX5_ACCESS_REGISTER_IN_OP_MOD_WRITE);
+       MLX5_SET(access_register_in, in, register_id, reg_id);
+       MLX5_SET(access_register_in, in, argument, arg);
+       ptr = MLX5_ADDR_OF(access_register_in, in, register_data);
+       memcpy(ptr, data, dw_cnt * sizeof(uint32_t));
+       rc = mlx5_glue->devx_general_cmd(ctx, in, sizeof(in), out, sizeof(out));
+
+       rc = mlx5_glue->devx_general_cmd(ctx, in,
+                                        MLX5_ST_SZ_BYTES(access_register_in) +
+                                        dw_cnt * sizeof(uint32_t),
+                                        out, sizeof(out));
+       if (rc)
+               goto error;
+       status = MLX5_GET(access_register_out, out, status);
+       if (status) {
+               int syndrome = MLX5_GET(access_register_out, out, syndrome);
+
+               DRV_LOG(DEBUG, "Failed to write access NIC register 0x%X, "
+                              "status %x, syndrome = %x",
+                              reg_id, status, syndrome);
+               return -1;
+       }
+       return 0;
+error:
+       rc = (rc > 0) ? -rc : rc;
+       return rc;
+}
+
 /**
  * Allocate flow counters via devx interface.
  *
@@ -263,6 +327,10 @@ mlx5_devx_cmd_mkey_create(void *ctx,
        MLX5_SET(create_mkey_in, in, pg_access, attr->pg_access);
        MLX5_SET(mkc, mkc, lw, 0x1);
        MLX5_SET(mkc, mkc, lr, 0x1);
+       if (attr->set_remote_rw) {
+               MLX5_SET(mkc, mkc, rw, 0x1);
+               MLX5_SET(mkc, mkc, rr, 0x1);
+       }
        MLX5_SET(mkc, mkc, qpn, 0xffffff);
        MLX5_SET(mkc, mkc, pd, attr->pd);
        MLX5_SET(mkc, mkc, mkey_7_0, attr->umem_id & 0xFF);
@@ -273,6 +341,11 @@ mlx5_devx_cmd_mkey_create(void *ctx,
        MLX5_SET(mkc, mkc, relaxed_ordering_read, attr->relaxed_ordering_read);
        MLX5_SET64(mkc, mkc, start_addr, attr->addr);
        MLX5_SET64(mkc, mkc, len, attr->size);
+       MLX5_SET(mkc, mkc, crypto_en, attr->crypto_en);
+       if (attr->crypto_en) {
+               MLX5_SET(mkc, mkc, bsf_en, attr->crypto_en);
+               MLX5_SET(mkc, mkc, bsf_octword_size, 4);
+       }
        mkey->obj = mlx5_glue->devx_obj_create(ctx, in, in_size_dw * 4, out,
                                               sizeof(out));
        if (!mkey->obj) {
@@ -626,6 +699,29 @@ mlx5_devx_cmd_create_flex_parser(void *ctx,
        return parse_flex_obj;
 }
 
+static int
+mlx5_devx_query_pkt_integrity_match(void *hcattr)
+{
+       return MLX5_GET(flow_table_nic_cap, hcattr,
+                       ft_field_support_2_nic_receive.inner_l3_ok) &&
+              MLX5_GET(flow_table_nic_cap, hcattr,
+                       ft_field_support_2_nic_receive.inner_l4_ok) &&
+              MLX5_GET(flow_table_nic_cap, hcattr,
+                       ft_field_support_2_nic_receive.outer_l3_ok) &&
+              MLX5_GET(flow_table_nic_cap, hcattr,
+                       ft_field_support_2_nic_receive.outer_l4_ok) &&
+              MLX5_GET(flow_table_nic_cap, hcattr,
+                       ft_field_support_2_nic_receive
+                               .inner_ipv4_checksum_ok) &&
+              MLX5_GET(flow_table_nic_cap, hcattr,
+                       ft_field_support_2_nic_receive.inner_l4_checksum_ok) &&
+              MLX5_GET(flow_table_nic_cap, hcattr,
+                       ft_field_support_2_nic_receive
+                               .outer_ipv4_checksum_ok) &&
+              MLX5_GET(flow_table_nic_cap, hcattr,
+                       ft_field_support_2_nic_receive.outer_l4_checksum_ok);
+}
+
 /**
  * Query HCA attributes.
  * Using those attributes we can check on run time if the device
@@ -647,6 +743,7 @@ mlx5_devx_cmd_query_hca_attr(void *ctx,
        uint32_t out[MLX5_ST_SZ_DW(query_hca_cap_out)] = {0};
        void *hcattr;
        int status, syndrome, rc, i;
+       uint64_t general_obj_types_supported = 0;
 
        MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP);
        MLX5_SET(query_hca_cap_in, in, op_mod,
@@ -725,12 +822,30 @@ mlx5_devx_cmd_query_hca_attr(void *ctx,
        attr->regex = MLX5_GET(cmd_hca_cap, hcattr, regexp);
        attr->regexp_num_of_engines = MLX5_GET(cmd_hca_cap, hcattr,
                                               regexp_num_of_engines);
-       attr->flow_hit_aso = !!(MLX5_GET64(cmd_hca_cap, hcattr,
-                                          general_obj_types) &
+       /* Read the general_obj_types bitmap and extract the relevant bits. */
+       general_obj_types_supported = MLX5_GET64(cmd_hca_cap, hcattr,
+                                                general_obj_types);
+       attr->vdpa.valid = !!(general_obj_types_supported &
+                             MLX5_GENERAL_OBJ_TYPES_CAP_VIRTQ_NET_Q);
+       attr->vdpa.queue_counters_valid =
+                       !!(general_obj_types_supported &
+                          MLX5_GENERAL_OBJ_TYPES_CAP_VIRTIO_Q_COUNTERS);
+       attr->parse_graph_flex_node =
+                       !!(general_obj_types_supported &
+                          MLX5_GENERAL_OBJ_TYPES_CAP_PARSE_GRAPH_FLEX_NODE);
+       attr->flow_hit_aso = !!(general_obj_types_supported &
                                MLX5_GENERAL_OBJ_TYPES_CAP_FLOW_HIT_ASO);
-       attr->geneve_tlv_opt = !!(MLX5_GET64(cmd_hca_cap, hcattr,
-                                          general_obj_types) &
-                               MLX5_GENERAL_OBJ_TYPES_CAP_GENEVE_TLV_OPT);
+       attr->geneve_tlv_opt = !!(general_obj_types_supported &
+                                 MLX5_GENERAL_OBJ_TYPES_CAP_GENEVE_TLV_OPT);
+       attr->dek = !!(general_obj_types_supported &
+                      MLX5_GENERAL_OBJ_TYPES_CAP_DEK);
+       attr->import_kek = !!(general_obj_types_supported &
+                             MLX5_GENERAL_OBJ_TYPES_CAP_IMPORT_KEK);
+       attr->credential = !!(general_obj_types_supported &
+                             MLX5_GENERAL_OBJ_TYPES_CAP_CREDENTIAL);
+       attr->crypto_login = !!(general_obj_types_supported &
+                               MLX5_GENERAL_OBJ_TYPES_CAP_CRYPTO_LOGIN);
+       /* Add reading of other GENERAL_OBJ_TYPES_CAP bits above this line. */
        attr->log_max_cq = MLX5_GET(cmd_hca_cap, hcattr, log_max_cq);
        attr->log_max_qp = MLX5_GET(cmd_hca_cap, hcattr, log_max_qp);
        attr->log_max_cq_sz = MLX5_GET(cmd_hca_cap, hcattr, log_max_cq_sz);
@@ -760,6 +875,12 @@ mlx5_devx_cmd_query_hca_attr(void *ctx,
                MLX5_GET(cmd_hca_cap, hcattr, umr_indirect_mkey_disabled);
        attr->umr_modify_entity_size_disabled =
                MLX5_GET(cmd_hca_cap, hcattr, umr_modify_entity_size_disabled);
+       attr->crypto = MLX5_GET(cmd_hca_cap, hcattr, crypto);
+       if (attr->crypto)
+               attr->aes_xts = MLX5_GET(cmd_hca_cap, hcattr, aes_xts);
+       attr->ct_offload = !!(MLX5_GET64(cmd_hca_cap, hcattr,
+                                        general_obj_types) &
+                             MLX5_GENERAL_OBJ_TYPES_CAP_CONN_TRACK_OFFLOAD);
        if (attr->qos.sup) {
                MLX5_SET(query_hca_cap_in, in, op_mod,
                         MLX5_GET_HCA_CAP_OP_MOD_QOS_CAP |
@@ -823,10 +944,13 @@ mlx5_devx_cmd_query_hca_attr(void *ctx,
                return -1;
        }
        hcattr = MLX5_ADDR_OF(query_hca_cap_out, out, capability);
-       attr->log_max_ft_sampler_num =
-                       MLX5_GET(flow_table_nic_cap,
-                       hcattr, flow_table_properties.log_max_ft_sampler_num);
-
+       attr->log_max_ft_sampler_num = MLX5_GET
+               (flow_table_nic_cap, hcattr,
+                flow_table_properties_nic_receive.log_max_ft_sampler_num);
+       attr->flow.tunnel_header_0_1 = MLX5_GET
+               (flow_table_nic_cap, hcattr,
+                ft_field_support_2_nic_receive.tunnel_header_0_1);
+       attr->pkt_integrity_match = mlx5_devx_query_pkt_integrity_match(hcattr);
        /* Query HCA offloads for Ethernet protocol. */
        memset(in, 0, sizeof(in));
        memset(out, 0, sizeof(out));
@@ -851,6 +975,8 @@ mlx5_devx_cmd_query_hca_attr(void *ctx,
        hcattr = MLX5_ADDR_OF(query_hca_cap_out, out, capability);
        attr->wqe_vlan_insert = MLX5_GET(per_protocol_networking_offload_caps,
                                         hcattr, wqe_vlan_insert);
+       attr->csum_cap = MLX5_GET(per_protocol_networking_offload_caps,
+                                        hcattr, csum_cap);
        attr->lro_cap = MLX5_GET(per_protocol_networking_offload_caps, hcattr,
                                 lro_cap);
        attr->tunnel_lro_gre = MLX5_GET(per_protocol_networking_offload_caps,
@@ -2227,6 +2353,56 @@ mlx5_devx_cmd_create_flow_meter_aso_obj(void *ctx, uint32_t pd,
        return flow_meter_aso_obj;
 }
 
+/*
+ * Create general object of type CONN_TRACK_OFFLOAD using DevX API.
+ *
+ * @param[in] ctx
+ *   Context returned from mlx5 open_device() glue function.
+ * @param [in] pd
+ *   PD value to associate the CONN_TRACK_OFFLOAD ASO object with.
+ * @param [in] log_obj_size
+ *   log_obj_size to allocate its power of 2 * objects
+ *   in one CONN_TRACK_OFFLOAD bulk allocation.
+ *
+ * @return
+ *   The DevX object created, NULL otherwise and rte_errno is set.
+ */
+struct mlx5_devx_obj *
+mlx5_devx_cmd_create_conn_track_offload_obj(void *ctx, uint32_t pd,
+                                           uint32_t log_obj_size)
+{
+       uint32_t in[MLX5_ST_SZ_DW(create_conn_track_aso_in)] = {0};
+       uint32_t out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
+       struct mlx5_devx_obj *ct_aso_obj;
+       void *ptr;
+
+       ct_aso_obj = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*ct_aso_obj),
+                                0, SOCKET_ID_ANY);
+       if (!ct_aso_obj) {
+               DRV_LOG(ERR, "Failed to allocate CONN_TRACK_OFFLOAD object.");
+               rte_errno = ENOMEM;
+               return NULL;
+       }
+       ptr = MLX5_ADDR_OF(create_conn_track_aso_in, in, hdr);
+       MLX5_SET(general_obj_in_cmd_hdr, ptr, opcode,
+                MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
+       MLX5_SET(general_obj_in_cmd_hdr, ptr, obj_type,
+                MLX5_GENERAL_OBJ_TYPE_CONN_TRACK_OFFLOAD);
+       MLX5_SET(general_obj_in_cmd_hdr, ptr, log_obj_range, log_obj_size);
+       ptr = MLX5_ADDR_OF(create_conn_track_aso_in, in, conn_track_offload);
+       MLX5_SET(conn_track_offload, ptr, conn_track_aso_access_pd, pd);
+       ct_aso_obj->obj = mlx5_glue->devx_obj_create(ctx, in, sizeof(in),
+                                                    out, sizeof(out));
+       if (!ct_aso_obj->obj) {
+               rte_errno = errno;
+               DRV_LOG(ERR, "Failed to create CONN_TRACK_OFFLOAD obj by using DevX.");
+               mlx5_free(ct_aso_obj);
+               return NULL;
+       }
+       ct_aso_obj->id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+       return ct_aso_obj;
+}
+
 /**
  * Create general object of type GENEVE TLV option using DevX API.
  *
@@ -2263,7 +2439,7 @@ mlx5_devx_cmd_create_geneve_tlv_option(void *ctx,
        MLX5_SET(general_obj_in_cmd_hdr, hdr, opcode,
                        MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
        MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_type,
-                       MLX5_OBJ_TYPE_GENEVE_TLV_OPT);
+                MLX5_GENERAL_OBJ_TYPE_GENEVE_TLV_OPT);
        MLX5_SET(geneve_tlv_option, opt, option_class,
                        rte_be_to_cpu_16(class));
        MLX5_SET(geneve_tlv_option, opt, option_type, type);
@@ -2381,3 +2557,203 @@ mlx5_devx_cmd_queue_counter_query(struct mlx5_devx_obj *dcs, int clear,
        *out_of_buffers = MLX5_GET(query_q_counter_out, out, out_of_buffer);
        return 0;
 }
+
+/**
+ * Create general object of type DEK using DevX API.
+ *
+ * @param[in] ctx
+ *   Context returned from mlx5 open_device() glue function.
+ * @param [in] attr
+ *   Pointer to DEK attributes structure.
+ *
+ * @return
+ *   The DevX object created, NULL otherwise and rte_errno is set.
+ */
+struct mlx5_devx_obj *
+mlx5_devx_cmd_create_dek_obj(void *ctx, struct mlx5_devx_dek_attr *attr)
+{
+       uint32_t in[MLX5_ST_SZ_DW(create_dek_in)] = {0};
+       uint32_t out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0};
+       struct mlx5_devx_obj *dek_obj = NULL;
+       void *ptr = NULL, *key_addr = NULL;
+
+       dek_obj = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*dek_obj),
+                             0, SOCKET_ID_ANY);
+       if (dek_obj == NULL) {
+               DRV_LOG(ERR, "Failed to allocate DEK object data");
+               rte_errno = ENOMEM;
+               return NULL;
+       }
+       ptr = MLX5_ADDR_OF(create_dek_in, in, hdr);
+       MLX5_SET(general_obj_in_cmd_hdr, ptr, opcode,
+                MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
+       MLX5_SET(general_obj_in_cmd_hdr, ptr, obj_type,
+                MLX5_GENERAL_OBJ_TYPE_DEK);
+       ptr = MLX5_ADDR_OF(create_dek_in, in, dek);
+       MLX5_SET(dek, ptr, key_size, attr->key_size);
+       MLX5_SET(dek, ptr, has_keytag, attr->has_keytag);
+       MLX5_SET(dek, ptr, key_purpose, attr->key_purpose);
+       MLX5_SET(dek, ptr, pd, attr->pd);
+       MLX5_SET64(dek, ptr, opaque, attr->opaque);
+       key_addr = MLX5_ADDR_OF(dek, ptr, key);
+       memcpy(key_addr, (void *)(attr->key), MLX5_CRYPTO_KEY_MAX_SIZE);
+       dek_obj->obj = mlx5_glue->devx_obj_create(ctx, in, sizeof(in),
+                                                 out, sizeof(out));
+       if (dek_obj->obj == NULL) {
+               rte_errno = errno;
+               DRV_LOG(ERR, "Failed to create DEK obj using DevX.");
+               mlx5_free(dek_obj);
+               return NULL;
+       }
+       dek_obj->id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+       return dek_obj;
+}
+
+/**
+ * Create general object of type IMPORT_KEK using DevX API.
+ *
+ * @param[in] ctx
+ *   Context returned from mlx5 open_device() glue function.
+ * @param [in] attr
+ *   Pointer to IMPORT_KEK attributes structure.
+ *
+ * @return
+ *   The DevX object created, NULL otherwise and rte_errno is set.
+ */
+struct mlx5_devx_obj *
+mlx5_devx_cmd_create_import_kek_obj(void *ctx,
+                                   struct mlx5_devx_import_kek_attr *attr)
+{
+       uint32_t in[MLX5_ST_SZ_DW(create_import_kek_in)] = {0};
+       uint32_t out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0};
+       struct mlx5_devx_obj *import_kek_obj = NULL;
+       void *ptr = NULL, *key_addr = NULL;
+
+       import_kek_obj = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*import_kek_obj),
+                                    0, SOCKET_ID_ANY);
+       if (import_kek_obj == NULL) {
+               DRV_LOG(ERR, "Failed to allocate IMPORT_KEK object data");
+               rte_errno = ENOMEM;
+               return NULL;
+       }
+       ptr = MLX5_ADDR_OF(create_import_kek_in, in, hdr);
+       MLX5_SET(general_obj_in_cmd_hdr, ptr, opcode,
+                MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
+       MLX5_SET(general_obj_in_cmd_hdr, ptr, obj_type,
+                MLX5_GENERAL_OBJ_TYPE_IMPORT_KEK);
+       ptr = MLX5_ADDR_OF(create_import_kek_in, in, import_kek);
+       MLX5_SET(import_kek, ptr, key_size, attr->key_size);
+       key_addr = MLX5_ADDR_OF(import_kek, ptr, key);
+       memcpy(key_addr, (void *)(attr->key), MLX5_CRYPTO_KEY_MAX_SIZE);
+       import_kek_obj->obj = mlx5_glue->devx_obj_create(ctx, in, sizeof(in),
+                                                        out, sizeof(out));
+       if (import_kek_obj->obj == NULL) {
+               rte_errno = errno;
+               DRV_LOG(ERR, "Failed to create IMPORT_KEK object using DevX.");
+               mlx5_free(import_kek_obj);
+               return NULL;
+       }
+       import_kek_obj->id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+       return import_kek_obj;
+}
+
+/**
+ * Create general object of type CREDENTIAL using DevX API.
+ *
+ * @param[in] ctx
+ *   Context returned from mlx5 open_device() glue function.
+ * @param [in] attr
+ *   Pointer to CREDENTIAL attributes structure.
+ *
+ * @return
+ *   The DevX object created, NULL otherwise and rte_errno is set.
+ */
+struct mlx5_devx_obj *
+mlx5_devx_cmd_create_credential_obj(void *ctx,
+                                   struct mlx5_devx_credential_attr *attr)
+{
+       uint32_t in[MLX5_ST_SZ_DW(create_credential_in)] = {0};
+       uint32_t out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0};
+       struct mlx5_devx_obj *credential_obj = NULL;
+       void *ptr = NULL, *credential_addr = NULL;
+
+       credential_obj = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*credential_obj),
+                                    0, SOCKET_ID_ANY);
+       if (credential_obj == NULL) {
+               DRV_LOG(ERR, "Failed to allocate CREDENTIAL object data");
+               rte_errno = ENOMEM;
+               return NULL;
+       }
+       ptr = MLX5_ADDR_OF(create_credential_in, in, hdr);
+       MLX5_SET(general_obj_in_cmd_hdr, ptr, opcode,
+                MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
+       MLX5_SET(general_obj_in_cmd_hdr, ptr, obj_type,
+                MLX5_GENERAL_OBJ_TYPE_CREDENTIAL);
+       ptr = MLX5_ADDR_OF(create_credential_in, in, credential);
+       MLX5_SET(credential, ptr, credential_role, attr->credential_role);
+       credential_addr = MLX5_ADDR_OF(credential, ptr, credential);
+       memcpy(credential_addr, (void *)(attr->credential),
+              MLX5_CRYPTO_CREDENTIAL_SIZE);
+       credential_obj->obj = mlx5_glue->devx_obj_create(ctx, in, sizeof(in),
+                                                        out, sizeof(out));
+       if (credential_obj->obj == NULL) {
+               rte_errno = errno;
+               DRV_LOG(ERR, "Failed to create CREDENTIAL object using DevX.");
+               mlx5_free(credential_obj);
+               return NULL;
+       }
+       credential_obj->id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+       return credential_obj;
+}
+
+/**
+ * Create general object of type CRYPTO_LOGIN using DevX API.
+ *
+ * @param[in] ctx
+ *   Context returned from mlx5 open_device() glue function.
+ * @param [in] attr
+ *   Pointer to CRYPTO_LOGIN attributes structure.
+ *
+ * @return
+ *   The DevX object created, NULL otherwise and rte_errno is set.
+ */
+struct mlx5_devx_obj *
+mlx5_devx_cmd_create_crypto_login_obj(void *ctx,
+                                     struct mlx5_devx_crypto_login_attr *attr)
+{
+       uint32_t in[MLX5_ST_SZ_DW(create_crypto_login_in)] = {0};
+       uint32_t out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0};
+       struct mlx5_devx_obj *crypto_login_obj = NULL;
+       void *ptr = NULL, *credential_addr = NULL;
+
+       crypto_login_obj = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*crypto_login_obj),
+                                      0, SOCKET_ID_ANY);
+       if (crypto_login_obj == NULL) {
+               DRV_LOG(ERR, "Failed to allocate CRYPTO_LOGIN object data");
+               rte_errno = ENOMEM;
+               return NULL;
+       }
+       ptr = MLX5_ADDR_OF(create_crypto_login_in, in, hdr);
+       MLX5_SET(general_obj_in_cmd_hdr, ptr, opcode,
+                MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
+       MLX5_SET(general_obj_in_cmd_hdr, ptr, obj_type,
+                MLX5_GENERAL_OBJ_TYPE_CRYPTO_LOGIN);
+       ptr = MLX5_ADDR_OF(create_crypto_login_in, in, crypto_login);
+       MLX5_SET(crypto_login, ptr, credential_pointer,
+                attr->credential_pointer);
+       MLX5_SET(crypto_login, ptr, session_import_kek_ptr,
+                attr->session_import_kek_ptr);
+       credential_addr = MLX5_ADDR_OF(crypto_login, ptr, credential);
+       memcpy(credential_addr, (void *)(attr->credential),
+              MLX5_CRYPTO_CREDENTIAL_SIZE);
+       crypto_login_obj->obj = mlx5_glue->devx_obj_create(ctx, in, sizeof(in),
+                                                          out, sizeof(out));
+       if (crypto_login_obj->obj == NULL) {
+               rte_errno = errno;
+               DRV_LOG(ERR, "Failed to create CRYPTO_LOGIN obj using DevX.");
+               mlx5_free(crypto_login_obj);
+               return NULL;
+       }
+       crypto_login_obj->id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+       return crypto_login_obj;
+}