18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "iw_cxgb4.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic void destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, 388c2ecf20Sopenharmony_ci struct c4iw_dev_ucontext *uctx, struct sk_buff *skb, 398c2ecf20Sopenharmony_ci struct c4iw_wr_wait *wr_waitp) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct fw_ri_res_wr *res_wr; 428c2ecf20Sopenharmony_ci struct fw_ri_res *res; 438c2ecf20Sopenharmony_ci int wr_len; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci wr_len = sizeof(*res_wr) + sizeof(*res); 468c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci res_wr = __skb_put_zero(skb, wr_len); 498c2ecf20Sopenharmony_ci res_wr->op_nres = cpu_to_be32( 508c2ecf20Sopenharmony_ci FW_WR_OP_V(FW_RI_RES_WR) | 518c2ecf20Sopenharmony_ci FW_RI_RES_WR_NRES_V(1) | 528c2ecf20Sopenharmony_ci FW_WR_COMPL_F); 538c2ecf20Sopenharmony_ci res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); 548c2ecf20Sopenharmony_ci res_wr->cookie = (uintptr_t)wr_waitp; 558c2ecf20Sopenharmony_ci res = res_wr->res; 568c2ecf20Sopenharmony_ci res->u.cq.restype = FW_RI_RES_TYPE_CQ; 578c2ecf20Sopenharmony_ci res->u.cq.op = FW_RI_RES_OP_RESET; 588c2ecf20Sopenharmony_ci res->u.cq.iqid = cpu_to_be32(cq->cqid); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci c4iw_init_wr_wait(wr_waitp); 618c2ecf20Sopenharmony_ci c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci kfree(cq->sw_queue); 648c2ecf20Sopenharmony_ci dma_free_coherent(&(rdev->lldi.pdev->dev), 658c2ecf20Sopenharmony_ci cq->memsize, cq->queue, 668c2ecf20Sopenharmony_ci dma_unmap_addr(cq, mapping)); 678c2ecf20Sopenharmony_ci c4iw_put_cqid(rdev, cq->cqid, uctx); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq, 718c2ecf20Sopenharmony_ci struct c4iw_dev_ucontext *uctx, 728c2ecf20Sopenharmony_ci struct c4iw_wr_wait *wr_waitp) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct fw_ri_res_wr *res_wr; 758c2ecf20Sopenharmony_ci struct fw_ri_res *res; 768c2ecf20Sopenharmony_ci int wr_len; 778c2ecf20Sopenharmony_ci int user = (uctx != &rdev->uctx); 788c2ecf20Sopenharmony_ci int ret; 798c2ecf20Sopenharmony_ci struct sk_buff *skb; 808c2ecf20Sopenharmony_ci struct c4iw_ucontext *ucontext = NULL; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (user) 838c2ecf20Sopenharmony_ci ucontext = container_of(uctx, struct c4iw_ucontext, uctx); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci cq->cqid = c4iw_get_cqid(rdev, uctx); 868c2ecf20Sopenharmony_ci if (!cq->cqid) { 878c2ecf20Sopenharmony_ci ret = -ENOMEM; 888c2ecf20Sopenharmony_ci goto err1; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (!user) { 928c2ecf20Sopenharmony_ci cq->sw_queue = kzalloc(cq->memsize, GFP_KERNEL); 938c2ecf20Sopenharmony_ci if (!cq->sw_queue) { 948c2ecf20Sopenharmony_ci ret = -ENOMEM; 958c2ecf20Sopenharmony_ci goto err2; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci cq->queue = dma_alloc_coherent(&rdev->lldi.pdev->dev, cq->memsize, 998c2ecf20Sopenharmony_ci &cq->dma_addr, GFP_KERNEL); 1008c2ecf20Sopenharmony_ci if (!cq->queue) { 1018c2ecf20Sopenharmony_ci ret = -ENOMEM; 1028c2ecf20Sopenharmony_ci goto err3; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci dma_unmap_addr_set(cq, mapping, cq->dma_addr); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (user && ucontext->is_32b_cqe) { 1078c2ecf20Sopenharmony_ci cq->qp_errp = &((struct t4_status_page *) 1088c2ecf20Sopenharmony_ci ((u8 *)cq->queue + (cq->size - 1) * 1098c2ecf20Sopenharmony_ci (sizeof(*cq->queue) / 2)))->qp_err; 1108c2ecf20Sopenharmony_ci } else { 1118c2ecf20Sopenharmony_ci cq->qp_errp = &((struct t4_status_page *) 1128c2ecf20Sopenharmony_ci ((u8 *)cq->queue + (cq->size - 1) * 1138c2ecf20Sopenharmony_ci sizeof(*cq->queue)))->qp_err; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* build fw_ri_res_wr */ 1178c2ecf20Sopenharmony_ci wr_len = sizeof(*res_wr) + sizeof(*res); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci skb = alloc_skb(wr_len, GFP_KERNEL); 1208c2ecf20Sopenharmony_ci if (!skb) { 1218c2ecf20Sopenharmony_ci ret = -ENOMEM; 1228c2ecf20Sopenharmony_ci goto err4; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci res_wr = __skb_put_zero(skb, wr_len); 1278c2ecf20Sopenharmony_ci res_wr->op_nres = cpu_to_be32( 1288c2ecf20Sopenharmony_ci FW_WR_OP_V(FW_RI_RES_WR) | 1298c2ecf20Sopenharmony_ci FW_RI_RES_WR_NRES_V(1) | 1308c2ecf20Sopenharmony_ci FW_WR_COMPL_F); 1318c2ecf20Sopenharmony_ci res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16)); 1328c2ecf20Sopenharmony_ci res_wr->cookie = (uintptr_t)wr_waitp; 1338c2ecf20Sopenharmony_ci res = res_wr->res; 1348c2ecf20Sopenharmony_ci res->u.cq.restype = FW_RI_RES_TYPE_CQ; 1358c2ecf20Sopenharmony_ci res->u.cq.op = FW_RI_RES_OP_WRITE; 1368c2ecf20Sopenharmony_ci res->u.cq.iqid = cpu_to_be32(cq->cqid); 1378c2ecf20Sopenharmony_ci res->u.cq.iqandst_to_iqandstindex = cpu_to_be32( 1388c2ecf20Sopenharmony_ci FW_RI_RES_WR_IQANUS_V(0) | 1398c2ecf20Sopenharmony_ci FW_RI_RES_WR_IQANUD_V(1) | 1408c2ecf20Sopenharmony_ci FW_RI_RES_WR_IQANDST_F | 1418c2ecf20Sopenharmony_ci FW_RI_RES_WR_IQANDSTINDEX_V( 1428c2ecf20Sopenharmony_ci rdev->lldi.ciq_ids[cq->vector])); 1438c2ecf20Sopenharmony_ci res->u.cq.iqdroprss_to_iqesize = cpu_to_be16( 1448c2ecf20Sopenharmony_ci FW_RI_RES_WR_IQDROPRSS_F | 1458c2ecf20Sopenharmony_ci FW_RI_RES_WR_IQPCIECH_V(2) | 1468c2ecf20Sopenharmony_ci FW_RI_RES_WR_IQINTCNTTHRESH_V(0) | 1478c2ecf20Sopenharmony_ci FW_RI_RES_WR_IQO_F | 1488c2ecf20Sopenharmony_ci ((user && ucontext->is_32b_cqe) ? 1498c2ecf20Sopenharmony_ci FW_RI_RES_WR_IQESIZE_V(1) : 1508c2ecf20Sopenharmony_ci FW_RI_RES_WR_IQESIZE_V(2))); 1518c2ecf20Sopenharmony_ci res->u.cq.iqsize = cpu_to_be16(cq->size); 1528c2ecf20Sopenharmony_ci res->u.cq.iqaddr = cpu_to_be64(cq->dma_addr); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci c4iw_init_wr_wait(wr_waitp); 1558c2ecf20Sopenharmony_ci ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__); 1568c2ecf20Sopenharmony_ci if (ret) 1578c2ecf20Sopenharmony_ci goto err4; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci cq->gen = 1; 1608c2ecf20Sopenharmony_ci cq->gts = rdev->lldi.gts_reg; 1618c2ecf20Sopenharmony_ci cq->rdev = rdev; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci cq->bar2_va = c4iw_bar2_addrs(rdev, cq->cqid, CXGB4_BAR2_QTYPE_INGRESS, 1648c2ecf20Sopenharmony_ci &cq->bar2_qid, 1658c2ecf20Sopenharmony_ci user ? &cq->bar2_pa : NULL); 1668c2ecf20Sopenharmony_ci if (user && !cq->bar2_pa) { 1678c2ecf20Sopenharmony_ci pr_warn("%s: cqid %u not in BAR2 range\n", 1688c2ecf20Sopenharmony_ci pci_name(rdev->lldi.pdev), cq->cqid); 1698c2ecf20Sopenharmony_ci ret = -EINVAL; 1708c2ecf20Sopenharmony_ci goto err4; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_cierr4: 1748c2ecf20Sopenharmony_ci dma_free_coherent(&rdev->lldi.pdev->dev, cq->memsize, cq->queue, 1758c2ecf20Sopenharmony_ci dma_unmap_addr(cq, mapping)); 1768c2ecf20Sopenharmony_cierr3: 1778c2ecf20Sopenharmony_ci kfree(cq->sw_queue); 1788c2ecf20Sopenharmony_cierr2: 1798c2ecf20Sopenharmony_ci c4iw_put_cqid(rdev, cq->cqid, uctx); 1808c2ecf20Sopenharmony_cierr1: 1818c2ecf20Sopenharmony_ci return ret; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic void insert_recv_cqe(struct t4_wq *wq, struct t4_cq *cq, u32 srqidx) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct t4_cqe cqe; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci pr_debug("wq %p cq %p sw_cidx %u sw_pidx %u\n", 1898c2ecf20Sopenharmony_ci wq, cq, cq->sw_cidx, cq->sw_pidx); 1908c2ecf20Sopenharmony_ci memset(&cqe, 0, sizeof(cqe)); 1918c2ecf20Sopenharmony_ci cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) | 1928c2ecf20Sopenharmony_ci CQE_OPCODE_V(FW_RI_SEND) | 1938c2ecf20Sopenharmony_ci CQE_TYPE_V(0) | 1948c2ecf20Sopenharmony_ci CQE_SWCQE_V(1) | 1958c2ecf20Sopenharmony_ci CQE_QPID_V(wq->sq.qid)); 1968c2ecf20Sopenharmony_ci cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen)); 1978c2ecf20Sopenharmony_ci if (srqidx) 1988c2ecf20Sopenharmony_ci cqe.u.srcqe.abs_rqe_idx = cpu_to_be32(srqidx); 1998c2ecf20Sopenharmony_ci cq->sw_queue[cq->sw_pidx] = cqe; 2008c2ecf20Sopenharmony_ci t4_swcq_produce(cq); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ciint c4iw_flush_rq(struct t4_wq *wq, struct t4_cq *cq, int count) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci int flushed = 0; 2068c2ecf20Sopenharmony_ci int in_use = wq->rq.in_use - count; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci pr_debug("wq %p cq %p rq.in_use %u skip count %u\n", 2098c2ecf20Sopenharmony_ci wq, cq, wq->rq.in_use, count); 2108c2ecf20Sopenharmony_ci while (in_use--) { 2118c2ecf20Sopenharmony_ci insert_recv_cqe(wq, cq, 0); 2128c2ecf20Sopenharmony_ci flushed++; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci return flushed; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic void insert_sq_cqe(struct t4_wq *wq, struct t4_cq *cq, 2188c2ecf20Sopenharmony_ci struct t4_swsqe *swcqe) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct t4_cqe cqe; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci pr_debug("wq %p cq %p sw_cidx %u sw_pidx %u\n", 2238c2ecf20Sopenharmony_ci wq, cq, cq->sw_cidx, cq->sw_pidx); 2248c2ecf20Sopenharmony_ci memset(&cqe, 0, sizeof(cqe)); 2258c2ecf20Sopenharmony_ci cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) | 2268c2ecf20Sopenharmony_ci CQE_OPCODE_V(swcqe->opcode) | 2278c2ecf20Sopenharmony_ci CQE_TYPE_V(1) | 2288c2ecf20Sopenharmony_ci CQE_SWCQE_V(1) | 2298c2ecf20Sopenharmony_ci CQE_QPID_V(wq->sq.qid)); 2308c2ecf20Sopenharmony_ci CQE_WRID_SQ_IDX(&cqe) = swcqe->idx; 2318c2ecf20Sopenharmony_ci cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen)); 2328c2ecf20Sopenharmony_ci cq->sw_queue[cq->sw_pidx] = cqe; 2338c2ecf20Sopenharmony_ci t4_swcq_produce(cq); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic void advance_oldest_read(struct t4_wq *wq); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciint c4iw_flush_sq(struct c4iw_qp *qhp) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci int flushed = 0; 2418c2ecf20Sopenharmony_ci struct t4_wq *wq = &qhp->wq; 2428c2ecf20Sopenharmony_ci struct c4iw_cq *chp = to_c4iw_cq(qhp->ibqp.send_cq); 2438c2ecf20Sopenharmony_ci struct t4_cq *cq = &chp->cq; 2448c2ecf20Sopenharmony_ci int idx; 2458c2ecf20Sopenharmony_ci struct t4_swsqe *swsqe; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (wq->sq.flush_cidx == -1) 2488c2ecf20Sopenharmony_ci wq->sq.flush_cidx = wq->sq.cidx; 2498c2ecf20Sopenharmony_ci idx = wq->sq.flush_cidx; 2508c2ecf20Sopenharmony_ci while (idx != wq->sq.pidx) { 2518c2ecf20Sopenharmony_ci swsqe = &wq->sq.sw_sq[idx]; 2528c2ecf20Sopenharmony_ci swsqe->flushed = 1; 2538c2ecf20Sopenharmony_ci insert_sq_cqe(wq, cq, swsqe); 2548c2ecf20Sopenharmony_ci if (wq->sq.oldest_read == swsqe) { 2558c2ecf20Sopenharmony_ci advance_oldest_read(wq); 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci flushed++; 2588c2ecf20Sopenharmony_ci if (++idx == wq->sq.size) 2598c2ecf20Sopenharmony_ci idx = 0; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci wq->sq.flush_cidx += flushed; 2628c2ecf20Sopenharmony_ci if (wq->sq.flush_cidx >= wq->sq.size) 2638c2ecf20Sopenharmony_ci wq->sq.flush_cidx -= wq->sq.size; 2648c2ecf20Sopenharmony_ci return flushed; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic void flush_completed_wrs(struct t4_wq *wq, struct t4_cq *cq) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct t4_swsqe *swsqe; 2708c2ecf20Sopenharmony_ci int cidx; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (wq->sq.flush_cidx == -1) 2738c2ecf20Sopenharmony_ci wq->sq.flush_cidx = wq->sq.cidx; 2748c2ecf20Sopenharmony_ci cidx = wq->sq.flush_cidx; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci while (cidx != wq->sq.pidx) { 2778c2ecf20Sopenharmony_ci swsqe = &wq->sq.sw_sq[cidx]; 2788c2ecf20Sopenharmony_ci if (!swsqe->signaled) { 2798c2ecf20Sopenharmony_ci if (++cidx == wq->sq.size) 2808c2ecf20Sopenharmony_ci cidx = 0; 2818c2ecf20Sopenharmony_ci } else if (swsqe->complete) { 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* 2848c2ecf20Sopenharmony_ci * Insert this completed cqe into the swcq. 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci pr_debug("moving cqe into swcq sq idx %u cq idx %u\n", 2878c2ecf20Sopenharmony_ci cidx, cq->sw_pidx); 2888c2ecf20Sopenharmony_ci swsqe->cqe.header |= htonl(CQE_SWCQE_V(1)); 2898c2ecf20Sopenharmony_ci cq->sw_queue[cq->sw_pidx] = swsqe->cqe; 2908c2ecf20Sopenharmony_ci t4_swcq_produce(cq); 2918c2ecf20Sopenharmony_ci swsqe->flushed = 1; 2928c2ecf20Sopenharmony_ci if (++cidx == wq->sq.size) 2938c2ecf20Sopenharmony_ci cidx = 0; 2948c2ecf20Sopenharmony_ci wq->sq.flush_cidx = cidx; 2958c2ecf20Sopenharmony_ci } else 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic void create_read_req_cqe(struct t4_wq *wq, struct t4_cqe *hw_cqe, 3018c2ecf20Sopenharmony_ci struct t4_cqe *read_cqe) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci read_cqe->u.scqe.cidx = wq->sq.oldest_read->idx; 3048c2ecf20Sopenharmony_ci read_cqe->len = htonl(wq->sq.oldest_read->read_len); 3058c2ecf20Sopenharmony_ci read_cqe->header = htonl(CQE_QPID_V(CQE_QPID(hw_cqe)) | 3068c2ecf20Sopenharmony_ci CQE_SWCQE_V(SW_CQE(hw_cqe)) | 3078c2ecf20Sopenharmony_ci CQE_OPCODE_V(FW_RI_READ_REQ) | 3088c2ecf20Sopenharmony_ci CQE_TYPE_V(1)); 3098c2ecf20Sopenharmony_ci read_cqe->bits_type_ts = hw_cqe->bits_type_ts; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic void advance_oldest_read(struct t4_wq *wq) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci u32 rptr = wq->sq.oldest_read - wq->sq.sw_sq + 1; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (rptr == wq->sq.size) 3188c2ecf20Sopenharmony_ci rptr = 0; 3198c2ecf20Sopenharmony_ci while (rptr != wq->sq.pidx) { 3208c2ecf20Sopenharmony_ci wq->sq.oldest_read = &wq->sq.sw_sq[rptr]; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (wq->sq.oldest_read->opcode == FW_RI_READ_REQ) 3238c2ecf20Sopenharmony_ci return; 3248c2ecf20Sopenharmony_ci if (++rptr == wq->sq.size) 3258c2ecf20Sopenharmony_ci rptr = 0; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci wq->sq.oldest_read = NULL; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci/* 3318c2ecf20Sopenharmony_ci * Move all CQEs from the HWCQ into the SWCQ. 3328c2ecf20Sopenharmony_ci * Deal with out-of-order and/or completions that complete 3338c2ecf20Sopenharmony_ci * prior unsignalled WRs. 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_civoid c4iw_flush_hw_cq(struct c4iw_cq *chp, struct c4iw_qp *flush_qhp) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci struct t4_cqe *hw_cqe, *swcqe, read_cqe; 3388c2ecf20Sopenharmony_ci struct c4iw_qp *qhp; 3398c2ecf20Sopenharmony_ci struct t4_swsqe *swsqe; 3408c2ecf20Sopenharmony_ci int ret; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci pr_debug("cqid 0x%x\n", chp->cq.cqid); 3438c2ecf20Sopenharmony_ci ret = t4_next_hw_cqe(&chp->cq, &hw_cqe); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* 3468c2ecf20Sopenharmony_ci * This logic is similar to poll_cq(), but not quite the same 3478c2ecf20Sopenharmony_ci * unfortunately. Need to move pertinent HW CQEs to the SW CQ but 3488c2ecf20Sopenharmony_ci * also do any translation magic that poll_cq() normally does. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci while (!ret) { 3518c2ecf20Sopenharmony_ci qhp = get_qhp(chp->rhp, CQE_QPID(hw_cqe)); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* 3548c2ecf20Sopenharmony_ci * drop CQEs with no associated QP 3558c2ecf20Sopenharmony_ci */ 3568c2ecf20Sopenharmony_ci if (qhp == NULL) 3578c2ecf20Sopenharmony_ci goto next_cqe; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (flush_qhp != qhp) { 3608c2ecf20Sopenharmony_ci spin_lock(&qhp->lock); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (qhp->wq.flushed == 1) 3638c2ecf20Sopenharmony_ci goto next_cqe; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (CQE_OPCODE(hw_cqe) == FW_RI_TERMINATE) 3678c2ecf20Sopenharmony_ci goto next_cqe; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (CQE_OPCODE(hw_cqe) == FW_RI_READ_RESP) { 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* If we have reached here because of async 3728c2ecf20Sopenharmony_ci * event or other error, and have egress error 3738c2ecf20Sopenharmony_ci * then drop 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_ci if (CQE_TYPE(hw_cqe) == 1) 3768c2ecf20Sopenharmony_ci goto next_cqe; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* drop peer2peer RTR reads. 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_ci if (CQE_WRID_STAG(hw_cqe) == 1) 3818c2ecf20Sopenharmony_ci goto next_cqe; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* 3848c2ecf20Sopenharmony_ci * Eat completions for unsignaled read WRs. 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_ci if (!qhp->wq.sq.oldest_read->signaled) { 3878c2ecf20Sopenharmony_ci advance_oldest_read(&qhp->wq); 3888c2ecf20Sopenharmony_ci goto next_cqe; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* 3928c2ecf20Sopenharmony_ci * Don't write to the HWCQ, create a new read req CQE 3938c2ecf20Sopenharmony_ci * in local memory and move it into the swcq. 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_ci create_read_req_cqe(&qhp->wq, hw_cqe, &read_cqe); 3968c2ecf20Sopenharmony_ci hw_cqe = &read_cqe; 3978c2ecf20Sopenharmony_ci advance_oldest_read(&qhp->wq); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* if its a SQ completion, then do the magic to move all the 4018c2ecf20Sopenharmony_ci * unsignaled and now in-order completions into the swcq. 4028c2ecf20Sopenharmony_ci */ 4038c2ecf20Sopenharmony_ci if (SQ_TYPE(hw_cqe)) { 4048c2ecf20Sopenharmony_ci swsqe = &qhp->wq.sq.sw_sq[CQE_WRID_SQ_IDX(hw_cqe)]; 4058c2ecf20Sopenharmony_ci swsqe->cqe = *hw_cqe; 4068c2ecf20Sopenharmony_ci swsqe->complete = 1; 4078c2ecf20Sopenharmony_ci flush_completed_wrs(&qhp->wq, &chp->cq); 4088c2ecf20Sopenharmony_ci } else { 4098c2ecf20Sopenharmony_ci swcqe = &chp->cq.sw_queue[chp->cq.sw_pidx]; 4108c2ecf20Sopenharmony_ci *swcqe = *hw_cqe; 4118c2ecf20Sopenharmony_ci swcqe->header |= cpu_to_be32(CQE_SWCQE_V(1)); 4128c2ecf20Sopenharmony_ci t4_swcq_produce(&chp->cq); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_cinext_cqe: 4158c2ecf20Sopenharmony_ci t4_hwcq_consume(&chp->cq); 4168c2ecf20Sopenharmony_ci ret = t4_next_hw_cqe(&chp->cq, &hw_cqe); 4178c2ecf20Sopenharmony_ci if (qhp && flush_qhp != qhp) 4188c2ecf20Sopenharmony_ci spin_unlock(&qhp->lock); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic int cqe_completes_wr(struct t4_cqe *cqe, struct t4_wq *wq) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci if (DRAIN_CQE(cqe)) { 4258c2ecf20Sopenharmony_ci WARN_ONCE(1, "Unexpected DRAIN CQE qp id %u!\n", wq->sq.qid); 4268c2ecf20Sopenharmony_ci return 0; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (CQE_OPCODE(cqe) == FW_RI_TERMINATE) 4308c2ecf20Sopenharmony_ci return 0; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if ((CQE_OPCODE(cqe) == FW_RI_RDMA_WRITE) && RQ_TYPE(cqe)) 4338c2ecf20Sopenharmony_ci return 0; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if ((CQE_OPCODE(cqe) == FW_RI_READ_RESP) && SQ_TYPE(cqe)) 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (CQE_SEND_OPCODE(cqe) && RQ_TYPE(cqe) && t4_rq_empty(wq)) 4398c2ecf20Sopenharmony_ci return 0; 4408c2ecf20Sopenharmony_ci return 1; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_civoid c4iw_count_rcqes(struct t4_cq *cq, struct t4_wq *wq, int *count) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct t4_cqe *cqe; 4468c2ecf20Sopenharmony_ci u32 ptr; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci *count = 0; 4498c2ecf20Sopenharmony_ci pr_debug("count zero %d\n", *count); 4508c2ecf20Sopenharmony_ci ptr = cq->sw_cidx; 4518c2ecf20Sopenharmony_ci while (ptr != cq->sw_pidx) { 4528c2ecf20Sopenharmony_ci cqe = &cq->sw_queue[ptr]; 4538c2ecf20Sopenharmony_ci if (RQ_TYPE(cqe) && (CQE_OPCODE(cqe) != FW_RI_READ_RESP) && 4548c2ecf20Sopenharmony_ci (CQE_QPID(cqe) == wq->sq.qid) && cqe_completes_wr(cqe, wq)) 4558c2ecf20Sopenharmony_ci (*count)++; 4568c2ecf20Sopenharmony_ci if (++ptr == cq->size) 4578c2ecf20Sopenharmony_ci ptr = 0; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci pr_debug("cq %p count %d\n", cq, *count); 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic void post_pending_srq_wrs(struct t4_srq *srq) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct t4_srq_pending_wr *pwr; 4658c2ecf20Sopenharmony_ci u16 idx = 0; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci while (srq->pending_in_use) { 4688c2ecf20Sopenharmony_ci pwr = &srq->pending_wrs[srq->pending_cidx]; 4698c2ecf20Sopenharmony_ci srq->sw_rq[srq->pidx].wr_id = pwr->wr_id; 4708c2ecf20Sopenharmony_ci srq->sw_rq[srq->pidx].valid = 1; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci pr_debug("%s posting pending cidx %u pidx %u wq_pidx %u in_use %u rq_size %u wr_id %llx\n", 4738c2ecf20Sopenharmony_ci __func__, 4748c2ecf20Sopenharmony_ci srq->cidx, srq->pidx, srq->wq_pidx, 4758c2ecf20Sopenharmony_ci srq->in_use, srq->size, 4768c2ecf20Sopenharmony_ci (unsigned long long)pwr->wr_id); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci c4iw_copy_wr_to_srq(srq, &pwr->wqe, pwr->len16); 4798c2ecf20Sopenharmony_ci t4_srq_consume_pending_wr(srq); 4808c2ecf20Sopenharmony_ci t4_srq_produce(srq, pwr->len16); 4818c2ecf20Sopenharmony_ci idx += DIV_ROUND_UP(pwr->len16 * 16, T4_EQ_ENTRY_SIZE); 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (idx) { 4858c2ecf20Sopenharmony_ci t4_ring_srq_db(srq, idx, pwr->len16, &pwr->wqe); 4868c2ecf20Sopenharmony_ci srq->queue[srq->size].status.host_wq_pidx = 4878c2ecf20Sopenharmony_ci srq->wq_pidx; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic u64 reap_srq_cqe(struct t4_cqe *hw_cqe, struct t4_srq *srq) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci int rel_idx = CQE_ABS_RQE_IDX(hw_cqe) - srq->rqt_abs_idx; 4948c2ecf20Sopenharmony_ci u64 wr_id; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci srq->sw_rq[rel_idx].valid = 0; 4978c2ecf20Sopenharmony_ci wr_id = srq->sw_rq[rel_idx].wr_id; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (rel_idx == srq->cidx) { 5008c2ecf20Sopenharmony_ci pr_debug("%s in order cqe rel_idx %u cidx %u pidx %u wq_pidx %u in_use %u rq_size %u wr_id %llx\n", 5018c2ecf20Sopenharmony_ci __func__, rel_idx, srq->cidx, srq->pidx, 5028c2ecf20Sopenharmony_ci srq->wq_pidx, srq->in_use, srq->size, 5038c2ecf20Sopenharmony_ci (unsigned long long)srq->sw_rq[rel_idx].wr_id); 5048c2ecf20Sopenharmony_ci t4_srq_consume(srq); 5058c2ecf20Sopenharmony_ci while (srq->ooo_count && !srq->sw_rq[srq->cidx].valid) { 5068c2ecf20Sopenharmony_ci pr_debug("%s eat ooo cidx %u pidx %u wq_pidx %u in_use %u rq_size %u ooo_count %u wr_id %llx\n", 5078c2ecf20Sopenharmony_ci __func__, srq->cidx, srq->pidx, 5088c2ecf20Sopenharmony_ci srq->wq_pidx, srq->in_use, 5098c2ecf20Sopenharmony_ci srq->size, srq->ooo_count, 5108c2ecf20Sopenharmony_ci (unsigned long long) 5118c2ecf20Sopenharmony_ci srq->sw_rq[srq->cidx].wr_id); 5128c2ecf20Sopenharmony_ci t4_srq_consume_ooo(srq); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci if (srq->ooo_count == 0 && srq->pending_in_use) 5158c2ecf20Sopenharmony_ci post_pending_srq_wrs(srq); 5168c2ecf20Sopenharmony_ci } else { 5178c2ecf20Sopenharmony_ci pr_debug("%s ooo cqe rel_idx %u cidx %u pidx %u wq_pidx %u in_use %u rq_size %u ooo_count %u wr_id %llx\n", 5188c2ecf20Sopenharmony_ci __func__, rel_idx, srq->cidx, 5198c2ecf20Sopenharmony_ci srq->pidx, srq->wq_pidx, 5208c2ecf20Sopenharmony_ci srq->in_use, srq->size, 5218c2ecf20Sopenharmony_ci srq->ooo_count, 5228c2ecf20Sopenharmony_ci (unsigned long long)srq->sw_rq[rel_idx].wr_id); 5238c2ecf20Sopenharmony_ci t4_srq_produce_ooo(srq); 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci return wr_id; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci/* 5298c2ecf20Sopenharmony_ci * poll_cq 5308c2ecf20Sopenharmony_ci * 5318c2ecf20Sopenharmony_ci * Caller must: 5328c2ecf20Sopenharmony_ci * check the validity of the first CQE, 5338c2ecf20Sopenharmony_ci * supply the wq assicated with the qpid. 5348c2ecf20Sopenharmony_ci * 5358c2ecf20Sopenharmony_ci * credit: cq credit to return to sge. 5368c2ecf20Sopenharmony_ci * cqe_flushed: 1 iff the CQE is flushed. 5378c2ecf20Sopenharmony_ci * cqe: copy of the polled CQE. 5388c2ecf20Sopenharmony_ci * 5398c2ecf20Sopenharmony_ci * return value: 5408c2ecf20Sopenharmony_ci * 0 CQE returned ok. 5418c2ecf20Sopenharmony_ci * -EAGAIN CQE skipped, try again. 5428c2ecf20Sopenharmony_ci * -EOVERFLOW CQ overflow detected. 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_cistatic int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe, 5458c2ecf20Sopenharmony_ci u8 *cqe_flushed, u64 *cookie, u32 *credit, 5468c2ecf20Sopenharmony_ci struct t4_srq *srq) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci int ret = 0; 5498c2ecf20Sopenharmony_ci struct t4_cqe *hw_cqe, read_cqe; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci *cqe_flushed = 0; 5528c2ecf20Sopenharmony_ci *credit = 0; 5538c2ecf20Sopenharmony_ci ret = t4_next_cqe(cq, &hw_cqe); 5548c2ecf20Sopenharmony_ci if (ret) 5558c2ecf20Sopenharmony_ci return ret; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci pr_debug("CQE OVF %u qpid 0x%0x genbit %u type %u status 0x%0x opcode 0x%0x len 0x%0x wrid_hi_stag 0x%x wrid_low_msn 0x%x\n", 5588c2ecf20Sopenharmony_ci CQE_OVFBIT(hw_cqe), CQE_QPID(hw_cqe), 5598c2ecf20Sopenharmony_ci CQE_GENBIT(hw_cqe), CQE_TYPE(hw_cqe), CQE_STATUS(hw_cqe), 5608c2ecf20Sopenharmony_ci CQE_OPCODE(hw_cqe), CQE_LEN(hw_cqe), CQE_WRID_HI(hw_cqe), 5618c2ecf20Sopenharmony_ci CQE_WRID_LOW(hw_cqe)); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* 5648c2ecf20Sopenharmony_ci * skip cqe's not affiliated with a QP. 5658c2ecf20Sopenharmony_ci */ 5668c2ecf20Sopenharmony_ci if (wq == NULL) { 5678c2ecf20Sopenharmony_ci ret = -EAGAIN; 5688c2ecf20Sopenharmony_ci goto skip_cqe; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* 5728c2ecf20Sopenharmony_ci * skip hw cqe's if the wq is flushed. 5738c2ecf20Sopenharmony_ci */ 5748c2ecf20Sopenharmony_ci if (wq->flushed && !SW_CQE(hw_cqe)) { 5758c2ecf20Sopenharmony_ci ret = -EAGAIN; 5768c2ecf20Sopenharmony_ci goto skip_cqe; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* 5808c2ecf20Sopenharmony_ci * skip TERMINATE cqes... 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ci if (CQE_OPCODE(hw_cqe) == FW_RI_TERMINATE) { 5838c2ecf20Sopenharmony_ci ret = -EAGAIN; 5848c2ecf20Sopenharmony_ci goto skip_cqe; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* 5888c2ecf20Sopenharmony_ci * Special cqe for drain WR completions... 5898c2ecf20Sopenharmony_ci */ 5908c2ecf20Sopenharmony_ci if (DRAIN_CQE(hw_cqe)) { 5918c2ecf20Sopenharmony_ci *cookie = CQE_DRAIN_COOKIE(hw_cqe); 5928c2ecf20Sopenharmony_ci *cqe = *hw_cqe; 5938c2ecf20Sopenharmony_ci goto skip_cqe; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* 5978c2ecf20Sopenharmony_ci * Gotta tweak READ completions: 5988c2ecf20Sopenharmony_ci * 1) the cqe doesn't contain the sq_wptr from the wr. 5998c2ecf20Sopenharmony_ci * 2) opcode not reflected from the wr. 6008c2ecf20Sopenharmony_ci * 3) read_len not reflected from the wr. 6018c2ecf20Sopenharmony_ci * 4) cq_type is RQ_TYPE not SQ_TYPE. 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_ci if (RQ_TYPE(hw_cqe) && (CQE_OPCODE(hw_cqe) == FW_RI_READ_RESP)) { 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* If we have reached here because of async 6068c2ecf20Sopenharmony_ci * event or other error, and have egress error 6078c2ecf20Sopenharmony_ci * then drop 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci if (CQE_TYPE(hw_cqe) == 1) { 6108c2ecf20Sopenharmony_ci if (CQE_STATUS(hw_cqe)) 6118c2ecf20Sopenharmony_ci t4_set_wq_in_error(wq, 0); 6128c2ecf20Sopenharmony_ci ret = -EAGAIN; 6138c2ecf20Sopenharmony_ci goto skip_cqe; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* If this is an unsolicited read response, then the read 6178c2ecf20Sopenharmony_ci * was generated by the kernel driver as part of peer-2-peer 6188c2ecf20Sopenharmony_ci * connection setup. So ignore the completion. 6198c2ecf20Sopenharmony_ci */ 6208c2ecf20Sopenharmony_ci if (CQE_WRID_STAG(hw_cqe) == 1) { 6218c2ecf20Sopenharmony_ci if (CQE_STATUS(hw_cqe)) 6228c2ecf20Sopenharmony_ci t4_set_wq_in_error(wq, 0); 6238c2ecf20Sopenharmony_ci ret = -EAGAIN; 6248c2ecf20Sopenharmony_ci goto skip_cqe; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* 6288c2ecf20Sopenharmony_ci * Eat completions for unsignaled read WRs. 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_ci if (!wq->sq.oldest_read->signaled) { 6318c2ecf20Sopenharmony_ci advance_oldest_read(wq); 6328c2ecf20Sopenharmony_ci ret = -EAGAIN; 6338c2ecf20Sopenharmony_ci goto skip_cqe; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci /* 6378c2ecf20Sopenharmony_ci * Don't write to the HWCQ, so create a new read req CQE 6388c2ecf20Sopenharmony_ci * in local memory. 6398c2ecf20Sopenharmony_ci */ 6408c2ecf20Sopenharmony_ci create_read_req_cqe(wq, hw_cqe, &read_cqe); 6418c2ecf20Sopenharmony_ci hw_cqe = &read_cqe; 6428c2ecf20Sopenharmony_ci advance_oldest_read(wq); 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (CQE_STATUS(hw_cqe) || t4_wq_in_error(wq)) { 6468c2ecf20Sopenharmony_ci *cqe_flushed = (CQE_STATUS(hw_cqe) == T4_ERR_SWFLUSH); 6478c2ecf20Sopenharmony_ci t4_set_wq_in_error(wq, 0); 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* 6518c2ecf20Sopenharmony_ci * RECV completion. 6528c2ecf20Sopenharmony_ci */ 6538c2ecf20Sopenharmony_ci if (RQ_TYPE(hw_cqe)) { 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* 6568c2ecf20Sopenharmony_ci * HW only validates 4 bits of MSN. So we must validate that 6578c2ecf20Sopenharmony_ci * the MSN in the SEND is the next expected MSN. If its not, 6588c2ecf20Sopenharmony_ci * then we complete this with T4_ERR_MSN and mark the wq in 6598c2ecf20Sopenharmony_ci * error. 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_ci if (unlikely(!CQE_STATUS(hw_cqe) && 6628c2ecf20Sopenharmony_ci CQE_WRID_MSN(hw_cqe) != wq->rq.msn)) { 6638c2ecf20Sopenharmony_ci t4_set_wq_in_error(wq, 0); 6648c2ecf20Sopenharmony_ci hw_cqe->header |= cpu_to_be32(CQE_STATUS_V(T4_ERR_MSN)); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci goto proc_cqe; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* 6708c2ecf20Sopenharmony_ci * If we get here its a send completion. 6718c2ecf20Sopenharmony_ci * 6728c2ecf20Sopenharmony_ci * Handle out of order completion. These get stuffed 6738c2ecf20Sopenharmony_ci * in the SW SQ. Then the SW SQ is walked to move any 6748c2ecf20Sopenharmony_ci * now in-order completions into the SW CQ. This handles 6758c2ecf20Sopenharmony_ci * 2 cases: 6768c2ecf20Sopenharmony_ci * 1) reaping unsignaled WRs when the first subsequent 6778c2ecf20Sopenharmony_ci * signaled WR is completed. 6788c2ecf20Sopenharmony_ci * 2) out of order read completions. 6798c2ecf20Sopenharmony_ci */ 6808c2ecf20Sopenharmony_ci if (!SW_CQE(hw_cqe) && (CQE_WRID_SQ_IDX(hw_cqe) != wq->sq.cidx)) { 6818c2ecf20Sopenharmony_ci struct t4_swsqe *swsqe; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci pr_debug("out of order completion going in sw_sq at idx %u\n", 6848c2ecf20Sopenharmony_ci CQE_WRID_SQ_IDX(hw_cqe)); 6858c2ecf20Sopenharmony_ci swsqe = &wq->sq.sw_sq[CQE_WRID_SQ_IDX(hw_cqe)]; 6868c2ecf20Sopenharmony_ci swsqe->cqe = *hw_cqe; 6878c2ecf20Sopenharmony_ci swsqe->complete = 1; 6888c2ecf20Sopenharmony_ci ret = -EAGAIN; 6898c2ecf20Sopenharmony_ci goto flush_wq; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ciproc_cqe: 6938c2ecf20Sopenharmony_ci *cqe = *hw_cqe; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* 6968c2ecf20Sopenharmony_ci * Reap the associated WR(s) that are freed up with this 6978c2ecf20Sopenharmony_ci * completion. 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_ci if (SQ_TYPE(hw_cqe)) { 7008c2ecf20Sopenharmony_ci int idx = CQE_WRID_SQ_IDX(hw_cqe); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* 7038c2ecf20Sopenharmony_ci * Account for any unsignaled completions completed by 7048c2ecf20Sopenharmony_ci * this signaled completion. In this case, cidx points 7058c2ecf20Sopenharmony_ci * to the first unsignaled one, and idx points to the 7068c2ecf20Sopenharmony_ci * signaled one. So adjust in_use based on this delta. 7078c2ecf20Sopenharmony_ci * if this is not completing any unsigned wrs, then the 7088c2ecf20Sopenharmony_ci * delta will be 0. Handle wrapping also! 7098c2ecf20Sopenharmony_ci */ 7108c2ecf20Sopenharmony_ci if (idx < wq->sq.cidx) 7118c2ecf20Sopenharmony_ci wq->sq.in_use -= wq->sq.size + idx - wq->sq.cidx; 7128c2ecf20Sopenharmony_ci else 7138c2ecf20Sopenharmony_ci wq->sq.in_use -= idx - wq->sq.cidx; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci wq->sq.cidx = (uint16_t)idx; 7168c2ecf20Sopenharmony_ci pr_debug("completing sq idx %u\n", wq->sq.cidx); 7178c2ecf20Sopenharmony_ci *cookie = wq->sq.sw_sq[wq->sq.cidx].wr_id; 7188c2ecf20Sopenharmony_ci if (c4iw_wr_log) 7198c2ecf20Sopenharmony_ci c4iw_log_wr_stats(wq, hw_cqe); 7208c2ecf20Sopenharmony_ci t4_sq_consume(wq); 7218c2ecf20Sopenharmony_ci } else { 7228c2ecf20Sopenharmony_ci if (!srq) { 7238c2ecf20Sopenharmony_ci pr_debug("completing rq idx %u\n", wq->rq.cidx); 7248c2ecf20Sopenharmony_ci *cookie = wq->rq.sw_rq[wq->rq.cidx].wr_id; 7258c2ecf20Sopenharmony_ci if (c4iw_wr_log) 7268c2ecf20Sopenharmony_ci c4iw_log_wr_stats(wq, hw_cqe); 7278c2ecf20Sopenharmony_ci t4_rq_consume(wq); 7288c2ecf20Sopenharmony_ci } else { 7298c2ecf20Sopenharmony_ci *cookie = reap_srq_cqe(hw_cqe, srq); 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci wq->rq.msn++; 7328c2ecf20Sopenharmony_ci goto skip_cqe; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ciflush_wq: 7368c2ecf20Sopenharmony_ci /* 7378c2ecf20Sopenharmony_ci * Flush any completed cqes that are now in-order. 7388c2ecf20Sopenharmony_ci */ 7398c2ecf20Sopenharmony_ci flush_completed_wrs(wq, cq); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ciskip_cqe: 7428c2ecf20Sopenharmony_ci if (SW_CQE(hw_cqe)) { 7438c2ecf20Sopenharmony_ci pr_debug("cq %p cqid 0x%x skip sw cqe cidx %u\n", 7448c2ecf20Sopenharmony_ci cq, cq->cqid, cq->sw_cidx); 7458c2ecf20Sopenharmony_ci t4_swcq_consume(cq); 7468c2ecf20Sopenharmony_ci } else { 7478c2ecf20Sopenharmony_ci pr_debug("cq %p cqid 0x%x skip hw cqe cidx %u\n", 7488c2ecf20Sopenharmony_ci cq, cq->cqid, cq->cidx); 7498c2ecf20Sopenharmony_ci t4_hwcq_consume(cq); 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci return ret; 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic int __c4iw_poll_cq_one(struct c4iw_cq *chp, struct c4iw_qp *qhp, 7558c2ecf20Sopenharmony_ci struct ib_wc *wc, struct c4iw_srq *srq) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci struct t4_cqe cqe; 7588c2ecf20Sopenharmony_ci struct t4_wq *wq = qhp ? &qhp->wq : NULL; 7598c2ecf20Sopenharmony_ci u32 credit = 0; 7608c2ecf20Sopenharmony_ci u8 cqe_flushed; 7618c2ecf20Sopenharmony_ci u64 cookie = 0; 7628c2ecf20Sopenharmony_ci int ret; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci ret = poll_cq(wq, &(chp->cq), &cqe, &cqe_flushed, &cookie, &credit, 7658c2ecf20Sopenharmony_ci srq ? &srq->wq : NULL); 7668c2ecf20Sopenharmony_ci if (ret) 7678c2ecf20Sopenharmony_ci goto out; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci wc->wr_id = cookie; 7708c2ecf20Sopenharmony_ci wc->qp = qhp ? &qhp->ibqp : NULL; 7718c2ecf20Sopenharmony_ci wc->vendor_err = CQE_STATUS(&cqe); 7728c2ecf20Sopenharmony_ci wc->wc_flags = 0; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* 7758c2ecf20Sopenharmony_ci * Simulate a SRQ_LIMIT_REACHED HW notification if required. 7768c2ecf20Sopenharmony_ci */ 7778c2ecf20Sopenharmony_ci if (srq && !(srq->flags & T4_SRQ_LIMIT_SUPPORT) && srq->armed && 7788c2ecf20Sopenharmony_ci srq->wq.in_use < srq->srq_limit) 7798c2ecf20Sopenharmony_ci c4iw_dispatch_srq_limit_reached_event(srq); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci pr_debug("qpid 0x%x type %d opcode %d status 0x%x len %u wrid hi 0x%x lo 0x%x cookie 0x%llx\n", 7828c2ecf20Sopenharmony_ci CQE_QPID(&cqe), 7838c2ecf20Sopenharmony_ci CQE_TYPE(&cqe), CQE_OPCODE(&cqe), 7848c2ecf20Sopenharmony_ci CQE_STATUS(&cqe), CQE_LEN(&cqe), 7858c2ecf20Sopenharmony_ci CQE_WRID_HI(&cqe), CQE_WRID_LOW(&cqe), 7868c2ecf20Sopenharmony_ci (unsigned long long)cookie); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (CQE_TYPE(&cqe) == 0) { 7898c2ecf20Sopenharmony_ci if (!CQE_STATUS(&cqe)) 7908c2ecf20Sopenharmony_ci wc->byte_len = CQE_LEN(&cqe); 7918c2ecf20Sopenharmony_ci else 7928c2ecf20Sopenharmony_ci wc->byte_len = 0; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci switch (CQE_OPCODE(&cqe)) { 7958c2ecf20Sopenharmony_ci case FW_RI_SEND: 7968c2ecf20Sopenharmony_ci wc->opcode = IB_WC_RECV; 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci case FW_RI_SEND_WITH_INV: 7998c2ecf20Sopenharmony_ci case FW_RI_SEND_WITH_SE_INV: 8008c2ecf20Sopenharmony_ci wc->opcode = IB_WC_RECV; 8018c2ecf20Sopenharmony_ci wc->ex.invalidate_rkey = CQE_WRID_STAG(&cqe); 8028c2ecf20Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_INVALIDATE; 8038c2ecf20Sopenharmony_ci c4iw_invalidate_mr(qhp->rhp, wc->ex.invalidate_rkey); 8048c2ecf20Sopenharmony_ci break; 8058c2ecf20Sopenharmony_ci case FW_RI_WRITE_IMMEDIATE: 8068c2ecf20Sopenharmony_ci wc->opcode = IB_WC_RECV_RDMA_WITH_IMM; 8078c2ecf20Sopenharmony_ci wc->ex.imm_data = CQE_IMM_DATA(&cqe); 8088c2ecf20Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_IMM; 8098c2ecf20Sopenharmony_ci break; 8108c2ecf20Sopenharmony_ci default: 8118c2ecf20Sopenharmony_ci pr_err("Unexpected opcode %d in the CQE received for QPID=0x%0x\n", 8128c2ecf20Sopenharmony_ci CQE_OPCODE(&cqe), CQE_QPID(&cqe)); 8138c2ecf20Sopenharmony_ci ret = -EINVAL; 8148c2ecf20Sopenharmony_ci goto out; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci } else { 8178c2ecf20Sopenharmony_ci switch (CQE_OPCODE(&cqe)) { 8188c2ecf20Sopenharmony_ci case FW_RI_WRITE_IMMEDIATE: 8198c2ecf20Sopenharmony_ci case FW_RI_RDMA_WRITE: 8208c2ecf20Sopenharmony_ci wc->opcode = IB_WC_RDMA_WRITE; 8218c2ecf20Sopenharmony_ci break; 8228c2ecf20Sopenharmony_ci case FW_RI_READ_REQ: 8238c2ecf20Sopenharmony_ci wc->opcode = IB_WC_RDMA_READ; 8248c2ecf20Sopenharmony_ci wc->byte_len = CQE_LEN(&cqe); 8258c2ecf20Sopenharmony_ci break; 8268c2ecf20Sopenharmony_ci case FW_RI_SEND_WITH_INV: 8278c2ecf20Sopenharmony_ci case FW_RI_SEND_WITH_SE_INV: 8288c2ecf20Sopenharmony_ci wc->opcode = IB_WC_SEND; 8298c2ecf20Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_INVALIDATE; 8308c2ecf20Sopenharmony_ci break; 8318c2ecf20Sopenharmony_ci case FW_RI_SEND: 8328c2ecf20Sopenharmony_ci case FW_RI_SEND_WITH_SE: 8338c2ecf20Sopenharmony_ci wc->opcode = IB_WC_SEND; 8348c2ecf20Sopenharmony_ci break; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci case FW_RI_LOCAL_INV: 8378c2ecf20Sopenharmony_ci wc->opcode = IB_WC_LOCAL_INV; 8388c2ecf20Sopenharmony_ci break; 8398c2ecf20Sopenharmony_ci case FW_RI_FAST_REGISTER: 8408c2ecf20Sopenharmony_ci wc->opcode = IB_WC_REG_MR; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci /* Invalidate the MR if the fastreg failed */ 8438c2ecf20Sopenharmony_ci if (CQE_STATUS(&cqe) != T4_ERR_SUCCESS) 8448c2ecf20Sopenharmony_ci c4iw_invalidate_mr(qhp->rhp, 8458c2ecf20Sopenharmony_ci CQE_WRID_FR_STAG(&cqe)); 8468c2ecf20Sopenharmony_ci break; 8478c2ecf20Sopenharmony_ci default: 8488c2ecf20Sopenharmony_ci pr_err("Unexpected opcode %d in the CQE received for QPID=0x%0x\n", 8498c2ecf20Sopenharmony_ci CQE_OPCODE(&cqe), CQE_QPID(&cqe)); 8508c2ecf20Sopenharmony_ci ret = -EINVAL; 8518c2ecf20Sopenharmony_ci goto out; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci if (cqe_flushed) 8568c2ecf20Sopenharmony_ci wc->status = IB_WC_WR_FLUSH_ERR; 8578c2ecf20Sopenharmony_ci else { 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci switch (CQE_STATUS(&cqe)) { 8608c2ecf20Sopenharmony_ci case T4_ERR_SUCCESS: 8618c2ecf20Sopenharmony_ci wc->status = IB_WC_SUCCESS; 8628c2ecf20Sopenharmony_ci break; 8638c2ecf20Sopenharmony_ci case T4_ERR_STAG: 8648c2ecf20Sopenharmony_ci wc->status = IB_WC_LOC_ACCESS_ERR; 8658c2ecf20Sopenharmony_ci break; 8668c2ecf20Sopenharmony_ci case T4_ERR_PDID: 8678c2ecf20Sopenharmony_ci wc->status = IB_WC_LOC_PROT_ERR; 8688c2ecf20Sopenharmony_ci break; 8698c2ecf20Sopenharmony_ci case T4_ERR_QPID: 8708c2ecf20Sopenharmony_ci case T4_ERR_ACCESS: 8718c2ecf20Sopenharmony_ci wc->status = IB_WC_LOC_ACCESS_ERR; 8728c2ecf20Sopenharmony_ci break; 8738c2ecf20Sopenharmony_ci case T4_ERR_WRAP: 8748c2ecf20Sopenharmony_ci wc->status = IB_WC_GENERAL_ERR; 8758c2ecf20Sopenharmony_ci break; 8768c2ecf20Sopenharmony_ci case T4_ERR_BOUND: 8778c2ecf20Sopenharmony_ci wc->status = IB_WC_LOC_LEN_ERR; 8788c2ecf20Sopenharmony_ci break; 8798c2ecf20Sopenharmony_ci case T4_ERR_INVALIDATE_SHARED_MR: 8808c2ecf20Sopenharmony_ci case T4_ERR_INVALIDATE_MR_WITH_MW_BOUND: 8818c2ecf20Sopenharmony_ci wc->status = IB_WC_MW_BIND_ERR; 8828c2ecf20Sopenharmony_ci break; 8838c2ecf20Sopenharmony_ci case T4_ERR_CRC: 8848c2ecf20Sopenharmony_ci case T4_ERR_MARKER: 8858c2ecf20Sopenharmony_ci case T4_ERR_PDU_LEN_ERR: 8868c2ecf20Sopenharmony_ci case T4_ERR_OUT_OF_RQE: 8878c2ecf20Sopenharmony_ci case T4_ERR_DDP_VERSION: 8888c2ecf20Sopenharmony_ci case T4_ERR_RDMA_VERSION: 8898c2ecf20Sopenharmony_ci case T4_ERR_DDP_QUEUE_NUM: 8908c2ecf20Sopenharmony_ci case T4_ERR_MSN: 8918c2ecf20Sopenharmony_ci case T4_ERR_TBIT: 8928c2ecf20Sopenharmony_ci case T4_ERR_MO: 8938c2ecf20Sopenharmony_ci case T4_ERR_MSN_RANGE: 8948c2ecf20Sopenharmony_ci case T4_ERR_IRD_OVERFLOW: 8958c2ecf20Sopenharmony_ci case T4_ERR_OPCODE: 8968c2ecf20Sopenharmony_ci case T4_ERR_INTERNAL_ERR: 8978c2ecf20Sopenharmony_ci wc->status = IB_WC_FATAL_ERR; 8988c2ecf20Sopenharmony_ci break; 8998c2ecf20Sopenharmony_ci case T4_ERR_SWFLUSH: 9008c2ecf20Sopenharmony_ci wc->status = IB_WC_WR_FLUSH_ERR; 9018c2ecf20Sopenharmony_ci break; 9028c2ecf20Sopenharmony_ci default: 9038c2ecf20Sopenharmony_ci pr_err("Unexpected cqe_status 0x%x for QPID=0x%0x\n", 9048c2ecf20Sopenharmony_ci CQE_STATUS(&cqe), CQE_QPID(&cqe)); 9058c2ecf20Sopenharmony_ci wc->status = IB_WC_FATAL_ERR; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ciout: 9098c2ecf20Sopenharmony_ci return ret; 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci/* 9138c2ecf20Sopenharmony_ci * Get one cq entry from c4iw and map it to openib. 9148c2ecf20Sopenharmony_ci * 9158c2ecf20Sopenharmony_ci * Returns: 9168c2ecf20Sopenharmony_ci * 0 cqe returned 9178c2ecf20Sopenharmony_ci * -ENODATA EMPTY; 9188c2ecf20Sopenharmony_ci * -EAGAIN caller must try again 9198c2ecf20Sopenharmony_ci * any other -errno fatal error 9208c2ecf20Sopenharmony_ci */ 9218c2ecf20Sopenharmony_cistatic int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc) 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci struct c4iw_srq *srq = NULL; 9248c2ecf20Sopenharmony_ci struct c4iw_qp *qhp = NULL; 9258c2ecf20Sopenharmony_ci struct t4_cqe *rd_cqe; 9268c2ecf20Sopenharmony_ci int ret; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci ret = t4_next_cqe(&chp->cq, &rd_cqe); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (ret) 9318c2ecf20Sopenharmony_ci return ret; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci qhp = get_qhp(chp->rhp, CQE_QPID(rd_cqe)); 9348c2ecf20Sopenharmony_ci if (qhp) { 9358c2ecf20Sopenharmony_ci spin_lock(&qhp->lock); 9368c2ecf20Sopenharmony_ci srq = qhp->srq; 9378c2ecf20Sopenharmony_ci if (srq) 9388c2ecf20Sopenharmony_ci spin_lock(&srq->lock); 9398c2ecf20Sopenharmony_ci ret = __c4iw_poll_cq_one(chp, qhp, wc, srq); 9408c2ecf20Sopenharmony_ci spin_unlock(&qhp->lock); 9418c2ecf20Sopenharmony_ci if (srq) 9428c2ecf20Sopenharmony_ci spin_unlock(&srq->lock); 9438c2ecf20Sopenharmony_ci } else { 9448c2ecf20Sopenharmony_ci ret = __c4iw_poll_cq_one(chp, NULL, wc, NULL); 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci return ret; 9478c2ecf20Sopenharmony_ci} 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ciint c4iw_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) 9508c2ecf20Sopenharmony_ci{ 9518c2ecf20Sopenharmony_ci struct c4iw_cq *chp; 9528c2ecf20Sopenharmony_ci unsigned long flags; 9538c2ecf20Sopenharmony_ci int npolled; 9548c2ecf20Sopenharmony_ci int err = 0; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci chp = to_c4iw_cq(ibcq); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci spin_lock_irqsave(&chp->lock, flags); 9598c2ecf20Sopenharmony_ci for (npolled = 0; npolled < num_entries; ++npolled) { 9608c2ecf20Sopenharmony_ci do { 9618c2ecf20Sopenharmony_ci err = c4iw_poll_cq_one(chp, wc + npolled); 9628c2ecf20Sopenharmony_ci } while (err == -EAGAIN); 9638c2ecf20Sopenharmony_ci if (err) 9648c2ecf20Sopenharmony_ci break; 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chp->lock, flags); 9678c2ecf20Sopenharmony_ci return !err || err == -ENODATA ? npolled : err; 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ciint c4iw_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci struct c4iw_cq *chp; 9738c2ecf20Sopenharmony_ci struct c4iw_ucontext *ucontext; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci pr_debug("ib_cq %p\n", ib_cq); 9768c2ecf20Sopenharmony_ci chp = to_c4iw_cq(ib_cq); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci xa_erase_irq(&chp->rhp->cqs, chp->cq.cqid); 9798c2ecf20Sopenharmony_ci atomic_dec(&chp->refcnt); 9808c2ecf20Sopenharmony_ci wait_event(chp->wait, !atomic_read(&chp->refcnt)); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci ucontext = rdma_udata_to_drv_context(udata, struct c4iw_ucontext, 9838c2ecf20Sopenharmony_ci ibucontext); 9848c2ecf20Sopenharmony_ci destroy_cq(&chp->rhp->rdev, &chp->cq, 9858c2ecf20Sopenharmony_ci ucontext ? &ucontext->uctx : &chp->cq.rdev->uctx, 9868c2ecf20Sopenharmony_ci chp->destroy_skb, chp->wr_waitp); 9878c2ecf20Sopenharmony_ci c4iw_put_wr_wait(chp->wr_waitp); 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ciint c4iw_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, 9928c2ecf20Sopenharmony_ci struct ib_udata *udata) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci struct ib_device *ibdev = ibcq->device; 9958c2ecf20Sopenharmony_ci int entries = attr->cqe; 9968c2ecf20Sopenharmony_ci int vector = attr->comp_vector; 9978c2ecf20Sopenharmony_ci struct c4iw_dev *rhp = to_c4iw_dev(ibcq->device); 9988c2ecf20Sopenharmony_ci struct c4iw_cq *chp = to_c4iw_cq(ibcq); 9998c2ecf20Sopenharmony_ci struct c4iw_create_cq ucmd; 10008c2ecf20Sopenharmony_ci struct c4iw_create_cq_resp uresp; 10018c2ecf20Sopenharmony_ci int ret, wr_len; 10028c2ecf20Sopenharmony_ci size_t memsize, hwentries; 10038c2ecf20Sopenharmony_ci struct c4iw_mm_entry *mm, *mm2; 10048c2ecf20Sopenharmony_ci struct c4iw_ucontext *ucontext = rdma_udata_to_drv_context( 10058c2ecf20Sopenharmony_ci udata, struct c4iw_ucontext, ibucontext); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci pr_debug("ib_dev %p entries %d\n", ibdev, entries); 10088c2ecf20Sopenharmony_ci if (attr->flags) 10098c2ecf20Sopenharmony_ci return -EINVAL; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (entries < 1 || entries > ibdev->attrs.max_cqe) 10128c2ecf20Sopenharmony_ci return -EINVAL; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (vector >= rhp->rdev.lldi.nciq) 10158c2ecf20Sopenharmony_ci return -EINVAL; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (udata) { 10188c2ecf20Sopenharmony_ci if (udata->inlen < sizeof(ucmd)) 10198c2ecf20Sopenharmony_ci ucontext->is_32b_cqe = 1; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci chp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL); 10238c2ecf20Sopenharmony_ci if (!chp->wr_waitp) { 10248c2ecf20Sopenharmony_ci ret = -ENOMEM; 10258c2ecf20Sopenharmony_ci goto err_free_chp; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci c4iw_init_wr_wait(chp->wr_waitp); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci wr_len = sizeof(struct fw_ri_res_wr) + sizeof(struct fw_ri_res); 10308c2ecf20Sopenharmony_ci chp->destroy_skb = alloc_skb(wr_len, GFP_KERNEL); 10318c2ecf20Sopenharmony_ci if (!chp->destroy_skb) { 10328c2ecf20Sopenharmony_ci ret = -ENOMEM; 10338c2ecf20Sopenharmony_ci goto err_free_wr_wait; 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci /* account for the status page. */ 10378c2ecf20Sopenharmony_ci entries++; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci /* IQ needs one extra entry to differentiate full vs empty. */ 10408c2ecf20Sopenharmony_ci entries++; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci /* 10438c2ecf20Sopenharmony_ci * entries must be multiple of 16 for HW. 10448c2ecf20Sopenharmony_ci */ 10458c2ecf20Sopenharmony_ci entries = roundup(entries, 16); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci /* 10488c2ecf20Sopenharmony_ci * Make actual HW queue 2x to avoid cdix_inc overflows. 10498c2ecf20Sopenharmony_ci */ 10508c2ecf20Sopenharmony_ci hwentries = min(entries * 2, rhp->rdev.hw_queue.t4_max_iq_size); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* 10538c2ecf20Sopenharmony_ci * Make HW queue at least 64 entries so GTS updates aren't too 10548c2ecf20Sopenharmony_ci * frequent. 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_ci if (hwentries < 64) 10578c2ecf20Sopenharmony_ci hwentries = 64; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci memsize = hwentries * ((ucontext && ucontext->is_32b_cqe) ? 10608c2ecf20Sopenharmony_ci (sizeof(*chp->cq.queue) / 2) : sizeof(*chp->cq.queue)); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* 10638c2ecf20Sopenharmony_ci * memsize must be a multiple of the page size if its a user cq. 10648c2ecf20Sopenharmony_ci */ 10658c2ecf20Sopenharmony_ci if (udata) 10668c2ecf20Sopenharmony_ci memsize = roundup(memsize, PAGE_SIZE); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci chp->cq.size = hwentries; 10698c2ecf20Sopenharmony_ci chp->cq.memsize = memsize; 10708c2ecf20Sopenharmony_ci chp->cq.vector = vector; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci ret = create_cq(&rhp->rdev, &chp->cq, 10738c2ecf20Sopenharmony_ci ucontext ? &ucontext->uctx : &rhp->rdev.uctx, 10748c2ecf20Sopenharmony_ci chp->wr_waitp); 10758c2ecf20Sopenharmony_ci if (ret) 10768c2ecf20Sopenharmony_ci goto err_free_skb; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci chp->rhp = rhp; 10798c2ecf20Sopenharmony_ci chp->cq.size--; /* status page */ 10808c2ecf20Sopenharmony_ci chp->ibcq.cqe = entries - 2; 10818c2ecf20Sopenharmony_ci spin_lock_init(&chp->lock); 10828c2ecf20Sopenharmony_ci spin_lock_init(&chp->comp_handler_lock); 10838c2ecf20Sopenharmony_ci atomic_set(&chp->refcnt, 1); 10848c2ecf20Sopenharmony_ci init_waitqueue_head(&chp->wait); 10858c2ecf20Sopenharmony_ci ret = xa_insert_irq(&rhp->cqs, chp->cq.cqid, chp, GFP_KERNEL); 10868c2ecf20Sopenharmony_ci if (ret) 10878c2ecf20Sopenharmony_ci goto err_destroy_cq; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (ucontext) { 10908c2ecf20Sopenharmony_ci ret = -ENOMEM; 10918c2ecf20Sopenharmony_ci mm = kmalloc(sizeof(*mm), GFP_KERNEL); 10928c2ecf20Sopenharmony_ci if (!mm) 10938c2ecf20Sopenharmony_ci goto err_remove_handle; 10948c2ecf20Sopenharmony_ci mm2 = kmalloc(sizeof(*mm2), GFP_KERNEL); 10958c2ecf20Sopenharmony_ci if (!mm2) 10968c2ecf20Sopenharmony_ci goto err_free_mm; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci memset(&uresp, 0, sizeof(uresp)); 10998c2ecf20Sopenharmony_ci uresp.qid_mask = rhp->rdev.cqmask; 11008c2ecf20Sopenharmony_ci uresp.cqid = chp->cq.cqid; 11018c2ecf20Sopenharmony_ci uresp.size = chp->cq.size; 11028c2ecf20Sopenharmony_ci uresp.memsize = chp->cq.memsize; 11038c2ecf20Sopenharmony_ci spin_lock(&ucontext->mmap_lock); 11048c2ecf20Sopenharmony_ci uresp.key = ucontext->key; 11058c2ecf20Sopenharmony_ci ucontext->key += PAGE_SIZE; 11068c2ecf20Sopenharmony_ci uresp.gts_key = ucontext->key; 11078c2ecf20Sopenharmony_ci ucontext->key += PAGE_SIZE; 11088c2ecf20Sopenharmony_ci /* communicate to the userspace that 11098c2ecf20Sopenharmony_ci * kernel driver supports 64B CQE 11108c2ecf20Sopenharmony_ci */ 11118c2ecf20Sopenharmony_ci uresp.flags |= C4IW_64B_CQE; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci spin_unlock(&ucontext->mmap_lock); 11148c2ecf20Sopenharmony_ci ret = ib_copy_to_udata(udata, &uresp, 11158c2ecf20Sopenharmony_ci ucontext->is_32b_cqe ? 11168c2ecf20Sopenharmony_ci sizeof(uresp) - sizeof(uresp.flags) : 11178c2ecf20Sopenharmony_ci sizeof(uresp)); 11188c2ecf20Sopenharmony_ci if (ret) 11198c2ecf20Sopenharmony_ci goto err_free_mm2; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci mm->key = uresp.key; 11228c2ecf20Sopenharmony_ci mm->addr = virt_to_phys(chp->cq.queue); 11238c2ecf20Sopenharmony_ci mm->len = chp->cq.memsize; 11248c2ecf20Sopenharmony_ci insert_mmap(ucontext, mm); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci mm2->key = uresp.gts_key; 11278c2ecf20Sopenharmony_ci mm2->addr = chp->cq.bar2_pa; 11288c2ecf20Sopenharmony_ci mm2->len = PAGE_SIZE; 11298c2ecf20Sopenharmony_ci insert_mmap(ucontext, mm2); 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci pr_debug("cqid 0x%0x chp %p size %u memsize %zu, dma_addr %pad\n", 11338c2ecf20Sopenharmony_ci chp->cq.cqid, chp, chp->cq.size, chp->cq.memsize, 11348c2ecf20Sopenharmony_ci &chp->cq.dma_addr); 11358c2ecf20Sopenharmony_ci return 0; 11368c2ecf20Sopenharmony_cierr_free_mm2: 11378c2ecf20Sopenharmony_ci kfree(mm2); 11388c2ecf20Sopenharmony_cierr_free_mm: 11398c2ecf20Sopenharmony_ci kfree(mm); 11408c2ecf20Sopenharmony_cierr_remove_handle: 11418c2ecf20Sopenharmony_ci xa_erase_irq(&rhp->cqs, chp->cq.cqid); 11428c2ecf20Sopenharmony_cierr_destroy_cq: 11438c2ecf20Sopenharmony_ci destroy_cq(&chp->rhp->rdev, &chp->cq, 11448c2ecf20Sopenharmony_ci ucontext ? &ucontext->uctx : &rhp->rdev.uctx, 11458c2ecf20Sopenharmony_ci chp->destroy_skb, chp->wr_waitp); 11468c2ecf20Sopenharmony_cierr_free_skb: 11478c2ecf20Sopenharmony_ci kfree_skb(chp->destroy_skb); 11488c2ecf20Sopenharmony_cierr_free_wr_wait: 11498c2ecf20Sopenharmony_ci c4iw_put_wr_wait(chp->wr_waitp); 11508c2ecf20Sopenharmony_cierr_free_chp: 11518c2ecf20Sopenharmony_ci return ret; 11528c2ecf20Sopenharmony_ci} 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ciint c4iw_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) 11558c2ecf20Sopenharmony_ci{ 11568c2ecf20Sopenharmony_ci struct c4iw_cq *chp; 11578c2ecf20Sopenharmony_ci int ret = 0; 11588c2ecf20Sopenharmony_ci unsigned long flag; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci chp = to_c4iw_cq(ibcq); 11618c2ecf20Sopenharmony_ci spin_lock_irqsave(&chp->lock, flag); 11628c2ecf20Sopenharmony_ci t4_arm_cq(&chp->cq, 11638c2ecf20Sopenharmony_ci (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED); 11648c2ecf20Sopenharmony_ci if (flags & IB_CQ_REPORT_MISSED_EVENTS) 11658c2ecf20Sopenharmony_ci ret = t4_cq_notempty(&chp->cq); 11668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chp->lock, flag); 11678c2ecf20Sopenharmony_ci return ret; 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_civoid c4iw_flush_srqidx(struct c4iw_qp *qhp, u32 srqidx) 11718c2ecf20Sopenharmony_ci{ 11728c2ecf20Sopenharmony_ci struct c4iw_cq *rchp = to_c4iw_cq(qhp->ibqp.recv_cq); 11738c2ecf20Sopenharmony_ci unsigned long flag; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci /* locking heirarchy: cq lock first, then qp lock. */ 11768c2ecf20Sopenharmony_ci spin_lock_irqsave(&rchp->lock, flag); 11778c2ecf20Sopenharmony_ci spin_lock(&qhp->lock); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci /* create a SRQ RECV CQE for srqidx */ 11808c2ecf20Sopenharmony_ci insert_recv_cqe(&qhp->wq, &rchp->cq, srqidx); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci spin_unlock(&qhp->lock); 11838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rchp->lock, flag); 11848c2ecf20Sopenharmony_ci} 1185