f-stack/dpdk/drivers/net/mlx5/hws/mlx5dr_send.c

851 lines
22 KiB
C
Raw Normal View History

2023-09-13 12:21:49 +00:00
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) 2022 NVIDIA Corporation & Affiliates
*/
#include "mlx5dr_internal.h"
struct mlx5dr_send_ring_dep_wqe *
mlx5dr_send_add_new_dep_wqe(struct mlx5dr_send_engine *queue)
{
struct mlx5dr_send_ring_sq *send_sq = &queue->send_ring->send_sq;
unsigned int idx = send_sq->head_dep_idx++ & (queue->num_entries - 1);
memset(&send_sq->dep_wqe[idx].wqe_data.tag, 0, MLX5DR_MATCH_TAG_SZ);
return &send_sq->dep_wqe[idx];
}
void mlx5dr_send_abort_new_dep_wqe(struct mlx5dr_send_engine *queue)
{
queue->send_ring->send_sq.head_dep_idx--;
}
void mlx5dr_send_all_dep_wqe(struct mlx5dr_send_engine *queue)
{
struct mlx5dr_send_ring_sq *send_sq = &queue->send_ring->send_sq;
struct mlx5dr_send_ste_attr ste_attr = {0};
struct mlx5dr_send_ring_dep_wqe *dep_wqe;
ste_attr.send_attr.opmod = MLX5DR_WQE_GTA_OPMOD_STE;
ste_attr.send_attr.opcode = MLX5DR_WQE_OPCODE_TBL_ACCESS;
ste_attr.send_attr.len = MLX5DR_WQE_SZ_GTA_CTRL + MLX5DR_WQE_SZ_GTA_DATA;
ste_attr.gta_opcode = MLX5DR_WQE_GTA_OP_ACTIVATE;
/* Fence first from previous depend WQEs */
ste_attr.send_attr.fence = 1;
while (send_sq->head_dep_idx != send_sq->tail_dep_idx) {
dep_wqe = &send_sq->dep_wqe[send_sq->tail_dep_idx++ & (queue->num_entries - 1)];
/* Notify HW on the last WQE */
ste_attr.send_attr.notify_hw = (send_sq->tail_dep_idx == send_sq->head_dep_idx);
ste_attr.send_attr.user_data = dep_wqe->user_data;
ste_attr.send_attr.rule = dep_wqe->rule;
ste_attr.rtc_0 = dep_wqe->rtc_0;
ste_attr.rtc_1 = dep_wqe->rtc_1;
ste_attr.retry_rtc_0 = dep_wqe->retry_rtc_0;
ste_attr.retry_rtc_1 = dep_wqe->retry_rtc_1;
ste_attr.used_id_rtc_0 = &dep_wqe->rule->rtc_0;
ste_attr.used_id_rtc_1 = &dep_wqe->rule->rtc_1;
ste_attr.wqe_ctrl = &dep_wqe->wqe_ctrl;
ste_attr.wqe_data = &dep_wqe->wqe_data;
mlx5dr_send_ste(queue, &ste_attr);
/* Fencing is done only on the first WQE */
ste_attr.send_attr.fence = 0;
}
}
struct mlx5dr_send_engine_post_ctrl
mlx5dr_send_engine_post_start(struct mlx5dr_send_engine *queue)
{
struct mlx5dr_send_engine_post_ctrl ctrl;
ctrl.queue = queue;
/* Currently only one send ring is supported */
ctrl.send_ring = &queue->send_ring[0];
ctrl.num_wqebbs = 0;
return ctrl;
}
void mlx5dr_send_engine_post_req_wqe(struct mlx5dr_send_engine_post_ctrl *ctrl,
char **buf, size_t *len)
{
struct mlx5dr_send_ring_sq *send_sq = &ctrl->send_ring->send_sq;
unsigned int idx;
idx = (send_sq->cur_post + ctrl->num_wqebbs) & send_sq->buf_mask;
*buf = send_sq->buf + (idx << MLX5_SEND_WQE_SHIFT);
*len = MLX5_SEND_WQE_BB;
if (!ctrl->num_wqebbs) {
*buf += sizeof(struct mlx5dr_wqe_ctrl_seg);
*len -= sizeof(struct mlx5dr_wqe_ctrl_seg);
}
ctrl->num_wqebbs++;
}
static void mlx5dr_send_engine_post_ring(struct mlx5dr_send_ring_sq *sq,
struct mlx5dv_devx_uar *uar,
struct mlx5dr_wqe_ctrl_seg *wqe_ctrl)
{
rte_compiler_barrier();
sq->db[MLX5_SND_DBR] = rte_cpu_to_be_32(sq->cur_post);
rte_wmb();
mlx5dr_uar_write64_relaxed(*((uint64_t *)wqe_ctrl), uar->reg_addr);
rte_wmb();
}
static void
mlx5dr_send_wqe_set_tag(struct mlx5dr_wqe_gta_data_seg_ste *wqe_data,
struct mlx5dr_rule_match_tag *tag,
bool is_jumbo)
{
if (is_jumbo) {
/* Clear previous possibly dirty control */
memset(wqe_data, 0, MLX5DR_STE_CTRL_SZ);
memcpy(wqe_data->action, tag->jumbo, MLX5DR_JUMBO_TAG_SZ);
} else {
/* Clear previous possibly dirty control and actions */
memset(wqe_data, 0, MLX5DR_STE_CTRL_SZ + MLX5DR_ACTIONS_SZ);
memcpy(wqe_data->tag, tag->match, MLX5DR_MATCH_TAG_SZ);
}
}
void mlx5dr_send_engine_post_end(struct mlx5dr_send_engine_post_ctrl *ctrl,
struct mlx5dr_send_engine_post_attr *attr)
{
struct mlx5dr_wqe_ctrl_seg *wqe_ctrl;
struct mlx5dr_send_ring_sq *sq;
uint32_t flags = 0;
unsigned int idx;
sq = &ctrl->send_ring->send_sq;
idx = sq->cur_post & sq->buf_mask;
sq->last_idx = idx;
wqe_ctrl = (void *)(sq->buf + (idx << MLX5_SEND_WQE_SHIFT));
wqe_ctrl->opmod_idx_opcode =
rte_cpu_to_be_32((attr->opmod << 24) |
((sq->cur_post & 0xffff) << 8) |
attr->opcode);
wqe_ctrl->qpn_ds =
rte_cpu_to_be_32((attr->len + sizeof(struct mlx5dr_wqe_ctrl_seg)) / 16 |
sq->sqn << 8);
wqe_ctrl->imm = rte_cpu_to_be_32(attr->id);
flags |= attr->notify_hw ? MLX5_WQE_CTRL_CQ_UPDATE : 0;
flags |= attr->fence ? MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE : 0;
wqe_ctrl->flags = rte_cpu_to_be_32(flags);
sq->wr_priv[idx].id = attr->id;
sq->wr_priv[idx].retry_id = attr->retry_id;
sq->wr_priv[idx].rule = attr->rule;
sq->wr_priv[idx].user_data = attr->user_data;
sq->wr_priv[idx].num_wqebbs = ctrl->num_wqebbs;
if (attr->rule) {
sq->wr_priv[idx].rule->pending_wqes++;
sq->wr_priv[idx].used_id = attr->used_id;
}
sq->cur_post += ctrl->num_wqebbs;
if (attr->notify_hw)
mlx5dr_send_engine_post_ring(sq, ctrl->queue->uar, wqe_ctrl);
}
static void mlx5dr_send_wqe(struct mlx5dr_send_engine *queue,
struct mlx5dr_send_engine_post_attr *send_attr,
struct mlx5dr_wqe_gta_ctrl_seg *send_wqe_ctrl,
void *send_wqe_data,
void *send_wqe_tag,
bool is_jumbo,
uint8_t gta_opcode,
uint32_t direct_index)
{
struct mlx5dr_wqe_gta_data_seg_ste *wqe_data;
struct mlx5dr_wqe_gta_ctrl_seg *wqe_ctrl;
struct mlx5dr_send_engine_post_ctrl ctrl;
size_t wqe_len;
ctrl = mlx5dr_send_engine_post_start(queue);
mlx5dr_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len);
mlx5dr_send_engine_post_req_wqe(&ctrl, (void *)&wqe_data, &wqe_len);
wqe_ctrl->op_dirix = htobe32(gta_opcode << 28 | direct_index);
memcpy(wqe_ctrl->stc_ix, send_wqe_ctrl->stc_ix, sizeof(send_wqe_ctrl->stc_ix));
if (send_wqe_data)
memcpy(wqe_data, send_wqe_data, sizeof(*wqe_data));
else
mlx5dr_send_wqe_set_tag(wqe_data, send_wqe_tag, is_jumbo);
mlx5dr_send_engine_post_end(&ctrl, send_attr);
}
void mlx5dr_send_ste(struct mlx5dr_send_engine *queue,
struct mlx5dr_send_ste_attr *ste_attr)
{
struct mlx5dr_send_engine_post_attr *send_attr = &ste_attr->send_attr;
uint8_t notify_hw = send_attr->notify_hw;
uint8_t fence = send_attr->fence;
if (ste_attr->rtc_1) {
send_attr->id = ste_attr->rtc_1;
send_attr->used_id = ste_attr->used_id_rtc_1;
send_attr->retry_id = ste_attr->retry_rtc_1;
send_attr->fence = fence;
send_attr->notify_hw = notify_hw && !ste_attr->rtc_0;
mlx5dr_send_wqe(queue, send_attr,
ste_attr->wqe_ctrl,
ste_attr->wqe_data,
ste_attr->wqe_tag,
ste_attr->wqe_tag_is_jumbo,
ste_attr->gta_opcode,
ste_attr->direct_index);
}
if (ste_attr->rtc_0) {
send_attr->id = ste_attr->rtc_0;
send_attr->used_id = ste_attr->used_id_rtc_0;
send_attr->retry_id = ste_attr->retry_rtc_0;
send_attr->fence = fence && !ste_attr->rtc_1;
send_attr->notify_hw = notify_hw;
mlx5dr_send_wqe(queue, send_attr,
ste_attr->wqe_ctrl,
ste_attr->wqe_data,
ste_attr->wqe_tag,
ste_attr->wqe_tag_is_jumbo,
ste_attr->gta_opcode,
ste_attr->direct_index);
}
/* Restore to ortginal requested values */
send_attr->notify_hw = notify_hw;
send_attr->fence = fence;
}
static void mlx5dr_send_engine_retry_post_send(struct mlx5dr_send_engine *queue,
struct mlx5dr_send_ring_priv *priv,
uint16_t wqe_cnt)
{
struct mlx5dr_send_engine_post_attr send_attr = {0};
struct mlx5dr_wqe_gta_data_seg_ste *wqe_data;
struct mlx5dr_wqe_gta_ctrl_seg *wqe_ctrl;
struct mlx5dr_send_engine_post_ctrl ctrl;
struct mlx5dr_send_ring_sq *send_sq;
unsigned int idx;
size_t wqe_len;
char *p;
send_attr.rule = priv->rule;
send_attr.opcode = MLX5DR_WQE_OPCODE_TBL_ACCESS;
send_attr.opmod = MLX5DR_WQE_GTA_OPMOD_STE;
send_attr.len = MLX5_SEND_WQE_BB * 2 - sizeof(struct mlx5dr_wqe_ctrl_seg);
send_attr.notify_hw = 1;
send_attr.fence = 0;
send_attr.user_data = priv->user_data;
send_attr.id = priv->retry_id;
send_attr.used_id = priv->used_id;
ctrl = mlx5dr_send_engine_post_start(queue);
mlx5dr_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len);
mlx5dr_send_engine_post_req_wqe(&ctrl, (void *)&wqe_data, &wqe_len);
send_sq = &ctrl.send_ring->send_sq;
idx = wqe_cnt & send_sq->buf_mask;
p = send_sq->buf + (idx << MLX5_SEND_WQE_SHIFT);
/* Copy old gta ctrl */
memcpy(wqe_ctrl, p + sizeof(struct mlx5dr_wqe_ctrl_seg),
MLX5_SEND_WQE_BB - sizeof(struct mlx5dr_wqe_ctrl_seg));
idx = (wqe_cnt + 1) & send_sq->buf_mask;
p = send_sq->buf + (idx << MLX5_SEND_WQE_SHIFT);
/* Copy old gta data */
memcpy(wqe_data, p, MLX5_SEND_WQE_BB);
mlx5dr_send_engine_post_end(&ctrl, &send_attr);
}
void mlx5dr_send_engine_flush_queue(struct mlx5dr_send_engine *queue)
{
struct mlx5dr_send_ring_sq *sq = &queue->send_ring[0].send_sq;
struct mlx5dr_wqe_ctrl_seg *wqe_ctrl;
wqe_ctrl = (void *)(sq->buf + (sq->last_idx << MLX5_SEND_WQE_SHIFT));
wqe_ctrl->flags |= rte_cpu_to_be_32(MLX5_WQE_CTRL_CQ_UPDATE);
mlx5dr_send_engine_post_ring(sq, queue->uar, wqe_ctrl);
}
static void mlx5dr_send_engine_update_rule(struct mlx5dr_send_engine *queue,
struct mlx5dr_send_ring_priv *priv,
uint16_t wqe_cnt,
enum rte_flow_op_status *status)
{
priv->rule->pending_wqes--;
if (*status == RTE_FLOW_OP_ERROR) {
if (priv->retry_id) {
mlx5dr_send_engine_retry_post_send(queue, priv, wqe_cnt);
return;
}
/* Some part of the rule failed */
priv->rule->status = MLX5DR_RULE_STATUS_FAILING;
*priv->used_id = 0;
} else {
*priv->used_id = priv->id;
}
/* Update rule status for the last completion */
if (!priv->rule->pending_wqes) {
if (unlikely(priv->rule->status == MLX5DR_RULE_STATUS_FAILING)) {
/* Rule completely failed and doesn't require cleanup */
if (!priv->rule->rtc_0 && !priv->rule->rtc_1)
priv->rule->status = MLX5DR_RULE_STATUS_FAILED;
*status = RTE_FLOW_OP_ERROR;
} else {
/* Increase the status, this only works on good flow as the enum
* is arrange it away creating -> created -> deleting -> deleted
*/
priv->rule->status++;
*status = RTE_FLOW_OP_SUCCESS;
/* Rule was deleted now we can safely release action STEs */
if (priv->rule->status == MLX5DR_RULE_STATUS_DELETED)
mlx5dr_rule_free_action_ste_idx(priv->rule);
}
}
}
static void mlx5dr_send_engine_update(struct mlx5dr_send_engine *queue,
struct mlx5_cqe64 *cqe,
struct mlx5dr_send_ring_priv *priv,
struct rte_flow_op_result res[],
int64_t *i,
uint32_t res_nb,
uint16_t wqe_cnt)
{
enum rte_flow_op_status status;
if (!cqe || (likely(rte_be_to_cpu_32(cqe->byte_cnt) >> 31 == 0) &&
likely(mlx5dv_get_cqe_opcode(cqe) == MLX5_CQE_REQ))) {
status = RTE_FLOW_OP_SUCCESS;
} else {
status = RTE_FLOW_OP_ERROR;
}
if (priv->user_data) {
if (priv->rule) {
mlx5dr_send_engine_update_rule(queue, priv, wqe_cnt, &status);
/* Completion is provided on the last rule WQE */
if (priv->rule->pending_wqes)
return;
}
if (*i < res_nb) {
res[*i].user_data = priv->user_data;
res[*i].status = status;
(*i)++;
mlx5dr_send_engine_dec_rule(queue);
} else {
mlx5dr_send_engine_gen_comp(queue, priv->user_data, status);
}
}
}
static void mlx5dr_send_engine_poll_cq(struct mlx5dr_send_engine *queue,
struct mlx5dr_send_ring *send_ring,
struct rte_flow_op_result res[],
int64_t *i,
uint32_t res_nb)
{
struct mlx5dr_send_ring_cq *cq = &send_ring->send_cq;
struct mlx5dr_send_ring_sq *sq = &send_ring->send_sq;
uint32_t cq_idx = cq->cons_index & cq->ncqe_mask;
struct mlx5dr_send_ring_priv *priv;
struct mlx5_cqe64 *cqe;
uint32_t offset_cqe64;
uint8_t cqe_opcode;
uint8_t cqe_owner;
uint16_t wqe_cnt;
uint8_t sw_own;
offset_cqe64 = RTE_CACHE_LINE_SIZE - sizeof(struct mlx5_cqe64);
cqe = (void *)(cq->buf + (cq_idx << cq->cqe_log_sz) + offset_cqe64);
sw_own = (cq->cons_index & cq->ncqe) ? 1 : 0;
cqe_opcode = mlx5dv_get_cqe_opcode(cqe);
cqe_owner = mlx5dv_get_cqe_owner(cqe);
if (cqe_opcode == MLX5_CQE_INVALID ||
cqe_owner != sw_own)
return;
if (unlikely(mlx5dv_get_cqe_opcode(cqe) != MLX5_CQE_REQ))
queue->err = true;
rte_io_rmb();
wqe_cnt = be16toh(cqe->wqe_counter) & sq->buf_mask;
while (cq->poll_wqe != wqe_cnt) {
priv = &sq->wr_priv[cq->poll_wqe];
mlx5dr_send_engine_update(queue, NULL, priv, res, i, res_nb, 0);
cq->poll_wqe = (cq->poll_wqe + priv->num_wqebbs) & sq->buf_mask;
}
priv = &sq->wr_priv[wqe_cnt];
cq->poll_wqe = (wqe_cnt + priv->num_wqebbs) & sq->buf_mask;
mlx5dr_send_engine_update(queue, cqe, priv, res, i, res_nb, wqe_cnt);
cq->cons_index++;
}
static void mlx5dr_send_engine_poll_cqs(struct mlx5dr_send_engine *queue,
struct rte_flow_op_result res[],
int64_t *polled,
uint32_t res_nb)
{
int j;
for (j = 0; j < MLX5DR_NUM_SEND_RINGS; j++) {
mlx5dr_send_engine_poll_cq(queue, &queue->send_ring[j],
res, polled, res_nb);
*queue->send_ring[j].send_cq.db =
htobe32(queue->send_ring[j].send_cq.cons_index & 0xffffff);
}
}
static void mlx5dr_send_engine_poll_list(struct mlx5dr_send_engine *queue,
struct rte_flow_op_result res[],
int64_t *polled,
uint32_t res_nb)
{
struct mlx5dr_completed_poll *comp = &queue->completed;
while (comp->ci != comp->pi) {
if (*polled < res_nb) {
res[*polled].status =
comp->entries[comp->ci].status;
res[*polled].user_data =
comp->entries[comp->ci].user_data;
(*polled)++;
comp->ci = (comp->ci + 1) & comp->mask;
mlx5dr_send_engine_dec_rule(queue);
} else {
return;
}
}
}
static int mlx5dr_send_engine_poll(struct mlx5dr_send_engine *queue,
struct rte_flow_op_result res[],
uint32_t res_nb)
{
int64_t polled = 0;
mlx5dr_send_engine_poll_list(queue, res, &polled, res_nb);
if (polled >= res_nb)
return polled;
mlx5dr_send_engine_poll_cqs(queue, res, &polled, res_nb);
return polled;
}
int mlx5dr_send_queue_poll(struct mlx5dr_context *ctx,
uint16_t queue_id,
struct rte_flow_op_result res[],
uint32_t res_nb)
{
return mlx5dr_send_engine_poll(&ctx->send_queue[queue_id],
res, res_nb);
}
static int mlx5dr_send_ring_create_sq_obj(struct mlx5dr_context *ctx,
struct mlx5dr_send_engine *queue,
struct mlx5dr_send_ring_sq *sq,
struct mlx5dr_send_ring_cq *cq,
size_t log_wq_sz)
{
struct mlx5dr_cmd_sq_create_attr attr = {0};
int err;
attr.cqn = cq->cqn;
attr.pdn = ctx->pd_num;
attr.page_id = queue->uar->page_id;
attr.dbr_id = sq->db_umem->umem_id;
attr.wq_id = sq->buf_umem->umem_id;
attr.log_wq_sz = log_wq_sz;
if (ctx->caps->sq_ts_format == MLX5_HCA_CAP_TIMESTAMP_FORMAT_FR)
attr.ts_format = MLX5_QPC_TIMESTAMP_FORMAT_FREE_RUNNING;
else
attr.ts_format = MLX5_QPC_TIMESTAMP_FORMAT_DEFAULT;
sq->obj = mlx5dr_cmd_sq_create(ctx->ibv_ctx, &attr);
if (!sq->obj)
return rte_errno;
sq->sqn = sq->obj->id;
err = mlx5dr_cmd_sq_modify_rdy(sq->obj);
if (err)
goto free_sq;
return 0;
free_sq:
mlx5dr_cmd_destroy_obj(sq->obj);
return err;
}
static inline unsigned long align(unsigned long val, unsigned long align)
{
return (val + align - 1) & ~(align - 1);
}
static int mlx5dr_send_ring_open_sq(struct mlx5dr_context *ctx,
struct mlx5dr_send_engine *queue,
struct mlx5dr_send_ring_sq *sq,
struct mlx5dr_send_ring_cq *cq)
{
size_t sq_log_buf_sz;
size_t buf_aligned;
size_t sq_buf_sz;
size_t page_size;
size_t buf_sz;
int err;
buf_sz = queue->num_entries * MAX_WQES_PER_RULE;
sq_log_buf_sz = log2above(buf_sz);
sq_buf_sz = 1 << (sq_log_buf_sz + log2above(MLX5_SEND_WQE_BB));
sq->reg_addr = queue->uar->reg_addr;
page_size = sysconf(_SC_PAGESIZE);
buf_aligned = align(sq_buf_sz, page_size);
err = posix_memalign((void **)&sq->buf, page_size, buf_aligned);
if (err) {
rte_errno = ENOMEM;
return err;
}
memset(sq->buf, 0, buf_aligned);
err = posix_memalign((void **)&sq->db, 8, 8);
if (err)
goto free_buf;
sq->buf_umem = mlx5_glue->devx_umem_reg(ctx->ibv_ctx, sq->buf, sq_buf_sz, 0);
if (!sq->buf_umem) {
err = errno;
goto free_db;
}
sq->db_umem = mlx5_glue->devx_umem_reg(ctx->ibv_ctx, sq->db, 8, 0);
if (!sq->db_umem) {
err = errno;
goto free_buf_umem;
}
err = mlx5dr_send_ring_create_sq_obj(ctx, queue, sq, cq, sq_log_buf_sz);
if (err)
goto free_db_umem;
sq->wr_priv = simple_malloc(sizeof(*sq->wr_priv) * buf_sz);
if (!sq->wr_priv) {
err = ENOMEM;
goto destroy_sq_obj;
}
sq->dep_wqe = simple_calloc(queue->num_entries, sizeof(*sq->dep_wqe));
if (!sq->dep_wqe) {
err = ENOMEM;
goto destroy_wr_priv;
}
sq->buf_mask = buf_sz - 1;
return 0;
destroy_wr_priv:
simple_free(sq->wr_priv);
destroy_sq_obj:
mlx5dr_cmd_destroy_obj(sq->obj);
free_db_umem:
mlx5_glue->devx_umem_dereg(sq->db_umem);
free_buf_umem:
mlx5_glue->devx_umem_dereg(sq->buf_umem);
free_db:
free(sq->db);
free_buf:
free(sq->buf);
rte_errno = err;
return err;
}
static void mlx5dr_send_ring_close_sq(struct mlx5dr_send_ring_sq *sq)
{
simple_free(sq->dep_wqe);
mlx5dr_cmd_destroy_obj(sq->obj);
mlx5_glue->devx_umem_dereg(sq->db_umem);
mlx5_glue->devx_umem_dereg(sq->buf_umem);
simple_free(sq->wr_priv);
free(sq->db);
free(sq->buf);
}
static int mlx5dr_send_ring_open_cq(struct mlx5dr_context *ctx,
struct mlx5dr_send_engine *queue,
struct mlx5dr_send_ring_cq *cq)
{
struct mlx5dv_cq mlx5_cq = {0};
struct mlx5dv_obj obj;
struct ibv_cq *ibv_cq;
size_t cq_size;
int err;
cq_size = queue->num_entries;
ibv_cq = mlx5_glue->create_cq(ctx->ibv_ctx, cq_size, NULL, NULL, 0);
if (!ibv_cq) {
DR_LOG(ERR, "Failed to create CQ");
rte_errno = errno;
return rte_errno;
}
obj.cq.in = ibv_cq;
obj.cq.out = &mlx5_cq;
err = mlx5_glue->dv_init_obj(&obj, MLX5DV_OBJ_CQ);
if (err) {
err = errno;
goto close_cq;
}
cq->buf = mlx5_cq.buf;
cq->db = mlx5_cq.dbrec;
cq->ncqe = mlx5_cq.cqe_cnt;
cq->cqe_sz = mlx5_cq.cqe_size;
cq->cqe_log_sz = log2above(cq->cqe_sz);
cq->ncqe_mask = cq->ncqe - 1;
cq->buf_sz = cq->cqe_sz * cq->ncqe;
cq->cqn = mlx5_cq.cqn;
cq->ibv_cq = ibv_cq;
return 0;
close_cq:
mlx5_glue->destroy_cq(ibv_cq);
rte_errno = err;
return err;
}
static void mlx5dr_send_ring_close_cq(struct mlx5dr_send_ring_cq *cq)
{
mlx5_glue->destroy_cq(cq->ibv_cq);
}
static void mlx5dr_send_ring_close(struct mlx5dr_send_ring *ring)
{
mlx5dr_send_ring_close_sq(&ring->send_sq);
mlx5dr_send_ring_close_cq(&ring->send_cq);
}
static int mlx5dr_send_ring_open(struct mlx5dr_context *ctx,
struct mlx5dr_send_engine *queue,
struct mlx5dr_send_ring *ring)
{
int err;
err = mlx5dr_send_ring_open_cq(ctx, queue, &ring->send_cq);
if (err)
return err;
err = mlx5dr_send_ring_open_sq(ctx, queue, &ring->send_sq, &ring->send_cq);
if (err)
goto close_cq;
return err;
close_cq:
mlx5dr_send_ring_close_cq(&ring->send_cq);
return err;
}
static void __mlx5dr_send_rings_close(struct mlx5dr_send_engine *queue,
uint16_t i)
{
while (i--)
mlx5dr_send_ring_close(&queue->send_ring[i]);
}
static void mlx5dr_send_rings_close(struct mlx5dr_send_engine *queue)
{
__mlx5dr_send_rings_close(queue, queue->rings);
}
static int mlx5dr_send_rings_open(struct mlx5dr_context *ctx,
struct mlx5dr_send_engine *queue)
{
uint16_t i;
int err;
for (i = 0; i < queue->rings; i++) {
err = mlx5dr_send_ring_open(ctx, queue, &queue->send_ring[i]);
if (err)
goto free_rings;
}
return 0;
free_rings:
__mlx5dr_send_rings_close(queue, i);
return err;
}
void mlx5dr_send_queue_close(struct mlx5dr_send_engine *queue)
{
mlx5dr_send_rings_close(queue);
simple_free(queue->completed.entries);
mlx5_glue->devx_free_uar(queue->uar);
}
int mlx5dr_send_queue_open(struct mlx5dr_context *ctx,
struct mlx5dr_send_engine *queue,
uint16_t queue_size)
{
struct mlx5dv_devx_uar *uar;
int err;
#ifdef MLX5DV_UAR_ALLOC_TYPE_NC
uar = mlx5_glue->devx_alloc_uar(ctx->ibv_ctx, MLX5_IB_UAPI_UAR_ALLOC_TYPE_NC);
if (!uar) {
rte_errno = errno;
return rte_errno;
}
#else
uar = NULL;
rte_errno = ENOTSUP;
return rte_errno;
#endif
queue->uar = uar;
queue->rings = MLX5DR_NUM_SEND_RINGS;
queue->num_entries = roundup_pow_of_two(queue_size);
queue->used_entries = 0;
queue->th_entries = queue->num_entries;
queue->completed.entries = simple_calloc(queue->num_entries,
sizeof(queue->completed.entries[0]));
if (!queue->completed.entries) {
rte_errno = ENOMEM;
goto free_uar;
}
queue->completed.pi = 0;
queue->completed.ci = 0;
queue->completed.mask = queue->num_entries - 1;
err = mlx5dr_send_rings_open(ctx, queue);
if (err)
goto free_completed_entries;
return 0;
free_completed_entries:
simple_free(queue->completed.entries);
free_uar:
mlx5_glue->devx_free_uar(uar);
return rte_errno;
}
static void __mlx5dr_send_queues_close(struct mlx5dr_context *ctx, uint16_t queues)
{
struct mlx5dr_send_engine *queue;
while (queues--) {
queue = &ctx->send_queue[queues];
mlx5dr_send_queue_close(queue);
}
}
void mlx5dr_send_queues_close(struct mlx5dr_context *ctx)
{
__mlx5dr_send_queues_close(ctx, ctx->queues);
simple_free(ctx->send_queue);
}
int mlx5dr_send_queues_open(struct mlx5dr_context *ctx,
uint16_t queues,
uint16_t queue_size)
{
int err = 0;
uint32_t i;
/* Open one extra queue for control path */
ctx->queues = queues + 1;
ctx->send_queue = simple_calloc(ctx->queues, sizeof(*ctx->send_queue));
if (!ctx->send_queue) {
rte_errno = ENOMEM;
return rte_errno;
}
for (i = 0; i < ctx->queues; i++) {
err = mlx5dr_send_queue_open(ctx, &ctx->send_queue[i], queue_size);
if (err)
goto close_send_queues;
}
return 0;
close_send_queues:
__mlx5dr_send_queues_close(ctx, i);
simple_free(ctx->send_queue);
return err;
}
int mlx5dr_send_queue_action(struct mlx5dr_context *ctx,
uint16_t queue_id,
uint32_t actions)
{
struct mlx5dr_send_ring_sq *send_sq;
struct mlx5dr_send_engine *queue;
queue = &ctx->send_queue[queue_id];
send_sq = &queue->send_ring->send_sq;
if (actions == MLX5DR_SEND_QUEUE_ACTION_DRAIN) {
if (send_sq->head_dep_idx != send_sq->tail_dep_idx)
/* Send dependent WQEs to drain the queue */
mlx5dr_send_all_dep_wqe(queue);
else
/* Signal on the last posted WQE */
mlx5dr_send_engine_flush_queue(queue);
} else {
rte_errno = EINVAL;
return -rte_errno;
}
return 0;
}