18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 68c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 78c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 88c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 98c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 128c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 138c2ecf20Sopenharmony_ci * conditions are met: 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 168c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 178c2ecf20Sopenharmony_ci * disclaimer. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 208c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 218c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 228c2ecf20Sopenharmony_ci * provided with the distribution. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 258c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 268c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 278c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 288c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 298c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 308c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 318c2ecf20Sopenharmony_ci * SOFTWARE. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/mlx4/qp.h> 358c2ecf20Sopenharmony_ci#include <linux/mlx4/srq.h> 368c2ecf20Sopenharmony_ci#include <linux/slab.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "mlx4_ib.h" 398c2ecf20Sopenharmony_ci#include <rdma/mlx4-abi.h> 408c2ecf20Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void *get_wqe(struct mlx4_ib_srq *srq, int n) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci return mlx4_buf_offset(&srq->buf, n << srq->msrq.wqe_shift); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void mlx4_ib_srq_event(struct mlx4_srq *srq, enum mlx4_event type) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct ib_event event; 508c2ecf20Sopenharmony_ci struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (ibsrq->event_handler) { 538c2ecf20Sopenharmony_ci event.device = ibsrq->device; 548c2ecf20Sopenharmony_ci event.element.srq = ibsrq; 558c2ecf20Sopenharmony_ci switch (type) { 568c2ecf20Sopenharmony_ci case MLX4_EVENT_TYPE_SRQ_LIMIT: 578c2ecf20Sopenharmony_ci event.event = IB_EVENT_SRQ_LIMIT_REACHED; 588c2ecf20Sopenharmony_ci break; 598c2ecf20Sopenharmony_ci case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: 608c2ecf20Sopenharmony_ci event.event = IB_EVENT_SRQ_ERR; 618c2ecf20Sopenharmony_ci break; 628c2ecf20Sopenharmony_ci default: 638c2ecf20Sopenharmony_ci pr_warn("Unexpected event type %d " 648c2ecf20Sopenharmony_ci "on SRQ %06x\n", type, srq->srqn); 658c2ecf20Sopenharmony_ci return; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci ibsrq->event_handler(&event, ibsrq->srq_context); 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ciint mlx4_ib_create_srq(struct ib_srq *ib_srq, 738c2ecf20Sopenharmony_ci struct ib_srq_init_attr *init_attr, 748c2ecf20Sopenharmony_ci struct ib_udata *udata) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ib_srq->device); 778c2ecf20Sopenharmony_ci struct mlx4_ib_ucontext *ucontext = rdma_udata_to_drv_context( 788c2ecf20Sopenharmony_ci udata, struct mlx4_ib_ucontext, ibucontext); 798c2ecf20Sopenharmony_ci struct mlx4_ib_srq *srq = to_msrq(ib_srq); 808c2ecf20Sopenharmony_ci struct mlx4_wqe_srq_next_seg *next; 818c2ecf20Sopenharmony_ci struct mlx4_wqe_data_seg *scatter; 828c2ecf20Sopenharmony_ci u32 cqn; 838c2ecf20Sopenharmony_ci u16 xrcdn; 848c2ecf20Sopenharmony_ci int desc_size; 858c2ecf20Sopenharmony_ci int buf_size; 868c2ecf20Sopenharmony_ci int err; 878c2ecf20Sopenharmony_ci int i; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* Sanity check SRQ size before proceeding */ 908c2ecf20Sopenharmony_ci if (init_attr->attr.max_wr >= dev->dev->caps.max_srq_wqes || 918c2ecf20Sopenharmony_ci init_attr->attr.max_sge > dev->dev->caps.max_srq_sge) 928c2ecf20Sopenharmony_ci return -EINVAL; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci mutex_init(&srq->mutex); 958c2ecf20Sopenharmony_ci spin_lock_init(&srq->lock); 968c2ecf20Sopenharmony_ci srq->msrq.max = roundup_pow_of_two(init_attr->attr.max_wr + 1); 978c2ecf20Sopenharmony_ci srq->msrq.max_gs = init_attr->attr.max_sge; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci desc_size = max(32UL, 1008c2ecf20Sopenharmony_ci roundup_pow_of_two(sizeof (struct mlx4_wqe_srq_next_seg) + 1018c2ecf20Sopenharmony_ci srq->msrq.max_gs * 1028c2ecf20Sopenharmony_ci sizeof (struct mlx4_wqe_data_seg))); 1038c2ecf20Sopenharmony_ci srq->msrq.wqe_shift = ilog2(desc_size); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci buf_size = srq->msrq.max * desc_size; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (udata) { 1088c2ecf20Sopenharmony_ci struct mlx4_ib_create_srq ucmd; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) 1118c2ecf20Sopenharmony_ci return -EFAULT; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci srq->umem = 1148c2ecf20Sopenharmony_ci ib_umem_get(ib_srq->device, ucmd.buf_addr, buf_size, 0); 1158c2ecf20Sopenharmony_ci if (IS_ERR(srq->umem)) 1168c2ecf20Sopenharmony_ci return PTR_ERR(srq->umem); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci err = mlx4_mtt_init( 1198c2ecf20Sopenharmony_ci dev->dev, ib_umem_num_dma_blocks(srq->umem, PAGE_SIZE), 1208c2ecf20Sopenharmony_ci PAGE_SHIFT, &srq->mtt); 1218c2ecf20Sopenharmony_ci if (err) 1228c2ecf20Sopenharmony_ci goto err_buf; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci err = mlx4_ib_umem_write_mtt(dev, &srq->mtt, srq->umem); 1258c2ecf20Sopenharmony_ci if (err) 1268c2ecf20Sopenharmony_ci goto err_mtt; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci err = mlx4_ib_db_map_user(udata, ucmd.db_addr, &srq->db); 1298c2ecf20Sopenharmony_ci if (err) 1308c2ecf20Sopenharmony_ci goto err_mtt; 1318c2ecf20Sopenharmony_ci } else { 1328c2ecf20Sopenharmony_ci err = mlx4_db_alloc(dev->dev, &srq->db, 0); 1338c2ecf20Sopenharmony_ci if (err) 1348c2ecf20Sopenharmony_ci return err; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci *srq->db.db = 0; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, 1398c2ecf20Sopenharmony_ci &srq->buf)) { 1408c2ecf20Sopenharmony_ci err = -ENOMEM; 1418c2ecf20Sopenharmony_ci goto err_db; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci srq->head = 0; 1458c2ecf20Sopenharmony_ci srq->tail = srq->msrq.max - 1; 1468c2ecf20Sopenharmony_ci srq->wqe_ctr = 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci for (i = 0; i < srq->msrq.max; ++i) { 1498c2ecf20Sopenharmony_ci next = get_wqe(srq, i); 1508c2ecf20Sopenharmony_ci next->next_wqe_index = 1518c2ecf20Sopenharmony_ci cpu_to_be16((i + 1) & (srq->msrq.max - 1)); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci for (scatter = (void *) (next + 1); 1548c2ecf20Sopenharmony_ci (void *) scatter < (void *) next + desc_size; 1558c2ecf20Sopenharmony_ci ++scatter) 1568c2ecf20Sopenharmony_ci scatter->lkey = cpu_to_be32(MLX4_INVALID_LKEY); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci err = mlx4_mtt_init(dev->dev, srq->buf.npages, srq->buf.page_shift, 1608c2ecf20Sopenharmony_ci &srq->mtt); 1618c2ecf20Sopenharmony_ci if (err) 1628c2ecf20Sopenharmony_ci goto err_buf; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci err = mlx4_buf_write_mtt(dev->dev, &srq->mtt, &srq->buf); 1658c2ecf20Sopenharmony_ci if (err) 1668c2ecf20Sopenharmony_ci goto err_mtt; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci srq->wrid = kvmalloc_array(srq->msrq.max, 1698c2ecf20Sopenharmony_ci sizeof(u64), GFP_KERNEL); 1708c2ecf20Sopenharmony_ci if (!srq->wrid) { 1718c2ecf20Sopenharmony_ci err = -ENOMEM; 1728c2ecf20Sopenharmony_ci goto err_mtt; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci cqn = ib_srq_has_cq(init_attr->srq_type) ? 1778c2ecf20Sopenharmony_ci to_mcq(init_attr->ext.cq)->mcq.cqn : 0; 1788c2ecf20Sopenharmony_ci xrcdn = (init_attr->srq_type == IB_SRQT_XRC) ? 1798c2ecf20Sopenharmony_ci to_mxrcd(init_attr->ext.xrc.xrcd)->xrcdn : 1808c2ecf20Sopenharmony_ci (u16) dev->dev->caps.reserved_xrcds; 1818c2ecf20Sopenharmony_ci err = mlx4_srq_alloc(dev->dev, to_mpd(ib_srq->pd)->pdn, cqn, xrcdn, 1828c2ecf20Sopenharmony_ci &srq->mtt, srq->db.dma, &srq->msrq); 1838c2ecf20Sopenharmony_ci if (err) 1848c2ecf20Sopenharmony_ci goto err_wrid; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci srq->msrq.event = mlx4_ib_srq_event; 1878c2ecf20Sopenharmony_ci srq->ibsrq.ext.xrc.srq_num = srq->msrq.srqn; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (udata) 1908c2ecf20Sopenharmony_ci if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof (__u32))) { 1918c2ecf20Sopenharmony_ci err = -EFAULT; 1928c2ecf20Sopenharmony_ci goto err_wrid; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci init_attr->attr.max_wr = srq->msrq.max - 1; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cierr_wrid: 2008c2ecf20Sopenharmony_ci if (udata) 2018c2ecf20Sopenharmony_ci mlx4_ib_db_unmap_user(ucontext, &srq->db); 2028c2ecf20Sopenharmony_ci else 2038c2ecf20Sopenharmony_ci kvfree(srq->wrid); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cierr_mtt: 2068c2ecf20Sopenharmony_ci mlx4_mtt_cleanup(dev->dev, &srq->mtt); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cierr_buf: 2098c2ecf20Sopenharmony_ci if (!srq->umem) 2108c2ecf20Sopenharmony_ci mlx4_buf_free(dev->dev, buf_size, &srq->buf); 2118c2ecf20Sopenharmony_ci ib_umem_release(srq->umem); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cierr_db: 2148c2ecf20Sopenharmony_ci if (!udata) 2158c2ecf20Sopenharmony_ci mlx4_db_free(dev->dev, &srq->db); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return err; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ciint mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, 2218c2ecf20Sopenharmony_ci enum ib_srq_attr_mask attr_mask, struct ib_udata *udata) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibsrq->device); 2248c2ecf20Sopenharmony_ci struct mlx4_ib_srq *srq = to_msrq(ibsrq); 2258c2ecf20Sopenharmony_ci int ret; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* We don't support resizing SRQs (yet?) */ 2288c2ecf20Sopenharmony_ci if (attr_mask & IB_SRQ_MAX_WR) 2298c2ecf20Sopenharmony_ci return -EINVAL; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (attr_mask & IB_SRQ_LIMIT) { 2328c2ecf20Sopenharmony_ci if (attr->srq_limit >= srq->msrq.max) 2338c2ecf20Sopenharmony_ci return -EINVAL; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci mutex_lock(&srq->mutex); 2368c2ecf20Sopenharmony_ci ret = mlx4_srq_arm(dev->dev, &srq->msrq, attr->srq_limit); 2378c2ecf20Sopenharmony_ci mutex_unlock(&srq->mutex); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (ret) 2408c2ecf20Sopenharmony_ci return ret; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciint mlx4_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibsrq->device); 2498c2ecf20Sopenharmony_ci struct mlx4_ib_srq *srq = to_msrq(ibsrq); 2508c2ecf20Sopenharmony_ci int ret; 2518c2ecf20Sopenharmony_ci int limit_watermark; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci ret = mlx4_srq_query(dev->dev, &srq->msrq, &limit_watermark); 2548c2ecf20Sopenharmony_ci if (ret) 2558c2ecf20Sopenharmony_ci return ret; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci srq_attr->srq_limit = limit_watermark; 2588c2ecf20Sopenharmony_ci srq_attr->max_wr = srq->msrq.max - 1; 2598c2ecf20Sopenharmony_ci srq_attr->max_sge = srq->msrq.max_gs; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ciint mlx4_ib_destroy_srq(struct ib_srq *srq, struct ib_udata *udata) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(srq->device); 2678c2ecf20Sopenharmony_ci struct mlx4_ib_srq *msrq = to_msrq(srq); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci mlx4_srq_free(dev->dev, &msrq->msrq); 2708c2ecf20Sopenharmony_ci mlx4_mtt_cleanup(dev->dev, &msrq->mtt); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (udata) { 2738c2ecf20Sopenharmony_ci mlx4_ib_db_unmap_user( 2748c2ecf20Sopenharmony_ci rdma_udata_to_drv_context( 2758c2ecf20Sopenharmony_ci udata, 2768c2ecf20Sopenharmony_ci struct mlx4_ib_ucontext, 2778c2ecf20Sopenharmony_ci ibucontext), 2788c2ecf20Sopenharmony_ci &msrq->db); 2798c2ecf20Sopenharmony_ci } else { 2808c2ecf20Sopenharmony_ci kvfree(msrq->wrid); 2818c2ecf20Sopenharmony_ci mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift, 2828c2ecf20Sopenharmony_ci &msrq->buf); 2838c2ecf20Sopenharmony_ci mlx4_db_free(dev->dev, &msrq->db); 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci ib_umem_release(msrq->umem); 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_civoid mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct mlx4_wqe_srq_next_seg *next; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* always called with interrupts disabled. */ 2948c2ecf20Sopenharmony_ci spin_lock(&srq->lock); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci next = get_wqe(srq, srq->tail); 2978c2ecf20Sopenharmony_ci next->next_wqe_index = cpu_to_be16(wqe_index); 2988c2ecf20Sopenharmony_ci srq->tail = wqe_index; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci spin_unlock(&srq->lock); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ciint mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, 3048c2ecf20Sopenharmony_ci const struct ib_recv_wr **bad_wr) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct mlx4_ib_srq *srq = to_msrq(ibsrq); 3078c2ecf20Sopenharmony_ci struct mlx4_wqe_srq_next_seg *next; 3088c2ecf20Sopenharmony_ci struct mlx4_wqe_data_seg *scat; 3098c2ecf20Sopenharmony_ci unsigned long flags; 3108c2ecf20Sopenharmony_ci int err = 0; 3118c2ecf20Sopenharmony_ci int nreq; 3128c2ecf20Sopenharmony_ci int i; 3138c2ecf20Sopenharmony_ci struct mlx4_ib_dev *mdev = to_mdev(ibsrq->device); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci spin_lock_irqsave(&srq->lock, flags); 3168c2ecf20Sopenharmony_ci if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) { 3178c2ecf20Sopenharmony_ci err = -EIO; 3188c2ecf20Sopenharmony_ci *bad_wr = wr; 3198c2ecf20Sopenharmony_ci nreq = 0; 3208c2ecf20Sopenharmony_ci goto out; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci for (nreq = 0; wr; ++nreq, wr = wr->next) { 3248c2ecf20Sopenharmony_ci if (unlikely(wr->num_sge > srq->msrq.max_gs)) { 3258c2ecf20Sopenharmony_ci err = -EINVAL; 3268c2ecf20Sopenharmony_ci *bad_wr = wr; 3278c2ecf20Sopenharmony_ci break; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (unlikely(srq->head == srq->tail)) { 3318c2ecf20Sopenharmony_ci err = -ENOMEM; 3328c2ecf20Sopenharmony_ci *bad_wr = wr; 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci srq->wrid[srq->head] = wr->wr_id; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci next = get_wqe(srq, srq->head); 3398c2ecf20Sopenharmony_ci srq->head = be16_to_cpu(next->next_wqe_index); 3408c2ecf20Sopenharmony_ci scat = (struct mlx4_wqe_data_seg *) (next + 1); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci for (i = 0; i < wr->num_sge; ++i) { 3438c2ecf20Sopenharmony_ci scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length); 3448c2ecf20Sopenharmony_ci scat[i].lkey = cpu_to_be32(wr->sg_list[i].lkey); 3458c2ecf20Sopenharmony_ci scat[i].addr = cpu_to_be64(wr->sg_list[i].addr); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (i < srq->msrq.max_gs) { 3498c2ecf20Sopenharmony_ci scat[i].byte_count = 0; 3508c2ecf20Sopenharmony_ci scat[i].lkey = cpu_to_be32(MLX4_INVALID_LKEY); 3518c2ecf20Sopenharmony_ci scat[i].addr = 0; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (likely(nreq)) { 3568c2ecf20Sopenharmony_ci srq->wqe_ctr += nreq; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* 3598c2ecf20Sopenharmony_ci * Make sure that descriptors are written before 3608c2ecf20Sopenharmony_ci * doorbell record. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci wmb(); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci *srq->db.db = cpu_to_be32(srq->wqe_ctr); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ciout: 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&srq->lock, flags); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return err; 3718c2ecf20Sopenharmony_ci} 372