129c8d9ebSAdit Ranadive /* 229c8d9ebSAdit Ranadive * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. 329c8d9ebSAdit Ranadive * 429c8d9ebSAdit Ranadive * This program is free software; you can redistribute it and/or 529c8d9ebSAdit Ranadive * modify it under the terms of EITHER the GNU General Public License 629c8d9ebSAdit Ranadive * version 2 as published by the Free Software Foundation or the BSD 729c8d9ebSAdit Ranadive * 2-Clause License. This program is distributed in the hope that it 829c8d9ebSAdit Ranadive * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED 929c8d9ebSAdit Ranadive * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 1029c8d9ebSAdit Ranadive * See the GNU General Public License version 2 for more details at 1129c8d9ebSAdit Ranadive * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. 1229c8d9ebSAdit Ranadive * 1329c8d9ebSAdit Ranadive * You should have received a copy of the GNU General Public License 1429c8d9ebSAdit Ranadive * along with this program available in the file COPYING in the main 1529c8d9ebSAdit Ranadive * directory of this source tree. 1629c8d9ebSAdit Ranadive * 1729c8d9ebSAdit Ranadive * The BSD 2-Clause License 1829c8d9ebSAdit Ranadive * 1929c8d9ebSAdit Ranadive * Redistribution and use in source and binary forms, with or 2029c8d9ebSAdit Ranadive * without modification, are permitted provided that the following 2129c8d9ebSAdit Ranadive * conditions are met: 2229c8d9ebSAdit Ranadive * 2329c8d9ebSAdit Ranadive * - Redistributions of source code must retain the above 2429c8d9ebSAdit Ranadive * copyright notice, this list of conditions and the following 2529c8d9ebSAdit Ranadive * disclaimer. 2629c8d9ebSAdit Ranadive * 2729c8d9ebSAdit Ranadive * - Redistributions in binary form must reproduce the above 2829c8d9ebSAdit Ranadive * copyright notice, this list of conditions and the following 2929c8d9ebSAdit Ranadive * disclaimer in the documentation and/or other materials 3029c8d9ebSAdit Ranadive * provided with the distribution. 3129c8d9ebSAdit Ranadive * 3229c8d9ebSAdit Ranadive * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3329c8d9ebSAdit Ranadive * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3429c8d9ebSAdit Ranadive * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 3529c8d9ebSAdit Ranadive * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 3629c8d9ebSAdit Ranadive * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 3729c8d9ebSAdit Ranadive * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 3829c8d9ebSAdit Ranadive * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 3929c8d9ebSAdit Ranadive * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4029c8d9ebSAdit Ranadive * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4129c8d9ebSAdit Ranadive * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 4229c8d9ebSAdit Ranadive * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 4329c8d9ebSAdit Ranadive * OF THE POSSIBILITY OF SUCH DAMAGE. 4429c8d9ebSAdit Ranadive */ 4529c8d9ebSAdit Ranadive 4629c8d9ebSAdit Ranadive #include <asm/page.h> 4729c8d9ebSAdit Ranadive #include <linux/io.h> 4829c8d9ebSAdit Ranadive #include <linux/wait.h> 4929c8d9ebSAdit Ranadive #include <rdma/ib_addr.h> 5029c8d9ebSAdit Ranadive #include <rdma/ib_smi.h> 5129c8d9ebSAdit Ranadive #include <rdma/ib_user_verbs.h> 52ff23dfa1SShamir Rabinovitch #include <rdma/uverbs_ioctl.h> 5329c8d9ebSAdit Ranadive 5429c8d9ebSAdit Ranadive #include "pvrdma.h" 5529c8d9ebSAdit Ranadive 5629c8d9ebSAdit Ranadive /** 5729c8d9ebSAdit Ranadive * pvrdma_req_notify_cq - request notification for a completion queue 5829c8d9ebSAdit Ranadive * @ibcq: the completion queue 5929c8d9ebSAdit Ranadive * @notify_flags: notification flags 6029c8d9ebSAdit Ranadive * 6129c8d9ebSAdit Ranadive * @return: 0 for success. 6229c8d9ebSAdit Ranadive */ 6329c8d9ebSAdit Ranadive int pvrdma_req_notify_cq(struct ib_cq *ibcq, 6429c8d9ebSAdit Ranadive enum ib_cq_notify_flags notify_flags) 6529c8d9ebSAdit Ranadive { 6629c8d9ebSAdit Ranadive struct pvrdma_dev *dev = to_vdev(ibcq->device); 6729c8d9ebSAdit Ranadive struct pvrdma_cq *cq = to_vcq(ibcq); 6829c8d9ebSAdit Ranadive u32 val = cq->cq_handle; 69a7d2e039SBryan Tan unsigned long flags; 70a7d2e039SBryan Tan int has_data = 0; 7129c8d9ebSAdit Ranadive 7229c8d9ebSAdit Ranadive val |= (notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? 7329c8d9ebSAdit Ranadive PVRDMA_UAR_CQ_ARM_SOL : PVRDMA_UAR_CQ_ARM; 7429c8d9ebSAdit Ranadive 75a7d2e039SBryan Tan spin_lock_irqsave(&cq->cq_lock, flags); 76a7d2e039SBryan Tan 7729c8d9ebSAdit Ranadive pvrdma_write_uar_cq(dev, val); 7829c8d9ebSAdit Ranadive 79a7d2e039SBryan Tan if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) { 80a7d2e039SBryan Tan unsigned int head; 81a7d2e039SBryan Tan 82a7d2e039SBryan Tan has_data = pvrdma_idx_ring_has_data(&cq->ring_state->rx, 83a7d2e039SBryan Tan cq->ibcq.cqe, &head); 84a7d2e039SBryan Tan if (unlikely(has_data == PVRDMA_INVALID_IDX)) 85a7d2e039SBryan Tan dev_err(&dev->pdev->dev, "CQ ring state invalid\n"); 86a7d2e039SBryan Tan } 87a7d2e039SBryan Tan 88a7d2e039SBryan Tan spin_unlock_irqrestore(&cq->cq_lock, flags); 89a7d2e039SBryan Tan 90a7d2e039SBryan Tan return has_data; 9129c8d9ebSAdit Ranadive } 9229c8d9ebSAdit Ranadive 9329c8d9ebSAdit Ranadive /** 9429c8d9ebSAdit Ranadive * pvrdma_create_cq - create completion queue 95e39afe3dSLeon Romanovsky * @ibcq: Allocated CQ 9629c8d9ebSAdit Ranadive * @attr: completion queue attributes 9729c8d9ebSAdit Ranadive * @udata: user data 9829c8d9ebSAdit Ranadive * 99e39afe3dSLeon Romanovsky * @return: 0 on success 10029c8d9ebSAdit Ranadive */ 101e39afe3dSLeon Romanovsky int pvrdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, 10229c8d9ebSAdit Ranadive struct ib_udata *udata) 10329c8d9ebSAdit Ranadive { 104e39afe3dSLeon Romanovsky struct ib_device *ibdev = ibcq->device; 10529c8d9ebSAdit Ranadive int entries = attr->cqe; 10629c8d9ebSAdit Ranadive struct pvrdma_dev *dev = to_vdev(ibdev); 107e39afe3dSLeon Romanovsky struct pvrdma_cq *cq = to_vcq(ibcq); 10829c8d9ebSAdit Ranadive int ret; 10929c8d9ebSAdit Ranadive int npages; 11029c8d9ebSAdit Ranadive unsigned long flags; 11129c8d9ebSAdit Ranadive union pvrdma_cmd_req req; 11229c8d9ebSAdit Ranadive union pvrdma_cmd_resp rsp; 11329c8d9ebSAdit Ranadive struct pvrdma_cmd_create_cq *cmd = &req.create_cq; 11429c8d9ebSAdit Ranadive struct pvrdma_cmd_create_cq_resp *resp = &rsp.create_cq_resp; 115e39afe3dSLeon Romanovsky struct pvrdma_create_cq_resp cq_resp = {}; 11629c8d9ebSAdit Ranadive struct pvrdma_create_cq ucmd; 117ff23dfa1SShamir Rabinovitch struct pvrdma_ucontext *context = rdma_udata_to_drv_context( 118ff23dfa1SShamir Rabinovitch udata, struct pvrdma_ucontext, ibucontext); 11929c8d9ebSAdit Ranadive 12029c8d9ebSAdit Ranadive BUILD_BUG_ON(sizeof(struct pvrdma_cqe) != 64); 12129c8d9ebSAdit Ranadive 1221c407cb5SJason Gunthorpe if (attr->flags) 1231c407cb5SJason Gunthorpe return -EOPNOTSUPP; 1241c407cb5SJason Gunthorpe 12529c8d9ebSAdit Ranadive entries = roundup_pow_of_two(entries); 12629c8d9ebSAdit Ranadive if (entries < 1 || entries > dev->dsr->caps.max_cqe) 127e39afe3dSLeon Romanovsky return -EINVAL; 12829c8d9ebSAdit Ranadive 12929c8d9ebSAdit Ranadive if (!atomic_add_unless(&dev->num_cqs, 1, dev->dsr->caps.max_cq)) 130e39afe3dSLeon Romanovsky return -ENOMEM; 13129c8d9ebSAdit Ranadive 13229c8d9ebSAdit Ranadive cq->ibcq.cqe = entries; 133ff23dfa1SShamir Rabinovitch cq->is_kernel = !udata; 13429c8d9ebSAdit Ranadive 1355aef7cf2SBryan Tan if (!cq->is_kernel) { 13629c8d9ebSAdit Ranadive if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) { 13729c8d9ebSAdit Ranadive ret = -EFAULT; 13829c8d9ebSAdit Ranadive goto err_cq; 13929c8d9ebSAdit Ranadive } 14029c8d9ebSAdit Ranadive 141c320e527SMoni Shoua cq->umem = ib_umem_get(ibdev, ucmd.buf_addr, ucmd.buf_size, 14272b894b0SChristoph Hellwig IB_ACCESS_LOCAL_WRITE); 14329c8d9ebSAdit Ranadive if (IS_ERR(cq->umem)) { 14429c8d9ebSAdit Ranadive ret = PTR_ERR(cq->umem); 14529c8d9ebSAdit Ranadive goto err_cq; 14629c8d9ebSAdit Ranadive } 14729c8d9ebSAdit Ranadive 14887aebd3fSJason Gunthorpe npages = ib_umem_num_dma_blocks(cq->umem, PAGE_SIZE); 14929c8d9ebSAdit Ranadive } else { 15029c8d9ebSAdit Ranadive /* One extra page for shared ring state */ 15129c8d9ebSAdit Ranadive npages = 1 + (entries * sizeof(struct pvrdma_cqe) + 15229c8d9ebSAdit Ranadive PAGE_SIZE - 1) / PAGE_SIZE; 15329c8d9ebSAdit Ranadive 15429c8d9ebSAdit Ranadive /* Skip header page. */ 15529c8d9ebSAdit Ranadive cq->offset = PAGE_SIZE; 15629c8d9ebSAdit Ranadive } 15729c8d9ebSAdit Ranadive 15829c8d9ebSAdit Ranadive if (npages < 0 || npages > PVRDMA_PAGE_DIR_MAX_PAGES) { 15929c8d9ebSAdit Ranadive dev_warn(&dev->pdev->dev, 16029c8d9ebSAdit Ranadive "overflow pages in completion queue\n"); 16129c8d9ebSAdit Ranadive ret = -EINVAL; 16229c8d9ebSAdit Ranadive goto err_umem; 16329c8d9ebSAdit Ranadive } 16429c8d9ebSAdit Ranadive 16529c8d9ebSAdit Ranadive ret = pvrdma_page_dir_init(dev, &cq->pdir, npages, cq->is_kernel); 16629c8d9ebSAdit Ranadive if (ret) { 16729c8d9ebSAdit Ranadive dev_warn(&dev->pdev->dev, 16829c8d9ebSAdit Ranadive "could not allocate page directory\n"); 16929c8d9ebSAdit Ranadive goto err_umem; 17029c8d9ebSAdit Ranadive } 17129c8d9ebSAdit Ranadive 17229c8d9ebSAdit Ranadive /* Ring state is always the first page. Set in library for user cq. */ 17329c8d9ebSAdit Ranadive if (cq->is_kernel) 17429c8d9ebSAdit Ranadive cq->ring_state = cq->pdir.pages[0]; 17529c8d9ebSAdit Ranadive else 17629c8d9ebSAdit Ranadive pvrdma_page_dir_insert_umem(&cq->pdir, cq->umem, 0); 17729c8d9ebSAdit Ranadive 178a61eb613SBryan Tan refcount_set(&cq->refcnt, 1); 179e3524b26SBryan Tan init_completion(&cq->free); 18029c8d9ebSAdit Ranadive spin_lock_init(&cq->cq_lock); 18129c8d9ebSAdit Ranadive 18229c8d9ebSAdit Ranadive memset(cmd, 0, sizeof(*cmd)); 18329c8d9ebSAdit Ranadive cmd->hdr.cmd = PVRDMA_CMD_CREATE_CQ; 18429c8d9ebSAdit Ranadive cmd->nchunks = npages; 185ff23dfa1SShamir Rabinovitch cmd->ctx_handle = context ? context->ctx_handle : 0; 18629c8d9ebSAdit Ranadive cmd->cqe = entries; 18729c8d9ebSAdit Ranadive cmd->pdir_dma = cq->pdir.dir_dma; 18829c8d9ebSAdit Ranadive ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_CQ_RESP); 18929c8d9ebSAdit Ranadive if (ret < 0) { 19029c8d9ebSAdit Ranadive dev_warn(&dev->pdev->dev, 19129c8d9ebSAdit Ranadive "could not create completion queue, error: %d\n", ret); 19229c8d9ebSAdit Ranadive goto err_page_dir; 19329c8d9ebSAdit Ranadive } 19429c8d9ebSAdit Ranadive 19529c8d9ebSAdit Ranadive cq->ibcq.cqe = resp->cqe; 19629c8d9ebSAdit Ranadive cq->cq_handle = resp->cq_handle; 1971f5a6c47SAdit Ranadive cq_resp.cqn = resp->cq_handle; 19829c8d9ebSAdit Ranadive spin_lock_irqsave(&dev->cq_tbl_lock, flags); 19929c8d9ebSAdit Ranadive dev->cq_tbl[cq->cq_handle % dev->dsr->caps.max_cq] = cq; 20029c8d9ebSAdit Ranadive spin_unlock_irqrestore(&dev->cq_tbl_lock, flags); 20129c8d9ebSAdit Ranadive 2025aef7cf2SBryan Tan if (!cq->is_kernel) { 203ff23dfa1SShamir Rabinovitch cq->uar = &context->uar; 20429c8d9ebSAdit Ranadive 20529c8d9ebSAdit Ranadive /* Copy udata back. */ 2061f5a6c47SAdit Ranadive if (ib_copy_to_udata(udata, &cq_resp, sizeof(cq_resp))) { 20729c8d9ebSAdit Ranadive dev_warn(&dev->pdev->dev, 20829c8d9ebSAdit Ranadive "failed to copy back udata\n"); 209c4367a26SShamir Rabinovitch pvrdma_destroy_cq(&cq->ibcq, udata); 210e39afe3dSLeon Romanovsky return -EINVAL; 21129c8d9ebSAdit Ranadive } 21229c8d9ebSAdit Ranadive } 21329c8d9ebSAdit Ranadive 214e39afe3dSLeon Romanovsky return 0; 21529c8d9ebSAdit Ranadive 21629c8d9ebSAdit Ranadive err_page_dir: 21729c8d9ebSAdit Ranadive pvrdma_page_dir_cleanup(dev, &cq->pdir); 21829c8d9ebSAdit Ranadive err_umem: 21929c8d9ebSAdit Ranadive ib_umem_release(cq->umem); 22029c8d9ebSAdit Ranadive err_cq: 22129c8d9ebSAdit Ranadive atomic_dec(&dev->num_cqs); 222e39afe3dSLeon Romanovsky return ret; 22329c8d9ebSAdit Ranadive } 22429c8d9ebSAdit Ranadive 22529c8d9ebSAdit Ranadive static void pvrdma_free_cq(struct pvrdma_dev *dev, struct pvrdma_cq *cq) 22629c8d9ebSAdit Ranadive { 227a61eb613SBryan Tan if (refcount_dec_and_test(&cq->refcnt)) 228e3524b26SBryan Tan complete(&cq->free); 229e3524b26SBryan Tan wait_for_completion(&cq->free); 23029c8d9ebSAdit Ranadive 23129c8d9ebSAdit Ranadive ib_umem_release(cq->umem); 23229c8d9ebSAdit Ranadive 23329c8d9ebSAdit Ranadive pvrdma_page_dir_cleanup(dev, &cq->pdir); 23429c8d9ebSAdit Ranadive } 23529c8d9ebSAdit Ranadive 23629c8d9ebSAdit Ranadive /** 23729c8d9ebSAdit Ranadive * pvrdma_destroy_cq - destroy completion queue 23829c8d9ebSAdit Ranadive * @cq: the completion queue to destroy. 239c4367a26SShamir Rabinovitch * @udata: user data or null for kernel object 24029c8d9ebSAdit Ranadive */ 24143d781b9SLeon Romanovsky int pvrdma_destroy_cq(struct ib_cq *cq, struct ib_udata *udata) 24229c8d9ebSAdit Ranadive { 24329c8d9ebSAdit Ranadive struct pvrdma_cq *vcq = to_vcq(cq); 24429c8d9ebSAdit Ranadive union pvrdma_cmd_req req; 24529c8d9ebSAdit Ranadive struct pvrdma_cmd_destroy_cq *cmd = &req.destroy_cq; 24629c8d9ebSAdit Ranadive struct pvrdma_dev *dev = to_vdev(cq->device); 24729c8d9ebSAdit Ranadive unsigned long flags; 24829c8d9ebSAdit Ranadive int ret; 24929c8d9ebSAdit Ranadive 25029c8d9ebSAdit Ranadive memset(cmd, 0, sizeof(*cmd)); 25129c8d9ebSAdit Ranadive cmd->hdr.cmd = PVRDMA_CMD_DESTROY_CQ; 25229c8d9ebSAdit Ranadive cmd->cq_handle = vcq->cq_handle; 25329c8d9ebSAdit Ranadive 25429c8d9ebSAdit Ranadive ret = pvrdma_cmd_post(dev, &req, NULL, 0); 25529c8d9ebSAdit Ranadive if (ret < 0) 25629c8d9ebSAdit Ranadive dev_warn(&dev->pdev->dev, 25729c8d9ebSAdit Ranadive "could not destroy completion queue, error: %d\n", 25829c8d9ebSAdit Ranadive ret); 25929c8d9ebSAdit Ranadive 26029c8d9ebSAdit Ranadive /* free cq's resources */ 26129c8d9ebSAdit Ranadive spin_lock_irqsave(&dev->cq_tbl_lock, flags); 26229c8d9ebSAdit Ranadive dev->cq_tbl[vcq->cq_handle] = NULL; 26329c8d9ebSAdit Ranadive spin_unlock_irqrestore(&dev->cq_tbl_lock, flags); 26429c8d9ebSAdit Ranadive 26529c8d9ebSAdit Ranadive pvrdma_free_cq(dev, vcq); 26629c8d9ebSAdit Ranadive atomic_dec(&dev->num_cqs); 26743d781b9SLeon Romanovsky return 0; 26829c8d9ebSAdit Ranadive } 26929c8d9ebSAdit Ranadive 27029c8d9ebSAdit Ranadive static inline struct pvrdma_cqe *get_cqe(struct pvrdma_cq *cq, int i) 27129c8d9ebSAdit Ranadive { 27229c8d9ebSAdit Ranadive return (struct pvrdma_cqe *)pvrdma_page_dir_get_ptr( 27329c8d9ebSAdit Ranadive &cq->pdir, 27429c8d9ebSAdit Ranadive cq->offset + 27529c8d9ebSAdit Ranadive sizeof(struct pvrdma_cqe) * i); 27629c8d9ebSAdit Ranadive } 27729c8d9ebSAdit Ranadive 27829c8d9ebSAdit Ranadive void _pvrdma_flush_cqe(struct pvrdma_qp *qp, struct pvrdma_cq *cq) 27929c8d9ebSAdit Ranadive { 28014d6c3a8SAdit Ranadive unsigned int head; 28129c8d9ebSAdit Ranadive int has_data; 28229c8d9ebSAdit Ranadive 28329c8d9ebSAdit Ranadive if (!cq->is_kernel) 28429c8d9ebSAdit Ranadive return; 28529c8d9ebSAdit Ranadive 28629c8d9ebSAdit Ranadive /* Lock held */ 28729c8d9ebSAdit Ranadive has_data = pvrdma_idx_ring_has_data(&cq->ring_state->rx, 28829c8d9ebSAdit Ranadive cq->ibcq.cqe, &head); 28929c8d9ebSAdit Ranadive if (unlikely(has_data > 0)) { 29029c8d9ebSAdit Ranadive int items; 29129c8d9ebSAdit Ranadive int curr; 29229c8d9ebSAdit Ranadive int tail = pvrdma_idx(&cq->ring_state->rx.prod_tail, 29329c8d9ebSAdit Ranadive cq->ibcq.cqe); 29429c8d9ebSAdit Ranadive struct pvrdma_cqe *cqe; 29529c8d9ebSAdit Ranadive struct pvrdma_cqe *curr_cqe; 29629c8d9ebSAdit Ranadive 29729c8d9ebSAdit Ranadive items = (tail > head) ? (tail - head) : 29829c8d9ebSAdit Ranadive (cq->ibcq.cqe - head + tail); 29929c8d9ebSAdit Ranadive curr = --tail; 30029c8d9ebSAdit Ranadive while (items-- > 0) { 30129c8d9ebSAdit Ranadive if (curr < 0) 30229c8d9ebSAdit Ranadive curr = cq->ibcq.cqe - 1; 30329c8d9ebSAdit Ranadive if (tail < 0) 30429c8d9ebSAdit Ranadive tail = cq->ibcq.cqe - 1; 30529c8d9ebSAdit Ranadive curr_cqe = get_cqe(cq, curr); 30629c8d9ebSAdit Ranadive if ((curr_cqe->qp & 0xFFFF) != qp->qp_handle) { 30729c8d9ebSAdit Ranadive if (curr != tail) { 30829c8d9ebSAdit Ranadive cqe = get_cqe(cq, tail); 30929c8d9ebSAdit Ranadive *cqe = *curr_cqe; 31029c8d9ebSAdit Ranadive } 31129c8d9ebSAdit Ranadive tail--; 31229c8d9ebSAdit Ranadive } else { 31329c8d9ebSAdit Ranadive pvrdma_idx_ring_inc( 31429c8d9ebSAdit Ranadive &cq->ring_state->rx.cons_head, 31529c8d9ebSAdit Ranadive cq->ibcq.cqe); 31629c8d9ebSAdit Ranadive } 31729c8d9ebSAdit Ranadive curr--; 31829c8d9ebSAdit Ranadive } 31929c8d9ebSAdit Ranadive } 32029c8d9ebSAdit Ranadive } 32129c8d9ebSAdit Ranadive 32229c8d9ebSAdit Ranadive static int pvrdma_poll_one(struct pvrdma_cq *cq, struct pvrdma_qp **cur_qp, 32329c8d9ebSAdit Ranadive struct ib_wc *wc) 32429c8d9ebSAdit Ranadive { 32529c8d9ebSAdit Ranadive struct pvrdma_dev *dev = to_vdev(cq->ibcq.device); 32629c8d9ebSAdit Ranadive int has_data; 32729c8d9ebSAdit Ranadive unsigned int head; 32829c8d9ebSAdit Ranadive bool tried = false; 32929c8d9ebSAdit Ranadive struct pvrdma_cqe *cqe; 33029c8d9ebSAdit Ranadive 33129c8d9ebSAdit Ranadive retry: 33229c8d9ebSAdit Ranadive has_data = pvrdma_idx_ring_has_data(&cq->ring_state->rx, 33329c8d9ebSAdit Ranadive cq->ibcq.cqe, &head); 33429c8d9ebSAdit Ranadive if (has_data == 0) { 33529c8d9ebSAdit Ranadive if (tried) 33629c8d9ebSAdit Ranadive return -EAGAIN; 33729c8d9ebSAdit Ranadive 33829c8d9ebSAdit Ranadive pvrdma_write_uar_cq(dev, cq->cq_handle | PVRDMA_UAR_CQ_POLL); 33929c8d9ebSAdit Ranadive 34029c8d9ebSAdit Ranadive tried = true; 34129c8d9ebSAdit Ranadive goto retry; 34229c8d9ebSAdit Ranadive } else if (has_data == PVRDMA_INVALID_IDX) { 34329c8d9ebSAdit Ranadive dev_err(&dev->pdev->dev, "CQ ring state invalid\n"); 34429c8d9ebSAdit Ranadive return -EAGAIN; 34529c8d9ebSAdit Ranadive } 34629c8d9ebSAdit Ranadive 34729c8d9ebSAdit Ranadive cqe = get_cqe(cq, head); 34829c8d9ebSAdit Ranadive 34929c8d9ebSAdit Ranadive /* Ensure cqe is valid. */ 35029c8d9ebSAdit Ranadive rmb(); 35129c8d9ebSAdit Ranadive if (dev->qp_tbl[cqe->qp & 0xffff]) 35229c8d9ebSAdit Ranadive *cur_qp = (struct pvrdma_qp *)dev->qp_tbl[cqe->qp & 0xffff]; 35329c8d9ebSAdit Ranadive else 35429c8d9ebSAdit Ranadive return -EAGAIN; 35529c8d9ebSAdit Ranadive 35629c8d9ebSAdit Ranadive wc->opcode = pvrdma_wc_opcode_to_ib(cqe->opcode); 35729c8d9ebSAdit Ranadive wc->status = pvrdma_wc_status_to_ib(cqe->status); 35829c8d9ebSAdit Ranadive wc->wr_id = cqe->wr_id; 35929c8d9ebSAdit Ranadive wc->qp = &(*cur_qp)->ibqp; 36029c8d9ebSAdit Ranadive wc->byte_len = cqe->byte_len; 36129c8d9ebSAdit Ranadive wc->ex.imm_data = cqe->imm_data; 36229c8d9ebSAdit Ranadive wc->src_qp = cqe->src_qp; 36329c8d9ebSAdit Ranadive wc->wc_flags = pvrdma_wc_flags_to_ib(cqe->wc_flags); 36429c8d9ebSAdit Ranadive wc->pkey_index = cqe->pkey_index; 36529c8d9ebSAdit Ranadive wc->slid = cqe->slid; 36629c8d9ebSAdit Ranadive wc->sl = cqe->sl; 36729c8d9ebSAdit Ranadive wc->dlid_path_bits = cqe->dlid_path_bits; 36829c8d9ebSAdit Ranadive wc->port_num = cqe->port_num; 369c67294b7SYuval Shaia wc->vendor_err = cqe->vendor_err; 370*9f206f73SBryan Tan wc->network_hdr_type = pvrdma_network_type_to_ib(cqe->network_hdr_type); 37129c8d9ebSAdit Ranadive 37229c8d9ebSAdit Ranadive /* Update shared ring state */ 37329c8d9ebSAdit Ranadive pvrdma_idx_ring_inc(&cq->ring_state->rx.cons_head, cq->ibcq.cqe); 37429c8d9ebSAdit Ranadive 37529c8d9ebSAdit Ranadive return 0; 37629c8d9ebSAdit Ranadive } 37729c8d9ebSAdit Ranadive 37829c8d9ebSAdit Ranadive /** 37929c8d9ebSAdit Ranadive * pvrdma_poll_cq - poll for work completion queue entries 38029c8d9ebSAdit Ranadive * @ibcq: completion queue 38129c8d9ebSAdit Ranadive * @num_entries: the maximum number of entries 38262cbff32SKamal Heib * @wc: pointer to work completion array 38329c8d9ebSAdit Ranadive * 38429c8d9ebSAdit Ranadive * @return: number of polled completion entries 38529c8d9ebSAdit Ranadive */ 38629c8d9ebSAdit Ranadive int pvrdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) 38729c8d9ebSAdit Ranadive { 38829c8d9ebSAdit Ranadive struct pvrdma_cq *cq = to_vcq(ibcq); 38929c8d9ebSAdit Ranadive struct pvrdma_qp *cur_qp = NULL; 39029c8d9ebSAdit Ranadive unsigned long flags; 39129c8d9ebSAdit Ranadive int npolled; 39229c8d9ebSAdit Ranadive 39329c8d9ebSAdit Ranadive if (num_entries < 1 || wc == NULL) 39429c8d9ebSAdit Ranadive return 0; 39529c8d9ebSAdit Ranadive 39629c8d9ebSAdit Ranadive spin_lock_irqsave(&cq->cq_lock, flags); 39729c8d9ebSAdit Ranadive for (npolled = 0; npolled < num_entries; ++npolled) { 39829c8d9ebSAdit Ranadive if (pvrdma_poll_one(cq, &cur_qp, wc + npolled)) 39929c8d9ebSAdit Ranadive break; 40029c8d9ebSAdit Ranadive } 40129c8d9ebSAdit Ranadive 40229c8d9ebSAdit Ranadive spin_unlock_irqrestore(&cq->cq_lock, flags); 40329c8d9ebSAdit Ranadive 40429c8d9ebSAdit Ranadive /* Ensure we do not return errors from poll_cq */ 40529c8d9ebSAdit Ranadive return npolled; 40629c8d9ebSAdit Ranadive } 407