+
+/**
+ * Create VIRTQ using DevX API.
+ *
+ * @param[in] ctx
+ * Context returned from mlx5 open_device() glue function.
+ * @param [in] attr
+ * Pointer to VIRTQ attributes structure.
+ *
+ * @return
+ * The DevX object created, NULL otherwise and rte_errno is set.
+ */
+struct mlx5_devx_obj *
+mlx5_devx_cmd_create_virtq(void *ctx,
+ struct mlx5_devx_virtq_attr *attr)
+{
+ uint32_t in[MLX5_ST_SZ_DW(create_virtq_in)] = {0};
+ uint32_t out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0};
+ struct mlx5_devx_obj *virtq_obj = mlx5_malloc(MLX5_MEM_ZERO,
+ sizeof(*virtq_obj),
+ 0, SOCKET_ID_ANY);
+ void *virtq = MLX5_ADDR_OF(create_virtq_in, in, virtq);
+ void *hdr = MLX5_ADDR_OF(create_virtq_in, in, hdr);
+ void *virtctx = MLX5_ADDR_OF(virtio_net_q, virtq, virtio_q_context);
+
+ if (!virtq_obj) {
+ DRV_LOG(ERR, "Failed to allocate virtq data.");
+ rte_errno = ENOMEM;
+ return NULL;
+ }
+ 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_GENERAL_OBJ_TYPE_VIRTQ);
+ MLX5_SET16(virtio_net_q, virtq, hw_available_index,
+ attr->hw_available_index);
+ MLX5_SET16(virtio_net_q, virtq, hw_used_index, attr->hw_used_index);
+ MLX5_SET16(virtio_net_q, virtq, tso_ipv4, attr->tso_ipv4);
+ MLX5_SET16(virtio_net_q, virtq, tso_ipv6, attr->tso_ipv6);
+ MLX5_SET16(virtio_net_q, virtq, tx_csum, attr->tx_csum);
+ MLX5_SET16(virtio_net_q, virtq, rx_csum, attr->rx_csum);
+ MLX5_SET16(virtio_q, virtctx, virtio_version_1_0,
+ attr->virtio_version_1_0);
+ MLX5_SET16(virtio_q, virtctx, event_mode, attr->event_mode);
+ MLX5_SET(virtio_q, virtctx, event_qpn_or_msix, attr->qp_id);
+ MLX5_SET64(virtio_q, virtctx, desc_addr, attr->desc_addr);
+ MLX5_SET64(virtio_q, virtctx, used_addr, attr->used_addr);
+ MLX5_SET64(virtio_q, virtctx, available_addr, attr->available_addr);
+ MLX5_SET16(virtio_q, virtctx, queue_index, attr->queue_index);
+ MLX5_SET16(virtio_q, virtctx, queue_size, attr->q_size);
+ MLX5_SET(virtio_q, virtctx, virtio_q_mkey, attr->mkey);
+ MLX5_SET(virtio_q, virtctx, umem_1_id, attr->umems[0].id);
+ MLX5_SET(virtio_q, virtctx, umem_1_size, attr->umems[0].size);
+ MLX5_SET64(virtio_q, virtctx, umem_1_offset, attr->umems[0].offset);
+ MLX5_SET(virtio_q, virtctx, umem_2_id, attr->umems[1].id);
+ MLX5_SET(virtio_q, virtctx, umem_2_size, attr->umems[1].size);
+ MLX5_SET64(virtio_q, virtctx, umem_2_offset, attr->umems[1].offset);
+ MLX5_SET(virtio_q, virtctx, umem_3_id, attr->umems[2].id);
+ MLX5_SET(virtio_q, virtctx, umem_3_size, attr->umems[2].size);
+ MLX5_SET64(virtio_q, virtctx, umem_3_offset, attr->umems[2].offset);
+ MLX5_SET(virtio_q, virtctx, counter_set_id, attr->counters_obj_id);
+ MLX5_SET(virtio_q, virtctx, pd, attr->pd);
+ MLX5_SET(virtio_net_q, virtq, tisn_or_qpn, attr->tis_id);
+ virtq_obj->obj = mlx5_glue->devx_obj_create(ctx, in, sizeof(in), out,
+ sizeof(out));
+ if (!virtq_obj->obj) {
+ rte_errno = errno;
+ DRV_LOG(ERR, "Failed to create VIRTQ Obj using DevX.");
+ mlx5_free(virtq_obj);
+ return NULL;
+ }
+ virtq_obj->id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+ return virtq_obj;
+}
+
+/**
+ * Modify VIRTQ using DevX API.
+ *
+ * @param[in] virtq_obj
+ * Pointer to virtq object structure.
+ * @param [in] attr
+ * Pointer to modify virtq attributes structure.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx5_devx_cmd_modify_virtq(struct mlx5_devx_obj *virtq_obj,
+ struct mlx5_devx_virtq_attr *attr)
+{
+ uint32_t in[MLX5_ST_SZ_DW(create_virtq_in)] = {0};
+ uint32_t out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0};
+ void *virtq = MLX5_ADDR_OF(create_virtq_in, in, virtq);
+ void *hdr = MLX5_ADDR_OF(create_virtq_in, in, hdr);
+ void *virtctx = MLX5_ADDR_OF(virtio_net_q, virtq, virtio_q_context);
+ int ret;
+
+ MLX5_SET(general_obj_in_cmd_hdr, hdr, opcode,
+ MLX5_CMD_OP_MODIFY_GENERAL_OBJECT);
+ MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_type,
+ MLX5_GENERAL_OBJ_TYPE_VIRTQ);
+ MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_id, virtq_obj->id);
+ MLX5_SET64(virtio_net_q, virtq, modify_field_select, attr->type);
+ MLX5_SET16(virtio_q, virtctx, queue_index, attr->queue_index);
+ switch (attr->type) {
+ case MLX5_VIRTQ_MODIFY_TYPE_STATE:
+ MLX5_SET16(virtio_net_q, virtq, state, attr->state);
+ break;
+ case MLX5_VIRTQ_MODIFY_TYPE_DIRTY_BITMAP_PARAMS:
+ MLX5_SET(virtio_net_q, virtq, dirty_bitmap_mkey,
+ attr->dirty_bitmap_mkey);
+ MLX5_SET64(virtio_net_q, virtq, dirty_bitmap_addr,
+ attr->dirty_bitmap_addr);
+ MLX5_SET(virtio_net_q, virtq, dirty_bitmap_size,
+ attr->dirty_bitmap_size);
+ break;
+ case MLX5_VIRTQ_MODIFY_TYPE_DIRTY_BITMAP_DUMP_ENABLE:
+ MLX5_SET(virtio_net_q, virtq, dirty_bitmap_dump_enable,
+ attr->dirty_bitmap_dump_enable);
+ break;
+ default:
+ rte_errno = EINVAL;
+ return -rte_errno;
+ }
+ ret = mlx5_glue->devx_obj_modify(virtq_obj->obj, in, sizeof(in),
+ out, sizeof(out));
+ if (ret) {
+ DRV_LOG(ERR, "Failed to modify VIRTQ using DevX.");
+ rte_errno = errno;
+ return -rte_errno;
+ }
+ return ret;
+}
+
+/**
+ * Query VIRTQ using DevX API.
+ *
+ * @param[in] virtq_obj
+ * Pointer to virtq object structure.
+ * @param [in/out] attr
+ * Pointer to virtq attributes structure.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx5_devx_cmd_query_virtq(struct mlx5_devx_obj *virtq_obj,
+ struct mlx5_devx_virtq_attr *attr)
+{
+ uint32_t in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {0};
+ uint32_t out[MLX5_ST_SZ_DW(query_virtq_out)] = {0};
+ void *hdr = MLX5_ADDR_OF(query_virtq_out, in, hdr);
+ void *virtq = MLX5_ADDR_OF(query_virtq_out, out, virtq);
+ int ret;
+
+ MLX5_SET(general_obj_in_cmd_hdr, hdr, opcode,
+ MLX5_CMD_OP_QUERY_GENERAL_OBJECT);
+ MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_type,
+ MLX5_GENERAL_OBJ_TYPE_VIRTQ);
+ MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_id, virtq_obj->id);
+ ret = mlx5_glue->devx_obj_query(virtq_obj->obj, in, sizeof(in),
+ out, sizeof(out));
+ if (ret) {
+ DRV_LOG(ERR, "Failed to modify VIRTQ using DevX.");
+ rte_errno = errno;
+ return -errno;
+ }
+ attr->hw_available_index = MLX5_GET16(virtio_net_q, virtq,
+ hw_available_index);
+ attr->hw_used_index = MLX5_GET16(virtio_net_q, virtq, hw_used_index);
+ return ret;
+}
+
+/**
+ * Create QP using DevX API.
+ *
+ * @param[in] ctx
+ * Context returned from mlx5 open_device() glue function.
+ * @param [in] attr
+ * Pointer to QP attributes structure.
+ *
+ * @return
+ * The DevX object created, NULL otherwise and rte_errno is set.
+ */
+struct mlx5_devx_obj *
+mlx5_devx_cmd_create_qp(void *ctx,
+ struct mlx5_devx_qp_attr *attr)
+{
+ uint32_t in[MLX5_ST_SZ_DW(create_qp_in)] = {0};
+ uint32_t out[MLX5_ST_SZ_DW(create_qp_out)] = {0};
+ struct mlx5_devx_obj *qp_obj = mlx5_malloc(MLX5_MEM_ZERO,
+ sizeof(*qp_obj),
+ 0, SOCKET_ID_ANY);
+ void *qpc = MLX5_ADDR_OF(create_qp_in, in, qpc);
+
+ if (!qp_obj) {
+ DRV_LOG(ERR, "Failed to allocate QP data.");
+ rte_errno = ENOMEM;
+ return NULL;
+ }
+ MLX5_SET(create_qp_in, in, opcode, MLX5_CMD_OP_CREATE_QP);
+ MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC);
+ MLX5_SET(qpc, qpc, pd, attr->pd);
+ if (attr->uar_index) {
+ MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED);
+ MLX5_SET(qpc, qpc, uar_page, attr->uar_index);
+ MLX5_SET(qpc, qpc, log_page_size, attr->log_page_size -
+ MLX5_ADAPTER_PAGE_SHIFT);
+ if (attr->sq_size) {
+ MLX5_ASSERT(RTE_IS_POWER_OF_2(attr->sq_size));
+ MLX5_SET(qpc, qpc, cqn_snd, attr->cqn);
+ MLX5_SET(qpc, qpc, log_sq_size,
+ rte_log2_u32(attr->sq_size));
+ } else {
+ MLX5_SET(qpc, qpc, no_sq, 1);
+ }
+ if (attr->rq_size) {
+ MLX5_ASSERT(RTE_IS_POWER_OF_2(attr->rq_size));
+ MLX5_SET(qpc, qpc, cqn_rcv, attr->cqn);
+ MLX5_SET(qpc, qpc, log_rq_stride, attr->log_rq_stride -
+ MLX5_LOG_RQ_STRIDE_SHIFT);
+ MLX5_SET(qpc, qpc, log_rq_size,
+ rte_log2_u32(attr->rq_size));
+ MLX5_SET(qpc, qpc, rq_type, MLX5_NON_ZERO_RQ);
+ } else {
+ MLX5_SET(qpc, qpc, rq_type, MLX5_ZERO_LEN_RQ);
+ }
+ if (attr->dbr_umem_valid) {
+ MLX5_SET(qpc, qpc, dbr_umem_valid,
+ attr->dbr_umem_valid);
+ MLX5_SET(qpc, qpc, dbr_umem_id, attr->dbr_umem_id);
+ }
+ MLX5_SET64(qpc, qpc, dbr_addr, attr->dbr_address);
+ MLX5_SET64(create_qp_in, in, wq_umem_offset,
+ attr->wq_umem_offset);
+ MLX5_SET(create_qp_in, in, wq_umem_id, attr->wq_umem_id);
+ MLX5_SET(create_qp_in, in, wq_umem_valid, 1);
+ } else {
+ /* Special QP to be managed by FW - no SQ\RQ\CQ\UAR\DB rec. */
+ MLX5_SET(qpc, qpc, rq_type, MLX5_ZERO_LEN_RQ);
+ MLX5_SET(qpc, qpc, no_sq, 1);
+ }
+ qp_obj->obj = mlx5_glue->devx_obj_create(ctx, in, sizeof(in), out,
+ sizeof(out));
+ if (!qp_obj->obj) {
+ rte_errno = errno;
+ DRV_LOG(ERR, "Failed to create QP Obj using DevX.");
+ mlx5_free(qp_obj);
+ return NULL;
+ }
+ qp_obj->id = MLX5_GET(create_qp_out, out, qpn);
+ return qp_obj;
+}
+
+/**
+ * Modify QP using DevX API.
+ * Currently supports only force loop-back QP.
+ *
+ * @param[in] qp
+ * Pointer to QP object structure.
+ * @param [in] qp_st_mod_op
+ * The QP state modification operation.
+ * @param [in] remote_qp_id
+ * The remote QP ID for MLX5_CMD_OP_INIT2RTR_QP operation.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx5_devx_cmd_modify_qp_state(struct mlx5_devx_obj *qp, uint32_t qp_st_mod_op,
+ uint32_t remote_qp_id)
+{
+ union {
+ uint32_t rst2init[MLX5_ST_SZ_DW(rst2init_qp_in)];
+ uint32_t init2rtr[MLX5_ST_SZ_DW(init2rtr_qp_in)];
+ uint32_t rtr2rts[MLX5_ST_SZ_DW(rtr2rts_qp_in)];
+ } in;
+ union {
+ uint32_t rst2init[MLX5_ST_SZ_DW(rst2init_qp_out)];
+ uint32_t init2rtr[MLX5_ST_SZ_DW(init2rtr_qp_out)];
+ uint32_t rtr2rts[MLX5_ST_SZ_DW(rtr2rts_qp_out)];
+ } out;
+ void *qpc;
+ int ret;
+ unsigned int inlen;
+ unsigned int outlen;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ MLX5_SET(rst2init_qp_in, &in, opcode, qp_st_mod_op);
+ switch (qp_st_mod_op) {
+ case MLX5_CMD_OP_RST2INIT_QP:
+ MLX5_SET(rst2init_qp_in, &in, qpn, qp->id);
+ qpc = MLX5_ADDR_OF(rst2init_qp_in, &in, qpc);
+ MLX5_SET(qpc, qpc, primary_address_path.vhca_port_num, 1);
+ MLX5_SET(qpc, qpc, rre, 1);
+ MLX5_SET(qpc, qpc, rwe, 1);
+ MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED);
+ inlen = sizeof(in.rst2init);
+ outlen = sizeof(out.rst2init);
+ break;
+ case MLX5_CMD_OP_INIT2RTR_QP:
+ MLX5_SET(init2rtr_qp_in, &in, qpn, qp->id);
+ qpc = MLX5_ADDR_OF(init2rtr_qp_in, &in, qpc);
+ MLX5_SET(qpc, qpc, primary_address_path.fl, 1);
+ MLX5_SET(qpc, qpc, primary_address_path.vhca_port_num, 1);
+ MLX5_SET(qpc, qpc, mtu, 1);
+ MLX5_SET(qpc, qpc, log_msg_max, 30);
+ MLX5_SET(qpc, qpc, remote_qpn, remote_qp_id);
+ MLX5_SET(qpc, qpc, min_rnr_nak, 0);
+ inlen = sizeof(in.init2rtr);
+ outlen = sizeof(out.init2rtr);
+ break;
+ case MLX5_CMD_OP_RTR2RTS_QP:
+ qpc = MLX5_ADDR_OF(rtr2rts_qp_in, &in, qpc);
+ MLX5_SET(rtr2rts_qp_in, &in, qpn, qp->id);
+ MLX5_SET(qpc, qpc, primary_address_path.ack_timeout, 14);
+ MLX5_SET(qpc, qpc, log_ack_req_freq, 0);
+ MLX5_SET(qpc, qpc, retry_count, 7);
+ MLX5_SET(qpc, qpc, rnr_retry, 7);
+ inlen = sizeof(in.rtr2rts);
+ outlen = sizeof(out.rtr2rts);
+ break;
+ default:
+ DRV_LOG(ERR, "Invalid or unsupported QP modify op %u.",
+ qp_st_mod_op);
+ rte_errno = EINVAL;
+ return -rte_errno;
+ }
+ ret = mlx5_glue->devx_obj_modify(qp->obj, &in, inlen, &out, outlen);
+ if (ret) {
+ DRV_LOG(ERR, "Failed to modify QP using DevX.");
+ rte_errno = errno;
+ return -rte_errno;
+ }
+ return ret;
+}
+
+struct mlx5_devx_obj *
+mlx5_devx_cmd_create_virtio_q_counters(void *ctx)
+{
+ uint32_t in[MLX5_ST_SZ_DW(create_virtio_q_counters_in)] = {0};
+ uint32_t out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0};
+ struct mlx5_devx_obj *couners_obj = mlx5_malloc(MLX5_MEM_ZERO,
+ sizeof(*couners_obj), 0,
+ SOCKET_ID_ANY);
+ void *hdr = MLX5_ADDR_OF(create_virtio_q_counters_in, in, hdr);
+
+ if (!couners_obj) {
+ DRV_LOG(ERR, "Failed to allocate virtio queue counters data.");
+ rte_errno = ENOMEM;
+ return NULL;
+ }
+ 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_GENERAL_OBJ_TYPE_VIRTIO_Q_COUNTERS);
+ couners_obj->obj = mlx5_glue->devx_obj_create(ctx, in, sizeof(in), out,
+ sizeof(out));
+ if (!couners_obj->obj) {
+ rte_errno = errno;
+ DRV_LOG(ERR, "Failed to create virtio queue counters Obj using"
+ " DevX.");
+ mlx5_free(couners_obj);
+ return NULL;
+ }
+ couners_obj->id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+ return couners_obj;
+}
+
+int
+mlx5_devx_cmd_query_virtio_q_counters(struct mlx5_devx_obj *couners_obj,
+ struct mlx5_devx_virtio_q_couners_attr *attr)
+{
+ uint32_t in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {0};
+ uint32_t out[MLX5_ST_SZ_DW(query_virtio_q_counters_out)] = {0};
+ void *hdr = MLX5_ADDR_OF(query_virtio_q_counters_out, in, hdr);
+ void *virtio_q_counters = MLX5_ADDR_OF(query_virtio_q_counters_out, out,
+ virtio_q_counters);
+ int ret;
+
+ MLX5_SET(general_obj_in_cmd_hdr, hdr, opcode,
+ MLX5_CMD_OP_QUERY_GENERAL_OBJECT);
+ MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_type,
+ MLX5_GENERAL_OBJ_TYPE_VIRTIO_Q_COUNTERS);
+ MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_id, couners_obj->id);
+ ret = mlx5_glue->devx_obj_query(couners_obj->obj, in, sizeof(in), out,
+ sizeof(out));
+ if (ret) {
+ DRV_LOG(ERR, "Failed to query virtio q counters using DevX.");
+ rte_errno = errno;
+ return -errno;
+ }
+ attr->received_desc = MLX5_GET64(virtio_q_counters, virtio_q_counters,
+ received_desc);
+ attr->completed_desc = MLX5_GET64(virtio_q_counters, virtio_q_counters,
+ completed_desc);
+ attr->error_cqes = MLX5_GET(virtio_q_counters, virtio_q_counters,
+ error_cqes);
+ attr->bad_desc_errors = MLX5_GET(virtio_q_counters, virtio_q_counters,
+ bad_desc_errors);
+ attr->exceed_max_chain = MLX5_GET(virtio_q_counters, virtio_q_counters,
+ exceed_max_chain);
+ attr->invalid_buffer = MLX5_GET(virtio_q_counters, virtio_q_counters,
+ invalid_buffer);
+ return ret;
+}