Blame src/vma/ib/mlx5/ib_mlx5.cpp

Packit 6d2c1b
/*
Packit 6d2c1b
 * Copyright (c) 2001-2020 Mellanox Technologies, Ltd. All rights reserved.
Packit 6d2c1b
 *
Packit 6d2c1b
 * This software is available to you under a choice of one of two
Packit 6d2c1b
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit 6d2c1b
 * General Public License (GPL) Version 2, available from the file
Packit 6d2c1b
 * COPYING in the main directory of this source tree, or the
Packit 6d2c1b
 * BSD license below:
Packit 6d2c1b
 *
Packit 6d2c1b
 *     Redistribution and use in source and binary forms, with or
Packit 6d2c1b
 *     without modification, are permitted provided that the following
Packit 6d2c1b
 *     conditions are met:
Packit 6d2c1b
 *
Packit 6d2c1b
 *      - Redistributions of source code must retain the above
Packit 6d2c1b
 *        copyright notice, this list of conditions and the following
Packit 6d2c1b
 *        disclaimer.
Packit 6d2c1b
 *
Packit 6d2c1b
 *      - Redistributions in binary form must reproduce the above
Packit 6d2c1b
 *        copyright notice, this list of conditions and the following
Packit 6d2c1b
 *        disclaimer in the documentation and/or other materials
Packit 6d2c1b
 *        provided with the distribution.
Packit 6d2c1b
 *
Packit 6d2c1b
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit 6d2c1b
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 6d2c1b
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit 6d2c1b
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit 6d2c1b
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit 6d2c1b
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit 6d2c1b
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit 6d2c1b
 * SOFTWARE.
Packit 6d2c1b
 */
