18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/module.h> 348c2ecf20Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include "iw_cxgb4.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic int db_delay_usecs = 1; 398c2ecf20Sopenharmony_cimodule_param(db_delay_usecs, int, 0644); 408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(db_delay_usecs, "Usecs to delay awaiting db fifo to drain"); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic int ocqp_support = 1; 438c2ecf20Sopenharmony_cimodule_param(ocqp_support, int, 0644); 448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ocqp_support, "Support on-chip SQs (default=1)"); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciint db_fc_threshold = 1000; 478c2ecf20Sopenharmony_cimodule_param(db_fc_threshold, int, 0644); 488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(db_fc_threshold, 498c2ecf20Sopenharmony_ci "QP count/threshold that triggers" 508c2ecf20Sopenharmony_ci " automatic db flow control mode (default = 1000)"); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciint db_coalescing_threshold; 538c2ecf20Sopenharmony_cimodule_param(db_coalescing_threshold, int, 0644); 548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(db_coalescing_threshold, 558c2ecf20Sopenharmony_ci "QP count/threshold that triggers" 568c2ecf20Sopenharmony_ci " disabling db coalescing (default = 0)"); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int max_fr_immd = T4_MAX_FR_IMMD; 598c2ecf20Sopenharmony_cimodule_param(max_fr_immd, int, 0644); 608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_fr_immd, "fastreg threshold for using DSGL instead of immediate"); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int alloc_ird(struct c4iw_dev *dev, u32 ird) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci int ret = 0; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci xa_lock_irq(&dev->qps); 678c2ecf20Sopenharmony_ci if (ird <= dev->avail_ird) 688c2ecf20Sopenharmony_ci dev->avail_ird -= ird; 698c2ecf20Sopenharmony_ci else 708c2ecf20Sopenharmony_ci ret = -ENOMEM; 718c2ecf20Sopenharmony_ci xa_unlock_irq(&dev->qps); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (ret) 748c2ecf20Sopenharmony_ci dev_warn(&dev->rdev.lldi.pdev->dev, 758c2ecf20Sopenharmony_ci "device IRD resources exhausted\n"); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return ret; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic void free_ird(struct c4iw_dev *dev, int ird) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci xa_lock_irq(&dev->qps); 838c2ecf20Sopenharmony_ci dev->avail_ird += ird; 848c2ecf20Sopenharmony_ci xa_unlock_irq(&dev->qps); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci unsigned long flag; 908c2ecf20Sopenharmony_ci spin_lock_irqsave(&qhp->lock, flag); 918c2ecf20Sopenharmony_ci qhp->attr.state = state; 928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void dealloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci c4iw_ocqp_pool_free(rdev, sq->dma_addr, sq->memsize); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void dealloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci dma_free_coherent(&(rdev->lldi.pdev->dev), sq->memsize, sq->queue, 1038c2ecf20Sopenharmony_ci dma_unmap_addr(sq, mapping)); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void dealloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci if (t4_sq_onchip(sq)) 1098c2ecf20Sopenharmony_ci dealloc_oc_sq(rdev, sq); 1108c2ecf20Sopenharmony_ci else 1118c2ecf20Sopenharmony_ci dealloc_host_sq(rdev, sq); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic int alloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci if (!ocqp_support || !ocqp_supported(&rdev->lldi)) 1178c2ecf20Sopenharmony_ci return -ENOSYS; 1188c2ecf20Sopenharmony_ci sq->dma_addr = c4iw_ocqp_pool_alloc(rdev, sq->memsize); 1198c2ecf20Sopenharmony_ci if (!sq->dma_addr) 1208c2ecf20Sopenharmony_ci return -ENOMEM; 1218c2ecf20Sopenharmony_ci sq->phys_addr = rdev->oc_mw_pa + sq->dma_addr - 1228c2ecf20Sopenharmony_ci rdev->lldi.vr->ocq.start; 1238c2ecf20Sopenharmony_ci sq->queue = (__force union t4_wr *)(rdev->oc_mw_kva + sq->dma_addr - 1248c2ecf20Sopenharmony_ci rdev->lldi.vr->ocq.start); 1258c2ecf20Sopenharmony_ci sq->flags |= T4_SQ_ONCHIP; 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci sq->queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev), sq->memsize, 1328c2ecf20Sopenharmony_ci &(sq->dma_addr), GFP_KERNEL); 1338c2ecf20Sopenharmony_ci if (!sq->queue) 1348c2ecf20Sopenharmony_ci return -ENOMEM; 1358c2ecf20Sopenharmony_ci sq->phys_addr = virt_to_phys(sq->queue); 1368c2ecf20Sopenharmony_ci dma_unmap_addr_set(sq, mapping, sq->dma_addr); 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic int alloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq, int user) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci int ret = -ENOSYS; 1438c2ecf20Sopenharmony_ci if (user) 1448c2ecf20Sopenharmony_ci ret = alloc_oc_sq(rdev, sq); 1458c2ecf20Sopenharmony_ci if (ret) 1468c2ecf20Sopenharmony_ci ret = alloc_host_sq(rdev, sq); 1478c2ecf20Sopenharmony_ci return ret; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, 1518c2ecf20Sopenharmony_ci struct c4iw_dev_ucontext *uctx, int has_rq) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci /* 1548c2ecf20Sopenharmony_ci * uP clears EQ contexts when the connection exits rdma mode, 1558c2ecf20Sopenharmony_ci * so no need to post a RESET WR for these EQs. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci dealloc_sq(rdev, &wq->sq); 1588c2ecf20Sopenharmony_ci kfree(wq->sq.sw_sq); 1598c2ecf20Sopenharmony_ci c4iw_put_qpid(rdev, wq->sq.qid, uctx); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (has_rq) { 1628c2ecf20Sopenharmony_ci dma_free_coherent(&rdev->lldi.pdev->dev, 1638c2ecf20Sopenharmony_ci wq->rq.memsize, wq->rq.queue, 1648c2ecf20Sopenharmony_ci dma_unmap_addr(&wq->rq, mapping)); 1658c2ecf20Sopenharmony_ci c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size); 1668c2ecf20Sopenharmony_ci kfree(wq->rq.sw_rq); 1678c2ecf20Sopenharmony_ci c4iw_put_qpid(rdev, wq->rq.qid, uctx); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* 1738c2ecf20Sopenharmony_ci * Determine the BAR2 virtual address and qid. If pbar2_pa is not NULL, 1748c2ecf20Sopenharmony_ci * then this is a user mapping so compute the page-aligned physical address 1758c2ecf20Sopenharmony_ci * for mapping. 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_civoid __iomem *c4iw_bar2_addrs(struct c4iw_rdev *rdev, unsigned int qid, 1788c2ecf20Sopenharmony_ci enum cxgb4_bar2_qtype qtype, 1798c2ecf20Sopenharmony_ci unsigned int *pbar2_qid, u64 *pbar2_pa) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci u64 bar2_qoffset; 1828c2ecf20Sopenharmony_ci int ret; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci ret = cxgb4_bar2_sge_qregs(rdev->lldi.ports[0], qid, qtype, 1858c2ecf20Sopenharmony_ci pbar2_pa ? 1 : 0, 1868c2ecf20Sopenharmony_ci &bar2_qoffset, pbar2_qid); 1878c2ecf20Sopenharmony_ci if (ret) 1888c2ecf20Sopenharmony_ci return NULL; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (pbar2_pa) 1918c2ecf20Sopenharmony_ci *pbar2_pa = (rdev->bar2_pa + bar2_qoffset) & PAGE_MASK; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (is_t4(rdev->lldi.adapter_type)) 1948c2ecf20Sopenharmony_ci return NULL; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci return rdev->bar2_kva + bar2_qoffset; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, 2008c2ecf20Sopenharmony_ci struct t4_cq *rcq, struct t4_cq *scq, 2018c2ecf20Sopenharmony_ci struct c4iw_dev_ucontext *uctx, 2028c2ecf20Sopenharmony_ci struct c4iw_wr_wait *wr_waitp, 2038c2ecf20Sopenharmony_ci int need_rq) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci int user = (uctx != &rdev->uctx); 2068c2ecf20Sopenharmony_ci struct fw_ri_res_wr *res_wr; 2078c2ecf20Sopenharmony_ci struct fw_ri_res *res; 2088c2ecf20Sopenharmony_ci int wr_len; 2098c2ecf20Sopenharmony_ci struct sk_buff *skb; 2108c2ecf20Sopenharmony_ci int ret = 0; 2118c2ecf20Sopenharmony_ci int eqsize; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci wq->sq.qid = c4iw_get_qpid(rdev, uctx); 2148c2ecf20Sopenharmony_ci if (!wq->sq.qid) 2158c2ecf20Sopenharmony_ci return -ENOMEM; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (need_rq) { 2188c2ecf20Sopenharmony_ci wq->rq.qid = c4iw_get_qpid(rdev, uctx); 2198c2ecf20Sopenharmony_ci if (!wq->rq.qid) { 2208c2ecf20Sopenharmony_ci ret = -ENOMEM; 2218c2ecf20Sopenharmony_ci goto free_sq_qid; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (!user) { 2268c2ecf20Sopenharmony_ci wq->sq.sw_sq = kcalloc(wq->sq.size, sizeof(*wq->sq.sw_sq), 2278c2ecf20Sopenharmony_ci GFP_KERNEL); 2288c2ecf20Sopenharmony_ci if (!wq->sq.sw_sq) { 2298c2ecf20Sopenharmony_ci ret = -ENOMEM; 2308c2ecf20Sopenharmony_ci goto free_rq_qid;//FIXME 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (need_rq) { 2348c2ecf20Sopenharmony_ci wq->rq.sw_rq = kcalloc(wq->rq.size, 2358c2ecf20Sopenharmony_ci sizeof(*wq->rq.sw_rq), 2368c2ecf20Sopenharmony_ci GFP_KERNEL); 2378c2ecf20Sopenharmony_ci if (!wq->rq.sw_rq) { 2388c2ecf20Sopenharmony_ci ret = -ENOMEM; 2398c2ecf20Sopenharmony_ci goto free_sw_sq; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (need_rq) { 2458c2ecf20Sopenharmony_ci /* 2468c2ecf20Sopenharmony_ci * RQT must be a power of 2 and at least 16 deep. 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci wq->rq.rqt_size = 2498c2ecf20Sopenharmony_ci roundup_pow_of_two(max_t(u16, wq->rq.size, 16)); 2508c2ecf20Sopenharmony_ci wq->rq.rqt_hwaddr = c4iw_rqtpool_alloc(rdev, wq->rq.rqt_size); 2518c2ecf20Sopenharmony_ci if (!wq->rq.rqt_hwaddr) { 2528c2ecf20Sopenharmony_ci ret = -ENOMEM; 2538c2ecf20Sopenharmony_ci goto free_sw_rq; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci ret = alloc_sq(rdev, &wq->sq, user); 2588c2ecf20Sopenharmony_ci if (ret) 2598c2ecf20Sopenharmony_ci goto free_hwaddr; 2608c2ecf20Sopenharmony_ci memset(wq->sq.queue, 0, wq->sq.memsize); 2618c2ecf20Sopenharmony_ci dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (need_rq) { 2648c2ecf20Sopenharmony_ci wq->rq.queue = dma_alloc_coherent(&rdev->lldi.pdev->dev, 2658c2ecf20Sopenharmony_ci wq->rq.memsize, 2668c2ecf20Sopenharmony_ci &wq->rq.dma_addr, 2678c2ecf20Sopenharmony_ci GFP_KERNEL); 2688c2ecf20Sopenharmony_ci if (!wq->rq.queue) { 2698c2ecf20Sopenharmony_ci ret = -ENOMEM; 2708c2ecf20Sopenharmony_ci goto free_sq; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci pr_debug("sq base va 0x%p pa 0x%llx rq base va 0x%p pa 0x%llx\n", 2738c2ecf20Sopenharmony_ci wq->sq.queue, 2748c2ecf20Sopenharmony_ci (unsigned long long)virt_to_phys(wq->sq.queue), 2758c2ecf20Sopenharmony_ci wq->rq.queue, 2768c2ecf20Sopenharmony_ci (unsigned long long)virt_to_phys(wq->rq.queue)); 2778c2ecf20Sopenharmony_ci dma_unmap_addr_set(&wq->rq, mapping, wq->rq.dma_addr); 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci wq->db = rdev->lldi.db_reg; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci wq->sq.bar2_va = c4iw_bar2_addrs(rdev, wq->sq.qid, 2838c2ecf20Sopenharmony_ci CXGB4_BAR2_QTYPE_EGRESS, 2848c2ecf20Sopenharmony_ci &wq->sq.bar2_qid, 2858c2ecf20Sopenharmony_ci user ? &wq->sq.bar2_pa : NULL); 2868c2ecf20Sopenharmony_ci if (need_rq) 2878c2ecf20Sopenharmony_ci wq->rq.bar2_va = c4iw_bar2_addrs(rdev, wq->rq.qid, 2888c2ecf20Sopenharmony_ci CXGB4_BAR2_QTYPE_EGRESS, 2898c2ecf20Sopenharmony_ci &wq->rq.bar2_qid, 2908c2ecf20Sopenharmony_ci user ? &wq->rq.bar2_pa : NULL); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* 2938c2ecf20Sopenharmony_ci * User mode must have bar2 access. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci if (user && (!wq->sq.bar2_pa || (need_rq && !wq->rq.bar2_pa))) { 2968c2ecf20Sopenharmony_ci pr_warn("%s: sqid %u or rqid %u not in BAR2 range\n", 2978c2ecf20Sopenharmony_ci pci_name(rdev->lldi.pdev), wq->sq.qid, wq->rq.qid); 2988c2ecf20Sopenharmony_ci ret = -EINVAL; 2998c2ecf20Sopenharmony_ci goto free_dma; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci wq->rdev = rdev; 3038c2ecf20Sopenharmony_ci wq->rq.msn = 1; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* build fw_ri_res_wr */ 3068c2ecf20Sopenharmony_ci wr_len = sizeof(*res_wr) + 2 * sizeof(*res); 3078c2ecf20Sopenharmony_ci if (need_rq) 3088c2ecf20Sopenharmony_ci wr_len += sizeof(*res); 3098c2ecf20Sopenharmony_ci skb = alloc_skb(wr_len, GFP_KERNEL); 3108c2ecf20Sopenharmony_ci if (!skb) { 3118c2ecf20Sopenharmony_ci ret = -ENOMEM; 3128c2ecf20Sopenharmony_ci goto free_dma; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci res_wr = __skb_put_zero(skb, wr_len); 3178c2ecf20Sopenharmony_ci res_wr->op_nres = cpu_to_be32( 3188c2ecf20Sopenharmony_ci FW_WR_OP_V(FW_RI_RES_WR) | 3198c2ecf20Sopenharmony_ci FW_RI_RES_WR_NRES_V(need_rq ? 2 : 1) | 3208c2ecf20Sopenharmony_ci FW_WR_COMPL_F); 3218c2ecf20Sopenharmony_ci res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); 3228c2ecf20Sopenharmony_ci res_wr->cookie = (uintptr_t)wr_waitp; 3238c2ecf20Sopenharmony_ci res = res_wr->res; 3248c2ecf20Sopenharmony_ci res->u.sqrq.restype = FW_RI_RES_TYPE_SQ; 3258c2ecf20Sopenharmony_ci res->u.sqrq.op = FW_RI_RES_OP_WRITE; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* 3288c2ecf20Sopenharmony_ci * eqsize is the number of 64B entries plus the status page size. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci eqsize = wq->sq.size * T4_SQ_NUM_SLOTS + 3318c2ecf20Sopenharmony_ci rdev->hw_queue.t4_eq_status_entries; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci res->u.sqrq.fetchszm_to_iqid = cpu_to_be32( 3348c2ecf20Sopenharmony_ci FW_RI_RES_WR_HOSTFCMODE_V(0) | /* no host cidx updates */ 3358c2ecf20Sopenharmony_ci FW_RI_RES_WR_CPRIO_V(0) | /* don't keep in chip cache */ 3368c2ecf20Sopenharmony_ci FW_RI_RES_WR_PCIECHN_V(0) | /* set by uP at ri_init time */ 3378c2ecf20Sopenharmony_ci (t4_sq_onchip(&wq->sq) ? FW_RI_RES_WR_ONCHIP_F : 0) | 3388c2ecf20Sopenharmony_ci FW_RI_RES_WR_IQID_V(scq->cqid)); 3398c2ecf20Sopenharmony_ci res->u.sqrq.dcaen_to_eqsize = cpu_to_be32( 3408c2ecf20Sopenharmony_ci FW_RI_RES_WR_DCAEN_V(0) | 3418c2ecf20Sopenharmony_ci FW_RI_RES_WR_DCACPU_V(0) | 3428c2ecf20Sopenharmony_ci FW_RI_RES_WR_FBMIN_V(2) | 3438c2ecf20Sopenharmony_ci (t4_sq_onchip(&wq->sq) ? FW_RI_RES_WR_FBMAX_V(2) : 3448c2ecf20Sopenharmony_ci FW_RI_RES_WR_FBMAX_V(3)) | 3458c2ecf20Sopenharmony_ci FW_RI_RES_WR_CIDXFTHRESHO_V(0) | 3468c2ecf20Sopenharmony_ci FW_RI_RES_WR_CIDXFTHRESH_V(0) | 3478c2ecf20Sopenharmony_ci FW_RI_RES_WR_EQSIZE_V(eqsize)); 3488c2ecf20Sopenharmony_ci res->u.sqrq.eqid = cpu_to_be32(wq->sq.qid); 3498c2ecf20Sopenharmony_ci res->u.sqrq.eqaddr = cpu_to_be64(wq->sq.dma_addr); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (need_rq) { 3528c2ecf20Sopenharmony_ci res++; 3538c2ecf20Sopenharmony_ci res->u.sqrq.restype = FW_RI_RES_TYPE_RQ; 3548c2ecf20Sopenharmony_ci res->u.sqrq.op = FW_RI_RES_OP_WRITE; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* 3578c2ecf20Sopenharmony_ci * eqsize is the number of 64B entries plus the status page size 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_ci eqsize = wq->rq.size * T4_RQ_NUM_SLOTS + 3608c2ecf20Sopenharmony_ci rdev->hw_queue.t4_eq_status_entries; 3618c2ecf20Sopenharmony_ci res->u.sqrq.fetchszm_to_iqid = 3628c2ecf20Sopenharmony_ci /* no host cidx updates */ 3638c2ecf20Sopenharmony_ci cpu_to_be32(FW_RI_RES_WR_HOSTFCMODE_V(0) | 3648c2ecf20Sopenharmony_ci /* don't keep in chip cache */ 3658c2ecf20Sopenharmony_ci FW_RI_RES_WR_CPRIO_V(0) | 3668c2ecf20Sopenharmony_ci /* set by uP at ri_init time */ 3678c2ecf20Sopenharmony_ci FW_RI_RES_WR_PCIECHN_V(0) | 3688c2ecf20Sopenharmony_ci FW_RI_RES_WR_IQID_V(rcq->cqid)); 3698c2ecf20Sopenharmony_ci res->u.sqrq.dcaen_to_eqsize = 3708c2ecf20Sopenharmony_ci cpu_to_be32(FW_RI_RES_WR_DCAEN_V(0) | 3718c2ecf20Sopenharmony_ci FW_RI_RES_WR_DCACPU_V(0) | 3728c2ecf20Sopenharmony_ci FW_RI_RES_WR_FBMIN_V(2) | 3738c2ecf20Sopenharmony_ci FW_RI_RES_WR_FBMAX_V(3) | 3748c2ecf20Sopenharmony_ci FW_RI_RES_WR_CIDXFTHRESHO_V(0) | 3758c2ecf20Sopenharmony_ci FW_RI_RES_WR_CIDXFTHRESH_V(0) | 3768c2ecf20Sopenharmony_ci FW_RI_RES_WR_EQSIZE_V(eqsize)); 3778c2ecf20Sopenharmony_ci res->u.sqrq.eqid = cpu_to_be32(wq->rq.qid); 3788c2ecf20Sopenharmony_ci res->u.sqrq.eqaddr = cpu_to_be64(wq->rq.dma_addr); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci c4iw_init_wr_wait(wr_waitp); 3828c2ecf20Sopenharmony_ci ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, wq->sq.qid, __func__); 3838c2ecf20Sopenharmony_ci if (ret) 3848c2ecf20Sopenharmony_ci goto free_dma; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci pr_debug("sqid 0x%x rqid 0x%x kdb 0x%p sq_bar2_addr %p rq_bar2_addr %p\n", 3878c2ecf20Sopenharmony_ci wq->sq.qid, wq->rq.qid, wq->db, 3888c2ecf20Sopenharmony_ci wq->sq.bar2_va, wq->rq.bar2_va); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return 0; 3918c2ecf20Sopenharmony_cifree_dma: 3928c2ecf20Sopenharmony_ci if (need_rq) 3938c2ecf20Sopenharmony_ci dma_free_coherent(&rdev->lldi.pdev->dev, 3948c2ecf20Sopenharmony_ci wq->rq.memsize, wq->rq.queue, 3958c2ecf20Sopenharmony_ci dma_unmap_addr(&wq->rq, mapping)); 3968c2ecf20Sopenharmony_cifree_sq: 3978c2ecf20Sopenharmony_ci dealloc_sq(rdev, &wq->sq); 3988c2ecf20Sopenharmony_cifree_hwaddr: 3998c2ecf20Sopenharmony_ci if (need_rq) 4008c2ecf20Sopenharmony_ci c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size); 4018c2ecf20Sopenharmony_cifree_sw_rq: 4028c2ecf20Sopenharmony_ci if (need_rq) 4038c2ecf20Sopenharmony_ci kfree(wq->rq.sw_rq); 4048c2ecf20Sopenharmony_cifree_sw_sq: 4058c2ecf20Sopenharmony_ci kfree(wq->sq.sw_sq); 4068c2ecf20Sopenharmony_cifree_rq_qid: 4078c2ecf20Sopenharmony_ci if (need_rq) 4088c2ecf20Sopenharmony_ci c4iw_put_qpid(rdev, wq->rq.qid, uctx); 4098c2ecf20Sopenharmony_cifree_sq_qid: 4108c2ecf20Sopenharmony_ci c4iw_put_qpid(rdev, wq->sq.qid, uctx); 4118c2ecf20Sopenharmony_ci return ret; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int build_immd(struct t4_sq *sq, struct fw_ri_immd *immdp, 4158c2ecf20Sopenharmony_ci const struct ib_send_wr *wr, int max, u32 *plenp) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci u8 *dstp, *srcp; 4188c2ecf20Sopenharmony_ci u32 plen = 0; 4198c2ecf20Sopenharmony_ci int i; 4208c2ecf20Sopenharmony_ci int rem, len; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci dstp = (u8 *)immdp->data; 4238c2ecf20Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 4248c2ecf20Sopenharmony_ci if ((plen + wr->sg_list[i].length) > max) 4258c2ecf20Sopenharmony_ci return -EMSGSIZE; 4268c2ecf20Sopenharmony_ci srcp = (u8 *)(unsigned long)wr->sg_list[i].addr; 4278c2ecf20Sopenharmony_ci plen += wr->sg_list[i].length; 4288c2ecf20Sopenharmony_ci rem = wr->sg_list[i].length; 4298c2ecf20Sopenharmony_ci while (rem) { 4308c2ecf20Sopenharmony_ci if (dstp == (u8 *)&sq->queue[sq->size]) 4318c2ecf20Sopenharmony_ci dstp = (u8 *)sq->queue; 4328c2ecf20Sopenharmony_ci if (rem <= (u8 *)&sq->queue[sq->size] - dstp) 4338c2ecf20Sopenharmony_ci len = rem; 4348c2ecf20Sopenharmony_ci else 4358c2ecf20Sopenharmony_ci len = (u8 *)&sq->queue[sq->size] - dstp; 4368c2ecf20Sopenharmony_ci memcpy(dstp, srcp, len); 4378c2ecf20Sopenharmony_ci dstp += len; 4388c2ecf20Sopenharmony_ci srcp += len; 4398c2ecf20Sopenharmony_ci rem -= len; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci len = roundup(plen + sizeof(*immdp), 16) - (plen + sizeof(*immdp)); 4438c2ecf20Sopenharmony_ci if (len) 4448c2ecf20Sopenharmony_ci memset(dstp, 0, len); 4458c2ecf20Sopenharmony_ci immdp->op = FW_RI_DATA_IMMD; 4468c2ecf20Sopenharmony_ci immdp->r1 = 0; 4478c2ecf20Sopenharmony_ci immdp->r2 = 0; 4488c2ecf20Sopenharmony_ci immdp->immdlen = cpu_to_be32(plen); 4498c2ecf20Sopenharmony_ci *plenp = plen; 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic int build_isgl(__be64 *queue_start, __be64 *queue_end, 4548c2ecf20Sopenharmony_ci struct fw_ri_isgl *isglp, struct ib_sge *sg_list, 4558c2ecf20Sopenharmony_ci int num_sge, u32 *plenp) 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci int i; 4598c2ecf20Sopenharmony_ci u32 plen = 0; 4608c2ecf20Sopenharmony_ci __be64 *flitp; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if ((__be64 *)isglp == queue_end) 4638c2ecf20Sopenharmony_ci isglp = (struct fw_ri_isgl *)queue_start; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci flitp = (__be64 *)isglp->sge; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci for (i = 0; i < num_sge; i++) { 4688c2ecf20Sopenharmony_ci if ((plen + sg_list[i].length) < plen) 4698c2ecf20Sopenharmony_ci return -EMSGSIZE; 4708c2ecf20Sopenharmony_ci plen += sg_list[i].length; 4718c2ecf20Sopenharmony_ci *flitp = cpu_to_be64(((u64)sg_list[i].lkey << 32) | 4728c2ecf20Sopenharmony_ci sg_list[i].length); 4738c2ecf20Sopenharmony_ci if (++flitp == queue_end) 4748c2ecf20Sopenharmony_ci flitp = queue_start; 4758c2ecf20Sopenharmony_ci *flitp = cpu_to_be64(sg_list[i].addr); 4768c2ecf20Sopenharmony_ci if (++flitp == queue_end) 4778c2ecf20Sopenharmony_ci flitp = queue_start; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci *flitp = (__force __be64)0; 4808c2ecf20Sopenharmony_ci isglp->op = FW_RI_DATA_ISGL; 4818c2ecf20Sopenharmony_ci isglp->r1 = 0; 4828c2ecf20Sopenharmony_ci isglp->nsge = cpu_to_be16(num_sge); 4838c2ecf20Sopenharmony_ci isglp->r2 = 0; 4848c2ecf20Sopenharmony_ci if (plenp) 4858c2ecf20Sopenharmony_ci *plenp = plen; 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic int build_rdma_send(struct t4_sq *sq, union t4_wr *wqe, 4908c2ecf20Sopenharmony_ci const struct ib_send_wr *wr, u8 *len16) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci u32 plen; 4938c2ecf20Sopenharmony_ci int size; 4948c2ecf20Sopenharmony_ci int ret; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (wr->num_sge > T4_MAX_SEND_SGE) 4978c2ecf20Sopenharmony_ci return -EINVAL; 4988c2ecf20Sopenharmony_ci switch (wr->opcode) { 4998c2ecf20Sopenharmony_ci case IB_WR_SEND: 5008c2ecf20Sopenharmony_ci if (wr->send_flags & IB_SEND_SOLICITED) 5018c2ecf20Sopenharmony_ci wqe->send.sendop_pkd = cpu_to_be32( 5028c2ecf20Sopenharmony_ci FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_SE)); 5038c2ecf20Sopenharmony_ci else 5048c2ecf20Sopenharmony_ci wqe->send.sendop_pkd = cpu_to_be32( 5058c2ecf20Sopenharmony_ci FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND)); 5068c2ecf20Sopenharmony_ci wqe->send.stag_inv = 0; 5078c2ecf20Sopenharmony_ci break; 5088c2ecf20Sopenharmony_ci case IB_WR_SEND_WITH_INV: 5098c2ecf20Sopenharmony_ci if (wr->send_flags & IB_SEND_SOLICITED) 5108c2ecf20Sopenharmony_ci wqe->send.sendop_pkd = cpu_to_be32( 5118c2ecf20Sopenharmony_ci FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_SE_INV)); 5128c2ecf20Sopenharmony_ci else 5138c2ecf20Sopenharmony_ci wqe->send.sendop_pkd = cpu_to_be32( 5148c2ecf20Sopenharmony_ci FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_INV)); 5158c2ecf20Sopenharmony_ci wqe->send.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey); 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci default: 5198c2ecf20Sopenharmony_ci return -EINVAL; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci wqe->send.r3 = 0; 5228c2ecf20Sopenharmony_ci wqe->send.r4 = 0; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci plen = 0; 5258c2ecf20Sopenharmony_ci if (wr->num_sge) { 5268c2ecf20Sopenharmony_ci if (wr->send_flags & IB_SEND_INLINE) { 5278c2ecf20Sopenharmony_ci ret = build_immd(sq, wqe->send.u.immd_src, wr, 5288c2ecf20Sopenharmony_ci T4_MAX_SEND_INLINE, &plen); 5298c2ecf20Sopenharmony_ci if (ret) 5308c2ecf20Sopenharmony_ci return ret; 5318c2ecf20Sopenharmony_ci size = sizeof(wqe->send) + sizeof(struct fw_ri_immd) + 5328c2ecf20Sopenharmony_ci plen; 5338c2ecf20Sopenharmony_ci } else { 5348c2ecf20Sopenharmony_ci ret = build_isgl((__be64 *)sq->queue, 5358c2ecf20Sopenharmony_ci (__be64 *)&sq->queue[sq->size], 5368c2ecf20Sopenharmony_ci wqe->send.u.isgl_src, 5378c2ecf20Sopenharmony_ci wr->sg_list, wr->num_sge, &plen); 5388c2ecf20Sopenharmony_ci if (ret) 5398c2ecf20Sopenharmony_ci return ret; 5408c2ecf20Sopenharmony_ci size = sizeof(wqe->send) + sizeof(struct fw_ri_isgl) + 5418c2ecf20Sopenharmony_ci wr->num_sge * sizeof(struct fw_ri_sge); 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci } else { 5448c2ecf20Sopenharmony_ci wqe->send.u.immd_src[0].op = FW_RI_DATA_IMMD; 5458c2ecf20Sopenharmony_ci wqe->send.u.immd_src[0].r1 = 0; 5468c2ecf20Sopenharmony_ci wqe->send.u.immd_src[0].r2 = 0; 5478c2ecf20Sopenharmony_ci wqe->send.u.immd_src[0].immdlen = 0; 5488c2ecf20Sopenharmony_ci size = sizeof(wqe->send) + sizeof(struct fw_ri_immd); 5498c2ecf20Sopenharmony_ci plen = 0; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci *len16 = DIV_ROUND_UP(size, 16); 5528c2ecf20Sopenharmony_ci wqe->send.plen = cpu_to_be32(plen); 5538c2ecf20Sopenharmony_ci return 0; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic int build_rdma_write(struct t4_sq *sq, union t4_wr *wqe, 5578c2ecf20Sopenharmony_ci const struct ib_send_wr *wr, u8 *len16) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci u32 plen; 5608c2ecf20Sopenharmony_ci int size; 5618c2ecf20Sopenharmony_ci int ret; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (wr->num_sge > T4_MAX_SEND_SGE) 5648c2ecf20Sopenharmony_ci return -EINVAL; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* 5678c2ecf20Sopenharmony_ci * iWARP protocol supports 64 bit immediate data but rdma api 5688c2ecf20Sopenharmony_ci * limits it to 32bit. 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_ci if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) 5718c2ecf20Sopenharmony_ci wqe->write.iw_imm_data.ib_imm_data.imm_data32 = wr->ex.imm_data; 5728c2ecf20Sopenharmony_ci else 5738c2ecf20Sopenharmony_ci wqe->write.iw_imm_data.ib_imm_data.imm_data32 = 0; 5748c2ecf20Sopenharmony_ci wqe->write.stag_sink = cpu_to_be32(rdma_wr(wr)->rkey); 5758c2ecf20Sopenharmony_ci wqe->write.to_sink = cpu_to_be64(rdma_wr(wr)->remote_addr); 5768c2ecf20Sopenharmony_ci if (wr->num_sge) { 5778c2ecf20Sopenharmony_ci if (wr->send_flags & IB_SEND_INLINE) { 5788c2ecf20Sopenharmony_ci ret = build_immd(sq, wqe->write.u.immd_src, wr, 5798c2ecf20Sopenharmony_ci T4_MAX_WRITE_INLINE, &plen); 5808c2ecf20Sopenharmony_ci if (ret) 5818c2ecf20Sopenharmony_ci return ret; 5828c2ecf20Sopenharmony_ci size = sizeof(wqe->write) + sizeof(struct fw_ri_immd) + 5838c2ecf20Sopenharmony_ci plen; 5848c2ecf20Sopenharmony_ci } else { 5858c2ecf20Sopenharmony_ci ret = build_isgl((__be64 *)sq->queue, 5868c2ecf20Sopenharmony_ci (__be64 *)&sq->queue[sq->size], 5878c2ecf20Sopenharmony_ci wqe->write.u.isgl_src, 5888c2ecf20Sopenharmony_ci wr->sg_list, wr->num_sge, &plen); 5898c2ecf20Sopenharmony_ci if (ret) 5908c2ecf20Sopenharmony_ci return ret; 5918c2ecf20Sopenharmony_ci size = sizeof(wqe->write) + sizeof(struct fw_ri_isgl) + 5928c2ecf20Sopenharmony_ci wr->num_sge * sizeof(struct fw_ri_sge); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci } else { 5958c2ecf20Sopenharmony_ci wqe->write.u.immd_src[0].op = FW_RI_DATA_IMMD; 5968c2ecf20Sopenharmony_ci wqe->write.u.immd_src[0].r1 = 0; 5978c2ecf20Sopenharmony_ci wqe->write.u.immd_src[0].r2 = 0; 5988c2ecf20Sopenharmony_ci wqe->write.u.immd_src[0].immdlen = 0; 5998c2ecf20Sopenharmony_ci size = sizeof(wqe->write) + sizeof(struct fw_ri_immd); 6008c2ecf20Sopenharmony_ci plen = 0; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci *len16 = DIV_ROUND_UP(size, 16); 6038c2ecf20Sopenharmony_ci wqe->write.plen = cpu_to_be32(plen); 6048c2ecf20Sopenharmony_ci return 0; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic void build_immd_cmpl(struct t4_sq *sq, struct fw_ri_immd_cmpl *immdp, 6088c2ecf20Sopenharmony_ci struct ib_send_wr *wr) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci memcpy((u8 *)immdp->data, (u8 *)(uintptr_t)wr->sg_list->addr, 16); 6118c2ecf20Sopenharmony_ci memset(immdp->r1, 0, 6); 6128c2ecf20Sopenharmony_ci immdp->op = FW_RI_DATA_IMMD; 6138c2ecf20Sopenharmony_ci immdp->immdlen = 16; 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic void build_rdma_write_cmpl(struct t4_sq *sq, 6178c2ecf20Sopenharmony_ci struct fw_ri_rdma_write_cmpl_wr *wcwr, 6188c2ecf20Sopenharmony_ci const struct ib_send_wr *wr, u8 *len16) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci u32 plen; 6218c2ecf20Sopenharmony_ci int size; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* 6248c2ecf20Sopenharmony_ci * This code assumes the struct fields preceding the write isgl 6258c2ecf20Sopenharmony_ci * fit in one 64B WR slot. This is because the WQE is built 6268c2ecf20Sopenharmony_ci * directly in the dma queue, and wrapping is only handled 6278c2ecf20Sopenharmony_ci * by the code buildling sgls. IE the "fixed part" of the wr 6288c2ecf20Sopenharmony_ci * structs must all fit in 64B. The WQE build code should probably be 6298c2ecf20Sopenharmony_ci * redesigned to avoid this restriction, but for now just add 6308c2ecf20Sopenharmony_ci * the BUILD_BUG_ON() to catch if this WQE struct gets too big. 6318c2ecf20Sopenharmony_ci */ 6328c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct fw_ri_rdma_write_cmpl_wr, u) > 64); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci wcwr->stag_sink = cpu_to_be32(rdma_wr(wr)->rkey); 6358c2ecf20Sopenharmony_ci wcwr->to_sink = cpu_to_be64(rdma_wr(wr)->remote_addr); 6368c2ecf20Sopenharmony_ci if (wr->next->opcode == IB_WR_SEND) 6378c2ecf20Sopenharmony_ci wcwr->stag_inv = 0; 6388c2ecf20Sopenharmony_ci else 6398c2ecf20Sopenharmony_ci wcwr->stag_inv = cpu_to_be32(wr->next->ex.invalidate_rkey); 6408c2ecf20Sopenharmony_ci wcwr->r2 = 0; 6418c2ecf20Sopenharmony_ci wcwr->r3 = 0; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* SEND_INV SGL */ 6448c2ecf20Sopenharmony_ci if (wr->next->send_flags & IB_SEND_INLINE) 6458c2ecf20Sopenharmony_ci build_immd_cmpl(sq, &wcwr->u_cmpl.immd_src, wr->next); 6468c2ecf20Sopenharmony_ci else 6478c2ecf20Sopenharmony_ci build_isgl((__be64 *)sq->queue, (__be64 *)&sq->queue[sq->size], 6488c2ecf20Sopenharmony_ci &wcwr->u_cmpl.isgl_src, wr->next->sg_list, 1, NULL); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* WRITE SGL */ 6518c2ecf20Sopenharmony_ci build_isgl((__be64 *)sq->queue, (__be64 *)&sq->queue[sq->size], 6528c2ecf20Sopenharmony_ci wcwr->u.isgl_src, wr->sg_list, wr->num_sge, &plen); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci size = sizeof(*wcwr) + sizeof(struct fw_ri_isgl) + 6558c2ecf20Sopenharmony_ci wr->num_sge * sizeof(struct fw_ri_sge); 6568c2ecf20Sopenharmony_ci wcwr->plen = cpu_to_be32(plen); 6578c2ecf20Sopenharmony_ci *len16 = DIV_ROUND_UP(size, 16); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic int build_rdma_read(union t4_wr *wqe, const struct ib_send_wr *wr, 6618c2ecf20Sopenharmony_ci u8 *len16) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci if (wr->num_sge > 1) 6648c2ecf20Sopenharmony_ci return -EINVAL; 6658c2ecf20Sopenharmony_ci if (wr->num_sge && wr->sg_list[0].length) { 6668c2ecf20Sopenharmony_ci wqe->read.stag_src = cpu_to_be32(rdma_wr(wr)->rkey); 6678c2ecf20Sopenharmony_ci wqe->read.to_src_hi = cpu_to_be32((u32)(rdma_wr(wr)->remote_addr 6688c2ecf20Sopenharmony_ci >> 32)); 6698c2ecf20Sopenharmony_ci wqe->read.to_src_lo = cpu_to_be32((u32)rdma_wr(wr)->remote_addr); 6708c2ecf20Sopenharmony_ci wqe->read.stag_sink = cpu_to_be32(wr->sg_list[0].lkey); 6718c2ecf20Sopenharmony_ci wqe->read.plen = cpu_to_be32(wr->sg_list[0].length); 6728c2ecf20Sopenharmony_ci wqe->read.to_sink_hi = cpu_to_be32((u32)(wr->sg_list[0].addr 6738c2ecf20Sopenharmony_ci >> 32)); 6748c2ecf20Sopenharmony_ci wqe->read.to_sink_lo = cpu_to_be32((u32)(wr->sg_list[0].addr)); 6758c2ecf20Sopenharmony_ci } else { 6768c2ecf20Sopenharmony_ci wqe->read.stag_src = cpu_to_be32(2); 6778c2ecf20Sopenharmony_ci wqe->read.to_src_hi = 0; 6788c2ecf20Sopenharmony_ci wqe->read.to_src_lo = 0; 6798c2ecf20Sopenharmony_ci wqe->read.stag_sink = cpu_to_be32(2); 6808c2ecf20Sopenharmony_ci wqe->read.plen = 0; 6818c2ecf20Sopenharmony_ci wqe->read.to_sink_hi = 0; 6828c2ecf20Sopenharmony_ci wqe->read.to_sink_lo = 0; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci wqe->read.r2 = 0; 6858c2ecf20Sopenharmony_ci wqe->read.r5 = 0; 6868c2ecf20Sopenharmony_ci *len16 = DIV_ROUND_UP(sizeof(wqe->read), 16); 6878c2ecf20Sopenharmony_ci return 0; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic void post_write_cmpl(struct c4iw_qp *qhp, const struct ib_send_wr *wr) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci bool send_signaled = (wr->next->send_flags & IB_SEND_SIGNALED) || 6938c2ecf20Sopenharmony_ci qhp->sq_sig_all; 6948c2ecf20Sopenharmony_ci bool write_signaled = (wr->send_flags & IB_SEND_SIGNALED) || 6958c2ecf20Sopenharmony_ci qhp->sq_sig_all; 6968c2ecf20Sopenharmony_ci struct t4_swsqe *swsqe; 6978c2ecf20Sopenharmony_ci union t4_wr *wqe; 6988c2ecf20Sopenharmony_ci u16 write_wrid; 6998c2ecf20Sopenharmony_ci u8 len16; 7008c2ecf20Sopenharmony_ci u16 idx; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* 7038c2ecf20Sopenharmony_ci * The sw_sq entries still look like a WRITE and a SEND and consume 7048c2ecf20Sopenharmony_ci * 2 slots. The FW WR, however, will be a single uber-WR. 7058c2ecf20Sopenharmony_ci */ 7068c2ecf20Sopenharmony_ci wqe = (union t4_wr *)((u8 *)qhp->wq.sq.queue + 7078c2ecf20Sopenharmony_ci qhp->wq.sq.wq_pidx * T4_EQ_ENTRY_SIZE); 7088c2ecf20Sopenharmony_ci build_rdma_write_cmpl(&qhp->wq.sq, &wqe->write_cmpl, wr, &len16); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* WRITE swsqe */ 7118c2ecf20Sopenharmony_ci swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx]; 7128c2ecf20Sopenharmony_ci swsqe->opcode = FW_RI_RDMA_WRITE; 7138c2ecf20Sopenharmony_ci swsqe->idx = qhp->wq.sq.pidx; 7148c2ecf20Sopenharmony_ci swsqe->complete = 0; 7158c2ecf20Sopenharmony_ci swsqe->signaled = write_signaled; 7168c2ecf20Sopenharmony_ci swsqe->flushed = 0; 7178c2ecf20Sopenharmony_ci swsqe->wr_id = wr->wr_id; 7188c2ecf20Sopenharmony_ci if (c4iw_wr_log) { 7198c2ecf20Sopenharmony_ci swsqe->sge_ts = 7208c2ecf20Sopenharmony_ci cxgb4_read_sge_timestamp(qhp->rhp->rdev.lldi.ports[0]); 7218c2ecf20Sopenharmony_ci swsqe->host_time = ktime_get(); 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci write_wrid = qhp->wq.sq.pidx; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* just bump the sw_sq */ 7278c2ecf20Sopenharmony_ci qhp->wq.sq.in_use++; 7288c2ecf20Sopenharmony_ci if (++qhp->wq.sq.pidx == qhp->wq.sq.size) 7298c2ecf20Sopenharmony_ci qhp->wq.sq.pidx = 0; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* SEND_WITH_INV swsqe */ 7328c2ecf20Sopenharmony_ci swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx]; 7338c2ecf20Sopenharmony_ci if (wr->next->opcode == IB_WR_SEND) 7348c2ecf20Sopenharmony_ci swsqe->opcode = FW_RI_SEND; 7358c2ecf20Sopenharmony_ci else 7368c2ecf20Sopenharmony_ci swsqe->opcode = FW_RI_SEND_WITH_INV; 7378c2ecf20Sopenharmony_ci swsqe->idx = qhp->wq.sq.pidx; 7388c2ecf20Sopenharmony_ci swsqe->complete = 0; 7398c2ecf20Sopenharmony_ci swsqe->signaled = send_signaled; 7408c2ecf20Sopenharmony_ci swsqe->flushed = 0; 7418c2ecf20Sopenharmony_ci swsqe->wr_id = wr->next->wr_id; 7428c2ecf20Sopenharmony_ci if (c4iw_wr_log) { 7438c2ecf20Sopenharmony_ci swsqe->sge_ts = 7448c2ecf20Sopenharmony_ci cxgb4_read_sge_timestamp(qhp->rhp->rdev.lldi.ports[0]); 7458c2ecf20Sopenharmony_ci swsqe->host_time = ktime_get(); 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci wqe->write_cmpl.flags_send = send_signaled ? FW_RI_COMPLETION_FLAG : 0; 7498c2ecf20Sopenharmony_ci wqe->write_cmpl.wrid_send = qhp->wq.sq.pidx; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci init_wr_hdr(wqe, write_wrid, FW_RI_RDMA_WRITE_CMPL_WR, 7528c2ecf20Sopenharmony_ci write_signaled ? FW_RI_COMPLETION_FLAG : 0, len16); 7538c2ecf20Sopenharmony_ci t4_sq_produce(&qhp->wq, len16); 7548c2ecf20Sopenharmony_ci idx = DIV_ROUND_UP(len16 * 16, T4_EQ_ENTRY_SIZE); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci t4_ring_sq_db(&qhp->wq, idx, wqe); 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_cistatic int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe, 7608c2ecf20Sopenharmony_ci const struct ib_recv_wr *wr, u8 *len16) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci int ret; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci ret = build_isgl((__be64 *)qhp->wq.rq.queue, 7658c2ecf20Sopenharmony_ci (__be64 *)&qhp->wq.rq.queue[qhp->wq.rq.size], 7668c2ecf20Sopenharmony_ci &wqe->recv.isgl, wr->sg_list, wr->num_sge, NULL); 7678c2ecf20Sopenharmony_ci if (ret) 7688c2ecf20Sopenharmony_ci return ret; 7698c2ecf20Sopenharmony_ci *len16 = DIV_ROUND_UP( 7708c2ecf20Sopenharmony_ci sizeof(wqe->recv) + wr->num_sge * sizeof(struct fw_ri_sge), 16); 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int build_srq_recv(union t4_recv_wr *wqe, const struct ib_recv_wr *wr, 7758c2ecf20Sopenharmony_ci u8 *len16) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci int ret; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci ret = build_isgl((__be64 *)wqe, (__be64 *)(wqe + 1), 7808c2ecf20Sopenharmony_ci &wqe->recv.isgl, wr->sg_list, wr->num_sge, NULL); 7818c2ecf20Sopenharmony_ci if (ret) 7828c2ecf20Sopenharmony_ci return ret; 7838c2ecf20Sopenharmony_ci *len16 = DIV_ROUND_UP(sizeof(wqe->recv) + 7848c2ecf20Sopenharmony_ci wr->num_sge * sizeof(struct fw_ri_sge), 16); 7858c2ecf20Sopenharmony_ci return 0; 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_cistatic void build_tpte_memreg(struct fw_ri_fr_nsmr_tpte_wr *fr, 7898c2ecf20Sopenharmony_ci const struct ib_reg_wr *wr, struct c4iw_mr *mhp, 7908c2ecf20Sopenharmony_ci u8 *len16) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci __be64 *p = (__be64 *)fr->pbl; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci fr->r2 = cpu_to_be32(0); 7958c2ecf20Sopenharmony_ci fr->stag = cpu_to_be32(mhp->ibmr.rkey); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci fr->tpte.valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F | 7988c2ecf20Sopenharmony_ci FW_RI_TPTE_STAGKEY_V((mhp->ibmr.rkey & FW_RI_TPTE_STAGKEY_M)) | 7998c2ecf20Sopenharmony_ci FW_RI_TPTE_STAGSTATE_V(1) | 8008c2ecf20Sopenharmony_ci FW_RI_TPTE_STAGTYPE_V(FW_RI_STAG_NSMR) | 8018c2ecf20Sopenharmony_ci FW_RI_TPTE_PDID_V(mhp->attr.pdid)); 8028c2ecf20Sopenharmony_ci fr->tpte.locread_to_qpid = cpu_to_be32( 8038c2ecf20Sopenharmony_ci FW_RI_TPTE_PERM_V(c4iw_ib_to_tpt_access(wr->access)) | 8048c2ecf20Sopenharmony_ci FW_RI_TPTE_ADDRTYPE_V(FW_RI_VA_BASED_TO) | 8058c2ecf20Sopenharmony_ci FW_RI_TPTE_PS_V(ilog2(wr->mr->page_size) - 12)); 8068c2ecf20Sopenharmony_ci fr->tpte.nosnoop_pbladdr = cpu_to_be32(FW_RI_TPTE_PBLADDR_V( 8078c2ecf20Sopenharmony_ci PBL_OFF(&mhp->rhp->rdev, mhp->attr.pbl_addr)>>3)); 8088c2ecf20Sopenharmony_ci fr->tpte.dca_mwbcnt_pstag = cpu_to_be32(0); 8098c2ecf20Sopenharmony_ci fr->tpte.len_hi = cpu_to_be32(0); 8108c2ecf20Sopenharmony_ci fr->tpte.len_lo = cpu_to_be32(mhp->ibmr.length); 8118c2ecf20Sopenharmony_ci fr->tpte.va_hi = cpu_to_be32(mhp->ibmr.iova >> 32); 8128c2ecf20Sopenharmony_ci fr->tpte.va_lo_fbo = cpu_to_be32(mhp->ibmr.iova & 0xffffffff); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci p[0] = cpu_to_be64((u64)mhp->mpl[0]); 8158c2ecf20Sopenharmony_ci p[1] = cpu_to_be64((u64)mhp->mpl[1]); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci *len16 = DIV_ROUND_UP(sizeof(*fr), 16); 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_cistatic int build_memreg(struct t4_sq *sq, union t4_wr *wqe, 8218c2ecf20Sopenharmony_ci const struct ib_reg_wr *wr, struct c4iw_mr *mhp, 8228c2ecf20Sopenharmony_ci u8 *len16, bool dsgl_supported) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci struct fw_ri_immd *imdp; 8258c2ecf20Sopenharmony_ci __be64 *p; 8268c2ecf20Sopenharmony_ci int i; 8278c2ecf20Sopenharmony_ci int pbllen = roundup(mhp->mpl_len * sizeof(u64), 32); 8288c2ecf20Sopenharmony_ci int rem; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (mhp->mpl_len > t4_max_fr_depth(dsgl_supported && use_dsgl)) 8318c2ecf20Sopenharmony_ci return -EINVAL; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci wqe->fr.qpbinde_to_dcacpu = 0; 8348c2ecf20Sopenharmony_ci wqe->fr.pgsz_shift = ilog2(wr->mr->page_size) - 12; 8358c2ecf20Sopenharmony_ci wqe->fr.addr_type = FW_RI_VA_BASED_TO; 8368c2ecf20Sopenharmony_ci wqe->fr.mem_perms = c4iw_ib_to_tpt_access(wr->access); 8378c2ecf20Sopenharmony_ci wqe->fr.len_hi = 0; 8388c2ecf20Sopenharmony_ci wqe->fr.len_lo = cpu_to_be32(mhp->ibmr.length); 8398c2ecf20Sopenharmony_ci wqe->fr.stag = cpu_to_be32(wr->key); 8408c2ecf20Sopenharmony_ci wqe->fr.va_hi = cpu_to_be32(mhp->ibmr.iova >> 32); 8418c2ecf20Sopenharmony_ci wqe->fr.va_lo_fbo = cpu_to_be32(mhp->ibmr.iova & 8428c2ecf20Sopenharmony_ci 0xffffffff); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (dsgl_supported && use_dsgl && (pbllen > max_fr_immd)) { 8458c2ecf20Sopenharmony_ci struct fw_ri_dsgl *sglp; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci for (i = 0; i < mhp->mpl_len; i++) 8488c2ecf20Sopenharmony_ci mhp->mpl[i] = (__force u64)cpu_to_be64((u64)mhp->mpl[i]); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci sglp = (struct fw_ri_dsgl *)(&wqe->fr + 1); 8518c2ecf20Sopenharmony_ci sglp->op = FW_RI_DATA_DSGL; 8528c2ecf20Sopenharmony_ci sglp->r1 = 0; 8538c2ecf20Sopenharmony_ci sglp->nsge = cpu_to_be16(1); 8548c2ecf20Sopenharmony_ci sglp->addr0 = cpu_to_be64(mhp->mpl_addr); 8558c2ecf20Sopenharmony_ci sglp->len0 = cpu_to_be32(pbllen); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci *len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*sglp), 16); 8588c2ecf20Sopenharmony_ci } else { 8598c2ecf20Sopenharmony_ci imdp = (struct fw_ri_immd *)(&wqe->fr + 1); 8608c2ecf20Sopenharmony_ci imdp->op = FW_RI_DATA_IMMD; 8618c2ecf20Sopenharmony_ci imdp->r1 = 0; 8628c2ecf20Sopenharmony_ci imdp->r2 = 0; 8638c2ecf20Sopenharmony_ci imdp->immdlen = cpu_to_be32(pbllen); 8648c2ecf20Sopenharmony_ci p = (__be64 *)(imdp + 1); 8658c2ecf20Sopenharmony_ci rem = pbllen; 8668c2ecf20Sopenharmony_ci for (i = 0; i < mhp->mpl_len; i++) { 8678c2ecf20Sopenharmony_ci *p = cpu_to_be64((u64)mhp->mpl[i]); 8688c2ecf20Sopenharmony_ci rem -= sizeof(*p); 8698c2ecf20Sopenharmony_ci if (++p == (__be64 *)&sq->queue[sq->size]) 8708c2ecf20Sopenharmony_ci p = (__be64 *)sq->queue; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci while (rem) { 8738c2ecf20Sopenharmony_ci *p = 0; 8748c2ecf20Sopenharmony_ci rem -= sizeof(*p); 8758c2ecf20Sopenharmony_ci if (++p == (__be64 *)&sq->queue[sq->size]) 8768c2ecf20Sopenharmony_ci p = (__be64 *)sq->queue; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci *len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*imdp) 8798c2ecf20Sopenharmony_ci + pbllen, 16); 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci return 0; 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic int build_inv_stag(union t4_wr *wqe, const struct ib_send_wr *wr, 8858c2ecf20Sopenharmony_ci u8 *len16) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci wqe->inv.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey); 8888c2ecf20Sopenharmony_ci wqe->inv.r2 = 0; 8898c2ecf20Sopenharmony_ci *len16 = DIV_ROUND_UP(sizeof(wqe->inv), 16); 8908c2ecf20Sopenharmony_ci return 0; 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_civoid c4iw_qp_add_ref(struct ib_qp *qp) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci pr_debug("ib_qp %p\n", qp); 8968c2ecf20Sopenharmony_ci refcount_inc(&to_c4iw_qp(qp)->qp_refcnt); 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_civoid c4iw_qp_rem_ref(struct ib_qp *qp) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci pr_debug("ib_qp %p\n", qp); 9028c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&to_c4iw_qp(qp)->qp_refcnt)) 9038c2ecf20Sopenharmony_ci complete(&to_c4iw_qp(qp)->qp_rel_comp); 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic void add_to_fc_list(struct list_head *head, struct list_head *entry) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci if (list_empty(entry)) 9098c2ecf20Sopenharmony_ci list_add_tail(entry, head); 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_cistatic int ring_kernel_sq_db(struct c4iw_qp *qhp, u16 inc) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci unsigned long flags; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci xa_lock_irqsave(&qhp->rhp->qps, flags); 9178c2ecf20Sopenharmony_ci spin_lock(&qhp->lock); 9188c2ecf20Sopenharmony_ci if (qhp->rhp->db_state == NORMAL) 9198c2ecf20Sopenharmony_ci t4_ring_sq_db(&qhp->wq, inc, NULL); 9208c2ecf20Sopenharmony_ci else { 9218c2ecf20Sopenharmony_ci add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry); 9228c2ecf20Sopenharmony_ci qhp->wq.sq.wq_pidx_inc += inc; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci spin_unlock(&qhp->lock); 9258c2ecf20Sopenharmony_ci xa_unlock_irqrestore(&qhp->rhp->qps, flags); 9268c2ecf20Sopenharmony_ci return 0; 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci unsigned long flags; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci xa_lock_irqsave(&qhp->rhp->qps, flags); 9348c2ecf20Sopenharmony_ci spin_lock(&qhp->lock); 9358c2ecf20Sopenharmony_ci if (qhp->rhp->db_state == NORMAL) 9368c2ecf20Sopenharmony_ci t4_ring_rq_db(&qhp->wq, inc, NULL); 9378c2ecf20Sopenharmony_ci else { 9388c2ecf20Sopenharmony_ci add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry); 9398c2ecf20Sopenharmony_ci qhp->wq.rq.wq_pidx_inc += inc; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci spin_unlock(&qhp->lock); 9428c2ecf20Sopenharmony_ci xa_unlock_irqrestore(&qhp->rhp->qps, flags); 9438c2ecf20Sopenharmony_ci return 0; 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cistatic int ib_to_fw_opcode(int ib_opcode) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci int opcode; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci switch (ib_opcode) { 9518c2ecf20Sopenharmony_ci case IB_WR_SEND_WITH_INV: 9528c2ecf20Sopenharmony_ci opcode = FW_RI_SEND_WITH_INV; 9538c2ecf20Sopenharmony_ci break; 9548c2ecf20Sopenharmony_ci case IB_WR_SEND: 9558c2ecf20Sopenharmony_ci opcode = FW_RI_SEND; 9568c2ecf20Sopenharmony_ci break; 9578c2ecf20Sopenharmony_ci case IB_WR_RDMA_WRITE: 9588c2ecf20Sopenharmony_ci opcode = FW_RI_RDMA_WRITE; 9598c2ecf20Sopenharmony_ci break; 9608c2ecf20Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 9618c2ecf20Sopenharmony_ci opcode = FW_RI_WRITE_IMMEDIATE; 9628c2ecf20Sopenharmony_ci break; 9638c2ecf20Sopenharmony_ci case IB_WR_RDMA_READ: 9648c2ecf20Sopenharmony_ci case IB_WR_RDMA_READ_WITH_INV: 9658c2ecf20Sopenharmony_ci opcode = FW_RI_READ_REQ; 9668c2ecf20Sopenharmony_ci break; 9678c2ecf20Sopenharmony_ci case IB_WR_REG_MR: 9688c2ecf20Sopenharmony_ci opcode = FW_RI_FAST_REGISTER; 9698c2ecf20Sopenharmony_ci break; 9708c2ecf20Sopenharmony_ci case IB_WR_LOCAL_INV: 9718c2ecf20Sopenharmony_ci opcode = FW_RI_LOCAL_INV; 9728c2ecf20Sopenharmony_ci break; 9738c2ecf20Sopenharmony_ci default: 9748c2ecf20Sopenharmony_ci opcode = -EINVAL; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci return opcode; 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistatic int complete_sq_drain_wr(struct c4iw_qp *qhp, 9808c2ecf20Sopenharmony_ci const struct ib_send_wr *wr) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci struct t4_cqe cqe = {}; 9838c2ecf20Sopenharmony_ci struct c4iw_cq *schp; 9848c2ecf20Sopenharmony_ci unsigned long flag; 9858c2ecf20Sopenharmony_ci struct t4_cq *cq; 9868c2ecf20Sopenharmony_ci int opcode; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci schp = to_c4iw_cq(qhp->ibqp.send_cq); 9898c2ecf20Sopenharmony_ci cq = &schp->cq; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci opcode = ib_to_fw_opcode(wr->opcode); 9928c2ecf20Sopenharmony_ci if (opcode < 0) 9938c2ecf20Sopenharmony_ci return opcode; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci cqe.u.drain_cookie = wr->wr_id; 9968c2ecf20Sopenharmony_ci cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) | 9978c2ecf20Sopenharmony_ci CQE_OPCODE_V(opcode) | 9988c2ecf20Sopenharmony_ci CQE_TYPE_V(1) | 9998c2ecf20Sopenharmony_ci CQE_SWCQE_V(1) | 10008c2ecf20Sopenharmony_ci CQE_DRAIN_V(1) | 10018c2ecf20Sopenharmony_ci CQE_QPID_V(qhp->wq.sq.qid)); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci spin_lock_irqsave(&schp->lock, flag); 10048c2ecf20Sopenharmony_ci cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen)); 10058c2ecf20Sopenharmony_ci cq->sw_queue[cq->sw_pidx] = cqe; 10068c2ecf20Sopenharmony_ci t4_swcq_produce(cq); 10078c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&schp->lock, flag); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (t4_clear_cq_armed(&schp->cq)) { 10108c2ecf20Sopenharmony_ci spin_lock_irqsave(&schp->comp_handler_lock, flag); 10118c2ecf20Sopenharmony_ci (*schp->ibcq.comp_handler)(&schp->ibcq, 10128c2ecf20Sopenharmony_ci schp->ibcq.cq_context); 10138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&schp->comp_handler_lock, flag); 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci return 0; 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic int complete_sq_drain_wrs(struct c4iw_qp *qhp, 10198c2ecf20Sopenharmony_ci const struct ib_send_wr *wr, 10208c2ecf20Sopenharmony_ci const struct ib_send_wr **bad_wr) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci int ret = 0; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci while (wr) { 10258c2ecf20Sopenharmony_ci ret = complete_sq_drain_wr(qhp, wr); 10268c2ecf20Sopenharmony_ci if (ret) { 10278c2ecf20Sopenharmony_ci *bad_wr = wr; 10288c2ecf20Sopenharmony_ci break; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci wr = wr->next; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci return ret; 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cistatic void complete_rq_drain_wr(struct c4iw_qp *qhp, 10368c2ecf20Sopenharmony_ci const struct ib_recv_wr *wr) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci struct t4_cqe cqe = {}; 10398c2ecf20Sopenharmony_ci struct c4iw_cq *rchp; 10408c2ecf20Sopenharmony_ci unsigned long flag; 10418c2ecf20Sopenharmony_ci struct t4_cq *cq; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci rchp = to_c4iw_cq(qhp->ibqp.recv_cq); 10448c2ecf20Sopenharmony_ci cq = &rchp->cq; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci cqe.u.drain_cookie = wr->wr_id; 10478c2ecf20Sopenharmony_ci cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) | 10488c2ecf20Sopenharmony_ci CQE_OPCODE_V(FW_RI_SEND) | 10498c2ecf20Sopenharmony_ci CQE_TYPE_V(0) | 10508c2ecf20Sopenharmony_ci CQE_SWCQE_V(1) | 10518c2ecf20Sopenharmony_ci CQE_DRAIN_V(1) | 10528c2ecf20Sopenharmony_ci CQE_QPID_V(qhp->wq.sq.qid)); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci spin_lock_irqsave(&rchp->lock, flag); 10558c2ecf20Sopenharmony_ci cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen)); 10568c2ecf20Sopenharmony_ci cq->sw_queue[cq->sw_pidx] = cqe; 10578c2ecf20Sopenharmony_ci t4_swcq_produce(cq); 10588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rchp->lock, flag); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (t4_clear_cq_armed(&rchp->cq)) { 10618c2ecf20Sopenharmony_ci spin_lock_irqsave(&rchp->comp_handler_lock, flag); 10628c2ecf20Sopenharmony_ci (*rchp->ibcq.comp_handler)(&rchp->ibcq, 10638c2ecf20Sopenharmony_ci rchp->ibcq.cq_context); 10648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci} 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cistatic void complete_rq_drain_wrs(struct c4iw_qp *qhp, 10698c2ecf20Sopenharmony_ci const struct ib_recv_wr *wr) 10708c2ecf20Sopenharmony_ci{ 10718c2ecf20Sopenharmony_ci while (wr) { 10728c2ecf20Sopenharmony_ci complete_rq_drain_wr(qhp, wr); 10738c2ecf20Sopenharmony_ci wr = wr->next; 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci} 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ciint c4iw_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, 10788c2ecf20Sopenharmony_ci const struct ib_send_wr **bad_wr) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci int err = 0; 10818c2ecf20Sopenharmony_ci u8 len16 = 0; 10828c2ecf20Sopenharmony_ci enum fw_wr_opcodes fw_opcode = 0; 10838c2ecf20Sopenharmony_ci enum fw_ri_wr_flags fw_flags; 10848c2ecf20Sopenharmony_ci struct c4iw_qp *qhp; 10858c2ecf20Sopenharmony_ci struct c4iw_dev *rhp; 10868c2ecf20Sopenharmony_ci union t4_wr *wqe = NULL; 10878c2ecf20Sopenharmony_ci u32 num_wrs; 10888c2ecf20Sopenharmony_ci struct t4_swsqe *swsqe; 10898c2ecf20Sopenharmony_ci unsigned long flag; 10908c2ecf20Sopenharmony_ci u16 idx = 0; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci qhp = to_c4iw_qp(ibqp); 10938c2ecf20Sopenharmony_ci rhp = qhp->rhp; 10948c2ecf20Sopenharmony_ci spin_lock_irqsave(&qhp->lock, flag); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* 10978c2ecf20Sopenharmony_ci * If the qp has been flushed, then just insert a special 10988c2ecf20Sopenharmony_ci * drain cqe. 10998c2ecf20Sopenharmony_ci */ 11008c2ecf20Sopenharmony_ci if (qhp->wq.flushed) { 11018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 11028c2ecf20Sopenharmony_ci err = complete_sq_drain_wrs(qhp, wr, bad_wr); 11038c2ecf20Sopenharmony_ci return err; 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci num_wrs = t4_sq_avail(&qhp->wq); 11068c2ecf20Sopenharmony_ci if (num_wrs == 0) { 11078c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 11088c2ecf20Sopenharmony_ci *bad_wr = wr; 11098c2ecf20Sopenharmony_ci return -ENOMEM; 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci /* 11138c2ecf20Sopenharmony_ci * Fastpath for NVMe-oF target WRITE + SEND_WITH_INV wr chain which is 11148c2ecf20Sopenharmony_ci * the response for small NVMEe-oF READ requests. If the chain is 11158c2ecf20Sopenharmony_ci * exactly a WRITE->SEND_WITH_INV or a WRITE->SEND and the sgl depths 11168c2ecf20Sopenharmony_ci * and lengths meet the requirements of the fw_ri_write_cmpl_wr work 11178c2ecf20Sopenharmony_ci * request, then build and post the write_cmpl WR. If any of the tests 11188c2ecf20Sopenharmony_ci * below are not true, then we continue on with the tradtional WRITE 11198c2ecf20Sopenharmony_ci * and SEND WRs. 11208c2ecf20Sopenharmony_ci */ 11218c2ecf20Sopenharmony_ci if (qhp->rhp->rdev.lldi.write_cmpl_support && 11228c2ecf20Sopenharmony_ci CHELSIO_CHIP_VERSION(qhp->rhp->rdev.lldi.adapter_type) >= 11238c2ecf20Sopenharmony_ci CHELSIO_T5 && 11248c2ecf20Sopenharmony_ci wr && wr->next && !wr->next->next && 11258c2ecf20Sopenharmony_ci wr->opcode == IB_WR_RDMA_WRITE && 11268c2ecf20Sopenharmony_ci wr->sg_list[0].length && wr->num_sge <= T4_WRITE_CMPL_MAX_SGL && 11278c2ecf20Sopenharmony_ci (wr->next->opcode == IB_WR_SEND || 11288c2ecf20Sopenharmony_ci wr->next->opcode == IB_WR_SEND_WITH_INV) && 11298c2ecf20Sopenharmony_ci wr->next->sg_list[0].length == T4_WRITE_CMPL_MAX_CQE && 11308c2ecf20Sopenharmony_ci wr->next->num_sge == 1 && num_wrs >= 2) { 11318c2ecf20Sopenharmony_ci post_write_cmpl(qhp, wr); 11328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 11338c2ecf20Sopenharmony_ci return 0; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci while (wr) { 11378c2ecf20Sopenharmony_ci if (num_wrs == 0) { 11388c2ecf20Sopenharmony_ci err = -ENOMEM; 11398c2ecf20Sopenharmony_ci *bad_wr = wr; 11408c2ecf20Sopenharmony_ci break; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci wqe = (union t4_wr *)((u8 *)qhp->wq.sq.queue + 11438c2ecf20Sopenharmony_ci qhp->wq.sq.wq_pidx * T4_EQ_ENTRY_SIZE); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci fw_flags = 0; 11468c2ecf20Sopenharmony_ci if (wr->send_flags & IB_SEND_SOLICITED) 11478c2ecf20Sopenharmony_ci fw_flags |= FW_RI_SOLICITED_EVENT_FLAG; 11488c2ecf20Sopenharmony_ci if (wr->send_flags & IB_SEND_SIGNALED || qhp->sq_sig_all) 11498c2ecf20Sopenharmony_ci fw_flags |= FW_RI_COMPLETION_FLAG; 11508c2ecf20Sopenharmony_ci swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx]; 11518c2ecf20Sopenharmony_ci switch (wr->opcode) { 11528c2ecf20Sopenharmony_ci case IB_WR_SEND_WITH_INV: 11538c2ecf20Sopenharmony_ci case IB_WR_SEND: 11548c2ecf20Sopenharmony_ci if (wr->send_flags & IB_SEND_FENCE) 11558c2ecf20Sopenharmony_ci fw_flags |= FW_RI_READ_FENCE_FLAG; 11568c2ecf20Sopenharmony_ci fw_opcode = FW_RI_SEND_WR; 11578c2ecf20Sopenharmony_ci if (wr->opcode == IB_WR_SEND) 11588c2ecf20Sopenharmony_ci swsqe->opcode = FW_RI_SEND; 11598c2ecf20Sopenharmony_ci else 11608c2ecf20Sopenharmony_ci swsqe->opcode = FW_RI_SEND_WITH_INV; 11618c2ecf20Sopenharmony_ci err = build_rdma_send(&qhp->wq.sq, wqe, wr, &len16); 11628c2ecf20Sopenharmony_ci break; 11638c2ecf20Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 11648c2ecf20Sopenharmony_ci if (unlikely(!rhp->rdev.lldi.write_w_imm_support)) { 11658c2ecf20Sopenharmony_ci err = -EINVAL; 11668c2ecf20Sopenharmony_ci break; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci fw_flags |= FW_RI_RDMA_WRITE_WITH_IMMEDIATE; 11698c2ecf20Sopenharmony_ci fallthrough; 11708c2ecf20Sopenharmony_ci case IB_WR_RDMA_WRITE: 11718c2ecf20Sopenharmony_ci fw_opcode = FW_RI_RDMA_WRITE_WR; 11728c2ecf20Sopenharmony_ci swsqe->opcode = FW_RI_RDMA_WRITE; 11738c2ecf20Sopenharmony_ci err = build_rdma_write(&qhp->wq.sq, wqe, wr, &len16); 11748c2ecf20Sopenharmony_ci break; 11758c2ecf20Sopenharmony_ci case IB_WR_RDMA_READ: 11768c2ecf20Sopenharmony_ci case IB_WR_RDMA_READ_WITH_INV: 11778c2ecf20Sopenharmony_ci fw_opcode = FW_RI_RDMA_READ_WR; 11788c2ecf20Sopenharmony_ci swsqe->opcode = FW_RI_READ_REQ; 11798c2ecf20Sopenharmony_ci if (wr->opcode == IB_WR_RDMA_READ_WITH_INV) { 11808c2ecf20Sopenharmony_ci c4iw_invalidate_mr(rhp, wr->sg_list[0].lkey); 11818c2ecf20Sopenharmony_ci fw_flags = FW_RI_RDMA_READ_INVALIDATE; 11828c2ecf20Sopenharmony_ci } else { 11838c2ecf20Sopenharmony_ci fw_flags = 0; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci err = build_rdma_read(wqe, wr, &len16); 11868c2ecf20Sopenharmony_ci if (err) 11878c2ecf20Sopenharmony_ci break; 11888c2ecf20Sopenharmony_ci swsqe->read_len = wr->sg_list[0].length; 11898c2ecf20Sopenharmony_ci if (!qhp->wq.sq.oldest_read) 11908c2ecf20Sopenharmony_ci qhp->wq.sq.oldest_read = swsqe; 11918c2ecf20Sopenharmony_ci break; 11928c2ecf20Sopenharmony_ci case IB_WR_REG_MR: { 11938c2ecf20Sopenharmony_ci struct c4iw_mr *mhp = to_c4iw_mr(reg_wr(wr)->mr); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci swsqe->opcode = FW_RI_FAST_REGISTER; 11968c2ecf20Sopenharmony_ci if (rhp->rdev.lldi.fr_nsmr_tpte_wr_support && 11978c2ecf20Sopenharmony_ci !mhp->attr.state && mhp->mpl_len <= 2) { 11988c2ecf20Sopenharmony_ci fw_opcode = FW_RI_FR_NSMR_TPTE_WR; 11998c2ecf20Sopenharmony_ci build_tpte_memreg(&wqe->fr_tpte, reg_wr(wr), 12008c2ecf20Sopenharmony_ci mhp, &len16); 12018c2ecf20Sopenharmony_ci } else { 12028c2ecf20Sopenharmony_ci fw_opcode = FW_RI_FR_NSMR_WR; 12038c2ecf20Sopenharmony_ci err = build_memreg(&qhp->wq.sq, wqe, reg_wr(wr), 12048c2ecf20Sopenharmony_ci mhp, &len16, 12058c2ecf20Sopenharmony_ci rhp->rdev.lldi.ulptx_memwrite_dsgl); 12068c2ecf20Sopenharmony_ci if (err) 12078c2ecf20Sopenharmony_ci break; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci mhp->attr.state = 1; 12108c2ecf20Sopenharmony_ci break; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci case IB_WR_LOCAL_INV: 12138c2ecf20Sopenharmony_ci if (wr->send_flags & IB_SEND_FENCE) 12148c2ecf20Sopenharmony_ci fw_flags |= FW_RI_LOCAL_FENCE_FLAG; 12158c2ecf20Sopenharmony_ci fw_opcode = FW_RI_INV_LSTAG_WR; 12168c2ecf20Sopenharmony_ci swsqe->opcode = FW_RI_LOCAL_INV; 12178c2ecf20Sopenharmony_ci err = build_inv_stag(wqe, wr, &len16); 12188c2ecf20Sopenharmony_ci c4iw_invalidate_mr(rhp, wr->ex.invalidate_rkey); 12198c2ecf20Sopenharmony_ci break; 12208c2ecf20Sopenharmony_ci default: 12218c2ecf20Sopenharmony_ci pr_warn("%s post of type=%d TBD!\n", __func__, 12228c2ecf20Sopenharmony_ci wr->opcode); 12238c2ecf20Sopenharmony_ci err = -EINVAL; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci if (err) { 12268c2ecf20Sopenharmony_ci *bad_wr = wr; 12278c2ecf20Sopenharmony_ci break; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci swsqe->idx = qhp->wq.sq.pidx; 12308c2ecf20Sopenharmony_ci swsqe->complete = 0; 12318c2ecf20Sopenharmony_ci swsqe->signaled = (wr->send_flags & IB_SEND_SIGNALED) || 12328c2ecf20Sopenharmony_ci qhp->sq_sig_all; 12338c2ecf20Sopenharmony_ci swsqe->flushed = 0; 12348c2ecf20Sopenharmony_ci swsqe->wr_id = wr->wr_id; 12358c2ecf20Sopenharmony_ci if (c4iw_wr_log) { 12368c2ecf20Sopenharmony_ci swsqe->sge_ts = cxgb4_read_sge_timestamp( 12378c2ecf20Sopenharmony_ci rhp->rdev.lldi.ports[0]); 12388c2ecf20Sopenharmony_ci swsqe->host_time = ktime_get(); 12398c2ecf20Sopenharmony_ci } 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci init_wr_hdr(wqe, qhp->wq.sq.pidx, fw_opcode, fw_flags, len16); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci pr_debug("cookie 0x%llx pidx 0x%x opcode 0x%x read_len %u\n", 12448c2ecf20Sopenharmony_ci (unsigned long long)wr->wr_id, qhp->wq.sq.pidx, 12458c2ecf20Sopenharmony_ci swsqe->opcode, swsqe->read_len); 12468c2ecf20Sopenharmony_ci wr = wr->next; 12478c2ecf20Sopenharmony_ci num_wrs--; 12488c2ecf20Sopenharmony_ci t4_sq_produce(&qhp->wq, len16); 12498c2ecf20Sopenharmony_ci idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE); 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci if (!rhp->rdev.status_page->db_off) { 12528c2ecf20Sopenharmony_ci t4_ring_sq_db(&qhp->wq, idx, wqe); 12538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 12548c2ecf20Sopenharmony_ci } else { 12558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 12568c2ecf20Sopenharmony_ci ring_kernel_sq_db(qhp, idx); 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci return err; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ciint c4iw_post_receive(struct ib_qp *ibqp, const struct ib_recv_wr *wr, 12628c2ecf20Sopenharmony_ci const struct ib_recv_wr **bad_wr) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci int err = 0; 12658c2ecf20Sopenharmony_ci struct c4iw_qp *qhp; 12668c2ecf20Sopenharmony_ci union t4_recv_wr *wqe = NULL; 12678c2ecf20Sopenharmony_ci u32 num_wrs; 12688c2ecf20Sopenharmony_ci u8 len16 = 0; 12698c2ecf20Sopenharmony_ci unsigned long flag; 12708c2ecf20Sopenharmony_ci u16 idx = 0; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci qhp = to_c4iw_qp(ibqp); 12738c2ecf20Sopenharmony_ci spin_lock_irqsave(&qhp->lock, flag); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci /* 12768c2ecf20Sopenharmony_ci * If the qp has been flushed, then just insert a special 12778c2ecf20Sopenharmony_ci * drain cqe. 12788c2ecf20Sopenharmony_ci */ 12798c2ecf20Sopenharmony_ci if (qhp->wq.flushed) { 12808c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 12818c2ecf20Sopenharmony_ci complete_rq_drain_wrs(qhp, wr); 12828c2ecf20Sopenharmony_ci return err; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci num_wrs = t4_rq_avail(&qhp->wq); 12858c2ecf20Sopenharmony_ci if (num_wrs == 0) { 12868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 12878c2ecf20Sopenharmony_ci *bad_wr = wr; 12888c2ecf20Sopenharmony_ci return -ENOMEM; 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci while (wr) { 12918c2ecf20Sopenharmony_ci if (wr->num_sge > T4_MAX_RECV_SGE) { 12928c2ecf20Sopenharmony_ci err = -EINVAL; 12938c2ecf20Sopenharmony_ci *bad_wr = wr; 12948c2ecf20Sopenharmony_ci break; 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci wqe = (union t4_recv_wr *)((u8 *)qhp->wq.rq.queue + 12978c2ecf20Sopenharmony_ci qhp->wq.rq.wq_pidx * 12988c2ecf20Sopenharmony_ci T4_EQ_ENTRY_SIZE); 12998c2ecf20Sopenharmony_ci if (num_wrs) 13008c2ecf20Sopenharmony_ci err = build_rdma_recv(qhp, wqe, wr, &len16); 13018c2ecf20Sopenharmony_ci else 13028c2ecf20Sopenharmony_ci err = -ENOMEM; 13038c2ecf20Sopenharmony_ci if (err) { 13048c2ecf20Sopenharmony_ci *bad_wr = wr; 13058c2ecf20Sopenharmony_ci break; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].wr_id = wr->wr_id; 13098c2ecf20Sopenharmony_ci if (c4iw_wr_log) { 13108c2ecf20Sopenharmony_ci qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].sge_ts = 13118c2ecf20Sopenharmony_ci cxgb4_read_sge_timestamp( 13128c2ecf20Sopenharmony_ci qhp->rhp->rdev.lldi.ports[0]); 13138c2ecf20Sopenharmony_ci qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].host_time = 13148c2ecf20Sopenharmony_ci ktime_get(); 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci wqe->recv.opcode = FW_RI_RECV_WR; 13188c2ecf20Sopenharmony_ci wqe->recv.r1 = 0; 13198c2ecf20Sopenharmony_ci wqe->recv.wrid = qhp->wq.rq.pidx; 13208c2ecf20Sopenharmony_ci wqe->recv.r2[0] = 0; 13218c2ecf20Sopenharmony_ci wqe->recv.r2[1] = 0; 13228c2ecf20Sopenharmony_ci wqe->recv.r2[2] = 0; 13238c2ecf20Sopenharmony_ci wqe->recv.len16 = len16; 13248c2ecf20Sopenharmony_ci pr_debug("cookie 0x%llx pidx %u\n", 13258c2ecf20Sopenharmony_ci (unsigned long long)wr->wr_id, qhp->wq.rq.pidx); 13268c2ecf20Sopenharmony_ci t4_rq_produce(&qhp->wq, len16); 13278c2ecf20Sopenharmony_ci idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE); 13288c2ecf20Sopenharmony_ci wr = wr->next; 13298c2ecf20Sopenharmony_ci num_wrs--; 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci if (!qhp->rhp->rdev.status_page->db_off) { 13328c2ecf20Sopenharmony_ci t4_ring_rq_db(&qhp->wq, idx, wqe); 13338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 13348c2ecf20Sopenharmony_ci } else { 13358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 13368c2ecf20Sopenharmony_ci ring_kernel_rq_db(qhp, idx); 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci return err; 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic void defer_srq_wr(struct t4_srq *srq, union t4_recv_wr *wqe, 13428c2ecf20Sopenharmony_ci u64 wr_id, u8 len16) 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci struct t4_srq_pending_wr *pwr = &srq->pending_wrs[srq->pending_pidx]; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci pr_debug("%s cidx %u pidx %u wq_pidx %u in_use %u ooo_count %u wr_id 0x%llx pending_cidx %u pending_pidx %u pending_in_use %u\n", 13478c2ecf20Sopenharmony_ci __func__, srq->cidx, srq->pidx, srq->wq_pidx, 13488c2ecf20Sopenharmony_ci srq->in_use, srq->ooo_count, 13498c2ecf20Sopenharmony_ci (unsigned long long)wr_id, srq->pending_cidx, 13508c2ecf20Sopenharmony_ci srq->pending_pidx, srq->pending_in_use); 13518c2ecf20Sopenharmony_ci pwr->wr_id = wr_id; 13528c2ecf20Sopenharmony_ci pwr->len16 = len16; 13538c2ecf20Sopenharmony_ci memcpy(&pwr->wqe, wqe, len16 * 16); 13548c2ecf20Sopenharmony_ci t4_srq_produce_pending_wr(srq); 13558c2ecf20Sopenharmony_ci} 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ciint c4iw_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, 13588c2ecf20Sopenharmony_ci const struct ib_recv_wr **bad_wr) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci union t4_recv_wr *wqe, lwqe; 13618c2ecf20Sopenharmony_ci struct c4iw_srq *srq; 13628c2ecf20Sopenharmony_ci unsigned long flag; 13638c2ecf20Sopenharmony_ci u8 len16 = 0; 13648c2ecf20Sopenharmony_ci u16 idx = 0; 13658c2ecf20Sopenharmony_ci int err = 0; 13668c2ecf20Sopenharmony_ci u32 num_wrs; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci srq = to_c4iw_srq(ibsrq); 13698c2ecf20Sopenharmony_ci spin_lock_irqsave(&srq->lock, flag); 13708c2ecf20Sopenharmony_ci num_wrs = t4_srq_avail(&srq->wq); 13718c2ecf20Sopenharmony_ci if (num_wrs == 0) { 13728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&srq->lock, flag); 13738c2ecf20Sopenharmony_ci return -ENOMEM; 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci while (wr) { 13768c2ecf20Sopenharmony_ci if (wr->num_sge > T4_MAX_RECV_SGE) { 13778c2ecf20Sopenharmony_ci err = -EINVAL; 13788c2ecf20Sopenharmony_ci *bad_wr = wr; 13798c2ecf20Sopenharmony_ci break; 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci wqe = &lwqe; 13828c2ecf20Sopenharmony_ci if (num_wrs) 13838c2ecf20Sopenharmony_ci err = build_srq_recv(wqe, wr, &len16); 13848c2ecf20Sopenharmony_ci else 13858c2ecf20Sopenharmony_ci err = -ENOMEM; 13868c2ecf20Sopenharmony_ci if (err) { 13878c2ecf20Sopenharmony_ci *bad_wr = wr; 13888c2ecf20Sopenharmony_ci break; 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci wqe->recv.opcode = FW_RI_RECV_WR; 13928c2ecf20Sopenharmony_ci wqe->recv.r1 = 0; 13938c2ecf20Sopenharmony_ci wqe->recv.wrid = srq->wq.pidx; 13948c2ecf20Sopenharmony_ci wqe->recv.r2[0] = 0; 13958c2ecf20Sopenharmony_ci wqe->recv.r2[1] = 0; 13968c2ecf20Sopenharmony_ci wqe->recv.r2[2] = 0; 13978c2ecf20Sopenharmony_ci wqe->recv.len16 = len16; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci if (srq->wq.ooo_count || 14008c2ecf20Sopenharmony_ci srq->wq.pending_in_use || 14018c2ecf20Sopenharmony_ci srq->wq.sw_rq[srq->wq.pidx].valid) { 14028c2ecf20Sopenharmony_ci defer_srq_wr(&srq->wq, wqe, wr->wr_id, len16); 14038c2ecf20Sopenharmony_ci } else { 14048c2ecf20Sopenharmony_ci srq->wq.sw_rq[srq->wq.pidx].wr_id = wr->wr_id; 14058c2ecf20Sopenharmony_ci srq->wq.sw_rq[srq->wq.pidx].valid = 1; 14068c2ecf20Sopenharmony_ci c4iw_copy_wr_to_srq(&srq->wq, wqe, len16); 14078c2ecf20Sopenharmony_ci pr_debug("%s cidx %u pidx %u wq_pidx %u in_use %u wr_id 0x%llx\n", 14088c2ecf20Sopenharmony_ci __func__, srq->wq.cidx, 14098c2ecf20Sopenharmony_ci srq->wq.pidx, srq->wq.wq_pidx, 14108c2ecf20Sopenharmony_ci srq->wq.in_use, 14118c2ecf20Sopenharmony_ci (unsigned long long)wr->wr_id); 14128c2ecf20Sopenharmony_ci t4_srq_produce(&srq->wq, len16); 14138c2ecf20Sopenharmony_ci idx += DIV_ROUND_UP(len16 * 16, T4_EQ_ENTRY_SIZE); 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci wr = wr->next; 14168c2ecf20Sopenharmony_ci num_wrs--; 14178c2ecf20Sopenharmony_ci } 14188c2ecf20Sopenharmony_ci if (idx) 14198c2ecf20Sopenharmony_ci t4_ring_srq_db(&srq->wq, idx, len16, wqe); 14208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&srq->lock, flag); 14218c2ecf20Sopenharmony_ci return err; 14228c2ecf20Sopenharmony_ci} 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_cistatic inline void build_term_codes(struct t4_cqe *err_cqe, u8 *layer_type, 14258c2ecf20Sopenharmony_ci u8 *ecode) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci int status; 14288c2ecf20Sopenharmony_ci int tagged; 14298c2ecf20Sopenharmony_ci int opcode; 14308c2ecf20Sopenharmony_ci int rqtype; 14318c2ecf20Sopenharmony_ci int send_inv; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci if (!err_cqe) { 14348c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|DDP_LOCAL_CATA; 14358c2ecf20Sopenharmony_ci *ecode = 0; 14368c2ecf20Sopenharmony_ci return; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci status = CQE_STATUS(err_cqe); 14408c2ecf20Sopenharmony_ci opcode = CQE_OPCODE(err_cqe); 14418c2ecf20Sopenharmony_ci rqtype = RQ_TYPE(err_cqe); 14428c2ecf20Sopenharmony_ci send_inv = (opcode == FW_RI_SEND_WITH_INV) || 14438c2ecf20Sopenharmony_ci (opcode == FW_RI_SEND_WITH_SE_INV); 14448c2ecf20Sopenharmony_ci tagged = (opcode == FW_RI_RDMA_WRITE) || 14458c2ecf20Sopenharmony_ci (rqtype && (opcode == FW_RI_READ_RESP)); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci switch (status) { 14488c2ecf20Sopenharmony_ci case T4_ERR_STAG: 14498c2ecf20Sopenharmony_ci if (send_inv) { 14508c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP; 14518c2ecf20Sopenharmony_ci *ecode = RDMAP_CANT_INV_STAG; 14528c2ecf20Sopenharmony_ci } else { 14538c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; 14548c2ecf20Sopenharmony_ci *ecode = RDMAP_INV_STAG; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci break; 14578c2ecf20Sopenharmony_ci case T4_ERR_PDID: 14588c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; 14598c2ecf20Sopenharmony_ci if ((opcode == FW_RI_SEND_WITH_INV) || 14608c2ecf20Sopenharmony_ci (opcode == FW_RI_SEND_WITH_SE_INV)) 14618c2ecf20Sopenharmony_ci *ecode = RDMAP_CANT_INV_STAG; 14628c2ecf20Sopenharmony_ci else 14638c2ecf20Sopenharmony_ci *ecode = RDMAP_STAG_NOT_ASSOC; 14648c2ecf20Sopenharmony_ci break; 14658c2ecf20Sopenharmony_ci case T4_ERR_QPID: 14668c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; 14678c2ecf20Sopenharmony_ci *ecode = RDMAP_STAG_NOT_ASSOC; 14688c2ecf20Sopenharmony_ci break; 14698c2ecf20Sopenharmony_ci case T4_ERR_ACCESS: 14708c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; 14718c2ecf20Sopenharmony_ci *ecode = RDMAP_ACC_VIOL; 14728c2ecf20Sopenharmony_ci break; 14738c2ecf20Sopenharmony_ci case T4_ERR_WRAP: 14748c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; 14758c2ecf20Sopenharmony_ci *ecode = RDMAP_TO_WRAP; 14768c2ecf20Sopenharmony_ci break; 14778c2ecf20Sopenharmony_ci case T4_ERR_BOUND: 14788c2ecf20Sopenharmony_ci if (tagged) { 14798c2ecf20Sopenharmony_ci *layer_type = LAYER_DDP|DDP_TAGGED_ERR; 14808c2ecf20Sopenharmony_ci *ecode = DDPT_BASE_BOUNDS; 14818c2ecf20Sopenharmony_ci } else { 14828c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; 14838c2ecf20Sopenharmony_ci *ecode = RDMAP_BASE_BOUNDS; 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci break; 14868c2ecf20Sopenharmony_ci case T4_ERR_INVALIDATE_SHARED_MR: 14878c2ecf20Sopenharmony_ci case T4_ERR_INVALIDATE_MR_WITH_MW_BOUND: 14888c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP; 14898c2ecf20Sopenharmony_ci *ecode = RDMAP_CANT_INV_STAG; 14908c2ecf20Sopenharmony_ci break; 14918c2ecf20Sopenharmony_ci case T4_ERR_ECC: 14928c2ecf20Sopenharmony_ci case T4_ERR_ECC_PSTAG: 14938c2ecf20Sopenharmony_ci case T4_ERR_INTERNAL_ERR: 14948c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_LOCAL_CATA; 14958c2ecf20Sopenharmony_ci *ecode = 0; 14968c2ecf20Sopenharmony_ci break; 14978c2ecf20Sopenharmony_ci case T4_ERR_OUT_OF_RQE: 14988c2ecf20Sopenharmony_ci *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; 14998c2ecf20Sopenharmony_ci *ecode = DDPU_INV_MSN_NOBUF; 15008c2ecf20Sopenharmony_ci break; 15018c2ecf20Sopenharmony_ci case T4_ERR_PBL_ADDR_BOUND: 15028c2ecf20Sopenharmony_ci *layer_type = LAYER_DDP|DDP_TAGGED_ERR; 15038c2ecf20Sopenharmony_ci *ecode = DDPT_BASE_BOUNDS; 15048c2ecf20Sopenharmony_ci break; 15058c2ecf20Sopenharmony_ci case T4_ERR_CRC: 15068c2ecf20Sopenharmony_ci *layer_type = LAYER_MPA|DDP_LLP; 15078c2ecf20Sopenharmony_ci *ecode = MPA_CRC_ERR; 15088c2ecf20Sopenharmony_ci break; 15098c2ecf20Sopenharmony_ci case T4_ERR_MARKER: 15108c2ecf20Sopenharmony_ci *layer_type = LAYER_MPA|DDP_LLP; 15118c2ecf20Sopenharmony_ci *ecode = MPA_MARKER_ERR; 15128c2ecf20Sopenharmony_ci break; 15138c2ecf20Sopenharmony_ci case T4_ERR_PDU_LEN_ERR: 15148c2ecf20Sopenharmony_ci *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; 15158c2ecf20Sopenharmony_ci *ecode = DDPU_MSG_TOOBIG; 15168c2ecf20Sopenharmony_ci break; 15178c2ecf20Sopenharmony_ci case T4_ERR_DDP_VERSION: 15188c2ecf20Sopenharmony_ci if (tagged) { 15198c2ecf20Sopenharmony_ci *layer_type = LAYER_DDP|DDP_TAGGED_ERR; 15208c2ecf20Sopenharmony_ci *ecode = DDPT_INV_VERS; 15218c2ecf20Sopenharmony_ci } else { 15228c2ecf20Sopenharmony_ci *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; 15238c2ecf20Sopenharmony_ci *ecode = DDPU_INV_VERS; 15248c2ecf20Sopenharmony_ci } 15258c2ecf20Sopenharmony_ci break; 15268c2ecf20Sopenharmony_ci case T4_ERR_RDMA_VERSION: 15278c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP; 15288c2ecf20Sopenharmony_ci *ecode = RDMAP_INV_VERS; 15298c2ecf20Sopenharmony_ci break; 15308c2ecf20Sopenharmony_ci case T4_ERR_OPCODE: 15318c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP; 15328c2ecf20Sopenharmony_ci *ecode = RDMAP_INV_OPCODE; 15338c2ecf20Sopenharmony_ci break; 15348c2ecf20Sopenharmony_ci case T4_ERR_DDP_QUEUE_NUM: 15358c2ecf20Sopenharmony_ci *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; 15368c2ecf20Sopenharmony_ci *ecode = DDPU_INV_QN; 15378c2ecf20Sopenharmony_ci break; 15388c2ecf20Sopenharmony_ci case T4_ERR_MSN: 15398c2ecf20Sopenharmony_ci case T4_ERR_MSN_GAP: 15408c2ecf20Sopenharmony_ci case T4_ERR_MSN_RANGE: 15418c2ecf20Sopenharmony_ci case T4_ERR_IRD_OVERFLOW: 15428c2ecf20Sopenharmony_ci *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; 15438c2ecf20Sopenharmony_ci *ecode = DDPU_INV_MSN_RANGE; 15448c2ecf20Sopenharmony_ci break; 15458c2ecf20Sopenharmony_ci case T4_ERR_TBIT: 15468c2ecf20Sopenharmony_ci *layer_type = LAYER_DDP|DDP_LOCAL_CATA; 15478c2ecf20Sopenharmony_ci *ecode = 0; 15488c2ecf20Sopenharmony_ci break; 15498c2ecf20Sopenharmony_ci case T4_ERR_MO: 15508c2ecf20Sopenharmony_ci *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; 15518c2ecf20Sopenharmony_ci *ecode = DDPU_INV_MO; 15528c2ecf20Sopenharmony_ci break; 15538c2ecf20Sopenharmony_ci default: 15548c2ecf20Sopenharmony_ci *layer_type = LAYER_RDMAP|DDP_LOCAL_CATA; 15558c2ecf20Sopenharmony_ci *ecode = 0; 15568c2ecf20Sopenharmony_ci break; 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci} 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_cistatic void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe, 15618c2ecf20Sopenharmony_ci gfp_t gfp) 15628c2ecf20Sopenharmony_ci{ 15638c2ecf20Sopenharmony_ci struct fw_ri_wr *wqe; 15648c2ecf20Sopenharmony_ci struct sk_buff *skb; 15658c2ecf20Sopenharmony_ci struct terminate_message *term; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci pr_debug("qhp %p qid 0x%x tid %u\n", qhp, qhp->wq.sq.qid, 15688c2ecf20Sopenharmony_ci qhp->ep->hwtid); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci skb = skb_dequeue(&qhp->ep->com.ep_skb_list); 15718c2ecf20Sopenharmony_ci if (WARN_ON(!skb)) 15728c2ecf20Sopenharmony_ci return; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci wqe = __skb_put_zero(skb, sizeof(*wqe)); 15778c2ecf20Sopenharmony_ci wqe->op_compl = cpu_to_be32(FW_WR_OP_V(FW_RI_INIT_WR)); 15788c2ecf20Sopenharmony_ci wqe->flowid_len16 = cpu_to_be32( 15798c2ecf20Sopenharmony_ci FW_WR_FLOWID_V(qhp->ep->hwtid) | 15808c2ecf20Sopenharmony_ci FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16))); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci wqe->u.terminate.type = FW_RI_TYPE_TERMINATE; 15838c2ecf20Sopenharmony_ci wqe->u.terminate.immdlen = cpu_to_be32(sizeof(*term)); 15848c2ecf20Sopenharmony_ci term = (struct terminate_message *)wqe->u.terminate.termmsg; 15858c2ecf20Sopenharmony_ci if (qhp->attr.layer_etype == (LAYER_MPA|DDP_LLP)) { 15868c2ecf20Sopenharmony_ci term->layer_etype = qhp->attr.layer_etype; 15878c2ecf20Sopenharmony_ci term->ecode = qhp->attr.ecode; 15888c2ecf20Sopenharmony_ci } else 15898c2ecf20Sopenharmony_ci build_term_codes(err_cqe, &term->layer_etype, &term->ecode); 15908c2ecf20Sopenharmony_ci c4iw_ofld_send(&qhp->rhp->rdev, skb); 15918c2ecf20Sopenharmony_ci} 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci/* 15948c2ecf20Sopenharmony_ci * Assumes qhp lock is held. 15958c2ecf20Sopenharmony_ci */ 15968c2ecf20Sopenharmony_cistatic void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp, 15978c2ecf20Sopenharmony_ci struct c4iw_cq *schp) 15988c2ecf20Sopenharmony_ci{ 15998c2ecf20Sopenharmony_ci int count; 16008c2ecf20Sopenharmony_ci int rq_flushed = 0, sq_flushed; 16018c2ecf20Sopenharmony_ci unsigned long flag; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci pr_debug("qhp %p rchp %p schp %p\n", qhp, rchp, schp); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci /* locking hierarchy: cqs lock first, then qp lock. */ 16068c2ecf20Sopenharmony_ci spin_lock_irqsave(&rchp->lock, flag); 16078c2ecf20Sopenharmony_ci if (schp != rchp) 16088c2ecf20Sopenharmony_ci spin_lock(&schp->lock); 16098c2ecf20Sopenharmony_ci spin_lock(&qhp->lock); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci if (qhp->wq.flushed) { 16128c2ecf20Sopenharmony_ci spin_unlock(&qhp->lock); 16138c2ecf20Sopenharmony_ci if (schp != rchp) 16148c2ecf20Sopenharmony_ci spin_unlock(&schp->lock); 16158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rchp->lock, flag); 16168c2ecf20Sopenharmony_ci return; 16178c2ecf20Sopenharmony_ci } 16188c2ecf20Sopenharmony_ci qhp->wq.flushed = 1; 16198c2ecf20Sopenharmony_ci t4_set_wq_in_error(&qhp->wq, 0); 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci c4iw_flush_hw_cq(rchp, qhp); 16228c2ecf20Sopenharmony_ci if (!qhp->srq) { 16238c2ecf20Sopenharmony_ci c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count); 16248c2ecf20Sopenharmony_ci rq_flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count); 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (schp != rchp) 16288c2ecf20Sopenharmony_ci c4iw_flush_hw_cq(schp, qhp); 16298c2ecf20Sopenharmony_ci sq_flushed = c4iw_flush_sq(qhp); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci spin_unlock(&qhp->lock); 16328c2ecf20Sopenharmony_ci if (schp != rchp) 16338c2ecf20Sopenharmony_ci spin_unlock(&schp->lock); 16348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rchp->lock, flag); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci if (schp == rchp) { 16378c2ecf20Sopenharmony_ci if ((rq_flushed || sq_flushed) && 16388c2ecf20Sopenharmony_ci t4_clear_cq_armed(&rchp->cq)) { 16398c2ecf20Sopenharmony_ci spin_lock_irqsave(&rchp->comp_handler_lock, flag); 16408c2ecf20Sopenharmony_ci (*rchp->ibcq.comp_handler)(&rchp->ibcq, 16418c2ecf20Sopenharmony_ci rchp->ibcq.cq_context); 16428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci } else { 16458c2ecf20Sopenharmony_ci if (rq_flushed && t4_clear_cq_armed(&rchp->cq)) { 16468c2ecf20Sopenharmony_ci spin_lock_irqsave(&rchp->comp_handler_lock, flag); 16478c2ecf20Sopenharmony_ci (*rchp->ibcq.comp_handler)(&rchp->ibcq, 16488c2ecf20Sopenharmony_ci rchp->ibcq.cq_context); 16498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci if (sq_flushed && t4_clear_cq_armed(&schp->cq)) { 16528c2ecf20Sopenharmony_ci spin_lock_irqsave(&schp->comp_handler_lock, flag); 16538c2ecf20Sopenharmony_ci (*schp->ibcq.comp_handler)(&schp->ibcq, 16548c2ecf20Sopenharmony_ci schp->ibcq.cq_context); 16558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&schp->comp_handler_lock, flag); 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci} 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_cistatic void flush_qp(struct c4iw_qp *qhp) 16618c2ecf20Sopenharmony_ci{ 16628c2ecf20Sopenharmony_ci struct c4iw_cq *rchp, *schp; 16638c2ecf20Sopenharmony_ci unsigned long flag; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci rchp = to_c4iw_cq(qhp->ibqp.recv_cq); 16668c2ecf20Sopenharmony_ci schp = to_c4iw_cq(qhp->ibqp.send_cq); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci if (qhp->ibqp.uobject) { 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci /* for user qps, qhp->wq.flushed is protected by qhp->mutex */ 16718c2ecf20Sopenharmony_ci if (qhp->wq.flushed) 16728c2ecf20Sopenharmony_ci return; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci qhp->wq.flushed = 1; 16758c2ecf20Sopenharmony_ci t4_set_wq_in_error(&qhp->wq, 0); 16768c2ecf20Sopenharmony_ci t4_set_cq_in_error(&rchp->cq); 16778c2ecf20Sopenharmony_ci spin_lock_irqsave(&rchp->comp_handler_lock, flag); 16788c2ecf20Sopenharmony_ci (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); 16798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); 16808c2ecf20Sopenharmony_ci if (schp != rchp) { 16818c2ecf20Sopenharmony_ci t4_set_cq_in_error(&schp->cq); 16828c2ecf20Sopenharmony_ci spin_lock_irqsave(&schp->comp_handler_lock, flag); 16838c2ecf20Sopenharmony_ci (*schp->ibcq.comp_handler)(&schp->ibcq, 16848c2ecf20Sopenharmony_ci schp->ibcq.cq_context); 16858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&schp->comp_handler_lock, flag); 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ci return; 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci __flush_qp(qhp, rchp, schp); 16908c2ecf20Sopenharmony_ci} 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_cistatic int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp, 16938c2ecf20Sopenharmony_ci struct c4iw_ep *ep) 16948c2ecf20Sopenharmony_ci{ 16958c2ecf20Sopenharmony_ci struct fw_ri_wr *wqe; 16968c2ecf20Sopenharmony_ci int ret; 16978c2ecf20Sopenharmony_ci struct sk_buff *skb; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci pr_debug("qhp %p qid 0x%x tid %u\n", qhp, qhp->wq.sq.qid, ep->hwtid); 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci skb = skb_dequeue(&ep->com.ep_skb_list); 17028c2ecf20Sopenharmony_ci if (WARN_ON(!skb)) 17038c2ecf20Sopenharmony_ci return -ENOMEM; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx); 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci wqe = __skb_put_zero(skb, sizeof(*wqe)); 17088c2ecf20Sopenharmony_ci wqe->op_compl = cpu_to_be32( 17098c2ecf20Sopenharmony_ci FW_WR_OP_V(FW_RI_INIT_WR) | 17108c2ecf20Sopenharmony_ci FW_WR_COMPL_F); 17118c2ecf20Sopenharmony_ci wqe->flowid_len16 = cpu_to_be32( 17128c2ecf20Sopenharmony_ci FW_WR_FLOWID_V(ep->hwtid) | 17138c2ecf20Sopenharmony_ci FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16))); 17148c2ecf20Sopenharmony_ci wqe->cookie = (uintptr_t)ep->com.wr_waitp; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci wqe->u.fini.type = FW_RI_TYPE_FINI; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci ret = c4iw_ref_send_wait(&rhp->rdev, skb, ep->com.wr_waitp, 17198c2ecf20Sopenharmony_ci qhp->ep->hwtid, qhp->wq.sq.qid, __func__); 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci pr_debug("ret %d\n", ret); 17228c2ecf20Sopenharmony_ci return ret; 17238c2ecf20Sopenharmony_ci} 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_cistatic void build_rtr_msg(u8 p2p_type, struct fw_ri_init *init) 17268c2ecf20Sopenharmony_ci{ 17278c2ecf20Sopenharmony_ci pr_debug("p2p_type = %d\n", p2p_type); 17288c2ecf20Sopenharmony_ci memset(&init->u, 0, sizeof(init->u)); 17298c2ecf20Sopenharmony_ci switch (p2p_type) { 17308c2ecf20Sopenharmony_ci case FW_RI_INIT_P2PTYPE_RDMA_WRITE: 17318c2ecf20Sopenharmony_ci init->u.write.opcode = FW_RI_RDMA_WRITE_WR; 17328c2ecf20Sopenharmony_ci init->u.write.stag_sink = cpu_to_be32(1); 17338c2ecf20Sopenharmony_ci init->u.write.to_sink = cpu_to_be64(1); 17348c2ecf20Sopenharmony_ci init->u.write.u.immd_src[0].op = FW_RI_DATA_IMMD; 17358c2ecf20Sopenharmony_ci init->u.write.len16 = DIV_ROUND_UP( 17368c2ecf20Sopenharmony_ci sizeof(init->u.write) + sizeof(struct fw_ri_immd), 16); 17378c2ecf20Sopenharmony_ci break; 17388c2ecf20Sopenharmony_ci case FW_RI_INIT_P2PTYPE_READ_REQ: 17398c2ecf20Sopenharmony_ci init->u.write.opcode = FW_RI_RDMA_READ_WR; 17408c2ecf20Sopenharmony_ci init->u.read.stag_src = cpu_to_be32(1); 17418c2ecf20Sopenharmony_ci init->u.read.to_src_lo = cpu_to_be32(1); 17428c2ecf20Sopenharmony_ci init->u.read.stag_sink = cpu_to_be32(1); 17438c2ecf20Sopenharmony_ci init->u.read.to_sink_lo = cpu_to_be32(1); 17448c2ecf20Sopenharmony_ci init->u.read.len16 = DIV_ROUND_UP(sizeof(init->u.read), 16); 17458c2ecf20Sopenharmony_ci break; 17468c2ecf20Sopenharmony_ci } 17478c2ecf20Sopenharmony_ci} 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_cistatic int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp) 17508c2ecf20Sopenharmony_ci{ 17518c2ecf20Sopenharmony_ci struct fw_ri_wr *wqe; 17528c2ecf20Sopenharmony_ci int ret; 17538c2ecf20Sopenharmony_ci struct sk_buff *skb; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci pr_debug("qhp %p qid 0x%x tid %u ird %u ord %u\n", qhp, 17568c2ecf20Sopenharmony_ci qhp->wq.sq.qid, qhp->ep->hwtid, qhp->ep->ird, qhp->ep->ord); 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci skb = alloc_skb(sizeof(*wqe), GFP_KERNEL); 17598c2ecf20Sopenharmony_ci if (!skb) { 17608c2ecf20Sopenharmony_ci ret = -ENOMEM; 17618c2ecf20Sopenharmony_ci goto out; 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci ret = alloc_ird(rhp, qhp->attr.max_ird); 17648c2ecf20Sopenharmony_ci if (ret) { 17658c2ecf20Sopenharmony_ci qhp->attr.max_ird = 0; 17668c2ecf20Sopenharmony_ci kfree_skb(skb); 17678c2ecf20Sopenharmony_ci goto out; 17688c2ecf20Sopenharmony_ci } 17698c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx); 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci wqe = __skb_put_zero(skb, sizeof(*wqe)); 17728c2ecf20Sopenharmony_ci wqe->op_compl = cpu_to_be32( 17738c2ecf20Sopenharmony_ci FW_WR_OP_V(FW_RI_INIT_WR) | 17748c2ecf20Sopenharmony_ci FW_WR_COMPL_F); 17758c2ecf20Sopenharmony_ci wqe->flowid_len16 = cpu_to_be32( 17768c2ecf20Sopenharmony_ci FW_WR_FLOWID_V(qhp->ep->hwtid) | 17778c2ecf20Sopenharmony_ci FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16))); 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci wqe->cookie = (uintptr_t)qhp->ep->com.wr_waitp; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci wqe->u.init.type = FW_RI_TYPE_INIT; 17828c2ecf20Sopenharmony_ci wqe->u.init.mpareqbit_p2ptype = 17838c2ecf20Sopenharmony_ci FW_RI_WR_MPAREQBIT_V(qhp->attr.mpa_attr.initiator) | 17848c2ecf20Sopenharmony_ci FW_RI_WR_P2PTYPE_V(qhp->attr.mpa_attr.p2p_type); 17858c2ecf20Sopenharmony_ci wqe->u.init.mpa_attrs = FW_RI_MPA_IETF_ENABLE; 17868c2ecf20Sopenharmony_ci if (qhp->attr.mpa_attr.recv_marker_enabled) 17878c2ecf20Sopenharmony_ci wqe->u.init.mpa_attrs |= FW_RI_MPA_RX_MARKER_ENABLE; 17888c2ecf20Sopenharmony_ci if (qhp->attr.mpa_attr.xmit_marker_enabled) 17898c2ecf20Sopenharmony_ci wqe->u.init.mpa_attrs |= FW_RI_MPA_TX_MARKER_ENABLE; 17908c2ecf20Sopenharmony_ci if (qhp->attr.mpa_attr.crc_enabled) 17918c2ecf20Sopenharmony_ci wqe->u.init.mpa_attrs |= FW_RI_MPA_CRC_ENABLE; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci wqe->u.init.qp_caps = FW_RI_QP_RDMA_READ_ENABLE | 17948c2ecf20Sopenharmony_ci FW_RI_QP_RDMA_WRITE_ENABLE | 17958c2ecf20Sopenharmony_ci FW_RI_QP_BIND_ENABLE; 17968c2ecf20Sopenharmony_ci if (!qhp->ibqp.uobject) 17978c2ecf20Sopenharmony_ci wqe->u.init.qp_caps |= FW_RI_QP_FAST_REGISTER_ENABLE | 17988c2ecf20Sopenharmony_ci FW_RI_QP_STAG0_ENABLE; 17998c2ecf20Sopenharmony_ci wqe->u.init.nrqe = cpu_to_be16(t4_rqes_posted(&qhp->wq)); 18008c2ecf20Sopenharmony_ci wqe->u.init.pdid = cpu_to_be32(qhp->attr.pd); 18018c2ecf20Sopenharmony_ci wqe->u.init.qpid = cpu_to_be32(qhp->wq.sq.qid); 18028c2ecf20Sopenharmony_ci wqe->u.init.sq_eqid = cpu_to_be32(qhp->wq.sq.qid); 18038c2ecf20Sopenharmony_ci if (qhp->srq) { 18048c2ecf20Sopenharmony_ci wqe->u.init.rq_eqid = cpu_to_be32(FW_RI_INIT_RQEQID_SRQ | 18058c2ecf20Sopenharmony_ci qhp->srq->idx); 18068c2ecf20Sopenharmony_ci } else { 18078c2ecf20Sopenharmony_ci wqe->u.init.rq_eqid = cpu_to_be32(qhp->wq.rq.qid); 18088c2ecf20Sopenharmony_ci wqe->u.init.hwrqsize = cpu_to_be32(qhp->wq.rq.rqt_size); 18098c2ecf20Sopenharmony_ci wqe->u.init.hwrqaddr = cpu_to_be32(qhp->wq.rq.rqt_hwaddr - 18108c2ecf20Sopenharmony_ci rhp->rdev.lldi.vr->rq.start); 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci wqe->u.init.scqid = cpu_to_be32(qhp->attr.scq); 18138c2ecf20Sopenharmony_ci wqe->u.init.rcqid = cpu_to_be32(qhp->attr.rcq); 18148c2ecf20Sopenharmony_ci wqe->u.init.ord_max = cpu_to_be32(qhp->attr.max_ord); 18158c2ecf20Sopenharmony_ci wqe->u.init.ird_max = cpu_to_be32(qhp->attr.max_ird); 18168c2ecf20Sopenharmony_ci wqe->u.init.iss = cpu_to_be32(qhp->ep->snd_seq); 18178c2ecf20Sopenharmony_ci wqe->u.init.irs = cpu_to_be32(qhp->ep->rcv_seq); 18188c2ecf20Sopenharmony_ci if (qhp->attr.mpa_attr.initiator) 18198c2ecf20Sopenharmony_ci build_rtr_msg(qhp->attr.mpa_attr.p2p_type, &wqe->u.init); 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci ret = c4iw_ref_send_wait(&rhp->rdev, skb, qhp->ep->com.wr_waitp, 18228c2ecf20Sopenharmony_ci qhp->ep->hwtid, qhp->wq.sq.qid, __func__); 18238c2ecf20Sopenharmony_ci if (!ret) 18248c2ecf20Sopenharmony_ci goto out; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci free_ird(rhp, qhp->attr.max_ird); 18278c2ecf20Sopenharmony_ciout: 18288c2ecf20Sopenharmony_ci pr_debug("ret %d\n", ret); 18298c2ecf20Sopenharmony_ci return ret; 18308c2ecf20Sopenharmony_ci} 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ciint c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, 18338c2ecf20Sopenharmony_ci enum c4iw_qp_attr_mask mask, 18348c2ecf20Sopenharmony_ci struct c4iw_qp_attributes *attrs, 18358c2ecf20Sopenharmony_ci int internal) 18368c2ecf20Sopenharmony_ci{ 18378c2ecf20Sopenharmony_ci int ret = 0; 18388c2ecf20Sopenharmony_ci struct c4iw_qp_attributes newattr = qhp->attr; 18398c2ecf20Sopenharmony_ci int disconnect = 0; 18408c2ecf20Sopenharmony_ci int terminate = 0; 18418c2ecf20Sopenharmony_ci int abort = 0; 18428c2ecf20Sopenharmony_ci int free = 0; 18438c2ecf20Sopenharmony_ci struct c4iw_ep *ep = NULL; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci pr_debug("qhp %p sqid 0x%x rqid 0x%x ep %p state %d -> %d\n", 18468c2ecf20Sopenharmony_ci qhp, qhp->wq.sq.qid, qhp->wq.rq.qid, qhp->ep, qhp->attr.state, 18478c2ecf20Sopenharmony_ci (mask & C4IW_QP_ATTR_NEXT_STATE) ? attrs->next_state : -1); 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci mutex_lock(&qhp->mutex); 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci /* Process attr changes if in IDLE */ 18528c2ecf20Sopenharmony_ci if (mask & C4IW_QP_ATTR_VALID_MODIFY) { 18538c2ecf20Sopenharmony_ci if (qhp->attr.state != C4IW_QP_STATE_IDLE) { 18548c2ecf20Sopenharmony_ci ret = -EIO; 18558c2ecf20Sopenharmony_ci goto out; 18568c2ecf20Sopenharmony_ci } 18578c2ecf20Sopenharmony_ci if (mask & C4IW_QP_ATTR_ENABLE_RDMA_READ) 18588c2ecf20Sopenharmony_ci newattr.enable_rdma_read = attrs->enable_rdma_read; 18598c2ecf20Sopenharmony_ci if (mask & C4IW_QP_ATTR_ENABLE_RDMA_WRITE) 18608c2ecf20Sopenharmony_ci newattr.enable_rdma_write = attrs->enable_rdma_write; 18618c2ecf20Sopenharmony_ci if (mask & C4IW_QP_ATTR_ENABLE_RDMA_BIND) 18628c2ecf20Sopenharmony_ci newattr.enable_bind = attrs->enable_bind; 18638c2ecf20Sopenharmony_ci if (mask & C4IW_QP_ATTR_MAX_ORD) { 18648c2ecf20Sopenharmony_ci if (attrs->max_ord > c4iw_max_read_depth) { 18658c2ecf20Sopenharmony_ci ret = -EINVAL; 18668c2ecf20Sopenharmony_ci goto out; 18678c2ecf20Sopenharmony_ci } 18688c2ecf20Sopenharmony_ci newattr.max_ord = attrs->max_ord; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci if (mask & C4IW_QP_ATTR_MAX_IRD) { 18718c2ecf20Sopenharmony_ci if (attrs->max_ird > cur_max_read_depth(rhp)) { 18728c2ecf20Sopenharmony_ci ret = -EINVAL; 18738c2ecf20Sopenharmony_ci goto out; 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci newattr.max_ird = attrs->max_ird; 18768c2ecf20Sopenharmony_ci } 18778c2ecf20Sopenharmony_ci qhp->attr = newattr; 18788c2ecf20Sopenharmony_ci } 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci if (mask & C4IW_QP_ATTR_SQ_DB) { 18818c2ecf20Sopenharmony_ci ret = ring_kernel_sq_db(qhp, attrs->sq_db_inc); 18828c2ecf20Sopenharmony_ci goto out; 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci if (mask & C4IW_QP_ATTR_RQ_DB) { 18858c2ecf20Sopenharmony_ci ret = ring_kernel_rq_db(qhp, attrs->rq_db_inc); 18868c2ecf20Sopenharmony_ci goto out; 18878c2ecf20Sopenharmony_ci } 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci if (!(mask & C4IW_QP_ATTR_NEXT_STATE)) 18908c2ecf20Sopenharmony_ci goto out; 18918c2ecf20Sopenharmony_ci if (qhp->attr.state == attrs->next_state) 18928c2ecf20Sopenharmony_ci goto out; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci switch (qhp->attr.state) { 18958c2ecf20Sopenharmony_ci case C4IW_QP_STATE_IDLE: 18968c2ecf20Sopenharmony_ci switch (attrs->next_state) { 18978c2ecf20Sopenharmony_ci case C4IW_QP_STATE_RTS: 18988c2ecf20Sopenharmony_ci if (!(mask & C4IW_QP_ATTR_LLP_STREAM_HANDLE)) { 18998c2ecf20Sopenharmony_ci ret = -EINVAL; 19008c2ecf20Sopenharmony_ci goto out; 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci if (!(mask & C4IW_QP_ATTR_MPA_ATTR)) { 19038c2ecf20Sopenharmony_ci ret = -EINVAL; 19048c2ecf20Sopenharmony_ci goto out; 19058c2ecf20Sopenharmony_ci } 19068c2ecf20Sopenharmony_ci qhp->attr.mpa_attr = attrs->mpa_attr; 19078c2ecf20Sopenharmony_ci qhp->attr.llp_stream_handle = attrs->llp_stream_handle; 19088c2ecf20Sopenharmony_ci qhp->ep = qhp->attr.llp_stream_handle; 19098c2ecf20Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_RTS); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci /* 19128c2ecf20Sopenharmony_ci * Ref the endpoint here and deref when we 19138c2ecf20Sopenharmony_ci * disassociate the endpoint from the QP. This 19148c2ecf20Sopenharmony_ci * happens in CLOSING->IDLE transition or *->ERROR 19158c2ecf20Sopenharmony_ci * transition. 19168c2ecf20Sopenharmony_ci */ 19178c2ecf20Sopenharmony_ci c4iw_get_ep(&qhp->ep->com); 19188c2ecf20Sopenharmony_ci ret = rdma_init(rhp, qhp); 19198c2ecf20Sopenharmony_ci if (ret) 19208c2ecf20Sopenharmony_ci goto err; 19218c2ecf20Sopenharmony_ci break; 19228c2ecf20Sopenharmony_ci case C4IW_QP_STATE_ERROR: 19238c2ecf20Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_ERROR); 19248c2ecf20Sopenharmony_ci flush_qp(qhp); 19258c2ecf20Sopenharmony_ci break; 19268c2ecf20Sopenharmony_ci default: 19278c2ecf20Sopenharmony_ci ret = -EINVAL; 19288c2ecf20Sopenharmony_ci goto out; 19298c2ecf20Sopenharmony_ci } 19308c2ecf20Sopenharmony_ci break; 19318c2ecf20Sopenharmony_ci case C4IW_QP_STATE_RTS: 19328c2ecf20Sopenharmony_ci switch (attrs->next_state) { 19338c2ecf20Sopenharmony_ci case C4IW_QP_STATE_CLOSING: 19348c2ecf20Sopenharmony_ci t4_set_wq_in_error(&qhp->wq, 0); 19358c2ecf20Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_CLOSING); 19368c2ecf20Sopenharmony_ci ep = qhp->ep; 19378c2ecf20Sopenharmony_ci if (!internal) { 19388c2ecf20Sopenharmony_ci abort = 0; 19398c2ecf20Sopenharmony_ci disconnect = 1; 19408c2ecf20Sopenharmony_ci c4iw_get_ep(&qhp->ep->com); 19418c2ecf20Sopenharmony_ci } 19428c2ecf20Sopenharmony_ci ret = rdma_fini(rhp, qhp, ep); 19438c2ecf20Sopenharmony_ci if (ret) 19448c2ecf20Sopenharmony_ci goto err; 19458c2ecf20Sopenharmony_ci break; 19468c2ecf20Sopenharmony_ci case C4IW_QP_STATE_TERMINATE: 19478c2ecf20Sopenharmony_ci t4_set_wq_in_error(&qhp->wq, 0); 19488c2ecf20Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_TERMINATE); 19498c2ecf20Sopenharmony_ci qhp->attr.layer_etype = attrs->layer_etype; 19508c2ecf20Sopenharmony_ci qhp->attr.ecode = attrs->ecode; 19518c2ecf20Sopenharmony_ci ep = qhp->ep; 19528c2ecf20Sopenharmony_ci if (!internal) { 19538c2ecf20Sopenharmony_ci c4iw_get_ep(&ep->com); 19548c2ecf20Sopenharmony_ci terminate = 1; 19558c2ecf20Sopenharmony_ci disconnect = 1; 19568c2ecf20Sopenharmony_ci } else { 19578c2ecf20Sopenharmony_ci terminate = qhp->attr.send_term; 19588c2ecf20Sopenharmony_ci ret = rdma_fini(rhp, qhp, ep); 19598c2ecf20Sopenharmony_ci if (ret) 19608c2ecf20Sopenharmony_ci goto err; 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci break; 19638c2ecf20Sopenharmony_ci case C4IW_QP_STATE_ERROR: 19648c2ecf20Sopenharmony_ci t4_set_wq_in_error(&qhp->wq, 0); 19658c2ecf20Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_ERROR); 19668c2ecf20Sopenharmony_ci if (!internal) { 19678c2ecf20Sopenharmony_ci abort = 1; 19688c2ecf20Sopenharmony_ci disconnect = 1; 19698c2ecf20Sopenharmony_ci ep = qhp->ep; 19708c2ecf20Sopenharmony_ci c4iw_get_ep(&qhp->ep->com); 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci goto err; 19738c2ecf20Sopenharmony_ci break; 19748c2ecf20Sopenharmony_ci default: 19758c2ecf20Sopenharmony_ci ret = -EINVAL; 19768c2ecf20Sopenharmony_ci goto out; 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci break; 19798c2ecf20Sopenharmony_ci case C4IW_QP_STATE_CLOSING: 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci /* 19828c2ecf20Sopenharmony_ci * Allow kernel users to move to ERROR for qp draining. 19838c2ecf20Sopenharmony_ci */ 19848c2ecf20Sopenharmony_ci if (!internal && (qhp->ibqp.uobject || attrs->next_state != 19858c2ecf20Sopenharmony_ci C4IW_QP_STATE_ERROR)) { 19868c2ecf20Sopenharmony_ci ret = -EINVAL; 19878c2ecf20Sopenharmony_ci goto out; 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci switch (attrs->next_state) { 19908c2ecf20Sopenharmony_ci case C4IW_QP_STATE_IDLE: 19918c2ecf20Sopenharmony_ci flush_qp(qhp); 19928c2ecf20Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_IDLE); 19938c2ecf20Sopenharmony_ci qhp->attr.llp_stream_handle = NULL; 19948c2ecf20Sopenharmony_ci c4iw_put_ep(&qhp->ep->com); 19958c2ecf20Sopenharmony_ci qhp->ep = NULL; 19968c2ecf20Sopenharmony_ci wake_up(&qhp->wait); 19978c2ecf20Sopenharmony_ci break; 19988c2ecf20Sopenharmony_ci case C4IW_QP_STATE_ERROR: 19998c2ecf20Sopenharmony_ci goto err; 20008c2ecf20Sopenharmony_ci default: 20018c2ecf20Sopenharmony_ci ret = -EINVAL; 20028c2ecf20Sopenharmony_ci goto err; 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci break; 20058c2ecf20Sopenharmony_ci case C4IW_QP_STATE_ERROR: 20068c2ecf20Sopenharmony_ci if (attrs->next_state != C4IW_QP_STATE_IDLE) { 20078c2ecf20Sopenharmony_ci ret = -EINVAL; 20088c2ecf20Sopenharmony_ci goto out; 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci if (!t4_sq_empty(&qhp->wq) || !t4_rq_empty(&qhp->wq)) { 20118c2ecf20Sopenharmony_ci ret = -EINVAL; 20128c2ecf20Sopenharmony_ci goto out; 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_IDLE); 20158c2ecf20Sopenharmony_ci break; 20168c2ecf20Sopenharmony_ci case C4IW_QP_STATE_TERMINATE: 20178c2ecf20Sopenharmony_ci if (!internal) { 20188c2ecf20Sopenharmony_ci ret = -EINVAL; 20198c2ecf20Sopenharmony_ci goto out; 20208c2ecf20Sopenharmony_ci } 20218c2ecf20Sopenharmony_ci goto err; 20228c2ecf20Sopenharmony_ci break; 20238c2ecf20Sopenharmony_ci default: 20248c2ecf20Sopenharmony_ci pr_err("%s in a bad state %d\n", __func__, qhp->attr.state); 20258c2ecf20Sopenharmony_ci ret = -EINVAL; 20268c2ecf20Sopenharmony_ci goto err; 20278c2ecf20Sopenharmony_ci break; 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci goto out; 20308c2ecf20Sopenharmony_cierr: 20318c2ecf20Sopenharmony_ci pr_debug("disassociating ep %p qpid 0x%x\n", qhp->ep, 20328c2ecf20Sopenharmony_ci qhp->wq.sq.qid); 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci /* disassociate the LLP connection */ 20358c2ecf20Sopenharmony_ci qhp->attr.llp_stream_handle = NULL; 20368c2ecf20Sopenharmony_ci if (!ep) 20378c2ecf20Sopenharmony_ci ep = qhp->ep; 20388c2ecf20Sopenharmony_ci qhp->ep = NULL; 20398c2ecf20Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_ERROR); 20408c2ecf20Sopenharmony_ci free = 1; 20418c2ecf20Sopenharmony_ci abort = 1; 20428c2ecf20Sopenharmony_ci flush_qp(qhp); 20438c2ecf20Sopenharmony_ci wake_up(&qhp->wait); 20448c2ecf20Sopenharmony_ciout: 20458c2ecf20Sopenharmony_ci mutex_unlock(&qhp->mutex); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci if (terminate) 20488c2ecf20Sopenharmony_ci post_terminate(qhp, NULL, internal ? GFP_ATOMIC : GFP_KERNEL); 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci /* 20518c2ecf20Sopenharmony_ci * If disconnect is 1, then we need to initiate a disconnect 20528c2ecf20Sopenharmony_ci * on the EP. This can be a normal close (RTS->CLOSING) or 20538c2ecf20Sopenharmony_ci * an abnormal close (RTS/CLOSING->ERROR). 20548c2ecf20Sopenharmony_ci */ 20558c2ecf20Sopenharmony_ci if (disconnect) { 20568c2ecf20Sopenharmony_ci c4iw_ep_disconnect(ep, abort, internal ? GFP_ATOMIC : 20578c2ecf20Sopenharmony_ci GFP_KERNEL); 20588c2ecf20Sopenharmony_ci c4iw_put_ep(&ep->com); 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci /* 20628c2ecf20Sopenharmony_ci * If free is 1, then we've disassociated the EP from the QP 20638c2ecf20Sopenharmony_ci * and we need to dereference the EP. 20648c2ecf20Sopenharmony_ci */ 20658c2ecf20Sopenharmony_ci if (free) 20668c2ecf20Sopenharmony_ci c4iw_put_ep(&ep->com); 20678c2ecf20Sopenharmony_ci pr_debug("exit state %d\n", qhp->attr.state); 20688c2ecf20Sopenharmony_ci return ret; 20698c2ecf20Sopenharmony_ci} 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ciint c4iw_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata) 20728c2ecf20Sopenharmony_ci{ 20738c2ecf20Sopenharmony_ci struct c4iw_dev *rhp; 20748c2ecf20Sopenharmony_ci struct c4iw_qp *qhp; 20758c2ecf20Sopenharmony_ci struct c4iw_ucontext *ucontext; 20768c2ecf20Sopenharmony_ci struct c4iw_qp_attributes attrs; 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci qhp = to_c4iw_qp(ib_qp); 20798c2ecf20Sopenharmony_ci rhp = qhp->rhp; 20808c2ecf20Sopenharmony_ci ucontext = qhp->ucontext; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci attrs.next_state = C4IW_QP_STATE_ERROR; 20838c2ecf20Sopenharmony_ci if (qhp->attr.state == C4IW_QP_STATE_TERMINATE) 20848c2ecf20Sopenharmony_ci c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); 20858c2ecf20Sopenharmony_ci else 20868c2ecf20Sopenharmony_ci c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); 20878c2ecf20Sopenharmony_ci wait_event(qhp->wait, !qhp->ep); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci xa_lock_irq(&rhp->qps); 20908c2ecf20Sopenharmony_ci __xa_erase(&rhp->qps, qhp->wq.sq.qid); 20918c2ecf20Sopenharmony_ci if (!list_empty(&qhp->db_fc_entry)) 20928c2ecf20Sopenharmony_ci list_del_init(&qhp->db_fc_entry); 20938c2ecf20Sopenharmony_ci xa_unlock_irq(&rhp->qps); 20948c2ecf20Sopenharmony_ci free_ird(rhp, qhp->attr.max_ird); 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci c4iw_qp_rem_ref(ib_qp); 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci wait_for_completion(&qhp->qp_rel_comp); 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci pr_debug("ib_qp %p qpid 0x%0x\n", ib_qp, qhp->wq.sq.qid); 21018c2ecf20Sopenharmony_ci pr_debug("qhp %p ucontext %p\n", qhp, ucontext); 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci destroy_qp(&rhp->rdev, &qhp->wq, 21048c2ecf20Sopenharmony_ci ucontext ? &ucontext->uctx : &rhp->rdev.uctx, !qhp->srq); 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci c4iw_put_wr_wait(qhp->wr_waitp); 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci kfree(qhp); 21098c2ecf20Sopenharmony_ci return 0; 21108c2ecf20Sopenharmony_ci} 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_cistruct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, 21138c2ecf20Sopenharmony_ci struct ib_udata *udata) 21148c2ecf20Sopenharmony_ci{ 21158c2ecf20Sopenharmony_ci struct c4iw_dev *rhp; 21168c2ecf20Sopenharmony_ci struct c4iw_qp *qhp; 21178c2ecf20Sopenharmony_ci struct c4iw_pd *php; 21188c2ecf20Sopenharmony_ci struct c4iw_cq *schp; 21198c2ecf20Sopenharmony_ci struct c4iw_cq *rchp; 21208c2ecf20Sopenharmony_ci struct c4iw_create_qp_resp uresp; 21218c2ecf20Sopenharmony_ci unsigned int sqsize, rqsize = 0; 21228c2ecf20Sopenharmony_ci struct c4iw_ucontext *ucontext = rdma_udata_to_drv_context( 21238c2ecf20Sopenharmony_ci udata, struct c4iw_ucontext, ibucontext); 21248c2ecf20Sopenharmony_ci int ret; 21258c2ecf20Sopenharmony_ci struct c4iw_mm_entry *sq_key_mm, *rq_key_mm = NULL, *sq_db_key_mm; 21268c2ecf20Sopenharmony_ci struct c4iw_mm_entry *rq_db_key_mm = NULL, *ma_sync_key_mm = NULL; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci pr_debug("ib_pd %p\n", pd); 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci if (attrs->qp_type != IB_QPT_RC) 21318c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci php = to_c4iw_pd(pd); 21348c2ecf20Sopenharmony_ci rhp = php->rhp; 21358c2ecf20Sopenharmony_ci schp = get_chp(rhp, ((struct c4iw_cq *)attrs->send_cq)->cq.cqid); 21368c2ecf20Sopenharmony_ci rchp = get_chp(rhp, ((struct c4iw_cq *)attrs->recv_cq)->cq.cqid); 21378c2ecf20Sopenharmony_ci if (!schp || !rchp) 21388c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci if (attrs->cap.max_inline_data > T4_MAX_SEND_INLINE) 21418c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci if (!attrs->srq) { 21448c2ecf20Sopenharmony_ci if (attrs->cap.max_recv_wr > rhp->rdev.hw_queue.t4_max_rq_size) 21458c2ecf20Sopenharmony_ci return ERR_PTR(-E2BIG); 21468c2ecf20Sopenharmony_ci rqsize = attrs->cap.max_recv_wr + 1; 21478c2ecf20Sopenharmony_ci if (rqsize < 8) 21488c2ecf20Sopenharmony_ci rqsize = 8; 21498c2ecf20Sopenharmony_ci } 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci if (attrs->cap.max_send_wr > rhp->rdev.hw_queue.t4_max_sq_size) 21528c2ecf20Sopenharmony_ci return ERR_PTR(-E2BIG); 21538c2ecf20Sopenharmony_ci sqsize = attrs->cap.max_send_wr + 1; 21548c2ecf20Sopenharmony_ci if (sqsize < 8) 21558c2ecf20Sopenharmony_ci sqsize = 8; 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci qhp = kzalloc(sizeof(*qhp), GFP_KERNEL); 21588c2ecf20Sopenharmony_ci if (!qhp) 21598c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci qhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL); 21628c2ecf20Sopenharmony_ci if (!qhp->wr_waitp) { 21638c2ecf20Sopenharmony_ci ret = -ENOMEM; 21648c2ecf20Sopenharmony_ci goto err_free_qhp; 21658c2ecf20Sopenharmony_ci } 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci qhp->wq.sq.size = sqsize; 21688c2ecf20Sopenharmony_ci qhp->wq.sq.memsize = 21698c2ecf20Sopenharmony_ci (sqsize + rhp->rdev.hw_queue.t4_eq_status_entries) * 21708c2ecf20Sopenharmony_ci sizeof(*qhp->wq.sq.queue) + 16 * sizeof(__be64); 21718c2ecf20Sopenharmony_ci qhp->wq.sq.flush_cidx = -1; 21728c2ecf20Sopenharmony_ci if (!attrs->srq) { 21738c2ecf20Sopenharmony_ci qhp->wq.rq.size = rqsize; 21748c2ecf20Sopenharmony_ci qhp->wq.rq.memsize = 21758c2ecf20Sopenharmony_ci (rqsize + rhp->rdev.hw_queue.t4_eq_status_entries) * 21768c2ecf20Sopenharmony_ci sizeof(*qhp->wq.rq.queue); 21778c2ecf20Sopenharmony_ci } 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci if (ucontext) { 21808c2ecf20Sopenharmony_ci qhp->wq.sq.memsize = roundup(qhp->wq.sq.memsize, PAGE_SIZE); 21818c2ecf20Sopenharmony_ci if (!attrs->srq) 21828c2ecf20Sopenharmony_ci qhp->wq.rq.memsize = 21838c2ecf20Sopenharmony_ci roundup(qhp->wq.rq.memsize, PAGE_SIZE); 21848c2ecf20Sopenharmony_ci } 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci ret = create_qp(&rhp->rdev, &qhp->wq, &schp->cq, &rchp->cq, 21878c2ecf20Sopenharmony_ci ucontext ? &ucontext->uctx : &rhp->rdev.uctx, 21888c2ecf20Sopenharmony_ci qhp->wr_waitp, !attrs->srq); 21898c2ecf20Sopenharmony_ci if (ret) 21908c2ecf20Sopenharmony_ci goto err_free_wr_wait; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci attrs->cap.max_recv_wr = rqsize - 1; 21938c2ecf20Sopenharmony_ci attrs->cap.max_send_wr = sqsize - 1; 21948c2ecf20Sopenharmony_ci attrs->cap.max_inline_data = T4_MAX_SEND_INLINE; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci qhp->rhp = rhp; 21978c2ecf20Sopenharmony_ci qhp->attr.pd = php->pdid; 21988c2ecf20Sopenharmony_ci qhp->attr.scq = ((struct c4iw_cq *) attrs->send_cq)->cq.cqid; 21998c2ecf20Sopenharmony_ci qhp->attr.rcq = ((struct c4iw_cq *) attrs->recv_cq)->cq.cqid; 22008c2ecf20Sopenharmony_ci qhp->attr.sq_num_entries = attrs->cap.max_send_wr; 22018c2ecf20Sopenharmony_ci qhp->attr.sq_max_sges = attrs->cap.max_send_sge; 22028c2ecf20Sopenharmony_ci qhp->attr.sq_max_sges_rdma_write = attrs->cap.max_send_sge; 22038c2ecf20Sopenharmony_ci if (!attrs->srq) { 22048c2ecf20Sopenharmony_ci qhp->attr.rq_num_entries = attrs->cap.max_recv_wr; 22058c2ecf20Sopenharmony_ci qhp->attr.rq_max_sges = attrs->cap.max_recv_sge; 22068c2ecf20Sopenharmony_ci } 22078c2ecf20Sopenharmony_ci qhp->attr.state = C4IW_QP_STATE_IDLE; 22088c2ecf20Sopenharmony_ci qhp->attr.next_state = C4IW_QP_STATE_IDLE; 22098c2ecf20Sopenharmony_ci qhp->attr.enable_rdma_read = 1; 22108c2ecf20Sopenharmony_ci qhp->attr.enable_rdma_write = 1; 22118c2ecf20Sopenharmony_ci qhp->attr.enable_bind = 1; 22128c2ecf20Sopenharmony_ci qhp->attr.max_ord = 0; 22138c2ecf20Sopenharmony_ci qhp->attr.max_ird = 0; 22148c2ecf20Sopenharmony_ci qhp->sq_sig_all = attrs->sq_sig_type == IB_SIGNAL_ALL_WR; 22158c2ecf20Sopenharmony_ci spin_lock_init(&qhp->lock); 22168c2ecf20Sopenharmony_ci mutex_init(&qhp->mutex); 22178c2ecf20Sopenharmony_ci init_waitqueue_head(&qhp->wait); 22188c2ecf20Sopenharmony_ci init_completion(&qhp->qp_rel_comp); 22198c2ecf20Sopenharmony_ci refcount_set(&qhp->qp_refcnt, 1); 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci ret = xa_insert_irq(&rhp->qps, qhp->wq.sq.qid, qhp, GFP_KERNEL); 22228c2ecf20Sopenharmony_ci if (ret) 22238c2ecf20Sopenharmony_ci goto err_destroy_qp; 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci if (udata && ucontext) { 22268c2ecf20Sopenharmony_ci sq_key_mm = kmalloc(sizeof(*sq_key_mm), GFP_KERNEL); 22278c2ecf20Sopenharmony_ci if (!sq_key_mm) { 22288c2ecf20Sopenharmony_ci ret = -ENOMEM; 22298c2ecf20Sopenharmony_ci goto err_remove_handle; 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ci if (!attrs->srq) { 22328c2ecf20Sopenharmony_ci rq_key_mm = kmalloc(sizeof(*rq_key_mm), GFP_KERNEL); 22338c2ecf20Sopenharmony_ci if (!rq_key_mm) { 22348c2ecf20Sopenharmony_ci ret = -ENOMEM; 22358c2ecf20Sopenharmony_ci goto err_free_sq_key; 22368c2ecf20Sopenharmony_ci } 22378c2ecf20Sopenharmony_ci } 22388c2ecf20Sopenharmony_ci sq_db_key_mm = kmalloc(sizeof(*sq_db_key_mm), GFP_KERNEL); 22398c2ecf20Sopenharmony_ci if (!sq_db_key_mm) { 22408c2ecf20Sopenharmony_ci ret = -ENOMEM; 22418c2ecf20Sopenharmony_ci goto err_free_rq_key; 22428c2ecf20Sopenharmony_ci } 22438c2ecf20Sopenharmony_ci if (!attrs->srq) { 22448c2ecf20Sopenharmony_ci rq_db_key_mm = 22458c2ecf20Sopenharmony_ci kmalloc(sizeof(*rq_db_key_mm), GFP_KERNEL); 22468c2ecf20Sopenharmony_ci if (!rq_db_key_mm) { 22478c2ecf20Sopenharmony_ci ret = -ENOMEM; 22488c2ecf20Sopenharmony_ci goto err_free_sq_db_key; 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci } 22518c2ecf20Sopenharmony_ci memset(&uresp, 0, sizeof(uresp)); 22528c2ecf20Sopenharmony_ci if (t4_sq_onchip(&qhp->wq.sq)) { 22538c2ecf20Sopenharmony_ci ma_sync_key_mm = kmalloc(sizeof(*ma_sync_key_mm), 22548c2ecf20Sopenharmony_ci GFP_KERNEL); 22558c2ecf20Sopenharmony_ci if (!ma_sync_key_mm) { 22568c2ecf20Sopenharmony_ci ret = -ENOMEM; 22578c2ecf20Sopenharmony_ci goto err_free_rq_db_key; 22588c2ecf20Sopenharmony_ci } 22598c2ecf20Sopenharmony_ci uresp.flags = C4IW_QPF_ONCHIP; 22608c2ecf20Sopenharmony_ci } 22618c2ecf20Sopenharmony_ci if (rhp->rdev.lldi.write_w_imm_support) 22628c2ecf20Sopenharmony_ci uresp.flags |= C4IW_QPF_WRITE_W_IMM; 22638c2ecf20Sopenharmony_ci uresp.qid_mask = rhp->rdev.qpmask; 22648c2ecf20Sopenharmony_ci uresp.sqid = qhp->wq.sq.qid; 22658c2ecf20Sopenharmony_ci uresp.sq_size = qhp->wq.sq.size; 22668c2ecf20Sopenharmony_ci uresp.sq_memsize = qhp->wq.sq.memsize; 22678c2ecf20Sopenharmony_ci if (!attrs->srq) { 22688c2ecf20Sopenharmony_ci uresp.rqid = qhp->wq.rq.qid; 22698c2ecf20Sopenharmony_ci uresp.rq_size = qhp->wq.rq.size; 22708c2ecf20Sopenharmony_ci uresp.rq_memsize = qhp->wq.rq.memsize; 22718c2ecf20Sopenharmony_ci } 22728c2ecf20Sopenharmony_ci spin_lock(&ucontext->mmap_lock); 22738c2ecf20Sopenharmony_ci if (ma_sync_key_mm) { 22748c2ecf20Sopenharmony_ci uresp.ma_sync_key = ucontext->key; 22758c2ecf20Sopenharmony_ci ucontext->key += PAGE_SIZE; 22768c2ecf20Sopenharmony_ci } 22778c2ecf20Sopenharmony_ci uresp.sq_key = ucontext->key; 22788c2ecf20Sopenharmony_ci ucontext->key += PAGE_SIZE; 22798c2ecf20Sopenharmony_ci if (!attrs->srq) { 22808c2ecf20Sopenharmony_ci uresp.rq_key = ucontext->key; 22818c2ecf20Sopenharmony_ci ucontext->key += PAGE_SIZE; 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci uresp.sq_db_gts_key = ucontext->key; 22848c2ecf20Sopenharmony_ci ucontext->key += PAGE_SIZE; 22858c2ecf20Sopenharmony_ci if (!attrs->srq) { 22868c2ecf20Sopenharmony_ci uresp.rq_db_gts_key = ucontext->key; 22878c2ecf20Sopenharmony_ci ucontext->key += PAGE_SIZE; 22888c2ecf20Sopenharmony_ci } 22898c2ecf20Sopenharmony_ci spin_unlock(&ucontext->mmap_lock); 22908c2ecf20Sopenharmony_ci ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); 22918c2ecf20Sopenharmony_ci if (ret) 22928c2ecf20Sopenharmony_ci goto err_free_ma_sync_key; 22938c2ecf20Sopenharmony_ci sq_key_mm->key = uresp.sq_key; 22948c2ecf20Sopenharmony_ci sq_key_mm->addr = qhp->wq.sq.phys_addr; 22958c2ecf20Sopenharmony_ci sq_key_mm->len = PAGE_ALIGN(qhp->wq.sq.memsize); 22968c2ecf20Sopenharmony_ci insert_mmap(ucontext, sq_key_mm); 22978c2ecf20Sopenharmony_ci if (!attrs->srq) { 22988c2ecf20Sopenharmony_ci rq_key_mm->key = uresp.rq_key; 22998c2ecf20Sopenharmony_ci rq_key_mm->addr = virt_to_phys(qhp->wq.rq.queue); 23008c2ecf20Sopenharmony_ci rq_key_mm->len = PAGE_ALIGN(qhp->wq.rq.memsize); 23018c2ecf20Sopenharmony_ci insert_mmap(ucontext, rq_key_mm); 23028c2ecf20Sopenharmony_ci } 23038c2ecf20Sopenharmony_ci sq_db_key_mm->key = uresp.sq_db_gts_key; 23048c2ecf20Sopenharmony_ci sq_db_key_mm->addr = (u64)(unsigned long)qhp->wq.sq.bar2_pa; 23058c2ecf20Sopenharmony_ci sq_db_key_mm->len = PAGE_SIZE; 23068c2ecf20Sopenharmony_ci insert_mmap(ucontext, sq_db_key_mm); 23078c2ecf20Sopenharmony_ci if (!attrs->srq) { 23088c2ecf20Sopenharmony_ci rq_db_key_mm->key = uresp.rq_db_gts_key; 23098c2ecf20Sopenharmony_ci rq_db_key_mm->addr = 23108c2ecf20Sopenharmony_ci (u64)(unsigned long)qhp->wq.rq.bar2_pa; 23118c2ecf20Sopenharmony_ci rq_db_key_mm->len = PAGE_SIZE; 23128c2ecf20Sopenharmony_ci insert_mmap(ucontext, rq_db_key_mm); 23138c2ecf20Sopenharmony_ci } 23148c2ecf20Sopenharmony_ci if (ma_sync_key_mm) { 23158c2ecf20Sopenharmony_ci ma_sync_key_mm->key = uresp.ma_sync_key; 23168c2ecf20Sopenharmony_ci ma_sync_key_mm->addr = 23178c2ecf20Sopenharmony_ci (pci_resource_start(rhp->rdev.lldi.pdev, 0) + 23188c2ecf20Sopenharmony_ci PCIE_MA_SYNC_A) & PAGE_MASK; 23198c2ecf20Sopenharmony_ci ma_sync_key_mm->len = PAGE_SIZE; 23208c2ecf20Sopenharmony_ci insert_mmap(ucontext, ma_sync_key_mm); 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci qhp->ucontext = ucontext; 23248c2ecf20Sopenharmony_ci } 23258c2ecf20Sopenharmony_ci if (!attrs->srq) { 23268c2ecf20Sopenharmony_ci qhp->wq.qp_errp = 23278c2ecf20Sopenharmony_ci &qhp->wq.rq.queue[qhp->wq.rq.size].status.qp_err; 23288c2ecf20Sopenharmony_ci } else { 23298c2ecf20Sopenharmony_ci qhp->wq.qp_errp = 23308c2ecf20Sopenharmony_ci &qhp->wq.sq.queue[qhp->wq.sq.size].status.qp_err; 23318c2ecf20Sopenharmony_ci qhp->wq.srqidxp = 23328c2ecf20Sopenharmony_ci &qhp->wq.sq.queue[qhp->wq.sq.size].status.srqidx; 23338c2ecf20Sopenharmony_ci } 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci qhp->ibqp.qp_num = qhp->wq.sq.qid; 23368c2ecf20Sopenharmony_ci if (attrs->srq) 23378c2ecf20Sopenharmony_ci qhp->srq = to_c4iw_srq(attrs->srq); 23388c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qhp->db_fc_entry); 23398c2ecf20Sopenharmony_ci pr_debug("sq id %u size %u memsize %zu num_entries %u rq id %u size %u memsize %zu num_entries %u\n", 23408c2ecf20Sopenharmony_ci qhp->wq.sq.qid, qhp->wq.sq.size, qhp->wq.sq.memsize, 23418c2ecf20Sopenharmony_ci attrs->cap.max_send_wr, qhp->wq.rq.qid, qhp->wq.rq.size, 23428c2ecf20Sopenharmony_ci qhp->wq.rq.memsize, attrs->cap.max_recv_wr); 23438c2ecf20Sopenharmony_ci return &qhp->ibqp; 23448c2ecf20Sopenharmony_cierr_free_ma_sync_key: 23458c2ecf20Sopenharmony_ci kfree(ma_sync_key_mm); 23468c2ecf20Sopenharmony_cierr_free_rq_db_key: 23478c2ecf20Sopenharmony_ci if (!attrs->srq) 23488c2ecf20Sopenharmony_ci kfree(rq_db_key_mm); 23498c2ecf20Sopenharmony_cierr_free_sq_db_key: 23508c2ecf20Sopenharmony_ci kfree(sq_db_key_mm); 23518c2ecf20Sopenharmony_cierr_free_rq_key: 23528c2ecf20Sopenharmony_ci if (!attrs->srq) 23538c2ecf20Sopenharmony_ci kfree(rq_key_mm); 23548c2ecf20Sopenharmony_cierr_free_sq_key: 23558c2ecf20Sopenharmony_ci kfree(sq_key_mm); 23568c2ecf20Sopenharmony_cierr_remove_handle: 23578c2ecf20Sopenharmony_ci xa_erase_irq(&rhp->qps, qhp->wq.sq.qid); 23588c2ecf20Sopenharmony_cierr_destroy_qp: 23598c2ecf20Sopenharmony_ci destroy_qp(&rhp->rdev, &qhp->wq, 23608c2ecf20Sopenharmony_ci ucontext ? &ucontext->uctx : &rhp->rdev.uctx, !attrs->srq); 23618c2ecf20Sopenharmony_cierr_free_wr_wait: 23628c2ecf20Sopenharmony_ci c4iw_put_wr_wait(qhp->wr_waitp); 23638c2ecf20Sopenharmony_cierr_free_qhp: 23648c2ecf20Sopenharmony_ci kfree(qhp); 23658c2ecf20Sopenharmony_ci return ERR_PTR(ret); 23668c2ecf20Sopenharmony_ci} 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ciint c4iw_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 23698c2ecf20Sopenharmony_ci int attr_mask, struct ib_udata *udata) 23708c2ecf20Sopenharmony_ci{ 23718c2ecf20Sopenharmony_ci struct c4iw_dev *rhp; 23728c2ecf20Sopenharmony_ci struct c4iw_qp *qhp; 23738c2ecf20Sopenharmony_ci enum c4iw_qp_attr_mask mask = 0; 23748c2ecf20Sopenharmony_ci struct c4iw_qp_attributes attrs = {}; 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci pr_debug("ib_qp %p\n", ibqp); 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci /* iwarp does not support the RTR state */ 23798c2ecf20Sopenharmony_ci if ((attr_mask & IB_QP_STATE) && (attr->qp_state == IB_QPS_RTR)) 23808c2ecf20Sopenharmony_ci attr_mask &= ~IB_QP_STATE; 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci /* Make sure we still have something left to do */ 23838c2ecf20Sopenharmony_ci if (!attr_mask) 23848c2ecf20Sopenharmony_ci return 0; 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci qhp = to_c4iw_qp(ibqp); 23878c2ecf20Sopenharmony_ci rhp = qhp->rhp; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci attrs.next_state = c4iw_convert_state(attr->qp_state); 23908c2ecf20Sopenharmony_ci attrs.enable_rdma_read = (attr->qp_access_flags & 23918c2ecf20Sopenharmony_ci IB_ACCESS_REMOTE_READ) ? 1 : 0; 23928c2ecf20Sopenharmony_ci attrs.enable_rdma_write = (attr->qp_access_flags & 23938c2ecf20Sopenharmony_ci IB_ACCESS_REMOTE_WRITE) ? 1 : 0; 23948c2ecf20Sopenharmony_ci attrs.enable_bind = (attr->qp_access_flags & IB_ACCESS_MW_BIND) ? 1 : 0; 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci mask |= (attr_mask & IB_QP_STATE) ? C4IW_QP_ATTR_NEXT_STATE : 0; 23988c2ecf20Sopenharmony_ci mask |= (attr_mask & IB_QP_ACCESS_FLAGS) ? 23998c2ecf20Sopenharmony_ci (C4IW_QP_ATTR_ENABLE_RDMA_READ | 24008c2ecf20Sopenharmony_ci C4IW_QP_ATTR_ENABLE_RDMA_WRITE | 24018c2ecf20Sopenharmony_ci C4IW_QP_ATTR_ENABLE_RDMA_BIND) : 0; 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci /* 24048c2ecf20Sopenharmony_ci * Use SQ_PSN and RQ_PSN to pass in IDX_INC values for 24058c2ecf20Sopenharmony_ci * ringing the queue db when we're in DB_FULL mode. 24068c2ecf20Sopenharmony_ci * Only allow this on T4 devices. 24078c2ecf20Sopenharmony_ci */ 24088c2ecf20Sopenharmony_ci attrs.sq_db_inc = attr->sq_psn; 24098c2ecf20Sopenharmony_ci attrs.rq_db_inc = attr->rq_psn; 24108c2ecf20Sopenharmony_ci mask |= (attr_mask & IB_QP_SQ_PSN) ? C4IW_QP_ATTR_SQ_DB : 0; 24118c2ecf20Sopenharmony_ci mask |= (attr_mask & IB_QP_RQ_PSN) ? C4IW_QP_ATTR_RQ_DB : 0; 24128c2ecf20Sopenharmony_ci if (!is_t4(to_c4iw_qp(ibqp)->rhp->rdev.lldi.adapter_type) && 24138c2ecf20Sopenharmony_ci (mask & (C4IW_QP_ATTR_SQ_DB|C4IW_QP_ATTR_RQ_DB))) 24148c2ecf20Sopenharmony_ci return -EINVAL; 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci return c4iw_modify_qp(rhp, qhp, mask, &attrs, 0); 24178c2ecf20Sopenharmony_ci} 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_cistruct ib_qp *c4iw_get_qp(struct ib_device *dev, int qpn) 24208c2ecf20Sopenharmony_ci{ 24218c2ecf20Sopenharmony_ci pr_debug("ib_dev %p qpn 0x%x\n", dev, qpn); 24228c2ecf20Sopenharmony_ci return (struct ib_qp *)get_qhp(to_c4iw_dev(dev), qpn); 24238c2ecf20Sopenharmony_ci} 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_civoid c4iw_dispatch_srq_limit_reached_event(struct c4iw_srq *srq) 24268c2ecf20Sopenharmony_ci{ 24278c2ecf20Sopenharmony_ci struct ib_event event = {}; 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ci event.device = &srq->rhp->ibdev; 24308c2ecf20Sopenharmony_ci event.element.srq = &srq->ibsrq; 24318c2ecf20Sopenharmony_ci event.event = IB_EVENT_SRQ_LIMIT_REACHED; 24328c2ecf20Sopenharmony_ci ib_dispatch_event(&event); 24338c2ecf20Sopenharmony_ci} 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ciint c4iw_modify_srq(struct ib_srq *ib_srq, struct ib_srq_attr *attr, 24368c2ecf20Sopenharmony_ci enum ib_srq_attr_mask srq_attr_mask, 24378c2ecf20Sopenharmony_ci struct ib_udata *udata) 24388c2ecf20Sopenharmony_ci{ 24398c2ecf20Sopenharmony_ci struct c4iw_srq *srq = to_c4iw_srq(ib_srq); 24408c2ecf20Sopenharmony_ci int ret = 0; 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci /* 24438c2ecf20Sopenharmony_ci * XXX 0 mask == a SW interrupt for srq_limit reached... 24448c2ecf20Sopenharmony_ci */ 24458c2ecf20Sopenharmony_ci if (udata && !srq_attr_mask) { 24468c2ecf20Sopenharmony_ci c4iw_dispatch_srq_limit_reached_event(srq); 24478c2ecf20Sopenharmony_ci goto out; 24488c2ecf20Sopenharmony_ci } 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci /* no support for this yet */ 24518c2ecf20Sopenharmony_ci if (srq_attr_mask & IB_SRQ_MAX_WR) { 24528c2ecf20Sopenharmony_ci ret = -EINVAL; 24538c2ecf20Sopenharmony_ci goto out; 24548c2ecf20Sopenharmony_ci } 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci if (!udata && (srq_attr_mask & IB_SRQ_LIMIT)) { 24578c2ecf20Sopenharmony_ci srq->armed = true; 24588c2ecf20Sopenharmony_ci srq->srq_limit = attr->srq_limit; 24598c2ecf20Sopenharmony_ci } 24608c2ecf20Sopenharmony_ciout: 24618c2ecf20Sopenharmony_ci return ret; 24628c2ecf20Sopenharmony_ci} 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ciint c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 24658c2ecf20Sopenharmony_ci int attr_mask, struct ib_qp_init_attr *init_attr) 24668c2ecf20Sopenharmony_ci{ 24678c2ecf20Sopenharmony_ci struct c4iw_qp *qhp = to_c4iw_qp(ibqp); 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci memset(attr, 0, sizeof(*attr)); 24708c2ecf20Sopenharmony_ci memset(init_attr, 0, sizeof(*init_attr)); 24718c2ecf20Sopenharmony_ci attr->qp_state = to_ib_qp_state(qhp->attr.state); 24728c2ecf20Sopenharmony_ci attr->cur_qp_state = to_ib_qp_state(qhp->attr.state); 24738c2ecf20Sopenharmony_ci init_attr->cap.max_send_wr = qhp->attr.sq_num_entries; 24748c2ecf20Sopenharmony_ci init_attr->cap.max_recv_wr = qhp->attr.rq_num_entries; 24758c2ecf20Sopenharmony_ci init_attr->cap.max_send_sge = qhp->attr.sq_max_sges; 24768c2ecf20Sopenharmony_ci init_attr->cap.max_recv_sge = qhp->attr.rq_max_sges; 24778c2ecf20Sopenharmony_ci init_attr->cap.max_inline_data = T4_MAX_SEND_INLINE; 24788c2ecf20Sopenharmony_ci init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : 0; 24798c2ecf20Sopenharmony_ci return 0; 24808c2ecf20Sopenharmony_ci} 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_cistatic void free_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx, 24838c2ecf20Sopenharmony_ci struct c4iw_wr_wait *wr_waitp) 24848c2ecf20Sopenharmony_ci{ 24858c2ecf20Sopenharmony_ci struct c4iw_rdev *rdev = &srq->rhp->rdev; 24868c2ecf20Sopenharmony_ci struct sk_buff *skb = srq->destroy_skb; 24878c2ecf20Sopenharmony_ci struct t4_srq *wq = &srq->wq; 24888c2ecf20Sopenharmony_ci struct fw_ri_res_wr *res_wr; 24898c2ecf20Sopenharmony_ci struct fw_ri_res *res; 24908c2ecf20Sopenharmony_ci int wr_len; 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci wr_len = sizeof(*res_wr) + sizeof(*res); 24938c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ci res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len); 24968c2ecf20Sopenharmony_ci memset(res_wr, 0, wr_len); 24978c2ecf20Sopenharmony_ci res_wr->op_nres = cpu_to_be32(FW_WR_OP_V(FW_RI_RES_WR) | 24988c2ecf20Sopenharmony_ci FW_RI_RES_WR_NRES_V(1) | 24998c2ecf20Sopenharmony_ci FW_WR_COMPL_F); 25008c2ecf20Sopenharmony_ci res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); 25018c2ecf20Sopenharmony_ci res_wr->cookie = (uintptr_t)wr_waitp; 25028c2ecf20Sopenharmony_ci res = res_wr->res; 25038c2ecf20Sopenharmony_ci res->u.srq.restype = FW_RI_RES_TYPE_SRQ; 25048c2ecf20Sopenharmony_ci res->u.srq.op = FW_RI_RES_OP_RESET; 25058c2ecf20Sopenharmony_ci res->u.srq.srqid = cpu_to_be32(srq->idx); 25068c2ecf20Sopenharmony_ci res->u.srq.eqid = cpu_to_be32(wq->qid); 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci c4iw_init_wr_wait(wr_waitp); 25098c2ecf20Sopenharmony_ci c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__); 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci dma_free_coherent(&rdev->lldi.pdev->dev, 25128c2ecf20Sopenharmony_ci wq->memsize, wq->queue, 25138c2ecf20Sopenharmony_ci dma_unmap_addr(wq, mapping)); 25148c2ecf20Sopenharmony_ci c4iw_rqtpool_free(rdev, wq->rqt_hwaddr, wq->rqt_size); 25158c2ecf20Sopenharmony_ci kfree(wq->sw_rq); 25168c2ecf20Sopenharmony_ci c4iw_put_qpid(rdev, wq->qid, uctx); 25178c2ecf20Sopenharmony_ci} 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_cistatic int alloc_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx, 25208c2ecf20Sopenharmony_ci struct c4iw_wr_wait *wr_waitp) 25218c2ecf20Sopenharmony_ci{ 25228c2ecf20Sopenharmony_ci struct c4iw_rdev *rdev = &srq->rhp->rdev; 25238c2ecf20Sopenharmony_ci int user = (uctx != &rdev->uctx); 25248c2ecf20Sopenharmony_ci struct t4_srq *wq = &srq->wq; 25258c2ecf20Sopenharmony_ci struct fw_ri_res_wr *res_wr; 25268c2ecf20Sopenharmony_ci struct fw_ri_res *res; 25278c2ecf20Sopenharmony_ci struct sk_buff *skb; 25288c2ecf20Sopenharmony_ci int wr_len; 25298c2ecf20Sopenharmony_ci int eqsize; 25308c2ecf20Sopenharmony_ci int ret = -ENOMEM; 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci wq->qid = c4iw_get_qpid(rdev, uctx); 25338c2ecf20Sopenharmony_ci if (!wq->qid) 25348c2ecf20Sopenharmony_ci goto err; 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci if (!user) { 25378c2ecf20Sopenharmony_ci wq->sw_rq = kcalloc(wq->size, sizeof(*wq->sw_rq), 25388c2ecf20Sopenharmony_ci GFP_KERNEL); 25398c2ecf20Sopenharmony_ci if (!wq->sw_rq) 25408c2ecf20Sopenharmony_ci goto err_put_qpid; 25418c2ecf20Sopenharmony_ci wq->pending_wrs = kcalloc(srq->wq.size, 25428c2ecf20Sopenharmony_ci sizeof(*srq->wq.pending_wrs), 25438c2ecf20Sopenharmony_ci GFP_KERNEL); 25448c2ecf20Sopenharmony_ci if (!wq->pending_wrs) 25458c2ecf20Sopenharmony_ci goto err_free_sw_rq; 25468c2ecf20Sopenharmony_ci } 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci wq->rqt_size = wq->size; 25498c2ecf20Sopenharmony_ci wq->rqt_hwaddr = c4iw_rqtpool_alloc(rdev, wq->rqt_size); 25508c2ecf20Sopenharmony_ci if (!wq->rqt_hwaddr) 25518c2ecf20Sopenharmony_ci goto err_free_pending_wrs; 25528c2ecf20Sopenharmony_ci wq->rqt_abs_idx = (wq->rqt_hwaddr - rdev->lldi.vr->rq.start) >> 25538c2ecf20Sopenharmony_ci T4_RQT_ENTRY_SHIFT; 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci wq->queue = dma_alloc_coherent(&rdev->lldi.pdev->dev, wq->memsize, 25568c2ecf20Sopenharmony_ci &wq->dma_addr, GFP_KERNEL); 25578c2ecf20Sopenharmony_ci if (!wq->queue) 25588c2ecf20Sopenharmony_ci goto err_free_rqtpool; 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci dma_unmap_addr_set(wq, mapping, wq->dma_addr); 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci wq->bar2_va = c4iw_bar2_addrs(rdev, wq->qid, CXGB4_BAR2_QTYPE_EGRESS, 25638c2ecf20Sopenharmony_ci &wq->bar2_qid, 25648c2ecf20Sopenharmony_ci user ? &wq->bar2_pa : NULL); 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci /* 25678c2ecf20Sopenharmony_ci * User mode must have bar2 access. 25688c2ecf20Sopenharmony_ci */ 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci if (user && !wq->bar2_va) { 25718c2ecf20Sopenharmony_ci pr_warn(MOD "%s: srqid %u not in BAR2 range.\n", 25728c2ecf20Sopenharmony_ci pci_name(rdev->lldi.pdev), wq->qid); 25738c2ecf20Sopenharmony_ci ret = -EINVAL; 25748c2ecf20Sopenharmony_ci goto err_free_queue; 25758c2ecf20Sopenharmony_ci } 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci /* build fw_ri_res_wr */ 25788c2ecf20Sopenharmony_ci wr_len = sizeof(*res_wr) + sizeof(*res); 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci skb = alloc_skb(wr_len, GFP_KERNEL); 25818c2ecf20Sopenharmony_ci if (!skb) 25828c2ecf20Sopenharmony_ci goto err_free_queue; 25838c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len); 25868c2ecf20Sopenharmony_ci memset(res_wr, 0, wr_len); 25878c2ecf20Sopenharmony_ci res_wr->op_nres = cpu_to_be32(FW_WR_OP_V(FW_RI_RES_WR) | 25888c2ecf20Sopenharmony_ci FW_RI_RES_WR_NRES_V(1) | 25898c2ecf20Sopenharmony_ci FW_WR_COMPL_F); 25908c2ecf20Sopenharmony_ci res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); 25918c2ecf20Sopenharmony_ci res_wr->cookie = (uintptr_t)wr_waitp; 25928c2ecf20Sopenharmony_ci res = res_wr->res; 25938c2ecf20Sopenharmony_ci res->u.srq.restype = FW_RI_RES_TYPE_SRQ; 25948c2ecf20Sopenharmony_ci res->u.srq.op = FW_RI_RES_OP_WRITE; 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci /* 25978c2ecf20Sopenharmony_ci * eqsize is the number of 64B entries plus the status page size. 25988c2ecf20Sopenharmony_ci */ 25998c2ecf20Sopenharmony_ci eqsize = wq->size * T4_RQ_NUM_SLOTS + 26008c2ecf20Sopenharmony_ci rdev->hw_queue.t4_eq_status_entries; 26018c2ecf20Sopenharmony_ci res->u.srq.eqid = cpu_to_be32(wq->qid); 26028c2ecf20Sopenharmony_ci res->u.srq.fetchszm_to_iqid = 26038c2ecf20Sopenharmony_ci /* no host cidx updates */ 26048c2ecf20Sopenharmony_ci cpu_to_be32(FW_RI_RES_WR_HOSTFCMODE_V(0) | 26058c2ecf20Sopenharmony_ci FW_RI_RES_WR_CPRIO_V(0) | /* don't keep in chip cache */ 26068c2ecf20Sopenharmony_ci FW_RI_RES_WR_PCIECHN_V(0) | /* set by uP at ri_init time */ 26078c2ecf20Sopenharmony_ci FW_RI_RES_WR_FETCHRO_V(0)); /* relaxed_ordering */ 26088c2ecf20Sopenharmony_ci res->u.srq.dcaen_to_eqsize = 26098c2ecf20Sopenharmony_ci cpu_to_be32(FW_RI_RES_WR_DCAEN_V(0) | 26108c2ecf20Sopenharmony_ci FW_RI_RES_WR_DCACPU_V(0) | 26118c2ecf20Sopenharmony_ci FW_RI_RES_WR_FBMIN_V(2) | 26128c2ecf20Sopenharmony_ci FW_RI_RES_WR_FBMAX_V(3) | 26138c2ecf20Sopenharmony_ci FW_RI_RES_WR_CIDXFTHRESHO_V(0) | 26148c2ecf20Sopenharmony_ci FW_RI_RES_WR_CIDXFTHRESH_V(0) | 26158c2ecf20Sopenharmony_ci FW_RI_RES_WR_EQSIZE_V(eqsize)); 26168c2ecf20Sopenharmony_ci res->u.srq.eqaddr = cpu_to_be64(wq->dma_addr); 26178c2ecf20Sopenharmony_ci res->u.srq.srqid = cpu_to_be32(srq->idx); 26188c2ecf20Sopenharmony_ci res->u.srq.pdid = cpu_to_be32(srq->pdid); 26198c2ecf20Sopenharmony_ci res->u.srq.hwsrqsize = cpu_to_be32(wq->rqt_size); 26208c2ecf20Sopenharmony_ci res->u.srq.hwsrqaddr = cpu_to_be32(wq->rqt_hwaddr - 26218c2ecf20Sopenharmony_ci rdev->lldi.vr->rq.start); 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci c4iw_init_wr_wait(wr_waitp); 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, wq->qid, __func__); 26268c2ecf20Sopenharmony_ci if (ret) 26278c2ecf20Sopenharmony_ci goto err_free_queue; 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci pr_debug("%s srq %u eqid %u pdid %u queue va %p pa 0x%llx\n" 26308c2ecf20Sopenharmony_ci " bar2_addr %p rqt addr 0x%x size %d\n", 26318c2ecf20Sopenharmony_ci __func__, srq->idx, wq->qid, srq->pdid, wq->queue, 26328c2ecf20Sopenharmony_ci (u64)virt_to_phys(wq->queue), wq->bar2_va, 26338c2ecf20Sopenharmony_ci wq->rqt_hwaddr, wq->rqt_size); 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci return 0; 26368c2ecf20Sopenharmony_cierr_free_queue: 26378c2ecf20Sopenharmony_ci dma_free_coherent(&rdev->lldi.pdev->dev, 26388c2ecf20Sopenharmony_ci wq->memsize, wq->queue, 26398c2ecf20Sopenharmony_ci dma_unmap_addr(wq, mapping)); 26408c2ecf20Sopenharmony_cierr_free_rqtpool: 26418c2ecf20Sopenharmony_ci c4iw_rqtpool_free(rdev, wq->rqt_hwaddr, wq->rqt_size); 26428c2ecf20Sopenharmony_cierr_free_pending_wrs: 26438c2ecf20Sopenharmony_ci if (!user) 26448c2ecf20Sopenharmony_ci kfree(wq->pending_wrs); 26458c2ecf20Sopenharmony_cierr_free_sw_rq: 26468c2ecf20Sopenharmony_ci if (!user) 26478c2ecf20Sopenharmony_ci kfree(wq->sw_rq); 26488c2ecf20Sopenharmony_cierr_put_qpid: 26498c2ecf20Sopenharmony_ci c4iw_put_qpid(rdev, wq->qid, uctx); 26508c2ecf20Sopenharmony_cierr: 26518c2ecf20Sopenharmony_ci return ret; 26528c2ecf20Sopenharmony_ci} 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_civoid c4iw_copy_wr_to_srq(struct t4_srq *srq, union t4_recv_wr *wqe, u8 len16) 26558c2ecf20Sopenharmony_ci{ 26568c2ecf20Sopenharmony_ci u64 *src, *dst; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci src = (u64 *)wqe; 26598c2ecf20Sopenharmony_ci dst = (u64 *)((u8 *)srq->queue + srq->wq_pidx * T4_EQ_ENTRY_SIZE); 26608c2ecf20Sopenharmony_ci while (len16) { 26618c2ecf20Sopenharmony_ci *dst++ = *src++; 26628c2ecf20Sopenharmony_ci if (dst >= (u64 *)&srq->queue[srq->size]) 26638c2ecf20Sopenharmony_ci dst = (u64 *)srq->queue; 26648c2ecf20Sopenharmony_ci *dst++ = *src++; 26658c2ecf20Sopenharmony_ci if (dst >= (u64 *)&srq->queue[srq->size]) 26668c2ecf20Sopenharmony_ci dst = (u64 *)srq->queue; 26678c2ecf20Sopenharmony_ci len16--; 26688c2ecf20Sopenharmony_ci } 26698c2ecf20Sopenharmony_ci} 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ciint c4iw_create_srq(struct ib_srq *ib_srq, struct ib_srq_init_attr *attrs, 26728c2ecf20Sopenharmony_ci struct ib_udata *udata) 26738c2ecf20Sopenharmony_ci{ 26748c2ecf20Sopenharmony_ci struct ib_pd *pd = ib_srq->pd; 26758c2ecf20Sopenharmony_ci struct c4iw_dev *rhp; 26768c2ecf20Sopenharmony_ci struct c4iw_srq *srq = to_c4iw_srq(ib_srq); 26778c2ecf20Sopenharmony_ci struct c4iw_pd *php; 26788c2ecf20Sopenharmony_ci struct c4iw_create_srq_resp uresp; 26798c2ecf20Sopenharmony_ci struct c4iw_ucontext *ucontext; 26808c2ecf20Sopenharmony_ci struct c4iw_mm_entry *srq_key_mm, *srq_db_key_mm; 26818c2ecf20Sopenharmony_ci int rqsize; 26828c2ecf20Sopenharmony_ci int ret; 26838c2ecf20Sopenharmony_ci int wr_len; 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci pr_debug("%s ib_pd %p\n", __func__, pd); 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci php = to_c4iw_pd(pd); 26888c2ecf20Sopenharmony_ci rhp = php->rhp; 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci if (!rhp->rdev.lldi.vr->srq.size) 26918c2ecf20Sopenharmony_ci return -EINVAL; 26928c2ecf20Sopenharmony_ci if (attrs->attr.max_wr > rhp->rdev.hw_queue.t4_max_rq_size) 26938c2ecf20Sopenharmony_ci return -E2BIG; 26948c2ecf20Sopenharmony_ci if (attrs->attr.max_sge > T4_MAX_RECV_SGE) 26958c2ecf20Sopenharmony_ci return -E2BIG; 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci /* 26988c2ecf20Sopenharmony_ci * SRQ RQT and RQ must be a power of 2 and at least 16 deep. 26998c2ecf20Sopenharmony_ci */ 27008c2ecf20Sopenharmony_ci rqsize = attrs->attr.max_wr + 1; 27018c2ecf20Sopenharmony_ci rqsize = roundup_pow_of_two(max_t(u16, rqsize, 16)); 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci ucontext = rdma_udata_to_drv_context(udata, struct c4iw_ucontext, 27048c2ecf20Sopenharmony_ci ibucontext); 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci srq->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL); 27078c2ecf20Sopenharmony_ci if (!srq->wr_waitp) 27088c2ecf20Sopenharmony_ci return -ENOMEM; 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci srq->idx = c4iw_alloc_srq_idx(&rhp->rdev); 27118c2ecf20Sopenharmony_ci if (srq->idx < 0) { 27128c2ecf20Sopenharmony_ci ret = -ENOMEM; 27138c2ecf20Sopenharmony_ci goto err_free_wr_wait; 27148c2ecf20Sopenharmony_ci } 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ci wr_len = sizeof(struct fw_ri_res_wr) + sizeof(struct fw_ri_res); 27178c2ecf20Sopenharmony_ci srq->destroy_skb = alloc_skb(wr_len, GFP_KERNEL); 27188c2ecf20Sopenharmony_ci if (!srq->destroy_skb) { 27198c2ecf20Sopenharmony_ci ret = -ENOMEM; 27208c2ecf20Sopenharmony_ci goto err_free_srq_idx; 27218c2ecf20Sopenharmony_ci } 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ci srq->rhp = rhp; 27248c2ecf20Sopenharmony_ci srq->pdid = php->pdid; 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci srq->wq.size = rqsize; 27278c2ecf20Sopenharmony_ci srq->wq.memsize = 27288c2ecf20Sopenharmony_ci (rqsize + rhp->rdev.hw_queue.t4_eq_status_entries) * 27298c2ecf20Sopenharmony_ci sizeof(*srq->wq.queue); 27308c2ecf20Sopenharmony_ci if (ucontext) 27318c2ecf20Sopenharmony_ci srq->wq.memsize = roundup(srq->wq.memsize, PAGE_SIZE); 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci ret = alloc_srq_queue(srq, ucontext ? &ucontext->uctx : 27348c2ecf20Sopenharmony_ci &rhp->rdev.uctx, srq->wr_waitp); 27358c2ecf20Sopenharmony_ci if (ret) 27368c2ecf20Sopenharmony_ci goto err_free_skb; 27378c2ecf20Sopenharmony_ci attrs->attr.max_wr = rqsize - 1; 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci if (CHELSIO_CHIP_VERSION(rhp->rdev.lldi.adapter_type) > CHELSIO_T6) 27408c2ecf20Sopenharmony_ci srq->flags = T4_SRQ_LIMIT_SUPPORT; 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci if (udata) { 27438c2ecf20Sopenharmony_ci srq_key_mm = kmalloc(sizeof(*srq_key_mm), GFP_KERNEL); 27448c2ecf20Sopenharmony_ci if (!srq_key_mm) { 27458c2ecf20Sopenharmony_ci ret = -ENOMEM; 27468c2ecf20Sopenharmony_ci goto err_free_queue; 27478c2ecf20Sopenharmony_ci } 27488c2ecf20Sopenharmony_ci srq_db_key_mm = kmalloc(sizeof(*srq_db_key_mm), GFP_KERNEL); 27498c2ecf20Sopenharmony_ci if (!srq_db_key_mm) { 27508c2ecf20Sopenharmony_ci ret = -ENOMEM; 27518c2ecf20Sopenharmony_ci goto err_free_srq_key_mm; 27528c2ecf20Sopenharmony_ci } 27538c2ecf20Sopenharmony_ci memset(&uresp, 0, sizeof(uresp)); 27548c2ecf20Sopenharmony_ci uresp.flags = srq->flags; 27558c2ecf20Sopenharmony_ci uresp.qid_mask = rhp->rdev.qpmask; 27568c2ecf20Sopenharmony_ci uresp.srqid = srq->wq.qid; 27578c2ecf20Sopenharmony_ci uresp.srq_size = srq->wq.size; 27588c2ecf20Sopenharmony_ci uresp.srq_memsize = srq->wq.memsize; 27598c2ecf20Sopenharmony_ci uresp.rqt_abs_idx = srq->wq.rqt_abs_idx; 27608c2ecf20Sopenharmony_ci spin_lock(&ucontext->mmap_lock); 27618c2ecf20Sopenharmony_ci uresp.srq_key = ucontext->key; 27628c2ecf20Sopenharmony_ci ucontext->key += PAGE_SIZE; 27638c2ecf20Sopenharmony_ci uresp.srq_db_gts_key = ucontext->key; 27648c2ecf20Sopenharmony_ci ucontext->key += PAGE_SIZE; 27658c2ecf20Sopenharmony_ci spin_unlock(&ucontext->mmap_lock); 27668c2ecf20Sopenharmony_ci ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); 27678c2ecf20Sopenharmony_ci if (ret) 27688c2ecf20Sopenharmony_ci goto err_free_srq_db_key_mm; 27698c2ecf20Sopenharmony_ci srq_key_mm->key = uresp.srq_key; 27708c2ecf20Sopenharmony_ci srq_key_mm->addr = virt_to_phys(srq->wq.queue); 27718c2ecf20Sopenharmony_ci srq_key_mm->len = PAGE_ALIGN(srq->wq.memsize); 27728c2ecf20Sopenharmony_ci insert_mmap(ucontext, srq_key_mm); 27738c2ecf20Sopenharmony_ci srq_db_key_mm->key = uresp.srq_db_gts_key; 27748c2ecf20Sopenharmony_ci srq_db_key_mm->addr = (u64)(unsigned long)srq->wq.bar2_pa; 27758c2ecf20Sopenharmony_ci srq_db_key_mm->len = PAGE_SIZE; 27768c2ecf20Sopenharmony_ci insert_mmap(ucontext, srq_db_key_mm); 27778c2ecf20Sopenharmony_ci } 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci pr_debug("%s srq qid %u idx %u size %u memsize %lu num_entries %u\n", 27808c2ecf20Sopenharmony_ci __func__, srq->wq.qid, srq->idx, srq->wq.size, 27818c2ecf20Sopenharmony_ci (unsigned long)srq->wq.memsize, attrs->attr.max_wr); 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci spin_lock_init(&srq->lock); 27848c2ecf20Sopenharmony_ci return 0; 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_cierr_free_srq_db_key_mm: 27878c2ecf20Sopenharmony_ci kfree(srq_db_key_mm); 27888c2ecf20Sopenharmony_cierr_free_srq_key_mm: 27898c2ecf20Sopenharmony_ci kfree(srq_key_mm); 27908c2ecf20Sopenharmony_cierr_free_queue: 27918c2ecf20Sopenharmony_ci free_srq_queue(srq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx, 27928c2ecf20Sopenharmony_ci srq->wr_waitp); 27938c2ecf20Sopenharmony_cierr_free_skb: 27948c2ecf20Sopenharmony_ci kfree_skb(srq->destroy_skb); 27958c2ecf20Sopenharmony_cierr_free_srq_idx: 27968c2ecf20Sopenharmony_ci c4iw_free_srq_idx(&rhp->rdev, srq->idx); 27978c2ecf20Sopenharmony_cierr_free_wr_wait: 27988c2ecf20Sopenharmony_ci c4iw_put_wr_wait(srq->wr_waitp); 27998c2ecf20Sopenharmony_ci return ret; 28008c2ecf20Sopenharmony_ci} 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ciint c4iw_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata) 28038c2ecf20Sopenharmony_ci{ 28048c2ecf20Sopenharmony_ci struct c4iw_dev *rhp; 28058c2ecf20Sopenharmony_ci struct c4iw_srq *srq; 28068c2ecf20Sopenharmony_ci struct c4iw_ucontext *ucontext; 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_ci srq = to_c4iw_srq(ibsrq); 28098c2ecf20Sopenharmony_ci rhp = srq->rhp; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci pr_debug("%s id %d\n", __func__, srq->wq.qid); 28128c2ecf20Sopenharmony_ci ucontext = rdma_udata_to_drv_context(udata, struct c4iw_ucontext, 28138c2ecf20Sopenharmony_ci ibucontext); 28148c2ecf20Sopenharmony_ci free_srq_queue(srq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx, 28158c2ecf20Sopenharmony_ci srq->wr_waitp); 28168c2ecf20Sopenharmony_ci c4iw_free_srq_idx(&rhp->rdev, srq->idx); 28178c2ecf20Sopenharmony_ci c4iw_put_wr_wait(srq->wr_waitp); 28188c2ecf20Sopenharmony_ci return 0; 28198c2ecf20Sopenharmony_ci} 2820