1*9dab4d62SMichael Baum /* SPDX-License-Identifier: BSD-3-Clause 2*9dab4d62SMichael Baum * Copyright 2020 Mellanox Technologies, Ltd 3*9dab4d62SMichael Baum */ 4*9dab4d62SMichael Baum #include <stdint.h> 5*9dab4d62SMichael Baum 6*9dab4d62SMichael Baum #include <rte_errno.h> 7*9dab4d62SMichael Baum #include <rte_common.h> 8*9dab4d62SMichael Baum #include <rte_eal_paging.h> 9*9dab4d62SMichael Baum 10*9dab4d62SMichael Baum #include <mlx5_glue.h> 11*9dab4d62SMichael Baum #include <mlx5_common_os.h> 12*9dab4d62SMichael Baum 13*9dab4d62SMichael Baum #include "mlx5_prm.h" 14*9dab4d62SMichael Baum #include "mlx5_devx_cmds.h" 15*9dab4d62SMichael Baum #include "mlx5_common_utils.h" 16*9dab4d62SMichael Baum #include "mlx5_malloc.h" 17*9dab4d62SMichael Baum #include "mlx5_common.h" 18*9dab4d62SMichael Baum #include "mlx5_common_devx.h" 19*9dab4d62SMichael Baum 20*9dab4d62SMichael Baum /** 21*9dab4d62SMichael Baum * Destroy DevX Completion Queue. 22*9dab4d62SMichael Baum * 23*9dab4d62SMichael Baum * @param[in] cq 24*9dab4d62SMichael Baum * DevX CQ to destroy. 25*9dab4d62SMichael Baum */ 26*9dab4d62SMichael Baum void 27*9dab4d62SMichael Baum mlx5_devx_cq_destroy(struct mlx5_devx_cq *cq) 28*9dab4d62SMichael Baum { 29*9dab4d62SMichael Baum if (cq->cq) 30*9dab4d62SMichael Baum claim_zero(mlx5_devx_cmd_destroy(cq->cq)); 31*9dab4d62SMichael Baum if (cq->umem_obj) 32*9dab4d62SMichael Baum claim_zero(mlx5_os_umem_dereg(cq->umem_obj)); 33*9dab4d62SMichael Baum if (cq->umem_buf) 34*9dab4d62SMichael Baum mlx5_free((void *)(uintptr_t)cq->umem_buf); 35*9dab4d62SMichael Baum } 36*9dab4d62SMichael Baum 37*9dab4d62SMichael Baum /* Mark all CQEs initially as invalid. */ 38*9dab4d62SMichael Baum static void 39*9dab4d62SMichael Baum mlx5_cq_init(struct mlx5_devx_cq *cq_obj, uint16_t cq_size) 40*9dab4d62SMichael Baum { 41*9dab4d62SMichael Baum volatile struct mlx5_cqe *cqe = cq_obj->cqes; 42*9dab4d62SMichael Baum uint16_t i; 43*9dab4d62SMichael Baum 44*9dab4d62SMichael Baum for (i = 0; i < cq_size; i++, cqe++) 45*9dab4d62SMichael Baum cqe->op_own = (MLX5_CQE_INVALID << 4) | MLX5_CQE_OWNER_MASK; 46*9dab4d62SMichael Baum } 47*9dab4d62SMichael Baum 48*9dab4d62SMichael Baum /** 49*9dab4d62SMichael Baum * Create Completion Queue using DevX API. 50*9dab4d62SMichael Baum * 51*9dab4d62SMichael Baum * Get a pointer to partially initialized attributes structure, and updates the 52*9dab4d62SMichael Baum * following fields: 53*9dab4d62SMichael Baum * q_umem_valid 54*9dab4d62SMichael Baum * q_umem_id 55*9dab4d62SMichael Baum * q_umem_offset 56*9dab4d62SMichael Baum * db_umem_valid 57*9dab4d62SMichael Baum * db_umem_id 58*9dab4d62SMichael Baum * db_umem_offset 59*9dab4d62SMichael Baum * eqn 60*9dab4d62SMichael Baum * log_cq_size 61*9dab4d62SMichael Baum * log_page_size 62*9dab4d62SMichael Baum * All other fields are updated by caller. 63*9dab4d62SMichael Baum * 64*9dab4d62SMichael Baum * @param[in] ctx 65*9dab4d62SMichael Baum * Context returned from mlx5 open_device() glue function. 66*9dab4d62SMichael Baum * @param[in/out] cq_obj 67*9dab4d62SMichael Baum * Pointer to CQ to create. 68*9dab4d62SMichael Baum * @param[in] log_desc_n 69*9dab4d62SMichael Baum * Log of number of descriptors in queue. 70*9dab4d62SMichael Baum * @param[in] attr 71*9dab4d62SMichael Baum * Pointer to CQ attributes structure. 72*9dab4d62SMichael Baum * @param[in] socket 73*9dab4d62SMichael Baum * Socket to use for allocation. 74*9dab4d62SMichael Baum * 75*9dab4d62SMichael Baum * @return 76*9dab4d62SMichael Baum * 0 on success, a negative errno value otherwise and rte_errno is set. 77*9dab4d62SMichael Baum */ 78*9dab4d62SMichael Baum int 79*9dab4d62SMichael Baum mlx5_devx_cq_create(void *ctx, struct mlx5_devx_cq *cq_obj, uint16_t log_desc_n, 80*9dab4d62SMichael Baum struct mlx5_devx_cq_attr *attr, int socket) 81*9dab4d62SMichael Baum { 82*9dab4d62SMichael Baum struct mlx5_devx_obj *cq = NULL; 83*9dab4d62SMichael Baum struct mlx5dv_devx_umem *umem_obj = NULL; 84*9dab4d62SMichael Baum void *umem_buf = NULL; 85*9dab4d62SMichael Baum size_t page_size = rte_mem_page_size(); 86*9dab4d62SMichael Baum size_t alignment = MLX5_CQE_BUF_ALIGNMENT; 87*9dab4d62SMichael Baum uint32_t umem_size, umem_dbrec; 88*9dab4d62SMichael Baum uint32_t eqn; 89*9dab4d62SMichael Baum uint16_t cq_size = 1 << log_desc_n; 90*9dab4d62SMichael Baum int ret; 91*9dab4d62SMichael Baum 92*9dab4d62SMichael Baum if (page_size == (size_t)-1 || alignment == (size_t)-1) { 93*9dab4d62SMichael Baum DRV_LOG(ERR, "Failed to get page_size."); 94*9dab4d62SMichael Baum rte_errno = ENOMEM; 95*9dab4d62SMichael Baum return -rte_errno; 96*9dab4d62SMichael Baum } 97*9dab4d62SMichael Baum /* Query first EQN. */ 98*9dab4d62SMichael Baum ret = mlx5_glue->devx_query_eqn(ctx, 0, &eqn); 99*9dab4d62SMichael Baum if (ret) { 100*9dab4d62SMichael Baum rte_errno = errno; 101*9dab4d62SMichael Baum DRV_LOG(ERR, "Failed to query event queue number."); 102*9dab4d62SMichael Baum return -rte_errno; 103*9dab4d62SMichael Baum } 104*9dab4d62SMichael Baum /* Allocate memory buffer for CQEs and doorbell record. */ 105*9dab4d62SMichael Baum umem_size = sizeof(struct mlx5_cqe) * cq_size; 106*9dab4d62SMichael Baum umem_dbrec = RTE_ALIGN(umem_size, MLX5_DBR_SIZE); 107*9dab4d62SMichael Baum umem_size += MLX5_DBR_SIZE; 108*9dab4d62SMichael Baum umem_buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, umem_size, 109*9dab4d62SMichael Baum alignment, socket); 110*9dab4d62SMichael Baum if (!umem_buf) { 111*9dab4d62SMichael Baum DRV_LOG(ERR, "Failed to allocate memory for CQ."); 112*9dab4d62SMichael Baum rte_errno = ENOMEM; 113*9dab4d62SMichael Baum return -rte_errno; 114*9dab4d62SMichael Baum } 115*9dab4d62SMichael Baum /* Register allocated buffer in user space with DevX. */ 116*9dab4d62SMichael Baum umem_obj = mlx5_os_umem_reg(ctx, (void *)(uintptr_t)umem_buf, umem_size, 117*9dab4d62SMichael Baum IBV_ACCESS_LOCAL_WRITE); 118*9dab4d62SMichael Baum if (!umem_obj) { 119*9dab4d62SMichael Baum DRV_LOG(ERR, "Failed to register umem for CQ."); 120*9dab4d62SMichael Baum rte_errno = errno; 121*9dab4d62SMichael Baum goto error; 122*9dab4d62SMichael Baum } 123*9dab4d62SMichael Baum /* Fill attributes for CQ object creation. */ 124*9dab4d62SMichael Baum attr->q_umem_valid = 1; 125*9dab4d62SMichael Baum attr->q_umem_id = mlx5_os_get_umem_id(umem_obj); 126*9dab4d62SMichael Baum attr->q_umem_offset = 0; 127*9dab4d62SMichael Baum attr->db_umem_valid = 1; 128*9dab4d62SMichael Baum attr->db_umem_id = attr->q_umem_id; 129*9dab4d62SMichael Baum attr->db_umem_offset = umem_dbrec; 130*9dab4d62SMichael Baum attr->eqn = eqn; 131*9dab4d62SMichael Baum attr->log_cq_size = log_desc_n; 132*9dab4d62SMichael Baum attr->log_page_size = rte_log2_u32(page_size); 133*9dab4d62SMichael Baum /* Create completion queue object with DevX. */ 134*9dab4d62SMichael Baum cq = mlx5_devx_cmd_create_cq(ctx, attr); 135*9dab4d62SMichael Baum if (!cq) { 136*9dab4d62SMichael Baum DRV_LOG(ERR, "Can't create DevX CQ object."); 137*9dab4d62SMichael Baum rte_errno = ENOMEM; 138*9dab4d62SMichael Baum goto error; 139*9dab4d62SMichael Baum } 140*9dab4d62SMichael Baum cq_obj->umem_buf = umem_buf; 141*9dab4d62SMichael Baum cq_obj->umem_obj = umem_obj; 142*9dab4d62SMichael Baum cq_obj->cq = cq; 143*9dab4d62SMichael Baum cq_obj->db_rec = RTE_PTR_ADD(cq_obj->umem_buf, umem_dbrec); 144*9dab4d62SMichael Baum /* Mark all CQEs initially as invalid. */ 145*9dab4d62SMichael Baum mlx5_cq_init(cq_obj, cq_size); 146*9dab4d62SMichael Baum return 0; 147*9dab4d62SMichael Baum error: 148*9dab4d62SMichael Baum ret = rte_errno; 149*9dab4d62SMichael Baum if (umem_obj) 150*9dab4d62SMichael Baum claim_zero(mlx5_os_umem_dereg(umem_obj)); 151*9dab4d62SMichael Baum if (umem_buf) 152*9dab4d62SMichael Baum mlx5_free((void *)(uintptr_t)umem_buf); 153*9dab4d62SMichael Baum rte_errno = ret; 154*9dab4d62SMichael Baum return -rte_errno; 155*9dab4d62SMichael Baum } 156