Packit 6d2c1b
Packit 6d2c1b
#ifdef HAVE_CONFIG_H
Packit 6d2c1b
#include "config.h"
Packit 6d2c1b
#endif
Packit 6d2c1b
#include "util/valgrind.h"
Packit 6d2c1b
#if defined(DEFINED_DIRECT_VERBS)
Packit 6d2c1b
Packit 6d2c1b
#include "vma/util/valgrind.h"
Packit 6d2c1b
#include "vma/util/utils.h"
Packit 6d2c1b
#include "vma/ib/mlx5/ib_mlx5.h"
Packit 6d2c1b
Packit 6d2c1b
Packit 6d2c1b
int vma_ib_mlx5_get_qp(struct ibv_qp *qp, vma_ib_mlx5_qp_t *mlx5_qp, uint32_t flags)
Packit 6d2c1b
{
Packit 6d2c1b
	int ret = 0;
Packit 6d2c1b
	struct mlx5dv_obj obj;
Packit 6d2c1b
	struct mlx5dv_qp dqp;
Packit 6d2c1b
	enum ibv_qp_attr_mask attr_mask = IBV_QP_CAP;
Packit 6d2c1b
	struct ibv_qp_attr tmp_ibv_qp_attr;
Packit 6d2c1b
	struct ibv_qp_init_attr tmp_ibv_qp_init_attr;
Packit 6d2c1b
Packit 6d2c1b
	memset(&obj, 0, sizeof(obj));
Packit 6d2c1b
	memset(&dqp, 0, sizeof(dqp));
Packit 6d2c1b
Packit 6d2c1b
	obj.qp.in = qp;
Packit 6d2c1b
	obj.qp.out = &dq;;
Packit 6d2c1b
	ret = vma_ib_mlx5dv_init_obj(&obj, MLX5DV_OBJ_QP);
Packit 6d2c1b
	if (ret != 0) {
Packit 6d2c1b
		goto out;
Packit 6d2c1b
	}
Packit 6d2c1b
	VALGRIND_MAKE_MEM_DEFINED(&dqp, sizeof(dqp));
Packit 6d2c1b
	mlx5_qp->qp           = qp;
Packit 6d2c1b
	mlx5_qp->qpn          = qp->qp_num;
Packit 6d2c1b
	mlx5_qp->flags        = flags;
Packit 6d2c1b
	mlx5_qp->sq.dbrec     = &dqp.dbrec[MLX5_SND_DBR];
Packit 6d2c1b
	mlx5_qp->sq.buf       = dqp.sq.buf;
Packit 6d2c1b
	mlx5_qp->sq.wqe_cnt   = dqp.sq.wqe_cnt;
Packit 6d2c1b
	mlx5_qp->sq.stride    = dqp.sq.stride;
Packit 6d2c1b
	mlx5_qp->rq.dbrec     = &dqp.dbrec[MLX5_RCV_DBR];
Packit 6d2c1b
	mlx5_qp->rq.buf       = dqp.rq.buf;
Packit 6d2c1b
	mlx5_qp->rq.wqe_cnt   = dqp.rq.wqe_cnt;
Packit 6d2c1b
	mlx5_qp->rq.stride    = dqp.rq.stride;
Packit 6d2c1b
	mlx5_qp->rq.wqe_shift = ilog_2(dqp.rq.stride);
Packit 6d2c1b
	mlx5_qp->rq.head      = 0;
Packit 6d2c1b
	mlx5_qp->rq.tail      = 0;
Packit 6d2c1b
	mlx5_qp->bf.reg       = dqp.bf.reg;
Packit 6d2c1b
	mlx5_qp->bf.size      = dqp.bf.size;
Packit 6d2c1b
	mlx5_qp->bf.offset    = 0;
Packit 6d2c1b
Packit 6d2c1b
	ret = ibv_query_qp(qp, &tmp_ibv_qp_attr, attr_mask, &tmp_ibv_qp_init_attr);
Packit 6d2c1b
	if (ret != 0) {
Packit 6d2c1b
		goto out;
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	VALGRIND_MAKE_MEM_DEFINED(&tmp_ibv_qp_attr, sizeof(tmp_ibv_qp_attr));
Packit 6d2c1b
	mlx5_qp->cap.max_send_wr = tmp_ibv_qp_attr.cap.max_send_wr;
Packit 6d2c1b
	mlx5_qp->cap.max_recv_wr = tmp_ibv_qp_attr.cap.max_recv_wr;
Packit 6d2c1b
	mlx5_qp->cap.max_send_sge = tmp_ibv_qp_attr.cap.max_send_sge;
Packit 6d2c1b
	mlx5_qp->cap.max_recv_sge = tmp_ibv_qp_attr.cap.max_recv_sge;
Packit 6d2c1b
	mlx5_qp->cap.max_inline_data = tmp_ibv_qp_attr.cap.max_inline_data;
Packit 6d2c1b
Packit 6d2c1b
out:
Packit 6d2c1b
    return ret;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
int vma_ib_mlx5_get_cq(struct ibv_cq *cq, vma_ib_mlx5_cq_t *mlx5_cq)
Packit 6d2c1b
{
Packit 6d2c1b
	int ret = 0;
Packit 6d2c1b
	struct mlx5dv_obj obj;
Packit 6d2c1b
	struct mlx5dv_cq dcq;
Packit 6d2c1b
Packit 6d2c1b
	/* Initialization of cq can be done once to protect
Packit 6d2c1b
	 * internal data from corruption.
Packit 6d2c1b
	 * cq field is used to detect one time initialization
Packit 6d2c1b
	 * For example: this function can be called when QP is moved
Packit 6d2c1b
	 * from ERROR state to RESET so cq_ci or cq_sn should not be
Packit 6d2c1b
	 * updated
Packit 6d2c1b
	 */
Packit 6d2c1b
	if (mlx5_cq == NULL || mlx5_cq->cq == cq) {
Packit 6d2c1b
		return 0;
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	memset(&obj, 0, sizeof(obj));
Packit 6d2c1b
	memset(&dcq, 0, sizeof(dcq));
Packit 6d2c1b
Packit 6d2c1b
	obj.cq.in = cq;
Packit 6d2c1b
	obj.cq.out = &dcq;
Packit 6d2c1b
	ret = vma_ib_mlx5dv_init_obj(&obj, MLX5DV_OBJ_CQ);
Packit 6d2c1b
	if (ret != 0) {
Packit 6d2c1b
		return ret;
Packit 6d2c1b
	}
Packit 6d2c1b
	VALGRIND_MAKE_MEM_DEFINED(&dcq, sizeof(dcq));
Packit 6d2c1b
	mlx5_cq->cq           = cq;
Packit 6d2c1b
	mlx5_cq->cq_num       = dcq.cqn;
Packit 6d2c1b
	mlx5_cq->cq_ci        = 0;
Packit 6d2c1b
	mlx5_cq->cq_sn        = 0;
Packit 6d2c1b
	mlx5_cq->cqe_count    = dcq.cqe_cnt;
Packit 6d2c1b
	mlx5_cq->cqe_size     = dcq.cqe_size;
Packit 6d2c1b
	mlx5_cq->cqe_size_log = ilog_2(dcq.cqe_size);
Packit 6d2c1b
	mlx5_cq->dbrec        = dcq.dbrec;
Packit 6d2c1b
	mlx5_cq->uar          = dcq.cq_uar;
Packit 6d2c1b
Packit 6d2c1b
	/* Move buffer forward for 128b CQE, so we would get pointer to the 2nd
Packit 6d2c1b
	 * 64b when polling.
Packit 6d2c1b
	 */
Packit 6d2c1b
	mlx5_cq->cq_buf       = (uint8_t *)dcq.buf + dcq.cqe_size - sizeof(struct mlx5_cqe64);
Packit 6d2c1b
Packit 6d2c1b
    return 0;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
int vma_ib_mlx5_post_recv(vma_ib_mlx5_qp_t *mlx5_qp,
Packit 6d2c1b
		struct ibv_recv_wr *wr, struct ibv_recv_wr **bad_wr)
Packit 6d2c1b
{
Packit 6d2c1b
	struct mlx5_wqe_data_seg *scat;
Packit 6d2c1b
	int err = 0;
Packit 6d2c1b
	int nreq;
Packit 6d2c1b
	int ind;
Packit 6d2c1b
	int i, j;
Packit 6d2c1b
Packit 6d2c1b
	ind = mlx5_qp->rq.head & (mlx5_qp->rq.wqe_cnt - 1);
Packit 6d2c1b
	*bad_wr = NULL;
Packit 6d2c1b
Packit 6d2c1b
	for (nreq = 0; wr; ++nreq, wr = wr->next) {
Packit 6d2c1b
		if (unlikely((int)mlx5_qp->rq.head - (int)mlx5_qp->rq.tail + nreq >= (int)mlx5_qp->cap.max_recv_wr)) {
Packit 6d2c1b
			errno = ENOMEM;
Packit 6d2c1b
			err = -errno;
Packit 6d2c1b
			*bad_wr = wr;
Packit 6d2c1b
			goto out;
Packit 6d2c1b
		}
Packit 6d2c1b
Packit 6d2c1b
		if (unlikely(wr->num_sge > (int)mlx5_qp->cap.max_recv_sge)) {
Packit 6d2c1b
			errno = EINVAL;
Packit 6d2c1b
			err = -errno;
Packit 6d2c1b
			*bad_wr = wr;
Packit 6d2c1b
			goto out;
Packit 6d2c1b
		}
Packit 6d2c1b
Packit 6d2c1b
		scat = (struct mlx5_wqe_data_seg *)((uint8_t *)mlx5_qp->rq.buf + (ind << mlx5_qp->rq.wqe_shift));
Packit 6d2c1b
Packit 6d2c1b
		for (i = 0, j = 0; i < wr->num_sge; ++i) {
Packit 6d2c1b
			if (unlikely(!wr->sg_list[i].length)) continue;
Packit 6d2c1b
Packit 6d2c1b
			scat[j].byte_count = htonl(wr->sg_list[i].length);
Packit 6d2c1b
			scat[j].lkey       = htonl(wr->sg_list[i].lkey);
Packit 6d2c1b
			scat[j].addr       = htonll(wr->sg_list[i].addr);
Packit 6d2c1b
			j++;
Packit 6d2c1b
		}
Packit 6d2c1b
Packit 6d2c1b
		if (j < (int)mlx5_qp->cap.max_recv_sge) {
Packit 6d2c1b
			scat[j].byte_count = 0;
Packit 6d2c1b
			scat[j].lkey       = htonl(MLX5_INVALID_LKEY);
Packit 6d2c1b
			scat[j].addr       = 0;
Packit 6d2c1b
		}
Packit 6d2c1b
Packit 6d2c1b
		ind = (ind + 1) & (mlx5_qp->rq.wqe_cnt - 1);
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
out:
Packit 6d2c1b
	if (likely(nreq)) {
Packit 6d2c1b
		mlx5_qp->rq.head += nreq;
Packit 6d2c1b
Packit 6d2c1b
		/*
Packit 6d2c1b
		 * Make sure that descriptors are written before
Packit 6d2c1b
		 * doorbell record.
Packit 6d2c1b
		 */
Packit 6d2c1b
		wmb();
Packit 6d2c1b
Packit 6d2c1b
		/*
Packit 6d2c1b
		 * For Raw Packet QP, avoid updating the doorbell record
Packit 6d2c1b
		 * as long as the QP isn't in RTR state, to avoid receiving
Packit 6d2c1b
		 * packets in illegal states.
Packit 6d2c1b
		 * This is only for Raw Packet QPs since they are represented
Packit 6d2c1b
		 * differently in the hardware.
Packit 6d2c1b
		 */
Packit 6d2c1b
		if (likely(!((mlx5_qp->qp->qp_type == IBV_QPT_RAW_PACKET ||
Packit 6d2c1b
				mlx5_qp->flags & VMA_IB_MLX5_QP_FLAGS_USE_UNDERLAY) &&
Packit 6d2c1b
				mlx5_qp->qp->state < IBV_QPS_RTR)))
Packit 6d2c1b
			*mlx5_qp->rq.dbrec = htonl(mlx5_qp->rq.head & 0xffff);
Packit 6d2c1b
	}
Packit 6d2c1b
Packit 6d2c1b
	return err;
Packit 6d2c1b
}
Packit 6d2c1b
Packit 6d2c1b
#endif /* DEFINED_DIRECT_VERBS */