18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2013-2018, Mellanox Technologies inc. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/mlx5/qp.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <rdma/ib_umem.h> 108c2ecf20Sopenharmony_ci#include <rdma/ib_user_verbs.h> 118c2ecf20Sopenharmony_ci#include "mlx5_ib.h" 128c2ecf20Sopenharmony_ci#include "srq.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic void *get_wqe(struct mlx5_ib_srq *srq, int n) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci return mlx5_frag_buf_get_wqe(&srq->fbc, n); 178c2ecf20Sopenharmony_ci} 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic void mlx5_ib_srq_event(struct mlx5_core_srq *srq, enum mlx5_event type) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci struct ib_event event; 228c2ecf20Sopenharmony_ci struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci if (ibsrq->event_handler) { 258c2ecf20Sopenharmony_ci event.device = ibsrq->device; 268c2ecf20Sopenharmony_ci event.element.srq = ibsrq; 278c2ecf20Sopenharmony_ci switch (type) { 288c2ecf20Sopenharmony_ci case MLX5_EVENT_TYPE_SRQ_RQ_LIMIT: 298c2ecf20Sopenharmony_ci event.event = IB_EVENT_SRQ_LIMIT_REACHED; 308c2ecf20Sopenharmony_ci break; 318c2ecf20Sopenharmony_ci case MLX5_EVENT_TYPE_SRQ_CATAS_ERROR: 328c2ecf20Sopenharmony_ci event.event = IB_EVENT_SRQ_ERR; 338c2ecf20Sopenharmony_ci break; 348c2ecf20Sopenharmony_ci default: 358c2ecf20Sopenharmony_ci pr_warn("mlx5_ib: Unexpected event type %d on SRQ %06x\n", 368c2ecf20Sopenharmony_ci type, srq->srqn); 378c2ecf20Sopenharmony_ci return; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci ibsrq->event_handler(&event, ibsrq->srq_context); 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, 458c2ecf20Sopenharmony_ci struct mlx5_srq_attr *in, 468c2ecf20Sopenharmony_ci struct ib_udata *udata, int buf_size) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(pd->device); 498c2ecf20Sopenharmony_ci struct mlx5_ib_create_srq ucmd = {}; 508c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext *ucontext = rdma_udata_to_drv_context( 518c2ecf20Sopenharmony_ci udata, struct mlx5_ib_ucontext, ibucontext); 528c2ecf20Sopenharmony_ci size_t ucmdlen; 538c2ecf20Sopenharmony_ci int err; 548c2ecf20Sopenharmony_ci int npages; 558c2ecf20Sopenharmony_ci int page_shift; 568c2ecf20Sopenharmony_ci int ncont; 578c2ecf20Sopenharmony_ci u32 offset; 588c2ecf20Sopenharmony_ci u32 uidx = MLX5_IB_DEFAULT_UIDX; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci ucmdlen = min(udata->inlen, sizeof(ucmd)); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (ib_copy_from_udata(&ucmd, udata, ucmdlen)) { 638c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "failed copy udata\n"); 648c2ecf20Sopenharmony_ci return -EFAULT; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (ucmd.reserved0 || ucmd.reserved1) 688c2ecf20Sopenharmony_ci return -EINVAL; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (udata->inlen > sizeof(ucmd) && 718c2ecf20Sopenharmony_ci !ib_is_udata_cleared(udata, sizeof(ucmd), 728c2ecf20Sopenharmony_ci udata->inlen - sizeof(ucmd))) 738c2ecf20Sopenharmony_ci return -EINVAL; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (in->type != IB_SRQT_BASIC) { 768c2ecf20Sopenharmony_ci err = get_srq_user_index(ucontext, &ucmd, udata->inlen, &uidx); 778c2ecf20Sopenharmony_ci if (err) 788c2ecf20Sopenharmony_ci return err; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci srq->umem = ib_umem_get(pd->device, ucmd.buf_addr, buf_size, 0); 848c2ecf20Sopenharmony_ci if (IS_ERR(srq->umem)) { 858c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "failed umem get, size %d\n", buf_size); 868c2ecf20Sopenharmony_ci err = PTR_ERR(srq->umem); 878c2ecf20Sopenharmony_ci return err; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci mlx5_ib_cont_pages(srq->umem, ucmd.buf_addr, 0, &npages, 918c2ecf20Sopenharmony_ci &page_shift, &ncont, NULL); 928c2ecf20Sopenharmony_ci err = mlx5_ib_get_buf_offset(ucmd.buf_addr, page_shift, 938c2ecf20Sopenharmony_ci &offset); 948c2ecf20Sopenharmony_ci if (err) { 958c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "bad offset\n"); 968c2ecf20Sopenharmony_ci goto err_umem; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci in->pas = kvcalloc(ncont, sizeof(*in->pas), GFP_KERNEL); 1008c2ecf20Sopenharmony_ci if (!in->pas) { 1018c2ecf20Sopenharmony_ci err = -ENOMEM; 1028c2ecf20Sopenharmony_ci goto err_umem; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci mlx5_ib_populate_pas(dev, srq->umem, page_shift, in->pas, 0); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci err = mlx5_ib_db_map_user(ucontext, udata, ucmd.db_addr, &srq->db); 1088c2ecf20Sopenharmony_ci if (err) { 1098c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "map doorbell failed\n"); 1108c2ecf20Sopenharmony_ci goto err_in; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci in->log_page_size = page_shift - MLX5_ADAPTER_PAGE_SHIFT; 1148c2ecf20Sopenharmony_ci in->page_offset = offset; 1158c2ecf20Sopenharmony_ci in->uid = (in->type != IB_SRQT_XRC) ? to_mpd(pd)->uid : 0; 1168c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1 && 1178c2ecf20Sopenharmony_ci in->type != IB_SRQT_BASIC) 1188c2ecf20Sopenharmony_ci in->user_index = uidx; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cierr_in: 1238c2ecf20Sopenharmony_ci kvfree(in->pas); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cierr_umem: 1268c2ecf20Sopenharmony_ci ib_umem_release(srq->umem); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci return err; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, 1328c2ecf20Sopenharmony_ci struct mlx5_srq_attr *in, int buf_size) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci int err; 1358c2ecf20Sopenharmony_ci int i; 1368c2ecf20Sopenharmony_ci struct mlx5_wqe_srq_next_seg *next; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci err = mlx5_db_alloc(dev->mdev, &srq->db); 1398c2ecf20Sopenharmony_ci if (err) { 1408c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "alloc dbell rec failed\n"); 1418c2ecf20Sopenharmony_ci return err; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (mlx5_frag_buf_alloc_node(dev->mdev, buf_size, &srq->buf, 1458c2ecf20Sopenharmony_ci dev->mdev->priv.numa_node)) { 1468c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "buf alloc failed\n"); 1478c2ecf20Sopenharmony_ci err = -ENOMEM; 1488c2ecf20Sopenharmony_ci goto err_db; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci mlx5_init_fbc(srq->buf.frags, srq->msrq.wqe_shift, ilog2(srq->msrq.max), 1528c2ecf20Sopenharmony_ci &srq->fbc); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci srq->head = 0; 1558c2ecf20Sopenharmony_ci srq->tail = srq->msrq.max - 1; 1568c2ecf20Sopenharmony_ci srq->wqe_ctr = 0; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci for (i = 0; i < srq->msrq.max; i++) { 1598c2ecf20Sopenharmony_ci next = get_wqe(srq, i); 1608c2ecf20Sopenharmony_ci next->next_wqe_index = 1618c2ecf20Sopenharmony_ci cpu_to_be16((i + 1) & (srq->msrq.max - 1)); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "srq->buf.page_shift = %d\n", srq->buf.page_shift); 1658c2ecf20Sopenharmony_ci in->pas = kvcalloc(srq->buf.npages, sizeof(*in->pas), GFP_KERNEL); 1668c2ecf20Sopenharmony_ci if (!in->pas) { 1678c2ecf20Sopenharmony_ci err = -ENOMEM; 1688c2ecf20Sopenharmony_ci goto err_buf; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci mlx5_fill_page_frag_array(&srq->buf, in->pas); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci srq->wrid = kvmalloc_array(srq->msrq.max, sizeof(u64), GFP_KERNEL); 1738c2ecf20Sopenharmony_ci if (!srq->wrid) { 1748c2ecf20Sopenharmony_ci err = -ENOMEM; 1758c2ecf20Sopenharmony_ci goto err_in; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci srq->wq_sig = 0; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci in->log_page_size = srq->buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT; 1808c2ecf20Sopenharmony_ci if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1 && 1818c2ecf20Sopenharmony_ci in->type != IB_SRQT_BASIC) 1828c2ecf20Sopenharmony_ci in->user_index = MLX5_IB_DEFAULT_UIDX; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return 0; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cierr_in: 1878c2ecf20Sopenharmony_ci kvfree(in->pas); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cierr_buf: 1908c2ecf20Sopenharmony_ci mlx5_frag_buf_free(dev->mdev, &srq->buf); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cierr_db: 1938c2ecf20Sopenharmony_ci mlx5_db_free(dev->mdev, &srq->db); 1948c2ecf20Sopenharmony_ci return err; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic void destroy_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, 1988c2ecf20Sopenharmony_ci struct ib_udata *udata) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci mlx5_ib_db_unmap_user( 2018c2ecf20Sopenharmony_ci rdma_udata_to_drv_context( 2028c2ecf20Sopenharmony_ci udata, 2038c2ecf20Sopenharmony_ci struct mlx5_ib_ucontext, 2048c2ecf20Sopenharmony_ci ibucontext), 2058c2ecf20Sopenharmony_ci &srq->db); 2068c2ecf20Sopenharmony_ci ib_umem_release(srq->umem); 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void destroy_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci kvfree(srq->wrid); 2138c2ecf20Sopenharmony_ci mlx5_frag_buf_free(dev->mdev, &srq->buf); 2148c2ecf20Sopenharmony_ci mlx5_db_free(dev->mdev, &srq->db); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciint mlx5_ib_create_srq(struct ib_srq *ib_srq, 2188c2ecf20Sopenharmony_ci struct ib_srq_init_attr *init_attr, 2198c2ecf20Sopenharmony_ci struct ib_udata *udata) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ib_srq->device); 2228c2ecf20Sopenharmony_ci struct mlx5_ib_srq *srq = to_msrq(ib_srq); 2238c2ecf20Sopenharmony_ci size_t desc_size; 2248c2ecf20Sopenharmony_ci size_t buf_size; 2258c2ecf20Sopenharmony_ci int err; 2268c2ecf20Sopenharmony_ci struct mlx5_srq_attr in = {}; 2278c2ecf20Sopenharmony_ci __u32 max_srq_wqes = 1 << MLX5_CAP_GEN(dev->mdev, log_max_srq_sz); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Sanity check SRQ size before proceeding */ 2308c2ecf20Sopenharmony_ci if (init_attr->attr.max_wr >= max_srq_wqes) { 2318c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "max_wr %d, cap %d\n", 2328c2ecf20Sopenharmony_ci init_attr->attr.max_wr, 2338c2ecf20Sopenharmony_ci max_srq_wqes); 2348c2ecf20Sopenharmony_ci return -EINVAL; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci mutex_init(&srq->mutex); 2388c2ecf20Sopenharmony_ci spin_lock_init(&srq->lock); 2398c2ecf20Sopenharmony_ci srq->msrq.max = roundup_pow_of_two(init_attr->attr.max_wr + 1); 2408c2ecf20Sopenharmony_ci srq->msrq.max_gs = init_attr->attr.max_sge; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci desc_size = sizeof(struct mlx5_wqe_srq_next_seg) + 2438c2ecf20Sopenharmony_ci srq->msrq.max_gs * sizeof(struct mlx5_wqe_data_seg); 2448c2ecf20Sopenharmony_ci if (desc_size == 0 || srq->msrq.max_gs > desc_size) 2458c2ecf20Sopenharmony_ci return -EINVAL; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci desc_size = roundup_pow_of_two(desc_size); 2488c2ecf20Sopenharmony_ci desc_size = max_t(size_t, 32, desc_size); 2498c2ecf20Sopenharmony_ci if (desc_size < sizeof(struct mlx5_wqe_srq_next_seg)) 2508c2ecf20Sopenharmony_ci return -EINVAL; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci srq->msrq.max_avail_gather = (desc_size - sizeof(struct mlx5_wqe_srq_next_seg)) / 2538c2ecf20Sopenharmony_ci sizeof(struct mlx5_wqe_data_seg); 2548c2ecf20Sopenharmony_ci srq->msrq.wqe_shift = ilog2(desc_size); 2558c2ecf20Sopenharmony_ci buf_size = srq->msrq.max * desc_size; 2568c2ecf20Sopenharmony_ci if (buf_size < desc_size) 2578c2ecf20Sopenharmony_ci return -EINVAL; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci in.type = init_attr->srq_type; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (udata) 2628c2ecf20Sopenharmony_ci err = create_srq_user(ib_srq->pd, srq, &in, udata, buf_size); 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci err = create_srq_kernel(dev, srq, &in, buf_size); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (err) { 2678c2ecf20Sopenharmony_ci mlx5_ib_warn(dev, "create srq %s failed, err %d\n", 2688c2ecf20Sopenharmony_ci udata ? "user" : "kernel", err); 2698c2ecf20Sopenharmony_ci return err; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci in.log_size = ilog2(srq->msrq.max); 2738c2ecf20Sopenharmony_ci in.wqe_shift = srq->msrq.wqe_shift - 4; 2748c2ecf20Sopenharmony_ci if (srq->wq_sig) 2758c2ecf20Sopenharmony_ci in.flags |= MLX5_SRQ_FLAG_WQ_SIG; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (init_attr->srq_type == IB_SRQT_XRC && init_attr->ext.xrc.xrcd) 2788c2ecf20Sopenharmony_ci in.xrcd = to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn; 2798c2ecf20Sopenharmony_ci else 2808c2ecf20Sopenharmony_ci in.xrcd = dev->devr.xrcdn0; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (init_attr->srq_type == IB_SRQT_TM) { 2838c2ecf20Sopenharmony_ci in.tm_log_list_size = 2848c2ecf20Sopenharmony_ci ilog2(init_attr->ext.tag_matching.max_num_tags) + 1; 2858c2ecf20Sopenharmony_ci if (in.tm_log_list_size > 2868c2ecf20Sopenharmony_ci MLX5_CAP_GEN(dev->mdev, log_tag_matching_list_sz)) { 2878c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "TM SRQ max_num_tags exceeding limit\n"); 2888c2ecf20Sopenharmony_ci err = -EINVAL; 2898c2ecf20Sopenharmony_ci goto err_usr_kern_srq; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci in.flags |= MLX5_SRQ_FLAG_RNDV; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (ib_srq_has_cq(init_attr->srq_type)) 2958c2ecf20Sopenharmony_ci in.cqn = to_mcq(init_attr->ext.cq)->mcq.cqn; 2968c2ecf20Sopenharmony_ci else 2978c2ecf20Sopenharmony_ci in.cqn = to_mcq(dev->devr.c0)->mcq.cqn; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci in.pd = to_mpd(ib_srq->pd)->pdn; 3008c2ecf20Sopenharmony_ci in.db_record = srq->db.dma; 3018c2ecf20Sopenharmony_ci err = mlx5_cmd_create_srq(dev, &srq->msrq, &in); 3028c2ecf20Sopenharmony_ci kvfree(in.pas); 3038c2ecf20Sopenharmony_ci if (err) { 3048c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "create SRQ failed, err %d\n", err); 3058c2ecf20Sopenharmony_ci goto err_usr_kern_srq; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "create SRQ with srqn 0x%x\n", srq->msrq.srqn); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci srq->msrq.event = mlx5_ib_srq_event; 3118c2ecf20Sopenharmony_ci srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (udata) { 3148c2ecf20Sopenharmony_ci struct mlx5_ib_create_srq_resp resp = { 3158c2ecf20Sopenharmony_ci .srqn = srq->msrq.srqn, 3168c2ecf20Sopenharmony_ci }; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (ib_copy_to_udata(udata, &resp, min(udata->outlen, 3198c2ecf20Sopenharmony_ci sizeof(resp)))) { 3208c2ecf20Sopenharmony_ci mlx5_ib_dbg(dev, "copy to user failed\n"); 3218c2ecf20Sopenharmony_ci err = -EFAULT; 3228c2ecf20Sopenharmony_ci goto err_core; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci init_attr->attr.max_wr = srq->msrq.max - 1; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cierr_core: 3318c2ecf20Sopenharmony_ci mlx5_cmd_destroy_srq(dev, &srq->msrq); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cierr_usr_kern_srq: 3348c2ecf20Sopenharmony_ci if (udata) 3358c2ecf20Sopenharmony_ci destroy_srq_user(ib_srq->pd, srq, udata); 3368c2ecf20Sopenharmony_ci else 3378c2ecf20Sopenharmony_ci destroy_srq_kernel(dev, srq); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return err; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ciint mlx5_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, 3438c2ecf20Sopenharmony_ci enum ib_srq_attr_mask attr_mask, struct ib_udata *udata) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ibsrq->device); 3468c2ecf20Sopenharmony_ci struct mlx5_ib_srq *srq = to_msrq(ibsrq); 3478c2ecf20Sopenharmony_ci int ret; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* We don't support resizing SRQs yet */ 3508c2ecf20Sopenharmony_ci if (attr_mask & IB_SRQ_MAX_WR) 3518c2ecf20Sopenharmony_ci return -EINVAL; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (attr_mask & IB_SRQ_LIMIT) { 3548c2ecf20Sopenharmony_ci if (attr->srq_limit >= srq->msrq.max) 3558c2ecf20Sopenharmony_ci return -EINVAL; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci mutex_lock(&srq->mutex); 3588c2ecf20Sopenharmony_ci ret = mlx5_cmd_arm_srq(dev, &srq->msrq, attr->srq_limit, 1); 3598c2ecf20Sopenharmony_ci mutex_unlock(&srq->mutex); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (ret) 3628c2ecf20Sopenharmony_ci return ret; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return 0; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ciint mlx5_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ibsrq->device); 3718c2ecf20Sopenharmony_ci struct mlx5_ib_srq *srq = to_msrq(ibsrq); 3728c2ecf20Sopenharmony_ci int ret; 3738c2ecf20Sopenharmony_ci struct mlx5_srq_attr *out; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci out = kzalloc(sizeof(*out), GFP_KERNEL); 3768c2ecf20Sopenharmony_ci if (!out) 3778c2ecf20Sopenharmony_ci return -ENOMEM; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci ret = mlx5_cmd_query_srq(dev, &srq->msrq, out); 3808c2ecf20Sopenharmony_ci if (ret) 3818c2ecf20Sopenharmony_ci goto out_box; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci srq_attr->srq_limit = out->lwm; 3848c2ecf20Sopenharmony_ci srq_attr->max_wr = srq->msrq.max - 1; 3858c2ecf20Sopenharmony_ci srq_attr->max_sge = srq->msrq.max_gs; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ciout_box: 3888c2ecf20Sopenharmony_ci kfree(out); 3898c2ecf20Sopenharmony_ci return ret; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ciint mlx5_ib_destroy_srq(struct ib_srq *srq, struct ib_udata *udata) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(srq->device); 3958c2ecf20Sopenharmony_ci struct mlx5_ib_srq *msrq = to_msrq(srq); 3968c2ecf20Sopenharmony_ci int ret; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci ret = mlx5_cmd_destroy_srq(dev, &msrq->msrq); 3998c2ecf20Sopenharmony_ci if (ret) 4008c2ecf20Sopenharmony_ci return ret; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (udata) 4038c2ecf20Sopenharmony_ci destroy_srq_user(srq->pd, msrq, udata); 4048c2ecf20Sopenharmony_ci else 4058c2ecf20Sopenharmony_ci destroy_srq_kernel(dev, msrq); 4068c2ecf20Sopenharmony_ci return 0; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_civoid mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct mlx5_wqe_srq_next_seg *next; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* always called with interrupts disabled. */ 4148c2ecf20Sopenharmony_ci spin_lock(&srq->lock); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci next = get_wqe(srq, srq->tail); 4178c2ecf20Sopenharmony_ci next->next_wqe_index = cpu_to_be16(wqe_index); 4188c2ecf20Sopenharmony_ci srq->tail = wqe_index; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci spin_unlock(&srq->lock); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ciint mlx5_ib_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, 4248c2ecf20Sopenharmony_ci const struct ib_recv_wr **bad_wr) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct mlx5_ib_srq *srq = to_msrq(ibsrq); 4278c2ecf20Sopenharmony_ci struct mlx5_wqe_srq_next_seg *next; 4288c2ecf20Sopenharmony_ci struct mlx5_wqe_data_seg *scat; 4298c2ecf20Sopenharmony_ci struct mlx5_ib_dev *dev = to_mdev(ibsrq->device); 4308c2ecf20Sopenharmony_ci struct mlx5_core_dev *mdev = dev->mdev; 4318c2ecf20Sopenharmony_ci unsigned long flags; 4328c2ecf20Sopenharmony_ci int err = 0; 4338c2ecf20Sopenharmony_ci int nreq; 4348c2ecf20Sopenharmony_ci int i; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci spin_lock_irqsave(&srq->lock, flags); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { 4398c2ecf20Sopenharmony_ci err = -EIO; 4408c2ecf20Sopenharmony_ci *bad_wr = wr; 4418c2ecf20Sopenharmony_ci goto out; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci for (nreq = 0; wr; nreq++, wr = wr->next) { 4458c2ecf20Sopenharmony_ci if (unlikely(wr->num_sge > srq->msrq.max_gs)) { 4468c2ecf20Sopenharmony_ci err = -EINVAL; 4478c2ecf20Sopenharmony_ci *bad_wr = wr; 4488c2ecf20Sopenharmony_ci break; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (unlikely(srq->head == srq->tail)) { 4528c2ecf20Sopenharmony_ci err = -ENOMEM; 4538c2ecf20Sopenharmony_ci *bad_wr = wr; 4548c2ecf20Sopenharmony_ci break; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci srq->wrid[srq->head] = wr->wr_id; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci next = get_wqe(srq, srq->head); 4608c2ecf20Sopenharmony_ci srq->head = be16_to_cpu(next->next_wqe_index); 4618c2ecf20Sopenharmony_ci scat = (struct mlx5_wqe_data_seg *)(next + 1); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 4648c2ecf20Sopenharmony_ci scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length); 4658c2ecf20Sopenharmony_ci scat[i].lkey = cpu_to_be32(wr->sg_list[i].lkey); 4668c2ecf20Sopenharmony_ci scat[i].addr = cpu_to_be64(wr->sg_list[i].addr); 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (i < srq->msrq.max_avail_gather) { 4708c2ecf20Sopenharmony_ci scat[i].byte_count = 0; 4718c2ecf20Sopenharmony_ci scat[i].lkey = cpu_to_be32(MLX5_INVALID_LKEY); 4728c2ecf20Sopenharmony_ci scat[i].addr = 0; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (likely(nreq)) { 4778c2ecf20Sopenharmony_ci srq->wqe_ctr += nreq; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* Make sure that descriptors are written before 4808c2ecf20Sopenharmony_ci * doorbell record. 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_ci wmb(); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci *srq->db.db = cpu_to_be32(srq->wqe_ctr); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ciout: 4878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&srq->lock, flags); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return err; 4908c2ecf20Sopenharmony_ci} 491