162306a36Sopenharmony_ci/* QLogic qedr NIC Driver 262306a36Sopenharmony_ci * Copyright (c) 2015-2016 QLogic Corporation 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and /or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci#include <linux/dma-mapping.h> 3362306a36Sopenharmony_ci#include <linux/crc32.h> 3462306a36Sopenharmony_ci#include <net/ip.h> 3562306a36Sopenharmony_ci#include <net/ipv6.h> 3662306a36Sopenharmony_ci#include <net/udp.h> 3762306a36Sopenharmony_ci#include <linux/iommu.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 4062306a36Sopenharmony_ci#include <rdma/ib_user_verbs.h> 4162306a36Sopenharmony_ci#include <rdma/iw_cm.h> 4262306a36Sopenharmony_ci#include <rdma/ib_umem.h> 4362306a36Sopenharmony_ci#include <rdma/ib_addr.h> 4462306a36Sopenharmony_ci#include <rdma/ib_cache.h> 4562306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include <linux/qed/common_hsi.h> 4862306a36Sopenharmony_ci#include "qedr_hsi_rdma.h" 4962306a36Sopenharmony_ci#include <linux/qed/qed_if.h> 5062306a36Sopenharmony_ci#include "qedr.h" 5162306a36Sopenharmony_ci#include "verbs.h" 5262306a36Sopenharmony_ci#include <rdma/qedr-abi.h> 5362306a36Sopenharmony_ci#include "qedr_roce_cm.h" 5462306a36Sopenharmony_ci#include "qedr_iw_cm.h" 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define QEDR_SRQ_WQE_ELEM_SIZE sizeof(union rdma_srq_elm) 5762306a36Sopenharmony_ci#define RDMA_MAX_SGE_PER_SRQ (4) 5862306a36Sopenharmony_ci#define RDMA_MAX_SRQ_WQE_SIZE (RDMA_MAX_SGE_PER_SRQ + 1) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define DB_ADDR_SHIFT(addr) ((addr) << DB_PWM_ADDR_OFFSET_SHIFT) 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cienum { 6362306a36Sopenharmony_ci QEDR_USER_MMAP_IO_WC = 0, 6462306a36Sopenharmony_ci QEDR_USER_MMAP_PHYS_PAGE, 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic inline int qedr_ib_copy_to_udata(struct ib_udata *udata, void *src, 6862306a36Sopenharmony_ci size_t len) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci size_t min_len = min_t(size_t, len, udata->outlen); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return ib_copy_to_udata(udata, src, min_len); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciint qedr_query_pkey(struct ib_device *ibdev, u32 port, u16 index, u16 *pkey) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci if (index >= QEDR_ROCE_PKEY_TABLE_LEN) 7862306a36Sopenharmony_ci return -EINVAL; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci *pkey = QEDR_ROCE_PKEY_DEFAULT; 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciint qedr_iw_query_gid(struct ib_device *ibdev, u32 port, 8562306a36Sopenharmony_ci int index, union ib_gid *sgid) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibdev); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci memset(sgid->raw, 0, sizeof(sgid->raw)); 9062306a36Sopenharmony_ci ether_addr_copy(sgid->raw, dev->ndev->dev_addr); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "QUERY sgid[%d]=%llx:%llx\n", index, 9362306a36Sopenharmony_ci sgid->global.interface_id, sgid->global.subnet_prefix); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ciint qedr_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibsrq->device); 10162306a36Sopenharmony_ci struct qedr_device_attr *qattr = &dev->attr; 10262306a36Sopenharmony_ci struct qedr_srq *srq = get_qedr_srq(ibsrq); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci srq_attr->srq_limit = srq->srq_limit; 10562306a36Sopenharmony_ci srq_attr->max_wr = qattr->max_srq_wr; 10662306a36Sopenharmony_ci srq_attr->max_sge = qattr->max_sge; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ciint qedr_query_device(struct ib_device *ibdev, 11262306a36Sopenharmony_ci struct ib_device_attr *attr, struct ib_udata *udata) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibdev); 11562306a36Sopenharmony_ci struct qedr_device_attr *qattr = &dev->attr; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (!dev->rdma_ctx) { 11862306a36Sopenharmony_ci DP_ERR(dev, 11962306a36Sopenharmony_ci "qedr_query_device called with invalid params rdma_ctx=%p\n", 12062306a36Sopenharmony_ci dev->rdma_ctx); 12162306a36Sopenharmony_ci return -EINVAL; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci memset(attr, 0, sizeof(*attr)); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci attr->fw_ver = qattr->fw_ver; 12762306a36Sopenharmony_ci attr->sys_image_guid = qattr->sys_image_guid; 12862306a36Sopenharmony_ci attr->max_mr_size = qattr->max_mr_size; 12962306a36Sopenharmony_ci attr->page_size_cap = qattr->page_size_caps; 13062306a36Sopenharmony_ci attr->vendor_id = qattr->vendor_id; 13162306a36Sopenharmony_ci attr->vendor_part_id = qattr->vendor_part_id; 13262306a36Sopenharmony_ci attr->hw_ver = qattr->hw_ver; 13362306a36Sopenharmony_ci attr->max_qp = qattr->max_qp; 13462306a36Sopenharmony_ci attr->max_qp_wr = max_t(u32, qattr->max_sqe, qattr->max_rqe); 13562306a36Sopenharmony_ci attr->device_cap_flags = IB_DEVICE_CURR_QP_STATE_MOD | 13662306a36Sopenharmony_ci IB_DEVICE_RC_RNR_NAK_GEN | 13762306a36Sopenharmony_ci IB_DEVICE_MEM_MGT_EXTENSIONS; 13862306a36Sopenharmony_ci attr->kernel_cap_flags = IBK_LOCAL_DMA_LKEY; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (!rdma_protocol_iwarp(&dev->ibdev, 1)) 14162306a36Sopenharmony_ci attr->device_cap_flags |= IB_DEVICE_XRC; 14262306a36Sopenharmony_ci attr->max_send_sge = qattr->max_sge; 14362306a36Sopenharmony_ci attr->max_recv_sge = qattr->max_sge; 14462306a36Sopenharmony_ci attr->max_sge_rd = qattr->max_sge; 14562306a36Sopenharmony_ci attr->max_cq = qattr->max_cq; 14662306a36Sopenharmony_ci attr->max_cqe = qattr->max_cqe; 14762306a36Sopenharmony_ci attr->max_mr = qattr->max_mr; 14862306a36Sopenharmony_ci attr->max_mw = qattr->max_mw; 14962306a36Sopenharmony_ci attr->max_pd = qattr->max_pd; 15062306a36Sopenharmony_ci attr->atomic_cap = dev->atomic_cap; 15162306a36Sopenharmony_ci attr->max_qp_init_rd_atom = 15262306a36Sopenharmony_ci 1 << (fls(qattr->max_qp_req_rd_atomic_resc) - 1); 15362306a36Sopenharmony_ci attr->max_qp_rd_atom = 15462306a36Sopenharmony_ci min(1 << (fls(qattr->max_qp_resp_rd_atomic_resc) - 1), 15562306a36Sopenharmony_ci attr->max_qp_init_rd_atom); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci attr->max_srq = qattr->max_srq; 15862306a36Sopenharmony_ci attr->max_srq_sge = qattr->max_srq_sge; 15962306a36Sopenharmony_ci attr->max_srq_wr = qattr->max_srq_wr; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci attr->local_ca_ack_delay = qattr->dev_ack_delay; 16262306a36Sopenharmony_ci attr->max_fast_reg_page_list_len = qattr->max_mr / 8; 16362306a36Sopenharmony_ci attr->max_pkeys = qattr->max_pkey; 16462306a36Sopenharmony_ci attr->max_ah = qattr->max_ah; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic inline void get_link_speed_and_width(int speed, u16 *ib_speed, 17062306a36Sopenharmony_ci u8 *ib_width) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci switch (speed) { 17362306a36Sopenharmony_ci case 1000: 17462306a36Sopenharmony_ci *ib_speed = IB_SPEED_SDR; 17562306a36Sopenharmony_ci *ib_width = IB_WIDTH_1X; 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci case 10000: 17862306a36Sopenharmony_ci *ib_speed = IB_SPEED_QDR; 17962306a36Sopenharmony_ci *ib_width = IB_WIDTH_1X; 18062306a36Sopenharmony_ci break; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci case 20000: 18362306a36Sopenharmony_ci *ib_speed = IB_SPEED_DDR; 18462306a36Sopenharmony_ci *ib_width = IB_WIDTH_4X; 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci case 25000: 18862306a36Sopenharmony_ci *ib_speed = IB_SPEED_EDR; 18962306a36Sopenharmony_ci *ib_width = IB_WIDTH_1X; 19062306a36Sopenharmony_ci break; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci case 40000: 19362306a36Sopenharmony_ci *ib_speed = IB_SPEED_QDR; 19462306a36Sopenharmony_ci *ib_width = IB_WIDTH_4X; 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci case 50000: 19862306a36Sopenharmony_ci *ib_speed = IB_SPEED_HDR; 19962306a36Sopenharmony_ci *ib_width = IB_WIDTH_1X; 20062306a36Sopenharmony_ci break; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci case 100000: 20362306a36Sopenharmony_ci *ib_speed = IB_SPEED_EDR; 20462306a36Sopenharmony_ci *ib_width = IB_WIDTH_4X; 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci default: 20862306a36Sopenharmony_ci /* Unsupported */ 20962306a36Sopenharmony_ci *ib_speed = IB_SPEED_SDR; 21062306a36Sopenharmony_ci *ib_width = IB_WIDTH_1X; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ciint qedr_query_port(struct ib_device *ibdev, u32 port, 21562306a36Sopenharmony_ci struct ib_port_attr *attr) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct qedr_dev *dev; 21862306a36Sopenharmony_ci struct qed_rdma_port *rdma_port; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci dev = get_qedr_dev(ibdev); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (!dev->rdma_ctx) { 22362306a36Sopenharmony_ci DP_ERR(dev, "rdma_ctx is NULL\n"); 22462306a36Sopenharmony_ci return -EINVAL; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci rdma_port = dev->ops->rdma_query_port(dev->rdma_ctx); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* *attr being zeroed by the caller, avoid zeroing it here */ 23062306a36Sopenharmony_ci if (rdma_port->port_state == QED_RDMA_PORT_UP) { 23162306a36Sopenharmony_ci attr->state = IB_PORT_ACTIVE; 23262306a36Sopenharmony_ci attr->phys_state = IB_PORT_PHYS_STATE_LINK_UP; 23362306a36Sopenharmony_ci } else { 23462306a36Sopenharmony_ci attr->state = IB_PORT_DOWN; 23562306a36Sopenharmony_ci attr->phys_state = IB_PORT_PHYS_STATE_DISABLED; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci attr->max_mtu = IB_MTU_4096; 23862306a36Sopenharmony_ci attr->lid = 0; 23962306a36Sopenharmony_ci attr->lmc = 0; 24062306a36Sopenharmony_ci attr->sm_lid = 0; 24162306a36Sopenharmony_ci attr->sm_sl = 0; 24262306a36Sopenharmony_ci attr->ip_gids = true; 24362306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) { 24462306a36Sopenharmony_ci attr->active_mtu = iboe_get_mtu(dev->iwarp_max_mtu); 24562306a36Sopenharmony_ci attr->gid_tbl_len = 1; 24662306a36Sopenharmony_ci } else { 24762306a36Sopenharmony_ci attr->active_mtu = iboe_get_mtu(dev->ndev->mtu); 24862306a36Sopenharmony_ci attr->gid_tbl_len = QEDR_MAX_SGID; 24962306a36Sopenharmony_ci attr->pkey_tbl_len = QEDR_ROCE_PKEY_TABLE_LEN; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci attr->bad_pkey_cntr = rdma_port->pkey_bad_counter; 25262306a36Sopenharmony_ci attr->qkey_viol_cntr = 0; 25362306a36Sopenharmony_ci get_link_speed_and_width(rdma_port->link_speed, 25462306a36Sopenharmony_ci &attr->active_speed, &attr->active_width); 25562306a36Sopenharmony_ci attr->max_msg_sz = rdma_port->max_msg_size; 25662306a36Sopenharmony_ci attr->max_vl_num = 4; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ciint qedr_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct ib_device *ibdev = uctx->device; 26462306a36Sopenharmony_ci int rc; 26562306a36Sopenharmony_ci struct qedr_ucontext *ctx = get_qedr_ucontext(uctx); 26662306a36Sopenharmony_ci struct qedr_alloc_ucontext_resp uresp = {}; 26762306a36Sopenharmony_ci struct qedr_alloc_ucontext_req ureq = {}; 26862306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibdev); 26962306a36Sopenharmony_ci struct qed_rdma_add_user_out_params oparams; 27062306a36Sopenharmony_ci struct qedr_user_mmap_entry *entry; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (!udata) 27362306a36Sopenharmony_ci return -EFAULT; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (udata->inlen) { 27662306a36Sopenharmony_ci rc = ib_copy_from_udata(&ureq, udata, 27762306a36Sopenharmony_ci min(sizeof(ureq), udata->inlen)); 27862306a36Sopenharmony_ci if (rc) { 27962306a36Sopenharmony_ci DP_ERR(dev, "Problem copying data from user space\n"); 28062306a36Sopenharmony_ci return -EFAULT; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci ctx->edpm_mode = !!(ureq.context_flags & 28362306a36Sopenharmony_ci QEDR_ALLOC_UCTX_EDPM_MODE); 28462306a36Sopenharmony_ci ctx->db_rec = !!(ureq.context_flags & QEDR_ALLOC_UCTX_DB_REC); 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci rc = dev->ops->rdma_add_user(dev->rdma_ctx, &oparams); 28862306a36Sopenharmony_ci if (rc) { 28962306a36Sopenharmony_ci DP_ERR(dev, 29062306a36Sopenharmony_ci "failed to allocate a DPI for a new RoCE application, rc=%d. To overcome this consider to increase the number of DPIs, increase the doorbell BAR size or just close unnecessary RoCE applications. In order to increase the number of DPIs consult the qedr readme\n", 29162306a36Sopenharmony_ci rc); 29262306a36Sopenharmony_ci return rc; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci ctx->dpi = oparams.dpi; 29662306a36Sopenharmony_ci ctx->dpi_addr = oparams.dpi_addr; 29762306a36Sopenharmony_ci ctx->dpi_phys_addr = oparams.dpi_phys_addr; 29862306a36Sopenharmony_ci ctx->dpi_size = oparams.dpi_size; 29962306a36Sopenharmony_ci entry = kzalloc(sizeof(*entry), GFP_KERNEL); 30062306a36Sopenharmony_ci if (!entry) { 30162306a36Sopenharmony_ci rc = -ENOMEM; 30262306a36Sopenharmony_ci goto err; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci entry->io_address = ctx->dpi_phys_addr; 30662306a36Sopenharmony_ci entry->length = ctx->dpi_size; 30762306a36Sopenharmony_ci entry->mmap_flag = QEDR_USER_MMAP_IO_WC; 30862306a36Sopenharmony_ci entry->dpi = ctx->dpi; 30962306a36Sopenharmony_ci entry->dev = dev; 31062306a36Sopenharmony_ci rc = rdma_user_mmap_entry_insert(uctx, &entry->rdma_entry, 31162306a36Sopenharmony_ci ctx->dpi_size); 31262306a36Sopenharmony_ci if (rc) { 31362306a36Sopenharmony_ci kfree(entry); 31462306a36Sopenharmony_ci goto err; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci ctx->db_mmap_entry = &entry->rdma_entry; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (!dev->user_dpm_enabled) 31962306a36Sopenharmony_ci uresp.dpm_flags = 0; 32062306a36Sopenharmony_ci else if (rdma_protocol_iwarp(&dev->ibdev, 1)) 32162306a36Sopenharmony_ci uresp.dpm_flags = QEDR_DPM_TYPE_IWARP_LEGACY; 32262306a36Sopenharmony_ci else 32362306a36Sopenharmony_ci uresp.dpm_flags = QEDR_DPM_TYPE_ROCE_ENHANCED | 32462306a36Sopenharmony_ci QEDR_DPM_TYPE_ROCE_LEGACY | 32562306a36Sopenharmony_ci QEDR_DPM_TYPE_ROCE_EDPM_MODE; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (ureq.context_flags & QEDR_SUPPORT_DPM_SIZES) { 32862306a36Sopenharmony_ci uresp.dpm_flags |= QEDR_DPM_SIZES_SET; 32962306a36Sopenharmony_ci uresp.ldpm_limit_size = QEDR_LDPM_MAX_SIZE; 33062306a36Sopenharmony_ci uresp.edpm_trans_size = QEDR_EDPM_TRANS_SIZE; 33162306a36Sopenharmony_ci uresp.edpm_limit_size = QEDR_EDPM_MAX_SIZE; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci uresp.wids_enabled = 1; 33562306a36Sopenharmony_ci uresp.wid_count = oparams.wid_count; 33662306a36Sopenharmony_ci uresp.db_pa = rdma_user_mmap_get_offset(ctx->db_mmap_entry); 33762306a36Sopenharmony_ci uresp.db_size = ctx->dpi_size; 33862306a36Sopenharmony_ci uresp.max_send_wr = dev->attr.max_sqe; 33962306a36Sopenharmony_ci uresp.max_recv_wr = dev->attr.max_rqe; 34062306a36Sopenharmony_ci uresp.max_srq_wr = dev->attr.max_srq_wr; 34162306a36Sopenharmony_ci uresp.sges_per_send_wr = QEDR_MAX_SQE_ELEMENTS_PER_SQE; 34262306a36Sopenharmony_ci uresp.sges_per_recv_wr = QEDR_MAX_RQE_ELEMENTS_PER_RQE; 34362306a36Sopenharmony_ci uresp.sges_per_srq_wr = dev->attr.max_srq_sge; 34462306a36Sopenharmony_ci uresp.max_cqes = QEDR_MAX_CQES; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci rc = qedr_ib_copy_to_udata(udata, &uresp, sizeof(uresp)); 34762306a36Sopenharmony_ci if (rc) 34862306a36Sopenharmony_ci goto err; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci ctx->dev = dev; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "Allocating user context %p\n", 35362306a36Sopenharmony_ci &ctx->ibucontext); 35462306a36Sopenharmony_ci return 0; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cierr: 35762306a36Sopenharmony_ci if (!ctx->db_mmap_entry) 35862306a36Sopenharmony_ci dev->ops->rdma_remove_user(dev->rdma_ctx, ctx->dpi); 35962306a36Sopenharmony_ci else 36062306a36Sopenharmony_ci rdma_user_mmap_entry_remove(ctx->db_mmap_entry); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return rc; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_civoid qedr_dealloc_ucontext(struct ib_ucontext *ibctx) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci struct qedr_ucontext *uctx = get_qedr_ucontext(ibctx); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci DP_DEBUG(uctx->dev, QEDR_MSG_INIT, "Deallocating user context %p\n", 37062306a36Sopenharmony_ci uctx); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci rdma_user_mmap_entry_remove(uctx->db_mmap_entry); 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_civoid qedr_mmap_free(struct rdma_user_mmap_entry *rdma_entry) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct qedr_user_mmap_entry *entry = get_qedr_mmap_entry(rdma_entry); 37862306a36Sopenharmony_ci struct qedr_dev *dev = entry->dev; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (entry->mmap_flag == QEDR_USER_MMAP_PHYS_PAGE) 38162306a36Sopenharmony_ci free_page((unsigned long)entry->address); 38262306a36Sopenharmony_ci else if (entry->mmap_flag == QEDR_USER_MMAP_IO_WC) 38362306a36Sopenharmony_ci dev->ops->rdma_remove_user(dev->rdma_ctx, entry->dpi); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci kfree(entry); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ciint qedr_mmap(struct ib_ucontext *ucontext, struct vm_area_struct *vma) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct ib_device *dev = ucontext->device; 39162306a36Sopenharmony_ci size_t length = vma->vm_end - vma->vm_start; 39262306a36Sopenharmony_ci struct rdma_user_mmap_entry *rdma_entry; 39362306a36Sopenharmony_ci struct qedr_user_mmap_entry *entry; 39462306a36Sopenharmony_ci int rc = 0; 39562306a36Sopenharmony_ci u64 pfn; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci ibdev_dbg(dev, 39862306a36Sopenharmony_ci "start %#lx, end %#lx, length = %#zx, pgoff = %#lx\n", 39962306a36Sopenharmony_ci vma->vm_start, vma->vm_end, length, vma->vm_pgoff); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci rdma_entry = rdma_user_mmap_entry_get(ucontext, vma); 40262306a36Sopenharmony_ci if (!rdma_entry) { 40362306a36Sopenharmony_ci ibdev_dbg(dev, "pgoff[%#lx] does not have valid entry\n", 40462306a36Sopenharmony_ci vma->vm_pgoff); 40562306a36Sopenharmony_ci return -EINVAL; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci entry = get_qedr_mmap_entry(rdma_entry); 40862306a36Sopenharmony_ci ibdev_dbg(dev, 40962306a36Sopenharmony_ci "Mapping address[%#llx], length[%#zx], mmap_flag[%d]\n", 41062306a36Sopenharmony_ci entry->io_address, length, entry->mmap_flag); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci switch (entry->mmap_flag) { 41362306a36Sopenharmony_ci case QEDR_USER_MMAP_IO_WC: 41462306a36Sopenharmony_ci pfn = entry->io_address >> PAGE_SHIFT; 41562306a36Sopenharmony_ci rc = rdma_user_mmap_io(ucontext, vma, pfn, length, 41662306a36Sopenharmony_ci pgprot_writecombine(vma->vm_page_prot), 41762306a36Sopenharmony_ci rdma_entry); 41862306a36Sopenharmony_ci break; 41962306a36Sopenharmony_ci case QEDR_USER_MMAP_PHYS_PAGE: 42062306a36Sopenharmony_ci rc = vm_insert_page(vma, vma->vm_start, 42162306a36Sopenharmony_ci virt_to_page(entry->address)); 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci default: 42462306a36Sopenharmony_ci rc = -EINVAL; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (rc) 42862306a36Sopenharmony_ci ibdev_dbg(dev, 42962306a36Sopenharmony_ci "Couldn't mmap address[%#llx] length[%#zx] mmap_flag[%d] err[%d]\n", 43062306a36Sopenharmony_ci entry->io_address, length, entry->mmap_flag, rc); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci rdma_user_mmap_entry_put(rdma_entry); 43362306a36Sopenharmony_ci return rc; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ciint qedr_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct ib_device *ibdev = ibpd->device; 43962306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibdev); 44062306a36Sopenharmony_ci struct qedr_pd *pd = get_qedr_pd(ibpd); 44162306a36Sopenharmony_ci u16 pd_id; 44262306a36Sopenharmony_ci int rc; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "Function called from: %s\n", 44562306a36Sopenharmony_ci udata ? "User Lib" : "Kernel"); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (!dev->rdma_ctx) { 44862306a36Sopenharmony_ci DP_ERR(dev, "invalid RDMA context\n"); 44962306a36Sopenharmony_ci return -EINVAL; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci rc = dev->ops->rdma_alloc_pd(dev->rdma_ctx, &pd_id); 45362306a36Sopenharmony_ci if (rc) 45462306a36Sopenharmony_ci return rc; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci pd->pd_id = pd_id; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (udata) { 45962306a36Sopenharmony_ci struct qedr_alloc_pd_uresp uresp = { 46062306a36Sopenharmony_ci .pd_id = pd_id, 46162306a36Sopenharmony_ci }; 46262306a36Sopenharmony_ci struct qedr_ucontext *context = rdma_udata_to_drv_context( 46362306a36Sopenharmony_ci udata, struct qedr_ucontext, ibucontext); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci rc = qedr_ib_copy_to_udata(udata, &uresp, sizeof(uresp)); 46662306a36Sopenharmony_ci if (rc) { 46762306a36Sopenharmony_ci DP_ERR(dev, "copy error pd_id=0x%x.\n", pd_id); 46862306a36Sopenharmony_ci dev->ops->rdma_dealloc_pd(dev->rdma_ctx, pd_id); 46962306a36Sopenharmony_ci return rc; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci pd->uctx = context; 47362306a36Sopenharmony_ci pd->uctx->pd = pd; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return 0; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ciint qedr_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibpd->device); 48262306a36Sopenharmony_ci struct qedr_pd *pd = get_qedr_pd(ibpd); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "Deallocating PD %d\n", pd->pd_id); 48562306a36Sopenharmony_ci dev->ops->rdma_dealloc_pd(dev->rdma_ctx, pd->pd_id); 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ciint qedr_alloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibxrcd->device); 49362306a36Sopenharmony_ci struct qedr_xrcd *xrcd = get_qedr_xrcd(ibxrcd); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return dev->ops->rdma_alloc_xrcd(dev->rdma_ctx, &xrcd->xrcd_id); 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ciint qedr_dealloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibxrcd->device); 50162306a36Sopenharmony_ci u16 xrcd_id = get_qedr_xrcd(ibxrcd)->xrcd_id; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci dev->ops->rdma_dealloc_xrcd(dev->rdma_ctx, xrcd_id); 50462306a36Sopenharmony_ci return 0; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_cistatic void qedr_free_pbl(struct qedr_dev *dev, 50762306a36Sopenharmony_ci struct qedr_pbl_info *pbl_info, struct qedr_pbl *pbl) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci struct pci_dev *pdev = dev->pdev; 51062306a36Sopenharmony_ci int i; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci for (i = 0; i < pbl_info->num_pbls; i++) { 51362306a36Sopenharmony_ci if (!pbl[i].va) 51462306a36Sopenharmony_ci continue; 51562306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, pbl_info->pbl_size, 51662306a36Sopenharmony_ci pbl[i].va, pbl[i].pa); 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci kfree(pbl); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci#define MIN_FW_PBL_PAGE_SIZE (4 * 1024) 52362306a36Sopenharmony_ci#define MAX_FW_PBL_PAGE_SIZE (64 * 1024) 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci#define NUM_PBES_ON_PAGE(_page_size) (_page_size / sizeof(u64)) 52662306a36Sopenharmony_ci#define MAX_PBES_ON_PAGE NUM_PBES_ON_PAGE(MAX_FW_PBL_PAGE_SIZE) 52762306a36Sopenharmony_ci#define MAX_PBES_TWO_LAYER (MAX_PBES_ON_PAGE * MAX_PBES_ON_PAGE) 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic struct qedr_pbl *qedr_alloc_pbl_tbl(struct qedr_dev *dev, 53062306a36Sopenharmony_ci struct qedr_pbl_info *pbl_info, 53162306a36Sopenharmony_ci gfp_t flags) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci struct pci_dev *pdev = dev->pdev; 53462306a36Sopenharmony_ci struct qedr_pbl *pbl_table; 53562306a36Sopenharmony_ci dma_addr_t *pbl_main_tbl; 53662306a36Sopenharmony_ci dma_addr_t pa; 53762306a36Sopenharmony_ci void *va; 53862306a36Sopenharmony_ci int i; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci pbl_table = kcalloc(pbl_info->num_pbls, sizeof(*pbl_table), flags); 54162306a36Sopenharmony_ci if (!pbl_table) 54262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci for (i = 0; i < pbl_info->num_pbls; i++) { 54562306a36Sopenharmony_ci va = dma_alloc_coherent(&pdev->dev, pbl_info->pbl_size, &pa, 54662306a36Sopenharmony_ci flags); 54762306a36Sopenharmony_ci if (!va) 54862306a36Sopenharmony_ci goto err; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci pbl_table[i].va = va; 55162306a36Sopenharmony_ci pbl_table[i].pa = pa; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* Two-Layer PBLs, if we have more than one pbl we need to initialize 55562306a36Sopenharmony_ci * the first one with physical pointers to all of the rest 55662306a36Sopenharmony_ci */ 55762306a36Sopenharmony_ci pbl_main_tbl = (dma_addr_t *)pbl_table[0].va; 55862306a36Sopenharmony_ci for (i = 0; i < pbl_info->num_pbls - 1; i++) 55962306a36Sopenharmony_ci pbl_main_tbl[i] = pbl_table[i + 1].pa; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci return pbl_table; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cierr: 56462306a36Sopenharmony_ci for (i--; i >= 0; i--) 56562306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, pbl_info->pbl_size, 56662306a36Sopenharmony_ci pbl_table[i].va, pbl_table[i].pa); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci qedr_free_pbl(dev, pbl_info, pbl_table); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic int qedr_prepare_pbl_tbl(struct qedr_dev *dev, 57462306a36Sopenharmony_ci struct qedr_pbl_info *pbl_info, 57562306a36Sopenharmony_ci u32 num_pbes, int two_layer_capable) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci u32 pbl_capacity; 57862306a36Sopenharmony_ci u32 pbl_size; 57962306a36Sopenharmony_ci u32 num_pbls; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if ((num_pbes > MAX_PBES_ON_PAGE) && two_layer_capable) { 58262306a36Sopenharmony_ci if (num_pbes > MAX_PBES_TWO_LAYER) { 58362306a36Sopenharmony_ci DP_ERR(dev, "prepare pbl table: too many pages %d\n", 58462306a36Sopenharmony_ci num_pbes); 58562306a36Sopenharmony_ci return -EINVAL; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* calculate required pbl page size */ 58962306a36Sopenharmony_ci pbl_size = MIN_FW_PBL_PAGE_SIZE; 59062306a36Sopenharmony_ci pbl_capacity = NUM_PBES_ON_PAGE(pbl_size) * 59162306a36Sopenharmony_ci NUM_PBES_ON_PAGE(pbl_size); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci while (pbl_capacity < num_pbes) { 59462306a36Sopenharmony_ci pbl_size *= 2; 59562306a36Sopenharmony_ci pbl_capacity = pbl_size / sizeof(u64); 59662306a36Sopenharmony_ci pbl_capacity = pbl_capacity * pbl_capacity; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci num_pbls = DIV_ROUND_UP(num_pbes, NUM_PBES_ON_PAGE(pbl_size)); 60062306a36Sopenharmony_ci num_pbls++; /* One for the layer0 ( points to the pbls) */ 60162306a36Sopenharmony_ci pbl_info->two_layered = true; 60262306a36Sopenharmony_ci } else { 60362306a36Sopenharmony_ci /* One layered PBL */ 60462306a36Sopenharmony_ci num_pbls = 1; 60562306a36Sopenharmony_ci pbl_size = max_t(u32, MIN_FW_PBL_PAGE_SIZE, 60662306a36Sopenharmony_ci roundup_pow_of_two((num_pbes * sizeof(u64)))); 60762306a36Sopenharmony_ci pbl_info->two_layered = false; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci pbl_info->num_pbls = num_pbls; 61162306a36Sopenharmony_ci pbl_info->pbl_size = pbl_size; 61262306a36Sopenharmony_ci pbl_info->num_pbes = num_pbes; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_MR, 61562306a36Sopenharmony_ci "prepare pbl table: num_pbes=%d, num_pbls=%d, pbl_size=%d\n", 61662306a36Sopenharmony_ci pbl_info->num_pbes, pbl_info->num_pbls, pbl_info->pbl_size); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci return 0; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic void qedr_populate_pbls(struct qedr_dev *dev, struct ib_umem *umem, 62262306a36Sopenharmony_ci struct qedr_pbl *pbl, 62362306a36Sopenharmony_ci struct qedr_pbl_info *pbl_info, u32 pg_shift) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci int pbe_cnt, total_num_pbes = 0; 62662306a36Sopenharmony_ci struct qedr_pbl *pbl_tbl; 62762306a36Sopenharmony_ci struct ib_block_iter biter; 62862306a36Sopenharmony_ci struct regpair *pbe; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (!pbl_info->num_pbes) 63162306a36Sopenharmony_ci return; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* If we have a two layered pbl, the first pbl points to the rest 63462306a36Sopenharmony_ci * of the pbls and the first entry lays on the second pbl in the table 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_ci if (pbl_info->two_layered) 63762306a36Sopenharmony_ci pbl_tbl = &pbl[1]; 63862306a36Sopenharmony_ci else 63962306a36Sopenharmony_ci pbl_tbl = pbl; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci pbe = (struct regpair *)pbl_tbl->va; 64262306a36Sopenharmony_ci if (!pbe) { 64362306a36Sopenharmony_ci DP_ERR(dev, "cannot populate PBL due to a NULL PBE\n"); 64462306a36Sopenharmony_ci return; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci pbe_cnt = 0; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci rdma_umem_for_each_dma_block (umem, &biter, BIT(pg_shift)) { 65062306a36Sopenharmony_ci u64 pg_addr = rdma_block_iter_dma_address(&biter); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci pbe->lo = cpu_to_le32(pg_addr); 65362306a36Sopenharmony_ci pbe->hi = cpu_to_le32(upper_32_bits(pg_addr)); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci pbe_cnt++; 65662306a36Sopenharmony_ci total_num_pbes++; 65762306a36Sopenharmony_ci pbe++; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (total_num_pbes == pbl_info->num_pbes) 66062306a36Sopenharmony_ci return; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* If the given pbl is full storing the pbes, move to next pbl. 66362306a36Sopenharmony_ci */ 66462306a36Sopenharmony_ci if (pbe_cnt == (pbl_info->pbl_size / sizeof(u64))) { 66562306a36Sopenharmony_ci pbl_tbl++; 66662306a36Sopenharmony_ci pbe = (struct regpair *)pbl_tbl->va; 66762306a36Sopenharmony_ci pbe_cnt = 0; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic int qedr_db_recovery_add(struct qedr_dev *dev, 67362306a36Sopenharmony_ci void __iomem *db_addr, 67462306a36Sopenharmony_ci void *db_data, 67562306a36Sopenharmony_ci enum qed_db_rec_width db_width, 67662306a36Sopenharmony_ci enum qed_db_rec_space db_space) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci if (!db_data) { 67962306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "avoiding db rec since old lib\n"); 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci return dev->ops->common->db_recovery_add(dev->cdev, db_addr, db_data, 68462306a36Sopenharmony_ci db_width, db_space); 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic void qedr_db_recovery_del(struct qedr_dev *dev, 68862306a36Sopenharmony_ci void __iomem *db_addr, 68962306a36Sopenharmony_ci void *db_data) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci if (!db_data) { 69262306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "avoiding db rec since old lib\n"); 69362306a36Sopenharmony_ci return; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* Ignore return code as there is not much we can do about it. Error 69762306a36Sopenharmony_ci * log will be printed inside. 69862306a36Sopenharmony_ci */ 69962306a36Sopenharmony_ci dev->ops->common->db_recovery_del(dev->cdev, db_addr, db_data); 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic int qedr_copy_cq_uresp(struct qedr_dev *dev, 70362306a36Sopenharmony_ci struct qedr_cq *cq, struct ib_udata *udata, 70462306a36Sopenharmony_ci u32 db_offset) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct qedr_create_cq_uresp uresp; 70762306a36Sopenharmony_ci int rc; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci memset(&uresp, 0, sizeof(uresp)); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci uresp.db_offset = db_offset; 71262306a36Sopenharmony_ci uresp.icid = cq->icid; 71362306a36Sopenharmony_ci if (cq->q.db_mmap_entry) 71462306a36Sopenharmony_ci uresp.db_rec_addr = 71562306a36Sopenharmony_ci rdma_user_mmap_get_offset(cq->q.db_mmap_entry); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci rc = qedr_ib_copy_to_udata(udata, &uresp, sizeof(uresp)); 71862306a36Sopenharmony_ci if (rc) 71962306a36Sopenharmony_ci DP_ERR(dev, "copy error cqid=0x%x.\n", cq->icid); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return rc; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic void consume_cqe(struct qedr_cq *cq) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci if (cq->latest_cqe == cq->toggle_cqe) 72762306a36Sopenharmony_ci cq->pbl_toggle ^= RDMA_CQE_REQUESTER_TOGGLE_BIT_MASK; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci cq->latest_cqe = qed_chain_consume(&cq->pbl); 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic inline int qedr_align_cq_entries(int entries) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci u64 size, aligned_size; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* We allocate an extra entry that we don't report to the FW. */ 73762306a36Sopenharmony_ci size = (entries + 1) * QEDR_CQE_SIZE; 73862306a36Sopenharmony_ci aligned_size = ALIGN(size, PAGE_SIZE); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci return aligned_size / QEDR_CQE_SIZE; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic int qedr_init_user_db_rec(struct ib_udata *udata, 74462306a36Sopenharmony_ci struct qedr_dev *dev, struct qedr_userq *q, 74562306a36Sopenharmony_ci bool requires_db_rec) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct qedr_ucontext *uctx = 74862306a36Sopenharmony_ci rdma_udata_to_drv_context(udata, struct qedr_ucontext, 74962306a36Sopenharmony_ci ibucontext); 75062306a36Sopenharmony_ci struct qedr_user_mmap_entry *entry; 75162306a36Sopenharmony_ci int rc; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* Aborting for non doorbell userqueue (SRQ) or non-supporting lib */ 75462306a36Sopenharmony_ci if (requires_db_rec == 0 || !uctx->db_rec) 75562306a36Sopenharmony_ci return 0; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* Allocate a page for doorbell recovery, add to mmap */ 75862306a36Sopenharmony_ci q->db_rec_data = (void *)get_zeroed_page(GFP_USER); 75962306a36Sopenharmony_ci if (!q->db_rec_data) { 76062306a36Sopenharmony_ci DP_ERR(dev, "get_zeroed_page failed\n"); 76162306a36Sopenharmony_ci return -ENOMEM; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci entry = kzalloc(sizeof(*entry), GFP_KERNEL); 76562306a36Sopenharmony_ci if (!entry) 76662306a36Sopenharmony_ci goto err_free_db_data; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci entry->address = q->db_rec_data; 76962306a36Sopenharmony_ci entry->length = PAGE_SIZE; 77062306a36Sopenharmony_ci entry->mmap_flag = QEDR_USER_MMAP_PHYS_PAGE; 77162306a36Sopenharmony_ci rc = rdma_user_mmap_entry_insert(&uctx->ibucontext, 77262306a36Sopenharmony_ci &entry->rdma_entry, 77362306a36Sopenharmony_ci PAGE_SIZE); 77462306a36Sopenharmony_ci if (rc) 77562306a36Sopenharmony_ci goto err_free_entry; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci q->db_mmap_entry = &entry->rdma_entry; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci return 0; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cierr_free_entry: 78262306a36Sopenharmony_ci kfree(entry); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cierr_free_db_data: 78562306a36Sopenharmony_ci free_page((unsigned long)q->db_rec_data); 78662306a36Sopenharmony_ci q->db_rec_data = NULL; 78762306a36Sopenharmony_ci return -ENOMEM; 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic inline int qedr_init_user_queue(struct ib_udata *udata, 79162306a36Sopenharmony_ci struct qedr_dev *dev, 79262306a36Sopenharmony_ci struct qedr_userq *q, u64 buf_addr, 79362306a36Sopenharmony_ci size_t buf_len, bool requires_db_rec, 79462306a36Sopenharmony_ci int access, 79562306a36Sopenharmony_ci int alloc_and_init) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci u32 fw_pages; 79862306a36Sopenharmony_ci int rc; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci q->buf_addr = buf_addr; 80162306a36Sopenharmony_ci q->buf_len = buf_len; 80262306a36Sopenharmony_ci q->umem = ib_umem_get(&dev->ibdev, q->buf_addr, q->buf_len, access); 80362306a36Sopenharmony_ci if (IS_ERR(q->umem)) { 80462306a36Sopenharmony_ci DP_ERR(dev, "create user queue: failed ib_umem_get, got %ld\n", 80562306a36Sopenharmony_ci PTR_ERR(q->umem)); 80662306a36Sopenharmony_ci return PTR_ERR(q->umem); 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci fw_pages = ib_umem_num_dma_blocks(q->umem, 1 << FW_PAGE_SHIFT); 81062306a36Sopenharmony_ci rc = qedr_prepare_pbl_tbl(dev, &q->pbl_info, fw_pages, 0); 81162306a36Sopenharmony_ci if (rc) 81262306a36Sopenharmony_ci goto err0; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (alloc_and_init) { 81562306a36Sopenharmony_ci q->pbl_tbl = qedr_alloc_pbl_tbl(dev, &q->pbl_info, GFP_KERNEL); 81662306a36Sopenharmony_ci if (IS_ERR(q->pbl_tbl)) { 81762306a36Sopenharmony_ci rc = PTR_ERR(q->pbl_tbl); 81862306a36Sopenharmony_ci goto err0; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci qedr_populate_pbls(dev, q->umem, q->pbl_tbl, &q->pbl_info, 82162306a36Sopenharmony_ci FW_PAGE_SHIFT); 82262306a36Sopenharmony_ci } else { 82362306a36Sopenharmony_ci q->pbl_tbl = kzalloc(sizeof(*q->pbl_tbl), GFP_KERNEL); 82462306a36Sopenharmony_ci if (!q->pbl_tbl) { 82562306a36Sopenharmony_ci rc = -ENOMEM; 82662306a36Sopenharmony_ci goto err0; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci /* mmap the user address used to store doorbell data for recovery */ 83162306a36Sopenharmony_ci return qedr_init_user_db_rec(udata, dev, q, requires_db_rec); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cierr0: 83462306a36Sopenharmony_ci ib_umem_release(q->umem); 83562306a36Sopenharmony_ci q->umem = NULL; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci return rc; 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic inline void qedr_init_cq_params(struct qedr_cq *cq, 84162306a36Sopenharmony_ci struct qedr_ucontext *ctx, 84262306a36Sopenharmony_ci struct qedr_dev *dev, int vector, 84362306a36Sopenharmony_ci int chain_entries, int page_cnt, 84462306a36Sopenharmony_ci u64 pbl_ptr, 84562306a36Sopenharmony_ci struct qed_rdma_create_cq_in_params 84662306a36Sopenharmony_ci *params) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci memset(params, 0, sizeof(*params)); 84962306a36Sopenharmony_ci params->cq_handle_hi = upper_32_bits((uintptr_t)cq); 85062306a36Sopenharmony_ci params->cq_handle_lo = lower_32_bits((uintptr_t)cq); 85162306a36Sopenharmony_ci params->cnq_id = vector; 85262306a36Sopenharmony_ci params->cq_size = chain_entries - 1; 85362306a36Sopenharmony_ci params->dpi = (ctx) ? ctx->dpi : dev->dpi; 85462306a36Sopenharmony_ci params->pbl_num_pages = page_cnt; 85562306a36Sopenharmony_ci params->pbl_ptr = pbl_ptr; 85662306a36Sopenharmony_ci params->pbl_two_level = 0; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic void doorbell_cq(struct qedr_cq *cq, u32 cons, u8 flags) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci cq->db.data.agg_flags = flags; 86262306a36Sopenharmony_ci cq->db.data.value = cpu_to_le32(cons); 86362306a36Sopenharmony_ci writeq(cq->db.raw, cq->db_addr); 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ciint qedr_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci struct qedr_cq *cq = get_qedr_cq(ibcq); 86962306a36Sopenharmony_ci unsigned long sflags; 87062306a36Sopenharmony_ci struct qedr_dev *dev; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci dev = get_qedr_dev(ibcq->device); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (cq->destroyed) { 87562306a36Sopenharmony_ci DP_ERR(dev, 87662306a36Sopenharmony_ci "warning: arm was invoked after destroy for cq %p (icid=%d)\n", 87762306a36Sopenharmony_ci cq, cq->icid); 87862306a36Sopenharmony_ci return -EINVAL; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (cq->cq_type == QEDR_CQ_TYPE_GSI) 88362306a36Sopenharmony_ci return 0; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci spin_lock_irqsave(&cq->cq_lock, sflags); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci cq->arm_flags = 0; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (flags & IB_CQ_SOLICITED) 89062306a36Sopenharmony_ci cq->arm_flags |= DQ_UCM_ROCE_CQ_ARM_SE_CF_CMD; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (flags & IB_CQ_NEXT_COMP) 89362306a36Sopenharmony_ci cq->arm_flags |= DQ_UCM_ROCE_CQ_ARM_CF_CMD; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci doorbell_cq(cq, cq->cq_cons - 1, cq->arm_flags); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->cq_lock, sflags); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci return 0; 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ciint qedr_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, 90362306a36Sopenharmony_ci struct ib_udata *udata) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct ib_device *ibdev = ibcq->device; 90662306a36Sopenharmony_ci struct qedr_ucontext *ctx = rdma_udata_to_drv_context( 90762306a36Sopenharmony_ci udata, struct qedr_ucontext, ibucontext); 90862306a36Sopenharmony_ci struct qed_rdma_destroy_cq_out_params destroy_oparams; 90962306a36Sopenharmony_ci struct qed_rdma_destroy_cq_in_params destroy_iparams; 91062306a36Sopenharmony_ci struct qed_chain_init_params chain_params = { 91162306a36Sopenharmony_ci .mode = QED_CHAIN_MODE_PBL, 91262306a36Sopenharmony_ci .intended_use = QED_CHAIN_USE_TO_CONSUME, 91362306a36Sopenharmony_ci .cnt_type = QED_CHAIN_CNT_TYPE_U32, 91462306a36Sopenharmony_ci .elem_size = sizeof(union rdma_cqe), 91562306a36Sopenharmony_ci }; 91662306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibdev); 91762306a36Sopenharmony_ci struct qed_rdma_create_cq_in_params params; 91862306a36Sopenharmony_ci struct qedr_create_cq_ureq ureq = {}; 91962306a36Sopenharmony_ci int vector = attr->comp_vector; 92062306a36Sopenharmony_ci int entries = attr->cqe; 92162306a36Sopenharmony_ci struct qedr_cq *cq = get_qedr_cq(ibcq); 92262306a36Sopenharmony_ci int chain_entries; 92362306a36Sopenharmony_ci u32 db_offset; 92462306a36Sopenharmony_ci int page_cnt; 92562306a36Sopenharmony_ci u64 pbl_ptr; 92662306a36Sopenharmony_ci u16 icid; 92762306a36Sopenharmony_ci int rc; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, 93062306a36Sopenharmony_ci "create_cq: called from %s. entries=%d, vector=%d\n", 93162306a36Sopenharmony_ci udata ? "User Lib" : "Kernel", entries, vector); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (attr->flags) 93462306a36Sopenharmony_ci return -EOPNOTSUPP; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (entries > QEDR_MAX_CQES) { 93762306a36Sopenharmony_ci DP_ERR(dev, 93862306a36Sopenharmony_ci "create cq: the number of entries %d is too high. Must be equal or below %d.\n", 93962306a36Sopenharmony_ci entries, QEDR_MAX_CQES); 94062306a36Sopenharmony_ci return -EINVAL; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci chain_entries = qedr_align_cq_entries(entries); 94462306a36Sopenharmony_ci chain_entries = min_t(int, chain_entries, QEDR_MAX_CQES); 94562306a36Sopenharmony_ci chain_params.num_elems = chain_entries; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* calc db offset. user will add DPI base, kernel will add db addr */ 94862306a36Sopenharmony_ci db_offset = DB_ADDR_SHIFT(DQ_PWM_OFFSET_UCM_RDMA_CQ_CONS_32BIT); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (udata) { 95162306a36Sopenharmony_ci if (ib_copy_from_udata(&ureq, udata, min(sizeof(ureq), 95262306a36Sopenharmony_ci udata->inlen))) { 95362306a36Sopenharmony_ci DP_ERR(dev, 95462306a36Sopenharmony_ci "create cq: problem copying data from user space\n"); 95562306a36Sopenharmony_ci goto err0; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (!ureq.len) { 95962306a36Sopenharmony_ci DP_ERR(dev, 96062306a36Sopenharmony_ci "create cq: cannot create a cq with 0 entries\n"); 96162306a36Sopenharmony_ci goto err0; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci cq->cq_type = QEDR_CQ_TYPE_USER; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci rc = qedr_init_user_queue(udata, dev, &cq->q, ureq.addr, 96762306a36Sopenharmony_ci ureq.len, true, IB_ACCESS_LOCAL_WRITE, 96862306a36Sopenharmony_ci 1); 96962306a36Sopenharmony_ci if (rc) 97062306a36Sopenharmony_ci goto err0; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci pbl_ptr = cq->q.pbl_tbl->pa; 97362306a36Sopenharmony_ci page_cnt = cq->q.pbl_info.num_pbes; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci cq->ibcq.cqe = chain_entries; 97662306a36Sopenharmony_ci cq->q.db_addr = ctx->dpi_addr + db_offset; 97762306a36Sopenharmony_ci } else { 97862306a36Sopenharmony_ci cq->cq_type = QEDR_CQ_TYPE_KERNEL; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci rc = dev->ops->common->chain_alloc(dev->cdev, &cq->pbl, 98162306a36Sopenharmony_ci &chain_params); 98262306a36Sopenharmony_ci if (rc) 98362306a36Sopenharmony_ci goto err0; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci page_cnt = qed_chain_get_page_cnt(&cq->pbl); 98662306a36Sopenharmony_ci pbl_ptr = qed_chain_get_pbl_phys(&cq->pbl); 98762306a36Sopenharmony_ci cq->ibcq.cqe = cq->pbl.capacity; 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci qedr_init_cq_params(cq, ctx, dev, vector, chain_entries, page_cnt, 99162306a36Sopenharmony_ci pbl_ptr, ¶ms); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci rc = dev->ops->rdma_create_cq(dev->rdma_ctx, ¶ms, &icid); 99462306a36Sopenharmony_ci if (rc) 99562306a36Sopenharmony_ci goto err1; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci cq->icid = icid; 99862306a36Sopenharmony_ci cq->sig = QEDR_CQ_MAGIC_NUMBER; 99962306a36Sopenharmony_ci spin_lock_init(&cq->cq_lock); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci if (udata) { 100262306a36Sopenharmony_ci rc = qedr_copy_cq_uresp(dev, cq, udata, db_offset); 100362306a36Sopenharmony_ci if (rc) 100462306a36Sopenharmony_ci goto err2; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci rc = qedr_db_recovery_add(dev, cq->q.db_addr, 100762306a36Sopenharmony_ci &cq->q.db_rec_data->db_data, 100862306a36Sopenharmony_ci DB_REC_WIDTH_64B, 100962306a36Sopenharmony_ci DB_REC_USER); 101062306a36Sopenharmony_ci if (rc) 101162306a36Sopenharmony_ci goto err2; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci } else { 101462306a36Sopenharmony_ci /* Generate doorbell address. */ 101562306a36Sopenharmony_ci cq->db.data.icid = cq->icid; 101662306a36Sopenharmony_ci cq->db_addr = dev->db_addr + db_offset; 101762306a36Sopenharmony_ci cq->db.data.params = DB_AGG_CMD_MAX << 101862306a36Sopenharmony_ci RDMA_PWM_VAL32_DATA_AGG_CMD_SHIFT; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* point to the very last element, passing it we will toggle */ 102162306a36Sopenharmony_ci cq->toggle_cqe = qed_chain_get_last_elem(&cq->pbl); 102262306a36Sopenharmony_ci cq->pbl_toggle = RDMA_CQE_REQUESTER_TOGGLE_BIT_MASK; 102362306a36Sopenharmony_ci cq->latest_cqe = NULL; 102462306a36Sopenharmony_ci consume_cqe(cq); 102562306a36Sopenharmony_ci cq->cq_cons = qed_chain_get_cons_idx_u32(&cq->pbl); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci rc = qedr_db_recovery_add(dev, cq->db_addr, &cq->db.data, 102862306a36Sopenharmony_ci DB_REC_WIDTH_64B, DB_REC_KERNEL); 102962306a36Sopenharmony_ci if (rc) 103062306a36Sopenharmony_ci goto err2; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_CQ, 103462306a36Sopenharmony_ci "create cq: icid=0x%0x, addr=%p, size(entries)=0x%0x\n", 103562306a36Sopenharmony_ci cq->icid, cq, params.cq_size); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci return 0; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_cierr2: 104062306a36Sopenharmony_ci destroy_iparams.icid = cq->icid; 104162306a36Sopenharmony_ci dev->ops->rdma_destroy_cq(dev->rdma_ctx, &destroy_iparams, 104262306a36Sopenharmony_ci &destroy_oparams); 104362306a36Sopenharmony_cierr1: 104462306a36Sopenharmony_ci if (udata) { 104562306a36Sopenharmony_ci qedr_free_pbl(dev, &cq->q.pbl_info, cq->q.pbl_tbl); 104662306a36Sopenharmony_ci ib_umem_release(cq->q.umem); 104762306a36Sopenharmony_ci if (cq->q.db_mmap_entry) 104862306a36Sopenharmony_ci rdma_user_mmap_entry_remove(cq->q.db_mmap_entry); 104962306a36Sopenharmony_ci } else { 105062306a36Sopenharmony_ci dev->ops->common->chain_free(dev->cdev, &cq->pbl); 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_cierr0: 105362306a36Sopenharmony_ci return -EINVAL; 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci#define QEDR_DESTROY_CQ_MAX_ITERATIONS (10) 105762306a36Sopenharmony_ci#define QEDR_DESTROY_CQ_ITER_DURATION (10) 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ciint qedr_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibcq->device); 106262306a36Sopenharmony_ci struct qed_rdma_destroy_cq_out_params oparams; 106362306a36Sopenharmony_ci struct qed_rdma_destroy_cq_in_params iparams; 106462306a36Sopenharmony_ci struct qedr_cq *cq = get_qedr_cq(ibcq); 106562306a36Sopenharmony_ci int iter; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_CQ, "destroy cq %p (icid=%d)\n", cq, cq->icid); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci cq->destroyed = 1; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci /* GSIs CQs are handled by driver, so they don't exist in the FW */ 107262306a36Sopenharmony_ci if (cq->cq_type == QEDR_CQ_TYPE_GSI) { 107362306a36Sopenharmony_ci qedr_db_recovery_del(dev, cq->db_addr, &cq->db.data); 107462306a36Sopenharmony_ci return 0; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci iparams.icid = cq->icid; 107862306a36Sopenharmony_ci dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams); 107962306a36Sopenharmony_ci dev->ops->common->chain_free(dev->cdev, &cq->pbl); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci if (udata) { 108262306a36Sopenharmony_ci qedr_free_pbl(dev, &cq->q.pbl_info, cq->q.pbl_tbl); 108362306a36Sopenharmony_ci ib_umem_release(cq->q.umem); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (cq->q.db_rec_data) { 108662306a36Sopenharmony_ci qedr_db_recovery_del(dev, cq->q.db_addr, 108762306a36Sopenharmony_ci &cq->q.db_rec_data->db_data); 108862306a36Sopenharmony_ci rdma_user_mmap_entry_remove(cq->q.db_mmap_entry); 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci } else { 109162306a36Sopenharmony_ci qedr_db_recovery_del(dev, cq->db_addr, &cq->db.data); 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci /* We don't want the IRQ handler to handle a non-existing CQ so we 109562306a36Sopenharmony_ci * wait until all CNQ interrupts, if any, are received. This will always 109662306a36Sopenharmony_ci * happen and will always happen very fast. If not, then a serious error 109762306a36Sopenharmony_ci * has occured. That is why we can use a long delay. 109862306a36Sopenharmony_ci * We spin for a short time so we don’t lose time on context switching 109962306a36Sopenharmony_ci * in case all the completions are handled in that span. Otherwise 110062306a36Sopenharmony_ci * we sleep for a while and check again. Since the CNQ may be 110162306a36Sopenharmony_ci * associated with (only) the current CPU we use msleep to allow the 110262306a36Sopenharmony_ci * current CPU to be freed. 110362306a36Sopenharmony_ci * The CNQ notification is increased in qedr_irq_handler(). 110462306a36Sopenharmony_ci */ 110562306a36Sopenharmony_ci iter = QEDR_DESTROY_CQ_MAX_ITERATIONS; 110662306a36Sopenharmony_ci while (oparams.num_cq_notif != READ_ONCE(cq->cnq_notif) && iter) { 110762306a36Sopenharmony_ci udelay(QEDR_DESTROY_CQ_ITER_DURATION); 110862306a36Sopenharmony_ci iter--; 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci iter = QEDR_DESTROY_CQ_MAX_ITERATIONS; 111262306a36Sopenharmony_ci while (oparams.num_cq_notif != READ_ONCE(cq->cnq_notif) && iter) { 111362306a36Sopenharmony_ci msleep(QEDR_DESTROY_CQ_ITER_DURATION); 111462306a36Sopenharmony_ci iter--; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci /* Note that we don't need to have explicit code to wait for the 111862306a36Sopenharmony_ci * completion of the event handler because it is invoked from the EQ. 111962306a36Sopenharmony_ci * Since the destroy CQ ramrod has also been received on the EQ we can 112062306a36Sopenharmony_ci * be certain that there's no event handler in process. 112162306a36Sopenharmony_ci */ 112262306a36Sopenharmony_ci return 0; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic inline int get_gid_info_from_table(struct ib_qp *ibqp, 112662306a36Sopenharmony_ci struct ib_qp_attr *attr, 112762306a36Sopenharmony_ci int attr_mask, 112862306a36Sopenharmony_ci struct qed_rdma_modify_qp_in_params 112962306a36Sopenharmony_ci *qp_params) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci const struct ib_gid_attr *gid_attr; 113262306a36Sopenharmony_ci enum rdma_network_type nw_type; 113362306a36Sopenharmony_ci const struct ib_global_route *grh = rdma_ah_read_grh(&attr->ah_attr); 113462306a36Sopenharmony_ci u32 ipv4_addr; 113562306a36Sopenharmony_ci int ret; 113662306a36Sopenharmony_ci int i; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci gid_attr = grh->sgid_attr; 113962306a36Sopenharmony_ci ret = rdma_read_gid_l2_fields(gid_attr, &qp_params->vlan_id, NULL); 114062306a36Sopenharmony_ci if (ret) 114162306a36Sopenharmony_ci return ret; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci nw_type = rdma_gid_attr_network_type(gid_attr); 114462306a36Sopenharmony_ci switch (nw_type) { 114562306a36Sopenharmony_ci case RDMA_NETWORK_IPV6: 114662306a36Sopenharmony_ci memcpy(&qp_params->sgid.bytes[0], &gid_attr->gid.raw[0], 114762306a36Sopenharmony_ci sizeof(qp_params->sgid)); 114862306a36Sopenharmony_ci memcpy(&qp_params->dgid.bytes[0], 114962306a36Sopenharmony_ci &grh->dgid, 115062306a36Sopenharmony_ci sizeof(qp_params->dgid)); 115162306a36Sopenharmony_ci qp_params->roce_mode = ROCE_V2_IPV6; 115262306a36Sopenharmony_ci SET_FIELD(qp_params->modify_flags, 115362306a36Sopenharmony_ci QED_ROCE_MODIFY_QP_VALID_ROCE_MODE, 1); 115462306a36Sopenharmony_ci break; 115562306a36Sopenharmony_ci case RDMA_NETWORK_ROCE_V1: 115662306a36Sopenharmony_ci memcpy(&qp_params->sgid.bytes[0], &gid_attr->gid.raw[0], 115762306a36Sopenharmony_ci sizeof(qp_params->sgid)); 115862306a36Sopenharmony_ci memcpy(&qp_params->dgid.bytes[0], 115962306a36Sopenharmony_ci &grh->dgid, 116062306a36Sopenharmony_ci sizeof(qp_params->dgid)); 116162306a36Sopenharmony_ci qp_params->roce_mode = ROCE_V1; 116262306a36Sopenharmony_ci break; 116362306a36Sopenharmony_ci case RDMA_NETWORK_IPV4: 116462306a36Sopenharmony_ci memset(&qp_params->sgid, 0, sizeof(qp_params->sgid)); 116562306a36Sopenharmony_ci memset(&qp_params->dgid, 0, sizeof(qp_params->dgid)); 116662306a36Sopenharmony_ci ipv4_addr = qedr_get_ipv4_from_gid(gid_attr->gid.raw); 116762306a36Sopenharmony_ci qp_params->sgid.ipv4_addr = ipv4_addr; 116862306a36Sopenharmony_ci ipv4_addr = 116962306a36Sopenharmony_ci qedr_get_ipv4_from_gid(grh->dgid.raw); 117062306a36Sopenharmony_ci qp_params->dgid.ipv4_addr = ipv4_addr; 117162306a36Sopenharmony_ci SET_FIELD(qp_params->modify_flags, 117262306a36Sopenharmony_ci QED_ROCE_MODIFY_QP_VALID_ROCE_MODE, 1); 117362306a36Sopenharmony_ci qp_params->roce_mode = ROCE_V2_IPV4; 117462306a36Sopenharmony_ci break; 117562306a36Sopenharmony_ci default: 117662306a36Sopenharmony_ci return -EINVAL; 117762306a36Sopenharmony_ci } 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 118062306a36Sopenharmony_ci qp_params->sgid.dwords[i] = ntohl(qp_params->sgid.dwords[i]); 118162306a36Sopenharmony_ci qp_params->dgid.dwords[i] = ntohl(qp_params->dgid.dwords[i]); 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (qp_params->vlan_id >= VLAN_CFI_MASK) 118562306a36Sopenharmony_ci qp_params->vlan_id = 0; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci return 0; 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_cistatic int qedr_check_qp_attrs(struct ib_pd *ibpd, struct qedr_dev *dev, 119162306a36Sopenharmony_ci struct ib_qp_init_attr *attrs, 119262306a36Sopenharmony_ci struct ib_udata *udata) 119362306a36Sopenharmony_ci{ 119462306a36Sopenharmony_ci struct qedr_device_attr *qattr = &dev->attr; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci /* QP0... attrs->qp_type == IB_QPT_GSI */ 119762306a36Sopenharmony_ci if (attrs->qp_type != IB_QPT_RC && 119862306a36Sopenharmony_ci attrs->qp_type != IB_QPT_GSI && 119962306a36Sopenharmony_ci attrs->qp_type != IB_QPT_XRC_INI && 120062306a36Sopenharmony_ci attrs->qp_type != IB_QPT_XRC_TGT) { 120162306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, 120262306a36Sopenharmony_ci "create qp: unsupported qp type=0x%x requested\n", 120362306a36Sopenharmony_ci attrs->qp_type); 120462306a36Sopenharmony_ci return -EOPNOTSUPP; 120562306a36Sopenharmony_ci } 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci if (attrs->cap.max_send_wr > qattr->max_sqe) { 120862306a36Sopenharmony_ci DP_ERR(dev, 120962306a36Sopenharmony_ci "create qp: cannot create a SQ with %d elements (max_send_wr=0x%x)\n", 121062306a36Sopenharmony_ci attrs->cap.max_send_wr, qattr->max_sqe); 121162306a36Sopenharmony_ci return -EINVAL; 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci if (attrs->cap.max_inline_data > qattr->max_inline) { 121562306a36Sopenharmony_ci DP_ERR(dev, 121662306a36Sopenharmony_ci "create qp: unsupported inline data size=0x%x requested (max_inline=0x%x)\n", 121762306a36Sopenharmony_ci attrs->cap.max_inline_data, qattr->max_inline); 121862306a36Sopenharmony_ci return -EINVAL; 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (attrs->cap.max_send_sge > qattr->max_sge) { 122262306a36Sopenharmony_ci DP_ERR(dev, 122362306a36Sopenharmony_ci "create qp: unsupported send_sge=0x%x requested (max_send_sge=0x%x)\n", 122462306a36Sopenharmony_ci attrs->cap.max_send_sge, qattr->max_sge); 122562306a36Sopenharmony_ci return -EINVAL; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if (attrs->cap.max_recv_sge > qattr->max_sge) { 122962306a36Sopenharmony_ci DP_ERR(dev, 123062306a36Sopenharmony_ci "create qp: unsupported recv_sge=0x%x requested (max_recv_sge=0x%x)\n", 123162306a36Sopenharmony_ci attrs->cap.max_recv_sge, qattr->max_sge); 123262306a36Sopenharmony_ci return -EINVAL; 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci /* verify consumer QPs are not trying to use GSI QP's CQ. 123662306a36Sopenharmony_ci * TGT QP isn't associated with RQ/SQ 123762306a36Sopenharmony_ci */ 123862306a36Sopenharmony_ci if ((attrs->qp_type != IB_QPT_GSI) && (dev->gsi_qp_created) && 123962306a36Sopenharmony_ci (attrs->qp_type != IB_QPT_XRC_TGT) && 124062306a36Sopenharmony_ci (attrs->qp_type != IB_QPT_XRC_INI)) { 124162306a36Sopenharmony_ci struct qedr_cq *send_cq = get_qedr_cq(attrs->send_cq); 124262306a36Sopenharmony_ci struct qedr_cq *recv_cq = get_qedr_cq(attrs->recv_cq); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci if ((send_cq->cq_type == QEDR_CQ_TYPE_GSI) || 124562306a36Sopenharmony_ci (recv_cq->cq_type == QEDR_CQ_TYPE_GSI)) { 124662306a36Sopenharmony_ci DP_ERR(dev, 124762306a36Sopenharmony_ci "create qp: consumer QP cannot use GSI CQs.\n"); 124862306a36Sopenharmony_ci return -EINVAL; 124962306a36Sopenharmony_ci } 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci return 0; 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_cistatic int qedr_copy_srq_uresp(struct qedr_dev *dev, 125662306a36Sopenharmony_ci struct qedr_srq *srq, struct ib_udata *udata) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci struct qedr_create_srq_uresp uresp = {}; 125962306a36Sopenharmony_ci int rc; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci uresp.srq_id = srq->srq_id; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); 126462306a36Sopenharmony_ci if (rc) 126562306a36Sopenharmony_ci DP_ERR(dev, "create srq: problem copying data to user space\n"); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci return rc; 126862306a36Sopenharmony_ci} 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_cistatic void qedr_copy_rq_uresp(struct qedr_dev *dev, 127162306a36Sopenharmony_ci struct qedr_create_qp_uresp *uresp, 127262306a36Sopenharmony_ci struct qedr_qp *qp) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci /* iWARP requires two doorbells per RQ. */ 127562306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) { 127662306a36Sopenharmony_ci uresp->rq_db_offset = 127762306a36Sopenharmony_ci DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_IWARP_RQ_PROD); 127862306a36Sopenharmony_ci uresp->rq_db2_offset = DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_FLAGS); 127962306a36Sopenharmony_ci } else { 128062306a36Sopenharmony_ci uresp->rq_db_offset = 128162306a36Sopenharmony_ci DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_ROCE_RQ_PROD); 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci uresp->rq_icid = qp->icid; 128562306a36Sopenharmony_ci if (qp->urq.db_mmap_entry) 128662306a36Sopenharmony_ci uresp->rq_db_rec_addr = 128762306a36Sopenharmony_ci rdma_user_mmap_get_offset(qp->urq.db_mmap_entry); 128862306a36Sopenharmony_ci} 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_cistatic void qedr_copy_sq_uresp(struct qedr_dev *dev, 129162306a36Sopenharmony_ci struct qedr_create_qp_uresp *uresp, 129262306a36Sopenharmony_ci struct qedr_qp *qp) 129362306a36Sopenharmony_ci{ 129462306a36Sopenharmony_ci uresp->sq_db_offset = DB_ADDR_SHIFT(DQ_PWM_OFFSET_XCM_RDMA_SQ_PROD); 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci /* iWARP uses the same cid for rq and sq */ 129762306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) 129862306a36Sopenharmony_ci uresp->sq_icid = qp->icid; 129962306a36Sopenharmony_ci else 130062306a36Sopenharmony_ci uresp->sq_icid = qp->icid + 1; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci if (qp->usq.db_mmap_entry) 130362306a36Sopenharmony_ci uresp->sq_db_rec_addr = 130462306a36Sopenharmony_ci rdma_user_mmap_get_offset(qp->usq.db_mmap_entry); 130562306a36Sopenharmony_ci} 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_cistatic int qedr_copy_qp_uresp(struct qedr_dev *dev, 130862306a36Sopenharmony_ci struct qedr_qp *qp, struct ib_udata *udata, 130962306a36Sopenharmony_ci struct qedr_create_qp_uresp *uresp) 131062306a36Sopenharmony_ci{ 131162306a36Sopenharmony_ci int rc; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci memset(uresp, 0, sizeof(*uresp)); 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci if (qedr_qp_has_sq(qp)) 131662306a36Sopenharmony_ci qedr_copy_sq_uresp(dev, uresp, qp); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci if (qedr_qp_has_rq(qp)) 131962306a36Sopenharmony_ci qedr_copy_rq_uresp(dev, uresp, qp); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci uresp->atomic_supported = dev->atomic_cap != IB_ATOMIC_NONE; 132262306a36Sopenharmony_ci uresp->qp_id = qp->qp_id; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci rc = qedr_ib_copy_to_udata(udata, uresp, sizeof(*uresp)); 132562306a36Sopenharmony_ci if (rc) 132662306a36Sopenharmony_ci DP_ERR(dev, 132762306a36Sopenharmony_ci "create qp: failed a copy to user space with qp icid=0x%x.\n", 132862306a36Sopenharmony_ci qp->icid); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci return rc; 133162306a36Sopenharmony_ci} 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_cistatic void qedr_reset_qp_hwq_info(struct qedr_qp_hwq_info *qph) 133462306a36Sopenharmony_ci{ 133562306a36Sopenharmony_ci qed_chain_reset(&qph->pbl); 133662306a36Sopenharmony_ci qph->prod = 0; 133762306a36Sopenharmony_ci qph->cons = 0; 133862306a36Sopenharmony_ci qph->wqe_cons = 0; 133962306a36Sopenharmony_ci qph->db_data.data.value = cpu_to_le16(0); 134062306a36Sopenharmony_ci} 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_cistatic void qedr_set_common_qp_params(struct qedr_dev *dev, 134362306a36Sopenharmony_ci struct qedr_qp *qp, 134462306a36Sopenharmony_ci struct qedr_pd *pd, 134562306a36Sopenharmony_ci struct ib_qp_init_attr *attrs) 134662306a36Sopenharmony_ci{ 134762306a36Sopenharmony_ci spin_lock_init(&qp->q_lock); 134862306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) { 134962306a36Sopenharmony_ci kref_init(&qp->refcnt); 135062306a36Sopenharmony_ci init_completion(&qp->iwarp_cm_comp); 135162306a36Sopenharmony_ci init_completion(&qp->qp_rel_comp); 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci qp->pd = pd; 135562306a36Sopenharmony_ci qp->qp_type = attrs->qp_type; 135662306a36Sopenharmony_ci qp->max_inline_data = attrs->cap.max_inline_data; 135762306a36Sopenharmony_ci qp->state = QED_ROCE_QP_STATE_RESET; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci qp->prev_wqe_size = 0; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci qp->signaled = attrs->sq_sig_type == IB_SIGNAL_ALL_WR; 136262306a36Sopenharmony_ci qp->dev = dev; 136362306a36Sopenharmony_ci if (qedr_qp_has_sq(qp)) { 136462306a36Sopenharmony_ci qedr_reset_qp_hwq_info(&qp->sq); 136562306a36Sopenharmony_ci qp->sq.max_sges = attrs->cap.max_send_sge; 136662306a36Sopenharmony_ci qp->sq_cq = get_qedr_cq(attrs->send_cq); 136762306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, 136862306a36Sopenharmony_ci "SQ params:\tsq_max_sges = %d, sq_cq_id = %d\n", 136962306a36Sopenharmony_ci qp->sq.max_sges, qp->sq_cq->icid); 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci if (attrs->srq) 137362306a36Sopenharmony_ci qp->srq = get_qedr_srq(attrs->srq); 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci if (qedr_qp_has_rq(qp)) { 137662306a36Sopenharmony_ci qedr_reset_qp_hwq_info(&qp->rq); 137762306a36Sopenharmony_ci qp->rq_cq = get_qedr_cq(attrs->recv_cq); 137862306a36Sopenharmony_ci qp->rq.max_sges = attrs->cap.max_recv_sge; 137962306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, 138062306a36Sopenharmony_ci "RQ params:\trq_max_sges = %d, rq_cq_id = %d\n", 138162306a36Sopenharmony_ci qp->rq.max_sges, qp->rq_cq->icid); 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, 138562306a36Sopenharmony_ci "QP params:\tpd = %d, qp_type = %d, max_inline_data = %d, state = %d, signaled = %d, use_srq=%d\n", 138662306a36Sopenharmony_ci pd->pd_id, qp->qp_type, qp->max_inline_data, 138762306a36Sopenharmony_ci qp->state, qp->signaled, (attrs->srq) ? 1 : 0); 138862306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, 138962306a36Sopenharmony_ci "SQ params:\tsq_max_sges = %d, sq_cq_id = %d\n", 139062306a36Sopenharmony_ci qp->sq.max_sges, qp->sq_cq->icid); 139162306a36Sopenharmony_ci} 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_cistatic int qedr_set_roce_db_info(struct qedr_dev *dev, struct qedr_qp *qp) 139462306a36Sopenharmony_ci{ 139562306a36Sopenharmony_ci int rc = 0; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (qedr_qp_has_sq(qp)) { 139862306a36Sopenharmony_ci qp->sq.db = dev->db_addr + 139962306a36Sopenharmony_ci DB_ADDR_SHIFT(DQ_PWM_OFFSET_XCM_RDMA_SQ_PROD); 140062306a36Sopenharmony_ci qp->sq.db_data.data.icid = qp->icid + 1; 140162306a36Sopenharmony_ci rc = qedr_db_recovery_add(dev, qp->sq.db, &qp->sq.db_data, 140262306a36Sopenharmony_ci DB_REC_WIDTH_32B, DB_REC_KERNEL); 140362306a36Sopenharmony_ci if (rc) 140462306a36Sopenharmony_ci return rc; 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci if (qedr_qp_has_rq(qp)) { 140862306a36Sopenharmony_ci qp->rq.db = dev->db_addr + 140962306a36Sopenharmony_ci DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_ROCE_RQ_PROD); 141062306a36Sopenharmony_ci qp->rq.db_data.data.icid = qp->icid; 141162306a36Sopenharmony_ci rc = qedr_db_recovery_add(dev, qp->rq.db, &qp->rq.db_data, 141262306a36Sopenharmony_ci DB_REC_WIDTH_32B, DB_REC_KERNEL); 141362306a36Sopenharmony_ci if (rc && qedr_qp_has_sq(qp)) 141462306a36Sopenharmony_ci qedr_db_recovery_del(dev, qp->sq.db, &qp->sq.db_data); 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci return rc; 141862306a36Sopenharmony_ci} 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_cistatic int qedr_check_srq_params(struct qedr_dev *dev, 142162306a36Sopenharmony_ci struct ib_srq_init_attr *attrs, 142262306a36Sopenharmony_ci struct ib_udata *udata) 142362306a36Sopenharmony_ci{ 142462306a36Sopenharmony_ci struct qedr_device_attr *qattr = &dev->attr; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (attrs->attr.max_wr > qattr->max_srq_wr) { 142762306a36Sopenharmony_ci DP_ERR(dev, 142862306a36Sopenharmony_ci "create srq: unsupported srq_wr=0x%x requested (max_srq_wr=0x%x)\n", 142962306a36Sopenharmony_ci attrs->attr.max_wr, qattr->max_srq_wr); 143062306a36Sopenharmony_ci return -EINVAL; 143162306a36Sopenharmony_ci } 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (attrs->attr.max_sge > qattr->max_sge) { 143462306a36Sopenharmony_ci DP_ERR(dev, 143562306a36Sopenharmony_ci "create srq: unsupported sge=0x%x requested (max_srq_sge=0x%x)\n", 143662306a36Sopenharmony_ci attrs->attr.max_sge, qattr->max_sge); 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (!udata && attrs->srq_type == IB_SRQT_XRC) { 144062306a36Sopenharmony_ci DP_ERR(dev, "XRC SRQs are not supported in kernel-space\n"); 144162306a36Sopenharmony_ci return -EINVAL; 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci return 0; 144562306a36Sopenharmony_ci} 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_cistatic void qedr_free_srq_user_params(struct qedr_srq *srq) 144862306a36Sopenharmony_ci{ 144962306a36Sopenharmony_ci qedr_free_pbl(srq->dev, &srq->usrq.pbl_info, srq->usrq.pbl_tbl); 145062306a36Sopenharmony_ci ib_umem_release(srq->usrq.umem); 145162306a36Sopenharmony_ci ib_umem_release(srq->prod_umem); 145262306a36Sopenharmony_ci} 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_cistatic void qedr_free_srq_kernel_params(struct qedr_srq *srq) 145562306a36Sopenharmony_ci{ 145662306a36Sopenharmony_ci struct qedr_srq_hwq_info *hw_srq = &srq->hw_srq; 145762306a36Sopenharmony_ci struct qedr_dev *dev = srq->dev; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci dev->ops->common->chain_free(dev->cdev, &hw_srq->pbl); 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, sizeof(struct rdma_srq_producers), 146262306a36Sopenharmony_ci hw_srq->virt_prod_pair_addr, 146362306a36Sopenharmony_ci hw_srq->phy_prod_pair_addr); 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_cistatic int qedr_init_srq_user_params(struct ib_udata *udata, 146762306a36Sopenharmony_ci struct qedr_srq *srq, 146862306a36Sopenharmony_ci struct qedr_create_srq_ureq *ureq, 146962306a36Sopenharmony_ci int access) 147062306a36Sopenharmony_ci{ 147162306a36Sopenharmony_ci struct scatterlist *sg; 147262306a36Sopenharmony_ci int rc; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci rc = qedr_init_user_queue(udata, srq->dev, &srq->usrq, ureq->srq_addr, 147562306a36Sopenharmony_ci ureq->srq_len, false, access, 1); 147662306a36Sopenharmony_ci if (rc) 147762306a36Sopenharmony_ci return rc; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci srq->prod_umem = ib_umem_get(srq->ibsrq.device, ureq->prod_pair_addr, 148062306a36Sopenharmony_ci sizeof(struct rdma_srq_producers), access); 148162306a36Sopenharmony_ci if (IS_ERR(srq->prod_umem)) { 148262306a36Sopenharmony_ci qedr_free_pbl(srq->dev, &srq->usrq.pbl_info, srq->usrq.pbl_tbl); 148362306a36Sopenharmony_ci ib_umem_release(srq->usrq.umem); 148462306a36Sopenharmony_ci DP_ERR(srq->dev, 148562306a36Sopenharmony_ci "create srq: failed ib_umem_get for producer, got %ld\n", 148662306a36Sopenharmony_ci PTR_ERR(srq->prod_umem)); 148762306a36Sopenharmony_ci return PTR_ERR(srq->prod_umem); 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci sg = srq->prod_umem->sgt_append.sgt.sgl; 149162306a36Sopenharmony_ci srq->hw_srq.phy_prod_pair_addr = sg_dma_address(sg); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci return 0; 149462306a36Sopenharmony_ci} 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_cistatic int qedr_alloc_srq_kernel_params(struct qedr_srq *srq, 149762306a36Sopenharmony_ci struct qedr_dev *dev, 149862306a36Sopenharmony_ci struct ib_srq_init_attr *init_attr) 149962306a36Sopenharmony_ci{ 150062306a36Sopenharmony_ci struct qedr_srq_hwq_info *hw_srq = &srq->hw_srq; 150162306a36Sopenharmony_ci struct qed_chain_init_params params = { 150262306a36Sopenharmony_ci .mode = QED_CHAIN_MODE_PBL, 150362306a36Sopenharmony_ci .intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE, 150462306a36Sopenharmony_ci .cnt_type = QED_CHAIN_CNT_TYPE_U32, 150562306a36Sopenharmony_ci .elem_size = QEDR_SRQ_WQE_ELEM_SIZE, 150662306a36Sopenharmony_ci }; 150762306a36Sopenharmony_ci dma_addr_t phy_prod_pair_addr; 150862306a36Sopenharmony_ci u32 num_elems; 150962306a36Sopenharmony_ci void *va; 151062306a36Sopenharmony_ci int rc; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci va = dma_alloc_coherent(&dev->pdev->dev, 151362306a36Sopenharmony_ci sizeof(struct rdma_srq_producers), 151462306a36Sopenharmony_ci &phy_prod_pair_addr, GFP_KERNEL); 151562306a36Sopenharmony_ci if (!va) { 151662306a36Sopenharmony_ci DP_ERR(dev, 151762306a36Sopenharmony_ci "create srq: failed to allocate dma memory for producer\n"); 151862306a36Sopenharmony_ci return -ENOMEM; 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci hw_srq->phy_prod_pair_addr = phy_prod_pair_addr; 152262306a36Sopenharmony_ci hw_srq->virt_prod_pair_addr = va; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci num_elems = init_attr->attr.max_wr * RDMA_MAX_SRQ_WQE_SIZE; 152562306a36Sopenharmony_ci params.num_elems = num_elems; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci rc = dev->ops->common->chain_alloc(dev->cdev, &hw_srq->pbl, ¶ms); 152862306a36Sopenharmony_ci if (rc) 152962306a36Sopenharmony_ci goto err0; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci hw_srq->num_elems = num_elems; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci return 0; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_cierr0: 153662306a36Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, sizeof(struct rdma_srq_producers), 153762306a36Sopenharmony_ci va, phy_prod_pair_addr); 153862306a36Sopenharmony_ci return rc; 153962306a36Sopenharmony_ci} 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ciint qedr_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init_attr, 154262306a36Sopenharmony_ci struct ib_udata *udata) 154362306a36Sopenharmony_ci{ 154462306a36Sopenharmony_ci struct qed_rdma_destroy_srq_in_params destroy_in_params; 154562306a36Sopenharmony_ci struct qed_rdma_create_srq_in_params in_params = {}; 154662306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibsrq->device); 154762306a36Sopenharmony_ci struct qed_rdma_create_srq_out_params out_params; 154862306a36Sopenharmony_ci struct qedr_pd *pd = get_qedr_pd(ibsrq->pd); 154962306a36Sopenharmony_ci struct qedr_create_srq_ureq ureq = {}; 155062306a36Sopenharmony_ci u64 pbl_base_addr, phy_prod_pair_addr; 155162306a36Sopenharmony_ci struct qedr_srq_hwq_info *hw_srq; 155262306a36Sopenharmony_ci u32 page_cnt, page_size; 155362306a36Sopenharmony_ci struct qedr_srq *srq = get_qedr_srq(ibsrq); 155462306a36Sopenharmony_ci int rc = 0; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, 155762306a36Sopenharmony_ci "create SRQ called from %s (pd %p)\n", 155862306a36Sopenharmony_ci (udata) ? "User lib" : "kernel", pd); 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci if (init_attr->srq_type != IB_SRQT_BASIC && 156162306a36Sopenharmony_ci init_attr->srq_type != IB_SRQT_XRC) 156262306a36Sopenharmony_ci return -EOPNOTSUPP; 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci rc = qedr_check_srq_params(dev, init_attr, udata); 156562306a36Sopenharmony_ci if (rc) 156662306a36Sopenharmony_ci return -EINVAL; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci srq->dev = dev; 156962306a36Sopenharmony_ci srq->is_xrc = (init_attr->srq_type == IB_SRQT_XRC); 157062306a36Sopenharmony_ci hw_srq = &srq->hw_srq; 157162306a36Sopenharmony_ci spin_lock_init(&srq->lock); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci hw_srq->max_wr = init_attr->attr.max_wr; 157462306a36Sopenharmony_ci hw_srq->max_sges = init_attr->attr.max_sge; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci if (udata) { 157762306a36Sopenharmony_ci if (ib_copy_from_udata(&ureq, udata, min(sizeof(ureq), 157862306a36Sopenharmony_ci udata->inlen))) { 157962306a36Sopenharmony_ci DP_ERR(dev, 158062306a36Sopenharmony_ci "create srq: problem copying data from user space\n"); 158162306a36Sopenharmony_ci goto err0; 158262306a36Sopenharmony_ci } 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci rc = qedr_init_srq_user_params(udata, srq, &ureq, 0); 158562306a36Sopenharmony_ci if (rc) 158662306a36Sopenharmony_ci goto err0; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci page_cnt = srq->usrq.pbl_info.num_pbes; 158962306a36Sopenharmony_ci pbl_base_addr = srq->usrq.pbl_tbl->pa; 159062306a36Sopenharmony_ci phy_prod_pair_addr = hw_srq->phy_prod_pair_addr; 159162306a36Sopenharmony_ci page_size = PAGE_SIZE; 159262306a36Sopenharmony_ci } else { 159362306a36Sopenharmony_ci struct qed_chain *pbl; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci rc = qedr_alloc_srq_kernel_params(srq, dev, init_attr); 159662306a36Sopenharmony_ci if (rc) 159762306a36Sopenharmony_ci goto err0; 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci pbl = &hw_srq->pbl; 160062306a36Sopenharmony_ci page_cnt = qed_chain_get_page_cnt(pbl); 160162306a36Sopenharmony_ci pbl_base_addr = qed_chain_get_pbl_phys(pbl); 160262306a36Sopenharmony_ci phy_prod_pair_addr = hw_srq->phy_prod_pair_addr; 160362306a36Sopenharmony_ci page_size = QED_CHAIN_PAGE_SIZE; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci in_params.pd_id = pd->pd_id; 160762306a36Sopenharmony_ci in_params.pbl_base_addr = pbl_base_addr; 160862306a36Sopenharmony_ci in_params.prod_pair_addr = phy_prod_pair_addr; 160962306a36Sopenharmony_ci in_params.num_pages = page_cnt; 161062306a36Sopenharmony_ci in_params.page_size = page_size; 161162306a36Sopenharmony_ci if (srq->is_xrc) { 161262306a36Sopenharmony_ci struct qedr_xrcd *xrcd = get_qedr_xrcd(init_attr->ext.xrc.xrcd); 161362306a36Sopenharmony_ci struct qedr_cq *cq = get_qedr_cq(init_attr->ext.cq); 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci in_params.is_xrc = 1; 161662306a36Sopenharmony_ci in_params.xrcd_id = xrcd->xrcd_id; 161762306a36Sopenharmony_ci in_params.cq_cid = cq->icid; 161862306a36Sopenharmony_ci } 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci rc = dev->ops->rdma_create_srq(dev->rdma_ctx, &in_params, &out_params); 162162306a36Sopenharmony_ci if (rc) 162262306a36Sopenharmony_ci goto err1; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci srq->srq_id = out_params.srq_id; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci if (udata) { 162762306a36Sopenharmony_ci rc = qedr_copy_srq_uresp(dev, srq, udata); 162862306a36Sopenharmony_ci if (rc) 162962306a36Sopenharmony_ci goto err2; 163062306a36Sopenharmony_ci } 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci rc = xa_insert_irq(&dev->srqs, srq->srq_id, srq, GFP_KERNEL); 163362306a36Sopenharmony_ci if (rc) 163462306a36Sopenharmony_ci goto err2; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_SRQ, 163762306a36Sopenharmony_ci "create srq: created srq with srq_id=0x%0x\n", srq->srq_id); 163862306a36Sopenharmony_ci return 0; 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_cierr2: 164162306a36Sopenharmony_ci destroy_in_params.srq_id = srq->srq_id; 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci dev->ops->rdma_destroy_srq(dev->rdma_ctx, &destroy_in_params); 164462306a36Sopenharmony_cierr1: 164562306a36Sopenharmony_ci if (udata) 164662306a36Sopenharmony_ci qedr_free_srq_user_params(srq); 164762306a36Sopenharmony_ci else 164862306a36Sopenharmony_ci qedr_free_srq_kernel_params(srq); 164962306a36Sopenharmony_cierr0: 165062306a36Sopenharmony_ci return -EFAULT; 165162306a36Sopenharmony_ci} 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ciint qedr_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata) 165462306a36Sopenharmony_ci{ 165562306a36Sopenharmony_ci struct qed_rdma_destroy_srq_in_params in_params = {}; 165662306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibsrq->device); 165762306a36Sopenharmony_ci struct qedr_srq *srq = get_qedr_srq(ibsrq); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci xa_erase_irq(&dev->srqs, srq->srq_id); 166062306a36Sopenharmony_ci in_params.srq_id = srq->srq_id; 166162306a36Sopenharmony_ci in_params.is_xrc = srq->is_xrc; 166262306a36Sopenharmony_ci dev->ops->rdma_destroy_srq(dev->rdma_ctx, &in_params); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci if (ibsrq->uobject) 166562306a36Sopenharmony_ci qedr_free_srq_user_params(srq); 166662306a36Sopenharmony_ci else 166762306a36Sopenharmony_ci qedr_free_srq_kernel_params(srq); 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_SRQ, 167062306a36Sopenharmony_ci "destroy srq: destroyed srq with srq_id=0x%0x\n", 167162306a36Sopenharmony_ci srq->srq_id); 167262306a36Sopenharmony_ci return 0; 167362306a36Sopenharmony_ci} 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ciint qedr_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, 167662306a36Sopenharmony_ci enum ib_srq_attr_mask attr_mask, struct ib_udata *udata) 167762306a36Sopenharmony_ci{ 167862306a36Sopenharmony_ci struct qed_rdma_modify_srq_in_params in_params = {}; 167962306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibsrq->device); 168062306a36Sopenharmony_ci struct qedr_srq *srq = get_qedr_srq(ibsrq); 168162306a36Sopenharmony_ci int rc; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci if (attr_mask & IB_SRQ_MAX_WR) { 168462306a36Sopenharmony_ci DP_ERR(dev, 168562306a36Sopenharmony_ci "modify srq: invalid attribute mask=0x%x specified for %p\n", 168662306a36Sopenharmony_ci attr_mask, srq); 168762306a36Sopenharmony_ci return -EINVAL; 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci if (attr_mask & IB_SRQ_LIMIT) { 169162306a36Sopenharmony_ci if (attr->srq_limit >= srq->hw_srq.max_wr) { 169262306a36Sopenharmony_ci DP_ERR(dev, 169362306a36Sopenharmony_ci "modify srq: invalid srq_limit=0x%x (max_srq_limit=0x%x)\n", 169462306a36Sopenharmony_ci attr->srq_limit, srq->hw_srq.max_wr); 169562306a36Sopenharmony_ci return -EINVAL; 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci in_params.srq_id = srq->srq_id; 169962306a36Sopenharmony_ci in_params.wqe_limit = attr->srq_limit; 170062306a36Sopenharmony_ci rc = dev->ops->rdma_modify_srq(dev->rdma_ctx, &in_params); 170162306a36Sopenharmony_ci if (rc) 170262306a36Sopenharmony_ci return rc; 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci srq->srq_limit = attr->srq_limit; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_SRQ, 170862306a36Sopenharmony_ci "modify srq: modified srq with srq_id=0x%0x\n", srq->srq_id); 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci return 0; 171162306a36Sopenharmony_ci} 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_cistatic enum qed_rdma_qp_type qedr_ib_to_qed_qp_type(enum ib_qp_type ib_qp_type) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci switch (ib_qp_type) { 171662306a36Sopenharmony_ci case IB_QPT_RC: 171762306a36Sopenharmony_ci return QED_RDMA_QP_TYPE_RC; 171862306a36Sopenharmony_ci case IB_QPT_XRC_INI: 171962306a36Sopenharmony_ci return QED_RDMA_QP_TYPE_XRC_INI; 172062306a36Sopenharmony_ci case IB_QPT_XRC_TGT: 172162306a36Sopenharmony_ci return QED_RDMA_QP_TYPE_XRC_TGT; 172262306a36Sopenharmony_ci default: 172362306a36Sopenharmony_ci return QED_RDMA_QP_TYPE_INVAL; 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci} 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_cistatic inline void 172862306a36Sopenharmony_ciqedr_init_common_qp_in_params(struct qedr_dev *dev, 172962306a36Sopenharmony_ci struct qedr_pd *pd, 173062306a36Sopenharmony_ci struct qedr_qp *qp, 173162306a36Sopenharmony_ci struct ib_qp_init_attr *attrs, 173262306a36Sopenharmony_ci bool fmr_and_reserved_lkey, 173362306a36Sopenharmony_ci struct qed_rdma_create_qp_in_params *params) 173462306a36Sopenharmony_ci{ 173562306a36Sopenharmony_ci /* QP handle to be written in an async event */ 173662306a36Sopenharmony_ci params->qp_handle_async_lo = lower_32_bits((uintptr_t) qp); 173762306a36Sopenharmony_ci params->qp_handle_async_hi = upper_32_bits((uintptr_t) qp); 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci params->signal_all = (attrs->sq_sig_type == IB_SIGNAL_ALL_WR); 174062306a36Sopenharmony_ci params->fmr_and_reserved_lkey = fmr_and_reserved_lkey; 174162306a36Sopenharmony_ci params->qp_type = qedr_ib_to_qed_qp_type(attrs->qp_type); 174262306a36Sopenharmony_ci params->stats_queue = 0; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci if (pd) { 174562306a36Sopenharmony_ci params->pd = pd->pd_id; 174662306a36Sopenharmony_ci params->dpi = pd->uctx ? pd->uctx->dpi : dev->dpi; 174762306a36Sopenharmony_ci } 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci if (qedr_qp_has_sq(qp)) 175062306a36Sopenharmony_ci params->sq_cq_id = get_qedr_cq(attrs->send_cq)->icid; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci if (qedr_qp_has_rq(qp)) 175362306a36Sopenharmony_ci params->rq_cq_id = get_qedr_cq(attrs->recv_cq)->icid; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci if (qedr_qp_has_srq(qp)) { 175662306a36Sopenharmony_ci params->rq_cq_id = get_qedr_cq(attrs->recv_cq)->icid; 175762306a36Sopenharmony_ci params->srq_id = qp->srq->srq_id; 175862306a36Sopenharmony_ci params->use_srq = true; 175962306a36Sopenharmony_ci } else { 176062306a36Sopenharmony_ci params->srq_id = 0; 176162306a36Sopenharmony_ci params->use_srq = false; 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci} 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_cistatic inline void qedr_qp_user_print(struct qedr_dev *dev, struct qedr_qp *qp) 176662306a36Sopenharmony_ci{ 176762306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, "create qp: successfully created user QP. " 176862306a36Sopenharmony_ci "qp=%p. " 176962306a36Sopenharmony_ci "sq_addr=0x%llx, " 177062306a36Sopenharmony_ci "sq_len=%zd, " 177162306a36Sopenharmony_ci "rq_addr=0x%llx, " 177262306a36Sopenharmony_ci "rq_len=%zd" 177362306a36Sopenharmony_ci "\n", 177462306a36Sopenharmony_ci qp, 177562306a36Sopenharmony_ci qedr_qp_has_sq(qp) ? qp->usq.buf_addr : 0x0, 177662306a36Sopenharmony_ci qedr_qp_has_sq(qp) ? qp->usq.buf_len : 0, 177762306a36Sopenharmony_ci qedr_qp_has_rq(qp) ? qp->urq.buf_addr : 0x0, 177862306a36Sopenharmony_ci qedr_qp_has_sq(qp) ? qp->urq.buf_len : 0); 177962306a36Sopenharmony_ci} 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_cistatic inline void 178262306a36Sopenharmony_ciqedr_iwarp_populate_user_qp(struct qedr_dev *dev, 178362306a36Sopenharmony_ci struct qedr_qp *qp, 178462306a36Sopenharmony_ci struct qed_rdma_create_qp_out_params *out_params) 178562306a36Sopenharmony_ci{ 178662306a36Sopenharmony_ci qp->usq.pbl_tbl->va = out_params->sq_pbl_virt; 178762306a36Sopenharmony_ci qp->usq.pbl_tbl->pa = out_params->sq_pbl_phys; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci qedr_populate_pbls(dev, qp->usq.umem, qp->usq.pbl_tbl, 179062306a36Sopenharmony_ci &qp->usq.pbl_info, FW_PAGE_SHIFT); 179162306a36Sopenharmony_ci if (!qp->srq) { 179262306a36Sopenharmony_ci qp->urq.pbl_tbl->va = out_params->rq_pbl_virt; 179362306a36Sopenharmony_ci qp->urq.pbl_tbl->pa = out_params->rq_pbl_phys; 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci qedr_populate_pbls(dev, qp->urq.umem, qp->urq.pbl_tbl, 179762306a36Sopenharmony_ci &qp->urq.pbl_info, FW_PAGE_SHIFT); 179862306a36Sopenharmony_ci} 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_cistatic void qedr_cleanup_user(struct qedr_dev *dev, 180162306a36Sopenharmony_ci struct qedr_ucontext *ctx, 180262306a36Sopenharmony_ci struct qedr_qp *qp) 180362306a36Sopenharmony_ci{ 180462306a36Sopenharmony_ci if (qedr_qp_has_sq(qp)) { 180562306a36Sopenharmony_ci ib_umem_release(qp->usq.umem); 180662306a36Sopenharmony_ci qp->usq.umem = NULL; 180762306a36Sopenharmony_ci } 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci if (qedr_qp_has_rq(qp)) { 181062306a36Sopenharmony_ci ib_umem_release(qp->urq.umem); 181162306a36Sopenharmony_ci qp->urq.umem = NULL; 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci if (rdma_protocol_roce(&dev->ibdev, 1)) { 181562306a36Sopenharmony_ci qedr_free_pbl(dev, &qp->usq.pbl_info, qp->usq.pbl_tbl); 181662306a36Sopenharmony_ci qedr_free_pbl(dev, &qp->urq.pbl_info, qp->urq.pbl_tbl); 181762306a36Sopenharmony_ci } else { 181862306a36Sopenharmony_ci kfree(qp->usq.pbl_tbl); 181962306a36Sopenharmony_ci kfree(qp->urq.pbl_tbl); 182062306a36Sopenharmony_ci } 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci if (qp->usq.db_rec_data) { 182362306a36Sopenharmony_ci qedr_db_recovery_del(dev, qp->usq.db_addr, 182462306a36Sopenharmony_ci &qp->usq.db_rec_data->db_data); 182562306a36Sopenharmony_ci rdma_user_mmap_entry_remove(qp->usq.db_mmap_entry); 182662306a36Sopenharmony_ci } 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci if (qp->urq.db_rec_data) { 182962306a36Sopenharmony_ci qedr_db_recovery_del(dev, qp->urq.db_addr, 183062306a36Sopenharmony_ci &qp->urq.db_rec_data->db_data); 183162306a36Sopenharmony_ci rdma_user_mmap_entry_remove(qp->urq.db_mmap_entry); 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) 183562306a36Sopenharmony_ci qedr_db_recovery_del(dev, qp->urq.db_rec_db2_addr, 183662306a36Sopenharmony_ci &qp->urq.db_rec_db2_data); 183762306a36Sopenharmony_ci} 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_cistatic int qedr_create_user_qp(struct qedr_dev *dev, 184062306a36Sopenharmony_ci struct qedr_qp *qp, 184162306a36Sopenharmony_ci struct ib_pd *ibpd, 184262306a36Sopenharmony_ci struct ib_udata *udata, 184362306a36Sopenharmony_ci struct ib_qp_init_attr *attrs) 184462306a36Sopenharmony_ci{ 184562306a36Sopenharmony_ci struct qed_rdma_create_qp_in_params in_params; 184662306a36Sopenharmony_ci struct qed_rdma_create_qp_out_params out_params; 184762306a36Sopenharmony_ci struct qedr_create_qp_uresp uresp = {}; 184862306a36Sopenharmony_ci struct qedr_create_qp_ureq ureq = {}; 184962306a36Sopenharmony_ci int alloc_and_init = rdma_protocol_roce(&dev->ibdev, 1); 185062306a36Sopenharmony_ci struct qedr_ucontext *ctx = NULL; 185162306a36Sopenharmony_ci struct qedr_pd *pd = NULL; 185262306a36Sopenharmony_ci int rc = 0; 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci qp->create_type = QEDR_QP_CREATE_USER; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci if (ibpd) { 185762306a36Sopenharmony_ci pd = get_qedr_pd(ibpd); 185862306a36Sopenharmony_ci ctx = pd->uctx; 185962306a36Sopenharmony_ci } 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci if (udata) { 186262306a36Sopenharmony_ci rc = ib_copy_from_udata(&ureq, udata, min(sizeof(ureq), 186362306a36Sopenharmony_ci udata->inlen)); 186462306a36Sopenharmony_ci if (rc) { 186562306a36Sopenharmony_ci DP_ERR(dev, "Problem copying data from user space\n"); 186662306a36Sopenharmony_ci return rc; 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci } 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci if (qedr_qp_has_sq(qp)) { 187162306a36Sopenharmony_ci /* SQ - read access only (0) */ 187262306a36Sopenharmony_ci rc = qedr_init_user_queue(udata, dev, &qp->usq, ureq.sq_addr, 187362306a36Sopenharmony_ci ureq.sq_len, true, 0, alloc_and_init); 187462306a36Sopenharmony_ci if (rc) 187562306a36Sopenharmony_ci return rc; 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci if (qedr_qp_has_rq(qp)) { 187962306a36Sopenharmony_ci /* RQ - read access only (0) */ 188062306a36Sopenharmony_ci rc = qedr_init_user_queue(udata, dev, &qp->urq, ureq.rq_addr, 188162306a36Sopenharmony_ci ureq.rq_len, true, 0, alloc_and_init); 188262306a36Sopenharmony_ci if (rc) { 188362306a36Sopenharmony_ci ib_umem_release(qp->usq.umem); 188462306a36Sopenharmony_ci qp->usq.umem = NULL; 188562306a36Sopenharmony_ci if (rdma_protocol_roce(&dev->ibdev, 1)) { 188662306a36Sopenharmony_ci qedr_free_pbl(dev, &qp->usq.pbl_info, 188762306a36Sopenharmony_ci qp->usq.pbl_tbl); 188862306a36Sopenharmony_ci } else { 188962306a36Sopenharmony_ci kfree(qp->usq.pbl_tbl); 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci return rc; 189262306a36Sopenharmony_ci } 189362306a36Sopenharmony_ci } 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci memset(&in_params, 0, sizeof(in_params)); 189662306a36Sopenharmony_ci qedr_init_common_qp_in_params(dev, pd, qp, attrs, false, &in_params); 189762306a36Sopenharmony_ci in_params.qp_handle_lo = ureq.qp_handle_lo; 189862306a36Sopenharmony_ci in_params.qp_handle_hi = ureq.qp_handle_hi; 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_XRC_TGT) { 190162306a36Sopenharmony_ci struct qedr_xrcd *xrcd = get_qedr_xrcd(attrs->xrcd); 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci in_params.xrcd_id = xrcd->xrcd_id; 190462306a36Sopenharmony_ci in_params.qp_handle_lo = qp->qp_id; 190562306a36Sopenharmony_ci in_params.use_srq = 1; 190662306a36Sopenharmony_ci } 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci if (qedr_qp_has_sq(qp)) { 190962306a36Sopenharmony_ci in_params.sq_num_pages = qp->usq.pbl_info.num_pbes; 191062306a36Sopenharmony_ci in_params.sq_pbl_ptr = qp->usq.pbl_tbl->pa; 191162306a36Sopenharmony_ci } 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci if (qedr_qp_has_rq(qp)) { 191462306a36Sopenharmony_ci in_params.rq_num_pages = qp->urq.pbl_info.num_pbes; 191562306a36Sopenharmony_ci in_params.rq_pbl_ptr = qp->urq.pbl_tbl->pa; 191662306a36Sopenharmony_ci } 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci if (ctx) 191962306a36Sopenharmony_ci SET_FIELD(in_params.flags, QED_ROCE_EDPM_MODE, ctx->edpm_mode); 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx, 192262306a36Sopenharmony_ci &in_params, &out_params); 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci if (!qp->qed_qp) { 192562306a36Sopenharmony_ci rc = -ENOMEM; 192662306a36Sopenharmony_ci goto err1; 192762306a36Sopenharmony_ci } 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) 193062306a36Sopenharmony_ci qedr_iwarp_populate_user_qp(dev, qp, &out_params); 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci qp->qp_id = out_params.qp_id; 193362306a36Sopenharmony_ci qp->icid = out_params.icid; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci if (udata) { 193662306a36Sopenharmony_ci rc = qedr_copy_qp_uresp(dev, qp, udata, &uresp); 193762306a36Sopenharmony_ci if (rc) 193862306a36Sopenharmony_ci goto err; 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci /* db offset was calculated in copy_qp_uresp, now set in the user q */ 194262306a36Sopenharmony_ci if (qedr_qp_has_sq(qp)) { 194362306a36Sopenharmony_ci qp->usq.db_addr = ctx->dpi_addr + uresp.sq_db_offset; 194462306a36Sopenharmony_ci qp->sq.max_wr = attrs->cap.max_send_wr; 194562306a36Sopenharmony_ci rc = qedr_db_recovery_add(dev, qp->usq.db_addr, 194662306a36Sopenharmony_ci &qp->usq.db_rec_data->db_data, 194762306a36Sopenharmony_ci DB_REC_WIDTH_32B, 194862306a36Sopenharmony_ci DB_REC_USER); 194962306a36Sopenharmony_ci if (rc) 195062306a36Sopenharmony_ci goto err; 195162306a36Sopenharmony_ci } 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci if (qedr_qp_has_rq(qp)) { 195462306a36Sopenharmony_ci qp->urq.db_addr = ctx->dpi_addr + uresp.rq_db_offset; 195562306a36Sopenharmony_ci qp->rq.max_wr = attrs->cap.max_recv_wr; 195662306a36Sopenharmony_ci rc = qedr_db_recovery_add(dev, qp->urq.db_addr, 195762306a36Sopenharmony_ci &qp->urq.db_rec_data->db_data, 195862306a36Sopenharmony_ci DB_REC_WIDTH_32B, 195962306a36Sopenharmony_ci DB_REC_USER); 196062306a36Sopenharmony_ci if (rc) 196162306a36Sopenharmony_ci goto err; 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) { 196562306a36Sopenharmony_ci qp->urq.db_rec_db2_addr = ctx->dpi_addr + uresp.rq_db2_offset; 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci /* calculate the db_rec_db2 data since it is constant so no 196862306a36Sopenharmony_ci * need to reflect from user 196962306a36Sopenharmony_ci */ 197062306a36Sopenharmony_ci qp->urq.db_rec_db2_data.data.icid = cpu_to_le16(qp->icid); 197162306a36Sopenharmony_ci qp->urq.db_rec_db2_data.data.value = 197262306a36Sopenharmony_ci cpu_to_le16(DQ_TCM_IWARP_POST_RQ_CF_CMD); 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci rc = qedr_db_recovery_add(dev, qp->urq.db_rec_db2_addr, 197562306a36Sopenharmony_ci &qp->urq.db_rec_db2_data, 197662306a36Sopenharmony_ci DB_REC_WIDTH_32B, 197762306a36Sopenharmony_ci DB_REC_USER); 197862306a36Sopenharmony_ci if (rc) 197962306a36Sopenharmony_ci goto err; 198062306a36Sopenharmony_ci } 198162306a36Sopenharmony_ci qedr_qp_user_print(dev, qp); 198262306a36Sopenharmony_ci return rc; 198362306a36Sopenharmony_cierr: 198462306a36Sopenharmony_ci rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp); 198562306a36Sopenharmony_ci if (rc) 198662306a36Sopenharmony_ci DP_ERR(dev, "create qp: fatal fault. rc=%d", rc); 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_cierr1: 198962306a36Sopenharmony_ci qedr_cleanup_user(dev, ctx, qp); 199062306a36Sopenharmony_ci return rc; 199162306a36Sopenharmony_ci} 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_cistatic int qedr_set_iwarp_db_info(struct qedr_dev *dev, struct qedr_qp *qp) 199462306a36Sopenharmony_ci{ 199562306a36Sopenharmony_ci int rc; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci qp->sq.db = dev->db_addr + 199862306a36Sopenharmony_ci DB_ADDR_SHIFT(DQ_PWM_OFFSET_XCM_RDMA_SQ_PROD); 199962306a36Sopenharmony_ci qp->sq.db_data.data.icid = qp->icid; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci rc = qedr_db_recovery_add(dev, qp->sq.db, 200262306a36Sopenharmony_ci &qp->sq.db_data, 200362306a36Sopenharmony_ci DB_REC_WIDTH_32B, 200462306a36Sopenharmony_ci DB_REC_KERNEL); 200562306a36Sopenharmony_ci if (rc) 200662306a36Sopenharmony_ci return rc; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci qp->rq.db = dev->db_addr + 200962306a36Sopenharmony_ci DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_IWARP_RQ_PROD); 201062306a36Sopenharmony_ci qp->rq.db_data.data.icid = qp->icid; 201162306a36Sopenharmony_ci qp->rq.iwarp_db2 = dev->db_addr + 201262306a36Sopenharmony_ci DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_FLAGS); 201362306a36Sopenharmony_ci qp->rq.iwarp_db2_data.data.icid = qp->icid; 201462306a36Sopenharmony_ci qp->rq.iwarp_db2_data.data.value = DQ_TCM_IWARP_POST_RQ_CF_CMD; 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci rc = qedr_db_recovery_add(dev, qp->rq.db, 201762306a36Sopenharmony_ci &qp->rq.db_data, 201862306a36Sopenharmony_ci DB_REC_WIDTH_32B, 201962306a36Sopenharmony_ci DB_REC_KERNEL); 202062306a36Sopenharmony_ci if (rc) 202162306a36Sopenharmony_ci return rc; 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci rc = qedr_db_recovery_add(dev, qp->rq.iwarp_db2, 202462306a36Sopenharmony_ci &qp->rq.iwarp_db2_data, 202562306a36Sopenharmony_ci DB_REC_WIDTH_32B, 202662306a36Sopenharmony_ci DB_REC_KERNEL); 202762306a36Sopenharmony_ci return rc; 202862306a36Sopenharmony_ci} 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_cistatic int 203162306a36Sopenharmony_ciqedr_roce_create_kernel_qp(struct qedr_dev *dev, 203262306a36Sopenharmony_ci struct qedr_qp *qp, 203362306a36Sopenharmony_ci struct qed_rdma_create_qp_in_params *in_params, 203462306a36Sopenharmony_ci u32 n_sq_elems, u32 n_rq_elems) 203562306a36Sopenharmony_ci{ 203662306a36Sopenharmony_ci struct qed_rdma_create_qp_out_params out_params; 203762306a36Sopenharmony_ci struct qed_chain_init_params params = { 203862306a36Sopenharmony_ci .mode = QED_CHAIN_MODE_PBL, 203962306a36Sopenharmony_ci .cnt_type = QED_CHAIN_CNT_TYPE_U32, 204062306a36Sopenharmony_ci }; 204162306a36Sopenharmony_ci int rc; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci params.intended_use = QED_CHAIN_USE_TO_PRODUCE; 204462306a36Sopenharmony_ci params.num_elems = n_sq_elems; 204562306a36Sopenharmony_ci params.elem_size = QEDR_SQE_ELEMENT_SIZE; 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci rc = dev->ops->common->chain_alloc(dev->cdev, &qp->sq.pbl, ¶ms); 204862306a36Sopenharmony_ci if (rc) 204962306a36Sopenharmony_ci return rc; 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci in_params->sq_num_pages = qed_chain_get_page_cnt(&qp->sq.pbl); 205262306a36Sopenharmony_ci in_params->sq_pbl_ptr = qed_chain_get_pbl_phys(&qp->sq.pbl); 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci params.intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE; 205562306a36Sopenharmony_ci params.num_elems = n_rq_elems; 205662306a36Sopenharmony_ci params.elem_size = QEDR_RQE_ELEMENT_SIZE; 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci rc = dev->ops->common->chain_alloc(dev->cdev, &qp->rq.pbl, ¶ms); 205962306a36Sopenharmony_ci if (rc) 206062306a36Sopenharmony_ci return rc; 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci in_params->rq_num_pages = qed_chain_get_page_cnt(&qp->rq.pbl); 206362306a36Sopenharmony_ci in_params->rq_pbl_ptr = qed_chain_get_pbl_phys(&qp->rq.pbl); 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx, 206662306a36Sopenharmony_ci in_params, &out_params); 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci if (!qp->qed_qp) 206962306a36Sopenharmony_ci return -EINVAL; 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci qp->qp_id = out_params.qp_id; 207262306a36Sopenharmony_ci qp->icid = out_params.icid; 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci return qedr_set_roce_db_info(dev, qp); 207562306a36Sopenharmony_ci} 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_cistatic int 207862306a36Sopenharmony_ciqedr_iwarp_create_kernel_qp(struct qedr_dev *dev, 207962306a36Sopenharmony_ci struct qedr_qp *qp, 208062306a36Sopenharmony_ci struct qed_rdma_create_qp_in_params *in_params, 208162306a36Sopenharmony_ci u32 n_sq_elems, u32 n_rq_elems) 208262306a36Sopenharmony_ci{ 208362306a36Sopenharmony_ci struct qed_rdma_create_qp_out_params out_params; 208462306a36Sopenharmony_ci struct qed_chain_init_params params = { 208562306a36Sopenharmony_ci .mode = QED_CHAIN_MODE_PBL, 208662306a36Sopenharmony_ci .cnt_type = QED_CHAIN_CNT_TYPE_U32, 208762306a36Sopenharmony_ci }; 208862306a36Sopenharmony_ci int rc; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci in_params->sq_num_pages = QED_CHAIN_PAGE_CNT(n_sq_elems, 209162306a36Sopenharmony_ci QEDR_SQE_ELEMENT_SIZE, 209262306a36Sopenharmony_ci QED_CHAIN_PAGE_SIZE, 209362306a36Sopenharmony_ci QED_CHAIN_MODE_PBL); 209462306a36Sopenharmony_ci in_params->rq_num_pages = QED_CHAIN_PAGE_CNT(n_rq_elems, 209562306a36Sopenharmony_ci QEDR_RQE_ELEMENT_SIZE, 209662306a36Sopenharmony_ci QED_CHAIN_PAGE_SIZE, 209762306a36Sopenharmony_ci QED_CHAIN_MODE_PBL); 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx, 210062306a36Sopenharmony_ci in_params, &out_params); 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci if (!qp->qed_qp) 210362306a36Sopenharmony_ci return -EINVAL; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci /* Now we allocate the chain */ 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci params.intended_use = QED_CHAIN_USE_TO_PRODUCE; 210862306a36Sopenharmony_ci params.num_elems = n_sq_elems; 210962306a36Sopenharmony_ci params.elem_size = QEDR_SQE_ELEMENT_SIZE; 211062306a36Sopenharmony_ci params.ext_pbl_virt = out_params.sq_pbl_virt; 211162306a36Sopenharmony_ci params.ext_pbl_phys = out_params.sq_pbl_phys; 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci rc = dev->ops->common->chain_alloc(dev->cdev, &qp->sq.pbl, ¶ms); 211462306a36Sopenharmony_ci if (rc) 211562306a36Sopenharmony_ci goto err; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci params.intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE; 211862306a36Sopenharmony_ci params.num_elems = n_rq_elems; 211962306a36Sopenharmony_ci params.elem_size = QEDR_RQE_ELEMENT_SIZE; 212062306a36Sopenharmony_ci params.ext_pbl_virt = out_params.rq_pbl_virt; 212162306a36Sopenharmony_ci params.ext_pbl_phys = out_params.rq_pbl_phys; 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci rc = dev->ops->common->chain_alloc(dev->cdev, &qp->rq.pbl, ¶ms); 212462306a36Sopenharmony_ci if (rc) 212562306a36Sopenharmony_ci goto err; 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci qp->qp_id = out_params.qp_id; 212862306a36Sopenharmony_ci qp->icid = out_params.icid; 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci return qedr_set_iwarp_db_info(dev, qp); 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_cierr: 213362306a36Sopenharmony_ci dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp); 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci return rc; 213662306a36Sopenharmony_ci} 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_cistatic void qedr_cleanup_kernel(struct qedr_dev *dev, struct qedr_qp *qp) 213962306a36Sopenharmony_ci{ 214062306a36Sopenharmony_ci dev->ops->common->chain_free(dev->cdev, &qp->sq.pbl); 214162306a36Sopenharmony_ci kfree(qp->wqe_wr_id); 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci dev->ops->common->chain_free(dev->cdev, &qp->rq.pbl); 214462306a36Sopenharmony_ci kfree(qp->rqe_wr_id); 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci /* GSI qp is not registered to db mechanism so no need to delete */ 214762306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_GSI) 214862306a36Sopenharmony_ci return; 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci qedr_db_recovery_del(dev, qp->sq.db, &qp->sq.db_data); 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci if (!qp->srq) { 215362306a36Sopenharmony_ci qedr_db_recovery_del(dev, qp->rq.db, &qp->rq.db_data); 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) 215662306a36Sopenharmony_ci qedr_db_recovery_del(dev, qp->rq.iwarp_db2, 215762306a36Sopenharmony_ci &qp->rq.iwarp_db2_data); 215862306a36Sopenharmony_ci } 215962306a36Sopenharmony_ci} 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_cistatic int qedr_create_kernel_qp(struct qedr_dev *dev, 216262306a36Sopenharmony_ci struct qedr_qp *qp, 216362306a36Sopenharmony_ci struct ib_pd *ibpd, 216462306a36Sopenharmony_ci struct ib_qp_init_attr *attrs) 216562306a36Sopenharmony_ci{ 216662306a36Sopenharmony_ci struct qed_rdma_create_qp_in_params in_params; 216762306a36Sopenharmony_ci struct qedr_pd *pd = get_qedr_pd(ibpd); 216862306a36Sopenharmony_ci int rc = -EINVAL; 216962306a36Sopenharmony_ci u32 n_rq_elems; 217062306a36Sopenharmony_ci u32 n_sq_elems; 217162306a36Sopenharmony_ci u32 n_sq_entries; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci memset(&in_params, 0, sizeof(in_params)); 217462306a36Sopenharmony_ci qp->create_type = QEDR_QP_CREATE_KERNEL; 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci /* A single work request may take up to QEDR_MAX_SQ_WQE_SIZE elements in 217762306a36Sopenharmony_ci * the ring. The ring should allow at least a single WR, even if the 217862306a36Sopenharmony_ci * user requested none, due to allocation issues. 217962306a36Sopenharmony_ci * We should add an extra WR since the prod and cons indices of 218062306a36Sopenharmony_ci * wqe_wr_id are managed in such a way that the WQ is considered full 218162306a36Sopenharmony_ci * when (prod+1)%max_wr==cons. We currently don't do that because we 218262306a36Sopenharmony_ci * double the number of entries due an iSER issue that pushes far more 218362306a36Sopenharmony_ci * WRs than indicated. If we decline its ib_post_send() then we get 218462306a36Sopenharmony_ci * error prints in the dmesg we'd like to avoid. 218562306a36Sopenharmony_ci */ 218662306a36Sopenharmony_ci qp->sq.max_wr = min_t(u32, attrs->cap.max_send_wr * dev->wq_multiplier, 218762306a36Sopenharmony_ci dev->attr.max_sqe); 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci qp->wqe_wr_id = kcalloc(qp->sq.max_wr, sizeof(*qp->wqe_wr_id), 219062306a36Sopenharmony_ci GFP_KERNEL); 219162306a36Sopenharmony_ci if (!qp->wqe_wr_id) { 219262306a36Sopenharmony_ci DP_ERR(dev, "create qp: failed SQ shadow memory allocation\n"); 219362306a36Sopenharmony_ci return -ENOMEM; 219462306a36Sopenharmony_ci } 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci /* QP handle to be written in CQE */ 219762306a36Sopenharmony_ci in_params.qp_handle_lo = lower_32_bits((uintptr_t) qp); 219862306a36Sopenharmony_ci in_params.qp_handle_hi = upper_32_bits((uintptr_t) qp); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci /* A single work request may take up to QEDR_MAX_RQ_WQE_SIZE elements in 220162306a36Sopenharmony_ci * the ring. There ring should allow at least a single WR, even if the 220262306a36Sopenharmony_ci * user requested none, due to allocation issues. 220362306a36Sopenharmony_ci */ 220462306a36Sopenharmony_ci qp->rq.max_wr = (u16) max_t(u32, attrs->cap.max_recv_wr, 1); 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci /* Allocate driver internal RQ array */ 220762306a36Sopenharmony_ci qp->rqe_wr_id = kcalloc(qp->rq.max_wr, sizeof(*qp->rqe_wr_id), 220862306a36Sopenharmony_ci GFP_KERNEL); 220962306a36Sopenharmony_ci if (!qp->rqe_wr_id) { 221062306a36Sopenharmony_ci DP_ERR(dev, 221162306a36Sopenharmony_ci "create qp: failed RQ shadow memory allocation\n"); 221262306a36Sopenharmony_ci kfree(qp->wqe_wr_id); 221362306a36Sopenharmony_ci return -ENOMEM; 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci qedr_init_common_qp_in_params(dev, pd, qp, attrs, true, &in_params); 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci n_sq_entries = attrs->cap.max_send_wr; 221962306a36Sopenharmony_ci n_sq_entries = min_t(u32, n_sq_entries, dev->attr.max_sqe); 222062306a36Sopenharmony_ci n_sq_entries = max_t(u32, n_sq_entries, 1); 222162306a36Sopenharmony_ci n_sq_elems = n_sq_entries * QEDR_MAX_SQE_ELEMENTS_PER_SQE; 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci n_rq_elems = qp->rq.max_wr * QEDR_MAX_RQE_ELEMENTS_PER_RQE; 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) 222662306a36Sopenharmony_ci rc = qedr_iwarp_create_kernel_qp(dev, qp, &in_params, 222762306a36Sopenharmony_ci n_sq_elems, n_rq_elems); 222862306a36Sopenharmony_ci else 222962306a36Sopenharmony_ci rc = qedr_roce_create_kernel_qp(dev, qp, &in_params, 223062306a36Sopenharmony_ci n_sq_elems, n_rq_elems); 223162306a36Sopenharmony_ci if (rc) 223262306a36Sopenharmony_ci qedr_cleanup_kernel(dev, qp); 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci return rc; 223562306a36Sopenharmony_ci} 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_cistatic int qedr_free_qp_resources(struct qedr_dev *dev, struct qedr_qp *qp, 223862306a36Sopenharmony_ci struct ib_udata *udata) 223962306a36Sopenharmony_ci{ 224062306a36Sopenharmony_ci struct qedr_ucontext *ctx = 224162306a36Sopenharmony_ci rdma_udata_to_drv_context(udata, struct qedr_ucontext, 224262306a36Sopenharmony_ci ibucontext); 224362306a36Sopenharmony_ci int rc; 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci if (qp->qp_type != IB_QPT_GSI) { 224662306a36Sopenharmony_ci rc = dev->ops->rdma_destroy_qp(dev->rdma_ctx, qp->qed_qp); 224762306a36Sopenharmony_ci if (rc) 224862306a36Sopenharmony_ci return rc; 224962306a36Sopenharmony_ci } 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci if (qp->create_type == QEDR_QP_CREATE_USER) 225262306a36Sopenharmony_ci qedr_cleanup_user(dev, ctx, qp); 225362306a36Sopenharmony_ci else 225462306a36Sopenharmony_ci qedr_cleanup_kernel(dev, qp); 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci return 0; 225762306a36Sopenharmony_ci} 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ciint qedr_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, 226062306a36Sopenharmony_ci struct ib_udata *udata) 226162306a36Sopenharmony_ci{ 226262306a36Sopenharmony_ci struct qedr_xrcd *xrcd = NULL; 226362306a36Sopenharmony_ci struct ib_pd *ibpd = ibqp->pd; 226462306a36Sopenharmony_ci struct qedr_pd *pd = get_qedr_pd(ibpd); 226562306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibqp->device); 226662306a36Sopenharmony_ci struct qedr_qp *qp = get_qedr_qp(ibqp); 226762306a36Sopenharmony_ci int rc = 0; 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci if (attrs->create_flags) 227062306a36Sopenharmony_ci return -EOPNOTSUPP; 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci if (attrs->qp_type == IB_QPT_XRC_TGT) 227362306a36Sopenharmony_ci xrcd = get_qedr_xrcd(attrs->xrcd); 227462306a36Sopenharmony_ci else 227562306a36Sopenharmony_ci pd = get_qedr_pd(ibpd); 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, "create qp: called from %s, pd=%p\n", 227862306a36Sopenharmony_ci udata ? "user library" : "kernel", pd); 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci rc = qedr_check_qp_attrs(ibpd, dev, attrs, udata); 228162306a36Sopenharmony_ci if (rc) 228262306a36Sopenharmony_ci return rc; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, 228562306a36Sopenharmony_ci "create qp: called from %s, event_handler=%p, eepd=%p sq_cq=%p, sq_icid=%d, rq_cq=%p, rq_icid=%d\n", 228662306a36Sopenharmony_ci udata ? "user library" : "kernel", attrs->event_handler, pd, 228762306a36Sopenharmony_ci get_qedr_cq(attrs->send_cq), 228862306a36Sopenharmony_ci get_qedr_cq(attrs->send_cq)->icid, 228962306a36Sopenharmony_ci get_qedr_cq(attrs->recv_cq), 229062306a36Sopenharmony_ci attrs->recv_cq ? get_qedr_cq(attrs->recv_cq)->icid : 0); 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci qedr_set_common_qp_params(dev, qp, pd, attrs); 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci if (attrs->qp_type == IB_QPT_GSI) 229562306a36Sopenharmony_ci return qedr_create_gsi_qp(dev, attrs, qp); 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci if (udata || xrcd) 229862306a36Sopenharmony_ci rc = qedr_create_user_qp(dev, qp, ibpd, udata, attrs); 229962306a36Sopenharmony_ci else 230062306a36Sopenharmony_ci rc = qedr_create_kernel_qp(dev, qp, ibpd, attrs); 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci if (rc) 230362306a36Sopenharmony_ci return rc; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci qp->ibqp.qp_num = qp->qp_id; 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) { 230862306a36Sopenharmony_ci rc = xa_insert(&dev->qps, qp->qp_id, qp, GFP_KERNEL); 230962306a36Sopenharmony_ci if (rc) 231062306a36Sopenharmony_ci goto out_free_qp_resources; 231162306a36Sopenharmony_ci } 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci return 0; 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ciout_free_qp_resources: 231662306a36Sopenharmony_ci qedr_free_qp_resources(dev, qp, udata); 231762306a36Sopenharmony_ci return -EFAULT; 231862306a36Sopenharmony_ci} 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_cistatic enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state) 232162306a36Sopenharmony_ci{ 232262306a36Sopenharmony_ci switch (qp_state) { 232362306a36Sopenharmony_ci case QED_ROCE_QP_STATE_RESET: 232462306a36Sopenharmony_ci return IB_QPS_RESET; 232562306a36Sopenharmony_ci case QED_ROCE_QP_STATE_INIT: 232662306a36Sopenharmony_ci return IB_QPS_INIT; 232762306a36Sopenharmony_ci case QED_ROCE_QP_STATE_RTR: 232862306a36Sopenharmony_ci return IB_QPS_RTR; 232962306a36Sopenharmony_ci case QED_ROCE_QP_STATE_RTS: 233062306a36Sopenharmony_ci return IB_QPS_RTS; 233162306a36Sopenharmony_ci case QED_ROCE_QP_STATE_SQD: 233262306a36Sopenharmony_ci return IB_QPS_SQD; 233362306a36Sopenharmony_ci case QED_ROCE_QP_STATE_ERR: 233462306a36Sopenharmony_ci return IB_QPS_ERR; 233562306a36Sopenharmony_ci case QED_ROCE_QP_STATE_SQE: 233662306a36Sopenharmony_ci return IB_QPS_SQE; 233762306a36Sopenharmony_ci } 233862306a36Sopenharmony_ci return IB_QPS_ERR; 233962306a36Sopenharmony_ci} 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_cistatic enum qed_roce_qp_state qedr_get_state_from_ibqp( 234262306a36Sopenharmony_ci enum ib_qp_state qp_state) 234362306a36Sopenharmony_ci{ 234462306a36Sopenharmony_ci switch (qp_state) { 234562306a36Sopenharmony_ci case IB_QPS_RESET: 234662306a36Sopenharmony_ci return QED_ROCE_QP_STATE_RESET; 234762306a36Sopenharmony_ci case IB_QPS_INIT: 234862306a36Sopenharmony_ci return QED_ROCE_QP_STATE_INIT; 234962306a36Sopenharmony_ci case IB_QPS_RTR: 235062306a36Sopenharmony_ci return QED_ROCE_QP_STATE_RTR; 235162306a36Sopenharmony_ci case IB_QPS_RTS: 235262306a36Sopenharmony_ci return QED_ROCE_QP_STATE_RTS; 235362306a36Sopenharmony_ci case IB_QPS_SQD: 235462306a36Sopenharmony_ci return QED_ROCE_QP_STATE_SQD; 235562306a36Sopenharmony_ci case IB_QPS_ERR: 235662306a36Sopenharmony_ci return QED_ROCE_QP_STATE_ERR; 235762306a36Sopenharmony_ci default: 235862306a36Sopenharmony_ci return QED_ROCE_QP_STATE_ERR; 235962306a36Sopenharmony_ci } 236062306a36Sopenharmony_ci} 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_cistatic int qedr_update_qp_state(struct qedr_dev *dev, 236362306a36Sopenharmony_ci struct qedr_qp *qp, 236462306a36Sopenharmony_ci enum qed_roce_qp_state cur_state, 236562306a36Sopenharmony_ci enum qed_roce_qp_state new_state) 236662306a36Sopenharmony_ci{ 236762306a36Sopenharmony_ci int status = 0; 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci if (new_state == cur_state) 237062306a36Sopenharmony_ci return 0; 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci switch (cur_state) { 237362306a36Sopenharmony_ci case QED_ROCE_QP_STATE_RESET: 237462306a36Sopenharmony_ci switch (new_state) { 237562306a36Sopenharmony_ci case QED_ROCE_QP_STATE_INIT: 237662306a36Sopenharmony_ci break; 237762306a36Sopenharmony_ci default: 237862306a36Sopenharmony_ci status = -EINVAL; 237962306a36Sopenharmony_ci break; 238062306a36Sopenharmony_ci } 238162306a36Sopenharmony_ci break; 238262306a36Sopenharmony_ci case QED_ROCE_QP_STATE_INIT: 238362306a36Sopenharmony_ci switch (new_state) { 238462306a36Sopenharmony_ci case QED_ROCE_QP_STATE_RTR: 238562306a36Sopenharmony_ci /* Update doorbell (in case post_recv was 238662306a36Sopenharmony_ci * done before move to RTR) 238762306a36Sopenharmony_ci */ 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci if (rdma_protocol_roce(&dev->ibdev, 1)) { 239062306a36Sopenharmony_ci writel(qp->rq.db_data.raw, qp->rq.db); 239162306a36Sopenharmony_ci } 239262306a36Sopenharmony_ci break; 239362306a36Sopenharmony_ci case QED_ROCE_QP_STATE_ERR: 239462306a36Sopenharmony_ci break; 239562306a36Sopenharmony_ci default: 239662306a36Sopenharmony_ci /* Invalid state change. */ 239762306a36Sopenharmony_ci status = -EINVAL; 239862306a36Sopenharmony_ci break; 239962306a36Sopenharmony_ci } 240062306a36Sopenharmony_ci break; 240162306a36Sopenharmony_ci case QED_ROCE_QP_STATE_RTR: 240262306a36Sopenharmony_ci /* RTR->XXX */ 240362306a36Sopenharmony_ci switch (new_state) { 240462306a36Sopenharmony_ci case QED_ROCE_QP_STATE_RTS: 240562306a36Sopenharmony_ci break; 240662306a36Sopenharmony_ci case QED_ROCE_QP_STATE_ERR: 240762306a36Sopenharmony_ci break; 240862306a36Sopenharmony_ci default: 240962306a36Sopenharmony_ci /* Invalid state change. */ 241062306a36Sopenharmony_ci status = -EINVAL; 241162306a36Sopenharmony_ci break; 241262306a36Sopenharmony_ci } 241362306a36Sopenharmony_ci break; 241462306a36Sopenharmony_ci case QED_ROCE_QP_STATE_RTS: 241562306a36Sopenharmony_ci /* RTS->XXX */ 241662306a36Sopenharmony_ci switch (new_state) { 241762306a36Sopenharmony_ci case QED_ROCE_QP_STATE_SQD: 241862306a36Sopenharmony_ci break; 241962306a36Sopenharmony_ci case QED_ROCE_QP_STATE_ERR: 242062306a36Sopenharmony_ci break; 242162306a36Sopenharmony_ci default: 242262306a36Sopenharmony_ci /* Invalid state change. */ 242362306a36Sopenharmony_ci status = -EINVAL; 242462306a36Sopenharmony_ci break; 242562306a36Sopenharmony_ci } 242662306a36Sopenharmony_ci break; 242762306a36Sopenharmony_ci case QED_ROCE_QP_STATE_SQD: 242862306a36Sopenharmony_ci /* SQD->XXX */ 242962306a36Sopenharmony_ci switch (new_state) { 243062306a36Sopenharmony_ci case QED_ROCE_QP_STATE_RTS: 243162306a36Sopenharmony_ci case QED_ROCE_QP_STATE_ERR: 243262306a36Sopenharmony_ci break; 243362306a36Sopenharmony_ci default: 243462306a36Sopenharmony_ci /* Invalid state change. */ 243562306a36Sopenharmony_ci status = -EINVAL; 243662306a36Sopenharmony_ci break; 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci break; 243962306a36Sopenharmony_ci case QED_ROCE_QP_STATE_ERR: 244062306a36Sopenharmony_ci /* ERR->XXX */ 244162306a36Sopenharmony_ci switch (new_state) { 244262306a36Sopenharmony_ci case QED_ROCE_QP_STATE_RESET: 244362306a36Sopenharmony_ci if ((qp->rq.prod != qp->rq.cons) || 244462306a36Sopenharmony_ci (qp->sq.prod != qp->sq.cons)) { 244562306a36Sopenharmony_ci DP_NOTICE(dev, 244662306a36Sopenharmony_ci "Error->Reset with rq/sq not empty rq.prod=%x rq.cons=%x sq.prod=%x sq.cons=%x\n", 244762306a36Sopenharmony_ci qp->rq.prod, qp->rq.cons, qp->sq.prod, 244862306a36Sopenharmony_ci qp->sq.cons); 244962306a36Sopenharmony_ci status = -EINVAL; 245062306a36Sopenharmony_ci } 245162306a36Sopenharmony_ci break; 245262306a36Sopenharmony_ci default: 245362306a36Sopenharmony_ci status = -EINVAL; 245462306a36Sopenharmony_ci break; 245562306a36Sopenharmony_ci } 245662306a36Sopenharmony_ci break; 245762306a36Sopenharmony_ci default: 245862306a36Sopenharmony_ci status = -EINVAL; 245962306a36Sopenharmony_ci break; 246062306a36Sopenharmony_ci } 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci return status; 246362306a36Sopenharmony_ci} 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ciint qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 246662306a36Sopenharmony_ci int attr_mask, struct ib_udata *udata) 246762306a36Sopenharmony_ci{ 246862306a36Sopenharmony_ci struct qedr_qp *qp = get_qedr_qp(ibqp); 246962306a36Sopenharmony_ci struct qed_rdma_modify_qp_in_params qp_params = { 0 }; 247062306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(&qp->dev->ibdev); 247162306a36Sopenharmony_ci const struct ib_global_route *grh = rdma_ah_read_grh(&attr->ah_attr); 247262306a36Sopenharmony_ci enum ib_qp_state old_qp_state, new_qp_state; 247362306a36Sopenharmony_ci enum qed_roce_qp_state cur_state; 247462306a36Sopenharmony_ci int rc = 0; 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, 247762306a36Sopenharmony_ci "modify qp: qp %p attr_mask=0x%x, state=%d", qp, attr_mask, 247862306a36Sopenharmony_ci attr->qp_state); 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS) 248162306a36Sopenharmony_ci return -EOPNOTSUPP; 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci old_qp_state = qedr_get_ibqp_state(qp->state); 248462306a36Sopenharmony_ci if (attr_mask & IB_QP_STATE) 248562306a36Sopenharmony_ci new_qp_state = attr->qp_state; 248662306a36Sopenharmony_ci else 248762306a36Sopenharmony_ci new_qp_state = old_qp_state; 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci if (rdma_protocol_roce(&dev->ibdev, 1)) { 249062306a36Sopenharmony_ci if (!ib_modify_qp_is_ok(old_qp_state, new_qp_state, 249162306a36Sopenharmony_ci ibqp->qp_type, attr_mask)) { 249262306a36Sopenharmony_ci DP_ERR(dev, 249362306a36Sopenharmony_ci "modify qp: invalid attribute mask=0x%x specified for\n" 249462306a36Sopenharmony_ci "qpn=0x%x of type=0x%x old_qp_state=0x%x, new_qp_state=0x%x\n", 249562306a36Sopenharmony_ci attr_mask, qp->qp_id, ibqp->qp_type, 249662306a36Sopenharmony_ci old_qp_state, new_qp_state); 249762306a36Sopenharmony_ci rc = -EINVAL; 249862306a36Sopenharmony_ci goto err; 249962306a36Sopenharmony_ci } 250062306a36Sopenharmony_ci } 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci /* Translate the masks... */ 250362306a36Sopenharmony_ci if (attr_mask & IB_QP_STATE) { 250462306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 250562306a36Sopenharmony_ci QED_RDMA_MODIFY_QP_VALID_NEW_STATE, 1); 250662306a36Sopenharmony_ci qp_params.new_state = qedr_get_state_from_ibqp(attr->qp_state); 250762306a36Sopenharmony_ci } 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci if (attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) 251062306a36Sopenharmony_ci qp_params.sqd_async = true; 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci if (attr_mask & IB_QP_PKEY_INDEX) { 251362306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 251462306a36Sopenharmony_ci QED_ROCE_MODIFY_QP_VALID_PKEY, 1); 251562306a36Sopenharmony_ci if (attr->pkey_index >= QEDR_ROCE_PKEY_TABLE_LEN) { 251662306a36Sopenharmony_ci rc = -EINVAL; 251762306a36Sopenharmony_ci goto err; 251862306a36Sopenharmony_ci } 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci qp_params.pkey = QEDR_ROCE_PKEY_DEFAULT; 252162306a36Sopenharmony_ci } 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci if (attr_mask & IB_QP_QKEY) 252462306a36Sopenharmony_ci qp->qkey = attr->qkey; 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci if (attr_mask & IB_QP_ACCESS_FLAGS) { 252762306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 252862306a36Sopenharmony_ci QED_RDMA_MODIFY_QP_VALID_RDMA_OPS_EN, 1); 252962306a36Sopenharmony_ci qp_params.incoming_rdma_read_en = attr->qp_access_flags & 253062306a36Sopenharmony_ci IB_ACCESS_REMOTE_READ; 253162306a36Sopenharmony_ci qp_params.incoming_rdma_write_en = attr->qp_access_flags & 253262306a36Sopenharmony_ci IB_ACCESS_REMOTE_WRITE; 253362306a36Sopenharmony_ci qp_params.incoming_atomic_en = attr->qp_access_flags & 253462306a36Sopenharmony_ci IB_ACCESS_REMOTE_ATOMIC; 253562306a36Sopenharmony_ci } 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci if (attr_mask & (IB_QP_AV | IB_QP_PATH_MTU)) { 253862306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) 253962306a36Sopenharmony_ci return -EINVAL; 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci if (attr_mask & IB_QP_PATH_MTU) { 254262306a36Sopenharmony_ci if (attr->path_mtu < IB_MTU_256 || 254362306a36Sopenharmony_ci attr->path_mtu > IB_MTU_4096) { 254462306a36Sopenharmony_ci pr_err("error: Only MTU sizes of 256, 512, 1024, 2048 and 4096 are supported by RoCE\n"); 254562306a36Sopenharmony_ci rc = -EINVAL; 254662306a36Sopenharmony_ci goto err; 254762306a36Sopenharmony_ci } 254862306a36Sopenharmony_ci qp->mtu = min(ib_mtu_enum_to_int(attr->path_mtu), 254962306a36Sopenharmony_ci ib_mtu_enum_to_int(iboe_get_mtu 255062306a36Sopenharmony_ci (dev->ndev->mtu))); 255162306a36Sopenharmony_ci } 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci if (!qp->mtu) { 255462306a36Sopenharmony_ci qp->mtu = 255562306a36Sopenharmony_ci ib_mtu_enum_to_int(iboe_get_mtu(dev->ndev->mtu)); 255662306a36Sopenharmony_ci pr_err("Fixing zeroed MTU to qp->mtu = %d\n", qp->mtu); 255762306a36Sopenharmony_ci } 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 256062306a36Sopenharmony_ci QED_ROCE_MODIFY_QP_VALID_ADDRESS_VECTOR, 1); 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci qp_params.traffic_class_tos = grh->traffic_class; 256362306a36Sopenharmony_ci qp_params.flow_label = grh->flow_label; 256462306a36Sopenharmony_ci qp_params.hop_limit_ttl = grh->hop_limit; 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci qp->sgid_idx = grh->sgid_index; 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci rc = get_gid_info_from_table(ibqp, attr, attr_mask, &qp_params); 256962306a36Sopenharmony_ci if (rc) { 257062306a36Sopenharmony_ci DP_ERR(dev, 257162306a36Sopenharmony_ci "modify qp: problems with GID index %d (rc=%d)\n", 257262306a36Sopenharmony_ci grh->sgid_index, rc); 257362306a36Sopenharmony_ci return rc; 257462306a36Sopenharmony_ci } 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci rc = qedr_get_dmac(dev, &attr->ah_attr, 257762306a36Sopenharmony_ci qp_params.remote_mac_addr); 257862306a36Sopenharmony_ci if (rc) 257962306a36Sopenharmony_ci return rc; 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci qp_params.use_local_mac = true; 258262306a36Sopenharmony_ci ether_addr_copy(qp_params.local_mac_addr, dev->ndev->dev_addr); 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, "dgid=%x:%x:%x:%x\n", 258562306a36Sopenharmony_ci qp_params.dgid.dwords[0], qp_params.dgid.dwords[1], 258662306a36Sopenharmony_ci qp_params.dgid.dwords[2], qp_params.dgid.dwords[3]); 258762306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, "sgid=%x:%x:%x:%x\n", 258862306a36Sopenharmony_ci qp_params.sgid.dwords[0], qp_params.sgid.dwords[1], 258962306a36Sopenharmony_ci qp_params.sgid.dwords[2], qp_params.sgid.dwords[3]); 259062306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, "remote_mac=[%pM]\n", 259162306a36Sopenharmony_ci qp_params.remote_mac_addr); 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci qp_params.mtu = qp->mtu; 259462306a36Sopenharmony_ci qp_params.lb_indication = false; 259562306a36Sopenharmony_ci } 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci if (!qp_params.mtu) { 259862306a36Sopenharmony_ci /* Stay with current MTU */ 259962306a36Sopenharmony_ci if (qp->mtu) 260062306a36Sopenharmony_ci qp_params.mtu = qp->mtu; 260162306a36Sopenharmony_ci else 260262306a36Sopenharmony_ci qp_params.mtu = 260362306a36Sopenharmony_ci ib_mtu_enum_to_int(iboe_get_mtu(dev->ndev->mtu)); 260462306a36Sopenharmony_ci } 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci if (attr_mask & IB_QP_TIMEOUT) { 260762306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 260862306a36Sopenharmony_ci QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT, 1); 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci /* The received timeout value is an exponent used like this: 261162306a36Sopenharmony_ci * "12.7.34 LOCAL ACK TIMEOUT 261262306a36Sopenharmony_ci * Value representing the transport (ACK) timeout for use by 261362306a36Sopenharmony_ci * the remote, expressed as: 4.096 * 2^timeout [usec]" 261462306a36Sopenharmony_ci * The FW expects timeout in msec so we need to divide the usec 261562306a36Sopenharmony_ci * result by 1000. We'll approximate 1000~2^10, and 4.096 ~ 2^2, 261662306a36Sopenharmony_ci * so we get: 2^2 * 2^timeout / 2^10 = 2^(timeout - 8). 261762306a36Sopenharmony_ci * The value of zero means infinite so we use a 'max_t' to make 261862306a36Sopenharmony_ci * sure that sub 1 msec values will be configured as 1 msec. 261962306a36Sopenharmony_ci */ 262062306a36Sopenharmony_ci if (attr->timeout) 262162306a36Sopenharmony_ci qp_params.ack_timeout = 262262306a36Sopenharmony_ci 1 << max_t(int, attr->timeout - 8, 0); 262362306a36Sopenharmony_ci else 262462306a36Sopenharmony_ci qp_params.ack_timeout = 0; 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci qp->timeout = attr->timeout; 262762306a36Sopenharmony_ci } 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci if (attr_mask & IB_QP_RETRY_CNT) { 263062306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 263162306a36Sopenharmony_ci QED_ROCE_MODIFY_QP_VALID_RETRY_CNT, 1); 263262306a36Sopenharmony_ci qp_params.retry_cnt = attr->retry_cnt; 263362306a36Sopenharmony_ci } 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_ci if (attr_mask & IB_QP_RNR_RETRY) { 263662306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 263762306a36Sopenharmony_ci QED_ROCE_MODIFY_QP_VALID_RNR_RETRY_CNT, 1); 263862306a36Sopenharmony_ci qp_params.rnr_retry_cnt = attr->rnr_retry; 263962306a36Sopenharmony_ci } 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci if (attr_mask & IB_QP_RQ_PSN) { 264262306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 264362306a36Sopenharmony_ci QED_ROCE_MODIFY_QP_VALID_RQ_PSN, 1); 264462306a36Sopenharmony_ci qp_params.rq_psn = attr->rq_psn; 264562306a36Sopenharmony_ci qp->rq_psn = attr->rq_psn; 264662306a36Sopenharmony_ci } 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { 264962306a36Sopenharmony_ci if (attr->max_rd_atomic > dev->attr.max_qp_req_rd_atomic_resc) { 265062306a36Sopenharmony_ci rc = -EINVAL; 265162306a36Sopenharmony_ci DP_ERR(dev, 265262306a36Sopenharmony_ci "unsupported max_rd_atomic=%d, supported=%d\n", 265362306a36Sopenharmony_ci attr->max_rd_atomic, 265462306a36Sopenharmony_ci dev->attr.max_qp_req_rd_atomic_resc); 265562306a36Sopenharmony_ci goto err; 265662306a36Sopenharmony_ci } 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 265962306a36Sopenharmony_ci QED_RDMA_MODIFY_QP_VALID_MAX_RD_ATOMIC_REQ, 1); 266062306a36Sopenharmony_ci qp_params.max_rd_atomic_req = attr->max_rd_atomic; 266162306a36Sopenharmony_ci } 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci if (attr_mask & IB_QP_MIN_RNR_TIMER) { 266462306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 266562306a36Sopenharmony_ci QED_ROCE_MODIFY_QP_VALID_MIN_RNR_NAK_TIMER, 1); 266662306a36Sopenharmony_ci qp_params.min_rnr_nak_timer = attr->min_rnr_timer; 266762306a36Sopenharmony_ci } 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci if (attr_mask & IB_QP_SQ_PSN) { 267062306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 267162306a36Sopenharmony_ci QED_ROCE_MODIFY_QP_VALID_SQ_PSN, 1); 267262306a36Sopenharmony_ci qp_params.sq_psn = attr->sq_psn; 267362306a36Sopenharmony_ci qp->sq_psn = attr->sq_psn; 267462306a36Sopenharmony_ci } 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { 267762306a36Sopenharmony_ci if (attr->max_dest_rd_atomic > 267862306a36Sopenharmony_ci dev->attr.max_qp_resp_rd_atomic_resc) { 267962306a36Sopenharmony_ci DP_ERR(dev, 268062306a36Sopenharmony_ci "unsupported max_dest_rd_atomic=%d, supported=%d\n", 268162306a36Sopenharmony_ci attr->max_dest_rd_atomic, 268262306a36Sopenharmony_ci dev->attr.max_qp_resp_rd_atomic_resc); 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci rc = -EINVAL; 268562306a36Sopenharmony_ci goto err; 268662306a36Sopenharmony_ci } 268762306a36Sopenharmony_ci 268862306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 268962306a36Sopenharmony_ci QED_RDMA_MODIFY_QP_VALID_MAX_RD_ATOMIC_RESP, 1); 269062306a36Sopenharmony_ci qp_params.max_rd_atomic_resp = attr->max_dest_rd_atomic; 269162306a36Sopenharmony_ci } 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci if (attr_mask & IB_QP_DEST_QPN) { 269462306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 269562306a36Sopenharmony_ci QED_ROCE_MODIFY_QP_VALID_DEST_QP, 1); 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci qp_params.dest_qp = attr->dest_qp_num; 269862306a36Sopenharmony_ci qp->dest_qp_num = attr->dest_qp_num; 269962306a36Sopenharmony_ci } 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci cur_state = qp->state; 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ci /* Update the QP state before the actual ramrod to prevent a race with 270462306a36Sopenharmony_ci * fast path. Modifying the QP state to error will cause the device to 270562306a36Sopenharmony_ci * flush the CQEs and while polling the flushed CQEs will considered as 270662306a36Sopenharmony_ci * a potential issue if the QP isn't in error state. 270762306a36Sopenharmony_ci */ 270862306a36Sopenharmony_ci if ((attr_mask & IB_QP_STATE) && qp->qp_type != IB_QPT_GSI && 270962306a36Sopenharmony_ci !udata && qp_params.new_state == QED_ROCE_QP_STATE_ERR) 271062306a36Sopenharmony_ci qp->state = QED_ROCE_QP_STATE_ERR; 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci if (qp->qp_type != IB_QPT_GSI) 271362306a36Sopenharmony_ci rc = dev->ops->rdma_modify_qp(dev->rdma_ctx, 271462306a36Sopenharmony_ci qp->qed_qp, &qp_params); 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci if (attr_mask & IB_QP_STATE) { 271762306a36Sopenharmony_ci if ((qp->qp_type != IB_QPT_GSI) && (!udata)) 271862306a36Sopenharmony_ci rc = qedr_update_qp_state(dev, qp, cur_state, 271962306a36Sopenharmony_ci qp_params.new_state); 272062306a36Sopenharmony_ci qp->state = qp_params.new_state; 272162306a36Sopenharmony_ci } 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_cierr: 272462306a36Sopenharmony_ci return rc; 272562306a36Sopenharmony_ci} 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_cistatic int qedr_to_ib_qp_acc_flags(struct qed_rdma_query_qp_out_params *params) 272862306a36Sopenharmony_ci{ 272962306a36Sopenharmony_ci int ib_qp_acc_flags = 0; 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci if (params->incoming_rdma_write_en) 273262306a36Sopenharmony_ci ib_qp_acc_flags |= IB_ACCESS_REMOTE_WRITE; 273362306a36Sopenharmony_ci if (params->incoming_rdma_read_en) 273462306a36Sopenharmony_ci ib_qp_acc_flags |= IB_ACCESS_REMOTE_READ; 273562306a36Sopenharmony_ci if (params->incoming_atomic_en) 273662306a36Sopenharmony_ci ib_qp_acc_flags |= IB_ACCESS_REMOTE_ATOMIC; 273762306a36Sopenharmony_ci ib_qp_acc_flags |= IB_ACCESS_LOCAL_WRITE; 273862306a36Sopenharmony_ci return ib_qp_acc_flags; 273962306a36Sopenharmony_ci} 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ciint qedr_query_qp(struct ib_qp *ibqp, 274262306a36Sopenharmony_ci struct ib_qp_attr *qp_attr, 274362306a36Sopenharmony_ci int attr_mask, struct ib_qp_init_attr *qp_init_attr) 274462306a36Sopenharmony_ci{ 274562306a36Sopenharmony_ci struct qed_rdma_query_qp_out_params params; 274662306a36Sopenharmony_ci struct qedr_qp *qp = get_qedr_qp(ibqp); 274762306a36Sopenharmony_ci struct qedr_dev *dev = qp->dev; 274862306a36Sopenharmony_ci int rc = 0; 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 275162306a36Sopenharmony_ci memset(qp_attr, 0, sizeof(*qp_attr)); 275262306a36Sopenharmony_ci memset(qp_init_attr, 0, sizeof(*qp_init_attr)); 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci if (qp->qp_type != IB_QPT_GSI) { 275562306a36Sopenharmony_ci rc = dev->ops->rdma_query_qp(dev->rdma_ctx, qp->qed_qp, ¶ms); 275662306a36Sopenharmony_ci if (rc) 275762306a36Sopenharmony_ci goto err; 275862306a36Sopenharmony_ci qp_attr->qp_state = qedr_get_ibqp_state(params.state); 275962306a36Sopenharmony_ci } else { 276062306a36Sopenharmony_ci qp_attr->qp_state = qedr_get_ibqp_state(QED_ROCE_QP_STATE_RTS); 276162306a36Sopenharmony_ci } 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci qp_attr->cur_qp_state = qedr_get_ibqp_state(params.state); 276462306a36Sopenharmony_ci qp_attr->path_mtu = ib_mtu_int_to_enum(params.mtu); 276562306a36Sopenharmony_ci qp_attr->path_mig_state = IB_MIG_MIGRATED; 276662306a36Sopenharmony_ci qp_attr->rq_psn = params.rq_psn; 276762306a36Sopenharmony_ci qp_attr->sq_psn = params.sq_psn; 276862306a36Sopenharmony_ci qp_attr->dest_qp_num = params.dest_qp; 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci qp_attr->qp_access_flags = qedr_to_ib_qp_acc_flags(¶ms); 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci qp_attr->cap.max_send_wr = qp->sq.max_wr; 277362306a36Sopenharmony_ci qp_attr->cap.max_recv_wr = qp->rq.max_wr; 277462306a36Sopenharmony_ci qp_attr->cap.max_send_sge = qp->sq.max_sges; 277562306a36Sopenharmony_ci qp_attr->cap.max_recv_sge = qp->rq.max_sges; 277662306a36Sopenharmony_ci qp_attr->cap.max_inline_data = dev->attr.max_inline; 277762306a36Sopenharmony_ci qp_init_attr->cap = qp_attr->cap; 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci qp_attr->ah_attr.type = RDMA_AH_ATTR_TYPE_ROCE; 278062306a36Sopenharmony_ci rdma_ah_set_grh(&qp_attr->ah_attr, NULL, 278162306a36Sopenharmony_ci params.flow_label, qp->sgid_idx, 278262306a36Sopenharmony_ci params.hop_limit_ttl, params.traffic_class_tos); 278362306a36Sopenharmony_ci rdma_ah_set_dgid_raw(&qp_attr->ah_attr, ¶ms.dgid.bytes[0]); 278462306a36Sopenharmony_ci rdma_ah_set_port_num(&qp_attr->ah_attr, 1); 278562306a36Sopenharmony_ci rdma_ah_set_sl(&qp_attr->ah_attr, 0); 278662306a36Sopenharmony_ci qp_attr->timeout = qp->timeout; 278762306a36Sopenharmony_ci qp_attr->rnr_retry = params.rnr_retry; 278862306a36Sopenharmony_ci qp_attr->retry_cnt = params.retry_cnt; 278962306a36Sopenharmony_ci qp_attr->min_rnr_timer = params.min_rnr_nak_timer; 279062306a36Sopenharmony_ci qp_attr->pkey_index = params.pkey_index; 279162306a36Sopenharmony_ci qp_attr->port_num = 1; 279262306a36Sopenharmony_ci rdma_ah_set_path_bits(&qp_attr->ah_attr, 0); 279362306a36Sopenharmony_ci rdma_ah_set_static_rate(&qp_attr->ah_attr, 0); 279462306a36Sopenharmony_ci qp_attr->alt_pkey_index = 0; 279562306a36Sopenharmony_ci qp_attr->alt_port_num = 0; 279662306a36Sopenharmony_ci qp_attr->alt_timeout = 0; 279762306a36Sopenharmony_ci memset(&qp_attr->alt_ah_attr, 0, sizeof(qp_attr->alt_ah_attr)); 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci qp_attr->sq_draining = (params.state == QED_ROCE_QP_STATE_SQD) ? 1 : 0; 280062306a36Sopenharmony_ci qp_attr->max_dest_rd_atomic = params.max_dest_rd_atomic; 280162306a36Sopenharmony_ci qp_attr->max_rd_atomic = params.max_rd_atomic; 280262306a36Sopenharmony_ci qp_attr->en_sqd_async_notify = (params.sqd_async) ? 1 : 0; 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, "QEDR_QUERY_QP: max_inline_data=%d\n", 280562306a36Sopenharmony_ci qp_attr->cap.max_inline_data); 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_cierr: 280862306a36Sopenharmony_ci return rc; 280962306a36Sopenharmony_ci} 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_ciint qedr_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) 281262306a36Sopenharmony_ci{ 281362306a36Sopenharmony_ci struct qedr_qp *qp = get_qedr_qp(ibqp); 281462306a36Sopenharmony_ci struct qedr_dev *dev = qp->dev; 281562306a36Sopenharmony_ci struct ib_qp_attr attr; 281662306a36Sopenharmony_ci int attr_mask = 0; 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, "destroy qp: destroying %p, qp type=%d\n", 281962306a36Sopenharmony_ci qp, qp->qp_type); 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci if (rdma_protocol_roce(&dev->ibdev, 1)) { 282262306a36Sopenharmony_ci if ((qp->state != QED_ROCE_QP_STATE_RESET) && 282362306a36Sopenharmony_ci (qp->state != QED_ROCE_QP_STATE_ERR) && 282462306a36Sopenharmony_ci (qp->state != QED_ROCE_QP_STATE_INIT)) { 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci attr.qp_state = IB_QPS_ERR; 282762306a36Sopenharmony_ci attr_mask |= IB_QP_STATE; 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci /* Change the QP state to ERROR */ 283062306a36Sopenharmony_ci qedr_modify_qp(ibqp, &attr, attr_mask, NULL); 283162306a36Sopenharmony_ci } 283262306a36Sopenharmony_ci } else { 283362306a36Sopenharmony_ci /* If connection establishment started the WAIT_FOR_CONNECT 283462306a36Sopenharmony_ci * bit will be on and we need to Wait for the establishment 283562306a36Sopenharmony_ci * to complete before destroying the qp. 283662306a36Sopenharmony_ci */ 283762306a36Sopenharmony_ci if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT, 283862306a36Sopenharmony_ci &qp->iwarp_cm_flags)) 283962306a36Sopenharmony_ci wait_for_completion(&qp->iwarp_cm_comp); 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci /* If graceful disconnect started, the WAIT_FOR_DISCONNECT 284262306a36Sopenharmony_ci * bit will be on, and we need to wait for the disconnect to 284362306a36Sopenharmony_ci * complete before continuing. We can use the same completion, 284462306a36Sopenharmony_ci * iwarp_cm_comp, since this is the only place that waits for 284562306a36Sopenharmony_ci * this completion and it is sequential. In addition, 284662306a36Sopenharmony_ci * disconnect can't occur before the connection is fully 284762306a36Sopenharmony_ci * established, therefore if WAIT_FOR_DISCONNECT is on it 284862306a36Sopenharmony_ci * means WAIT_FOR_CONNECT is also on and the completion for 284962306a36Sopenharmony_ci * CONNECT already occurred. 285062306a36Sopenharmony_ci */ 285162306a36Sopenharmony_ci if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_DISCONNECT, 285262306a36Sopenharmony_ci &qp->iwarp_cm_flags)) 285362306a36Sopenharmony_ci wait_for_completion(&qp->iwarp_cm_comp); 285462306a36Sopenharmony_ci } 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_GSI) 285762306a36Sopenharmony_ci qedr_destroy_gsi_qp(dev); 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci /* We need to remove the entry from the xarray before we release the 286062306a36Sopenharmony_ci * qp_id to avoid a race of the qp_id being reallocated and failing 286162306a36Sopenharmony_ci * on xa_insert 286262306a36Sopenharmony_ci */ 286362306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) 286462306a36Sopenharmony_ci xa_erase(&dev->qps, qp->qp_id); 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci qedr_free_qp_resources(dev, qp, udata); 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) { 286962306a36Sopenharmony_ci qedr_iw_qp_rem_ref(&qp->ibqp); 287062306a36Sopenharmony_ci wait_for_completion(&qp->qp_rel_comp); 287162306a36Sopenharmony_ci } 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ci return 0; 287462306a36Sopenharmony_ci} 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ciint qedr_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, 287762306a36Sopenharmony_ci struct ib_udata *udata) 287862306a36Sopenharmony_ci{ 287962306a36Sopenharmony_ci struct qedr_ah *ah = get_qedr_ah(ibah); 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci rdma_copy_ah_attr(&ah->attr, init_attr->ah_attr); 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci return 0; 288462306a36Sopenharmony_ci} 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ciint qedr_destroy_ah(struct ib_ah *ibah, u32 flags) 288762306a36Sopenharmony_ci{ 288862306a36Sopenharmony_ci struct qedr_ah *ah = get_qedr_ah(ibah); 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci rdma_destroy_ah_attr(&ah->attr); 289162306a36Sopenharmony_ci return 0; 289262306a36Sopenharmony_ci} 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_cistatic void free_mr_info(struct qedr_dev *dev, struct mr_info *info) 289562306a36Sopenharmony_ci{ 289662306a36Sopenharmony_ci struct qedr_pbl *pbl, *tmp; 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci if (info->pbl_table) 289962306a36Sopenharmony_ci list_add_tail(&info->pbl_table->list_entry, 290062306a36Sopenharmony_ci &info->free_pbl_list); 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_ci if (!list_empty(&info->inuse_pbl_list)) 290362306a36Sopenharmony_ci list_splice(&info->inuse_pbl_list, &info->free_pbl_list); 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci list_for_each_entry_safe(pbl, tmp, &info->free_pbl_list, list_entry) { 290662306a36Sopenharmony_ci list_del(&pbl->list_entry); 290762306a36Sopenharmony_ci qedr_free_pbl(dev, &info->pbl_info, pbl); 290862306a36Sopenharmony_ci } 290962306a36Sopenharmony_ci} 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_cistatic int init_mr_info(struct qedr_dev *dev, struct mr_info *info, 291262306a36Sopenharmony_ci size_t page_list_len, bool two_layered) 291362306a36Sopenharmony_ci{ 291462306a36Sopenharmony_ci struct qedr_pbl *tmp; 291562306a36Sopenharmony_ci int rc; 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_ci INIT_LIST_HEAD(&info->free_pbl_list); 291862306a36Sopenharmony_ci INIT_LIST_HEAD(&info->inuse_pbl_list); 291962306a36Sopenharmony_ci 292062306a36Sopenharmony_ci rc = qedr_prepare_pbl_tbl(dev, &info->pbl_info, 292162306a36Sopenharmony_ci page_list_len, two_layered); 292262306a36Sopenharmony_ci if (rc) 292362306a36Sopenharmony_ci goto done; 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_ci info->pbl_table = qedr_alloc_pbl_tbl(dev, &info->pbl_info, GFP_KERNEL); 292662306a36Sopenharmony_ci if (IS_ERR(info->pbl_table)) { 292762306a36Sopenharmony_ci rc = PTR_ERR(info->pbl_table); 292862306a36Sopenharmony_ci goto done; 292962306a36Sopenharmony_ci } 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_MR, "pbl_table_pa = %pa\n", 293262306a36Sopenharmony_ci &info->pbl_table->pa); 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci /* in usual case we use 2 PBLs, so we add one to free 293562306a36Sopenharmony_ci * list and allocating another one 293662306a36Sopenharmony_ci */ 293762306a36Sopenharmony_ci tmp = qedr_alloc_pbl_tbl(dev, &info->pbl_info, GFP_KERNEL); 293862306a36Sopenharmony_ci if (IS_ERR(tmp)) { 293962306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_MR, "Extra PBL is not allocated\n"); 294062306a36Sopenharmony_ci goto done; 294162306a36Sopenharmony_ci } 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci list_add_tail(&tmp->list_entry, &info->free_pbl_list); 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_MR, "extra pbl_table_pa = %pa\n", &tmp->pa); 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_cidone: 294862306a36Sopenharmony_ci if (rc) 294962306a36Sopenharmony_ci free_mr_info(dev, info); 295062306a36Sopenharmony_ci 295162306a36Sopenharmony_ci return rc; 295262306a36Sopenharmony_ci} 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_cistruct ib_mr *qedr_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 len, 295562306a36Sopenharmony_ci u64 usr_addr, int acc, struct ib_udata *udata) 295662306a36Sopenharmony_ci{ 295762306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibpd->device); 295862306a36Sopenharmony_ci struct qedr_mr *mr; 295962306a36Sopenharmony_ci struct qedr_pd *pd; 296062306a36Sopenharmony_ci int rc = -ENOMEM; 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci pd = get_qedr_pd(ibpd); 296362306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_MR, 296462306a36Sopenharmony_ci "qedr_register user mr pd = %d start = %lld, len = %lld, usr_addr = %lld, acc = %d\n", 296562306a36Sopenharmony_ci pd->pd_id, start, len, usr_addr, acc); 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci if (acc & IB_ACCESS_REMOTE_WRITE && !(acc & IB_ACCESS_LOCAL_WRITE)) 296862306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci mr = kzalloc(sizeof(*mr), GFP_KERNEL); 297162306a36Sopenharmony_ci if (!mr) 297262306a36Sopenharmony_ci return ERR_PTR(rc); 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci mr->type = QEDR_MR_USER; 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_ci mr->umem = ib_umem_get(ibpd->device, start, len, acc); 297762306a36Sopenharmony_ci if (IS_ERR(mr->umem)) { 297862306a36Sopenharmony_ci rc = -EFAULT; 297962306a36Sopenharmony_ci goto err0; 298062306a36Sopenharmony_ci } 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci rc = init_mr_info(dev, &mr->info, 298362306a36Sopenharmony_ci ib_umem_num_dma_blocks(mr->umem, PAGE_SIZE), 1); 298462306a36Sopenharmony_ci if (rc) 298562306a36Sopenharmony_ci goto err1; 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci qedr_populate_pbls(dev, mr->umem, mr->info.pbl_table, 298862306a36Sopenharmony_ci &mr->info.pbl_info, PAGE_SHIFT); 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci rc = dev->ops->rdma_alloc_tid(dev->rdma_ctx, &mr->hw_mr.itid); 299162306a36Sopenharmony_ci if (rc) { 299262306a36Sopenharmony_ci if (rc == -EINVAL) 299362306a36Sopenharmony_ci DP_ERR(dev, "Out of MR resources\n"); 299462306a36Sopenharmony_ci else 299562306a36Sopenharmony_ci DP_ERR(dev, "roce alloc tid returned error %d\n", rc); 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci goto err1; 299862306a36Sopenharmony_ci } 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_ci /* Index only, 18 bit long, lkey = itid << 8 | key */ 300162306a36Sopenharmony_ci mr->hw_mr.tid_type = QED_RDMA_TID_REGISTERED_MR; 300262306a36Sopenharmony_ci mr->hw_mr.key = 0; 300362306a36Sopenharmony_ci mr->hw_mr.pd = pd->pd_id; 300462306a36Sopenharmony_ci mr->hw_mr.local_read = 1; 300562306a36Sopenharmony_ci mr->hw_mr.local_write = (acc & IB_ACCESS_LOCAL_WRITE) ? 1 : 0; 300662306a36Sopenharmony_ci mr->hw_mr.remote_read = (acc & IB_ACCESS_REMOTE_READ) ? 1 : 0; 300762306a36Sopenharmony_ci mr->hw_mr.remote_write = (acc & IB_ACCESS_REMOTE_WRITE) ? 1 : 0; 300862306a36Sopenharmony_ci mr->hw_mr.remote_atomic = (acc & IB_ACCESS_REMOTE_ATOMIC) ? 1 : 0; 300962306a36Sopenharmony_ci mr->hw_mr.mw_bind = false; 301062306a36Sopenharmony_ci mr->hw_mr.pbl_ptr = mr->info.pbl_table[0].pa; 301162306a36Sopenharmony_ci mr->hw_mr.pbl_two_level = mr->info.pbl_info.two_layered; 301262306a36Sopenharmony_ci mr->hw_mr.pbl_page_size_log = ilog2(mr->info.pbl_info.pbl_size); 301362306a36Sopenharmony_ci mr->hw_mr.page_size_log = PAGE_SHIFT; 301462306a36Sopenharmony_ci mr->hw_mr.length = len; 301562306a36Sopenharmony_ci mr->hw_mr.vaddr = usr_addr; 301662306a36Sopenharmony_ci mr->hw_mr.phy_mr = false; 301762306a36Sopenharmony_ci mr->hw_mr.dma_mr = false; 301862306a36Sopenharmony_ci 301962306a36Sopenharmony_ci rc = dev->ops->rdma_register_tid(dev->rdma_ctx, &mr->hw_mr); 302062306a36Sopenharmony_ci if (rc) { 302162306a36Sopenharmony_ci DP_ERR(dev, "roce register tid returned an error %d\n", rc); 302262306a36Sopenharmony_ci goto err2; 302362306a36Sopenharmony_ci } 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_ci mr->ibmr.lkey = mr->hw_mr.itid << 8 | mr->hw_mr.key; 302662306a36Sopenharmony_ci if (mr->hw_mr.remote_write || mr->hw_mr.remote_read || 302762306a36Sopenharmony_ci mr->hw_mr.remote_atomic) 302862306a36Sopenharmony_ci mr->ibmr.rkey = mr->hw_mr.itid << 8 | mr->hw_mr.key; 302962306a36Sopenharmony_ci 303062306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_MR, "register user mr lkey: %x\n", 303162306a36Sopenharmony_ci mr->ibmr.lkey); 303262306a36Sopenharmony_ci return &mr->ibmr; 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_cierr2: 303562306a36Sopenharmony_ci dev->ops->rdma_free_tid(dev->rdma_ctx, mr->hw_mr.itid); 303662306a36Sopenharmony_cierr1: 303762306a36Sopenharmony_ci qedr_free_pbl(dev, &mr->info.pbl_info, mr->info.pbl_table); 303862306a36Sopenharmony_cierr0: 303962306a36Sopenharmony_ci kfree(mr); 304062306a36Sopenharmony_ci return ERR_PTR(rc); 304162306a36Sopenharmony_ci} 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_ciint qedr_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata) 304462306a36Sopenharmony_ci{ 304562306a36Sopenharmony_ci struct qedr_mr *mr = get_qedr_mr(ib_mr); 304662306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ib_mr->device); 304762306a36Sopenharmony_ci int rc = 0; 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_ci rc = dev->ops->rdma_deregister_tid(dev->rdma_ctx, mr->hw_mr.itid); 305062306a36Sopenharmony_ci if (rc) 305162306a36Sopenharmony_ci return rc; 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci dev->ops->rdma_free_tid(dev->rdma_ctx, mr->hw_mr.itid); 305462306a36Sopenharmony_ci 305562306a36Sopenharmony_ci if (mr->type != QEDR_MR_DMA) 305662306a36Sopenharmony_ci free_mr_info(dev, &mr->info); 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci /* it could be user registered memory. */ 305962306a36Sopenharmony_ci ib_umem_release(mr->umem); 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci kfree(mr); 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci return rc; 306462306a36Sopenharmony_ci} 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_cistatic struct qedr_mr *__qedr_alloc_mr(struct ib_pd *ibpd, 306762306a36Sopenharmony_ci int max_page_list_len) 306862306a36Sopenharmony_ci{ 306962306a36Sopenharmony_ci struct qedr_pd *pd = get_qedr_pd(ibpd); 307062306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibpd->device); 307162306a36Sopenharmony_ci struct qedr_mr *mr; 307262306a36Sopenharmony_ci int rc = -ENOMEM; 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_MR, 307562306a36Sopenharmony_ci "qedr_alloc_frmr pd = %d max_page_list_len= %d\n", pd->pd_id, 307662306a36Sopenharmony_ci max_page_list_len); 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ci mr = kzalloc(sizeof(*mr), GFP_KERNEL); 307962306a36Sopenharmony_ci if (!mr) 308062306a36Sopenharmony_ci return ERR_PTR(rc); 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci mr->dev = dev; 308362306a36Sopenharmony_ci mr->type = QEDR_MR_FRMR; 308462306a36Sopenharmony_ci 308562306a36Sopenharmony_ci rc = init_mr_info(dev, &mr->info, max_page_list_len, 1); 308662306a36Sopenharmony_ci if (rc) 308762306a36Sopenharmony_ci goto err0; 308862306a36Sopenharmony_ci 308962306a36Sopenharmony_ci rc = dev->ops->rdma_alloc_tid(dev->rdma_ctx, &mr->hw_mr.itid); 309062306a36Sopenharmony_ci if (rc) { 309162306a36Sopenharmony_ci if (rc == -EINVAL) 309262306a36Sopenharmony_ci DP_ERR(dev, "Out of MR resources\n"); 309362306a36Sopenharmony_ci else 309462306a36Sopenharmony_ci DP_ERR(dev, "roce alloc tid returned error %d\n", rc); 309562306a36Sopenharmony_ci 309662306a36Sopenharmony_ci goto err1; 309762306a36Sopenharmony_ci } 309862306a36Sopenharmony_ci 309962306a36Sopenharmony_ci /* Index only, 18 bit long, lkey = itid << 8 | key */ 310062306a36Sopenharmony_ci mr->hw_mr.tid_type = QED_RDMA_TID_FMR; 310162306a36Sopenharmony_ci mr->hw_mr.key = 0; 310262306a36Sopenharmony_ci mr->hw_mr.pd = pd->pd_id; 310362306a36Sopenharmony_ci mr->hw_mr.local_read = 1; 310462306a36Sopenharmony_ci mr->hw_mr.local_write = 0; 310562306a36Sopenharmony_ci mr->hw_mr.remote_read = 0; 310662306a36Sopenharmony_ci mr->hw_mr.remote_write = 0; 310762306a36Sopenharmony_ci mr->hw_mr.remote_atomic = 0; 310862306a36Sopenharmony_ci mr->hw_mr.mw_bind = false; 310962306a36Sopenharmony_ci mr->hw_mr.pbl_ptr = 0; 311062306a36Sopenharmony_ci mr->hw_mr.pbl_two_level = mr->info.pbl_info.two_layered; 311162306a36Sopenharmony_ci mr->hw_mr.pbl_page_size_log = ilog2(mr->info.pbl_info.pbl_size); 311262306a36Sopenharmony_ci mr->hw_mr.length = 0; 311362306a36Sopenharmony_ci mr->hw_mr.vaddr = 0; 311462306a36Sopenharmony_ci mr->hw_mr.phy_mr = true; 311562306a36Sopenharmony_ci mr->hw_mr.dma_mr = false; 311662306a36Sopenharmony_ci 311762306a36Sopenharmony_ci rc = dev->ops->rdma_register_tid(dev->rdma_ctx, &mr->hw_mr); 311862306a36Sopenharmony_ci if (rc) { 311962306a36Sopenharmony_ci DP_ERR(dev, "roce register tid returned an error %d\n", rc); 312062306a36Sopenharmony_ci goto err2; 312162306a36Sopenharmony_ci } 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci mr->ibmr.lkey = mr->hw_mr.itid << 8 | mr->hw_mr.key; 312462306a36Sopenharmony_ci mr->ibmr.rkey = mr->ibmr.lkey; 312562306a36Sopenharmony_ci 312662306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_MR, "alloc frmr: %x\n", mr->ibmr.lkey); 312762306a36Sopenharmony_ci return mr; 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_cierr2: 313062306a36Sopenharmony_ci dev->ops->rdma_free_tid(dev->rdma_ctx, mr->hw_mr.itid); 313162306a36Sopenharmony_cierr1: 313262306a36Sopenharmony_ci qedr_free_pbl(dev, &mr->info.pbl_info, mr->info.pbl_table); 313362306a36Sopenharmony_cierr0: 313462306a36Sopenharmony_ci kfree(mr); 313562306a36Sopenharmony_ci return ERR_PTR(rc); 313662306a36Sopenharmony_ci} 313762306a36Sopenharmony_ci 313862306a36Sopenharmony_cistruct ib_mr *qedr_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type, 313962306a36Sopenharmony_ci u32 max_num_sg) 314062306a36Sopenharmony_ci{ 314162306a36Sopenharmony_ci struct qedr_mr *mr; 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_ci if (mr_type != IB_MR_TYPE_MEM_REG) 314462306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ci mr = __qedr_alloc_mr(ibpd, max_num_sg); 314762306a36Sopenharmony_ci 314862306a36Sopenharmony_ci if (IS_ERR(mr)) 314962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 315062306a36Sopenharmony_ci 315162306a36Sopenharmony_ci return &mr->ibmr; 315262306a36Sopenharmony_ci} 315362306a36Sopenharmony_ci 315462306a36Sopenharmony_cistatic int qedr_set_page(struct ib_mr *ibmr, u64 addr) 315562306a36Sopenharmony_ci{ 315662306a36Sopenharmony_ci struct qedr_mr *mr = get_qedr_mr(ibmr); 315762306a36Sopenharmony_ci struct qedr_pbl *pbl_table; 315862306a36Sopenharmony_ci struct regpair *pbe; 315962306a36Sopenharmony_ci u32 pbes_in_page; 316062306a36Sopenharmony_ci 316162306a36Sopenharmony_ci if (unlikely(mr->npages == mr->info.pbl_info.num_pbes)) { 316262306a36Sopenharmony_ci DP_ERR(mr->dev, "qedr_set_page fails when %d\n", mr->npages); 316362306a36Sopenharmony_ci return -ENOMEM; 316462306a36Sopenharmony_ci } 316562306a36Sopenharmony_ci 316662306a36Sopenharmony_ci DP_DEBUG(mr->dev, QEDR_MSG_MR, "qedr_set_page pages[%d] = 0x%llx\n", 316762306a36Sopenharmony_ci mr->npages, addr); 316862306a36Sopenharmony_ci 316962306a36Sopenharmony_ci pbes_in_page = mr->info.pbl_info.pbl_size / sizeof(u64); 317062306a36Sopenharmony_ci pbl_table = mr->info.pbl_table + (mr->npages / pbes_in_page); 317162306a36Sopenharmony_ci pbe = (struct regpair *)pbl_table->va; 317262306a36Sopenharmony_ci pbe += mr->npages % pbes_in_page; 317362306a36Sopenharmony_ci pbe->lo = cpu_to_le32((u32)addr); 317462306a36Sopenharmony_ci pbe->hi = cpu_to_le32((u32)upper_32_bits(addr)); 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci mr->npages++; 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci return 0; 317962306a36Sopenharmony_ci} 318062306a36Sopenharmony_ci 318162306a36Sopenharmony_cistatic void handle_completed_mrs(struct qedr_dev *dev, struct mr_info *info) 318262306a36Sopenharmony_ci{ 318362306a36Sopenharmony_ci int work = info->completed - info->completed_handled - 1; 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_MR, "Special FMR work = %d\n", work); 318662306a36Sopenharmony_ci while (work-- > 0 && !list_empty(&info->inuse_pbl_list)) { 318762306a36Sopenharmony_ci struct qedr_pbl *pbl; 318862306a36Sopenharmony_ci 318962306a36Sopenharmony_ci /* Free all the page list that are possible to be freed 319062306a36Sopenharmony_ci * (all the ones that were invalidated), under the assumption 319162306a36Sopenharmony_ci * that if an FMR was completed successfully that means that 319262306a36Sopenharmony_ci * if there was an invalidate operation before it also ended 319362306a36Sopenharmony_ci */ 319462306a36Sopenharmony_ci pbl = list_first_entry(&info->inuse_pbl_list, 319562306a36Sopenharmony_ci struct qedr_pbl, list_entry); 319662306a36Sopenharmony_ci list_move_tail(&pbl->list_entry, &info->free_pbl_list); 319762306a36Sopenharmony_ci info->completed_handled++; 319862306a36Sopenharmony_ci } 319962306a36Sopenharmony_ci} 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ciint qedr_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, 320262306a36Sopenharmony_ci int sg_nents, unsigned int *sg_offset) 320362306a36Sopenharmony_ci{ 320462306a36Sopenharmony_ci struct qedr_mr *mr = get_qedr_mr(ibmr); 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci mr->npages = 0; 320762306a36Sopenharmony_ci 320862306a36Sopenharmony_ci handle_completed_mrs(mr->dev, &mr->info); 320962306a36Sopenharmony_ci return ib_sg_to_pages(ibmr, sg, sg_nents, NULL, qedr_set_page); 321062306a36Sopenharmony_ci} 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_cistruct ib_mr *qedr_get_dma_mr(struct ib_pd *ibpd, int acc) 321362306a36Sopenharmony_ci{ 321462306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibpd->device); 321562306a36Sopenharmony_ci struct qedr_pd *pd = get_qedr_pd(ibpd); 321662306a36Sopenharmony_ci struct qedr_mr *mr; 321762306a36Sopenharmony_ci int rc; 321862306a36Sopenharmony_ci 321962306a36Sopenharmony_ci mr = kzalloc(sizeof(*mr), GFP_KERNEL); 322062306a36Sopenharmony_ci if (!mr) 322162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci mr->type = QEDR_MR_DMA; 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_ci rc = dev->ops->rdma_alloc_tid(dev->rdma_ctx, &mr->hw_mr.itid); 322662306a36Sopenharmony_ci if (rc) { 322762306a36Sopenharmony_ci if (rc == -EINVAL) 322862306a36Sopenharmony_ci DP_ERR(dev, "Out of MR resources\n"); 322962306a36Sopenharmony_ci else 323062306a36Sopenharmony_ci DP_ERR(dev, "roce alloc tid returned error %d\n", rc); 323162306a36Sopenharmony_ci 323262306a36Sopenharmony_ci goto err1; 323362306a36Sopenharmony_ci } 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci /* index only, 18 bit long, lkey = itid << 8 | key */ 323662306a36Sopenharmony_ci mr->hw_mr.tid_type = QED_RDMA_TID_REGISTERED_MR; 323762306a36Sopenharmony_ci mr->hw_mr.pd = pd->pd_id; 323862306a36Sopenharmony_ci mr->hw_mr.local_read = 1; 323962306a36Sopenharmony_ci mr->hw_mr.local_write = (acc & IB_ACCESS_LOCAL_WRITE) ? 1 : 0; 324062306a36Sopenharmony_ci mr->hw_mr.remote_read = (acc & IB_ACCESS_REMOTE_READ) ? 1 : 0; 324162306a36Sopenharmony_ci mr->hw_mr.remote_write = (acc & IB_ACCESS_REMOTE_WRITE) ? 1 : 0; 324262306a36Sopenharmony_ci mr->hw_mr.remote_atomic = (acc & IB_ACCESS_REMOTE_ATOMIC) ? 1 : 0; 324362306a36Sopenharmony_ci mr->hw_mr.dma_mr = true; 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_ci rc = dev->ops->rdma_register_tid(dev->rdma_ctx, &mr->hw_mr); 324662306a36Sopenharmony_ci if (rc) { 324762306a36Sopenharmony_ci DP_ERR(dev, "roce register tid returned an error %d\n", rc); 324862306a36Sopenharmony_ci goto err2; 324962306a36Sopenharmony_ci } 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci mr->ibmr.lkey = mr->hw_mr.itid << 8 | mr->hw_mr.key; 325262306a36Sopenharmony_ci if (mr->hw_mr.remote_write || mr->hw_mr.remote_read || 325362306a36Sopenharmony_ci mr->hw_mr.remote_atomic) 325462306a36Sopenharmony_ci mr->ibmr.rkey = mr->hw_mr.itid << 8 | mr->hw_mr.key; 325562306a36Sopenharmony_ci 325662306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_MR, "get dma mr: lkey = %x\n", mr->ibmr.lkey); 325762306a36Sopenharmony_ci return &mr->ibmr; 325862306a36Sopenharmony_ci 325962306a36Sopenharmony_cierr2: 326062306a36Sopenharmony_ci dev->ops->rdma_free_tid(dev->rdma_ctx, mr->hw_mr.itid); 326162306a36Sopenharmony_cierr1: 326262306a36Sopenharmony_ci kfree(mr); 326362306a36Sopenharmony_ci return ERR_PTR(rc); 326462306a36Sopenharmony_ci} 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_cistatic inline int qedr_wq_is_full(struct qedr_qp_hwq_info *wq) 326762306a36Sopenharmony_ci{ 326862306a36Sopenharmony_ci return (((wq->prod + 1) % wq->max_wr) == wq->cons); 326962306a36Sopenharmony_ci} 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_cistatic int sge_data_len(struct ib_sge *sg_list, int num_sge) 327262306a36Sopenharmony_ci{ 327362306a36Sopenharmony_ci int i, len = 0; 327462306a36Sopenharmony_ci 327562306a36Sopenharmony_ci for (i = 0; i < num_sge; i++) 327662306a36Sopenharmony_ci len += sg_list[i].length; 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci return len; 327962306a36Sopenharmony_ci} 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_cistatic void swap_wqe_data64(u64 *p) 328262306a36Sopenharmony_ci{ 328362306a36Sopenharmony_ci int i; 328462306a36Sopenharmony_ci 328562306a36Sopenharmony_ci for (i = 0; i < QEDR_SQE_ELEMENT_SIZE / sizeof(u64); i++, p++) 328662306a36Sopenharmony_ci *p = cpu_to_be64(cpu_to_le64(*p)); 328762306a36Sopenharmony_ci} 328862306a36Sopenharmony_ci 328962306a36Sopenharmony_cistatic u32 qedr_prepare_sq_inline_data(struct qedr_dev *dev, 329062306a36Sopenharmony_ci struct qedr_qp *qp, u8 *wqe_size, 329162306a36Sopenharmony_ci const struct ib_send_wr *wr, 329262306a36Sopenharmony_ci const struct ib_send_wr **bad_wr, 329362306a36Sopenharmony_ci u8 *bits, u8 bit) 329462306a36Sopenharmony_ci{ 329562306a36Sopenharmony_ci u32 data_size = sge_data_len(wr->sg_list, wr->num_sge); 329662306a36Sopenharmony_ci char *seg_prt, *wqe; 329762306a36Sopenharmony_ci int i, seg_siz; 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_ci if (data_size > ROCE_REQ_MAX_INLINE_DATA_SIZE) { 330062306a36Sopenharmony_ci DP_ERR(dev, "Too much inline data in WR: %d\n", data_size); 330162306a36Sopenharmony_ci *bad_wr = wr; 330262306a36Sopenharmony_ci return 0; 330362306a36Sopenharmony_ci } 330462306a36Sopenharmony_ci 330562306a36Sopenharmony_ci if (!data_size) 330662306a36Sopenharmony_ci return data_size; 330762306a36Sopenharmony_ci 330862306a36Sopenharmony_ci *bits |= bit; 330962306a36Sopenharmony_ci 331062306a36Sopenharmony_ci seg_prt = NULL; 331162306a36Sopenharmony_ci wqe = NULL; 331262306a36Sopenharmony_ci seg_siz = 0; 331362306a36Sopenharmony_ci 331462306a36Sopenharmony_ci /* Copy data inline */ 331562306a36Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 331662306a36Sopenharmony_ci u32 len = wr->sg_list[i].length; 331762306a36Sopenharmony_ci void *src = (void *)(uintptr_t)wr->sg_list[i].addr; 331862306a36Sopenharmony_ci 331962306a36Sopenharmony_ci while (len > 0) { 332062306a36Sopenharmony_ci u32 cur; 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ci /* New segment required */ 332362306a36Sopenharmony_ci if (!seg_siz) { 332462306a36Sopenharmony_ci wqe = (char *)qed_chain_produce(&qp->sq.pbl); 332562306a36Sopenharmony_ci seg_prt = wqe; 332662306a36Sopenharmony_ci seg_siz = sizeof(struct rdma_sq_common_wqe); 332762306a36Sopenharmony_ci (*wqe_size)++; 332862306a36Sopenharmony_ci } 332962306a36Sopenharmony_ci 333062306a36Sopenharmony_ci /* Calculate currently allowed length */ 333162306a36Sopenharmony_ci cur = min_t(u32, len, seg_siz); 333262306a36Sopenharmony_ci memcpy(seg_prt, src, cur); 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci /* Update segment variables */ 333562306a36Sopenharmony_ci seg_prt += cur; 333662306a36Sopenharmony_ci seg_siz -= cur; 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci /* Update sge variables */ 333962306a36Sopenharmony_ci src += cur; 334062306a36Sopenharmony_ci len -= cur; 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci /* Swap fully-completed segments */ 334362306a36Sopenharmony_ci if (!seg_siz) 334462306a36Sopenharmony_ci swap_wqe_data64((u64 *)wqe); 334562306a36Sopenharmony_ci } 334662306a36Sopenharmony_ci } 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci /* swap last not completed segment */ 334962306a36Sopenharmony_ci if (seg_siz) 335062306a36Sopenharmony_ci swap_wqe_data64((u64 *)wqe); 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci return data_size; 335362306a36Sopenharmony_ci} 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci#define RQ_SGE_SET(sge, vaddr, vlength, vflags) \ 335662306a36Sopenharmony_ci do { \ 335762306a36Sopenharmony_ci DMA_REGPAIR_LE(sge->addr, vaddr); \ 335862306a36Sopenharmony_ci (sge)->length = cpu_to_le32(vlength); \ 335962306a36Sopenharmony_ci (sge)->flags = cpu_to_le32(vflags); \ 336062306a36Sopenharmony_ci } while (0) 336162306a36Sopenharmony_ci 336262306a36Sopenharmony_ci#define SRQ_HDR_SET(hdr, vwr_id, num_sge) \ 336362306a36Sopenharmony_ci do { \ 336462306a36Sopenharmony_ci DMA_REGPAIR_LE(hdr->wr_id, vwr_id); \ 336562306a36Sopenharmony_ci (hdr)->num_sges = num_sge; \ 336662306a36Sopenharmony_ci } while (0) 336762306a36Sopenharmony_ci 336862306a36Sopenharmony_ci#define SRQ_SGE_SET(sge, vaddr, vlength, vlkey) \ 336962306a36Sopenharmony_ci do { \ 337062306a36Sopenharmony_ci DMA_REGPAIR_LE(sge->addr, vaddr); \ 337162306a36Sopenharmony_ci (sge)->length = cpu_to_le32(vlength); \ 337262306a36Sopenharmony_ci (sge)->l_key = cpu_to_le32(vlkey); \ 337362306a36Sopenharmony_ci } while (0) 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_cistatic u32 qedr_prepare_sq_sges(struct qedr_qp *qp, u8 *wqe_size, 337662306a36Sopenharmony_ci const struct ib_send_wr *wr) 337762306a36Sopenharmony_ci{ 337862306a36Sopenharmony_ci u32 data_size = 0; 337962306a36Sopenharmony_ci int i; 338062306a36Sopenharmony_ci 338162306a36Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 338262306a36Sopenharmony_ci struct rdma_sq_sge *sge = qed_chain_produce(&qp->sq.pbl); 338362306a36Sopenharmony_ci 338462306a36Sopenharmony_ci DMA_REGPAIR_LE(sge->addr, wr->sg_list[i].addr); 338562306a36Sopenharmony_ci sge->l_key = cpu_to_le32(wr->sg_list[i].lkey); 338662306a36Sopenharmony_ci sge->length = cpu_to_le32(wr->sg_list[i].length); 338762306a36Sopenharmony_ci data_size += wr->sg_list[i].length; 338862306a36Sopenharmony_ci } 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_ci if (wqe_size) 339162306a36Sopenharmony_ci *wqe_size += wr->num_sge; 339262306a36Sopenharmony_ci 339362306a36Sopenharmony_ci return data_size; 339462306a36Sopenharmony_ci} 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_cistatic u32 qedr_prepare_sq_rdma_data(struct qedr_dev *dev, 339762306a36Sopenharmony_ci struct qedr_qp *qp, 339862306a36Sopenharmony_ci struct rdma_sq_rdma_wqe_1st *rwqe, 339962306a36Sopenharmony_ci struct rdma_sq_rdma_wqe_2nd *rwqe2, 340062306a36Sopenharmony_ci const struct ib_send_wr *wr, 340162306a36Sopenharmony_ci const struct ib_send_wr **bad_wr) 340262306a36Sopenharmony_ci{ 340362306a36Sopenharmony_ci rwqe2->r_key = cpu_to_le32(rdma_wr(wr)->rkey); 340462306a36Sopenharmony_ci DMA_REGPAIR_LE(rwqe2->remote_va, rdma_wr(wr)->remote_addr); 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_INLINE && 340762306a36Sopenharmony_ci (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM || 340862306a36Sopenharmony_ci wr->opcode == IB_WR_RDMA_WRITE)) { 340962306a36Sopenharmony_ci u8 flags = 0; 341062306a36Sopenharmony_ci 341162306a36Sopenharmony_ci SET_FIELD2(flags, RDMA_SQ_RDMA_WQE_1ST_INLINE_FLG, 1); 341262306a36Sopenharmony_ci return qedr_prepare_sq_inline_data(dev, qp, &rwqe->wqe_size, wr, 341362306a36Sopenharmony_ci bad_wr, &rwqe->flags, flags); 341462306a36Sopenharmony_ci } 341562306a36Sopenharmony_ci 341662306a36Sopenharmony_ci return qedr_prepare_sq_sges(qp, &rwqe->wqe_size, wr); 341762306a36Sopenharmony_ci} 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_cistatic u32 qedr_prepare_sq_send_data(struct qedr_dev *dev, 342062306a36Sopenharmony_ci struct qedr_qp *qp, 342162306a36Sopenharmony_ci struct rdma_sq_send_wqe_1st *swqe, 342262306a36Sopenharmony_ci struct rdma_sq_send_wqe_2st *swqe2, 342362306a36Sopenharmony_ci const struct ib_send_wr *wr, 342462306a36Sopenharmony_ci const struct ib_send_wr **bad_wr) 342562306a36Sopenharmony_ci{ 342662306a36Sopenharmony_ci memset(swqe2, 0, sizeof(*swqe2)); 342762306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_INLINE) { 342862306a36Sopenharmony_ci u8 flags = 0; 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_ci SET_FIELD2(flags, RDMA_SQ_SEND_WQE_INLINE_FLG, 1); 343162306a36Sopenharmony_ci return qedr_prepare_sq_inline_data(dev, qp, &swqe->wqe_size, wr, 343262306a36Sopenharmony_ci bad_wr, &swqe->flags, flags); 343362306a36Sopenharmony_ci } 343462306a36Sopenharmony_ci 343562306a36Sopenharmony_ci return qedr_prepare_sq_sges(qp, &swqe->wqe_size, wr); 343662306a36Sopenharmony_ci} 343762306a36Sopenharmony_ci 343862306a36Sopenharmony_cistatic int qedr_prepare_reg(struct qedr_qp *qp, 343962306a36Sopenharmony_ci struct rdma_sq_fmr_wqe_1st *fwqe1, 344062306a36Sopenharmony_ci const struct ib_reg_wr *wr) 344162306a36Sopenharmony_ci{ 344262306a36Sopenharmony_ci struct qedr_mr *mr = get_qedr_mr(wr->mr); 344362306a36Sopenharmony_ci struct rdma_sq_fmr_wqe_2nd *fwqe2; 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci fwqe2 = (struct rdma_sq_fmr_wqe_2nd *)qed_chain_produce(&qp->sq.pbl); 344662306a36Sopenharmony_ci fwqe1->addr.hi = upper_32_bits(mr->ibmr.iova); 344762306a36Sopenharmony_ci fwqe1->addr.lo = lower_32_bits(mr->ibmr.iova); 344862306a36Sopenharmony_ci fwqe1->l_key = wr->key; 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ci fwqe2->access_ctrl = 0; 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci SET_FIELD2(fwqe2->access_ctrl, RDMA_SQ_FMR_WQE_2ND_REMOTE_READ, 345362306a36Sopenharmony_ci !!(wr->access & IB_ACCESS_REMOTE_READ)); 345462306a36Sopenharmony_ci SET_FIELD2(fwqe2->access_ctrl, RDMA_SQ_FMR_WQE_2ND_REMOTE_WRITE, 345562306a36Sopenharmony_ci !!(wr->access & IB_ACCESS_REMOTE_WRITE)); 345662306a36Sopenharmony_ci SET_FIELD2(fwqe2->access_ctrl, RDMA_SQ_FMR_WQE_2ND_ENABLE_ATOMIC, 345762306a36Sopenharmony_ci !!(wr->access & IB_ACCESS_REMOTE_ATOMIC)); 345862306a36Sopenharmony_ci SET_FIELD2(fwqe2->access_ctrl, RDMA_SQ_FMR_WQE_2ND_LOCAL_READ, 1); 345962306a36Sopenharmony_ci SET_FIELD2(fwqe2->access_ctrl, RDMA_SQ_FMR_WQE_2ND_LOCAL_WRITE, 346062306a36Sopenharmony_ci !!(wr->access & IB_ACCESS_LOCAL_WRITE)); 346162306a36Sopenharmony_ci fwqe2->fmr_ctrl = 0; 346262306a36Sopenharmony_ci 346362306a36Sopenharmony_ci SET_FIELD2(fwqe2->fmr_ctrl, RDMA_SQ_FMR_WQE_2ND_PAGE_SIZE_LOG, 346462306a36Sopenharmony_ci ilog2(mr->ibmr.page_size) - 12); 346562306a36Sopenharmony_ci 346662306a36Sopenharmony_ci fwqe2->length_hi = 0; 346762306a36Sopenharmony_ci fwqe2->length_lo = mr->ibmr.length; 346862306a36Sopenharmony_ci fwqe2->pbl_addr.hi = upper_32_bits(mr->info.pbl_table->pa); 346962306a36Sopenharmony_ci fwqe2->pbl_addr.lo = lower_32_bits(mr->info.pbl_table->pa); 347062306a36Sopenharmony_ci 347162306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].mr = mr; 347262306a36Sopenharmony_ci 347362306a36Sopenharmony_ci return 0; 347462306a36Sopenharmony_ci} 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_cistatic enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode) 347762306a36Sopenharmony_ci{ 347862306a36Sopenharmony_ci switch (opcode) { 347962306a36Sopenharmony_ci case IB_WR_RDMA_WRITE: 348062306a36Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 348162306a36Sopenharmony_ci return IB_WC_RDMA_WRITE; 348262306a36Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 348362306a36Sopenharmony_ci case IB_WR_SEND: 348462306a36Sopenharmony_ci case IB_WR_SEND_WITH_INV: 348562306a36Sopenharmony_ci return IB_WC_SEND; 348662306a36Sopenharmony_ci case IB_WR_RDMA_READ: 348762306a36Sopenharmony_ci case IB_WR_RDMA_READ_WITH_INV: 348862306a36Sopenharmony_ci return IB_WC_RDMA_READ; 348962306a36Sopenharmony_ci case IB_WR_ATOMIC_CMP_AND_SWP: 349062306a36Sopenharmony_ci return IB_WC_COMP_SWAP; 349162306a36Sopenharmony_ci case IB_WR_ATOMIC_FETCH_AND_ADD: 349262306a36Sopenharmony_ci return IB_WC_FETCH_ADD; 349362306a36Sopenharmony_ci case IB_WR_REG_MR: 349462306a36Sopenharmony_ci return IB_WC_REG_MR; 349562306a36Sopenharmony_ci case IB_WR_LOCAL_INV: 349662306a36Sopenharmony_ci return IB_WC_LOCAL_INV; 349762306a36Sopenharmony_ci default: 349862306a36Sopenharmony_ci return IB_WC_SEND; 349962306a36Sopenharmony_ci } 350062306a36Sopenharmony_ci} 350162306a36Sopenharmony_ci 350262306a36Sopenharmony_cistatic inline bool qedr_can_post_send(struct qedr_qp *qp, 350362306a36Sopenharmony_ci const struct ib_send_wr *wr) 350462306a36Sopenharmony_ci{ 350562306a36Sopenharmony_ci int wq_is_full, err_wr, pbl_is_full; 350662306a36Sopenharmony_ci struct qedr_dev *dev = qp->dev; 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_ci /* prevent SQ overflow and/or processing of a bad WR */ 350962306a36Sopenharmony_ci err_wr = wr->num_sge > qp->sq.max_sges; 351062306a36Sopenharmony_ci wq_is_full = qedr_wq_is_full(&qp->sq); 351162306a36Sopenharmony_ci pbl_is_full = qed_chain_get_elem_left_u32(&qp->sq.pbl) < 351262306a36Sopenharmony_ci QEDR_MAX_SQE_ELEMENTS_PER_SQE; 351362306a36Sopenharmony_ci if (wq_is_full || err_wr || pbl_is_full) { 351462306a36Sopenharmony_ci if (wq_is_full && !(qp->err_bitmap & QEDR_QP_ERR_SQ_FULL)) { 351562306a36Sopenharmony_ci DP_ERR(dev, 351662306a36Sopenharmony_ci "error: WQ is full. Post send on QP %p failed (this error appears only once)\n", 351762306a36Sopenharmony_ci qp); 351862306a36Sopenharmony_ci qp->err_bitmap |= QEDR_QP_ERR_SQ_FULL; 351962306a36Sopenharmony_ci } 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci if (err_wr && !(qp->err_bitmap & QEDR_QP_ERR_BAD_SR)) { 352262306a36Sopenharmony_ci DP_ERR(dev, 352362306a36Sopenharmony_ci "error: WR is bad. Post send on QP %p failed (this error appears only once)\n", 352462306a36Sopenharmony_ci qp); 352562306a36Sopenharmony_ci qp->err_bitmap |= QEDR_QP_ERR_BAD_SR; 352662306a36Sopenharmony_ci } 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci if (pbl_is_full && 352962306a36Sopenharmony_ci !(qp->err_bitmap & QEDR_QP_ERR_SQ_PBL_FULL)) { 353062306a36Sopenharmony_ci DP_ERR(dev, 353162306a36Sopenharmony_ci "error: WQ PBL is full. Post send on QP %p failed (this error appears only once)\n", 353262306a36Sopenharmony_ci qp); 353362306a36Sopenharmony_ci qp->err_bitmap |= QEDR_QP_ERR_SQ_PBL_FULL; 353462306a36Sopenharmony_ci } 353562306a36Sopenharmony_ci return false; 353662306a36Sopenharmony_ci } 353762306a36Sopenharmony_ci return true; 353862306a36Sopenharmony_ci} 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_cistatic int __qedr_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, 354162306a36Sopenharmony_ci const struct ib_send_wr **bad_wr) 354262306a36Sopenharmony_ci{ 354362306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibqp->device); 354462306a36Sopenharmony_ci struct qedr_qp *qp = get_qedr_qp(ibqp); 354562306a36Sopenharmony_ci struct rdma_sq_atomic_wqe_1st *awqe1; 354662306a36Sopenharmony_ci struct rdma_sq_atomic_wqe_2nd *awqe2; 354762306a36Sopenharmony_ci struct rdma_sq_atomic_wqe_3rd *awqe3; 354862306a36Sopenharmony_ci struct rdma_sq_send_wqe_2st *swqe2; 354962306a36Sopenharmony_ci struct rdma_sq_local_inv_wqe *iwqe; 355062306a36Sopenharmony_ci struct rdma_sq_rdma_wqe_2nd *rwqe2; 355162306a36Sopenharmony_ci struct rdma_sq_send_wqe_1st *swqe; 355262306a36Sopenharmony_ci struct rdma_sq_rdma_wqe_1st *rwqe; 355362306a36Sopenharmony_ci struct rdma_sq_fmr_wqe_1st *fwqe1; 355462306a36Sopenharmony_ci struct rdma_sq_common_wqe *wqe; 355562306a36Sopenharmony_ci u32 length; 355662306a36Sopenharmony_ci int rc = 0; 355762306a36Sopenharmony_ci bool comp; 355862306a36Sopenharmony_ci 355962306a36Sopenharmony_ci if (!qedr_can_post_send(qp, wr)) { 356062306a36Sopenharmony_ci *bad_wr = wr; 356162306a36Sopenharmony_ci return -ENOMEM; 356262306a36Sopenharmony_ci } 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_ci wqe = qed_chain_produce(&qp->sq.pbl); 356562306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].signaled = 356662306a36Sopenharmony_ci !!(wr->send_flags & IB_SEND_SIGNALED) || qp->signaled; 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci wqe->flags = 0; 356962306a36Sopenharmony_ci SET_FIELD2(wqe->flags, RDMA_SQ_SEND_WQE_SE_FLG, 357062306a36Sopenharmony_ci !!(wr->send_flags & IB_SEND_SOLICITED)); 357162306a36Sopenharmony_ci comp = (!!(wr->send_flags & IB_SEND_SIGNALED)) || qp->signaled; 357262306a36Sopenharmony_ci SET_FIELD2(wqe->flags, RDMA_SQ_SEND_WQE_COMP_FLG, comp); 357362306a36Sopenharmony_ci SET_FIELD2(wqe->flags, RDMA_SQ_SEND_WQE_RD_FENCE_FLG, 357462306a36Sopenharmony_ci !!(wr->send_flags & IB_SEND_FENCE)); 357562306a36Sopenharmony_ci wqe->prev_wqe_size = qp->prev_wqe_size; 357662306a36Sopenharmony_ci 357762306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].opcode = qedr_ib_to_wc_opcode(wr->opcode); 357862306a36Sopenharmony_ci 357962306a36Sopenharmony_ci switch (wr->opcode) { 358062306a36Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 358162306a36Sopenharmony_ci if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { 358262306a36Sopenharmony_ci rc = -EINVAL; 358362306a36Sopenharmony_ci *bad_wr = wr; 358462306a36Sopenharmony_ci break; 358562306a36Sopenharmony_ci } 358662306a36Sopenharmony_ci wqe->req_type = RDMA_SQ_REQ_TYPE_SEND_WITH_IMM; 358762306a36Sopenharmony_ci swqe = (struct rdma_sq_send_wqe_1st *)wqe; 358862306a36Sopenharmony_ci swqe->wqe_size = 2; 358962306a36Sopenharmony_ci swqe2 = qed_chain_produce(&qp->sq.pbl); 359062306a36Sopenharmony_ci 359162306a36Sopenharmony_ci swqe->inv_key_or_imm_data = cpu_to_le32(be32_to_cpu(wr->ex.imm_data)); 359262306a36Sopenharmony_ci length = qedr_prepare_sq_send_data(dev, qp, swqe, swqe2, 359362306a36Sopenharmony_ci wr, bad_wr); 359462306a36Sopenharmony_ci swqe->length = cpu_to_le32(length); 359562306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].wqe_size = swqe->wqe_size; 359662306a36Sopenharmony_ci qp->prev_wqe_size = swqe->wqe_size; 359762306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].bytes_len = swqe->length; 359862306a36Sopenharmony_ci break; 359962306a36Sopenharmony_ci case IB_WR_SEND: 360062306a36Sopenharmony_ci wqe->req_type = RDMA_SQ_REQ_TYPE_SEND; 360162306a36Sopenharmony_ci swqe = (struct rdma_sq_send_wqe_1st *)wqe; 360262306a36Sopenharmony_ci 360362306a36Sopenharmony_ci swqe->wqe_size = 2; 360462306a36Sopenharmony_ci swqe2 = qed_chain_produce(&qp->sq.pbl); 360562306a36Sopenharmony_ci length = qedr_prepare_sq_send_data(dev, qp, swqe, swqe2, 360662306a36Sopenharmony_ci wr, bad_wr); 360762306a36Sopenharmony_ci swqe->length = cpu_to_le32(length); 360862306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].wqe_size = swqe->wqe_size; 360962306a36Sopenharmony_ci qp->prev_wqe_size = swqe->wqe_size; 361062306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].bytes_len = swqe->length; 361162306a36Sopenharmony_ci break; 361262306a36Sopenharmony_ci case IB_WR_SEND_WITH_INV: 361362306a36Sopenharmony_ci wqe->req_type = RDMA_SQ_REQ_TYPE_SEND_WITH_INVALIDATE; 361462306a36Sopenharmony_ci swqe = (struct rdma_sq_send_wqe_1st *)wqe; 361562306a36Sopenharmony_ci swqe2 = qed_chain_produce(&qp->sq.pbl); 361662306a36Sopenharmony_ci swqe->wqe_size = 2; 361762306a36Sopenharmony_ci swqe->inv_key_or_imm_data = cpu_to_le32(wr->ex.invalidate_rkey); 361862306a36Sopenharmony_ci length = qedr_prepare_sq_send_data(dev, qp, swqe, swqe2, 361962306a36Sopenharmony_ci wr, bad_wr); 362062306a36Sopenharmony_ci swqe->length = cpu_to_le32(length); 362162306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].wqe_size = swqe->wqe_size; 362262306a36Sopenharmony_ci qp->prev_wqe_size = swqe->wqe_size; 362362306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].bytes_len = swqe->length; 362462306a36Sopenharmony_ci break; 362562306a36Sopenharmony_ci 362662306a36Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 362762306a36Sopenharmony_ci if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) { 362862306a36Sopenharmony_ci rc = -EINVAL; 362962306a36Sopenharmony_ci *bad_wr = wr; 363062306a36Sopenharmony_ci break; 363162306a36Sopenharmony_ci } 363262306a36Sopenharmony_ci wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_WR_WITH_IMM; 363362306a36Sopenharmony_ci rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe; 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_ci rwqe->wqe_size = 2; 363662306a36Sopenharmony_ci rwqe->imm_data = htonl(cpu_to_le32(wr->ex.imm_data)); 363762306a36Sopenharmony_ci rwqe2 = qed_chain_produce(&qp->sq.pbl); 363862306a36Sopenharmony_ci length = qedr_prepare_sq_rdma_data(dev, qp, rwqe, rwqe2, 363962306a36Sopenharmony_ci wr, bad_wr); 364062306a36Sopenharmony_ci rwqe->length = cpu_to_le32(length); 364162306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].wqe_size = rwqe->wqe_size; 364262306a36Sopenharmony_ci qp->prev_wqe_size = rwqe->wqe_size; 364362306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].bytes_len = rwqe->length; 364462306a36Sopenharmony_ci break; 364562306a36Sopenharmony_ci case IB_WR_RDMA_WRITE: 364662306a36Sopenharmony_ci wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_WR; 364762306a36Sopenharmony_ci rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe; 364862306a36Sopenharmony_ci 364962306a36Sopenharmony_ci rwqe->wqe_size = 2; 365062306a36Sopenharmony_ci rwqe2 = qed_chain_produce(&qp->sq.pbl); 365162306a36Sopenharmony_ci length = qedr_prepare_sq_rdma_data(dev, qp, rwqe, rwqe2, 365262306a36Sopenharmony_ci wr, bad_wr); 365362306a36Sopenharmony_ci rwqe->length = cpu_to_le32(length); 365462306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].wqe_size = rwqe->wqe_size; 365562306a36Sopenharmony_ci qp->prev_wqe_size = rwqe->wqe_size; 365662306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].bytes_len = rwqe->length; 365762306a36Sopenharmony_ci break; 365862306a36Sopenharmony_ci case IB_WR_RDMA_READ_WITH_INV: 365962306a36Sopenharmony_ci SET_FIELD2(wqe->flags, RDMA_SQ_RDMA_WQE_1ST_READ_INV_FLG, 1); 366062306a36Sopenharmony_ci fallthrough; /* same is identical to RDMA READ */ 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci case IB_WR_RDMA_READ: 366362306a36Sopenharmony_ci wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_RD; 366462306a36Sopenharmony_ci rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe; 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci rwqe->wqe_size = 2; 366762306a36Sopenharmony_ci rwqe2 = qed_chain_produce(&qp->sq.pbl); 366862306a36Sopenharmony_ci length = qedr_prepare_sq_rdma_data(dev, qp, rwqe, rwqe2, 366962306a36Sopenharmony_ci wr, bad_wr); 367062306a36Sopenharmony_ci rwqe->length = cpu_to_le32(length); 367162306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].wqe_size = rwqe->wqe_size; 367262306a36Sopenharmony_ci qp->prev_wqe_size = rwqe->wqe_size; 367362306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].bytes_len = rwqe->length; 367462306a36Sopenharmony_ci break; 367562306a36Sopenharmony_ci 367662306a36Sopenharmony_ci case IB_WR_ATOMIC_CMP_AND_SWP: 367762306a36Sopenharmony_ci case IB_WR_ATOMIC_FETCH_AND_ADD: 367862306a36Sopenharmony_ci awqe1 = (struct rdma_sq_atomic_wqe_1st *)wqe; 367962306a36Sopenharmony_ci awqe1->wqe_size = 4; 368062306a36Sopenharmony_ci 368162306a36Sopenharmony_ci awqe2 = qed_chain_produce(&qp->sq.pbl); 368262306a36Sopenharmony_ci DMA_REGPAIR_LE(awqe2->remote_va, atomic_wr(wr)->remote_addr); 368362306a36Sopenharmony_ci awqe2->r_key = cpu_to_le32(atomic_wr(wr)->rkey); 368462306a36Sopenharmony_ci 368562306a36Sopenharmony_ci awqe3 = qed_chain_produce(&qp->sq.pbl); 368662306a36Sopenharmony_ci 368762306a36Sopenharmony_ci if (wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) { 368862306a36Sopenharmony_ci wqe->req_type = RDMA_SQ_REQ_TYPE_ATOMIC_ADD; 368962306a36Sopenharmony_ci DMA_REGPAIR_LE(awqe3->swap_data, 369062306a36Sopenharmony_ci atomic_wr(wr)->compare_add); 369162306a36Sopenharmony_ci } else { 369262306a36Sopenharmony_ci wqe->req_type = RDMA_SQ_REQ_TYPE_ATOMIC_CMP_AND_SWAP; 369362306a36Sopenharmony_ci DMA_REGPAIR_LE(awqe3->swap_data, 369462306a36Sopenharmony_ci atomic_wr(wr)->swap); 369562306a36Sopenharmony_ci DMA_REGPAIR_LE(awqe3->cmp_data, 369662306a36Sopenharmony_ci atomic_wr(wr)->compare_add); 369762306a36Sopenharmony_ci } 369862306a36Sopenharmony_ci 369962306a36Sopenharmony_ci qedr_prepare_sq_sges(qp, NULL, wr); 370062306a36Sopenharmony_ci 370162306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].wqe_size = awqe1->wqe_size; 370262306a36Sopenharmony_ci qp->prev_wqe_size = awqe1->wqe_size; 370362306a36Sopenharmony_ci break; 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_ci case IB_WR_LOCAL_INV: 370662306a36Sopenharmony_ci iwqe = (struct rdma_sq_local_inv_wqe *)wqe; 370762306a36Sopenharmony_ci iwqe->wqe_size = 1; 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_ci iwqe->req_type = RDMA_SQ_REQ_TYPE_LOCAL_INVALIDATE; 371062306a36Sopenharmony_ci iwqe->inv_l_key = wr->ex.invalidate_rkey; 371162306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].wqe_size = iwqe->wqe_size; 371262306a36Sopenharmony_ci qp->prev_wqe_size = iwqe->wqe_size; 371362306a36Sopenharmony_ci break; 371462306a36Sopenharmony_ci case IB_WR_REG_MR: 371562306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_CQ, "REG_MR\n"); 371662306a36Sopenharmony_ci wqe->req_type = RDMA_SQ_REQ_TYPE_FAST_MR; 371762306a36Sopenharmony_ci fwqe1 = (struct rdma_sq_fmr_wqe_1st *)wqe; 371862306a36Sopenharmony_ci fwqe1->wqe_size = 2; 371962306a36Sopenharmony_ci 372062306a36Sopenharmony_ci rc = qedr_prepare_reg(qp, fwqe1, reg_wr(wr)); 372162306a36Sopenharmony_ci if (rc) { 372262306a36Sopenharmony_ci DP_ERR(dev, "IB_REG_MR failed rc=%d\n", rc); 372362306a36Sopenharmony_ci *bad_wr = wr; 372462306a36Sopenharmony_ci break; 372562306a36Sopenharmony_ci } 372662306a36Sopenharmony_ci 372762306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].wqe_size = fwqe1->wqe_size; 372862306a36Sopenharmony_ci qp->prev_wqe_size = fwqe1->wqe_size; 372962306a36Sopenharmony_ci break; 373062306a36Sopenharmony_ci default: 373162306a36Sopenharmony_ci DP_ERR(dev, "invalid opcode 0x%x!\n", wr->opcode); 373262306a36Sopenharmony_ci rc = -EINVAL; 373362306a36Sopenharmony_ci *bad_wr = wr; 373462306a36Sopenharmony_ci break; 373562306a36Sopenharmony_ci } 373662306a36Sopenharmony_ci 373762306a36Sopenharmony_ci if (*bad_wr) { 373862306a36Sopenharmony_ci u16 value; 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_ci /* Restore prod to its position before 374162306a36Sopenharmony_ci * this WR was processed 374262306a36Sopenharmony_ci */ 374362306a36Sopenharmony_ci value = le16_to_cpu(qp->sq.db_data.data.value); 374462306a36Sopenharmony_ci qed_chain_set_prod(&qp->sq.pbl, value, wqe); 374562306a36Sopenharmony_ci 374662306a36Sopenharmony_ci /* Restore prev_wqe_size */ 374762306a36Sopenharmony_ci qp->prev_wqe_size = wqe->prev_wqe_size; 374862306a36Sopenharmony_ci rc = -EINVAL; 374962306a36Sopenharmony_ci DP_ERR(dev, "POST SEND FAILED\n"); 375062306a36Sopenharmony_ci } 375162306a36Sopenharmony_ci 375262306a36Sopenharmony_ci return rc; 375362306a36Sopenharmony_ci} 375462306a36Sopenharmony_ci 375562306a36Sopenharmony_ciint qedr_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, 375662306a36Sopenharmony_ci const struct ib_send_wr **bad_wr) 375762306a36Sopenharmony_ci{ 375862306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibqp->device); 375962306a36Sopenharmony_ci struct qedr_qp *qp = get_qedr_qp(ibqp); 376062306a36Sopenharmony_ci unsigned long flags; 376162306a36Sopenharmony_ci int rc = 0; 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_ci *bad_wr = NULL; 376462306a36Sopenharmony_ci 376562306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_GSI) 376662306a36Sopenharmony_ci return qedr_gsi_post_send(ibqp, wr, bad_wr); 376762306a36Sopenharmony_ci 376862306a36Sopenharmony_ci spin_lock_irqsave(&qp->q_lock, flags); 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci if (rdma_protocol_roce(&dev->ibdev, 1)) { 377162306a36Sopenharmony_ci if ((qp->state != QED_ROCE_QP_STATE_RTS) && 377262306a36Sopenharmony_ci (qp->state != QED_ROCE_QP_STATE_ERR) && 377362306a36Sopenharmony_ci (qp->state != QED_ROCE_QP_STATE_SQD)) { 377462306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 377562306a36Sopenharmony_ci *bad_wr = wr; 377662306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_CQ, 377762306a36Sopenharmony_ci "QP in wrong state! QP icid=0x%x state %d\n", 377862306a36Sopenharmony_ci qp->icid, qp->state); 377962306a36Sopenharmony_ci return -EINVAL; 378062306a36Sopenharmony_ci } 378162306a36Sopenharmony_ci } 378262306a36Sopenharmony_ci 378362306a36Sopenharmony_ci while (wr) { 378462306a36Sopenharmony_ci rc = __qedr_post_send(ibqp, wr, bad_wr); 378562306a36Sopenharmony_ci if (rc) 378662306a36Sopenharmony_ci break; 378762306a36Sopenharmony_ci 378862306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].wr_id = wr->wr_id; 378962306a36Sopenharmony_ci 379062306a36Sopenharmony_ci qedr_inc_sw_prod(&qp->sq); 379162306a36Sopenharmony_ci 379262306a36Sopenharmony_ci qp->sq.db_data.data.value++; 379362306a36Sopenharmony_ci 379462306a36Sopenharmony_ci wr = wr->next; 379562306a36Sopenharmony_ci } 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_ci /* Trigger doorbell 379862306a36Sopenharmony_ci * If there was a failure in the first WR then it will be triggered in 379962306a36Sopenharmony_ci * vane. However this is not harmful (as long as the producer value is 380062306a36Sopenharmony_ci * unchanged). For performance reasons we avoid checking for this 380162306a36Sopenharmony_ci * redundant doorbell. 380262306a36Sopenharmony_ci * 380362306a36Sopenharmony_ci * qp->wqe_wr_id is accessed during qedr_poll_cq, as 380462306a36Sopenharmony_ci * soon as we give the doorbell, we could get a completion 380562306a36Sopenharmony_ci * for this wr, therefore we need to make sure that the 380662306a36Sopenharmony_ci * memory is updated before giving the doorbell. 380762306a36Sopenharmony_ci * During qedr_poll_cq, rmb is called before accessing the 380862306a36Sopenharmony_ci * cqe. This covers for the smp_rmb as well. 380962306a36Sopenharmony_ci */ 381062306a36Sopenharmony_ci smp_wmb(); 381162306a36Sopenharmony_ci writel(qp->sq.db_data.raw, qp->sq.db); 381262306a36Sopenharmony_ci 381362306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 381462306a36Sopenharmony_ci 381562306a36Sopenharmony_ci return rc; 381662306a36Sopenharmony_ci} 381762306a36Sopenharmony_ci 381862306a36Sopenharmony_cistatic u32 qedr_srq_elem_left(struct qedr_srq_hwq_info *hw_srq) 381962306a36Sopenharmony_ci{ 382062306a36Sopenharmony_ci u32 used; 382162306a36Sopenharmony_ci 382262306a36Sopenharmony_ci /* Calculate number of elements used based on producer 382362306a36Sopenharmony_ci * count and consumer count and subtract it from max 382462306a36Sopenharmony_ci * work request supported so that we get elements left. 382562306a36Sopenharmony_ci */ 382662306a36Sopenharmony_ci used = hw_srq->wr_prod_cnt - (u32)atomic_read(&hw_srq->wr_cons_cnt); 382762306a36Sopenharmony_ci 382862306a36Sopenharmony_ci return hw_srq->max_wr - used; 382962306a36Sopenharmony_ci} 383062306a36Sopenharmony_ci 383162306a36Sopenharmony_ciint qedr_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, 383262306a36Sopenharmony_ci const struct ib_recv_wr **bad_wr) 383362306a36Sopenharmony_ci{ 383462306a36Sopenharmony_ci struct qedr_srq *srq = get_qedr_srq(ibsrq); 383562306a36Sopenharmony_ci struct qedr_srq_hwq_info *hw_srq; 383662306a36Sopenharmony_ci struct qedr_dev *dev = srq->dev; 383762306a36Sopenharmony_ci struct qed_chain *pbl; 383862306a36Sopenharmony_ci unsigned long flags; 383962306a36Sopenharmony_ci int status = 0; 384062306a36Sopenharmony_ci u32 num_sge; 384162306a36Sopenharmony_ci 384262306a36Sopenharmony_ci spin_lock_irqsave(&srq->lock, flags); 384362306a36Sopenharmony_ci 384462306a36Sopenharmony_ci hw_srq = &srq->hw_srq; 384562306a36Sopenharmony_ci pbl = &srq->hw_srq.pbl; 384662306a36Sopenharmony_ci while (wr) { 384762306a36Sopenharmony_ci struct rdma_srq_wqe_header *hdr; 384862306a36Sopenharmony_ci int i; 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_ci if (!qedr_srq_elem_left(hw_srq) || 385162306a36Sopenharmony_ci wr->num_sge > srq->hw_srq.max_sges) { 385262306a36Sopenharmony_ci DP_ERR(dev, "Can't post WR (%d,%d) || (%d > %d)\n", 385362306a36Sopenharmony_ci hw_srq->wr_prod_cnt, 385462306a36Sopenharmony_ci atomic_read(&hw_srq->wr_cons_cnt), 385562306a36Sopenharmony_ci wr->num_sge, srq->hw_srq.max_sges); 385662306a36Sopenharmony_ci status = -ENOMEM; 385762306a36Sopenharmony_ci *bad_wr = wr; 385862306a36Sopenharmony_ci break; 385962306a36Sopenharmony_ci } 386062306a36Sopenharmony_ci 386162306a36Sopenharmony_ci hdr = qed_chain_produce(pbl); 386262306a36Sopenharmony_ci num_sge = wr->num_sge; 386362306a36Sopenharmony_ci /* Set number of sge and work request id in header */ 386462306a36Sopenharmony_ci SRQ_HDR_SET(hdr, wr->wr_id, num_sge); 386562306a36Sopenharmony_ci 386662306a36Sopenharmony_ci srq->hw_srq.wr_prod_cnt++; 386762306a36Sopenharmony_ci hw_srq->wqe_prod++; 386862306a36Sopenharmony_ci hw_srq->sge_prod++; 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_SRQ, 387162306a36Sopenharmony_ci "SRQ WR: SGEs: %d with wr_id[%d] = %llx\n", 387262306a36Sopenharmony_ci wr->num_sge, hw_srq->wqe_prod, wr->wr_id); 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 387562306a36Sopenharmony_ci struct rdma_srq_sge *srq_sge = qed_chain_produce(pbl); 387662306a36Sopenharmony_ci 387762306a36Sopenharmony_ci /* Set SGE length, lkey and address */ 387862306a36Sopenharmony_ci SRQ_SGE_SET(srq_sge, wr->sg_list[i].addr, 387962306a36Sopenharmony_ci wr->sg_list[i].length, wr->sg_list[i].lkey); 388062306a36Sopenharmony_ci 388162306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_SRQ, 388262306a36Sopenharmony_ci "[%d]: len %d key %x addr %x:%x\n", 388362306a36Sopenharmony_ci i, srq_sge->length, srq_sge->l_key, 388462306a36Sopenharmony_ci srq_sge->addr.hi, srq_sge->addr.lo); 388562306a36Sopenharmony_ci hw_srq->sge_prod++; 388662306a36Sopenharmony_ci } 388762306a36Sopenharmony_ci 388862306a36Sopenharmony_ci /* Update WQE and SGE information before 388962306a36Sopenharmony_ci * updating producer. 389062306a36Sopenharmony_ci */ 389162306a36Sopenharmony_ci dma_wmb(); 389262306a36Sopenharmony_ci 389362306a36Sopenharmony_ci /* SRQ producer is 8 bytes. Need to update SGE producer index 389462306a36Sopenharmony_ci * in first 4 bytes and need to update WQE producer in 389562306a36Sopenharmony_ci * next 4 bytes. 389662306a36Sopenharmony_ci */ 389762306a36Sopenharmony_ci srq->hw_srq.virt_prod_pair_addr->sge_prod = cpu_to_le32(hw_srq->sge_prod); 389862306a36Sopenharmony_ci /* Make sure sge producer is updated first */ 389962306a36Sopenharmony_ci dma_wmb(); 390062306a36Sopenharmony_ci srq->hw_srq.virt_prod_pair_addr->wqe_prod = cpu_to_le32(hw_srq->wqe_prod); 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_ci wr = wr->next; 390362306a36Sopenharmony_ci } 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_SRQ, "POST: Elements in S-RQ: %d\n", 390662306a36Sopenharmony_ci qed_chain_get_elem_left(pbl)); 390762306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->lock, flags); 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ci return status; 391062306a36Sopenharmony_ci} 391162306a36Sopenharmony_ci 391262306a36Sopenharmony_ciint qedr_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, 391362306a36Sopenharmony_ci const struct ib_recv_wr **bad_wr) 391462306a36Sopenharmony_ci{ 391562306a36Sopenharmony_ci struct qedr_qp *qp = get_qedr_qp(ibqp); 391662306a36Sopenharmony_ci struct qedr_dev *dev = qp->dev; 391762306a36Sopenharmony_ci unsigned long flags; 391862306a36Sopenharmony_ci int status = 0; 391962306a36Sopenharmony_ci 392062306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_GSI) 392162306a36Sopenharmony_ci return qedr_gsi_post_recv(ibqp, wr, bad_wr); 392262306a36Sopenharmony_ci 392362306a36Sopenharmony_ci spin_lock_irqsave(&qp->q_lock, flags); 392462306a36Sopenharmony_ci 392562306a36Sopenharmony_ci while (wr) { 392662306a36Sopenharmony_ci int i; 392762306a36Sopenharmony_ci 392862306a36Sopenharmony_ci if (qed_chain_get_elem_left_u32(&qp->rq.pbl) < 392962306a36Sopenharmony_ci QEDR_MAX_RQE_ELEMENTS_PER_RQE || 393062306a36Sopenharmony_ci wr->num_sge > qp->rq.max_sges) { 393162306a36Sopenharmony_ci DP_ERR(dev, "Can't post WR (%d < %d) || (%d > %d)\n", 393262306a36Sopenharmony_ci qed_chain_get_elem_left_u32(&qp->rq.pbl), 393362306a36Sopenharmony_ci QEDR_MAX_RQE_ELEMENTS_PER_RQE, wr->num_sge, 393462306a36Sopenharmony_ci qp->rq.max_sges); 393562306a36Sopenharmony_ci status = -ENOMEM; 393662306a36Sopenharmony_ci *bad_wr = wr; 393762306a36Sopenharmony_ci break; 393862306a36Sopenharmony_ci } 393962306a36Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 394062306a36Sopenharmony_ci u32 flags = 0; 394162306a36Sopenharmony_ci struct rdma_rq_sge *rqe = 394262306a36Sopenharmony_ci qed_chain_produce(&qp->rq.pbl); 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_ci /* First one must include the number 394562306a36Sopenharmony_ci * of SGE in the list 394662306a36Sopenharmony_ci */ 394762306a36Sopenharmony_ci if (!i) 394862306a36Sopenharmony_ci SET_FIELD(flags, RDMA_RQ_SGE_NUM_SGES, 394962306a36Sopenharmony_ci wr->num_sge); 395062306a36Sopenharmony_ci 395162306a36Sopenharmony_ci SET_FIELD(flags, RDMA_RQ_SGE_L_KEY_LO, 395262306a36Sopenharmony_ci wr->sg_list[i].lkey); 395362306a36Sopenharmony_ci 395462306a36Sopenharmony_ci RQ_SGE_SET(rqe, wr->sg_list[i].addr, 395562306a36Sopenharmony_ci wr->sg_list[i].length, flags); 395662306a36Sopenharmony_ci } 395762306a36Sopenharmony_ci 395862306a36Sopenharmony_ci /* Special case of no sges. FW requires between 1-4 sges... 395962306a36Sopenharmony_ci * in this case we need to post 1 sge with length zero. this is 396062306a36Sopenharmony_ci * because rdma write with immediate consumes an RQ. 396162306a36Sopenharmony_ci */ 396262306a36Sopenharmony_ci if (!wr->num_sge) { 396362306a36Sopenharmony_ci u32 flags = 0; 396462306a36Sopenharmony_ci struct rdma_rq_sge *rqe = 396562306a36Sopenharmony_ci qed_chain_produce(&qp->rq.pbl); 396662306a36Sopenharmony_ci 396762306a36Sopenharmony_ci /* First one must include the number 396862306a36Sopenharmony_ci * of SGE in the list 396962306a36Sopenharmony_ci */ 397062306a36Sopenharmony_ci SET_FIELD(flags, RDMA_RQ_SGE_L_KEY_LO, 0); 397162306a36Sopenharmony_ci SET_FIELD(flags, RDMA_RQ_SGE_NUM_SGES, 1); 397262306a36Sopenharmony_ci 397362306a36Sopenharmony_ci RQ_SGE_SET(rqe, 0, 0, flags); 397462306a36Sopenharmony_ci i = 1; 397562306a36Sopenharmony_ci } 397662306a36Sopenharmony_ci 397762306a36Sopenharmony_ci qp->rqe_wr_id[qp->rq.prod].wr_id = wr->wr_id; 397862306a36Sopenharmony_ci qp->rqe_wr_id[qp->rq.prod].wqe_size = i; 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ci qedr_inc_sw_prod(&qp->rq); 398162306a36Sopenharmony_ci 398262306a36Sopenharmony_ci /* qp->rqe_wr_id is accessed during qedr_poll_cq, as 398362306a36Sopenharmony_ci * soon as we give the doorbell, we could get a completion 398462306a36Sopenharmony_ci * for this wr, therefore we need to make sure that the 398562306a36Sopenharmony_ci * memory is update before giving the doorbell. 398662306a36Sopenharmony_ci * During qedr_poll_cq, rmb is called before accessing the 398762306a36Sopenharmony_ci * cqe. This covers for the smp_rmb as well. 398862306a36Sopenharmony_ci */ 398962306a36Sopenharmony_ci smp_wmb(); 399062306a36Sopenharmony_ci 399162306a36Sopenharmony_ci qp->rq.db_data.data.value++; 399262306a36Sopenharmony_ci 399362306a36Sopenharmony_ci writel(qp->rq.db_data.raw, qp->rq.db); 399462306a36Sopenharmony_ci 399562306a36Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) { 399662306a36Sopenharmony_ci writel(qp->rq.iwarp_db2_data.raw, qp->rq.iwarp_db2); 399762306a36Sopenharmony_ci } 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_ci wr = wr->next; 400062306a36Sopenharmony_ci } 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 400362306a36Sopenharmony_ci 400462306a36Sopenharmony_ci return status; 400562306a36Sopenharmony_ci} 400662306a36Sopenharmony_ci 400762306a36Sopenharmony_cistatic int is_valid_cqe(struct qedr_cq *cq, union rdma_cqe *cqe) 400862306a36Sopenharmony_ci{ 400962306a36Sopenharmony_ci struct rdma_cqe_requester *resp_cqe = &cqe->req; 401062306a36Sopenharmony_ci 401162306a36Sopenharmony_ci return (resp_cqe->flags & RDMA_CQE_REQUESTER_TOGGLE_BIT_MASK) == 401262306a36Sopenharmony_ci cq->pbl_toggle; 401362306a36Sopenharmony_ci} 401462306a36Sopenharmony_ci 401562306a36Sopenharmony_cistatic struct qedr_qp *cqe_get_qp(union rdma_cqe *cqe) 401662306a36Sopenharmony_ci{ 401762306a36Sopenharmony_ci struct rdma_cqe_requester *resp_cqe = &cqe->req; 401862306a36Sopenharmony_ci struct qedr_qp *qp; 401962306a36Sopenharmony_ci 402062306a36Sopenharmony_ci qp = (struct qedr_qp *)(uintptr_t)HILO_GEN(resp_cqe->qp_handle.hi, 402162306a36Sopenharmony_ci resp_cqe->qp_handle.lo, 402262306a36Sopenharmony_ci u64); 402362306a36Sopenharmony_ci return qp; 402462306a36Sopenharmony_ci} 402562306a36Sopenharmony_ci 402662306a36Sopenharmony_cistatic enum rdma_cqe_type cqe_get_type(union rdma_cqe *cqe) 402762306a36Sopenharmony_ci{ 402862306a36Sopenharmony_ci struct rdma_cqe_requester *resp_cqe = &cqe->req; 402962306a36Sopenharmony_ci 403062306a36Sopenharmony_ci return GET_FIELD(resp_cqe->flags, RDMA_CQE_REQUESTER_TYPE); 403162306a36Sopenharmony_ci} 403262306a36Sopenharmony_ci 403362306a36Sopenharmony_ci/* Return latest CQE (needs processing) */ 403462306a36Sopenharmony_cistatic union rdma_cqe *get_cqe(struct qedr_cq *cq) 403562306a36Sopenharmony_ci{ 403662306a36Sopenharmony_ci return cq->latest_cqe; 403762306a36Sopenharmony_ci} 403862306a36Sopenharmony_ci 403962306a36Sopenharmony_ci/* In fmr we need to increase the number of fmr completed counter for the fmr 404062306a36Sopenharmony_ci * algorithm determining whether we can free a pbl or not. 404162306a36Sopenharmony_ci * we need to perform this whether the work request was signaled or not. for 404262306a36Sopenharmony_ci * this purpose we call this function from the condition that checks if a wr 404362306a36Sopenharmony_ci * should be skipped, to make sure we don't miss it ( possibly this fmr 404462306a36Sopenharmony_ci * operation was not signalted) 404562306a36Sopenharmony_ci */ 404662306a36Sopenharmony_cistatic inline void qedr_chk_if_fmr(struct qedr_qp *qp) 404762306a36Sopenharmony_ci{ 404862306a36Sopenharmony_ci if (qp->wqe_wr_id[qp->sq.cons].opcode == IB_WC_REG_MR) 404962306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.cons].mr->info.completed++; 405062306a36Sopenharmony_ci} 405162306a36Sopenharmony_ci 405262306a36Sopenharmony_cistatic int process_req(struct qedr_dev *dev, struct qedr_qp *qp, 405362306a36Sopenharmony_ci struct qedr_cq *cq, int num_entries, 405462306a36Sopenharmony_ci struct ib_wc *wc, u16 hw_cons, enum ib_wc_status status, 405562306a36Sopenharmony_ci int force) 405662306a36Sopenharmony_ci{ 405762306a36Sopenharmony_ci u16 cnt = 0; 405862306a36Sopenharmony_ci 405962306a36Sopenharmony_ci while (num_entries && qp->sq.wqe_cons != hw_cons) { 406062306a36Sopenharmony_ci if (!qp->wqe_wr_id[qp->sq.cons].signaled && !force) { 406162306a36Sopenharmony_ci qedr_chk_if_fmr(qp); 406262306a36Sopenharmony_ci /* skip WC */ 406362306a36Sopenharmony_ci goto next_cqe; 406462306a36Sopenharmony_ci } 406562306a36Sopenharmony_ci 406662306a36Sopenharmony_ci /* fill WC */ 406762306a36Sopenharmony_ci wc->status = status; 406862306a36Sopenharmony_ci wc->vendor_err = 0; 406962306a36Sopenharmony_ci wc->wc_flags = 0; 407062306a36Sopenharmony_ci wc->src_qp = qp->id; 407162306a36Sopenharmony_ci wc->qp = &qp->ibqp; 407262306a36Sopenharmony_ci 407362306a36Sopenharmony_ci wc->wr_id = qp->wqe_wr_id[qp->sq.cons].wr_id; 407462306a36Sopenharmony_ci wc->opcode = qp->wqe_wr_id[qp->sq.cons].opcode; 407562306a36Sopenharmony_ci 407662306a36Sopenharmony_ci switch (wc->opcode) { 407762306a36Sopenharmony_ci case IB_WC_RDMA_WRITE: 407862306a36Sopenharmony_ci wc->byte_len = qp->wqe_wr_id[qp->sq.cons].bytes_len; 407962306a36Sopenharmony_ci break; 408062306a36Sopenharmony_ci case IB_WC_COMP_SWAP: 408162306a36Sopenharmony_ci case IB_WC_FETCH_ADD: 408262306a36Sopenharmony_ci wc->byte_len = 8; 408362306a36Sopenharmony_ci break; 408462306a36Sopenharmony_ci case IB_WC_REG_MR: 408562306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.cons].mr->info.completed++; 408662306a36Sopenharmony_ci break; 408762306a36Sopenharmony_ci case IB_WC_RDMA_READ: 408862306a36Sopenharmony_ci case IB_WC_SEND: 408962306a36Sopenharmony_ci wc->byte_len = qp->wqe_wr_id[qp->sq.cons].bytes_len; 409062306a36Sopenharmony_ci break; 409162306a36Sopenharmony_ci default: 409262306a36Sopenharmony_ci break; 409362306a36Sopenharmony_ci } 409462306a36Sopenharmony_ci 409562306a36Sopenharmony_ci num_entries--; 409662306a36Sopenharmony_ci wc++; 409762306a36Sopenharmony_ci cnt++; 409862306a36Sopenharmony_cinext_cqe: 409962306a36Sopenharmony_ci while (qp->wqe_wr_id[qp->sq.cons].wqe_size--) 410062306a36Sopenharmony_ci qed_chain_consume(&qp->sq.pbl); 410162306a36Sopenharmony_ci qedr_inc_sw_cons(&qp->sq); 410262306a36Sopenharmony_ci } 410362306a36Sopenharmony_ci 410462306a36Sopenharmony_ci return cnt; 410562306a36Sopenharmony_ci} 410662306a36Sopenharmony_ci 410762306a36Sopenharmony_cistatic int qedr_poll_cq_req(struct qedr_dev *dev, 410862306a36Sopenharmony_ci struct qedr_qp *qp, struct qedr_cq *cq, 410962306a36Sopenharmony_ci int num_entries, struct ib_wc *wc, 411062306a36Sopenharmony_ci struct rdma_cqe_requester *req) 411162306a36Sopenharmony_ci{ 411262306a36Sopenharmony_ci int cnt = 0; 411362306a36Sopenharmony_ci 411462306a36Sopenharmony_ci switch (req->status) { 411562306a36Sopenharmony_ci case RDMA_CQE_REQ_STS_OK: 411662306a36Sopenharmony_ci cnt = process_req(dev, qp, cq, num_entries, wc, req->sq_cons, 411762306a36Sopenharmony_ci IB_WC_SUCCESS, 0); 411862306a36Sopenharmony_ci break; 411962306a36Sopenharmony_ci case RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR: 412062306a36Sopenharmony_ci if (qp->state != QED_ROCE_QP_STATE_ERR) 412162306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_CQ, 412262306a36Sopenharmony_ci "Error: POLL CQ with RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR. CQ icid=0x%x, QP icid=0x%x\n", 412362306a36Sopenharmony_ci cq->icid, qp->icid); 412462306a36Sopenharmony_ci cnt = process_req(dev, qp, cq, num_entries, wc, req->sq_cons, 412562306a36Sopenharmony_ci IB_WC_WR_FLUSH_ERR, 1); 412662306a36Sopenharmony_ci break; 412762306a36Sopenharmony_ci default: 412862306a36Sopenharmony_ci /* process all WQE before the cosumer */ 412962306a36Sopenharmony_ci qp->state = QED_ROCE_QP_STATE_ERR; 413062306a36Sopenharmony_ci cnt = process_req(dev, qp, cq, num_entries, wc, 413162306a36Sopenharmony_ci req->sq_cons - 1, IB_WC_SUCCESS, 0); 413262306a36Sopenharmony_ci wc += cnt; 413362306a36Sopenharmony_ci /* if we have extra WC fill it with actual error info */ 413462306a36Sopenharmony_ci if (cnt < num_entries) { 413562306a36Sopenharmony_ci enum ib_wc_status wc_status; 413662306a36Sopenharmony_ci 413762306a36Sopenharmony_ci switch (req->status) { 413862306a36Sopenharmony_ci case RDMA_CQE_REQ_STS_BAD_RESPONSE_ERR: 413962306a36Sopenharmony_ci DP_ERR(dev, 414062306a36Sopenharmony_ci "Error: POLL CQ with RDMA_CQE_REQ_STS_BAD_RESPONSE_ERR. CQ icid=0x%x, QP icid=0x%x\n", 414162306a36Sopenharmony_ci cq->icid, qp->icid); 414262306a36Sopenharmony_ci wc_status = IB_WC_BAD_RESP_ERR; 414362306a36Sopenharmony_ci break; 414462306a36Sopenharmony_ci case RDMA_CQE_REQ_STS_LOCAL_LENGTH_ERR: 414562306a36Sopenharmony_ci DP_ERR(dev, 414662306a36Sopenharmony_ci "Error: POLL CQ with RDMA_CQE_REQ_STS_LOCAL_LENGTH_ERR. CQ icid=0x%x, QP icid=0x%x\n", 414762306a36Sopenharmony_ci cq->icid, qp->icid); 414862306a36Sopenharmony_ci wc_status = IB_WC_LOC_LEN_ERR; 414962306a36Sopenharmony_ci break; 415062306a36Sopenharmony_ci case RDMA_CQE_REQ_STS_LOCAL_QP_OPERATION_ERR: 415162306a36Sopenharmony_ci DP_ERR(dev, 415262306a36Sopenharmony_ci "Error: POLL CQ with RDMA_CQE_REQ_STS_LOCAL_QP_OPERATION_ERR. CQ icid=0x%x, QP icid=0x%x\n", 415362306a36Sopenharmony_ci cq->icid, qp->icid); 415462306a36Sopenharmony_ci wc_status = IB_WC_LOC_QP_OP_ERR; 415562306a36Sopenharmony_ci break; 415662306a36Sopenharmony_ci case RDMA_CQE_REQ_STS_LOCAL_PROTECTION_ERR: 415762306a36Sopenharmony_ci DP_ERR(dev, 415862306a36Sopenharmony_ci "Error: POLL CQ with RDMA_CQE_REQ_STS_LOCAL_PROTECTION_ERR. CQ icid=0x%x, QP icid=0x%x\n", 415962306a36Sopenharmony_ci cq->icid, qp->icid); 416062306a36Sopenharmony_ci wc_status = IB_WC_LOC_PROT_ERR; 416162306a36Sopenharmony_ci break; 416262306a36Sopenharmony_ci case RDMA_CQE_REQ_STS_MEMORY_MGT_OPERATION_ERR: 416362306a36Sopenharmony_ci DP_ERR(dev, 416462306a36Sopenharmony_ci "Error: POLL CQ with RDMA_CQE_REQ_STS_MEMORY_MGT_OPERATION_ERR. CQ icid=0x%x, QP icid=0x%x\n", 416562306a36Sopenharmony_ci cq->icid, qp->icid); 416662306a36Sopenharmony_ci wc_status = IB_WC_MW_BIND_ERR; 416762306a36Sopenharmony_ci break; 416862306a36Sopenharmony_ci case RDMA_CQE_REQ_STS_REMOTE_INVALID_REQUEST_ERR: 416962306a36Sopenharmony_ci DP_ERR(dev, 417062306a36Sopenharmony_ci "Error: POLL CQ with RDMA_CQE_REQ_STS_REMOTE_INVALID_REQUEST_ERR. CQ icid=0x%x, QP icid=0x%x\n", 417162306a36Sopenharmony_ci cq->icid, qp->icid); 417262306a36Sopenharmony_ci wc_status = IB_WC_REM_INV_REQ_ERR; 417362306a36Sopenharmony_ci break; 417462306a36Sopenharmony_ci case RDMA_CQE_REQ_STS_REMOTE_ACCESS_ERR: 417562306a36Sopenharmony_ci DP_ERR(dev, 417662306a36Sopenharmony_ci "Error: POLL CQ with RDMA_CQE_REQ_STS_REMOTE_ACCESS_ERR. CQ icid=0x%x, QP icid=0x%x\n", 417762306a36Sopenharmony_ci cq->icid, qp->icid); 417862306a36Sopenharmony_ci wc_status = IB_WC_REM_ACCESS_ERR; 417962306a36Sopenharmony_ci break; 418062306a36Sopenharmony_ci case RDMA_CQE_REQ_STS_REMOTE_OPERATION_ERR: 418162306a36Sopenharmony_ci DP_ERR(dev, 418262306a36Sopenharmony_ci "Error: POLL CQ with RDMA_CQE_REQ_STS_REMOTE_OPERATION_ERR. CQ icid=0x%x, QP icid=0x%x\n", 418362306a36Sopenharmony_ci cq->icid, qp->icid); 418462306a36Sopenharmony_ci wc_status = IB_WC_REM_OP_ERR; 418562306a36Sopenharmony_ci break; 418662306a36Sopenharmony_ci case RDMA_CQE_REQ_STS_RNR_NAK_RETRY_CNT_ERR: 418762306a36Sopenharmony_ci DP_ERR(dev, 418862306a36Sopenharmony_ci "Error: POLL CQ with RDMA_CQE_REQ_STS_RNR_NAK_RETRY_CNT_ERR. CQ icid=0x%x, QP icid=0x%x\n", 418962306a36Sopenharmony_ci cq->icid, qp->icid); 419062306a36Sopenharmony_ci wc_status = IB_WC_RNR_RETRY_EXC_ERR; 419162306a36Sopenharmony_ci break; 419262306a36Sopenharmony_ci case RDMA_CQE_REQ_STS_TRANSPORT_RETRY_CNT_ERR: 419362306a36Sopenharmony_ci DP_ERR(dev, 419462306a36Sopenharmony_ci "Error: POLL CQ with ROCE_CQE_REQ_STS_TRANSPORT_RETRY_CNT_ERR. CQ icid=0x%x, QP icid=0x%x\n", 419562306a36Sopenharmony_ci cq->icid, qp->icid); 419662306a36Sopenharmony_ci wc_status = IB_WC_RETRY_EXC_ERR; 419762306a36Sopenharmony_ci break; 419862306a36Sopenharmony_ci default: 419962306a36Sopenharmony_ci DP_ERR(dev, 420062306a36Sopenharmony_ci "Error: POLL CQ with IB_WC_GENERAL_ERR. CQ icid=0x%x, QP icid=0x%x\n", 420162306a36Sopenharmony_ci cq->icid, qp->icid); 420262306a36Sopenharmony_ci wc_status = IB_WC_GENERAL_ERR; 420362306a36Sopenharmony_ci } 420462306a36Sopenharmony_ci cnt += process_req(dev, qp, cq, 1, wc, req->sq_cons, 420562306a36Sopenharmony_ci wc_status, 1); 420662306a36Sopenharmony_ci } 420762306a36Sopenharmony_ci } 420862306a36Sopenharmony_ci 420962306a36Sopenharmony_ci return cnt; 421062306a36Sopenharmony_ci} 421162306a36Sopenharmony_ci 421262306a36Sopenharmony_cistatic inline int qedr_cqe_resp_status_to_ib(u8 status) 421362306a36Sopenharmony_ci{ 421462306a36Sopenharmony_ci switch (status) { 421562306a36Sopenharmony_ci case RDMA_CQE_RESP_STS_LOCAL_ACCESS_ERR: 421662306a36Sopenharmony_ci return IB_WC_LOC_ACCESS_ERR; 421762306a36Sopenharmony_ci case RDMA_CQE_RESP_STS_LOCAL_LENGTH_ERR: 421862306a36Sopenharmony_ci return IB_WC_LOC_LEN_ERR; 421962306a36Sopenharmony_ci case RDMA_CQE_RESP_STS_LOCAL_QP_OPERATION_ERR: 422062306a36Sopenharmony_ci return IB_WC_LOC_QP_OP_ERR; 422162306a36Sopenharmony_ci case RDMA_CQE_RESP_STS_LOCAL_PROTECTION_ERR: 422262306a36Sopenharmony_ci return IB_WC_LOC_PROT_ERR; 422362306a36Sopenharmony_ci case RDMA_CQE_RESP_STS_MEMORY_MGT_OPERATION_ERR: 422462306a36Sopenharmony_ci return IB_WC_MW_BIND_ERR; 422562306a36Sopenharmony_ci case RDMA_CQE_RESP_STS_REMOTE_INVALID_REQUEST_ERR: 422662306a36Sopenharmony_ci return IB_WC_REM_INV_RD_REQ_ERR; 422762306a36Sopenharmony_ci case RDMA_CQE_RESP_STS_OK: 422862306a36Sopenharmony_ci return IB_WC_SUCCESS; 422962306a36Sopenharmony_ci default: 423062306a36Sopenharmony_ci return IB_WC_GENERAL_ERR; 423162306a36Sopenharmony_ci } 423262306a36Sopenharmony_ci} 423362306a36Sopenharmony_ci 423462306a36Sopenharmony_cistatic inline int qedr_set_ok_cqe_resp_wc(struct rdma_cqe_responder *resp, 423562306a36Sopenharmony_ci struct ib_wc *wc) 423662306a36Sopenharmony_ci{ 423762306a36Sopenharmony_ci wc->status = IB_WC_SUCCESS; 423862306a36Sopenharmony_ci wc->byte_len = le32_to_cpu(resp->length); 423962306a36Sopenharmony_ci 424062306a36Sopenharmony_ci if (resp->flags & QEDR_RESP_IMM) { 424162306a36Sopenharmony_ci wc->ex.imm_data = cpu_to_be32(le32_to_cpu(resp->imm_data_or_inv_r_Key)); 424262306a36Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_IMM; 424362306a36Sopenharmony_ci 424462306a36Sopenharmony_ci if (resp->flags & QEDR_RESP_RDMA) 424562306a36Sopenharmony_ci wc->opcode = IB_WC_RECV_RDMA_WITH_IMM; 424662306a36Sopenharmony_ci 424762306a36Sopenharmony_ci if (resp->flags & QEDR_RESP_INV) 424862306a36Sopenharmony_ci return -EINVAL; 424962306a36Sopenharmony_ci 425062306a36Sopenharmony_ci } else if (resp->flags & QEDR_RESP_INV) { 425162306a36Sopenharmony_ci wc->ex.imm_data = le32_to_cpu(resp->imm_data_or_inv_r_Key); 425262306a36Sopenharmony_ci wc->wc_flags |= IB_WC_WITH_INVALIDATE; 425362306a36Sopenharmony_ci 425462306a36Sopenharmony_ci if (resp->flags & QEDR_RESP_RDMA) 425562306a36Sopenharmony_ci return -EINVAL; 425662306a36Sopenharmony_ci 425762306a36Sopenharmony_ci } else if (resp->flags & QEDR_RESP_RDMA) { 425862306a36Sopenharmony_ci return -EINVAL; 425962306a36Sopenharmony_ci } 426062306a36Sopenharmony_ci 426162306a36Sopenharmony_ci return 0; 426262306a36Sopenharmony_ci} 426362306a36Sopenharmony_ci 426462306a36Sopenharmony_cistatic void __process_resp_one(struct qedr_dev *dev, struct qedr_qp *qp, 426562306a36Sopenharmony_ci struct qedr_cq *cq, struct ib_wc *wc, 426662306a36Sopenharmony_ci struct rdma_cqe_responder *resp, u64 wr_id) 426762306a36Sopenharmony_ci{ 426862306a36Sopenharmony_ci /* Must fill fields before qedr_set_ok_cqe_resp_wc() */ 426962306a36Sopenharmony_ci wc->opcode = IB_WC_RECV; 427062306a36Sopenharmony_ci wc->wc_flags = 0; 427162306a36Sopenharmony_ci 427262306a36Sopenharmony_ci if (likely(resp->status == RDMA_CQE_RESP_STS_OK)) { 427362306a36Sopenharmony_ci if (qedr_set_ok_cqe_resp_wc(resp, wc)) 427462306a36Sopenharmony_ci DP_ERR(dev, 427562306a36Sopenharmony_ci "CQ %p (icid=%d) has invalid CQE responder flags=0x%x\n", 427662306a36Sopenharmony_ci cq, cq->icid, resp->flags); 427762306a36Sopenharmony_ci 427862306a36Sopenharmony_ci } else { 427962306a36Sopenharmony_ci wc->status = qedr_cqe_resp_status_to_ib(resp->status); 428062306a36Sopenharmony_ci if (wc->status == IB_WC_GENERAL_ERR) 428162306a36Sopenharmony_ci DP_ERR(dev, 428262306a36Sopenharmony_ci "CQ %p (icid=%d) contains an invalid CQE status %d\n", 428362306a36Sopenharmony_ci cq, cq->icid, resp->status); 428462306a36Sopenharmony_ci } 428562306a36Sopenharmony_ci 428662306a36Sopenharmony_ci /* Fill the rest of the WC */ 428762306a36Sopenharmony_ci wc->vendor_err = 0; 428862306a36Sopenharmony_ci wc->src_qp = qp->id; 428962306a36Sopenharmony_ci wc->qp = &qp->ibqp; 429062306a36Sopenharmony_ci wc->wr_id = wr_id; 429162306a36Sopenharmony_ci} 429262306a36Sopenharmony_ci 429362306a36Sopenharmony_cistatic int process_resp_one_srq(struct qedr_dev *dev, struct qedr_qp *qp, 429462306a36Sopenharmony_ci struct qedr_cq *cq, struct ib_wc *wc, 429562306a36Sopenharmony_ci struct rdma_cqe_responder *resp) 429662306a36Sopenharmony_ci{ 429762306a36Sopenharmony_ci struct qedr_srq *srq = qp->srq; 429862306a36Sopenharmony_ci u64 wr_id; 429962306a36Sopenharmony_ci 430062306a36Sopenharmony_ci wr_id = HILO_GEN(le32_to_cpu(resp->srq_wr_id.hi), 430162306a36Sopenharmony_ci le32_to_cpu(resp->srq_wr_id.lo), u64); 430262306a36Sopenharmony_ci 430362306a36Sopenharmony_ci if (resp->status == RDMA_CQE_RESP_STS_WORK_REQUEST_FLUSHED_ERR) { 430462306a36Sopenharmony_ci wc->status = IB_WC_WR_FLUSH_ERR; 430562306a36Sopenharmony_ci wc->vendor_err = 0; 430662306a36Sopenharmony_ci wc->wr_id = wr_id; 430762306a36Sopenharmony_ci wc->byte_len = 0; 430862306a36Sopenharmony_ci wc->src_qp = qp->id; 430962306a36Sopenharmony_ci wc->qp = &qp->ibqp; 431062306a36Sopenharmony_ci wc->wr_id = wr_id; 431162306a36Sopenharmony_ci } else { 431262306a36Sopenharmony_ci __process_resp_one(dev, qp, cq, wc, resp, wr_id); 431362306a36Sopenharmony_ci } 431462306a36Sopenharmony_ci atomic_inc(&srq->hw_srq.wr_cons_cnt); 431562306a36Sopenharmony_ci 431662306a36Sopenharmony_ci return 1; 431762306a36Sopenharmony_ci} 431862306a36Sopenharmony_cistatic int process_resp_one(struct qedr_dev *dev, struct qedr_qp *qp, 431962306a36Sopenharmony_ci struct qedr_cq *cq, struct ib_wc *wc, 432062306a36Sopenharmony_ci struct rdma_cqe_responder *resp) 432162306a36Sopenharmony_ci{ 432262306a36Sopenharmony_ci u64 wr_id = qp->rqe_wr_id[qp->rq.cons].wr_id; 432362306a36Sopenharmony_ci 432462306a36Sopenharmony_ci __process_resp_one(dev, qp, cq, wc, resp, wr_id); 432562306a36Sopenharmony_ci 432662306a36Sopenharmony_ci while (qp->rqe_wr_id[qp->rq.cons].wqe_size--) 432762306a36Sopenharmony_ci qed_chain_consume(&qp->rq.pbl); 432862306a36Sopenharmony_ci qedr_inc_sw_cons(&qp->rq); 432962306a36Sopenharmony_ci 433062306a36Sopenharmony_ci return 1; 433162306a36Sopenharmony_ci} 433262306a36Sopenharmony_ci 433362306a36Sopenharmony_cistatic int process_resp_flush(struct qedr_qp *qp, struct qedr_cq *cq, 433462306a36Sopenharmony_ci int num_entries, struct ib_wc *wc, u16 hw_cons) 433562306a36Sopenharmony_ci{ 433662306a36Sopenharmony_ci u16 cnt = 0; 433762306a36Sopenharmony_ci 433862306a36Sopenharmony_ci while (num_entries && qp->rq.wqe_cons != hw_cons) { 433962306a36Sopenharmony_ci /* fill WC */ 434062306a36Sopenharmony_ci wc->status = IB_WC_WR_FLUSH_ERR; 434162306a36Sopenharmony_ci wc->vendor_err = 0; 434262306a36Sopenharmony_ci wc->wc_flags = 0; 434362306a36Sopenharmony_ci wc->src_qp = qp->id; 434462306a36Sopenharmony_ci wc->byte_len = 0; 434562306a36Sopenharmony_ci wc->wr_id = qp->rqe_wr_id[qp->rq.cons].wr_id; 434662306a36Sopenharmony_ci wc->qp = &qp->ibqp; 434762306a36Sopenharmony_ci num_entries--; 434862306a36Sopenharmony_ci wc++; 434962306a36Sopenharmony_ci cnt++; 435062306a36Sopenharmony_ci while (qp->rqe_wr_id[qp->rq.cons].wqe_size--) 435162306a36Sopenharmony_ci qed_chain_consume(&qp->rq.pbl); 435262306a36Sopenharmony_ci qedr_inc_sw_cons(&qp->rq); 435362306a36Sopenharmony_ci } 435462306a36Sopenharmony_ci 435562306a36Sopenharmony_ci return cnt; 435662306a36Sopenharmony_ci} 435762306a36Sopenharmony_ci 435862306a36Sopenharmony_cistatic void try_consume_resp_cqe(struct qedr_cq *cq, struct qedr_qp *qp, 435962306a36Sopenharmony_ci struct rdma_cqe_responder *resp, int *update) 436062306a36Sopenharmony_ci{ 436162306a36Sopenharmony_ci if (le16_to_cpu(resp->rq_cons_or_srq_id) == qp->rq.wqe_cons) { 436262306a36Sopenharmony_ci consume_cqe(cq); 436362306a36Sopenharmony_ci *update |= 1; 436462306a36Sopenharmony_ci } 436562306a36Sopenharmony_ci} 436662306a36Sopenharmony_ci 436762306a36Sopenharmony_cistatic int qedr_poll_cq_resp_srq(struct qedr_dev *dev, struct qedr_qp *qp, 436862306a36Sopenharmony_ci struct qedr_cq *cq, int num_entries, 436962306a36Sopenharmony_ci struct ib_wc *wc, 437062306a36Sopenharmony_ci struct rdma_cqe_responder *resp) 437162306a36Sopenharmony_ci{ 437262306a36Sopenharmony_ci int cnt; 437362306a36Sopenharmony_ci 437462306a36Sopenharmony_ci cnt = process_resp_one_srq(dev, qp, cq, wc, resp); 437562306a36Sopenharmony_ci consume_cqe(cq); 437662306a36Sopenharmony_ci 437762306a36Sopenharmony_ci return cnt; 437862306a36Sopenharmony_ci} 437962306a36Sopenharmony_ci 438062306a36Sopenharmony_cistatic int qedr_poll_cq_resp(struct qedr_dev *dev, struct qedr_qp *qp, 438162306a36Sopenharmony_ci struct qedr_cq *cq, int num_entries, 438262306a36Sopenharmony_ci struct ib_wc *wc, struct rdma_cqe_responder *resp, 438362306a36Sopenharmony_ci int *update) 438462306a36Sopenharmony_ci{ 438562306a36Sopenharmony_ci int cnt; 438662306a36Sopenharmony_ci 438762306a36Sopenharmony_ci if (resp->status == RDMA_CQE_RESP_STS_WORK_REQUEST_FLUSHED_ERR) { 438862306a36Sopenharmony_ci cnt = process_resp_flush(qp, cq, num_entries, wc, 438962306a36Sopenharmony_ci resp->rq_cons_or_srq_id); 439062306a36Sopenharmony_ci try_consume_resp_cqe(cq, qp, resp, update); 439162306a36Sopenharmony_ci } else { 439262306a36Sopenharmony_ci cnt = process_resp_one(dev, qp, cq, wc, resp); 439362306a36Sopenharmony_ci consume_cqe(cq); 439462306a36Sopenharmony_ci *update |= 1; 439562306a36Sopenharmony_ci } 439662306a36Sopenharmony_ci 439762306a36Sopenharmony_ci return cnt; 439862306a36Sopenharmony_ci} 439962306a36Sopenharmony_ci 440062306a36Sopenharmony_cistatic void try_consume_req_cqe(struct qedr_cq *cq, struct qedr_qp *qp, 440162306a36Sopenharmony_ci struct rdma_cqe_requester *req, int *update) 440262306a36Sopenharmony_ci{ 440362306a36Sopenharmony_ci if (le16_to_cpu(req->sq_cons) == qp->sq.wqe_cons) { 440462306a36Sopenharmony_ci consume_cqe(cq); 440562306a36Sopenharmony_ci *update |= 1; 440662306a36Sopenharmony_ci } 440762306a36Sopenharmony_ci} 440862306a36Sopenharmony_ci 440962306a36Sopenharmony_ciint qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) 441062306a36Sopenharmony_ci{ 441162306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibcq->device); 441262306a36Sopenharmony_ci struct qedr_cq *cq = get_qedr_cq(ibcq); 441362306a36Sopenharmony_ci union rdma_cqe *cqe; 441462306a36Sopenharmony_ci u32 old_cons, new_cons; 441562306a36Sopenharmony_ci unsigned long flags; 441662306a36Sopenharmony_ci int update = 0; 441762306a36Sopenharmony_ci int done = 0; 441862306a36Sopenharmony_ci 441962306a36Sopenharmony_ci if (cq->destroyed) { 442062306a36Sopenharmony_ci DP_ERR(dev, 442162306a36Sopenharmony_ci "warning: poll was invoked after destroy for cq %p (icid=%d)\n", 442262306a36Sopenharmony_ci cq, cq->icid); 442362306a36Sopenharmony_ci return 0; 442462306a36Sopenharmony_ci } 442562306a36Sopenharmony_ci 442662306a36Sopenharmony_ci if (cq->cq_type == QEDR_CQ_TYPE_GSI) 442762306a36Sopenharmony_ci return qedr_gsi_poll_cq(ibcq, num_entries, wc); 442862306a36Sopenharmony_ci 442962306a36Sopenharmony_ci spin_lock_irqsave(&cq->cq_lock, flags); 443062306a36Sopenharmony_ci cqe = cq->latest_cqe; 443162306a36Sopenharmony_ci old_cons = qed_chain_get_cons_idx_u32(&cq->pbl); 443262306a36Sopenharmony_ci while (num_entries && is_valid_cqe(cq, cqe)) { 443362306a36Sopenharmony_ci struct qedr_qp *qp; 443462306a36Sopenharmony_ci int cnt = 0; 443562306a36Sopenharmony_ci 443662306a36Sopenharmony_ci /* prevent speculative reads of any field of CQE */ 443762306a36Sopenharmony_ci rmb(); 443862306a36Sopenharmony_ci 443962306a36Sopenharmony_ci qp = cqe_get_qp(cqe); 444062306a36Sopenharmony_ci if (!qp) { 444162306a36Sopenharmony_ci WARN(1, "Error: CQE QP pointer is NULL. CQE=%p\n", cqe); 444262306a36Sopenharmony_ci break; 444362306a36Sopenharmony_ci } 444462306a36Sopenharmony_ci 444562306a36Sopenharmony_ci wc->qp = &qp->ibqp; 444662306a36Sopenharmony_ci 444762306a36Sopenharmony_ci switch (cqe_get_type(cqe)) { 444862306a36Sopenharmony_ci case RDMA_CQE_TYPE_REQUESTER: 444962306a36Sopenharmony_ci cnt = qedr_poll_cq_req(dev, qp, cq, num_entries, wc, 445062306a36Sopenharmony_ci &cqe->req); 445162306a36Sopenharmony_ci try_consume_req_cqe(cq, qp, &cqe->req, &update); 445262306a36Sopenharmony_ci break; 445362306a36Sopenharmony_ci case RDMA_CQE_TYPE_RESPONDER_RQ: 445462306a36Sopenharmony_ci cnt = qedr_poll_cq_resp(dev, qp, cq, num_entries, wc, 445562306a36Sopenharmony_ci &cqe->resp, &update); 445662306a36Sopenharmony_ci break; 445762306a36Sopenharmony_ci case RDMA_CQE_TYPE_RESPONDER_SRQ: 445862306a36Sopenharmony_ci cnt = qedr_poll_cq_resp_srq(dev, qp, cq, num_entries, 445962306a36Sopenharmony_ci wc, &cqe->resp); 446062306a36Sopenharmony_ci update = 1; 446162306a36Sopenharmony_ci break; 446262306a36Sopenharmony_ci case RDMA_CQE_TYPE_INVALID: 446362306a36Sopenharmony_ci default: 446462306a36Sopenharmony_ci DP_ERR(dev, "Error: invalid CQE type = %d\n", 446562306a36Sopenharmony_ci cqe_get_type(cqe)); 446662306a36Sopenharmony_ci } 446762306a36Sopenharmony_ci num_entries -= cnt; 446862306a36Sopenharmony_ci wc += cnt; 446962306a36Sopenharmony_ci done += cnt; 447062306a36Sopenharmony_ci 447162306a36Sopenharmony_ci cqe = get_cqe(cq); 447262306a36Sopenharmony_ci } 447362306a36Sopenharmony_ci new_cons = qed_chain_get_cons_idx_u32(&cq->pbl); 447462306a36Sopenharmony_ci 447562306a36Sopenharmony_ci cq->cq_cons += new_cons - old_cons; 447662306a36Sopenharmony_ci 447762306a36Sopenharmony_ci if (update) 447862306a36Sopenharmony_ci /* doorbell notifies abount latest VALID entry, 447962306a36Sopenharmony_ci * but chain already point to the next INVALID one 448062306a36Sopenharmony_ci */ 448162306a36Sopenharmony_ci doorbell_cq(cq, cq->cq_cons - 1, cq->arm_flags); 448262306a36Sopenharmony_ci 448362306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->cq_lock, flags); 448462306a36Sopenharmony_ci return done; 448562306a36Sopenharmony_ci} 448662306a36Sopenharmony_ci 448762306a36Sopenharmony_ciint qedr_process_mad(struct ib_device *ibdev, int process_mad_flags, 448862306a36Sopenharmony_ci u32 port_num, const struct ib_wc *in_wc, 448962306a36Sopenharmony_ci const struct ib_grh *in_grh, const struct ib_mad *in, 449062306a36Sopenharmony_ci struct ib_mad *out_mad, size_t *out_mad_size, 449162306a36Sopenharmony_ci u16 *out_mad_pkey_index) 449262306a36Sopenharmony_ci{ 449362306a36Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 449462306a36Sopenharmony_ci} 4495