162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/module.h> 3462306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include "iw_cxgb4.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int db_delay_usecs = 1; 3962306a36Sopenharmony_cimodule_param(db_delay_usecs, int, 0644); 4062306a36Sopenharmony_ciMODULE_PARM_DESC(db_delay_usecs, "Usecs to delay awaiting db fifo to drain"); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic int ocqp_support = 1; 4362306a36Sopenharmony_cimodule_param(ocqp_support, int, 0644); 4462306a36Sopenharmony_ciMODULE_PARM_DESC(ocqp_support, "Support on-chip SQs (default=1)"); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ciint db_fc_threshold = 1000; 4762306a36Sopenharmony_cimodule_param(db_fc_threshold, int, 0644); 4862306a36Sopenharmony_ciMODULE_PARM_DESC(db_fc_threshold, 4962306a36Sopenharmony_ci "QP count/threshold that triggers" 5062306a36Sopenharmony_ci " automatic db flow control mode (default = 1000)"); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ciint db_coalescing_threshold; 5362306a36Sopenharmony_cimodule_param(db_coalescing_threshold, int, 0644); 5462306a36Sopenharmony_ciMODULE_PARM_DESC(db_coalescing_threshold, 5562306a36Sopenharmony_ci "QP count/threshold that triggers" 5662306a36Sopenharmony_ci " disabling db coalescing (default = 0)"); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int max_fr_immd = T4_MAX_FR_IMMD; 5962306a36Sopenharmony_cimodule_param(max_fr_immd, int, 0644); 6062306a36Sopenharmony_ciMODULE_PARM_DESC(max_fr_immd, "fastreg threshold for using DSGL instead of immediate"); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic int alloc_ird(struct c4iw_dev *dev, u32 ird) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci int ret = 0; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci xa_lock_irq(&dev->qps); 6762306a36Sopenharmony_ci if (ird <= dev->avail_ird) 6862306a36Sopenharmony_ci dev->avail_ird -= ird; 6962306a36Sopenharmony_ci else 7062306a36Sopenharmony_ci ret = -ENOMEM; 7162306a36Sopenharmony_ci xa_unlock_irq(&dev->qps); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (ret) 7462306a36Sopenharmony_ci dev_warn(&dev->rdev.lldi.pdev->dev, 7562306a36Sopenharmony_ci "device IRD resources exhausted\n"); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return ret; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic void free_ird(struct c4iw_dev *dev, int ird) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci xa_lock_irq(&dev->qps); 8362306a36Sopenharmony_ci dev->avail_ird += ird; 8462306a36Sopenharmony_ci xa_unlock_irq(&dev->qps); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci unsigned long flag; 9062306a36Sopenharmony_ci spin_lock_irqsave(&qhp->lock, flag); 9162306a36Sopenharmony_ci qhp->attr.state = state; 9262306a36Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic void dealloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci c4iw_ocqp_pool_free(rdev, sq->dma_addr, sq->memsize); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic void dealloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci dma_free_coherent(&(rdev->lldi.pdev->dev), sq->memsize, sq->queue, 10362306a36Sopenharmony_ci dma_unmap_addr(sq, mapping)); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void dealloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci if (t4_sq_onchip(sq)) 10962306a36Sopenharmony_ci dealloc_oc_sq(rdev, sq); 11062306a36Sopenharmony_ci else 11162306a36Sopenharmony_ci dealloc_host_sq(rdev, sq); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int alloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci if (!ocqp_support || !ocqp_supported(&rdev->lldi)) 11762306a36Sopenharmony_ci return -ENOSYS; 11862306a36Sopenharmony_ci sq->dma_addr = c4iw_ocqp_pool_alloc(rdev, sq->memsize); 11962306a36Sopenharmony_ci if (!sq->dma_addr) 12062306a36Sopenharmony_ci return -ENOMEM; 12162306a36Sopenharmony_ci sq->phys_addr = rdev->oc_mw_pa + sq->dma_addr - 12262306a36Sopenharmony_ci rdev->lldi.vr->ocq.start; 12362306a36Sopenharmony_ci sq->queue = (__force union t4_wr *)(rdev->oc_mw_kva + sq->dma_addr - 12462306a36Sopenharmony_ci rdev->lldi.vr->ocq.start); 12562306a36Sopenharmony_ci sq->flags |= T4_SQ_ONCHIP; 12662306a36Sopenharmony_ci return 0; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci sq->queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev), sq->memsize, 13262306a36Sopenharmony_ci &(sq->dma_addr), GFP_KERNEL); 13362306a36Sopenharmony_ci if (!sq->queue) 13462306a36Sopenharmony_ci return -ENOMEM; 13562306a36Sopenharmony_ci sq->phys_addr = virt_to_phys(sq->queue); 13662306a36Sopenharmony_ci dma_unmap_addr_set(sq, mapping, sq->dma_addr); 13762306a36Sopenharmony_ci return 0; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic int alloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq, int user) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci int ret = -ENOSYS; 14362306a36Sopenharmony_ci if (user) 14462306a36Sopenharmony_ci ret = alloc_oc_sq(rdev, sq); 14562306a36Sopenharmony_ci if (ret) 14662306a36Sopenharmony_ci ret = alloc_host_sq(rdev, sq); 14762306a36Sopenharmony_ci return ret; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, 15162306a36Sopenharmony_ci struct c4iw_dev_ucontext *uctx, int has_rq) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci /* 15462306a36Sopenharmony_ci * uP clears EQ contexts when the connection exits rdma mode, 15562306a36Sopenharmony_ci * so no need to post a RESET WR for these EQs. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_ci dealloc_sq(rdev, &wq->sq); 15862306a36Sopenharmony_ci kfree(wq->sq.sw_sq); 15962306a36Sopenharmony_ci c4iw_put_qpid(rdev, wq->sq.qid, uctx); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (has_rq) { 16262306a36Sopenharmony_ci dma_free_coherent(&rdev->lldi.pdev->dev, 16362306a36Sopenharmony_ci wq->rq.memsize, wq->rq.queue, 16462306a36Sopenharmony_ci dma_unmap_addr(&wq->rq, mapping)); 16562306a36Sopenharmony_ci c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size); 16662306a36Sopenharmony_ci kfree(wq->rq.sw_rq); 16762306a36Sopenharmony_ci c4iw_put_qpid(rdev, wq->rq.qid, uctx); 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* 17362306a36Sopenharmony_ci * Determine the BAR2 virtual address and qid. If pbar2_pa is not NULL, 17462306a36Sopenharmony_ci * then this is a user mapping so compute the page-aligned physical address 17562306a36Sopenharmony_ci * for mapping. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_civoid __iomem *c4iw_bar2_addrs(struct c4iw_rdev *rdev, unsigned int qid, 17862306a36Sopenharmony_ci enum cxgb4_bar2_qtype qtype, 17962306a36Sopenharmony_ci unsigned int *pbar2_qid, u64 *pbar2_pa) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci u64 bar2_qoffset; 18262306a36Sopenharmony_ci int ret; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci ret = cxgb4_bar2_sge_qregs(rdev->lldi.ports[0], qid, qtype, 18562306a36Sopenharmony_ci pbar2_pa ? 1 : 0, 18662306a36Sopenharmony_ci &bar2_qoffset, pbar2_qid); 18762306a36Sopenharmony_ci if (ret) 18862306a36Sopenharmony_ci return NULL; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (pbar2_pa) 19162306a36Sopenharmony_ci *pbar2_pa = (rdev->bar2_pa + bar2_qoffset) & PAGE_MASK; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (is_t4(rdev->lldi.adapter_type)) 19462306a36Sopenharmony_ci return NULL; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return rdev->bar2_kva + bar2_qoffset; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, 20062306a36Sopenharmony_ci struct t4_cq *rcq, struct t4_cq *scq, 20162306a36Sopenharmony_ci struct c4iw_dev_ucontext *uctx, 20262306a36Sopenharmony_ci struct c4iw_wr_wait *wr_waitp, 20362306a36Sopenharmony_ci int need_rq) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci int user = (uctx != &rdev->uctx); 20662306a36Sopenharmony_ci struct fw_ri_res_wr *res_wr; 20762306a36Sopenharmony_ci struct fw_ri_res *res; 20862306a36Sopenharmony_ci int wr_len; 20962306a36Sopenharmony_ci struct sk_buff *skb; 21062306a36Sopenharmony_ci int ret = 0; 21162306a36Sopenharmony_ci int eqsize; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci wq->sq.qid = c4iw_get_qpid(rdev, uctx); 21462306a36Sopenharmony_ci if (!wq->sq.qid) 21562306a36Sopenharmony_ci return -ENOMEM; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (need_rq) { 21862306a36Sopenharmony_ci wq->rq.qid = c4iw_get_qpid(rdev, uctx); 21962306a36Sopenharmony_ci if (!wq->rq.qid) { 22062306a36Sopenharmony_ci ret = -ENOMEM; 22162306a36Sopenharmony_ci goto free_sq_qid; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (!user) { 22662306a36Sopenharmony_ci wq->sq.sw_sq = kcalloc(wq->sq.size, sizeof(*wq->sq.sw_sq), 22762306a36Sopenharmony_ci GFP_KERNEL); 22862306a36Sopenharmony_ci if (!wq->sq.sw_sq) { 22962306a36Sopenharmony_ci ret = -ENOMEM; 23062306a36Sopenharmony_ci goto free_rq_qid;//FIXME 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (need_rq) { 23462306a36Sopenharmony_ci wq->rq.sw_rq = kcalloc(wq->rq.size, 23562306a36Sopenharmony_ci sizeof(*wq->rq.sw_rq), 23662306a36Sopenharmony_ci GFP_KERNEL); 23762306a36Sopenharmony_ci if (!wq->rq.sw_rq) { 23862306a36Sopenharmony_ci ret = -ENOMEM; 23962306a36Sopenharmony_ci goto free_sw_sq; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (need_rq) { 24562306a36Sopenharmony_ci /* 24662306a36Sopenharmony_ci * RQT must be a power of 2 and at least 16 deep. 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_ci wq->rq.rqt_size = 24962306a36Sopenharmony_ci roundup_pow_of_two(max_t(u16, wq->rq.size, 16)); 25062306a36Sopenharmony_ci wq->rq.rqt_hwaddr = c4iw_rqtpool_alloc(rdev, wq->rq.rqt_size); 25162306a36Sopenharmony_ci if (!wq->rq.rqt_hwaddr) { 25262306a36Sopenharmony_ci ret = -ENOMEM; 25362306a36Sopenharmony_ci goto free_sw_rq; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci ret = alloc_sq(rdev, &wq->sq, user); 25862306a36Sopenharmony_ci if (ret) 25962306a36Sopenharmony_ci goto free_hwaddr; 26062306a36Sopenharmony_ci memset(wq->sq.queue, 0, wq->sq.memsize); 26162306a36Sopenharmony_ci dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (need_rq) { 26462306a36Sopenharmony_ci wq->rq.queue = dma_alloc_coherent(&rdev->lldi.pdev->dev, 26562306a36Sopenharmony_ci wq->rq.memsize, 26662306a36Sopenharmony_ci &wq->rq.dma_addr, 26762306a36Sopenharmony_ci GFP_KERNEL); 26862306a36Sopenharmony_ci if (!wq->rq.queue) { 26962306a36Sopenharmony_ci ret = -ENOMEM; 27062306a36Sopenharmony_ci goto free_sq; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci pr_debug("sq base va 0x%p pa 0x%llx rq base va 0x%p pa 0x%llx\n", 27362306a36Sopenharmony_ci wq->sq.queue, 27462306a36Sopenharmony_ci (unsigned long long)virt_to_phys(wq->sq.queue), 27562306a36Sopenharmony_ci wq->rq.queue, 27662306a36Sopenharmony_ci (unsigned long long)virt_to_phys(wq->rq.queue)); 27762306a36Sopenharmony_ci dma_unmap_addr_set(&wq->rq, mapping, wq->rq.dma_addr); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci wq->db = rdev->lldi.db_reg; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci wq->sq.bar2_va = c4iw_bar2_addrs(rdev, wq->sq.qid, 28362306a36Sopenharmony_ci CXGB4_BAR2_QTYPE_EGRESS, 28462306a36Sopenharmony_ci &wq->sq.bar2_qid, 28562306a36Sopenharmony_ci user ? &wq->sq.bar2_pa : NULL); 28662306a36Sopenharmony_ci if (need_rq) 28762306a36Sopenharmony_ci wq->rq.bar2_va = c4iw_bar2_addrs(rdev, wq->rq.qid, 28862306a36Sopenharmony_ci CXGB4_BAR2_QTYPE_EGRESS, 28962306a36Sopenharmony_ci &wq->rq.bar2_qid, 29062306a36Sopenharmony_ci user ? &wq->rq.bar2_pa : NULL); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* 29362306a36Sopenharmony_ci * User mode must have bar2 access. 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_ci if (user && (!wq->sq.bar2_pa || (need_rq && !wq->rq.bar2_pa))) { 29662306a36Sopenharmony_ci pr_warn("%s: sqid %u or rqid %u not in BAR2 range\n", 29762306a36Sopenharmony_ci pci_name(rdev->lldi.pdev), wq->sq.qid, wq->rq.qid); 29862306a36Sopenharmony_ci ret = -EINVAL; 29962306a36Sopenharmony_ci goto free_dma; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci wq->rdev = rdev; 30362306a36Sopenharmony_ci wq->rq.msn = 1; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* build fw_ri_res_wr */ 30662306a36Sopenharmony_ci wr_len = sizeof(*res_wr) + 2 * sizeof(*res); 30762306a36Sopenharmony_ci if (need_rq) 30862306a36Sopenharmony_ci wr_len += sizeof(*res); 30962306a36Sopenharmony_ci skb = alloc_skb(wr_len, GFP_KERNEL); 31062306a36Sopenharmony_ci if (!skb) { 31162306a36Sopenharmony_ci ret = -ENOMEM; 31262306a36Sopenharmony_ci goto free_dma; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci res_wr = __skb_put_zero(skb, wr_len); 31762306a36Sopenharmony_ci res_wr->op_nres = cpu_to_be32( 31862306a36Sopenharmony_ci FW_WR_OP_V(FW_RI_RES_WR) | 31962306a36Sopenharmony_ci FW_RI_RES_WR_NRES_V(need_rq ? 2 : 1) | 32062306a36Sopenharmony_ci FW_WR_COMPL_F); 32162306a36Sopenharmony_ci res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); 32262306a36Sopenharmony_ci res_wr->cookie = (uintptr_t)wr_waitp; 32362306a36Sopenharmony_ci res = res_wr->res; 32462306a36Sopenharmony_ci res->u.sqrq.restype = FW_RI_RES_TYPE_SQ; 32562306a36Sopenharmony_ci res->u.sqrq.op = FW_RI_RES_OP_WRITE; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* 32862306a36Sopenharmony_ci * eqsize is the number of 64B entries plus the status page size. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci eqsize = wq->sq.size * T4_SQ_NUM_SLOTS + 33162306a36Sopenharmony_ci rdev->hw_queue.t4_eq_status_entries; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci res->u.sqrq.fetchszm_to_iqid = cpu_to_be32( 33462306a36Sopenharmony_ci FW_RI_RES_WR_HOSTFCMODE_V(0) | /* no host cidx updates */ 33562306a36Sopenharmony_ci FW_RI_RES_WR_CPRIO_V(0) | /* don't keep in chip cache */ 33662306a36Sopenharmony_ci FW_RI_RES_WR_PCIECHN_V(0) | /* set by uP at ri_init time */ 33762306a36Sopenharmony_ci (t4_sq_onchip(&wq->sq) ? FW_RI_RES_WR_ONCHIP_F : 0) | 33862306a36Sopenharmony_ci FW_RI_RES_WR_IQID_V(scq->cqid)); 33962306a36Sopenharmony_ci res->u.sqrq.dcaen_to_eqsize = cpu_to_be32( 34062306a36Sopenharmony_ci FW_RI_RES_WR_DCAEN_V(0) | 34162306a36Sopenharmony_ci FW_RI_RES_WR_DCACPU_V(0) | 34262306a36Sopenharmony_ci FW_RI_RES_WR_FBMIN_V(2) | 34362306a36Sopenharmony_ci (t4_sq_onchip(&wq->sq) ? FW_RI_RES_WR_FBMAX_V(2) : 34462306a36Sopenharmony_ci FW_RI_RES_WR_FBMAX_V(3)) | 34562306a36Sopenharmony_ci FW_RI_RES_WR_CIDXFTHRESHO_V(0) | 34662306a36Sopenharmony_ci FW_RI_RES_WR_CIDXFTHRESH_V(0) | 34762306a36Sopenharmony_ci FW_RI_RES_WR_EQSIZE_V(eqsize)); 34862306a36Sopenharmony_ci res->u.sqrq.eqid = cpu_to_be32(wq->sq.qid); 34962306a36Sopenharmony_ci res->u.sqrq.eqaddr = cpu_to_be64(wq->sq.dma_addr); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (need_rq) { 35262306a36Sopenharmony_ci res++; 35362306a36Sopenharmony_ci res->u.sqrq.restype = FW_RI_RES_TYPE_RQ; 35462306a36Sopenharmony_ci res->u.sqrq.op = FW_RI_RES_OP_WRITE; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* 35762306a36Sopenharmony_ci * eqsize is the number of 64B entries plus the status page size 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci eqsize = wq->rq.size * T4_RQ_NUM_SLOTS + 36062306a36Sopenharmony_ci rdev->hw_queue.t4_eq_status_entries; 36162306a36Sopenharmony_ci res->u.sqrq.fetchszm_to_iqid = 36262306a36Sopenharmony_ci /* no host cidx updates */ 36362306a36Sopenharmony_ci cpu_to_be32(FW_RI_RES_WR_HOSTFCMODE_V(0) | 36462306a36Sopenharmony_ci /* don't keep in chip cache */ 36562306a36Sopenharmony_ci FW_RI_RES_WR_CPRIO_V(0) | 36662306a36Sopenharmony_ci /* set by uP at ri_init time */ 36762306a36Sopenharmony_ci FW_RI_RES_WR_PCIECHN_V(0) | 36862306a36Sopenharmony_ci FW_RI_RES_WR_IQID_V(rcq->cqid)); 36962306a36Sopenharmony_ci res->u.sqrq.dcaen_to_eqsize = 37062306a36Sopenharmony_ci cpu_to_be32(FW_RI_RES_WR_DCAEN_V(0) | 37162306a36Sopenharmony_ci FW_RI_RES_WR_DCACPU_V(0) | 37262306a36Sopenharmony_ci FW_RI_RES_WR_FBMIN_V(2) | 37362306a36Sopenharmony_ci FW_RI_RES_WR_FBMAX_V(3) | 37462306a36Sopenharmony_ci FW_RI_RES_WR_CIDXFTHRESHO_V(0) | 37562306a36Sopenharmony_ci FW_RI_RES_WR_CIDXFTHRESH_V(0) | 37662306a36Sopenharmony_ci FW_RI_RES_WR_EQSIZE_V(eqsize)); 37762306a36Sopenharmony_ci res->u.sqrq.eqid = cpu_to_be32(wq->rq.qid); 37862306a36Sopenharmony_ci res->u.sqrq.eqaddr = cpu_to_be64(wq->rq.dma_addr); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci c4iw_init_wr_wait(wr_waitp); 38262306a36Sopenharmony_ci ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, wq->sq.qid, __func__); 38362306a36Sopenharmony_ci if (ret) 38462306a36Sopenharmony_ci goto free_dma; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci pr_debug("sqid 0x%x rqid 0x%x kdb 0x%p sq_bar2_addr %p rq_bar2_addr %p\n", 38762306a36Sopenharmony_ci wq->sq.qid, wq->rq.qid, wq->db, 38862306a36Sopenharmony_ci wq->sq.bar2_va, wq->rq.bar2_va); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return 0; 39162306a36Sopenharmony_cifree_dma: 39262306a36Sopenharmony_ci if (need_rq) 39362306a36Sopenharmony_ci dma_free_coherent(&rdev->lldi.pdev->dev, 39462306a36Sopenharmony_ci wq->rq.memsize, wq->rq.queue, 39562306a36Sopenharmony_ci dma_unmap_addr(&wq->rq, mapping)); 39662306a36Sopenharmony_cifree_sq: 39762306a36Sopenharmony_ci dealloc_sq(rdev, &wq->sq); 39862306a36Sopenharmony_cifree_hwaddr: 39962306a36Sopenharmony_ci if (need_rq) 40062306a36Sopenharmony_ci c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size); 40162306a36Sopenharmony_cifree_sw_rq: 40262306a36Sopenharmony_ci if (need_rq) 40362306a36Sopenharmony_ci kfree(wq->rq.sw_rq); 40462306a36Sopenharmony_cifree_sw_sq: 40562306a36Sopenharmony_ci kfree(wq->sq.sw_sq); 40662306a36Sopenharmony_cifree_rq_qid: 40762306a36Sopenharmony_ci if (need_rq) 40862306a36Sopenharmony_ci c4iw_put_qpid(rdev, wq->rq.qid, uctx); 40962306a36Sopenharmony_cifree_sq_qid: 41062306a36Sopenharmony_ci c4iw_put_qpid(rdev, wq->sq.qid, uctx); 41162306a36Sopenharmony_ci return ret; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic int build_immd(struct t4_sq *sq, struct fw_ri_immd *immdp, 41562306a36Sopenharmony_ci const struct ib_send_wr *wr, int max, u32 *plenp) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci u8 *dstp, *srcp; 41862306a36Sopenharmony_ci u32 plen = 0; 41962306a36Sopenharmony_ci int i; 42062306a36Sopenharmony_ci int rem, len; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci dstp = (u8 *)immdp->data; 42362306a36Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 42462306a36Sopenharmony_ci if ((plen + wr->sg_list[i].length) > max) 42562306a36Sopenharmony_ci return -EMSGSIZE; 42662306a36Sopenharmony_ci srcp = (u8 *)(unsigned long)wr->sg_list[i].addr; 42762306a36Sopenharmony_ci plen += wr->sg_list[i].length; 42862306a36Sopenharmony_ci rem = wr->sg_list[i].length; 42962306a36Sopenharmony_ci while (rem) { 43062306a36Sopenharmony_ci if (dstp == (u8 *)&sq->queue[sq->size]) 43162306a36Sopenharmony_ci dstp = (u8 *)sq->queue; 43262306a36Sopenharmony_ci if (rem <= (u8 *)&sq->queue[sq->size] - dstp) 43362306a36Sopenharmony_ci len = rem; 43462306a36Sopenharmony_ci else 43562306a36Sopenharmony_ci len = (u8 *)&sq->queue[sq->size] - dstp; 43662306a36Sopenharmony_ci memcpy(dstp, srcp, len); 43762306a36Sopenharmony_ci dstp += len; 43862306a36Sopenharmony_ci srcp += len; 43962306a36Sopenharmony_ci rem -= len; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci len = roundup(plen + sizeof(*immdp), 16) - (plen + sizeof(*immdp)); 44362306a36Sopenharmony_ci if (len) 44462306a36Sopenharmony_ci memset(dstp, 0, len); 44562306a36Sopenharmony_ci immdp->op = FW_RI_DATA_IMMD; 44662306a36Sopenharmony_ci immdp->r1 = 0; 44762306a36Sopenharmony_ci immdp->r2 = 0; 44862306a36Sopenharmony_ci immdp->immdlen = cpu_to_be32(plen); 44962306a36Sopenharmony_ci *plenp = plen; 45062306a36Sopenharmony_ci return 0; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic int build_isgl(__be64 *queue_start, __be64 *queue_end, 45462306a36Sopenharmony_ci struct fw_ri_isgl *isglp, struct ib_sge *sg_list, 45562306a36Sopenharmony_ci int num_sge, u32 *plenp) 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci int i; 45962306a36Sopenharmony_ci u32 plen = 0; 46062306a36Sopenharmony_ci __be64 *flitp; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if ((__be64 *)isglp == queue_end) 46362306a36Sopenharmony_ci isglp = (struct fw_ri_isgl *)queue_start; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci flitp = (__be64 *)isglp->sge; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci for (i = 0; i < num_sge; i++) { 46862306a36Sopenharmony_ci if ((plen + sg_list[i].length) < plen) 46962306a36Sopenharmony_ci return -EMSGSIZE; 47062306a36Sopenharmony_ci plen += sg_list[i].length; 47162306a36Sopenharmony_ci *flitp = cpu_to_be64(((u64)sg_list[i].lkey << 32) | 47262306a36Sopenharmony_ci sg_list[i].length); 47362306a36Sopenharmony_ci if (++flitp == queue_end) 47462306a36Sopenharmony_ci flitp = queue_start; 47562306a36Sopenharmony_ci *flitp = cpu_to_be64(sg_list[i].addr); 47662306a36Sopenharmony_ci if (++flitp == queue_end) 47762306a36Sopenharmony_ci flitp = queue_start; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci *flitp = (__force __be64)0; 48062306a36Sopenharmony_ci isglp->op = FW_RI_DATA_ISGL; 48162306a36Sopenharmony_ci isglp->r1 = 0; 48262306a36Sopenharmony_ci isglp->nsge = cpu_to_be16(num_sge); 48362306a36Sopenharmony_ci isglp->r2 = 0; 48462306a36Sopenharmony_ci if (plenp) 48562306a36Sopenharmony_ci *plenp = plen; 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic int build_rdma_send(struct t4_sq *sq, union t4_wr *wqe, 49062306a36Sopenharmony_ci const struct ib_send_wr *wr, u8 *len16) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci u32 plen; 49362306a36Sopenharmony_ci int size; 49462306a36Sopenharmony_ci int ret; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (wr->num_sge > T4_MAX_SEND_SGE) 49762306a36Sopenharmony_ci return -EINVAL; 49862306a36Sopenharmony_ci switch (wr->opcode) { 49962306a36Sopenharmony_ci case IB_WR_SEND: 50062306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_SOLICITED) 50162306a36Sopenharmony_ci wqe->send.sendop_pkd = cpu_to_be32( 50262306a36Sopenharmony_ci FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_SE)); 50362306a36Sopenharmony_ci else 50462306a36Sopenharmony_ci wqe->send.sendop_pkd = cpu_to_be32( 50562306a36Sopenharmony_ci FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND)); 50662306a36Sopenharmony_ci wqe->send.stag_inv = 0; 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci case IB_WR_SEND_WITH_INV: 50962306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_SOLICITED) 51062306a36Sopenharmony_ci wqe->send.sendop_pkd = cpu_to_be32( 51162306a36Sopenharmony_ci FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_SE_INV)); 51262306a36Sopenharmony_ci else 51362306a36Sopenharmony_ci wqe->send.sendop_pkd = cpu_to_be32( 51462306a36Sopenharmony_ci FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_INV)); 51562306a36Sopenharmony_ci wqe->send.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey); 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci default: 51962306a36Sopenharmony_ci return -EINVAL; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci wqe->send.r3 = 0; 52262306a36Sopenharmony_ci wqe->send.r4 = 0; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci plen = 0; 52562306a36Sopenharmony_ci if (wr->num_sge) { 52662306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_INLINE) { 52762306a36Sopenharmony_ci ret = build_immd(sq, wqe->send.u.immd_src, wr, 52862306a36Sopenharmony_ci T4_MAX_SEND_INLINE, &plen); 52962306a36Sopenharmony_ci if (ret) 53062306a36Sopenharmony_ci return ret; 53162306a36Sopenharmony_ci size = sizeof(wqe->send) + sizeof(struct fw_ri_immd) + 53262306a36Sopenharmony_ci plen; 53362306a36Sopenharmony_ci } else { 53462306a36Sopenharmony_ci ret = build_isgl((__be64 *)sq->queue, 53562306a36Sopenharmony_ci (__be64 *)&sq->queue[sq->size], 53662306a36Sopenharmony_ci wqe->send.u.isgl_src, 53762306a36Sopenharmony_ci wr->sg_list, wr->num_sge, &plen); 53862306a36Sopenharmony_ci if (ret) 53962306a36Sopenharmony_ci return ret; 54062306a36Sopenharmony_ci size = sizeof(wqe->send) + sizeof(struct fw_ri_isgl) + 54162306a36Sopenharmony_ci wr->num_sge * sizeof(struct fw_ri_sge); 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci } else { 54462306a36Sopenharmony_ci wqe->send.u.immd_src[0].op = FW_RI_DATA_IMMD; 54562306a36Sopenharmony_ci wqe->send.u.immd_src[0].r1 = 0; 54662306a36Sopenharmony_ci wqe->send.u.immd_src[0].r2 = 0; 54762306a36Sopenharmony_ci wqe->send.u.immd_src[0].immdlen = 0; 54862306a36Sopenharmony_ci size = sizeof(wqe->send) + sizeof(struct fw_ri_immd); 54962306a36Sopenharmony_ci plen = 0; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci *len16 = DIV_ROUND_UP(size, 16); 55262306a36Sopenharmony_ci wqe->send.plen = cpu_to_be32(plen); 55362306a36Sopenharmony_ci return 0; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic int build_rdma_write(struct t4_sq *sq, union t4_wr *wqe, 55762306a36Sopenharmony_ci const struct ib_send_wr *wr, u8 *len16) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci u32 plen; 56062306a36Sopenharmony_ci int size; 56162306a36Sopenharmony_ci int ret; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (wr->num_sge > T4_MAX_SEND_SGE) 56462306a36Sopenharmony_ci return -EINVAL; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* 56762306a36Sopenharmony_ci * iWARP protocol supports 64 bit immediate data but rdma api 56862306a36Sopenharmony_ci * limits it to 32bit. 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ci if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) 57162306a36Sopenharmony_ci wqe->write.iw_imm_data.ib_imm_data.imm_data32 = wr->ex.imm_data; 57262306a36Sopenharmony_ci else 57362306a36Sopenharmony_ci wqe->write.iw_imm_data.ib_imm_data.imm_data32 = 0; 57462306a36Sopenharmony_ci wqe->write.stag_sink = cpu_to_be32(rdma_wr(wr)->rkey); 57562306a36Sopenharmony_ci wqe->write.to_sink = cpu_to_be64(rdma_wr(wr)->remote_addr); 57662306a36Sopenharmony_ci if (wr->num_sge) { 57762306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_INLINE) { 57862306a36Sopenharmony_ci ret = build_immd(sq, wqe->write.u.immd_src, wr, 57962306a36Sopenharmony_ci T4_MAX_WRITE_INLINE, &plen); 58062306a36Sopenharmony_ci if (ret) 58162306a36Sopenharmony_ci return ret; 58262306a36Sopenharmony_ci size = sizeof(wqe->write) + sizeof(struct fw_ri_immd) + 58362306a36Sopenharmony_ci plen; 58462306a36Sopenharmony_ci } else { 58562306a36Sopenharmony_ci ret = build_isgl((__be64 *)sq->queue, 58662306a36Sopenharmony_ci (__be64 *)&sq->queue[sq->size], 58762306a36Sopenharmony_ci wqe->write.u.isgl_src, 58862306a36Sopenharmony_ci wr->sg_list, wr->num_sge, &plen); 58962306a36Sopenharmony_ci if (ret) 59062306a36Sopenharmony_ci return ret; 59162306a36Sopenharmony_ci size = sizeof(wqe->write) + sizeof(struct fw_ri_isgl) + 59262306a36Sopenharmony_ci wr->num_sge * sizeof(struct fw_ri_sge); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci } else { 59562306a36Sopenharmony_ci wqe->write.u.immd_src[0].op = FW_RI_DATA_IMMD; 59662306a36Sopenharmony_ci wqe->write.u.immd_src[0].r1 = 0; 59762306a36Sopenharmony_ci wqe->write.u.immd_src[0].r2 = 0; 59862306a36Sopenharmony_ci wqe->write.u.immd_src[0].immdlen = 0; 59962306a36Sopenharmony_ci size = sizeof(wqe->write) + sizeof(struct fw_ri_immd); 60062306a36Sopenharmony_ci plen = 0; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci *len16 = DIV_ROUND_UP(size, 16); 60362306a36Sopenharmony_ci wqe->write.plen = cpu_to_be32(plen); 60462306a36Sopenharmony_ci return 0; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic void build_immd_cmpl(struct t4_sq *sq, struct fw_ri_immd_cmpl *immdp, 60862306a36Sopenharmony_ci struct ib_send_wr *wr) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci memcpy((u8 *)immdp->data, (u8 *)(uintptr_t)wr->sg_list->addr, 16); 61162306a36Sopenharmony_ci memset(immdp->r1, 0, 6); 61262306a36Sopenharmony_ci immdp->op = FW_RI_DATA_IMMD; 61362306a36Sopenharmony_ci immdp->immdlen = 16; 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic void build_rdma_write_cmpl(struct t4_sq *sq, 61762306a36Sopenharmony_ci struct fw_ri_rdma_write_cmpl_wr *wcwr, 61862306a36Sopenharmony_ci const struct ib_send_wr *wr, u8 *len16) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci u32 plen; 62162306a36Sopenharmony_ci int size; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* 62462306a36Sopenharmony_ci * This code assumes the struct fields preceding the write isgl 62562306a36Sopenharmony_ci * fit in one 64B WR slot. This is because the WQE is built 62662306a36Sopenharmony_ci * directly in the dma queue, and wrapping is only handled 62762306a36Sopenharmony_ci * by the code buildling sgls. IE the "fixed part" of the wr 62862306a36Sopenharmony_ci * structs must all fit in 64B. The WQE build code should probably be 62962306a36Sopenharmony_ci * redesigned to avoid this restriction, but for now just add 63062306a36Sopenharmony_ci * the BUILD_BUG_ON() to catch if this WQE struct gets too big. 63162306a36Sopenharmony_ci */ 63262306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct fw_ri_rdma_write_cmpl_wr, u) > 64); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci wcwr->stag_sink = cpu_to_be32(rdma_wr(wr)->rkey); 63562306a36Sopenharmony_ci wcwr->to_sink = cpu_to_be64(rdma_wr(wr)->remote_addr); 63662306a36Sopenharmony_ci if (wr->next->opcode == IB_WR_SEND) 63762306a36Sopenharmony_ci wcwr->stag_inv = 0; 63862306a36Sopenharmony_ci else 63962306a36Sopenharmony_ci wcwr->stag_inv = cpu_to_be32(wr->next->ex.invalidate_rkey); 64062306a36Sopenharmony_ci wcwr->r2 = 0; 64162306a36Sopenharmony_ci wcwr->r3 = 0; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* SEND_INV SGL */ 64462306a36Sopenharmony_ci if (wr->next->send_flags & IB_SEND_INLINE) 64562306a36Sopenharmony_ci build_immd_cmpl(sq, &wcwr->u_cmpl.immd_src, wr->next); 64662306a36Sopenharmony_ci else 64762306a36Sopenharmony_ci build_isgl((__be64 *)sq->queue, (__be64 *)&sq->queue[sq->size], 64862306a36Sopenharmony_ci &wcwr->u_cmpl.isgl_src, wr->next->sg_list, 1, NULL); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* WRITE SGL */ 65162306a36Sopenharmony_ci build_isgl((__be64 *)sq->queue, (__be64 *)&sq->queue[sq->size], 65262306a36Sopenharmony_ci wcwr->u.isgl_src, wr->sg_list, wr->num_sge, &plen); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci size = sizeof(*wcwr) + sizeof(struct fw_ri_isgl) + 65562306a36Sopenharmony_ci wr->num_sge * sizeof(struct fw_ri_sge); 65662306a36Sopenharmony_ci wcwr->plen = cpu_to_be32(plen); 65762306a36Sopenharmony_ci *len16 = DIV_ROUND_UP(size, 16); 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int build_rdma_read(union t4_wr *wqe, const struct ib_send_wr *wr, 66162306a36Sopenharmony_ci u8 *len16) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci if (wr->num_sge > 1) 66462306a36Sopenharmony_ci return -EINVAL; 66562306a36Sopenharmony_ci if (wr->num_sge && wr->sg_list[0].length) { 66662306a36Sopenharmony_ci wqe->read.stag_src = cpu_to_be32(rdma_wr(wr)->rkey); 66762306a36Sopenharmony_ci wqe->read.to_src_hi = cpu_to_be32((u32)(rdma_wr(wr)->remote_addr 66862306a36Sopenharmony_ci >> 32)); 66962306a36Sopenharmony_ci wqe->read.to_src_lo = cpu_to_be32((u32)rdma_wr(wr)->remote_addr); 67062306a36Sopenharmony_ci wqe->read.stag_sink = cpu_to_be32(wr->sg_list[0].lkey); 67162306a36Sopenharmony_ci wqe->read.plen = cpu_to_be32(wr->sg_list[0].length); 67262306a36Sopenharmony_ci wqe->read.to_sink_hi = cpu_to_be32((u32)(wr->sg_list[0].addr 67362306a36Sopenharmony_ci >> 32)); 67462306a36Sopenharmony_ci wqe->read.to_sink_lo = cpu_to_be32((u32)(wr->sg_list[0].addr)); 67562306a36Sopenharmony_ci } else { 67662306a36Sopenharmony_ci wqe->read.stag_src = cpu_to_be32(2); 67762306a36Sopenharmony_ci wqe->read.to_src_hi = 0; 67862306a36Sopenharmony_ci wqe->read.to_src_lo = 0; 67962306a36Sopenharmony_ci wqe->read.stag_sink = cpu_to_be32(2); 68062306a36Sopenharmony_ci wqe->read.plen = 0; 68162306a36Sopenharmony_ci wqe->read.to_sink_hi = 0; 68262306a36Sopenharmony_ci wqe->read.to_sink_lo = 0; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci wqe->read.r2 = 0; 68562306a36Sopenharmony_ci wqe->read.r5 = 0; 68662306a36Sopenharmony_ci *len16 = DIV_ROUND_UP(sizeof(wqe->read), 16); 68762306a36Sopenharmony_ci return 0; 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic void post_write_cmpl(struct c4iw_qp *qhp, const struct ib_send_wr *wr) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci bool send_signaled = (wr->next->send_flags & IB_SEND_SIGNALED) || 69362306a36Sopenharmony_ci qhp->sq_sig_all; 69462306a36Sopenharmony_ci bool write_signaled = (wr->send_flags & IB_SEND_SIGNALED) || 69562306a36Sopenharmony_ci qhp->sq_sig_all; 69662306a36Sopenharmony_ci struct t4_swsqe *swsqe; 69762306a36Sopenharmony_ci union t4_wr *wqe; 69862306a36Sopenharmony_ci u16 write_wrid; 69962306a36Sopenharmony_ci u8 len16; 70062306a36Sopenharmony_ci u16 idx; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* 70362306a36Sopenharmony_ci * The sw_sq entries still look like a WRITE and a SEND and consume 70462306a36Sopenharmony_ci * 2 slots. The FW WR, however, will be a single uber-WR. 70562306a36Sopenharmony_ci */ 70662306a36Sopenharmony_ci wqe = (union t4_wr *)((u8 *)qhp->wq.sq.queue + 70762306a36Sopenharmony_ci qhp->wq.sq.wq_pidx * T4_EQ_ENTRY_SIZE); 70862306a36Sopenharmony_ci build_rdma_write_cmpl(&qhp->wq.sq, &wqe->write_cmpl, wr, &len16); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* WRITE swsqe */ 71162306a36Sopenharmony_ci swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx]; 71262306a36Sopenharmony_ci swsqe->opcode = FW_RI_RDMA_WRITE; 71362306a36Sopenharmony_ci swsqe->idx = qhp->wq.sq.pidx; 71462306a36Sopenharmony_ci swsqe->complete = 0; 71562306a36Sopenharmony_ci swsqe->signaled = write_signaled; 71662306a36Sopenharmony_ci swsqe->flushed = 0; 71762306a36Sopenharmony_ci swsqe->wr_id = wr->wr_id; 71862306a36Sopenharmony_ci if (c4iw_wr_log) { 71962306a36Sopenharmony_ci swsqe->sge_ts = 72062306a36Sopenharmony_ci cxgb4_read_sge_timestamp(qhp->rhp->rdev.lldi.ports[0]); 72162306a36Sopenharmony_ci swsqe->host_time = ktime_get(); 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci write_wrid = qhp->wq.sq.pidx; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* just bump the sw_sq */ 72762306a36Sopenharmony_ci qhp->wq.sq.in_use++; 72862306a36Sopenharmony_ci if (++qhp->wq.sq.pidx == qhp->wq.sq.size) 72962306a36Sopenharmony_ci qhp->wq.sq.pidx = 0; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* SEND_WITH_INV swsqe */ 73262306a36Sopenharmony_ci swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx]; 73362306a36Sopenharmony_ci if (wr->next->opcode == IB_WR_SEND) 73462306a36Sopenharmony_ci swsqe->opcode = FW_RI_SEND; 73562306a36Sopenharmony_ci else 73662306a36Sopenharmony_ci swsqe->opcode = FW_RI_SEND_WITH_INV; 73762306a36Sopenharmony_ci swsqe->idx = qhp->wq.sq.pidx; 73862306a36Sopenharmony_ci swsqe->complete = 0; 73962306a36Sopenharmony_ci swsqe->signaled = send_signaled; 74062306a36Sopenharmony_ci swsqe->flushed = 0; 74162306a36Sopenharmony_ci swsqe->wr_id = wr->next->wr_id; 74262306a36Sopenharmony_ci if (c4iw_wr_log) { 74362306a36Sopenharmony_ci swsqe->sge_ts = 74462306a36Sopenharmony_ci cxgb4_read_sge_timestamp(qhp->rhp->rdev.lldi.ports[0]); 74562306a36Sopenharmony_ci swsqe->host_time = ktime_get(); 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci wqe->write_cmpl.flags_send = send_signaled ? FW_RI_COMPLETION_FLAG : 0; 74962306a36Sopenharmony_ci wqe->write_cmpl.wrid_send = qhp->wq.sq.pidx; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci init_wr_hdr(wqe, write_wrid, FW_RI_RDMA_WRITE_CMPL_WR, 75262306a36Sopenharmony_ci write_signaled ? FW_RI_COMPLETION_FLAG : 0, len16); 75362306a36Sopenharmony_ci t4_sq_produce(&qhp->wq, len16); 75462306a36Sopenharmony_ci idx = DIV_ROUND_UP(len16 * 16, T4_EQ_ENTRY_SIZE); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci t4_ring_sq_db(&qhp->wq, idx, wqe); 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe, 76062306a36Sopenharmony_ci const struct ib_recv_wr *wr, u8 *len16) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci int ret; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci ret = build_isgl((__be64 *)qhp->wq.rq.queue, 76562306a36Sopenharmony_ci (__be64 *)&qhp->wq.rq.queue[qhp->wq.rq.size], 76662306a36Sopenharmony_ci &wqe->recv.isgl, wr->sg_list, wr->num_sge, NULL); 76762306a36Sopenharmony_ci if (ret) 76862306a36Sopenharmony_ci return ret; 76962306a36Sopenharmony_ci *len16 = DIV_ROUND_UP( 77062306a36Sopenharmony_ci sizeof(wqe->recv) + wr->num_sge * sizeof(struct fw_ri_sge), 16); 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int build_srq_recv(union t4_recv_wr *wqe, const struct ib_recv_wr *wr, 77562306a36Sopenharmony_ci u8 *len16) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci int ret; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci ret = build_isgl((__be64 *)wqe, (__be64 *)(wqe + 1), 78062306a36Sopenharmony_ci &wqe->recv.isgl, wr->sg_list, wr->num_sge, NULL); 78162306a36Sopenharmony_ci if (ret) 78262306a36Sopenharmony_ci return ret; 78362306a36Sopenharmony_ci *len16 = DIV_ROUND_UP(sizeof(wqe->recv) + 78462306a36Sopenharmony_ci wr->num_sge * sizeof(struct fw_ri_sge), 16); 78562306a36Sopenharmony_ci return 0; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic void build_tpte_memreg(struct fw_ri_fr_nsmr_tpte_wr *fr, 78962306a36Sopenharmony_ci const struct ib_reg_wr *wr, struct c4iw_mr *mhp, 79062306a36Sopenharmony_ci u8 *len16) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci __be64 *p = (__be64 *)fr->pbl; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci fr->r2 = cpu_to_be32(0); 79562306a36Sopenharmony_ci fr->stag = cpu_to_be32(mhp->ibmr.rkey); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci fr->tpte.valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F | 79862306a36Sopenharmony_ci FW_RI_TPTE_STAGKEY_V((mhp->ibmr.rkey & FW_RI_TPTE_STAGKEY_M)) | 79962306a36Sopenharmony_ci FW_RI_TPTE_STAGSTATE_V(1) | 80062306a36Sopenharmony_ci FW_RI_TPTE_STAGTYPE_V(FW_RI_STAG_NSMR) | 80162306a36Sopenharmony_ci FW_RI_TPTE_PDID_V(mhp->attr.pdid)); 80262306a36Sopenharmony_ci fr->tpte.locread_to_qpid = cpu_to_be32( 80362306a36Sopenharmony_ci FW_RI_TPTE_PERM_V(c4iw_ib_to_tpt_access(wr->access)) | 80462306a36Sopenharmony_ci FW_RI_TPTE_ADDRTYPE_V(FW_RI_VA_BASED_TO) | 80562306a36Sopenharmony_ci FW_RI_TPTE_PS_V(ilog2(wr->mr->page_size) - 12)); 80662306a36Sopenharmony_ci fr->tpte.nosnoop_pbladdr = cpu_to_be32(FW_RI_TPTE_PBLADDR_V( 80762306a36Sopenharmony_ci PBL_OFF(&mhp->rhp->rdev, mhp->attr.pbl_addr)>>3)); 80862306a36Sopenharmony_ci fr->tpte.dca_mwbcnt_pstag = cpu_to_be32(0); 80962306a36Sopenharmony_ci fr->tpte.len_hi = cpu_to_be32(0); 81062306a36Sopenharmony_ci fr->tpte.len_lo = cpu_to_be32(mhp->ibmr.length); 81162306a36Sopenharmony_ci fr->tpte.va_hi = cpu_to_be32(mhp->ibmr.iova >> 32); 81262306a36Sopenharmony_ci fr->tpte.va_lo_fbo = cpu_to_be32(mhp->ibmr.iova & 0xffffffff); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci p[0] = cpu_to_be64((u64)mhp->mpl[0]); 81562306a36Sopenharmony_ci p[1] = cpu_to_be64((u64)mhp->mpl[1]); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci *len16 = DIV_ROUND_UP(sizeof(*fr), 16); 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic int build_memreg(struct t4_sq *sq, union t4_wr *wqe, 82162306a36Sopenharmony_ci const struct ib_reg_wr *wr, struct c4iw_mr *mhp, 82262306a36Sopenharmony_ci u8 *len16, bool dsgl_supported) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci struct fw_ri_immd *imdp; 82562306a36Sopenharmony_ci __be64 *p; 82662306a36Sopenharmony_ci int i; 82762306a36Sopenharmony_ci int pbllen = roundup(mhp->mpl_len * sizeof(u64), 32); 82862306a36Sopenharmony_ci int rem; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if (mhp->mpl_len > t4_max_fr_depth(dsgl_supported && use_dsgl)) 83162306a36Sopenharmony_ci return -EINVAL; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci wqe->fr.qpbinde_to_dcacpu = 0; 83462306a36Sopenharmony_ci wqe->fr.pgsz_shift = ilog2(wr->mr->page_size) - 12; 83562306a36Sopenharmony_ci wqe->fr.addr_type = FW_RI_VA_BASED_TO; 83662306a36Sopenharmony_ci wqe->fr.mem_perms = c4iw_ib_to_tpt_access(wr->access); 83762306a36Sopenharmony_ci wqe->fr.len_hi = 0; 83862306a36Sopenharmony_ci wqe->fr.len_lo = cpu_to_be32(mhp->ibmr.length); 83962306a36Sopenharmony_ci wqe->fr.stag = cpu_to_be32(wr->key); 84062306a36Sopenharmony_ci wqe->fr.va_hi = cpu_to_be32(mhp->ibmr.iova >> 32); 84162306a36Sopenharmony_ci wqe->fr.va_lo_fbo = cpu_to_be32(mhp->ibmr.iova & 84262306a36Sopenharmony_ci 0xffffffff); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (dsgl_supported && use_dsgl && (pbllen > max_fr_immd)) { 84562306a36Sopenharmony_ci struct fw_ri_dsgl *sglp; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci for (i = 0; i < mhp->mpl_len; i++) 84862306a36Sopenharmony_ci mhp->mpl[i] = (__force u64)cpu_to_be64((u64)mhp->mpl[i]); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci sglp = (struct fw_ri_dsgl *)(&wqe->fr + 1); 85162306a36Sopenharmony_ci sglp->op = FW_RI_DATA_DSGL; 85262306a36Sopenharmony_ci sglp->r1 = 0; 85362306a36Sopenharmony_ci sglp->nsge = cpu_to_be16(1); 85462306a36Sopenharmony_ci sglp->addr0 = cpu_to_be64(mhp->mpl_addr); 85562306a36Sopenharmony_ci sglp->len0 = cpu_to_be32(pbllen); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci *len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*sglp), 16); 85862306a36Sopenharmony_ci } else { 85962306a36Sopenharmony_ci imdp = (struct fw_ri_immd *)(&wqe->fr + 1); 86062306a36Sopenharmony_ci imdp->op = FW_RI_DATA_IMMD; 86162306a36Sopenharmony_ci imdp->r1 = 0; 86262306a36Sopenharmony_ci imdp->r2 = 0; 86362306a36Sopenharmony_ci imdp->immdlen = cpu_to_be32(pbllen); 86462306a36Sopenharmony_ci p = (__be64 *)(imdp + 1); 86562306a36Sopenharmony_ci rem = pbllen; 86662306a36Sopenharmony_ci for (i = 0; i < mhp->mpl_len; i++) { 86762306a36Sopenharmony_ci *p = cpu_to_be64((u64)mhp->mpl[i]); 86862306a36Sopenharmony_ci rem -= sizeof(*p); 86962306a36Sopenharmony_ci if (++p == (__be64 *)&sq->queue[sq->size]) 87062306a36Sopenharmony_ci p = (__be64 *)sq->queue; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci while (rem) { 87362306a36Sopenharmony_ci *p = 0; 87462306a36Sopenharmony_ci rem -= sizeof(*p); 87562306a36Sopenharmony_ci if (++p == (__be64 *)&sq->queue[sq->size]) 87662306a36Sopenharmony_ci p = (__be64 *)sq->queue; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci *len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*imdp) 87962306a36Sopenharmony_ci + pbllen, 16); 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci return 0; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic int build_inv_stag(union t4_wr *wqe, const struct ib_send_wr *wr, 88562306a36Sopenharmony_ci u8 *len16) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci wqe->inv.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey); 88862306a36Sopenharmony_ci wqe->inv.r2 = 0; 88962306a36Sopenharmony_ci *len16 = DIV_ROUND_UP(sizeof(wqe->inv), 16); 89062306a36Sopenharmony_ci return 0; 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_civoid c4iw_qp_add_ref(struct ib_qp *qp) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci pr_debug("ib_qp %p\n", qp); 89662306a36Sopenharmony_ci refcount_inc(&to_c4iw_qp(qp)->qp_refcnt); 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_civoid c4iw_qp_rem_ref(struct ib_qp *qp) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci pr_debug("ib_qp %p\n", qp); 90262306a36Sopenharmony_ci if (refcount_dec_and_test(&to_c4iw_qp(qp)->qp_refcnt)) 90362306a36Sopenharmony_ci complete(&to_c4iw_qp(qp)->qp_rel_comp); 90462306a36Sopenharmony_ci} 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_cistatic void add_to_fc_list(struct list_head *head, struct list_head *entry) 90762306a36Sopenharmony_ci{ 90862306a36Sopenharmony_ci if (list_empty(entry)) 90962306a36Sopenharmony_ci list_add_tail(entry, head); 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_cistatic int ring_kernel_sq_db(struct c4iw_qp *qhp, u16 inc) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci unsigned long flags; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci xa_lock_irqsave(&qhp->rhp->qps, flags); 91762306a36Sopenharmony_ci spin_lock(&qhp->lock); 91862306a36Sopenharmony_ci if (qhp->rhp->db_state == NORMAL) 91962306a36Sopenharmony_ci t4_ring_sq_db(&qhp->wq, inc, NULL); 92062306a36Sopenharmony_ci else { 92162306a36Sopenharmony_ci add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry); 92262306a36Sopenharmony_ci qhp->wq.sq.wq_pidx_inc += inc; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci spin_unlock(&qhp->lock); 92562306a36Sopenharmony_ci xa_unlock_irqrestore(&qhp->rhp->qps, flags); 92662306a36Sopenharmony_ci return 0; 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_cistatic int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci unsigned long flags; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci xa_lock_irqsave(&qhp->rhp->qps, flags); 93462306a36Sopenharmony_ci spin_lock(&qhp->lock); 93562306a36Sopenharmony_ci if (qhp->rhp->db_state == NORMAL) 93662306a36Sopenharmony_ci t4_ring_rq_db(&qhp->wq, inc, NULL); 93762306a36Sopenharmony_ci else { 93862306a36Sopenharmony_ci add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry); 93962306a36Sopenharmony_ci qhp->wq.rq.wq_pidx_inc += inc; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci spin_unlock(&qhp->lock); 94262306a36Sopenharmony_ci xa_unlock_irqrestore(&qhp->rhp->qps, flags); 94362306a36Sopenharmony_ci return 0; 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_cistatic int ib_to_fw_opcode(int ib_opcode) 94762306a36Sopenharmony_ci{ 94862306a36Sopenharmony_ci int opcode; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci switch (ib_opcode) { 95162306a36Sopenharmony_ci case IB_WR_SEND_WITH_INV: 95262306a36Sopenharmony_ci opcode = FW_RI_SEND_WITH_INV; 95362306a36Sopenharmony_ci break; 95462306a36Sopenharmony_ci case IB_WR_SEND: 95562306a36Sopenharmony_ci opcode = FW_RI_SEND; 95662306a36Sopenharmony_ci break; 95762306a36Sopenharmony_ci case IB_WR_RDMA_WRITE: 95862306a36Sopenharmony_ci opcode = FW_RI_RDMA_WRITE; 95962306a36Sopenharmony_ci break; 96062306a36Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 96162306a36Sopenharmony_ci opcode = FW_RI_WRITE_IMMEDIATE; 96262306a36Sopenharmony_ci break; 96362306a36Sopenharmony_ci case IB_WR_RDMA_READ: 96462306a36Sopenharmony_ci case IB_WR_RDMA_READ_WITH_INV: 96562306a36Sopenharmony_ci opcode = FW_RI_READ_REQ; 96662306a36Sopenharmony_ci break; 96762306a36Sopenharmony_ci case IB_WR_REG_MR: 96862306a36Sopenharmony_ci opcode = FW_RI_FAST_REGISTER; 96962306a36Sopenharmony_ci break; 97062306a36Sopenharmony_ci case IB_WR_LOCAL_INV: 97162306a36Sopenharmony_ci opcode = FW_RI_LOCAL_INV; 97262306a36Sopenharmony_ci break; 97362306a36Sopenharmony_ci default: 97462306a36Sopenharmony_ci opcode = -EINVAL; 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci return opcode; 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic int complete_sq_drain_wr(struct c4iw_qp *qhp, 98062306a36Sopenharmony_ci const struct ib_send_wr *wr) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci struct t4_cqe cqe = {}; 98362306a36Sopenharmony_ci struct c4iw_cq *schp; 98462306a36Sopenharmony_ci unsigned long flag; 98562306a36Sopenharmony_ci struct t4_cq *cq; 98662306a36Sopenharmony_ci int opcode; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci schp = to_c4iw_cq(qhp->ibqp.send_cq); 98962306a36Sopenharmony_ci cq = &schp->cq; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci opcode = ib_to_fw_opcode(wr->opcode); 99262306a36Sopenharmony_ci if (opcode < 0) 99362306a36Sopenharmony_ci return opcode; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci cqe.u.drain_cookie = wr->wr_id; 99662306a36Sopenharmony_ci cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) | 99762306a36Sopenharmony_ci CQE_OPCODE_V(opcode) | 99862306a36Sopenharmony_ci CQE_TYPE_V(1) | 99962306a36Sopenharmony_ci CQE_SWCQE_V(1) | 100062306a36Sopenharmony_ci CQE_DRAIN_V(1) | 100162306a36Sopenharmony_ci CQE_QPID_V(qhp->wq.sq.qid)); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci spin_lock_irqsave(&schp->lock, flag); 100462306a36Sopenharmony_ci cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen)); 100562306a36Sopenharmony_ci cq->sw_queue[cq->sw_pidx] = cqe; 100662306a36Sopenharmony_ci t4_swcq_produce(cq); 100762306a36Sopenharmony_ci spin_unlock_irqrestore(&schp->lock, flag); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (t4_clear_cq_armed(&schp->cq)) { 101062306a36Sopenharmony_ci spin_lock_irqsave(&schp->comp_handler_lock, flag); 101162306a36Sopenharmony_ci (*schp->ibcq.comp_handler)(&schp->ibcq, 101262306a36Sopenharmony_ci schp->ibcq.cq_context); 101362306a36Sopenharmony_ci spin_unlock_irqrestore(&schp->comp_handler_lock, flag); 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci return 0; 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic int complete_sq_drain_wrs(struct c4iw_qp *qhp, 101962306a36Sopenharmony_ci const struct ib_send_wr *wr, 102062306a36Sopenharmony_ci const struct ib_send_wr **bad_wr) 102162306a36Sopenharmony_ci{ 102262306a36Sopenharmony_ci int ret = 0; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci while (wr) { 102562306a36Sopenharmony_ci ret = complete_sq_drain_wr(qhp, wr); 102662306a36Sopenharmony_ci if (ret) { 102762306a36Sopenharmony_ci *bad_wr = wr; 102862306a36Sopenharmony_ci break; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci wr = wr->next; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci return ret; 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_cistatic void complete_rq_drain_wr(struct c4iw_qp *qhp, 103662306a36Sopenharmony_ci const struct ib_recv_wr *wr) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci struct t4_cqe cqe = {}; 103962306a36Sopenharmony_ci struct c4iw_cq *rchp; 104062306a36Sopenharmony_ci unsigned long flag; 104162306a36Sopenharmony_ci struct t4_cq *cq; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci rchp = to_c4iw_cq(qhp->ibqp.recv_cq); 104462306a36Sopenharmony_ci cq = &rchp->cq; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci cqe.u.drain_cookie = wr->wr_id; 104762306a36Sopenharmony_ci cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) | 104862306a36Sopenharmony_ci CQE_OPCODE_V(FW_RI_SEND) | 104962306a36Sopenharmony_ci CQE_TYPE_V(0) | 105062306a36Sopenharmony_ci CQE_SWCQE_V(1) | 105162306a36Sopenharmony_ci CQE_DRAIN_V(1) | 105262306a36Sopenharmony_ci CQE_QPID_V(qhp->wq.sq.qid)); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci spin_lock_irqsave(&rchp->lock, flag); 105562306a36Sopenharmony_ci cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen)); 105662306a36Sopenharmony_ci cq->sw_queue[cq->sw_pidx] = cqe; 105762306a36Sopenharmony_ci t4_swcq_produce(cq); 105862306a36Sopenharmony_ci spin_unlock_irqrestore(&rchp->lock, flag); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (t4_clear_cq_armed(&rchp->cq)) { 106162306a36Sopenharmony_ci spin_lock_irqsave(&rchp->comp_handler_lock, flag); 106262306a36Sopenharmony_ci (*rchp->ibcq.comp_handler)(&rchp->ibcq, 106362306a36Sopenharmony_ci rchp->ibcq.cq_context); 106462306a36Sopenharmony_ci spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic void complete_rq_drain_wrs(struct c4iw_qp *qhp, 106962306a36Sopenharmony_ci const struct ib_recv_wr *wr) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci while (wr) { 107262306a36Sopenharmony_ci complete_rq_drain_wr(qhp, wr); 107362306a36Sopenharmony_ci wr = wr->next; 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ciint c4iw_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, 107862306a36Sopenharmony_ci const struct ib_send_wr **bad_wr) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci int err = 0; 108162306a36Sopenharmony_ci u8 len16 = 0; 108262306a36Sopenharmony_ci enum fw_wr_opcodes fw_opcode = 0; 108362306a36Sopenharmony_ci enum fw_ri_wr_flags fw_flags; 108462306a36Sopenharmony_ci struct c4iw_qp *qhp; 108562306a36Sopenharmony_ci struct c4iw_dev *rhp; 108662306a36Sopenharmony_ci union t4_wr *wqe = NULL; 108762306a36Sopenharmony_ci u32 num_wrs; 108862306a36Sopenharmony_ci struct t4_swsqe *swsqe; 108962306a36Sopenharmony_ci unsigned long flag; 109062306a36Sopenharmony_ci u16 idx = 0; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci qhp = to_c4iw_qp(ibqp); 109362306a36Sopenharmony_ci rhp = qhp->rhp; 109462306a36Sopenharmony_ci spin_lock_irqsave(&qhp->lock, flag); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* 109762306a36Sopenharmony_ci * If the qp has been flushed, then just insert a special 109862306a36Sopenharmony_ci * drain cqe. 109962306a36Sopenharmony_ci */ 110062306a36Sopenharmony_ci if (qhp->wq.flushed) { 110162306a36Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 110262306a36Sopenharmony_ci err = complete_sq_drain_wrs(qhp, wr, bad_wr); 110362306a36Sopenharmony_ci return err; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci num_wrs = t4_sq_avail(&qhp->wq); 110662306a36Sopenharmony_ci if (num_wrs == 0) { 110762306a36Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 110862306a36Sopenharmony_ci *bad_wr = wr; 110962306a36Sopenharmony_ci return -ENOMEM; 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci /* 111362306a36Sopenharmony_ci * Fastpath for NVMe-oF target WRITE + SEND_WITH_INV wr chain which is 111462306a36Sopenharmony_ci * the response for small NVMEe-oF READ requests. If the chain is 111562306a36Sopenharmony_ci * exactly a WRITE->SEND_WITH_INV or a WRITE->SEND and the sgl depths 111662306a36Sopenharmony_ci * and lengths meet the requirements of the fw_ri_write_cmpl_wr work 111762306a36Sopenharmony_ci * request, then build and post the write_cmpl WR. If any of the tests 111862306a36Sopenharmony_ci * below are not true, then we continue on with the tradtional WRITE 111962306a36Sopenharmony_ci * and SEND WRs. 112062306a36Sopenharmony_ci */ 112162306a36Sopenharmony_ci if (qhp->rhp->rdev.lldi.write_cmpl_support && 112262306a36Sopenharmony_ci CHELSIO_CHIP_VERSION(qhp->rhp->rdev.lldi.adapter_type) >= 112362306a36Sopenharmony_ci CHELSIO_T5 && 112462306a36Sopenharmony_ci wr && wr->next && !wr->next->next && 112562306a36Sopenharmony_ci wr->opcode == IB_WR_RDMA_WRITE && 112662306a36Sopenharmony_ci wr->sg_list[0].length && wr->num_sge <= T4_WRITE_CMPL_MAX_SGL && 112762306a36Sopenharmony_ci (wr->next->opcode == IB_WR_SEND || 112862306a36Sopenharmony_ci wr->next->opcode == IB_WR_SEND_WITH_INV) && 112962306a36Sopenharmony_ci wr->next->sg_list[0].length == T4_WRITE_CMPL_MAX_CQE && 113062306a36Sopenharmony_ci wr->next->num_sge == 1 && num_wrs >= 2) { 113162306a36Sopenharmony_ci post_write_cmpl(qhp, wr); 113262306a36Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 113362306a36Sopenharmony_ci return 0; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci while (wr) { 113762306a36Sopenharmony_ci if (num_wrs == 0) { 113862306a36Sopenharmony_ci err = -ENOMEM; 113962306a36Sopenharmony_ci *bad_wr = wr; 114062306a36Sopenharmony_ci break; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci wqe = (union t4_wr *)((u8 *)qhp->wq.sq.queue + 114362306a36Sopenharmony_ci qhp->wq.sq.wq_pidx * T4_EQ_ENTRY_SIZE); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci fw_flags = 0; 114662306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_SOLICITED) 114762306a36Sopenharmony_ci fw_flags |= FW_RI_SOLICITED_EVENT_FLAG; 114862306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_SIGNALED || qhp->sq_sig_all) 114962306a36Sopenharmony_ci fw_flags |= FW_RI_COMPLETION_FLAG; 115062306a36Sopenharmony_ci swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx]; 115162306a36Sopenharmony_ci switch (wr->opcode) { 115262306a36Sopenharmony_ci case IB_WR_SEND_WITH_INV: 115362306a36Sopenharmony_ci case IB_WR_SEND: 115462306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_FENCE) 115562306a36Sopenharmony_ci fw_flags |= FW_RI_READ_FENCE_FLAG; 115662306a36Sopenharmony_ci fw_opcode = FW_RI_SEND_WR; 115762306a36Sopenharmony_ci if (wr->opcode == IB_WR_SEND) 115862306a36Sopenharmony_ci swsqe->opcode = FW_RI_SEND; 115962306a36Sopenharmony_ci else 116062306a36Sopenharmony_ci swsqe->opcode = FW_RI_SEND_WITH_INV; 116162306a36Sopenharmony_ci err = build_rdma_send(&qhp->wq.sq, wqe, wr, &len16); 116262306a36Sopenharmony_ci break; 116362306a36Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 116462306a36Sopenharmony_ci if (unlikely(!rhp->rdev.lldi.write_w_imm_support)) { 116562306a36Sopenharmony_ci err = -EINVAL; 116662306a36Sopenharmony_ci break; 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci fw_flags |= FW_RI_RDMA_WRITE_WITH_IMMEDIATE; 116962306a36Sopenharmony_ci fallthrough; 117062306a36Sopenharmony_ci case IB_WR_RDMA_WRITE: 117162306a36Sopenharmony_ci fw_opcode = FW_RI_RDMA_WRITE_WR; 117262306a36Sopenharmony_ci swsqe->opcode = FW_RI_RDMA_WRITE; 117362306a36Sopenharmony_ci err = build_rdma_write(&qhp->wq.sq, wqe, wr, &len16); 117462306a36Sopenharmony_ci break; 117562306a36Sopenharmony_ci case IB_WR_RDMA_READ: 117662306a36Sopenharmony_ci case IB_WR_RDMA_READ_WITH_INV: 117762306a36Sopenharmony_ci fw_opcode = FW_RI_RDMA_READ_WR; 117862306a36Sopenharmony_ci swsqe->opcode = FW_RI_READ_REQ; 117962306a36Sopenharmony_ci if (wr->opcode == IB_WR_RDMA_READ_WITH_INV) { 118062306a36Sopenharmony_ci c4iw_invalidate_mr(rhp, wr->sg_list[0].lkey); 118162306a36Sopenharmony_ci fw_flags = FW_RI_RDMA_READ_INVALIDATE; 118262306a36Sopenharmony_ci } else { 118362306a36Sopenharmony_ci fw_flags = 0; 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci err = build_rdma_read(wqe, wr, &len16); 118662306a36Sopenharmony_ci if (err) 118762306a36Sopenharmony_ci break; 118862306a36Sopenharmony_ci swsqe->read_len = wr->sg_list[0].length; 118962306a36Sopenharmony_ci if (!qhp->wq.sq.oldest_read) 119062306a36Sopenharmony_ci qhp->wq.sq.oldest_read = swsqe; 119162306a36Sopenharmony_ci break; 119262306a36Sopenharmony_ci case IB_WR_REG_MR: { 119362306a36Sopenharmony_ci struct c4iw_mr *mhp = to_c4iw_mr(reg_wr(wr)->mr); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci swsqe->opcode = FW_RI_FAST_REGISTER; 119662306a36Sopenharmony_ci if (rhp->rdev.lldi.fr_nsmr_tpte_wr_support && 119762306a36Sopenharmony_ci !mhp->attr.state && mhp->mpl_len <= 2) { 119862306a36Sopenharmony_ci fw_opcode = FW_RI_FR_NSMR_TPTE_WR; 119962306a36Sopenharmony_ci build_tpte_memreg(&wqe->fr_tpte, reg_wr(wr), 120062306a36Sopenharmony_ci mhp, &len16); 120162306a36Sopenharmony_ci } else { 120262306a36Sopenharmony_ci fw_opcode = FW_RI_FR_NSMR_WR; 120362306a36Sopenharmony_ci err = build_memreg(&qhp->wq.sq, wqe, reg_wr(wr), 120462306a36Sopenharmony_ci mhp, &len16, 120562306a36Sopenharmony_ci rhp->rdev.lldi.ulptx_memwrite_dsgl); 120662306a36Sopenharmony_ci if (err) 120762306a36Sopenharmony_ci break; 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci mhp->attr.state = 1; 121062306a36Sopenharmony_ci break; 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci case IB_WR_LOCAL_INV: 121362306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_FENCE) 121462306a36Sopenharmony_ci fw_flags |= FW_RI_LOCAL_FENCE_FLAG; 121562306a36Sopenharmony_ci fw_opcode = FW_RI_INV_LSTAG_WR; 121662306a36Sopenharmony_ci swsqe->opcode = FW_RI_LOCAL_INV; 121762306a36Sopenharmony_ci err = build_inv_stag(wqe, wr, &len16); 121862306a36Sopenharmony_ci c4iw_invalidate_mr(rhp, wr->ex.invalidate_rkey); 121962306a36Sopenharmony_ci break; 122062306a36Sopenharmony_ci default: 122162306a36Sopenharmony_ci pr_warn("%s post of type=%d TBD!\n", __func__, 122262306a36Sopenharmony_ci wr->opcode); 122362306a36Sopenharmony_ci err = -EINVAL; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci if (err) { 122662306a36Sopenharmony_ci *bad_wr = wr; 122762306a36Sopenharmony_ci break; 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci swsqe->idx = qhp->wq.sq.pidx; 123062306a36Sopenharmony_ci swsqe->complete = 0; 123162306a36Sopenharmony_ci swsqe->signaled = (wr->send_flags & IB_SEND_SIGNALED) || 123262306a36Sopenharmony_ci qhp->sq_sig_all; 123362306a36Sopenharmony_ci swsqe->flushed = 0; 123462306a36Sopenharmony_ci swsqe->wr_id = wr->wr_id; 123562306a36Sopenharmony_ci if (c4iw_wr_log) { 123662306a36Sopenharmony_ci swsqe->sge_ts = cxgb4_read_sge_timestamp( 123762306a36Sopenharmony_ci rhp->rdev.lldi.ports[0]); 123862306a36Sopenharmony_ci swsqe->host_time = ktime_get(); 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci init_wr_hdr(wqe, qhp->wq.sq.pidx, fw_opcode, fw_flags, len16); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci pr_debug("cookie 0x%llx pidx 0x%x opcode 0x%x read_len %u\n", 124462306a36Sopenharmony_ci (unsigned long long)wr->wr_id, qhp->wq.sq.pidx, 124562306a36Sopenharmony_ci swsqe->opcode, swsqe->read_len); 124662306a36Sopenharmony_ci wr = wr->next; 124762306a36Sopenharmony_ci num_wrs--; 124862306a36Sopenharmony_ci t4_sq_produce(&qhp->wq, len16); 124962306a36Sopenharmony_ci idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE); 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci if (!rhp->rdev.status_page->db_off) { 125262306a36Sopenharmony_ci t4_ring_sq_db(&qhp->wq, idx, wqe); 125362306a36Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 125462306a36Sopenharmony_ci } else { 125562306a36Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 125662306a36Sopenharmony_ci ring_kernel_sq_db(qhp, idx); 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci return err; 125962306a36Sopenharmony_ci} 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ciint c4iw_post_receive(struct ib_qp *ibqp, const struct ib_recv_wr *wr, 126262306a36Sopenharmony_ci const struct ib_recv_wr **bad_wr) 126362306a36Sopenharmony_ci{ 126462306a36Sopenharmony_ci int err = 0; 126562306a36Sopenharmony_ci struct c4iw_qp *qhp; 126662306a36Sopenharmony_ci union t4_recv_wr *wqe = NULL; 126762306a36Sopenharmony_ci u32 num_wrs; 126862306a36Sopenharmony_ci u8 len16 = 0; 126962306a36Sopenharmony_ci unsigned long flag; 127062306a36Sopenharmony_ci u16 idx = 0; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci qhp = to_c4iw_qp(ibqp); 127362306a36Sopenharmony_ci spin_lock_irqsave(&qhp->lock, flag); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci /* 127662306a36Sopenharmony_ci * If the qp has been flushed, then just insert a special 127762306a36Sopenharmony_ci * drain cqe. 127862306a36Sopenharmony_ci */ 127962306a36Sopenharmony_ci if (qhp->wq.flushed) { 128062306a36Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 128162306a36Sopenharmony_ci complete_rq_drain_wrs(qhp, wr); 128262306a36Sopenharmony_ci return err; 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci num_wrs = t4_rq_avail(&qhp->wq); 128562306a36Sopenharmony_ci if (num_wrs == 0) { 128662306a36Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 128762306a36Sopenharmony_ci *bad_wr = wr; 128862306a36Sopenharmony_ci return -ENOMEM; 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci while (wr) { 129162306a36Sopenharmony_ci if (wr->num_sge > T4_MAX_RECV_SGE) { 129262306a36Sopenharmony_ci err = -EINVAL; 129362306a36Sopenharmony_ci *bad_wr = wr; 129462306a36Sopenharmony_ci break; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci wqe = (union t4_recv_wr *)((u8 *)qhp->wq.rq.queue + 129762306a36Sopenharmony_ci qhp->wq.rq.wq_pidx * 129862306a36Sopenharmony_ci T4_EQ_ENTRY_SIZE); 129962306a36Sopenharmony_ci if (num_wrs) 130062306a36Sopenharmony_ci err = build_rdma_recv(qhp, wqe, wr, &len16); 130162306a36Sopenharmony_ci else 130262306a36Sopenharmony_ci err = -ENOMEM; 130362306a36Sopenharmony_ci if (err) { 130462306a36Sopenharmony_ci *bad_wr = wr; 130562306a36Sopenharmony_ci break; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].wr_id = wr->wr_id; 130962306a36Sopenharmony_ci if (c4iw_wr_log) { 131062306a36Sopenharmony_ci qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].sge_ts = 131162306a36Sopenharmony_ci cxgb4_read_sge_timestamp( 131262306a36Sopenharmony_ci qhp->rhp->rdev.lldi.ports[0]); 131362306a36Sopenharmony_ci qhp->wq.rq.sw_rq[qhp->wq.rq.pidx].host_time = 131462306a36Sopenharmony_ci ktime_get(); 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci wqe->recv.opcode = FW_RI_RECV_WR; 131862306a36Sopenharmony_ci wqe->recv.r1 = 0; 131962306a36Sopenharmony_ci wqe->recv.wrid = qhp->wq.rq.pidx; 132062306a36Sopenharmony_ci wqe->recv.r2[0] = 0; 132162306a36Sopenharmony_ci wqe->recv.r2[1] = 0; 132262306a36Sopenharmony_ci wqe->recv.r2[2] = 0; 132362306a36Sopenharmony_ci wqe->recv.len16 = len16; 132462306a36Sopenharmony_ci pr_debug("cookie 0x%llx pidx %u\n", 132562306a36Sopenharmony_ci (unsigned long long)wr->wr_id, qhp->wq.rq.pidx); 132662306a36Sopenharmony_ci t4_rq_produce(&qhp->wq, len16); 132762306a36Sopenharmony_ci idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE); 132862306a36Sopenharmony_ci wr = wr->next; 132962306a36Sopenharmony_ci num_wrs--; 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci if (!qhp->rhp->rdev.status_page->db_off) { 133262306a36Sopenharmony_ci t4_ring_rq_db(&qhp->wq, idx, wqe); 133362306a36Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 133462306a36Sopenharmony_ci } else { 133562306a36Sopenharmony_ci spin_unlock_irqrestore(&qhp->lock, flag); 133662306a36Sopenharmony_ci ring_kernel_rq_db(qhp, idx); 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci return err; 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_cistatic void defer_srq_wr(struct t4_srq *srq, union t4_recv_wr *wqe, 134262306a36Sopenharmony_ci u64 wr_id, u8 len16) 134362306a36Sopenharmony_ci{ 134462306a36Sopenharmony_ci struct t4_srq_pending_wr *pwr = &srq->pending_wrs[srq->pending_pidx]; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_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", 134762306a36Sopenharmony_ci __func__, srq->cidx, srq->pidx, srq->wq_pidx, 134862306a36Sopenharmony_ci srq->in_use, srq->ooo_count, 134962306a36Sopenharmony_ci (unsigned long long)wr_id, srq->pending_cidx, 135062306a36Sopenharmony_ci srq->pending_pidx, srq->pending_in_use); 135162306a36Sopenharmony_ci pwr->wr_id = wr_id; 135262306a36Sopenharmony_ci pwr->len16 = len16; 135362306a36Sopenharmony_ci memcpy(&pwr->wqe, wqe, len16 * 16); 135462306a36Sopenharmony_ci t4_srq_produce_pending_wr(srq); 135562306a36Sopenharmony_ci} 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ciint c4iw_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, 135862306a36Sopenharmony_ci const struct ib_recv_wr **bad_wr) 135962306a36Sopenharmony_ci{ 136062306a36Sopenharmony_ci union t4_recv_wr *wqe, lwqe; 136162306a36Sopenharmony_ci struct c4iw_srq *srq; 136262306a36Sopenharmony_ci unsigned long flag; 136362306a36Sopenharmony_ci u8 len16 = 0; 136462306a36Sopenharmony_ci u16 idx = 0; 136562306a36Sopenharmony_ci int err = 0; 136662306a36Sopenharmony_ci u32 num_wrs; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci srq = to_c4iw_srq(ibsrq); 136962306a36Sopenharmony_ci spin_lock_irqsave(&srq->lock, flag); 137062306a36Sopenharmony_ci num_wrs = t4_srq_avail(&srq->wq); 137162306a36Sopenharmony_ci if (num_wrs == 0) { 137262306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->lock, flag); 137362306a36Sopenharmony_ci return -ENOMEM; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci while (wr) { 137662306a36Sopenharmony_ci if (wr->num_sge > T4_MAX_RECV_SGE) { 137762306a36Sopenharmony_ci err = -EINVAL; 137862306a36Sopenharmony_ci *bad_wr = wr; 137962306a36Sopenharmony_ci break; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci wqe = &lwqe; 138262306a36Sopenharmony_ci if (num_wrs) 138362306a36Sopenharmony_ci err = build_srq_recv(wqe, wr, &len16); 138462306a36Sopenharmony_ci else 138562306a36Sopenharmony_ci err = -ENOMEM; 138662306a36Sopenharmony_ci if (err) { 138762306a36Sopenharmony_ci *bad_wr = wr; 138862306a36Sopenharmony_ci break; 138962306a36Sopenharmony_ci } 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci wqe->recv.opcode = FW_RI_RECV_WR; 139262306a36Sopenharmony_ci wqe->recv.r1 = 0; 139362306a36Sopenharmony_ci wqe->recv.wrid = srq->wq.pidx; 139462306a36Sopenharmony_ci wqe->recv.r2[0] = 0; 139562306a36Sopenharmony_ci wqe->recv.r2[1] = 0; 139662306a36Sopenharmony_ci wqe->recv.r2[2] = 0; 139762306a36Sopenharmony_ci wqe->recv.len16 = len16; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci if (srq->wq.ooo_count || 140062306a36Sopenharmony_ci srq->wq.pending_in_use || 140162306a36Sopenharmony_ci srq->wq.sw_rq[srq->wq.pidx].valid) { 140262306a36Sopenharmony_ci defer_srq_wr(&srq->wq, wqe, wr->wr_id, len16); 140362306a36Sopenharmony_ci } else { 140462306a36Sopenharmony_ci srq->wq.sw_rq[srq->wq.pidx].wr_id = wr->wr_id; 140562306a36Sopenharmony_ci srq->wq.sw_rq[srq->wq.pidx].valid = 1; 140662306a36Sopenharmony_ci c4iw_copy_wr_to_srq(&srq->wq, wqe, len16); 140762306a36Sopenharmony_ci pr_debug("%s cidx %u pidx %u wq_pidx %u in_use %u wr_id 0x%llx\n", 140862306a36Sopenharmony_ci __func__, srq->wq.cidx, 140962306a36Sopenharmony_ci srq->wq.pidx, srq->wq.wq_pidx, 141062306a36Sopenharmony_ci srq->wq.in_use, 141162306a36Sopenharmony_ci (unsigned long long)wr->wr_id); 141262306a36Sopenharmony_ci t4_srq_produce(&srq->wq, len16); 141362306a36Sopenharmony_ci idx += DIV_ROUND_UP(len16 * 16, T4_EQ_ENTRY_SIZE); 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci wr = wr->next; 141662306a36Sopenharmony_ci num_wrs--; 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci if (idx) 141962306a36Sopenharmony_ci t4_ring_srq_db(&srq->wq, idx, len16, wqe); 142062306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->lock, flag); 142162306a36Sopenharmony_ci return err; 142262306a36Sopenharmony_ci} 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_cistatic inline void build_term_codes(struct t4_cqe *err_cqe, u8 *layer_type, 142562306a36Sopenharmony_ci u8 *ecode) 142662306a36Sopenharmony_ci{ 142762306a36Sopenharmony_ci int status; 142862306a36Sopenharmony_ci int tagged; 142962306a36Sopenharmony_ci int opcode; 143062306a36Sopenharmony_ci int rqtype; 143162306a36Sopenharmony_ci int send_inv; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (!err_cqe) { 143462306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|DDP_LOCAL_CATA; 143562306a36Sopenharmony_ci *ecode = 0; 143662306a36Sopenharmony_ci return; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci status = CQE_STATUS(err_cqe); 144062306a36Sopenharmony_ci opcode = CQE_OPCODE(err_cqe); 144162306a36Sopenharmony_ci rqtype = RQ_TYPE(err_cqe); 144262306a36Sopenharmony_ci send_inv = (opcode == FW_RI_SEND_WITH_INV) || 144362306a36Sopenharmony_ci (opcode == FW_RI_SEND_WITH_SE_INV); 144462306a36Sopenharmony_ci tagged = (opcode == FW_RI_RDMA_WRITE) || 144562306a36Sopenharmony_ci (rqtype && (opcode == FW_RI_READ_RESP)); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci switch (status) { 144862306a36Sopenharmony_ci case T4_ERR_STAG: 144962306a36Sopenharmony_ci if (send_inv) { 145062306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP; 145162306a36Sopenharmony_ci *ecode = RDMAP_CANT_INV_STAG; 145262306a36Sopenharmony_ci } else { 145362306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; 145462306a36Sopenharmony_ci *ecode = RDMAP_INV_STAG; 145562306a36Sopenharmony_ci } 145662306a36Sopenharmony_ci break; 145762306a36Sopenharmony_ci case T4_ERR_PDID: 145862306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; 145962306a36Sopenharmony_ci if ((opcode == FW_RI_SEND_WITH_INV) || 146062306a36Sopenharmony_ci (opcode == FW_RI_SEND_WITH_SE_INV)) 146162306a36Sopenharmony_ci *ecode = RDMAP_CANT_INV_STAG; 146262306a36Sopenharmony_ci else 146362306a36Sopenharmony_ci *ecode = RDMAP_STAG_NOT_ASSOC; 146462306a36Sopenharmony_ci break; 146562306a36Sopenharmony_ci case T4_ERR_QPID: 146662306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; 146762306a36Sopenharmony_ci *ecode = RDMAP_STAG_NOT_ASSOC; 146862306a36Sopenharmony_ci break; 146962306a36Sopenharmony_ci case T4_ERR_ACCESS: 147062306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; 147162306a36Sopenharmony_ci *ecode = RDMAP_ACC_VIOL; 147262306a36Sopenharmony_ci break; 147362306a36Sopenharmony_ci case T4_ERR_WRAP: 147462306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; 147562306a36Sopenharmony_ci *ecode = RDMAP_TO_WRAP; 147662306a36Sopenharmony_ci break; 147762306a36Sopenharmony_ci case T4_ERR_BOUND: 147862306a36Sopenharmony_ci if (tagged) { 147962306a36Sopenharmony_ci *layer_type = LAYER_DDP|DDP_TAGGED_ERR; 148062306a36Sopenharmony_ci *ecode = DDPT_BASE_BOUNDS; 148162306a36Sopenharmony_ci } else { 148262306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT; 148362306a36Sopenharmony_ci *ecode = RDMAP_BASE_BOUNDS; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci break; 148662306a36Sopenharmony_ci case T4_ERR_INVALIDATE_SHARED_MR: 148762306a36Sopenharmony_ci case T4_ERR_INVALIDATE_MR_WITH_MW_BOUND: 148862306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP; 148962306a36Sopenharmony_ci *ecode = RDMAP_CANT_INV_STAG; 149062306a36Sopenharmony_ci break; 149162306a36Sopenharmony_ci case T4_ERR_ECC: 149262306a36Sopenharmony_ci case T4_ERR_ECC_PSTAG: 149362306a36Sopenharmony_ci case T4_ERR_INTERNAL_ERR: 149462306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_LOCAL_CATA; 149562306a36Sopenharmony_ci *ecode = 0; 149662306a36Sopenharmony_ci break; 149762306a36Sopenharmony_ci case T4_ERR_OUT_OF_RQE: 149862306a36Sopenharmony_ci *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; 149962306a36Sopenharmony_ci *ecode = DDPU_INV_MSN_NOBUF; 150062306a36Sopenharmony_ci break; 150162306a36Sopenharmony_ci case T4_ERR_PBL_ADDR_BOUND: 150262306a36Sopenharmony_ci *layer_type = LAYER_DDP|DDP_TAGGED_ERR; 150362306a36Sopenharmony_ci *ecode = DDPT_BASE_BOUNDS; 150462306a36Sopenharmony_ci break; 150562306a36Sopenharmony_ci case T4_ERR_CRC: 150662306a36Sopenharmony_ci *layer_type = LAYER_MPA|DDP_LLP; 150762306a36Sopenharmony_ci *ecode = MPA_CRC_ERR; 150862306a36Sopenharmony_ci break; 150962306a36Sopenharmony_ci case T4_ERR_MARKER: 151062306a36Sopenharmony_ci *layer_type = LAYER_MPA|DDP_LLP; 151162306a36Sopenharmony_ci *ecode = MPA_MARKER_ERR; 151262306a36Sopenharmony_ci break; 151362306a36Sopenharmony_ci case T4_ERR_PDU_LEN_ERR: 151462306a36Sopenharmony_ci *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; 151562306a36Sopenharmony_ci *ecode = DDPU_MSG_TOOBIG; 151662306a36Sopenharmony_ci break; 151762306a36Sopenharmony_ci case T4_ERR_DDP_VERSION: 151862306a36Sopenharmony_ci if (tagged) { 151962306a36Sopenharmony_ci *layer_type = LAYER_DDP|DDP_TAGGED_ERR; 152062306a36Sopenharmony_ci *ecode = DDPT_INV_VERS; 152162306a36Sopenharmony_ci } else { 152262306a36Sopenharmony_ci *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; 152362306a36Sopenharmony_ci *ecode = DDPU_INV_VERS; 152462306a36Sopenharmony_ci } 152562306a36Sopenharmony_ci break; 152662306a36Sopenharmony_ci case T4_ERR_RDMA_VERSION: 152762306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP; 152862306a36Sopenharmony_ci *ecode = RDMAP_INV_VERS; 152962306a36Sopenharmony_ci break; 153062306a36Sopenharmony_ci case T4_ERR_OPCODE: 153162306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP; 153262306a36Sopenharmony_ci *ecode = RDMAP_INV_OPCODE; 153362306a36Sopenharmony_ci break; 153462306a36Sopenharmony_ci case T4_ERR_DDP_QUEUE_NUM: 153562306a36Sopenharmony_ci *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; 153662306a36Sopenharmony_ci *ecode = DDPU_INV_QN; 153762306a36Sopenharmony_ci break; 153862306a36Sopenharmony_ci case T4_ERR_MSN: 153962306a36Sopenharmony_ci case T4_ERR_MSN_GAP: 154062306a36Sopenharmony_ci case T4_ERR_MSN_RANGE: 154162306a36Sopenharmony_ci case T4_ERR_IRD_OVERFLOW: 154262306a36Sopenharmony_ci *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; 154362306a36Sopenharmony_ci *ecode = DDPU_INV_MSN_RANGE; 154462306a36Sopenharmony_ci break; 154562306a36Sopenharmony_ci case T4_ERR_TBIT: 154662306a36Sopenharmony_ci *layer_type = LAYER_DDP|DDP_LOCAL_CATA; 154762306a36Sopenharmony_ci *ecode = 0; 154862306a36Sopenharmony_ci break; 154962306a36Sopenharmony_ci case T4_ERR_MO: 155062306a36Sopenharmony_ci *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR; 155162306a36Sopenharmony_ci *ecode = DDPU_INV_MO; 155262306a36Sopenharmony_ci break; 155362306a36Sopenharmony_ci default: 155462306a36Sopenharmony_ci *layer_type = LAYER_RDMAP|DDP_LOCAL_CATA; 155562306a36Sopenharmony_ci *ecode = 0; 155662306a36Sopenharmony_ci break; 155762306a36Sopenharmony_ci } 155862306a36Sopenharmony_ci} 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_cistatic void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe, 156162306a36Sopenharmony_ci gfp_t gfp) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci struct fw_ri_wr *wqe; 156462306a36Sopenharmony_ci struct sk_buff *skb; 156562306a36Sopenharmony_ci struct terminate_message *term; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci pr_debug("qhp %p qid 0x%x tid %u\n", qhp, qhp->wq.sq.qid, 156862306a36Sopenharmony_ci qhp->ep->hwtid); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci skb = skb_dequeue(&qhp->ep->com.ep_skb_list); 157162306a36Sopenharmony_ci if (WARN_ON(!skb)) 157262306a36Sopenharmony_ci return; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci wqe = __skb_put_zero(skb, sizeof(*wqe)); 157762306a36Sopenharmony_ci wqe->op_compl = cpu_to_be32(FW_WR_OP_V(FW_RI_INIT_WR)); 157862306a36Sopenharmony_ci wqe->flowid_len16 = cpu_to_be32( 157962306a36Sopenharmony_ci FW_WR_FLOWID_V(qhp->ep->hwtid) | 158062306a36Sopenharmony_ci FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16))); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci wqe->u.terminate.type = FW_RI_TYPE_TERMINATE; 158362306a36Sopenharmony_ci wqe->u.terminate.immdlen = cpu_to_be32(sizeof(*term)); 158462306a36Sopenharmony_ci term = (struct terminate_message *)wqe->u.terminate.termmsg; 158562306a36Sopenharmony_ci if (qhp->attr.layer_etype == (LAYER_MPA|DDP_LLP)) { 158662306a36Sopenharmony_ci term->layer_etype = qhp->attr.layer_etype; 158762306a36Sopenharmony_ci term->ecode = qhp->attr.ecode; 158862306a36Sopenharmony_ci } else 158962306a36Sopenharmony_ci build_term_codes(err_cqe, &term->layer_etype, &term->ecode); 159062306a36Sopenharmony_ci c4iw_ofld_send(&qhp->rhp->rdev, skb); 159162306a36Sopenharmony_ci} 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci/* 159462306a36Sopenharmony_ci * Assumes qhp lock is held. 159562306a36Sopenharmony_ci */ 159662306a36Sopenharmony_cistatic void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp, 159762306a36Sopenharmony_ci struct c4iw_cq *schp) 159862306a36Sopenharmony_ci{ 159962306a36Sopenharmony_ci int count; 160062306a36Sopenharmony_ci int rq_flushed = 0, sq_flushed; 160162306a36Sopenharmony_ci unsigned long flag; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci pr_debug("qhp %p rchp %p schp %p\n", qhp, rchp, schp); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci /* locking hierarchy: cqs lock first, then qp lock. */ 160662306a36Sopenharmony_ci spin_lock_irqsave(&rchp->lock, flag); 160762306a36Sopenharmony_ci if (schp != rchp) 160862306a36Sopenharmony_ci spin_lock(&schp->lock); 160962306a36Sopenharmony_ci spin_lock(&qhp->lock); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci if (qhp->wq.flushed) { 161262306a36Sopenharmony_ci spin_unlock(&qhp->lock); 161362306a36Sopenharmony_ci if (schp != rchp) 161462306a36Sopenharmony_ci spin_unlock(&schp->lock); 161562306a36Sopenharmony_ci spin_unlock_irqrestore(&rchp->lock, flag); 161662306a36Sopenharmony_ci return; 161762306a36Sopenharmony_ci } 161862306a36Sopenharmony_ci qhp->wq.flushed = 1; 161962306a36Sopenharmony_ci t4_set_wq_in_error(&qhp->wq, 0); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci c4iw_flush_hw_cq(rchp, qhp); 162262306a36Sopenharmony_ci if (!qhp->srq) { 162362306a36Sopenharmony_ci c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count); 162462306a36Sopenharmony_ci rq_flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count); 162562306a36Sopenharmony_ci } 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (schp != rchp) 162862306a36Sopenharmony_ci c4iw_flush_hw_cq(schp, qhp); 162962306a36Sopenharmony_ci sq_flushed = c4iw_flush_sq(qhp); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci spin_unlock(&qhp->lock); 163262306a36Sopenharmony_ci if (schp != rchp) 163362306a36Sopenharmony_ci spin_unlock(&schp->lock); 163462306a36Sopenharmony_ci spin_unlock_irqrestore(&rchp->lock, flag); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci if (schp == rchp) { 163762306a36Sopenharmony_ci if ((rq_flushed || sq_flushed) && 163862306a36Sopenharmony_ci t4_clear_cq_armed(&rchp->cq)) { 163962306a36Sopenharmony_ci spin_lock_irqsave(&rchp->comp_handler_lock, flag); 164062306a36Sopenharmony_ci (*rchp->ibcq.comp_handler)(&rchp->ibcq, 164162306a36Sopenharmony_ci rchp->ibcq.cq_context); 164262306a36Sopenharmony_ci spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci } else { 164562306a36Sopenharmony_ci if (rq_flushed && t4_clear_cq_armed(&rchp->cq)) { 164662306a36Sopenharmony_ci spin_lock_irqsave(&rchp->comp_handler_lock, flag); 164762306a36Sopenharmony_ci (*rchp->ibcq.comp_handler)(&rchp->ibcq, 164862306a36Sopenharmony_ci rchp->ibcq.cq_context); 164962306a36Sopenharmony_ci spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci if (sq_flushed && t4_clear_cq_armed(&schp->cq)) { 165262306a36Sopenharmony_ci spin_lock_irqsave(&schp->comp_handler_lock, flag); 165362306a36Sopenharmony_ci (*schp->ibcq.comp_handler)(&schp->ibcq, 165462306a36Sopenharmony_ci schp->ibcq.cq_context); 165562306a36Sopenharmony_ci spin_unlock_irqrestore(&schp->comp_handler_lock, flag); 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci} 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_cistatic void flush_qp(struct c4iw_qp *qhp) 166162306a36Sopenharmony_ci{ 166262306a36Sopenharmony_ci struct c4iw_cq *rchp, *schp; 166362306a36Sopenharmony_ci unsigned long flag; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci rchp = to_c4iw_cq(qhp->ibqp.recv_cq); 166662306a36Sopenharmony_ci schp = to_c4iw_cq(qhp->ibqp.send_cq); 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci if (qhp->ibqp.uobject) { 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci /* for user qps, qhp->wq.flushed is protected by qhp->mutex */ 167162306a36Sopenharmony_ci if (qhp->wq.flushed) 167262306a36Sopenharmony_ci return; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci qhp->wq.flushed = 1; 167562306a36Sopenharmony_ci t4_set_wq_in_error(&qhp->wq, 0); 167662306a36Sopenharmony_ci t4_set_cq_in_error(&rchp->cq); 167762306a36Sopenharmony_ci spin_lock_irqsave(&rchp->comp_handler_lock, flag); 167862306a36Sopenharmony_ci (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); 167962306a36Sopenharmony_ci spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); 168062306a36Sopenharmony_ci if (schp != rchp) { 168162306a36Sopenharmony_ci t4_set_cq_in_error(&schp->cq); 168262306a36Sopenharmony_ci spin_lock_irqsave(&schp->comp_handler_lock, flag); 168362306a36Sopenharmony_ci (*schp->ibcq.comp_handler)(&schp->ibcq, 168462306a36Sopenharmony_ci schp->ibcq.cq_context); 168562306a36Sopenharmony_ci spin_unlock_irqrestore(&schp->comp_handler_lock, flag); 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci return; 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci __flush_qp(qhp, rchp, schp); 169062306a36Sopenharmony_ci} 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_cistatic int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp, 169362306a36Sopenharmony_ci struct c4iw_ep *ep) 169462306a36Sopenharmony_ci{ 169562306a36Sopenharmony_ci struct fw_ri_wr *wqe; 169662306a36Sopenharmony_ci int ret; 169762306a36Sopenharmony_ci struct sk_buff *skb; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci pr_debug("qhp %p qid 0x%x tid %u\n", qhp, qhp->wq.sq.qid, ep->hwtid); 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci skb = skb_dequeue(&ep->com.ep_skb_list); 170262306a36Sopenharmony_ci if (WARN_ON(!skb)) 170362306a36Sopenharmony_ci return -ENOMEM; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, ep->txq_idx); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci wqe = __skb_put_zero(skb, sizeof(*wqe)); 170862306a36Sopenharmony_ci wqe->op_compl = cpu_to_be32( 170962306a36Sopenharmony_ci FW_WR_OP_V(FW_RI_INIT_WR) | 171062306a36Sopenharmony_ci FW_WR_COMPL_F); 171162306a36Sopenharmony_ci wqe->flowid_len16 = cpu_to_be32( 171262306a36Sopenharmony_ci FW_WR_FLOWID_V(ep->hwtid) | 171362306a36Sopenharmony_ci FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16))); 171462306a36Sopenharmony_ci wqe->cookie = (uintptr_t)ep->com.wr_waitp; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci wqe->u.fini.type = FW_RI_TYPE_FINI; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci ret = c4iw_ref_send_wait(&rhp->rdev, skb, ep->com.wr_waitp, 171962306a36Sopenharmony_ci qhp->ep->hwtid, qhp->wq.sq.qid, __func__); 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci pr_debug("ret %d\n", ret); 172262306a36Sopenharmony_ci return ret; 172362306a36Sopenharmony_ci} 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_cistatic void build_rtr_msg(u8 p2p_type, struct fw_ri_init *init) 172662306a36Sopenharmony_ci{ 172762306a36Sopenharmony_ci pr_debug("p2p_type = %d\n", p2p_type); 172862306a36Sopenharmony_ci memset(&init->u, 0, sizeof(init->u)); 172962306a36Sopenharmony_ci switch (p2p_type) { 173062306a36Sopenharmony_ci case FW_RI_INIT_P2PTYPE_RDMA_WRITE: 173162306a36Sopenharmony_ci init->u.write.opcode = FW_RI_RDMA_WRITE_WR; 173262306a36Sopenharmony_ci init->u.write.stag_sink = cpu_to_be32(1); 173362306a36Sopenharmony_ci init->u.write.to_sink = cpu_to_be64(1); 173462306a36Sopenharmony_ci init->u.write.u.immd_src[0].op = FW_RI_DATA_IMMD; 173562306a36Sopenharmony_ci init->u.write.len16 = DIV_ROUND_UP( 173662306a36Sopenharmony_ci sizeof(init->u.write) + sizeof(struct fw_ri_immd), 16); 173762306a36Sopenharmony_ci break; 173862306a36Sopenharmony_ci case FW_RI_INIT_P2PTYPE_READ_REQ: 173962306a36Sopenharmony_ci init->u.write.opcode = FW_RI_RDMA_READ_WR; 174062306a36Sopenharmony_ci init->u.read.stag_src = cpu_to_be32(1); 174162306a36Sopenharmony_ci init->u.read.to_src_lo = cpu_to_be32(1); 174262306a36Sopenharmony_ci init->u.read.stag_sink = cpu_to_be32(1); 174362306a36Sopenharmony_ci init->u.read.to_sink_lo = cpu_to_be32(1); 174462306a36Sopenharmony_ci init->u.read.len16 = DIV_ROUND_UP(sizeof(init->u.read), 16); 174562306a36Sopenharmony_ci break; 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci} 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_cistatic int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp) 175062306a36Sopenharmony_ci{ 175162306a36Sopenharmony_ci struct fw_ri_wr *wqe; 175262306a36Sopenharmony_ci int ret; 175362306a36Sopenharmony_ci struct sk_buff *skb; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci pr_debug("qhp %p qid 0x%x tid %u ird %u ord %u\n", qhp, 175662306a36Sopenharmony_ci qhp->wq.sq.qid, qhp->ep->hwtid, qhp->ep->ird, qhp->ep->ord); 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci skb = alloc_skb(sizeof(*wqe), GFP_KERNEL); 175962306a36Sopenharmony_ci if (!skb) { 176062306a36Sopenharmony_ci ret = -ENOMEM; 176162306a36Sopenharmony_ci goto out; 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci ret = alloc_ird(rhp, qhp->attr.max_ird); 176462306a36Sopenharmony_ci if (ret) { 176562306a36Sopenharmony_ci qhp->attr.max_ird = 0; 176662306a36Sopenharmony_ci kfree_skb(skb); 176762306a36Sopenharmony_ci goto out; 176862306a36Sopenharmony_ci } 176962306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_DATA, qhp->ep->txq_idx); 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci wqe = __skb_put_zero(skb, sizeof(*wqe)); 177262306a36Sopenharmony_ci wqe->op_compl = cpu_to_be32( 177362306a36Sopenharmony_ci FW_WR_OP_V(FW_RI_INIT_WR) | 177462306a36Sopenharmony_ci FW_WR_COMPL_F); 177562306a36Sopenharmony_ci wqe->flowid_len16 = cpu_to_be32( 177662306a36Sopenharmony_ci FW_WR_FLOWID_V(qhp->ep->hwtid) | 177762306a36Sopenharmony_ci FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16))); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci wqe->cookie = (uintptr_t)qhp->ep->com.wr_waitp; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci wqe->u.init.type = FW_RI_TYPE_INIT; 178262306a36Sopenharmony_ci wqe->u.init.mpareqbit_p2ptype = 178362306a36Sopenharmony_ci FW_RI_WR_MPAREQBIT_V(qhp->attr.mpa_attr.initiator) | 178462306a36Sopenharmony_ci FW_RI_WR_P2PTYPE_V(qhp->attr.mpa_attr.p2p_type); 178562306a36Sopenharmony_ci wqe->u.init.mpa_attrs = FW_RI_MPA_IETF_ENABLE; 178662306a36Sopenharmony_ci if (qhp->attr.mpa_attr.recv_marker_enabled) 178762306a36Sopenharmony_ci wqe->u.init.mpa_attrs |= FW_RI_MPA_RX_MARKER_ENABLE; 178862306a36Sopenharmony_ci if (qhp->attr.mpa_attr.xmit_marker_enabled) 178962306a36Sopenharmony_ci wqe->u.init.mpa_attrs |= FW_RI_MPA_TX_MARKER_ENABLE; 179062306a36Sopenharmony_ci if (qhp->attr.mpa_attr.crc_enabled) 179162306a36Sopenharmony_ci wqe->u.init.mpa_attrs |= FW_RI_MPA_CRC_ENABLE; 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci wqe->u.init.qp_caps = FW_RI_QP_RDMA_READ_ENABLE | 179462306a36Sopenharmony_ci FW_RI_QP_RDMA_WRITE_ENABLE | 179562306a36Sopenharmony_ci FW_RI_QP_BIND_ENABLE; 179662306a36Sopenharmony_ci if (!qhp->ibqp.uobject) 179762306a36Sopenharmony_ci wqe->u.init.qp_caps |= FW_RI_QP_FAST_REGISTER_ENABLE | 179862306a36Sopenharmony_ci FW_RI_QP_STAG0_ENABLE; 179962306a36Sopenharmony_ci wqe->u.init.nrqe = cpu_to_be16(t4_rqes_posted(&qhp->wq)); 180062306a36Sopenharmony_ci wqe->u.init.pdid = cpu_to_be32(qhp->attr.pd); 180162306a36Sopenharmony_ci wqe->u.init.qpid = cpu_to_be32(qhp->wq.sq.qid); 180262306a36Sopenharmony_ci wqe->u.init.sq_eqid = cpu_to_be32(qhp->wq.sq.qid); 180362306a36Sopenharmony_ci if (qhp->srq) { 180462306a36Sopenharmony_ci wqe->u.init.rq_eqid = cpu_to_be32(FW_RI_INIT_RQEQID_SRQ | 180562306a36Sopenharmony_ci qhp->srq->idx); 180662306a36Sopenharmony_ci } else { 180762306a36Sopenharmony_ci wqe->u.init.rq_eqid = cpu_to_be32(qhp->wq.rq.qid); 180862306a36Sopenharmony_ci wqe->u.init.hwrqsize = cpu_to_be32(qhp->wq.rq.rqt_size); 180962306a36Sopenharmony_ci wqe->u.init.hwrqaddr = cpu_to_be32(qhp->wq.rq.rqt_hwaddr - 181062306a36Sopenharmony_ci rhp->rdev.lldi.vr->rq.start); 181162306a36Sopenharmony_ci } 181262306a36Sopenharmony_ci wqe->u.init.scqid = cpu_to_be32(qhp->attr.scq); 181362306a36Sopenharmony_ci wqe->u.init.rcqid = cpu_to_be32(qhp->attr.rcq); 181462306a36Sopenharmony_ci wqe->u.init.ord_max = cpu_to_be32(qhp->attr.max_ord); 181562306a36Sopenharmony_ci wqe->u.init.ird_max = cpu_to_be32(qhp->attr.max_ird); 181662306a36Sopenharmony_ci wqe->u.init.iss = cpu_to_be32(qhp->ep->snd_seq); 181762306a36Sopenharmony_ci wqe->u.init.irs = cpu_to_be32(qhp->ep->rcv_seq); 181862306a36Sopenharmony_ci if (qhp->attr.mpa_attr.initiator) 181962306a36Sopenharmony_ci build_rtr_msg(qhp->attr.mpa_attr.p2p_type, &wqe->u.init); 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci ret = c4iw_ref_send_wait(&rhp->rdev, skb, qhp->ep->com.wr_waitp, 182262306a36Sopenharmony_ci qhp->ep->hwtid, qhp->wq.sq.qid, __func__); 182362306a36Sopenharmony_ci if (!ret) 182462306a36Sopenharmony_ci goto out; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci free_ird(rhp, qhp->attr.max_ird); 182762306a36Sopenharmony_ciout: 182862306a36Sopenharmony_ci pr_debug("ret %d\n", ret); 182962306a36Sopenharmony_ci return ret; 183062306a36Sopenharmony_ci} 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ciint c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, 183362306a36Sopenharmony_ci enum c4iw_qp_attr_mask mask, 183462306a36Sopenharmony_ci struct c4iw_qp_attributes *attrs, 183562306a36Sopenharmony_ci int internal) 183662306a36Sopenharmony_ci{ 183762306a36Sopenharmony_ci int ret = 0; 183862306a36Sopenharmony_ci struct c4iw_qp_attributes newattr = qhp->attr; 183962306a36Sopenharmony_ci int disconnect = 0; 184062306a36Sopenharmony_ci int terminate = 0; 184162306a36Sopenharmony_ci int abort = 0; 184262306a36Sopenharmony_ci int free = 0; 184362306a36Sopenharmony_ci struct c4iw_ep *ep = NULL; 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci pr_debug("qhp %p sqid 0x%x rqid 0x%x ep %p state %d -> %d\n", 184662306a36Sopenharmony_ci qhp, qhp->wq.sq.qid, qhp->wq.rq.qid, qhp->ep, qhp->attr.state, 184762306a36Sopenharmony_ci (mask & C4IW_QP_ATTR_NEXT_STATE) ? attrs->next_state : -1); 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci mutex_lock(&qhp->mutex); 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci /* Process attr changes if in IDLE */ 185262306a36Sopenharmony_ci if (mask & C4IW_QP_ATTR_VALID_MODIFY) { 185362306a36Sopenharmony_ci if (qhp->attr.state != C4IW_QP_STATE_IDLE) { 185462306a36Sopenharmony_ci ret = -EIO; 185562306a36Sopenharmony_ci goto out; 185662306a36Sopenharmony_ci } 185762306a36Sopenharmony_ci if (mask & C4IW_QP_ATTR_ENABLE_RDMA_READ) 185862306a36Sopenharmony_ci newattr.enable_rdma_read = attrs->enable_rdma_read; 185962306a36Sopenharmony_ci if (mask & C4IW_QP_ATTR_ENABLE_RDMA_WRITE) 186062306a36Sopenharmony_ci newattr.enable_rdma_write = attrs->enable_rdma_write; 186162306a36Sopenharmony_ci if (mask & C4IW_QP_ATTR_ENABLE_RDMA_BIND) 186262306a36Sopenharmony_ci newattr.enable_bind = attrs->enable_bind; 186362306a36Sopenharmony_ci if (mask & C4IW_QP_ATTR_MAX_ORD) { 186462306a36Sopenharmony_ci if (attrs->max_ord > c4iw_max_read_depth) { 186562306a36Sopenharmony_ci ret = -EINVAL; 186662306a36Sopenharmony_ci goto out; 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci newattr.max_ord = attrs->max_ord; 186962306a36Sopenharmony_ci } 187062306a36Sopenharmony_ci if (mask & C4IW_QP_ATTR_MAX_IRD) { 187162306a36Sopenharmony_ci if (attrs->max_ird > cur_max_read_depth(rhp)) { 187262306a36Sopenharmony_ci ret = -EINVAL; 187362306a36Sopenharmony_ci goto out; 187462306a36Sopenharmony_ci } 187562306a36Sopenharmony_ci newattr.max_ird = attrs->max_ird; 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci qhp->attr = newattr; 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci if (mask & C4IW_QP_ATTR_SQ_DB) { 188162306a36Sopenharmony_ci ret = ring_kernel_sq_db(qhp, attrs->sq_db_inc); 188262306a36Sopenharmony_ci goto out; 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci if (mask & C4IW_QP_ATTR_RQ_DB) { 188562306a36Sopenharmony_ci ret = ring_kernel_rq_db(qhp, attrs->rq_db_inc); 188662306a36Sopenharmony_ci goto out; 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci if (!(mask & C4IW_QP_ATTR_NEXT_STATE)) 189062306a36Sopenharmony_ci goto out; 189162306a36Sopenharmony_ci if (qhp->attr.state == attrs->next_state) 189262306a36Sopenharmony_ci goto out; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci switch (qhp->attr.state) { 189562306a36Sopenharmony_ci case C4IW_QP_STATE_IDLE: 189662306a36Sopenharmony_ci switch (attrs->next_state) { 189762306a36Sopenharmony_ci case C4IW_QP_STATE_RTS: 189862306a36Sopenharmony_ci if (!(mask & C4IW_QP_ATTR_LLP_STREAM_HANDLE)) { 189962306a36Sopenharmony_ci ret = -EINVAL; 190062306a36Sopenharmony_ci goto out; 190162306a36Sopenharmony_ci } 190262306a36Sopenharmony_ci if (!(mask & C4IW_QP_ATTR_MPA_ATTR)) { 190362306a36Sopenharmony_ci ret = -EINVAL; 190462306a36Sopenharmony_ci goto out; 190562306a36Sopenharmony_ci } 190662306a36Sopenharmony_ci qhp->attr.mpa_attr = attrs->mpa_attr; 190762306a36Sopenharmony_ci qhp->attr.llp_stream_handle = attrs->llp_stream_handle; 190862306a36Sopenharmony_ci qhp->ep = qhp->attr.llp_stream_handle; 190962306a36Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_RTS); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci /* 191262306a36Sopenharmony_ci * Ref the endpoint here and deref when we 191362306a36Sopenharmony_ci * disassociate the endpoint from the QP. This 191462306a36Sopenharmony_ci * happens in CLOSING->IDLE transition or *->ERROR 191562306a36Sopenharmony_ci * transition. 191662306a36Sopenharmony_ci */ 191762306a36Sopenharmony_ci c4iw_get_ep(&qhp->ep->com); 191862306a36Sopenharmony_ci ret = rdma_init(rhp, qhp); 191962306a36Sopenharmony_ci if (ret) 192062306a36Sopenharmony_ci goto err; 192162306a36Sopenharmony_ci break; 192262306a36Sopenharmony_ci case C4IW_QP_STATE_ERROR: 192362306a36Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_ERROR); 192462306a36Sopenharmony_ci flush_qp(qhp); 192562306a36Sopenharmony_ci break; 192662306a36Sopenharmony_ci default: 192762306a36Sopenharmony_ci ret = -EINVAL; 192862306a36Sopenharmony_ci goto out; 192962306a36Sopenharmony_ci } 193062306a36Sopenharmony_ci break; 193162306a36Sopenharmony_ci case C4IW_QP_STATE_RTS: 193262306a36Sopenharmony_ci switch (attrs->next_state) { 193362306a36Sopenharmony_ci case C4IW_QP_STATE_CLOSING: 193462306a36Sopenharmony_ci t4_set_wq_in_error(&qhp->wq, 0); 193562306a36Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_CLOSING); 193662306a36Sopenharmony_ci ep = qhp->ep; 193762306a36Sopenharmony_ci if (!internal) { 193862306a36Sopenharmony_ci abort = 0; 193962306a36Sopenharmony_ci disconnect = 1; 194062306a36Sopenharmony_ci c4iw_get_ep(&qhp->ep->com); 194162306a36Sopenharmony_ci } 194262306a36Sopenharmony_ci ret = rdma_fini(rhp, qhp, ep); 194362306a36Sopenharmony_ci if (ret) 194462306a36Sopenharmony_ci goto err; 194562306a36Sopenharmony_ci break; 194662306a36Sopenharmony_ci case C4IW_QP_STATE_TERMINATE: 194762306a36Sopenharmony_ci t4_set_wq_in_error(&qhp->wq, 0); 194862306a36Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_TERMINATE); 194962306a36Sopenharmony_ci qhp->attr.layer_etype = attrs->layer_etype; 195062306a36Sopenharmony_ci qhp->attr.ecode = attrs->ecode; 195162306a36Sopenharmony_ci ep = qhp->ep; 195262306a36Sopenharmony_ci if (!internal) { 195362306a36Sopenharmony_ci c4iw_get_ep(&ep->com); 195462306a36Sopenharmony_ci terminate = 1; 195562306a36Sopenharmony_ci disconnect = 1; 195662306a36Sopenharmony_ci } else { 195762306a36Sopenharmony_ci terminate = qhp->attr.send_term; 195862306a36Sopenharmony_ci ret = rdma_fini(rhp, qhp, ep); 195962306a36Sopenharmony_ci if (ret) 196062306a36Sopenharmony_ci goto err; 196162306a36Sopenharmony_ci } 196262306a36Sopenharmony_ci break; 196362306a36Sopenharmony_ci case C4IW_QP_STATE_ERROR: 196462306a36Sopenharmony_ci t4_set_wq_in_error(&qhp->wq, 0); 196562306a36Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_ERROR); 196662306a36Sopenharmony_ci if (!internal) { 196762306a36Sopenharmony_ci disconnect = 1; 196862306a36Sopenharmony_ci ep = qhp->ep; 196962306a36Sopenharmony_ci c4iw_get_ep(&qhp->ep->com); 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci goto err; 197262306a36Sopenharmony_ci break; 197362306a36Sopenharmony_ci default: 197462306a36Sopenharmony_ci ret = -EINVAL; 197562306a36Sopenharmony_ci goto out; 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci break; 197862306a36Sopenharmony_ci case C4IW_QP_STATE_CLOSING: 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci /* 198162306a36Sopenharmony_ci * Allow kernel users to move to ERROR for qp draining. 198262306a36Sopenharmony_ci */ 198362306a36Sopenharmony_ci if (!internal && (qhp->ibqp.uobject || attrs->next_state != 198462306a36Sopenharmony_ci C4IW_QP_STATE_ERROR)) { 198562306a36Sopenharmony_ci ret = -EINVAL; 198662306a36Sopenharmony_ci goto out; 198762306a36Sopenharmony_ci } 198862306a36Sopenharmony_ci switch (attrs->next_state) { 198962306a36Sopenharmony_ci case C4IW_QP_STATE_IDLE: 199062306a36Sopenharmony_ci flush_qp(qhp); 199162306a36Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_IDLE); 199262306a36Sopenharmony_ci qhp->attr.llp_stream_handle = NULL; 199362306a36Sopenharmony_ci c4iw_put_ep(&qhp->ep->com); 199462306a36Sopenharmony_ci qhp->ep = NULL; 199562306a36Sopenharmony_ci wake_up(&qhp->wait); 199662306a36Sopenharmony_ci break; 199762306a36Sopenharmony_ci case C4IW_QP_STATE_ERROR: 199862306a36Sopenharmony_ci goto err; 199962306a36Sopenharmony_ci default: 200062306a36Sopenharmony_ci ret = -EINVAL; 200162306a36Sopenharmony_ci goto err; 200262306a36Sopenharmony_ci } 200362306a36Sopenharmony_ci break; 200462306a36Sopenharmony_ci case C4IW_QP_STATE_ERROR: 200562306a36Sopenharmony_ci if (attrs->next_state != C4IW_QP_STATE_IDLE) { 200662306a36Sopenharmony_ci ret = -EINVAL; 200762306a36Sopenharmony_ci goto out; 200862306a36Sopenharmony_ci } 200962306a36Sopenharmony_ci if (!t4_sq_empty(&qhp->wq) || !t4_rq_empty(&qhp->wq)) { 201062306a36Sopenharmony_ci ret = -EINVAL; 201162306a36Sopenharmony_ci goto out; 201262306a36Sopenharmony_ci } 201362306a36Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_IDLE); 201462306a36Sopenharmony_ci break; 201562306a36Sopenharmony_ci case C4IW_QP_STATE_TERMINATE: 201662306a36Sopenharmony_ci if (!internal) { 201762306a36Sopenharmony_ci ret = -EINVAL; 201862306a36Sopenharmony_ci goto out; 201962306a36Sopenharmony_ci } 202062306a36Sopenharmony_ci goto err; 202162306a36Sopenharmony_ci break; 202262306a36Sopenharmony_ci default: 202362306a36Sopenharmony_ci pr_err("%s in a bad state %d\n", __func__, qhp->attr.state); 202462306a36Sopenharmony_ci ret = -EINVAL; 202562306a36Sopenharmony_ci goto err; 202662306a36Sopenharmony_ci break; 202762306a36Sopenharmony_ci } 202862306a36Sopenharmony_ci goto out; 202962306a36Sopenharmony_cierr: 203062306a36Sopenharmony_ci pr_debug("disassociating ep %p qpid 0x%x\n", qhp->ep, 203162306a36Sopenharmony_ci qhp->wq.sq.qid); 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci /* disassociate the LLP connection */ 203462306a36Sopenharmony_ci qhp->attr.llp_stream_handle = NULL; 203562306a36Sopenharmony_ci if (!ep) 203662306a36Sopenharmony_ci ep = qhp->ep; 203762306a36Sopenharmony_ci qhp->ep = NULL; 203862306a36Sopenharmony_ci set_state(qhp, C4IW_QP_STATE_ERROR); 203962306a36Sopenharmony_ci free = 1; 204062306a36Sopenharmony_ci abort = 1; 204162306a36Sopenharmony_ci flush_qp(qhp); 204262306a36Sopenharmony_ci wake_up(&qhp->wait); 204362306a36Sopenharmony_ciout: 204462306a36Sopenharmony_ci mutex_unlock(&qhp->mutex); 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci if (terminate) 204762306a36Sopenharmony_ci post_terminate(qhp, NULL, internal ? GFP_ATOMIC : GFP_KERNEL); 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci /* 205062306a36Sopenharmony_ci * If disconnect is 1, then we need to initiate a disconnect 205162306a36Sopenharmony_ci * on the EP. This can be a normal close (RTS->CLOSING) or 205262306a36Sopenharmony_ci * an abnormal close (RTS/CLOSING->ERROR). 205362306a36Sopenharmony_ci */ 205462306a36Sopenharmony_ci if (disconnect) { 205562306a36Sopenharmony_ci c4iw_ep_disconnect(ep, abort, internal ? GFP_ATOMIC : 205662306a36Sopenharmony_ci GFP_KERNEL); 205762306a36Sopenharmony_ci c4iw_put_ep(&ep->com); 205862306a36Sopenharmony_ci } 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci /* 206162306a36Sopenharmony_ci * If free is 1, then we've disassociated the EP from the QP 206262306a36Sopenharmony_ci * and we need to dereference the EP. 206362306a36Sopenharmony_ci */ 206462306a36Sopenharmony_ci if (free) 206562306a36Sopenharmony_ci c4iw_put_ep(&ep->com); 206662306a36Sopenharmony_ci pr_debug("exit state %d\n", qhp->attr.state); 206762306a36Sopenharmony_ci return ret; 206862306a36Sopenharmony_ci} 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ciint c4iw_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata) 207162306a36Sopenharmony_ci{ 207262306a36Sopenharmony_ci struct c4iw_dev *rhp; 207362306a36Sopenharmony_ci struct c4iw_qp *qhp; 207462306a36Sopenharmony_ci struct c4iw_ucontext *ucontext; 207562306a36Sopenharmony_ci struct c4iw_qp_attributes attrs; 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci qhp = to_c4iw_qp(ib_qp); 207862306a36Sopenharmony_ci rhp = qhp->rhp; 207962306a36Sopenharmony_ci ucontext = qhp->ucontext; 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci attrs.next_state = C4IW_QP_STATE_ERROR; 208262306a36Sopenharmony_ci if (qhp->attr.state == C4IW_QP_STATE_TERMINATE) 208362306a36Sopenharmony_ci c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); 208462306a36Sopenharmony_ci else 208562306a36Sopenharmony_ci c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); 208662306a36Sopenharmony_ci wait_event(qhp->wait, !qhp->ep); 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci xa_lock_irq(&rhp->qps); 208962306a36Sopenharmony_ci __xa_erase(&rhp->qps, qhp->wq.sq.qid); 209062306a36Sopenharmony_ci if (!list_empty(&qhp->db_fc_entry)) 209162306a36Sopenharmony_ci list_del_init(&qhp->db_fc_entry); 209262306a36Sopenharmony_ci xa_unlock_irq(&rhp->qps); 209362306a36Sopenharmony_ci free_ird(rhp, qhp->attr.max_ird); 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci c4iw_qp_rem_ref(ib_qp); 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci wait_for_completion(&qhp->qp_rel_comp); 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci pr_debug("ib_qp %p qpid 0x%0x\n", ib_qp, qhp->wq.sq.qid); 210062306a36Sopenharmony_ci pr_debug("qhp %p ucontext %p\n", qhp, ucontext); 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci destroy_qp(&rhp->rdev, &qhp->wq, 210362306a36Sopenharmony_ci ucontext ? &ucontext->uctx : &rhp->rdev.uctx, !qhp->srq); 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci c4iw_put_wr_wait(qhp->wr_waitp); 210662306a36Sopenharmony_ci return 0; 210762306a36Sopenharmony_ci} 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ciint c4iw_create_qp(struct ib_qp *qp, struct ib_qp_init_attr *attrs, 211062306a36Sopenharmony_ci struct ib_udata *udata) 211162306a36Sopenharmony_ci{ 211262306a36Sopenharmony_ci struct ib_pd *pd = qp->pd; 211362306a36Sopenharmony_ci struct c4iw_dev *rhp; 211462306a36Sopenharmony_ci struct c4iw_qp *qhp = to_c4iw_qp(qp); 211562306a36Sopenharmony_ci struct c4iw_pd *php; 211662306a36Sopenharmony_ci struct c4iw_cq *schp; 211762306a36Sopenharmony_ci struct c4iw_cq *rchp; 211862306a36Sopenharmony_ci struct c4iw_create_qp_resp uresp; 211962306a36Sopenharmony_ci unsigned int sqsize, rqsize = 0; 212062306a36Sopenharmony_ci struct c4iw_ucontext *ucontext = rdma_udata_to_drv_context( 212162306a36Sopenharmony_ci udata, struct c4iw_ucontext, ibucontext); 212262306a36Sopenharmony_ci int ret; 212362306a36Sopenharmony_ci struct c4iw_mm_entry *sq_key_mm, *rq_key_mm = NULL, *sq_db_key_mm; 212462306a36Sopenharmony_ci struct c4iw_mm_entry *rq_db_key_mm = NULL, *ma_sync_key_mm = NULL; 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci if (attrs->qp_type != IB_QPT_RC || attrs->create_flags) 212762306a36Sopenharmony_ci return -EOPNOTSUPP; 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci php = to_c4iw_pd(pd); 213062306a36Sopenharmony_ci rhp = php->rhp; 213162306a36Sopenharmony_ci schp = get_chp(rhp, ((struct c4iw_cq *)attrs->send_cq)->cq.cqid); 213262306a36Sopenharmony_ci rchp = get_chp(rhp, ((struct c4iw_cq *)attrs->recv_cq)->cq.cqid); 213362306a36Sopenharmony_ci if (!schp || !rchp) 213462306a36Sopenharmony_ci return -EINVAL; 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci if (attrs->cap.max_inline_data > T4_MAX_SEND_INLINE) 213762306a36Sopenharmony_ci return -EINVAL; 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci if (!attrs->srq) { 214062306a36Sopenharmony_ci if (attrs->cap.max_recv_wr > rhp->rdev.hw_queue.t4_max_rq_size) 214162306a36Sopenharmony_ci return -E2BIG; 214262306a36Sopenharmony_ci rqsize = attrs->cap.max_recv_wr + 1; 214362306a36Sopenharmony_ci if (rqsize < 8) 214462306a36Sopenharmony_ci rqsize = 8; 214562306a36Sopenharmony_ci } 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci if (attrs->cap.max_send_wr > rhp->rdev.hw_queue.t4_max_sq_size) 214862306a36Sopenharmony_ci return -E2BIG; 214962306a36Sopenharmony_ci sqsize = attrs->cap.max_send_wr + 1; 215062306a36Sopenharmony_ci if (sqsize < 8) 215162306a36Sopenharmony_ci sqsize = 8; 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_ci qhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL); 215462306a36Sopenharmony_ci if (!qhp->wr_waitp) 215562306a36Sopenharmony_ci return -ENOMEM; 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci qhp->wq.sq.size = sqsize; 215862306a36Sopenharmony_ci qhp->wq.sq.memsize = 215962306a36Sopenharmony_ci (sqsize + rhp->rdev.hw_queue.t4_eq_status_entries) * 216062306a36Sopenharmony_ci sizeof(*qhp->wq.sq.queue) + 16 * sizeof(__be64); 216162306a36Sopenharmony_ci qhp->wq.sq.flush_cidx = -1; 216262306a36Sopenharmony_ci if (!attrs->srq) { 216362306a36Sopenharmony_ci qhp->wq.rq.size = rqsize; 216462306a36Sopenharmony_ci qhp->wq.rq.memsize = 216562306a36Sopenharmony_ci (rqsize + rhp->rdev.hw_queue.t4_eq_status_entries) * 216662306a36Sopenharmony_ci sizeof(*qhp->wq.rq.queue); 216762306a36Sopenharmony_ci } 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci if (ucontext) { 217062306a36Sopenharmony_ci qhp->wq.sq.memsize = roundup(qhp->wq.sq.memsize, PAGE_SIZE); 217162306a36Sopenharmony_ci if (!attrs->srq) 217262306a36Sopenharmony_ci qhp->wq.rq.memsize = 217362306a36Sopenharmony_ci roundup(qhp->wq.rq.memsize, PAGE_SIZE); 217462306a36Sopenharmony_ci } 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci ret = create_qp(&rhp->rdev, &qhp->wq, &schp->cq, &rchp->cq, 217762306a36Sopenharmony_ci ucontext ? &ucontext->uctx : &rhp->rdev.uctx, 217862306a36Sopenharmony_ci qhp->wr_waitp, !attrs->srq); 217962306a36Sopenharmony_ci if (ret) 218062306a36Sopenharmony_ci goto err_free_wr_wait; 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci attrs->cap.max_recv_wr = rqsize - 1; 218362306a36Sopenharmony_ci attrs->cap.max_send_wr = sqsize - 1; 218462306a36Sopenharmony_ci attrs->cap.max_inline_data = T4_MAX_SEND_INLINE; 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci qhp->rhp = rhp; 218762306a36Sopenharmony_ci qhp->attr.pd = php->pdid; 218862306a36Sopenharmony_ci qhp->attr.scq = ((struct c4iw_cq *) attrs->send_cq)->cq.cqid; 218962306a36Sopenharmony_ci qhp->attr.rcq = ((struct c4iw_cq *) attrs->recv_cq)->cq.cqid; 219062306a36Sopenharmony_ci qhp->attr.sq_num_entries = attrs->cap.max_send_wr; 219162306a36Sopenharmony_ci qhp->attr.sq_max_sges = attrs->cap.max_send_sge; 219262306a36Sopenharmony_ci qhp->attr.sq_max_sges_rdma_write = attrs->cap.max_send_sge; 219362306a36Sopenharmony_ci if (!attrs->srq) { 219462306a36Sopenharmony_ci qhp->attr.rq_num_entries = attrs->cap.max_recv_wr; 219562306a36Sopenharmony_ci qhp->attr.rq_max_sges = attrs->cap.max_recv_sge; 219662306a36Sopenharmony_ci } 219762306a36Sopenharmony_ci qhp->attr.state = C4IW_QP_STATE_IDLE; 219862306a36Sopenharmony_ci qhp->attr.next_state = C4IW_QP_STATE_IDLE; 219962306a36Sopenharmony_ci qhp->attr.enable_rdma_read = 1; 220062306a36Sopenharmony_ci qhp->attr.enable_rdma_write = 1; 220162306a36Sopenharmony_ci qhp->attr.enable_bind = 1; 220262306a36Sopenharmony_ci qhp->attr.max_ord = 0; 220362306a36Sopenharmony_ci qhp->attr.max_ird = 0; 220462306a36Sopenharmony_ci qhp->sq_sig_all = attrs->sq_sig_type == IB_SIGNAL_ALL_WR; 220562306a36Sopenharmony_ci spin_lock_init(&qhp->lock); 220662306a36Sopenharmony_ci mutex_init(&qhp->mutex); 220762306a36Sopenharmony_ci init_waitqueue_head(&qhp->wait); 220862306a36Sopenharmony_ci init_completion(&qhp->qp_rel_comp); 220962306a36Sopenharmony_ci refcount_set(&qhp->qp_refcnt, 1); 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci ret = xa_insert_irq(&rhp->qps, qhp->wq.sq.qid, qhp, GFP_KERNEL); 221262306a36Sopenharmony_ci if (ret) 221362306a36Sopenharmony_ci goto err_destroy_qp; 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci if (udata && ucontext) { 221662306a36Sopenharmony_ci sq_key_mm = kmalloc(sizeof(*sq_key_mm), GFP_KERNEL); 221762306a36Sopenharmony_ci if (!sq_key_mm) { 221862306a36Sopenharmony_ci ret = -ENOMEM; 221962306a36Sopenharmony_ci goto err_remove_handle; 222062306a36Sopenharmony_ci } 222162306a36Sopenharmony_ci if (!attrs->srq) { 222262306a36Sopenharmony_ci rq_key_mm = kmalloc(sizeof(*rq_key_mm), GFP_KERNEL); 222362306a36Sopenharmony_ci if (!rq_key_mm) { 222462306a36Sopenharmony_ci ret = -ENOMEM; 222562306a36Sopenharmony_ci goto err_free_sq_key; 222662306a36Sopenharmony_ci } 222762306a36Sopenharmony_ci } 222862306a36Sopenharmony_ci sq_db_key_mm = kmalloc(sizeof(*sq_db_key_mm), GFP_KERNEL); 222962306a36Sopenharmony_ci if (!sq_db_key_mm) { 223062306a36Sopenharmony_ci ret = -ENOMEM; 223162306a36Sopenharmony_ci goto err_free_rq_key; 223262306a36Sopenharmony_ci } 223362306a36Sopenharmony_ci if (!attrs->srq) { 223462306a36Sopenharmony_ci rq_db_key_mm = 223562306a36Sopenharmony_ci kmalloc(sizeof(*rq_db_key_mm), GFP_KERNEL); 223662306a36Sopenharmony_ci if (!rq_db_key_mm) { 223762306a36Sopenharmony_ci ret = -ENOMEM; 223862306a36Sopenharmony_ci goto err_free_sq_db_key; 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci } 224162306a36Sopenharmony_ci memset(&uresp, 0, sizeof(uresp)); 224262306a36Sopenharmony_ci if (t4_sq_onchip(&qhp->wq.sq)) { 224362306a36Sopenharmony_ci ma_sync_key_mm = kmalloc(sizeof(*ma_sync_key_mm), 224462306a36Sopenharmony_ci GFP_KERNEL); 224562306a36Sopenharmony_ci if (!ma_sync_key_mm) { 224662306a36Sopenharmony_ci ret = -ENOMEM; 224762306a36Sopenharmony_ci goto err_free_rq_db_key; 224862306a36Sopenharmony_ci } 224962306a36Sopenharmony_ci uresp.flags = C4IW_QPF_ONCHIP; 225062306a36Sopenharmony_ci } 225162306a36Sopenharmony_ci if (rhp->rdev.lldi.write_w_imm_support) 225262306a36Sopenharmony_ci uresp.flags |= C4IW_QPF_WRITE_W_IMM; 225362306a36Sopenharmony_ci uresp.qid_mask = rhp->rdev.qpmask; 225462306a36Sopenharmony_ci uresp.sqid = qhp->wq.sq.qid; 225562306a36Sopenharmony_ci uresp.sq_size = qhp->wq.sq.size; 225662306a36Sopenharmony_ci uresp.sq_memsize = qhp->wq.sq.memsize; 225762306a36Sopenharmony_ci if (!attrs->srq) { 225862306a36Sopenharmony_ci uresp.rqid = qhp->wq.rq.qid; 225962306a36Sopenharmony_ci uresp.rq_size = qhp->wq.rq.size; 226062306a36Sopenharmony_ci uresp.rq_memsize = qhp->wq.rq.memsize; 226162306a36Sopenharmony_ci } 226262306a36Sopenharmony_ci spin_lock(&ucontext->mmap_lock); 226362306a36Sopenharmony_ci if (ma_sync_key_mm) { 226462306a36Sopenharmony_ci uresp.ma_sync_key = ucontext->key; 226562306a36Sopenharmony_ci ucontext->key += PAGE_SIZE; 226662306a36Sopenharmony_ci } 226762306a36Sopenharmony_ci uresp.sq_key = ucontext->key; 226862306a36Sopenharmony_ci ucontext->key += PAGE_SIZE; 226962306a36Sopenharmony_ci if (!attrs->srq) { 227062306a36Sopenharmony_ci uresp.rq_key = ucontext->key; 227162306a36Sopenharmony_ci ucontext->key += PAGE_SIZE; 227262306a36Sopenharmony_ci } 227362306a36Sopenharmony_ci uresp.sq_db_gts_key = ucontext->key; 227462306a36Sopenharmony_ci ucontext->key += PAGE_SIZE; 227562306a36Sopenharmony_ci if (!attrs->srq) { 227662306a36Sopenharmony_ci uresp.rq_db_gts_key = ucontext->key; 227762306a36Sopenharmony_ci ucontext->key += PAGE_SIZE; 227862306a36Sopenharmony_ci } 227962306a36Sopenharmony_ci spin_unlock(&ucontext->mmap_lock); 228062306a36Sopenharmony_ci ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); 228162306a36Sopenharmony_ci if (ret) 228262306a36Sopenharmony_ci goto err_free_ma_sync_key; 228362306a36Sopenharmony_ci sq_key_mm->key = uresp.sq_key; 228462306a36Sopenharmony_ci sq_key_mm->addr = qhp->wq.sq.phys_addr; 228562306a36Sopenharmony_ci sq_key_mm->len = PAGE_ALIGN(qhp->wq.sq.memsize); 228662306a36Sopenharmony_ci insert_mmap(ucontext, sq_key_mm); 228762306a36Sopenharmony_ci if (!attrs->srq) { 228862306a36Sopenharmony_ci rq_key_mm->key = uresp.rq_key; 228962306a36Sopenharmony_ci rq_key_mm->addr = virt_to_phys(qhp->wq.rq.queue); 229062306a36Sopenharmony_ci rq_key_mm->len = PAGE_ALIGN(qhp->wq.rq.memsize); 229162306a36Sopenharmony_ci insert_mmap(ucontext, rq_key_mm); 229262306a36Sopenharmony_ci } 229362306a36Sopenharmony_ci sq_db_key_mm->key = uresp.sq_db_gts_key; 229462306a36Sopenharmony_ci sq_db_key_mm->addr = (u64)(unsigned long)qhp->wq.sq.bar2_pa; 229562306a36Sopenharmony_ci sq_db_key_mm->len = PAGE_SIZE; 229662306a36Sopenharmony_ci insert_mmap(ucontext, sq_db_key_mm); 229762306a36Sopenharmony_ci if (!attrs->srq) { 229862306a36Sopenharmony_ci rq_db_key_mm->key = uresp.rq_db_gts_key; 229962306a36Sopenharmony_ci rq_db_key_mm->addr = 230062306a36Sopenharmony_ci (u64)(unsigned long)qhp->wq.rq.bar2_pa; 230162306a36Sopenharmony_ci rq_db_key_mm->len = PAGE_SIZE; 230262306a36Sopenharmony_ci insert_mmap(ucontext, rq_db_key_mm); 230362306a36Sopenharmony_ci } 230462306a36Sopenharmony_ci if (ma_sync_key_mm) { 230562306a36Sopenharmony_ci ma_sync_key_mm->key = uresp.ma_sync_key; 230662306a36Sopenharmony_ci ma_sync_key_mm->addr = 230762306a36Sopenharmony_ci (pci_resource_start(rhp->rdev.lldi.pdev, 0) + 230862306a36Sopenharmony_ci PCIE_MA_SYNC_A) & PAGE_MASK; 230962306a36Sopenharmony_ci ma_sync_key_mm->len = PAGE_SIZE; 231062306a36Sopenharmony_ci insert_mmap(ucontext, ma_sync_key_mm); 231162306a36Sopenharmony_ci } 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci qhp->ucontext = ucontext; 231462306a36Sopenharmony_ci } 231562306a36Sopenharmony_ci if (!attrs->srq) { 231662306a36Sopenharmony_ci qhp->wq.qp_errp = 231762306a36Sopenharmony_ci &qhp->wq.rq.queue[qhp->wq.rq.size].status.qp_err; 231862306a36Sopenharmony_ci } else { 231962306a36Sopenharmony_ci qhp->wq.qp_errp = 232062306a36Sopenharmony_ci &qhp->wq.sq.queue[qhp->wq.sq.size].status.qp_err; 232162306a36Sopenharmony_ci qhp->wq.srqidxp = 232262306a36Sopenharmony_ci &qhp->wq.sq.queue[qhp->wq.sq.size].status.srqidx; 232362306a36Sopenharmony_ci } 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci qhp->ibqp.qp_num = qhp->wq.sq.qid; 232662306a36Sopenharmony_ci if (attrs->srq) 232762306a36Sopenharmony_ci qhp->srq = to_c4iw_srq(attrs->srq); 232862306a36Sopenharmony_ci INIT_LIST_HEAD(&qhp->db_fc_entry); 232962306a36Sopenharmony_ci pr_debug("sq id %u size %u memsize %zu num_entries %u rq id %u size %u memsize %zu num_entries %u\n", 233062306a36Sopenharmony_ci qhp->wq.sq.qid, qhp->wq.sq.size, qhp->wq.sq.memsize, 233162306a36Sopenharmony_ci attrs->cap.max_send_wr, qhp->wq.rq.qid, qhp->wq.rq.size, 233262306a36Sopenharmony_ci qhp->wq.rq.memsize, attrs->cap.max_recv_wr); 233362306a36Sopenharmony_ci return 0; 233462306a36Sopenharmony_cierr_free_ma_sync_key: 233562306a36Sopenharmony_ci kfree(ma_sync_key_mm); 233662306a36Sopenharmony_cierr_free_rq_db_key: 233762306a36Sopenharmony_ci if (!attrs->srq) 233862306a36Sopenharmony_ci kfree(rq_db_key_mm); 233962306a36Sopenharmony_cierr_free_sq_db_key: 234062306a36Sopenharmony_ci kfree(sq_db_key_mm); 234162306a36Sopenharmony_cierr_free_rq_key: 234262306a36Sopenharmony_ci if (!attrs->srq) 234362306a36Sopenharmony_ci kfree(rq_key_mm); 234462306a36Sopenharmony_cierr_free_sq_key: 234562306a36Sopenharmony_ci kfree(sq_key_mm); 234662306a36Sopenharmony_cierr_remove_handle: 234762306a36Sopenharmony_ci xa_erase_irq(&rhp->qps, qhp->wq.sq.qid); 234862306a36Sopenharmony_cierr_destroy_qp: 234962306a36Sopenharmony_ci destroy_qp(&rhp->rdev, &qhp->wq, 235062306a36Sopenharmony_ci ucontext ? &ucontext->uctx : &rhp->rdev.uctx, !attrs->srq); 235162306a36Sopenharmony_cierr_free_wr_wait: 235262306a36Sopenharmony_ci c4iw_put_wr_wait(qhp->wr_waitp); 235362306a36Sopenharmony_ci return ret; 235462306a36Sopenharmony_ci} 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ciint c4iw_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 235762306a36Sopenharmony_ci int attr_mask, struct ib_udata *udata) 235862306a36Sopenharmony_ci{ 235962306a36Sopenharmony_ci struct c4iw_dev *rhp; 236062306a36Sopenharmony_ci struct c4iw_qp *qhp; 236162306a36Sopenharmony_ci enum c4iw_qp_attr_mask mask = 0; 236262306a36Sopenharmony_ci struct c4iw_qp_attributes attrs = {}; 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci pr_debug("ib_qp %p\n", ibqp); 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS) 236762306a36Sopenharmony_ci return -EOPNOTSUPP; 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci /* iwarp does not support the RTR state */ 237062306a36Sopenharmony_ci if ((attr_mask & IB_QP_STATE) && (attr->qp_state == IB_QPS_RTR)) 237162306a36Sopenharmony_ci attr_mask &= ~IB_QP_STATE; 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci /* Make sure we still have something left to do */ 237462306a36Sopenharmony_ci if (!attr_mask) 237562306a36Sopenharmony_ci return 0; 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci qhp = to_c4iw_qp(ibqp); 237862306a36Sopenharmony_ci rhp = qhp->rhp; 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_ci attrs.next_state = c4iw_convert_state(attr->qp_state); 238162306a36Sopenharmony_ci attrs.enable_rdma_read = (attr->qp_access_flags & 238262306a36Sopenharmony_ci IB_ACCESS_REMOTE_READ) ? 1 : 0; 238362306a36Sopenharmony_ci attrs.enable_rdma_write = (attr->qp_access_flags & 238462306a36Sopenharmony_ci IB_ACCESS_REMOTE_WRITE) ? 1 : 0; 238562306a36Sopenharmony_ci attrs.enable_bind = (attr->qp_access_flags & IB_ACCESS_MW_BIND) ? 1 : 0; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci mask |= (attr_mask & IB_QP_STATE) ? C4IW_QP_ATTR_NEXT_STATE : 0; 238962306a36Sopenharmony_ci mask |= (attr_mask & IB_QP_ACCESS_FLAGS) ? 239062306a36Sopenharmony_ci (C4IW_QP_ATTR_ENABLE_RDMA_READ | 239162306a36Sopenharmony_ci C4IW_QP_ATTR_ENABLE_RDMA_WRITE | 239262306a36Sopenharmony_ci C4IW_QP_ATTR_ENABLE_RDMA_BIND) : 0; 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci /* 239562306a36Sopenharmony_ci * Use SQ_PSN and RQ_PSN to pass in IDX_INC values for 239662306a36Sopenharmony_ci * ringing the queue db when we're in DB_FULL mode. 239762306a36Sopenharmony_ci * Only allow this on T4 devices. 239862306a36Sopenharmony_ci */ 239962306a36Sopenharmony_ci attrs.sq_db_inc = attr->sq_psn; 240062306a36Sopenharmony_ci attrs.rq_db_inc = attr->rq_psn; 240162306a36Sopenharmony_ci mask |= (attr_mask & IB_QP_SQ_PSN) ? C4IW_QP_ATTR_SQ_DB : 0; 240262306a36Sopenharmony_ci mask |= (attr_mask & IB_QP_RQ_PSN) ? C4IW_QP_ATTR_RQ_DB : 0; 240362306a36Sopenharmony_ci if (!is_t4(to_c4iw_qp(ibqp)->rhp->rdev.lldi.adapter_type) && 240462306a36Sopenharmony_ci (mask & (C4IW_QP_ATTR_SQ_DB|C4IW_QP_ATTR_RQ_DB))) 240562306a36Sopenharmony_ci return -EINVAL; 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci return c4iw_modify_qp(rhp, qhp, mask, &attrs, 0); 240862306a36Sopenharmony_ci} 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_cistruct ib_qp *c4iw_get_qp(struct ib_device *dev, int qpn) 241162306a36Sopenharmony_ci{ 241262306a36Sopenharmony_ci pr_debug("ib_dev %p qpn 0x%x\n", dev, qpn); 241362306a36Sopenharmony_ci return (struct ib_qp *)get_qhp(to_c4iw_dev(dev), qpn); 241462306a36Sopenharmony_ci} 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_civoid c4iw_dispatch_srq_limit_reached_event(struct c4iw_srq *srq) 241762306a36Sopenharmony_ci{ 241862306a36Sopenharmony_ci struct ib_event event = {}; 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci event.device = &srq->rhp->ibdev; 242162306a36Sopenharmony_ci event.element.srq = &srq->ibsrq; 242262306a36Sopenharmony_ci event.event = IB_EVENT_SRQ_LIMIT_REACHED; 242362306a36Sopenharmony_ci ib_dispatch_event(&event); 242462306a36Sopenharmony_ci} 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ciint c4iw_modify_srq(struct ib_srq *ib_srq, struct ib_srq_attr *attr, 242762306a36Sopenharmony_ci enum ib_srq_attr_mask srq_attr_mask, 242862306a36Sopenharmony_ci struct ib_udata *udata) 242962306a36Sopenharmony_ci{ 243062306a36Sopenharmony_ci struct c4iw_srq *srq = to_c4iw_srq(ib_srq); 243162306a36Sopenharmony_ci int ret = 0; 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_ci /* 243462306a36Sopenharmony_ci * XXX 0 mask == a SW interrupt for srq_limit reached... 243562306a36Sopenharmony_ci */ 243662306a36Sopenharmony_ci if (udata && !srq_attr_mask) { 243762306a36Sopenharmony_ci c4iw_dispatch_srq_limit_reached_event(srq); 243862306a36Sopenharmony_ci goto out; 243962306a36Sopenharmony_ci } 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci /* no support for this yet */ 244262306a36Sopenharmony_ci if (srq_attr_mask & IB_SRQ_MAX_WR) { 244362306a36Sopenharmony_ci ret = -EINVAL; 244462306a36Sopenharmony_ci goto out; 244562306a36Sopenharmony_ci } 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci if (!udata && (srq_attr_mask & IB_SRQ_LIMIT)) { 244862306a36Sopenharmony_ci srq->armed = true; 244962306a36Sopenharmony_ci srq->srq_limit = attr->srq_limit; 245062306a36Sopenharmony_ci } 245162306a36Sopenharmony_ciout: 245262306a36Sopenharmony_ci return ret; 245362306a36Sopenharmony_ci} 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ciint c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 245662306a36Sopenharmony_ci int attr_mask, struct ib_qp_init_attr *init_attr) 245762306a36Sopenharmony_ci{ 245862306a36Sopenharmony_ci struct c4iw_qp *qhp = to_c4iw_qp(ibqp); 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci memset(attr, 0, sizeof(*attr)); 246162306a36Sopenharmony_ci memset(init_attr, 0, sizeof(*init_attr)); 246262306a36Sopenharmony_ci attr->qp_state = to_ib_qp_state(qhp->attr.state); 246362306a36Sopenharmony_ci attr->cur_qp_state = to_ib_qp_state(qhp->attr.state); 246462306a36Sopenharmony_ci init_attr->cap.max_send_wr = qhp->attr.sq_num_entries; 246562306a36Sopenharmony_ci init_attr->cap.max_recv_wr = qhp->attr.rq_num_entries; 246662306a36Sopenharmony_ci init_attr->cap.max_send_sge = qhp->attr.sq_max_sges; 246762306a36Sopenharmony_ci init_attr->cap.max_recv_sge = qhp->attr.rq_max_sges; 246862306a36Sopenharmony_ci init_attr->cap.max_inline_data = T4_MAX_SEND_INLINE; 246962306a36Sopenharmony_ci init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; 247062306a36Sopenharmony_ci return 0; 247162306a36Sopenharmony_ci} 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_cistatic void free_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx, 247462306a36Sopenharmony_ci struct c4iw_wr_wait *wr_waitp) 247562306a36Sopenharmony_ci{ 247662306a36Sopenharmony_ci struct c4iw_rdev *rdev = &srq->rhp->rdev; 247762306a36Sopenharmony_ci struct sk_buff *skb = srq->destroy_skb; 247862306a36Sopenharmony_ci struct t4_srq *wq = &srq->wq; 247962306a36Sopenharmony_ci struct fw_ri_res_wr *res_wr; 248062306a36Sopenharmony_ci struct fw_ri_res *res; 248162306a36Sopenharmony_ci int wr_len; 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci wr_len = sizeof(*res_wr) + sizeof(*res); 248462306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len); 248762306a36Sopenharmony_ci memset(res_wr, 0, wr_len); 248862306a36Sopenharmony_ci res_wr->op_nres = cpu_to_be32(FW_WR_OP_V(FW_RI_RES_WR) | 248962306a36Sopenharmony_ci FW_RI_RES_WR_NRES_V(1) | 249062306a36Sopenharmony_ci FW_WR_COMPL_F); 249162306a36Sopenharmony_ci res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); 249262306a36Sopenharmony_ci res_wr->cookie = (uintptr_t)wr_waitp; 249362306a36Sopenharmony_ci res = res_wr->res; 249462306a36Sopenharmony_ci res->u.srq.restype = FW_RI_RES_TYPE_SRQ; 249562306a36Sopenharmony_ci res->u.srq.op = FW_RI_RES_OP_RESET; 249662306a36Sopenharmony_ci res->u.srq.srqid = cpu_to_be32(srq->idx); 249762306a36Sopenharmony_ci res->u.srq.eqid = cpu_to_be32(wq->qid); 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci c4iw_init_wr_wait(wr_waitp); 250062306a36Sopenharmony_ci c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__); 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci dma_free_coherent(&rdev->lldi.pdev->dev, 250362306a36Sopenharmony_ci wq->memsize, wq->queue, 250462306a36Sopenharmony_ci dma_unmap_addr(wq, mapping)); 250562306a36Sopenharmony_ci c4iw_rqtpool_free(rdev, wq->rqt_hwaddr, wq->rqt_size); 250662306a36Sopenharmony_ci kfree(wq->sw_rq); 250762306a36Sopenharmony_ci c4iw_put_qpid(rdev, wq->qid, uctx); 250862306a36Sopenharmony_ci} 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_cistatic int alloc_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx, 251162306a36Sopenharmony_ci struct c4iw_wr_wait *wr_waitp) 251262306a36Sopenharmony_ci{ 251362306a36Sopenharmony_ci struct c4iw_rdev *rdev = &srq->rhp->rdev; 251462306a36Sopenharmony_ci int user = (uctx != &rdev->uctx); 251562306a36Sopenharmony_ci struct t4_srq *wq = &srq->wq; 251662306a36Sopenharmony_ci struct fw_ri_res_wr *res_wr; 251762306a36Sopenharmony_ci struct fw_ri_res *res; 251862306a36Sopenharmony_ci struct sk_buff *skb; 251962306a36Sopenharmony_ci int wr_len; 252062306a36Sopenharmony_ci int eqsize; 252162306a36Sopenharmony_ci int ret = -ENOMEM; 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci wq->qid = c4iw_get_qpid(rdev, uctx); 252462306a36Sopenharmony_ci if (!wq->qid) 252562306a36Sopenharmony_ci goto err; 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci if (!user) { 252862306a36Sopenharmony_ci wq->sw_rq = kcalloc(wq->size, sizeof(*wq->sw_rq), 252962306a36Sopenharmony_ci GFP_KERNEL); 253062306a36Sopenharmony_ci if (!wq->sw_rq) 253162306a36Sopenharmony_ci goto err_put_qpid; 253262306a36Sopenharmony_ci wq->pending_wrs = kcalloc(srq->wq.size, 253362306a36Sopenharmony_ci sizeof(*srq->wq.pending_wrs), 253462306a36Sopenharmony_ci GFP_KERNEL); 253562306a36Sopenharmony_ci if (!wq->pending_wrs) 253662306a36Sopenharmony_ci goto err_free_sw_rq; 253762306a36Sopenharmony_ci } 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci wq->rqt_size = wq->size; 254062306a36Sopenharmony_ci wq->rqt_hwaddr = c4iw_rqtpool_alloc(rdev, wq->rqt_size); 254162306a36Sopenharmony_ci if (!wq->rqt_hwaddr) 254262306a36Sopenharmony_ci goto err_free_pending_wrs; 254362306a36Sopenharmony_ci wq->rqt_abs_idx = (wq->rqt_hwaddr - rdev->lldi.vr->rq.start) >> 254462306a36Sopenharmony_ci T4_RQT_ENTRY_SHIFT; 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci wq->queue = dma_alloc_coherent(&rdev->lldi.pdev->dev, wq->memsize, 254762306a36Sopenharmony_ci &wq->dma_addr, GFP_KERNEL); 254862306a36Sopenharmony_ci if (!wq->queue) 254962306a36Sopenharmony_ci goto err_free_rqtpool; 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci dma_unmap_addr_set(wq, mapping, wq->dma_addr); 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci wq->bar2_va = c4iw_bar2_addrs(rdev, wq->qid, CXGB4_BAR2_QTYPE_EGRESS, 255462306a36Sopenharmony_ci &wq->bar2_qid, 255562306a36Sopenharmony_ci user ? &wq->bar2_pa : NULL); 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci /* 255862306a36Sopenharmony_ci * User mode must have bar2 access. 255962306a36Sopenharmony_ci */ 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci if (user && !wq->bar2_va) { 256262306a36Sopenharmony_ci pr_warn(MOD "%s: srqid %u not in BAR2 range.\n", 256362306a36Sopenharmony_ci pci_name(rdev->lldi.pdev), wq->qid); 256462306a36Sopenharmony_ci ret = -EINVAL; 256562306a36Sopenharmony_ci goto err_free_queue; 256662306a36Sopenharmony_ci } 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci /* build fw_ri_res_wr */ 256962306a36Sopenharmony_ci wr_len = sizeof(*res_wr) + sizeof(*res); 257062306a36Sopenharmony_ci 257162306a36Sopenharmony_ci skb = alloc_skb(wr_len, GFP_KERNEL); 257262306a36Sopenharmony_ci if (!skb) 257362306a36Sopenharmony_ci goto err_free_queue; 257462306a36Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len); 257762306a36Sopenharmony_ci memset(res_wr, 0, wr_len); 257862306a36Sopenharmony_ci res_wr->op_nres = cpu_to_be32(FW_WR_OP_V(FW_RI_RES_WR) | 257962306a36Sopenharmony_ci FW_RI_RES_WR_NRES_V(1) | 258062306a36Sopenharmony_ci FW_WR_COMPL_F); 258162306a36Sopenharmony_ci res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); 258262306a36Sopenharmony_ci res_wr->cookie = (uintptr_t)wr_waitp; 258362306a36Sopenharmony_ci res = res_wr->res; 258462306a36Sopenharmony_ci res->u.srq.restype = FW_RI_RES_TYPE_SRQ; 258562306a36Sopenharmony_ci res->u.srq.op = FW_RI_RES_OP_WRITE; 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci /* 258862306a36Sopenharmony_ci * eqsize is the number of 64B entries plus the status page size. 258962306a36Sopenharmony_ci */ 259062306a36Sopenharmony_ci eqsize = wq->size * T4_RQ_NUM_SLOTS + 259162306a36Sopenharmony_ci rdev->hw_queue.t4_eq_status_entries; 259262306a36Sopenharmony_ci res->u.srq.eqid = cpu_to_be32(wq->qid); 259362306a36Sopenharmony_ci res->u.srq.fetchszm_to_iqid = 259462306a36Sopenharmony_ci /* no host cidx updates */ 259562306a36Sopenharmony_ci cpu_to_be32(FW_RI_RES_WR_HOSTFCMODE_V(0) | 259662306a36Sopenharmony_ci FW_RI_RES_WR_CPRIO_V(0) | /* don't keep in chip cache */ 259762306a36Sopenharmony_ci FW_RI_RES_WR_PCIECHN_V(0) | /* set by uP at ri_init time */ 259862306a36Sopenharmony_ci FW_RI_RES_WR_FETCHRO_V(0)); /* relaxed_ordering */ 259962306a36Sopenharmony_ci res->u.srq.dcaen_to_eqsize = 260062306a36Sopenharmony_ci cpu_to_be32(FW_RI_RES_WR_DCAEN_V(0) | 260162306a36Sopenharmony_ci FW_RI_RES_WR_DCACPU_V(0) | 260262306a36Sopenharmony_ci FW_RI_RES_WR_FBMIN_V(2) | 260362306a36Sopenharmony_ci FW_RI_RES_WR_FBMAX_V(3) | 260462306a36Sopenharmony_ci FW_RI_RES_WR_CIDXFTHRESHO_V(0) | 260562306a36Sopenharmony_ci FW_RI_RES_WR_CIDXFTHRESH_V(0) | 260662306a36Sopenharmony_ci FW_RI_RES_WR_EQSIZE_V(eqsize)); 260762306a36Sopenharmony_ci res->u.srq.eqaddr = cpu_to_be64(wq->dma_addr); 260862306a36Sopenharmony_ci res->u.srq.srqid = cpu_to_be32(srq->idx); 260962306a36Sopenharmony_ci res->u.srq.pdid = cpu_to_be32(srq->pdid); 261062306a36Sopenharmony_ci res->u.srq.hwsrqsize = cpu_to_be32(wq->rqt_size); 261162306a36Sopenharmony_ci res->u.srq.hwsrqaddr = cpu_to_be32(wq->rqt_hwaddr - 261262306a36Sopenharmony_ci rdev->lldi.vr->rq.start); 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ci c4iw_init_wr_wait(wr_waitp); 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, wq->qid, __func__); 261762306a36Sopenharmony_ci if (ret) 261862306a36Sopenharmony_ci goto err_free_queue; 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_ci pr_debug("%s srq %u eqid %u pdid %u queue va %p pa 0x%llx\n" 262162306a36Sopenharmony_ci " bar2_addr %p rqt addr 0x%x size %d\n", 262262306a36Sopenharmony_ci __func__, srq->idx, wq->qid, srq->pdid, wq->queue, 262362306a36Sopenharmony_ci (u64)virt_to_phys(wq->queue), wq->bar2_va, 262462306a36Sopenharmony_ci wq->rqt_hwaddr, wq->rqt_size); 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci return 0; 262762306a36Sopenharmony_cierr_free_queue: 262862306a36Sopenharmony_ci dma_free_coherent(&rdev->lldi.pdev->dev, 262962306a36Sopenharmony_ci wq->memsize, wq->queue, 263062306a36Sopenharmony_ci dma_unmap_addr(wq, mapping)); 263162306a36Sopenharmony_cierr_free_rqtpool: 263262306a36Sopenharmony_ci c4iw_rqtpool_free(rdev, wq->rqt_hwaddr, wq->rqt_size); 263362306a36Sopenharmony_cierr_free_pending_wrs: 263462306a36Sopenharmony_ci if (!user) 263562306a36Sopenharmony_ci kfree(wq->pending_wrs); 263662306a36Sopenharmony_cierr_free_sw_rq: 263762306a36Sopenharmony_ci if (!user) 263862306a36Sopenharmony_ci kfree(wq->sw_rq); 263962306a36Sopenharmony_cierr_put_qpid: 264062306a36Sopenharmony_ci c4iw_put_qpid(rdev, wq->qid, uctx); 264162306a36Sopenharmony_cierr: 264262306a36Sopenharmony_ci return ret; 264362306a36Sopenharmony_ci} 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_civoid c4iw_copy_wr_to_srq(struct t4_srq *srq, union t4_recv_wr *wqe, u8 len16) 264662306a36Sopenharmony_ci{ 264762306a36Sopenharmony_ci u64 *src, *dst; 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci src = (u64 *)wqe; 265062306a36Sopenharmony_ci dst = (u64 *)((u8 *)srq->queue + srq->wq_pidx * T4_EQ_ENTRY_SIZE); 265162306a36Sopenharmony_ci while (len16) { 265262306a36Sopenharmony_ci *dst++ = *src++; 265362306a36Sopenharmony_ci if (dst >= (u64 *)&srq->queue[srq->size]) 265462306a36Sopenharmony_ci dst = (u64 *)srq->queue; 265562306a36Sopenharmony_ci *dst++ = *src++; 265662306a36Sopenharmony_ci if (dst >= (u64 *)&srq->queue[srq->size]) 265762306a36Sopenharmony_ci dst = (u64 *)srq->queue; 265862306a36Sopenharmony_ci len16--; 265962306a36Sopenharmony_ci } 266062306a36Sopenharmony_ci} 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ciint c4iw_create_srq(struct ib_srq *ib_srq, struct ib_srq_init_attr *attrs, 266362306a36Sopenharmony_ci struct ib_udata *udata) 266462306a36Sopenharmony_ci{ 266562306a36Sopenharmony_ci struct ib_pd *pd = ib_srq->pd; 266662306a36Sopenharmony_ci struct c4iw_dev *rhp; 266762306a36Sopenharmony_ci struct c4iw_srq *srq = to_c4iw_srq(ib_srq); 266862306a36Sopenharmony_ci struct c4iw_pd *php; 266962306a36Sopenharmony_ci struct c4iw_create_srq_resp uresp; 267062306a36Sopenharmony_ci struct c4iw_ucontext *ucontext; 267162306a36Sopenharmony_ci struct c4iw_mm_entry *srq_key_mm, *srq_db_key_mm; 267262306a36Sopenharmony_ci int rqsize; 267362306a36Sopenharmony_ci int ret; 267462306a36Sopenharmony_ci int wr_len; 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci if (attrs->srq_type != IB_SRQT_BASIC) 267762306a36Sopenharmony_ci return -EOPNOTSUPP; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci pr_debug("%s ib_pd %p\n", __func__, pd); 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci php = to_c4iw_pd(pd); 268262306a36Sopenharmony_ci rhp = php->rhp; 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci if (!rhp->rdev.lldi.vr->srq.size) 268562306a36Sopenharmony_ci return -EINVAL; 268662306a36Sopenharmony_ci if (attrs->attr.max_wr > rhp->rdev.hw_queue.t4_max_rq_size) 268762306a36Sopenharmony_ci return -E2BIG; 268862306a36Sopenharmony_ci if (attrs->attr.max_sge > T4_MAX_RECV_SGE) 268962306a36Sopenharmony_ci return -E2BIG; 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci /* 269262306a36Sopenharmony_ci * SRQ RQT and RQ must be a power of 2 and at least 16 deep. 269362306a36Sopenharmony_ci */ 269462306a36Sopenharmony_ci rqsize = attrs->attr.max_wr + 1; 269562306a36Sopenharmony_ci rqsize = roundup_pow_of_two(max_t(u16, rqsize, 16)); 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci ucontext = rdma_udata_to_drv_context(udata, struct c4iw_ucontext, 269862306a36Sopenharmony_ci ibucontext); 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci srq->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL); 270162306a36Sopenharmony_ci if (!srq->wr_waitp) 270262306a36Sopenharmony_ci return -ENOMEM; 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_ci srq->idx = c4iw_alloc_srq_idx(&rhp->rdev); 270562306a36Sopenharmony_ci if (srq->idx < 0) { 270662306a36Sopenharmony_ci ret = -ENOMEM; 270762306a36Sopenharmony_ci goto err_free_wr_wait; 270862306a36Sopenharmony_ci } 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci wr_len = sizeof(struct fw_ri_res_wr) + sizeof(struct fw_ri_res); 271162306a36Sopenharmony_ci srq->destroy_skb = alloc_skb(wr_len, GFP_KERNEL); 271262306a36Sopenharmony_ci if (!srq->destroy_skb) { 271362306a36Sopenharmony_ci ret = -ENOMEM; 271462306a36Sopenharmony_ci goto err_free_srq_idx; 271562306a36Sopenharmony_ci } 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_ci srq->rhp = rhp; 271862306a36Sopenharmony_ci srq->pdid = php->pdid; 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ci srq->wq.size = rqsize; 272162306a36Sopenharmony_ci srq->wq.memsize = 272262306a36Sopenharmony_ci (rqsize + rhp->rdev.hw_queue.t4_eq_status_entries) * 272362306a36Sopenharmony_ci sizeof(*srq->wq.queue); 272462306a36Sopenharmony_ci if (ucontext) 272562306a36Sopenharmony_ci srq->wq.memsize = roundup(srq->wq.memsize, PAGE_SIZE); 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci ret = alloc_srq_queue(srq, ucontext ? &ucontext->uctx : 272862306a36Sopenharmony_ci &rhp->rdev.uctx, srq->wr_waitp); 272962306a36Sopenharmony_ci if (ret) 273062306a36Sopenharmony_ci goto err_free_skb; 273162306a36Sopenharmony_ci attrs->attr.max_wr = rqsize - 1; 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_ci if (CHELSIO_CHIP_VERSION(rhp->rdev.lldi.adapter_type) > CHELSIO_T6) 273462306a36Sopenharmony_ci srq->flags = T4_SRQ_LIMIT_SUPPORT; 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci if (udata) { 273762306a36Sopenharmony_ci srq_key_mm = kmalloc(sizeof(*srq_key_mm), GFP_KERNEL); 273862306a36Sopenharmony_ci if (!srq_key_mm) { 273962306a36Sopenharmony_ci ret = -ENOMEM; 274062306a36Sopenharmony_ci goto err_free_queue; 274162306a36Sopenharmony_ci } 274262306a36Sopenharmony_ci srq_db_key_mm = kmalloc(sizeof(*srq_db_key_mm), GFP_KERNEL); 274362306a36Sopenharmony_ci if (!srq_db_key_mm) { 274462306a36Sopenharmony_ci ret = -ENOMEM; 274562306a36Sopenharmony_ci goto err_free_srq_key_mm; 274662306a36Sopenharmony_ci } 274762306a36Sopenharmony_ci memset(&uresp, 0, sizeof(uresp)); 274862306a36Sopenharmony_ci uresp.flags = srq->flags; 274962306a36Sopenharmony_ci uresp.qid_mask = rhp->rdev.qpmask; 275062306a36Sopenharmony_ci uresp.srqid = srq->wq.qid; 275162306a36Sopenharmony_ci uresp.srq_size = srq->wq.size; 275262306a36Sopenharmony_ci uresp.srq_memsize = srq->wq.memsize; 275362306a36Sopenharmony_ci uresp.rqt_abs_idx = srq->wq.rqt_abs_idx; 275462306a36Sopenharmony_ci spin_lock(&ucontext->mmap_lock); 275562306a36Sopenharmony_ci uresp.srq_key = ucontext->key; 275662306a36Sopenharmony_ci ucontext->key += PAGE_SIZE; 275762306a36Sopenharmony_ci uresp.srq_db_gts_key = ucontext->key; 275862306a36Sopenharmony_ci ucontext->key += PAGE_SIZE; 275962306a36Sopenharmony_ci spin_unlock(&ucontext->mmap_lock); 276062306a36Sopenharmony_ci ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); 276162306a36Sopenharmony_ci if (ret) 276262306a36Sopenharmony_ci goto err_free_srq_db_key_mm; 276362306a36Sopenharmony_ci srq_key_mm->key = uresp.srq_key; 276462306a36Sopenharmony_ci srq_key_mm->addr = virt_to_phys(srq->wq.queue); 276562306a36Sopenharmony_ci srq_key_mm->len = PAGE_ALIGN(srq->wq.memsize); 276662306a36Sopenharmony_ci insert_mmap(ucontext, srq_key_mm); 276762306a36Sopenharmony_ci srq_db_key_mm->key = uresp.srq_db_gts_key; 276862306a36Sopenharmony_ci srq_db_key_mm->addr = (u64)(unsigned long)srq->wq.bar2_pa; 276962306a36Sopenharmony_ci srq_db_key_mm->len = PAGE_SIZE; 277062306a36Sopenharmony_ci insert_mmap(ucontext, srq_db_key_mm); 277162306a36Sopenharmony_ci } 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ci pr_debug("%s srq qid %u idx %u size %u memsize %lu num_entries %u\n", 277462306a36Sopenharmony_ci __func__, srq->wq.qid, srq->idx, srq->wq.size, 277562306a36Sopenharmony_ci (unsigned long)srq->wq.memsize, attrs->attr.max_wr); 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci spin_lock_init(&srq->lock); 277862306a36Sopenharmony_ci return 0; 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_cierr_free_srq_db_key_mm: 278162306a36Sopenharmony_ci kfree(srq_db_key_mm); 278262306a36Sopenharmony_cierr_free_srq_key_mm: 278362306a36Sopenharmony_ci kfree(srq_key_mm); 278462306a36Sopenharmony_cierr_free_queue: 278562306a36Sopenharmony_ci free_srq_queue(srq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx, 278662306a36Sopenharmony_ci srq->wr_waitp); 278762306a36Sopenharmony_cierr_free_skb: 278862306a36Sopenharmony_ci kfree_skb(srq->destroy_skb); 278962306a36Sopenharmony_cierr_free_srq_idx: 279062306a36Sopenharmony_ci c4iw_free_srq_idx(&rhp->rdev, srq->idx); 279162306a36Sopenharmony_cierr_free_wr_wait: 279262306a36Sopenharmony_ci c4iw_put_wr_wait(srq->wr_waitp); 279362306a36Sopenharmony_ci return ret; 279462306a36Sopenharmony_ci} 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ciint c4iw_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata) 279762306a36Sopenharmony_ci{ 279862306a36Sopenharmony_ci struct c4iw_dev *rhp; 279962306a36Sopenharmony_ci struct c4iw_srq *srq; 280062306a36Sopenharmony_ci struct c4iw_ucontext *ucontext; 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci srq = to_c4iw_srq(ibsrq); 280362306a36Sopenharmony_ci rhp = srq->rhp; 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci pr_debug("%s id %d\n", __func__, srq->wq.qid); 280662306a36Sopenharmony_ci ucontext = rdma_udata_to_drv_context(udata, struct c4iw_ucontext, 280762306a36Sopenharmony_ci ibucontext); 280862306a36Sopenharmony_ci free_srq_queue(srq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx, 280962306a36Sopenharmony_ci srq->wr_waitp); 281062306a36Sopenharmony_ci c4iw_free_srq_idx(&rhp->rdev, srq->idx); 281162306a36Sopenharmony_ci c4iw_put_wr_wait(srq->wr_waitp); 281262306a36Sopenharmony_ci return 0; 281362306a36Sopenharmony_ci} 2814