162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or 562306a36Sopenharmony_ci * modify it under the terms of EITHER the GNU General Public License 662306a36Sopenharmony_ci * version 2 as published by the Free Software Foundation or the BSD 762306a36Sopenharmony_ci * 2-Clause License. This program is distributed in the hope that it 862306a36Sopenharmony_ci * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED 962306a36Sopenharmony_ci * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 1062306a36Sopenharmony_ci * See the GNU General Public License version 2 for more details at 1162306a36Sopenharmony_ci * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 1462306a36Sopenharmony_ci * along with this program available in the file COPYING in the main 1562306a36Sopenharmony_ci * directory of this source tree. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * The BSD 2-Clause License 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 2062306a36Sopenharmony_ci * without modification, are permitted provided that the following 2162306a36Sopenharmony_ci * conditions are met: 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * - Redistributions of source code must retain the above 2462306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2562306a36Sopenharmony_ci * disclaimer. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2862306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2962306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 3062306a36Sopenharmony_ci * provided with the distribution. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3362306a36Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3462306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 3562306a36Sopenharmony_ci * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 3662306a36Sopenharmony_ci * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 3762306a36Sopenharmony_ci * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 3862306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 3962306a36Sopenharmony_ci * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4062306a36Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4162306a36Sopenharmony_ci * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 4262306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 4362306a36Sopenharmony_ci * OF THE POSSIBILITY OF SUCH DAMAGE. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <asm/page.h> 4762306a36Sopenharmony_ci#include <linux/io.h> 4862306a36Sopenharmony_ci#include <linux/wait.h> 4962306a36Sopenharmony_ci#include <rdma/ib_addr.h> 5062306a36Sopenharmony_ci#include <rdma/ib_smi.h> 5162306a36Sopenharmony_ci#include <rdma/ib_user_verbs.h> 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#include "pvrdma.h" 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void __pvrdma_destroy_qp(struct pvrdma_dev *dev, 5662306a36Sopenharmony_ci struct pvrdma_qp *qp); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic inline void get_cqs(struct pvrdma_qp *qp, struct pvrdma_cq **send_cq, 5962306a36Sopenharmony_ci struct pvrdma_cq **recv_cq) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci *send_cq = to_vcq(qp->ibqp.send_cq); 6262306a36Sopenharmony_ci *recv_cq = to_vcq(qp->ibqp.recv_cq); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic void pvrdma_lock_cqs(struct pvrdma_cq *scq, struct pvrdma_cq *rcq, 6662306a36Sopenharmony_ci unsigned long *scq_flags, 6762306a36Sopenharmony_ci unsigned long *rcq_flags) 6862306a36Sopenharmony_ci __acquires(scq->cq_lock) __acquires(rcq->cq_lock) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci if (scq == rcq) { 7162306a36Sopenharmony_ci spin_lock_irqsave(&scq->cq_lock, *scq_flags); 7262306a36Sopenharmony_ci __acquire(rcq->cq_lock); 7362306a36Sopenharmony_ci } else if (scq->cq_handle < rcq->cq_handle) { 7462306a36Sopenharmony_ci spin_lock_irqsave(&scq->cq_lock, *scq_flags); 7562306a36Sopenharmony_ci spin_lock_irqsave_nested(&rcq->cq_lock, *rcq_flags, 7662306a36Sopenharmony_ci SINGLE_DEPTH_NESTING); 7762306a36Sopenharmony_ci } else { 7862306a36Sopenharmony_ci spin_lock_irqsave(&rcq->cq_lock, *rcq_flags); 7962306a36Sopenharmony_ci spin_lock_irqsave_nested(&scq->cq_lock, *scq_flags, 8062306a36Sopenharmony_ci SINGLE_DEPTH_NESTING); 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void pvrdma_unlock_cqs(struct pvrdma_cq *scq, struct pvrdma_cq *rcq, 8562306a36Sopenharmony_ci unsigned long *scq_flags, 8662306a36Sopenharmony_ci unsigned long *rcq_flags) 8762306a36Sopenharmony_ci __releases(scq->cq_lock) __releases(rcq->cq_lock) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci if (scq == rcq) { 9062306a36Sopenharmony_ci __release(rcq->cq_lock); 9162306a36Sopenharmony_ci spin_unlock_irqrestore(&scq->cq_lock, *scq_flags); 9262306a36Sopenharmony_ci } else if (scq->cq_handle < rcq->cq_handle) { 9362306a36Sopenharmony_ci spin_unlock_irqrestore(&rcq->cq_lock, *rcq_flags); 9462306a36Sopenharmony_ci spin_unlock_irqrestore(&scq->cq_lock, *scq_flags); 9562306a36Sopenharmony_ci } else { 9662306a36Sopenharmony_ci spin_unlock_irqrestore(&scq->cq_lock, *scq_flags); 9762306a36Sopenharmony_ci spin_unlock_irqrestore(&rcq->cq_lock, *rcq_flags); 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic void pvrdma_reset_qp(struct pvrdma_qp *qp) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct pvrdma_cq *scq, *rcq; 10462306a36Sopenharmony_ci unsigned long scq_flags, rcq_flags; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* Clean up cqes */ 10762306a36Sopenharmony_ci get_cqs(qp, &scq, &rcq); 10862306a36Sopenharmony_ci pvrdma_lock_cqs(scq, rcq, &scq_flags, &rcq_flags); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci _pvrdma_flush_cqe(qp, scq); 11162306a36Sopenharmony_ci if (scq != rcq) 11262306a36Sopenharmony_ci _pvrdma_flush_cqe(qp, rcq); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci pvrdma_unlock_cqs(scq, rcq, &scq_flags, &rcq_flags); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* 11762306a36Sopenharmony_ci * Reset queuepair. The checks are because usermode queuepairs won't 11862306a36Sopenharmony_ci * have kernel ringstates. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci if (qp->rq.ring) { 12162306a36Sopenharmony_ci atomic_set(&qp->rq.ring->cons_head, 0); 12262306a36Sopenharmony_ci atomic_set(&qp->rq.ring->prod_tail, 0); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci if (qp->sq.ring) { 12562306a36Sopenharmony_ci atomic_set(&qp->sq.ring->cons_head, 0); 12662306a36Sopenharmony_ci atomic_set(&qp->sq.ring->prod_tail, 0); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int pvrdma_set_rq_size(struct pvrdma_dev *dev, 13162306a36Sopenharmony_ci struct ib_qp_cap *req_cap, 13262306a36Sopenharmony_ci struct pvrdma_qp *qp) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci if (req_cap->max_recv_wr > dev->dsr->caps.max_qp_wr || 13562306a36Sopenharmony_ci req_cap->max_recv_sge > dev->dsr->caps.max_sge) { 13662306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, "recv queue size invalid\n"); 13762306a36Sopenharmony_ci return -EINVAL; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci qp->rq.wqe_cnt = roundup_pow_of_two(max(1U, req_cap->max_recv_wr)); 14162306a36Sopenharmony_ci qp->rq.max_sg = roundup_pow_of_two(max(1U, req_cap->max_recv_sge)); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Write back */ 14462306a36Sopenharmony_ci req_cap->max_recv_wr = qp->rq.wqe_cnt; 14562306a36Sopenharmony_ci req_cap->max_recv_sge = qp->rq.max_sg; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci qp->rq.wqe_size = roundup_pow_of_two(sizeof(struct pvrdma_rq_wqe_hdr) + 14862306a36Sopenharmony_ci sizeof(struct pvrdma_sge) * 14962306a36Sopenharmony_ci qp->rq.max_sg); 15062306a36Sopenharmony_ci qp->npages_recv = (qp->rq.wqe_cnt * qp->rq.wqe_size + PAGE_SIZE - 1) / 15162306a36Sopenharmony_ci PAGE_SIZE; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic int pvrdma_set_sq_size(struct pvrdma_dev *dev, struct ib_qp_cap *req_cap, 15762306a36Sopenharmony_ci struct pvrdma_qp *qp) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci if (req_cap->max_send_wr > dev->dsr->caps.max_qp_wr || 16062306a36Sopenharmony_ci req_cap->max_send_sge > dev->dsr->caps.max_sge) { 16162306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, "send queue size invalid\n"); 16262306a36Sopenharmony_ci return -EINVAL; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci qp->sq.wqe_cnt = roundup_pow_of_two(max(1U, req_cap->max_send_wr)); 16662306a36Sopenharmony_ci qp->sq.max_sg = roundup_pow_of_two(max(1U, req_cap->max_send_sge)); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* Write back */ 16962306a36Sopenharmony_ci req_cap->max_send_wr = qp->sq.wqe_cnt; 17062306a36Sopenharmony_ci req_cap->max_send_sge = qp->sq.max_sg; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci qp->sq.wqe_size = roundup_pow_of_two(sizeof(struct pvrdma_sq_wqe_hdr) + 17362306a36Sopenharmony_ci sizeof(struct pvrdma_sge) * 17462306a36Sopenharmony_ci qp->sq.max_sg); 17562306a36Sopenharmony_ci /* Note: one extra page for the header. */ 17662306a36Sopenharmony_ci qp->npages_send = PVRDMA_QP_NUM_HEADER_PAGES + 17762306a36Sopenharmony_ci (qp->sq.wqe_cnt * qp->sq.wqe_size + PAGE_SIZE - 1) / 17862306a36Sopenharmony_ci PAGE_SIZE; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/** 18462306a36Sopenharmony_ci * pvrdma_create_qp - create queue pair 18562306a36Sopenharmony_ci * @ibqp: queue pair 18662306a36Sopenharmony_ci * @init_attr: queue pair attributes 18762306a36Sopenharmony_ci * @udata: user data 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * @return: the 0 on success, otherwise returns an errno. 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ciint pvrdma_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr, 19262306a36Sopenharmony_ci struct ib_udata *udata) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct pvrdma_qp *qp = to_vqp(ibqp); 19562306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(ibqp->device); 19662306a36Sopenharmony_ci union pvrdma_cmd_req req; 19762306a36Sopenharmony_ci union pvrdma_cmd_resp rsp; 19862306a36Sopenharmony_ci struct pvrdma_cmd_create_qp *cmd = &req.create_qp; 19962306a36Sopenharmony_ci struct pvrdma_cmd_create_qp_resp *resp = &rsp.create_qp_resp; 20062306a36Sopenharmony_ci struct pvrdma_cmd_create_qp_resp_v2 *resp_v2 = &rsp.create_qp_resp_v2; 20162306a36Sopenharmony_ci struct pvrdma_create_qp ucmd; 20262306a36Sopenharmony_ci struct pvrdma_create_qp_resp qp_resp = {}; 20362306a36Sopenharmony_ci unsigned long flags; 20462306a36Sopenharmony_ci int ret; 20562306a36Sopenharmony_ci bool is_srq = !!init_attr->srq; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (init_attr->create_flags) { 20862306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 20962306a36Sopenharmony_ci "invalid create queuepair flags %#x\n", 21062306a36Sopenharmony_ci init_attr->create_flags); 21162306a36Sopenharmony_ci return -EOPNOTSUPP; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (init_attr->qp_type != IB_QPT_RC && 21562306a36Sopenharmony_ci init_attr->qp_type != IB_QPT_UD && 21662306a36Sopenharmony_ci init_attr->qp_type != IB_QPT_GSI) { 21762306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, "queuepair type %d not supported\n", 21862306a36Sopenharmony_ci init_attr->qp_type); 21962306a36Sopenharmony_ci return -EOPNOTSUPP; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (is_srq && !dev->dsr->caps.max_srq) { 22362306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 22462306a36Sopenharmony_ci "SRQs not supported by device\n"); 22562306a36Sopenharmony_ci return -EINVAL; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (!atomic_add_unless(&dev->num_qps, 1, dev->dsr->caps.max_qp)) 22962306a36Sopenharmony_ci return -ENOMEM; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci switch (init_attr->qp_type) { 23262306a36Sopenharmony_ci case IB_QPT_GSI: 23362306a36Sopenharmony_ci if (init_attr->port_num == 0 || 23462306a36Sopenharmony_ci init_attr->port_num > ibqp->device->phys_port_cnt) { 23562306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, "invalid queuepair attrs\n"); 23662306a36Sopenharmony_ci ret = -EINVAL; 23762306a36Sopenharmony_ci goto err_qp; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci fallthrough; 24062306a36Sopenharmony_ci case IB_QPT_RC: 24162306a36Sopenharmony_ci case IB_QPT_UD: 24262306a36Sopenharmony_ci spin_lock_init(&qp->sq.lock); 24362306a36Sopenharmony_ci spin_lock_init(&qp->rq.lock); 24462306a36Sopenharmony_ci mutex_init(&qp->mutex); 24562306a36Sopenharmony_ci refcount_set(&qp->refcnt, 1); 24662306a36Sopenharmony_ci init_completion(&qp->free); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci qp->state = IB_QPS_RESET; 24962306a36Sopenharmony_ci qp->is_kernel = !udata; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (!qp->is_kernel) { 25262306a36Sopenharmony_ci dev_dbg(&dev->pdev->dev, 25362306a36Sopenharmony_ci "create queuepair from user space\n"); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) { 25662306a36Sopenharmony_ci ret = -EFAULT; 25762306a36Sopenharmony_ci goto err_qp; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* Userspace supports qpn and qp handles? */ 26162306a36Sopenharmony_ci if (dev->dsr_version >= PVRDMA_QPHANDLE_VERSION && 26262306a36Sopenharmony_ci udata->outlen < sizeof(qp_resp)) { 26362306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 26462306a36Sopenharmony_ci "create queuepair not supported\n"); 26562306a36Sopenharmony_ci ret = -EOPNOTSUPP; 26662306a36Sopenharmony_ci goto err_qp; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (!is_srq) { 27062306a36Sopenharmony_ci /* set qp->sq.wqe_cnt, shift, buf_size.. */ 27162306a36Sopenharmony_ci qp->rumem = ib_umem_get(ibqp->device, 27262306a36Sopenharmony_ci ucmd.rbuf_addr, 27362306a36Sopenharmony_ci ucmd.rbuf_size, 0); 27462306a36Sopenharmony_ci if (IS_ERR(qp->rumem)) { 27562306a36Sopenharmony_ci ret = PTR_ERR(qp->rumem); 27662306a36Sopenharmony_ci goto err_qp; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci qp->srq = NULL; 27962306a36Sopenharmony_ci } else { 28062306a36Sopenharmony_ci qp->rumem = NULL; 28162306a36Sopenharmony_ci qp->srq = to_vsrq(init_attr->srq); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci qp->sumem = ib_umem_get(ibqp->device, ucmd.sbuf_addr, 28562306a36Sopenharmony_ci ucmd.sbuf_size, 0); 28662306a36Sopenharmony_ci if (IS_ERR(qp->sumem)) { 28762306a36Sopenharmony_ci if (!is_srq) 28862306a36Sopenharmony_ci ib_umem_release(qp->rumem); 28962306a36Sopenharmony_ci ret = PTR_ERR(qp->sumem); 29062306a36Sopenharmony_ci goto err_qp; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci qp->npages_send = 29462306a36Sopenharmony_ci ib_umem_num_dma_blocks(qp->sumem, PAGE_SIZE); 29562306a36Sopenharmony_ci if (!is_srq) 29662306a36Sopenharmony_ci qp->npages_recv = ib_umem_num_dma_blocks( 29762306a36Sopenharmony_ci qp->rumem, PAGE_SIZE); 29862306a36Sopenharmony_ci else 29962306a36Sopenharmony_ci qp->npages_recv = 0; 30062306a36Sopenharmony_ci qp->npages = qp->npages_send + qp->npages_recv; 30162306a36Sopenharmony_ci } else { 30262306a36Sopenharmony_ci ret = pvrdma_set_sq_size(to_vdev(ibqp->device), 30362306a36Sopenharmony_ci &init_attr->cap, qp); 30462306a36Sopenharmony_ci if (ret) 30562306a36Sopenharmony_ci goto err_qp; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci ret = pvrdma_set_rq_size(to_vdev(ibqp->device), 30862306a36Sopenharmony_ci &init_attr->cap, qp); 30962306a36Sopenharmony_ci if (ret) 31062306a36Sopenharmony_ci goto err_qp; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci qp->npages = qp->npages_send + qp->npages_recv; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* Skip header page. */ 31562306a36Sopenharmony_ci qp->sq.offset = PVRDMA_QP_NUM_HEADER_PAGES * PAGE_SIZE; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* Recv queue pages are after send pages. */ 31862306a36Sopenharmony_ci qp->rq.offset = qp->npages_send * PAGE_SIZE; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (qp->npages < 0 || qp->npages > PVRDMA_PAGE_DIR_MAX_PAGES) { 32262306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 32362306a36Sopenharmony_ci "overflow pages in queuepair\n"); 32462306a36Sopenharmony_ci ret = -EINVAL; 32562306a36Sopenharmony_ci goto err_umem; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ret = pvrdma_page_dir_init(dev, &qp->pdir, qp->npages, 32962306a36Sopenharmony_ci qp->is_kernel); 33062306a36Sopenharmony_ci if (ret) { 33162306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 33262306a36Sopenharmony_ci "could not allocate page directory\n"); 33362306a36Sopenharmony_ci goto err_umem; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (!qp->is_kernel) { 33762306a36Sopenharmony_ci pvrdma_page_dir_insert_umem(&qp->pdir, qp->sumem, 0); 33862306a36Sopenharmony_ci if (!is_srq) 33962306a36Sopenharmony_ci pvrdma_page_dir_insert_umem(&qp->pdir, 34062306a36Sopenharmony_ci qp->rumem, 34162306a36Sopenharmony_ci qp->npages_send); 34262306a36Sopenharmony_ci } else { 34362306a36Sopenharmony_ci /* Ring state is always the first page. */ 34462306a36Sopenharmony_ci qp->sq.ring = qp->pdir.pages[0]; 34562306a36Sopenharmony_ci qp->rq.ring = is_srq ? NULL : &qp->sq.ring[1]; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci default: 34962306a36Sopenharmony_ci ret = -EINVAL; 35062306a36Sopenharmony_ci goto err_qp; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* Not supported */ 35462306a36Sopenharmony_ci init_attr->cap.max_inline_data = 0; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci memset(cmd, 0, sizeof(*cmd)); 35762306a36Sopenharmony_ci cmd->hdr.cmd = PVRDMA_CMD_CREATE_QP; 35862306a36Sopenharmony_ci cmd->pd_handle = to_vpd(ibqp->pd)->pd_handle; 35962306a36Sopenharmony_ci cmd->send_cq_handle = to_vcq(init_attr->send_cq)->cq_handle; 36062306a36Sopenharmony_ci cmd->recv_cq_handle = to_vcq(init_attr->recv_cq)->cq_handle; 36162306a36Sopenharmony_ci if (is_srq) 36262306a36Sopenharmony_ci cmd->srq_handle = to_vsrq(init_attr->srq)->srq_handle; 36362306a36Sopenharmony_ci else 36462306a36Sopenharmony_ci cmd->srq_handle = 0; 36562306a36Sopenharmony_ci cmd->max_send_wr = init_attr->cap.max_send_wr; 36662306a36Sopenharmony_ci cmd->max_recv_wr = init_attr->cap.max_recv_wr; 36762306a36Sopenharmony_ci cmd->max_send_sge = init_attr->cap.max_send_sge; 36862306a36Sopenharmony_ci cmd->max_recv_sge = init_attr->cap.max_recv_sge; 36962306a36Sopenharmony_ci cmd->max_inline_data = init_attr->cap.max_inline_data; 37062306a36Sopenharmony_ci cmd->sq_sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ? 1 : 0; 37162306a36Sopenharmony_ci cmd->qp_type = ib_qp_type_to_pvrdma(init_attr->qp_type); 37262306a36Sopenharmony_ci cmd->is_srq = is_srq; 37362306a36Sopenharmony_ci cmd->lkey = 0; 37462306a36Sopenharmony_ci cmd->access_flags = IB_ACCESS_LOCAL_WRITE; 37562306a36Sopenharmony_ci cmd->total_chunks = qp->npages; 37662306a36Sopenharmony_ci cmd->send_chunks = qp->npages_send - PVRDMA_QP_NUM_HEADER_PAGES; 37762306a36Sopenharmony_ci cmd->pdir_dma = qp->pdir.dir_dma; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci dev_dbg(&dev->pdev->dev, "create queuepair with %d, %d, %d, %d\n", 38062306a36Sopenharmony_ci cmd->max_send_wr, cmd->max_recv_wr, cmd->max_send_sge, 38162306a36Sopenharmony_ci cmd->max_recv_sge); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_QP_RESP); 38462306a36Sopenharmony_ci if (ret < 0) { 38562306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 38662306a36Sopenharmony_ci "could not create queuepair, error: %d\n", ret); 38762306a36Sopenharmony_ci goto err_pdir; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* max_send_wr/_recv_wr/_send_sge/_recv_sge/_inline_data */ 39162306a36Sopenharmony_ci qp->port = init_attr->port_num; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (dev->dsr_version >= PVRDMA_QPHANDLE_VERSION) { 39462306a36Sopenharmony_ci qp->ibqp.qp_num = resp_v2->qpn; 39562306a36Sopenharmony_ci qp->qp_handle = resp_v2->qp_handle; 39662306a36Sopenharmony_ci } else { 39762306a36Sopenharmony_ci qp->ibqp.qp_num = resp->qpn; 39862306a36Sopenharmony_ci qp->qp_handle = resp->qpn; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci spin_lock_irqsave(&dev->qp_tbl_lock, flags); 40262306a36Sopenharmony_ci dev->qp_tbl[qp->qp_handle % dev->dsr->caps.max_qp] = qp; 40362306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->qp_tbl_lock, flags); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (udata) { 40662306a36Sopenharmony_ci qp_resp.qpn = qp->ibqp.qp_num; 40762306a36Sopenharmony_ci qp_resp.qp_handle = qp->qp_handle; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (ib_copy_to_udata(udata, &qp_resp, 41062306a36Sopenharmony_ci min(udata->outlen, sizeof(qp_resp)))) { 41162306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 41262306a36Sopenharmony_ci "failed to copy back udata\n"); 41362306a36Sopenharmony_ci __pvrdma_destroy_qp(dev, qp); 41462306a36Sopenharmony_ci return -EINVAL; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci return 0; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cierr_pdir: 42162306a36Sopenharmony_ci pvrdma_page_dir_cleanup(dev, &qp->pdir); 42262306a36Sopenharmony_cierr_umem: 42362306a36Sopenharmony_ci ib_umem_release(qp->rumem); 42462306a36Sopenharmony_ci ib_umem_release(qp->sumem); 42562306a36Sopenharmony_cierr_qp: 42662306a36Sopenharmony_ci atomic_dec(&dev->num_qps); 42762306a36Sopenharmony_ci return ret; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic void _pvrdma_free_qp(struct pvrdma_qp *qp) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci unsigned long flags; 43362306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(qp->ibqp.device); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci spin_lock_irqsave(&dev->qp_tbl_lock, flags); 43662306a36Sopenharmony_ci dev->qp_tbl[qp->qp_handle] = NULL; 43762306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->qp_tbl_lock, flags); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (refcount_dec_and_test(&qp->refcnt)) 44062306a36Sopenharmony_ci complete(&qp->free); 44162306a36Sopenharmony_ci wait_for_completion(&qp->free); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci ib_umem_release(qp->rumem); 44462306a36Sopenharmony_ci ib_umem_release(qp->sumem); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci pvrdma_page_dir_cleanup(dev, &qp->pdir); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci atomic_dec(&dev->num_qps); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic void pvrdma_free_qp(struct pvrdma_qp *qp) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct pvrdma_cq *scq; 45462306a36Sopenharmony_ci struct pvrdma_cq *rcq; 45562306a36Sopenharmony_ci unsigned long scq_flags, rcq_flags; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* In case cq is polling */ 45862306a36Sopenharmony_ci get_cqs(qp, &scq, &rcq); 45962306a36Sopenharmony_ci pvrdma_lock_cqs(scq, rcq, &scq_flags, &rcq_flags); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci _pvrdma_flush_cqe(qp, scq); 46262306a36Sopenharmony_ci if (scq != rcq) 46362306a36Sopenharmony_ci _pvrdma_flush_cqe(qp, rcq); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci /* 46662306a36Sopenharmony_ci * We're now unlocking the CQs before clearing out the qp handle this 46762306a36Sopenharmony_ci * should still be safe. We have destroyed the backend QP and flushed 46862306a36Sopenharmony_ci * the CQEs so there should be no other completions for this QP. 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci pvrdma_unlock_cqs(scq, rcq, &scq_flags, &rcq_flags); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci _pvrdma_free_qp(qp); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic inline void _pvrdma_destroy_qp_work(struct pvrdma_dev *dev, 47662306a36Sopenharmony_ci u32 qp_handle) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci union pvrdma_cmd_req req; 47962306a36Sopenharmony_ci struct pvrdma_cmd_destroy_qp *cmd = &req.destroy_qp; 48062306a36Sopenharmony_ci int ret; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci memset(cmd, 0, sizeof(*cmd)); 48362306a36Sopenharmony_ci cmd->hdr.cmd = PVRDMA_CMD_DESTROY_QP; 48462306a36Sopenharmony_ci cmd->qp_handle = qp_handle; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci ret = pvrdma_cmd_post(dev, &req, NULL, 0); 48762306a36Sopenharmony_ci if (ret < 0) 48862306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 48962306a36Sopenharmony_ci "destroy queuepair failed, error: %d\n", ret); 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci/** 49362306a36Sopenharmony_ci * pvrdma_destroy_qp - destroy a queue pair 49462306a36Sopenharmony_ci * @qp: the queue pair to destroy 49562306a36Sopenharmony_ci * @udata: user data or null for kernel object 49662306a36Sopenharmony_ci * 49762306a36Sopenharmony_ci * @return: always 0. 49862306a36Sopenharmony_ci */ 49962306a36Sopenharmony_ciint pvrdma_destroy_qp(struct ib_qp *qp, struct ib_udata *udata) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci struct pvrdma_qp *vqp = to_vqp(qp); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci _pvrdma_destroy_qp_work(to_vdev(qp->device), vqp->qp_handle); 50462306a36Sopenharmony_ci pvrdma_free_qp(vqp); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic void __pvrdma_destroy_qp(struct pvrdma_dev *dev, 51062306a36Sopenharmony_ci struct pvrdma_qp *qp) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci _pvrdma_destroy_qp_work(dev, qp->qp_handle); 51362306a36Sopenharmony_ci _pvrdma_free_qp(qp); 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci/** 51762306a36Sopenharmony_ci * pvrdma_modify_qp - modify queue pair attributes 51862306a36Sopenharmony_ci * @ibqp: the queue pair 51962306a36Sopenharmony_ci * @attr: the new queue pair's attributes 52062306a36Sopenharmony_ci * @attr_mask: attributes mask 52162306a36Sopenharmony_ci * @udata: user data 52262306a36Sopenharmony_ci * 52362306a36Sopenharmony_ci * @returns 0 on success, otherwise returns an errno. 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ciint pvrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 52662306a36Sopenharmony_ci int attr_mask, struct ib_udata *udata) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(ibqp->device); 52962306a36Sopenharmony_ci struct pvrdma_qp *qp = to_vqp(ibqp); 53062306a36Sopenharmony_ci union pvrdma_cmd_req req; 53162306a36Sopenharmony_ci union pvrdma_cmd_resp rsp; 53262306a36Sopenharmony_ci struct pvrdma_cmd_modify_qp *cmd = &req.modify_qp; 53362306a36Sopenharmony_ci enum ib_qp_state cur_state, next_state; 53462306a36Sopenharmony_ci int ret; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS) 53762306a36Sopenharmony_ci return -EOPNOTSUPP; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* Sanity checking. Should need lock here */ 54062306a36Sopenharmony_ci mutex_lock(&qp->mutex); 54162306a36Sopenharmony_ci cur_state = (attr_mask & IB_QP_CUR_STATE) ? attr->cur_qp_state : 54262306a36Sopenharmony_ci qp->state; 54362306a36Sopenharmony_ci next_state = (attr_mask & IB_QP_STATE) ? attr->qp_state : cur_state; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (!ib_modify_qp_is_ok(cur_state, next_state, ibqp->qp_type, 54662306a36Sopenharmony_ci attr_mask)) { 54762306a36Sopenharmony_ci ret = -EINVAL; 54862306a36Sopenharmony_ci goto out; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (attr_mask & IB_QP_PORT) { 55262306a36Sopenharmony_ci if (attr->port_num == 0 || 55362306a36Sopenharmony_ci attr->port_num > ibqp->device->phys_port_cnt) { 55462306a36Sopenharmony_ci ret = -EINVAL; 55562306a36Sopenharmony_ci goto out; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (attr_mask & IB_QP_MIN_RNR_TIMER) { 56062306a36Sopenharmony_ci if (attr->min_rnr_timer > 31) { 56162306a36Sopenharmony_ci ret = -EINVAL; 56262306a36Sopenharmony_ci goto out; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (attr_mask & IB_QP_PKEY_INDEX) { 56762306a36Sopenharmony_ci if (attr->pkey_index >= dev->dsr->caps.max_pkeys) { 56862306a36Sopenharmony_ci ret = -EINVAL; 56962306a36Sopenharmony_ci goto out; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (attr_mask & IB_QP_QKEY) 57462306a36Sopenharmony_ci qp->qkey = attr->qkey; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (cur_state == next_state && cur_state == IB_QPS_RESET) { 57762306a36Sopenharmony_ci ret = 0; 57862306a36Sopenharmony_ci goto out; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci qp->state = next_state; 58262306a36Sopenharmony_ci memset(cmd, 0, sizeof(*cmd)); 58362306a36Sopenharmony_ci cmd->hdr.cmd = PVRDMA_CMD_MODIFY_QP; 58462306a36Sopenharmony_ci cmd->qp_handle = qp->qp_handle; 58562306a36Sopenharmony_ci cmd->attr_mask = ib_qp_attr_mask_to_pvrdma(attr_mask); 58662306a36Sopenharmony_ci cmd->attrs.qp_state = ib_qp_state_to_pvrdma(attr->qp_state); 58762306a36Sopenharmony_ci cmd->attrs.cur_qp_state = 58862306a36Sopenharmony_ci ib_qp_state_to_pvrdma(attr->cur_qp_state); 58962306a36Sopenharmony_ci cmd->attrs.path_mtu = ib_mtu_to_pvrdma(attr->path_mtu); 59062306a36Sopenharmony_ci cmd->attrs.path_mig_state = 59162306a36Sopenharmony_ci ib_mig_state_to_pvrdma(attr->path_mig_state); 59262306a36Sopenharmony_ci cmd->attrs.qkey = attr->qkey; 59362306a36Sopenharmony_ci cmd->attrs.rq_psn = attr->rq_psn; 59462306a36Sopenharmony_ci cmd->attrs.sq_psn = attr->sq_psn; 59562306a36Sopenharmony_ci cmd->attrs.dest_qp_num = attr->dest_qp_num; 59662306a36Sopenharmony_ci cmd->attrs.qp_access_flags = 59762306a36Sopenharmony_ci ib_access_flags_to_pvrdma(attr->qp_access_flags); 59862306a36Sopenharmony_ci cmd->attrs.pkey_index = attr->pkey_index; 59962306a36Sopenharmony_ci cmd->attrs.alt_pkey_index = attr->alt_pkey_index; 60062306a36Sopenharmony_ci cmd->attrs.en_sqd_async_notify = attr->en_sqd_async_notify; 60162306a36Sopenharmony_ci cmd->attrs.sq_draining = attr->sq_draining; 60262306a36Sopenharmony_ci cmd->attrs.max_rd_atomic = attr->max_rd_atomic; 60362306a36Sopenharmony_ci cmd->attrs.max_dest_rd_atomic = attr->max_dest_rd_atomic; 60462306a36Sopenharmony_ci cmd->attrs.min_rnr_timer = attr->min_rnr_timer; 60562306a36Sopenharmony_ci cmd->attrs.port_num = attr->port_num; 60662306a36Sopenharmony_ci cmd->attrs.timeout = attr->timeout; 60762306a36Sopenharmony_ci cmd->attrs.retry_cnt = attr->retry_cnt; 60862306a36Sopenharmony_ci cmd->attrs.rnr_retry = attr->rnr_retry; 60962306a36Sopenharmony_ci cmd->attrs.alt_port_num = attr->alt_port_num; 61062306a36Sopenharmony_ci cmd->attrs.alt_timeout = attr->alt_timeout; 61162306a36Sopenharmony_ci ib_qp_cap_to_pvrdma(&cmd->attrs.cap, &attr->cap); 61262306a36Sopenharmony_ci rdma_ah_attr_to_pvrdma(&cmd->attrs.ah_attr, &attr->ah_attr); 61362306a36Sopenharmony_ci rdma_ah_attr_to_pvrdma(&cmd->attrs.alt_ah_attr, &attr->alt_ah_attr); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_MODIFY_QP_RESP); 61662306a36Sopenharmony_ci if (ret < 0) { 61762306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 61862306a36Sopenharmony_ci "could not modify queuepair, error: %d\n", ret); 61962306a36Sopenharmony_ci } else if (rsp.hdr.err > 0) { 62062306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 62162306a36Sopenharmony_ci "cannot modify queuepair, error: %d\n", rsp.hdr.err); 62262306a36Sopenharmony_ci ret = -EINVAL; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (ret == 0 && next_state == IB_QPS_RESET) 62662306a36Sopenharmony_ci pvrdma_reset_qp(qp); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ciout: 62962306a36Sopenharmony_ci mutex_unlock(&qp->mutex); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci return ret; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic inline void *get_sq_wqe(struct pvrdma_qp *qp, unsigned int n) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci return pvrdma_page_dir_get_ptr(&qp->pdir, 63762306a36Sopenharmony_ci qp->sq.offset + n * qp->sq.wqe_size); 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic inline void *get_rq_wqe(struct pvrdma_qp *qp, unsigned int n) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci return pvrdma_page_dir_get_ptr(&qp->pdir, 64362306a36Sopenharmony_ci qp->rq.offset + n * qp->rq.wqe_size); 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic int set_reg_seg(struct pvrdma_sq_wqe_hdr *wqe_hdr, 64762306a36Sopenharmony_ci const struct ib_reg_wr *wr) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct pvrdma_user_mr *mr = to_vmr(wr->mr); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci wqe_hdr->wr.fast_reg.iova_start = mr->ibmr.iova; 65262306a36Sopenharmony_ci wqe_hdr->wr.fast_reg.pl_pdir_dma = mr->pdir.dir_dma; 65362306a36Sopenharmony_ci wqe_hdr->wr.fast_reg.page_shift = mr->page_shift; 65462306a36Sopenharmony_ci wqe_hdr->wr.fast_reg.page_list_len = mr->npages; 65562306a36Sopenharmony_ci wqe_hdr->wr.fast_reg.length = mr->ibmr.length; 65662306a36Sopenharmony_ci wqe_hdr->wr.fast_reg.access_flags = wr->access; 65762306a36Sopenharmony_ci wqe_hdr->wr.fast_reg.rkey = wr->key; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci return pvrdma_page_dir_insert_page_list(&mr->pdir, mr->pages, 66062306a36Sopenharmony_ci mr->npages); 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci/** 66462306a36Sopenharmony_ci * pvrdma_post_send - post send work request entries on a QP 66562306a36Sopenharmony_ci * @ibqp: the QP 66662306a36Sopenharmony_ci * @wr: work request list to post 66762306a36Sopenharmony_ci * @bad_wr: the first bad WR returned 66862306a36Sopenharmony_ci * 66962306a36Sopenharmony_ci * @return: 0 on success, otherwise errno returned. 67062306a36Sopenharmony_ci */ 67162306a36Sopenharmony_ciint pvrdma_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, 67262306a36Sopenharmony_ci const struct ib_send_wr **bad_wr) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct pvrdma_qp *qp = to_vqp(ibqp); 67562306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(ibqp->device); 67662306a36Sopenharmony_ci unsigned long flags; 67762306a36Sopenharmony_ci struct pvrdma_sq_wqe_hdr *wqe_hdr; 67862306a36Sopenharmony_ci struct pvrdma_sge *sge; 67962306a36Sopenharmony_ci int i, ret; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* 68262306a36Sopenharmony_ci * In states lower than RTS, we can fail immediately. In other states, 68362306a36Sopenharmony_ci * just post and let the device figure it out. 68462306a36Sopenharmony_ci */ 68562306a36Sopenharmony_ci if (qp->state < IB_QPS_RTS) { 68662306a36Sopenharmony_ci *bad_wr = wr; 68762306a36Sopenharmony_ci return -EINVAL; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci spin_lock_irqsave(&qp->sq.lock, flags); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci while (wr) { 69362306a36Sopenharmony_ci unsigned int tail = 0; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci if (unlikely(!pvrdma_idx_ring_has_space( 69662306a36Sopenharmony_ci qp->sq.ring, qp->sq.wqe_cnt, &tail))) { 69762306a36Sopenharmony_ci dev_warn_ratelimited(&dev->pdev->dev, 69862306a36Sopenharmony_ci "send queue is full\n"); 69962306a36Sopenharmony_ci *bad_wr = wr; 70062306a36Sopenharmony_ci ret = -ENOMEM; 70162306a36Sopenharmony_ci goto out; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (unlikely(wr->num_sge > qp->sq.max_sg || wr->num_sge < 0)) { 70562306a36Sopenharmony_ci dev_warn_ratelimited(&dev->pdev->dev, 70662306a36Sopenharmony_ci "send SGE overflow\n"); 70762306a36Sopenharmony_ci *bad_wr = wr; 70862306a36Sopenharmony_ci ret = -EINVAL; 70962306a36Sopenharmony_ci goto out; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* 71362306a36Sopenharmony_ci * Only support UD, RC. 71462306a36Sopenharmony_ci * Need to check opcode table for thorough checking. 71562306a36Sopenharmony_ci * opcode _UD _UC _RC 71662306a36Sopenharmony_ci * _SEND x x x 71762306a36Sopenharmony_ci * _SEND_WITH_IMM x x x 71862306a36Sopenharmony_ci * _RDMA_WRITE x x 71962306a36Sopenharmony_ci * _RDMA_WRITE_WITH_IMM x x 72062306a36Sopenharmony_ci * _LOCAL_INV x x 72162306a36Sopenharmony_ci * _SEND_WITH_INV x x 72262306a36Sopenharmony_ci * _RDMA_READ x 72362306a36Sopenharmony_ci * _ATOMIC_CMP_AND_SWP x 72462306a36Sopenharmony_ci * _ATOMIC_FETCH_AND_ADD x 72562306a36Sopenharmony_ci * _MASK_ATOMIC_CMP_AND_SWP x 72662306a36Sopenharmony_ci * _MASK_ATOMIC_FETCH_AND_ADD x 72762306a36Sopenharmony_ci * _REG_MR x 72862306a36Sopenharmony_ci * 72962306a36Sopenharmony_ci */ 73062306a36Sopenharmony_ci if (qp->ibqp.qp_type != IB_QPT_UD && 73162306a36Sopenharmony_ci qp->ibqp.qp_type != IB_QPT_RC && 73262306a36Sopenharmony_ci wr->opcode != IB_WR_SEND) { 73362306a36Sopenharmony_ci dev_warn_ratelimited(&dev->pdev->dev, 73462306a36Sopenharmony_ci "unsupported queuepair type\n"); 73562306a36Sopenharmony_ci *bad_wr = wr; 73662306a36Sopenharmony_ci ret = -EINVAL; 73762306a36Sopenharmony_ci goto out; 73862306a36Sopenharmony_ci } else if (qp->ibqp.qp_type == IB_QPT_UD || 73962306a36Sopenharmony_ci qp->ibqp.qp_type == IB_QPT_GSI) { 74062306a36Sopenharmony_ci if (wr->opcode != IB_WR_SEND && 74162306a36Sopenharmony_ci wr->opcode != IB_WR_SEND_WITH_IMM) { 74262306a36Sopenharmony_ci dev_warn_ratelimited(&dev->pdev->dev, 74362306a36Sopenharmony_ci "invalid send opcode\n"); 74462306a36Sopenharmony_ci *bad_wr = wr; 74562306a36Sopenharmony_ci ret = -EINVAL; 74662306a36Sopenharmony_ci goto out; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci wqe_hdr = (struct pvrdma_sq_wqe_hdr *)get_sq_wqe(qp, tail); 75162306a36Sopenharmony_ci memset(wqe_hdr, 0, sizeof(*wqe_hdr)); 75262306a36Sopenharmony_ci wqe_hdr->wr_id = wr->wr_id; 75362306a36Sopenharmony_ci wqe_hdr->num_sge = wr->num_sge; 75462306a36Sopenharmony_ci wqe_hdr->opcode = ib_wr_opcode_to_pvrdma(wr->opcode); 75562306a36Sopenharmony_ci wqe_hdr->send_flags = ib_send_flags_to_pvrdma(wr->send_flags); 75662306a36Sopenharmony_ci if (wr->opcode == IB_WR_SEND_WITH_IMM || 75762306a36Sopenharmony_ci wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) 75862306a36Sopenharmony_ci wqe_hdr->ex.imm_data = wr->ex.imm_data; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (unlikely(wqe_hdr->opcode == PVRDMA_WR_ERROR)) { 76162306a36Sopenharmony_ci *bad_wr = wr; 76262306a36Sopenharmony_ci ret = -EINVAL; 76362306a36Sopenharmony_ci goto out; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci switch (qp->ibqp.qp_type) { 76762306a36Sopenharmony_ci case IB_QPT_GSI: 76862306a36Sopenharmony_ci case IB_QPT_UD: 76962306a36Sopenharmony_ci if (unlikely(!ud_wr(wr)->ah)) { 77062306a36Sopenharmony_ci dev_warn_ratelimited(&dev->pdev->dev, 77162306a36Sopenharmony_ci "invalid address handle\n"); 77262306a36Sopenharmony_ci *bad_wr = wr; 77362306a36Sopenharmony_ci ret = -EINVAL; 77462306a36Sopenharmony_ci goto out; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* 77862306a36Sopenharmony_ci * Use qkey from qp context if high order bit set, 77962306a36Sopenharmony_ci * otherwise from work request. 78062306a36Sopenharmony_ci */ 78162306a36Sopenharmony_ci wqe_hdr->wr.ud.remote_qpn = ud_wr(wr)->remote_qpn; 78262306a36Sopenharmony_ci wqe_hdr->wr.ud.remote_qkey = 78362306a36Sopenharmony_ci ud_wr(wr)->remote_qkey & 0x80000000 ? 78462306a36Sopenharmony_ci qp->qkey : ud_wr(wr)->remote_qkey; 78562306a36Sopenharmony_ci wqe_hdr->wr.ud.av = to_vah(ud_wr(wr)->ah)->av; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci break; 78862306a36Sopenharmony_ci case IB_QPT_RC: 78962306a36Sopenharmony_ci switch (wr->opcode) { 79062306a36Sopenharmony_ci case IB_WR_RDMA_READ: 79162306a36Sopenharmony_ci case IB_WR_RDMA_WRITE: 79262306a36Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 79362306a36Sopenharmony_ci wqe_hdr->wr.rdma.remote_addr = 79462306a36Sopenharmony_ci rdma_wr(wr)->remote_addr; 79562306a36Sopenharmony_ci wqe_hdr->wr.rdma.rkey = rdma_wr(wr)->rkey; 79662306a36Sopenharmony_ci break; 79762306a36Sopenharmony_ci case IB_WR_LOCAL_INV: 79862306a36Sopenharmony_ci case IB_WR_SEND_WITH_INV: 79962306a36Sopenharmony_ci wqe_hdr->ex.invalidate_rkey = 80062306a36Sopenharmony_ci wr->ex.invalidate_rkey; 80162306a36Sopenharmony_ci break; 80262306a36Sopenharmony_ci case IB_WR_ATOMIC_CMP_AND_SWP: 80362306a36Sopenharmony_ci case IB_WR_ATOMIC_FETCH_AND_ADD: 80462306a36Sopenharmony_ci wqe_hdr->wr.atomic.remote_addr = 80562306a36Sopenharmony_ci atomic_wr(wr)->remote_addr; 80662306a36Sopenharmony_ci wqe_hdr->wr.atomic.rkey = atomic_wr(wr)->rkey; 80762306a36Sopenharmony_ci wqe_hdr->wr.atomic.compare_add = 80862306a36Sopenharmony_ci atomic_wr(wr)->compare_add; 80962306a36Sopenharmony_ci if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) 81062306a36Sopenharmony_ci wqe_hdr->wr.atomic.swap = 81162306a36Sopenharmony_ci atomic_wr(wr)->swap; 81262306a36Sopenharmony_ci break; 81362306a36Sopenharmony_ci case IB_WR_REG_MR: 81462306a36Sopenharmony_ci ret = set_reg_seg(wqe_hdr, reg_wr(wr)); 81562306a36Sopenharmony_ci if (ret < 0) { 81662306a36Sopenharmony_ci dev_warn_ratelimited(&dev->pdev->dev, 81762306a36Sopenharmony_ci "Failed to set fast register work request\n"); 81862306a36Sopenharmony_ci *bad_wr = wr; 81962306a36Sopenharmony_ci goto out; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci break; 82262306a36Sopenharmony_ci default: 82362306a36Sopenharmony_ci break; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci break; 82762306a36Sopenharmony_ci default: 82862306a36Sopenharmony_ci dev_warn_ratelimited(&dev->pdev->dev, 82962306a36Sopenharmony_ci "invalid queuepair type\n"); 83062306a36Sopenharmony_ci ret = -EINVAL; 83162306a36Sopenharmony_ci *bad_wr = wr; 83262306a36Sopenharmony_ci goto out; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci sge = (struct pvrdma_sge *)(wqe_hdr + 1); 83662306a36Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 83762306a36Sopenharmony_ci /* Need to check wqe_size 0 or max size */ 83862306a36Sopenharmony_ci sge->addr = wr->sg_list[i].addr; 83962306a36Sopenharmony_ci sge->length = wr->sg_list[i].length; 84062306a36Sopenharmony_ci sge->lkey = wr->sg_list[i].lkey; 84162306a36Sopenharmony_ci sge++; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci /* Make sure wqe is written before index update */ 84562306a36Sopenharmony_ci smp_wmb(); 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* Update shared sq ring */ 84862306a36Sopenharmony_ci pvrdma_idx_ring_inc(&qp->sq.ring->prod_tail, 84962306a36Sopenharmony_ci qp->sq.wqe_cnt); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci wr = wr->next; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci ret = 0; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ciout: 85762306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->sq.lock, flags); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (!ret) 86062306a36Sopenharmony_ci pvrdma_write_uar_qp(dev, PVRDMA_UAR_QP_SEND | qp->qp_handle); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return ret; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci/** 86662306a36Sopenharmony_ci * pvrdma_post_recv - post receive work request entries on a QP 86762306a36Sopenharmony_ci * @ibqp: the QP 86862306a36Sopenharmony_ci * @wr: the work request list to post 86962306a36Sopenharmony_ci * @bad_wr: the first bad WR returned 87062306a36Sopenharmony_ci * 87162306a36Sopenharmony_ci * @return: 0 on success, otherwise errno returned. 87262306a36Sopenharmony_ci */ 87362306a36Sopenharmony_ciint pvrdma_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, 87462306a36Sopenharmony_ci const struct ib_recv_wr **bad_wr) 87562306a36Sopenharmony_ci{ 87662306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(ibqp->device); 87762306a36Sopenharmony_ci unsigned long flags; 87862306a36Sopenharmony_ci struct pvrdma_qp *qp = to_vqp(ibqp); 87962306a36Sopenharmony_ci struct pvrdma_rq_wqe_hdr *wqe_hdr; 88062306a36Sopenharmony_ci struct pvrdma_sge *sge; 88162306a36Sopenharmony_ci int ret = 0; 88262306a36Sopenharmony_ci int i; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci /* 88562306a36Sopenharmony_ci * In the RESET state, we can fail immediately. For other states, 88662306a36Sopenharmony_ci * just post and let the device figure it out. 88762306a36Sopenharmony_ci */ 88862306a36Sopenharmony_ci if (qp->state == IB_QPS_RESET) { 88962306a36Sopenharmony_ci *bad_wr = wr; 89062306a36Sopenharmony_ci return -EINVAL; 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (qp->srq) { 89462306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, "QP associated with SRQ\n"); 89562306a36Sopenharmony_ci *bad_wr = wr; 89662306a36Sopenharmony_ci return -EINVAL; 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci spin_lock_irqsave(&qp->rq.lock, flags); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci while (wr) { 90262306a36Sopenharmony_ci unsigned int tail = 0; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (unlikely(wr->num_sge > qp->rq.max_sg || 90562306a36Sopenharmony_ci wr->num_sge < 0)) { 90662306a36Sopenharmony_ci ret = -EINVAL; 90762306a36Sopenharmony_ci *bad_wr = wr; 90862306a36Sopenharmony_ci dev_warn_ratelimited(&dev->pdev->dev, 90962306a36Sopenharmony_ci "recv SGE overflow\n"); 91062306a36Sopenharmony_ci goto out; 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (unlikely(!pvrdma_idx_ring_has_space( 91462306a36Sopenharmony_ci qp->rq.ring, qp->rq.wqe_cnt, &tail))) { 91562306a36Sopenharmony_ci ret = -ENOMEM; 91662306a36Sopenharmony_ci *bad_wr = wr; 91762306a36Sopenharmony_ci dev_warn_ratelimited(&dev->pdev->dev, 91862306a36Sopenharmony_ci "recv queue full\n"); 91962306a36Sopenharmony_ci goto out; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci wqe_hdr = (struct pvrdma_rq_wqe_hdr *)get_rq_wqe(qp, tail); 92362306a36Sopenharmony_ci wqe_hdr->wr_id = wr->wr_id; 92462306a36Sopenharmony_ci wqe_hdr->num_sge = wr->num_sge; 92562306a36Sopenharmony_ci wqe_hdr->total_len = 0; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci sge = (struct pvrdma_sge *)(wqe_hdr + 1); 92862306a36Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 92962306a36Sopenharmony_ci sge->addr = wr->sg_list[i].addr; 93062306a36Sopenharmony_ci sge->length = wr->sg_list[i].length; 93162306a36Sopenharmony_ci sge->lkey = wr->sg_list[i].lkey; 93262306a36Sopenharmony_ci sge++; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci /* Make sure wqe is written before index update */ 93662306a36Sopenharmony_ci smp_wmb(); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci /* Update shared rq ring */ 93962306a36Sopenharmony_ci pvrdma_idx_ring_inc(&qp->rq.ring->prod_tail, 94062306a36Sopenharmony_ci qp->rq.wqe_cnt); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci wr = wr->next; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->rq.lock, flags); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci pvrdma_write_uar_qp(dev, PVRDMA_UAR_QP_RECV | qp->qp_handle); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci return ret; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ciout: 95262306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->rq.lock, flags); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci return ret; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci/** 95862306a36Sopenharmony_ci * pvrdma_query_qp - query a queue pair's attributes 95962306a36Sopenharmony_ci * @ibqp: the queue pair to query 96062306a36Sopenharmony_ci * @attr: the queue pair's attributes 96162306a36Sopenharmony_ci * @attr_mask: attributes mask 96262306a36Sopenharmony_ci * @init_attr: initial queue pair attributes 96362306a36Sopenharmony_ci * 96462306a36Sopenharmony_ci * @returns 0 on success, otherwise returns an errno. 96562306a36Sopenharmony_ci */ 96662306a36Sopenharmony_ciint pvrdma_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 96762306a36Sopenharmony_ci int attr_mask, struct ib_qp_init_attr *init_attr) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci struct pvrdma_dev *dev = to_vdev(ibqp->device); 97062306a36Sopenharmony_ci struct pvrdma_qp *qp = to_vqp(ibqp); 97162306a36Sopenharmony_ci union pvrdma_cmd_req req; 97262306a36Sopenharmony_ci union pvrdma_cmd_resp rsp; 97362306a36Sopenharmony_ci struct pvrdma_cmd_query_qp *cmd = &req.query_qp; 97462306a36Sopenharmony_ci struct pvrdma_cmd_query_qp_resp *resp = &rsp.query_qp_resp; 97562306a36Sopenharmony_ci int ret = 0; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci mutex_lock(&qp->mutex); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci if (qp->state == IB_QPS_RESET) { 98062306a36Sopenharmony_ci attr->qp_state = IB_QPS_RESET; 98162306a36Sopenharmony_ci goto out; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci memset(cmd, 0, sizeof(*cmd)); 98562306a36Sopenharmony_ci cmd->hdr.cmd = PVRDMA_CMD_QUERY_QP; 98662306a36Sopenharmony_ci cmd->qp_handle = qp->qp_handle; 98762306a36Sopenharmony_ci cmd->attr_mask = ib_qp_attr_mask_to_pvrdma(attr_mask); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_QUERY_QP_RESP); 99062306a36Sopenharmony_ci if (ret < 0) { 99162306a36Sopenharmony_ci dev_warn(&dev->pdev->dev, 99262306a36Sopenharmony_ci "could not query queuepair, error: %d\n", ret); 99362306a36Sopenharmony_ci goto out; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci attr->qp_state = pvrdma_qp_state_to_ib(resp->attrs.qp_state); 99762306a36Sopenharmony_ci attr->cur_qp_state = 99862306a36Sopenharmony_ci pvrdma_qp_state_to_ib(resp->attrs.cur_qp_state); 99962306a36Sopenharmony_ci attr->path_mtu = pvrdma_mtu_to_ib(resp->attrs.path_mtu); 100062306a36Sopenharmony_ci attr->path_mig_state = 100162306a36Sopenharmony_ci pvrdma_mig_state_to_ib(resp->attrs.path_mig_state); 100262306a36Sopenharmony_ci attr->qkey = resp->attrs.qkey; 100362306a36Sopenharmony_ci attr->rq_psn = resp->attrs.rq_psn; 100462306a36Sopenharmony_ci attr->sq_psn = resp->attrs.sq_psn; 100562306a36Sopenharmony_ci attr->dest_qp_num = resp->attrs.dest_qp_num; 100662306a36Sopenharmony_ci attr->qp_access_flags = 100762306a36Sopenharmony_ci pvrdma_access_flags_to_ib(resp->attrs.qp_access_flags); 100862306a36Sopenharmony_ci attr->pkey_index = resp->attrs.pkey_index; 100962306a36Sopenharmony_ci attr->alt_pkey_index = resp->attrs.alt_pkey_index; 101062306a36Sopenharmony_ci attr->en_sqd_async_notify = resp->attrs.en_sqd_async_notify; 101162306a36Sopenharmony_ci attr->sq_draining = resp->attrs.sq_draining; 101262306a36Sopenharmony_ci attr->max_rd_atomic = resp->attrs.max_rd_atomic; 101362306a36Sopenharmony_ci attr->max_dest_rd_atomic = resp->attrs.max_dest_rd_atomic; 101462306a36Sopenharmony_ci attr->min_rnr_timer = resp->attrs.min_rnr_timer; 101562306a36Sopenharmony_ci attr->port_num = resp->attrs.port_num; 101662306a36Sopenharmony_ci attr->timeout = resp->attrs.timeout; 101762306a36Sopenharmony_ci attr->retry_cnt = resp->attrs.retry_cnt; 101862306a36Sopenharmony_ci attr->rnr_retry = resp->attrs.rnr_retry; 101962306a36Sopenharmony_ci attr->alt_port_num = resp->attrs.alt_port_num; 102062306a36Sopenharmony_ci attr->alt_timeout = resp->attrs.alt_timeout; 102162306a36Sopenharmony_ci pvrdma_qp_cap_to_ib(&attr->cap, &resp->attrs.cap); 102262306a36Sopenharmony_ci pvrdma_ah_attr_to_rdma(&attr->ah_attr, &resp->attrs.ah_attr); 102362306a36Sopenharmony_ci pvrdma_ah_attr_to_rdma(&attr->alt_ah_attr, &resp->attrs.alt_ah_attr); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci qp->state = attr->qp_state; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci ret = 0; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ciout: 103062306a36Sopenharmony_ci attr->cur_qp_state = attr->qp_state; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci init_attr->event_handler = qp->ibqp.event_handler; 103362306a36Sopenharmony_ci init_attr->qp_context = qp->ibqp.qp_context; 103462306a36Sopenharmony_ci init_attr->send_cq = qp->ibqp.send_cq; 103562306a36Sopenharmony_ci init_attr->recv_cq = qp->ibqp.recv_cq; 103662306a36Sopenharmony_ci init_attr->srq = qp->ibqp.srq; 103762306a36Sopenharmony_ci init_attr->xrcd = NULL; 103862306a36Sopenharmony_ci init_attr->cap = attr->cap; 103962306a36Sopenharmony_ci init_attr->sq_sig_type = 0; 104062306a36Sopenharmony_ci init_attr->qp_type = qp->ibqp.qp_type; 104162306a36Sopenharmony_ci init_attr->create_flags = 0; 104262306a36Sopenharmony_ci init_attr->port_num = qp->port; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci mutex_unlock(&qp->mutex); 104562306a36Sopenharmony_ci return ret; 104662306a36Sopenharmony_ci} 1047