162306a36Sopenharmony_ci/* This file is part of the Emulex RoCE Device Driver for 262306a36Sopenharmony_ci * RoCE (RDMA over Converged Ethernet) adapters. 362306a36Sopenharmony_ci * Copyright (C) 2012-2015 Emulex. All rights reserved. 462306a36Sopenharmony_ci * EMULEX and SLI are trademarks of Emulex. 562306a36Sopenharmony_ci * www.emulex.com 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This software is available to you under a choice of one of two licenses. 862306a36Sopenharmony_ci * You may choose to be licensed under the terms of the GNU General Public 962306a36Sopenharmony_ci * License (GPL) Version 2, available from the file COPYING in the main 1062306a36Sopenharmony_ci * directory of this source tree, or the BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 1362306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 1462306a36Sopenharmony_ci * are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above copyright notice, 1762306a36Sopenharmony_ci * this list of conditions and the following disclaimer. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above copyright 2062306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 2162306a36Sopenharmony_ci * the documentation and/or other materials provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2462306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE 2562306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2662306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2762306a36Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2862306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2962306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 3062306a36Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 3162306a36Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3262306a36Sopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 3362306a36Sopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * Contact Information: 3662306a36Sopenharmony_ci * linux-drivers@emulex.com 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * Emulex 3962306a36Sopenharmony_ci * 3333 Susan Street 4062306a36Sopenharmony_ci * Costa Mesa, CA 92626 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <linux/dma-mapping.h> 4462306a36Sopenharmony_ci#include <net/addrconf.h> 4562306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 4662306a36Sopenharmony_ci#include <rdma/ib_user_verbs.h> 4762306a36Sopenharmony_ci#include <rdma/iw_cm.h> 4862306a36Sopenharmony_ci#include <rdma/ib_umem.h> 4962306a36Sopenharmony_ci#include <rdma/ib_addr.h> 5062306a36Sopenharmony_ci#include <rdma/ib_cache.h> 5162306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#include "ocrdma.h" 5462306a36Sopenharmony_ci#include "ocrdma_hw.h" 5562306a36Sopenharmony_ci#include "ocrdma_verbs.h" 5662306a36Sopenharmony_ci#include <rdma/ocrdma-abi.h> 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ciint ocrdma_query_pkey(struct ib_device *ibdev, u32 port, u16 index, u16 *pkey) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci if (index > 0) 6162306a36Sopenharmony_ci return -EINVAL; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci *pkey = 0xffff; 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciint ocrdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr, 6862306a36Sopenharmony_ci struct ib_udata *uhw) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibdev); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (uhw->inlen || uhw->outlen) 7362306a36Sopenharmony_ci return -EINVAL; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci memset(attr, 0, sizeof *attr); 7662306a36Sopenharmony_ci memcpy(&attr->fw_ver, &dev->attr.fw_ver[0], 7762306a36Sopenharmony_ci min(sizeof(dev->attr.fw_ver), sizeof(attr->fw_ver))); 7862306a36Sopenharmony_ci addrconf_addr_eui48((u8 *)&attr->sys_image_guid, 7962306a36Sopenharmony_ci dev->nic_info.mac_addr); 8062306a36Sopenharmony_ci attr->max_mr_size = dev->attr.max_mr_size; 8162306a36Sopenharmony_ci attr->page_size_cap = 0xffff000; 8262306a36Sopenharmony_ci attr->vendor_id = dev->nic_info.pdev->vendor; 8362306a36Sopenharmony_ci attr->vendor_part_id = dev->nic_info.pdev->device; 8462306a36Sopenharmony_ci attr->hw_ver = dev->asic_id; 8562306a36Sopenharmony_ci attr->max_qp = dev->attr.max_qp; 8662306a36Sopenharmony_ci attr->max_ah = OCRDMA_MAX_AH; 8762306a36Sopenharmony_ci attr->max_qp_wr = dev->attr.max_wqe; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci attr->device_cap_flags = IB_DEVICE_CURR_QP_STATE_MOD | 9062306a36Sopenharmony_ci IB_DEVICE_RC_RNR_NAK_GEN | 9162306a36Sopenharmony_ci IB_DEVICE_SHUTDOWN_PORT | 9262306a36Sopenharmony_ci IB_DEVICE_SYS_IMAGE_GUID | 9362306a36Sopenharmony_ci IB_DEVICE_MEM_MGT_EXTENSIONS; 9462306a36Sopenharmony_ci attr->kernel_cap_flags = IBK_LOCAL_DMA_LKEY; 9562306a36Sopenharmony_ci attr->max_send_sge = dev->attr.max_send_sge; 9662306a36Sopenharmony_ci attr->max_recv_sge = dev->attr.max_recv_sge; 9762306a36Sopenharmony_ci attr->max_sge_rd = dev->attr.max_rdma_sge; 9862306a36Sopenharmony_ci attr->max_cq = dev->attr.max_cq; 9962306a36Sopenharmony_ci attr->max_cqe = dev->attr.max_cqe; 10062306a36Sopenharmony_ci attr->max_mr = dev->attr.max_mr; 10162306a36Sopenharmony_ci attr->max_mw = dev->attr.max_mw; 10262306a36Sopenharmony_ci attr->max_pd = dev->attr.max_pd; 10362306a36Sopenharmony_ci attr->atomic_cap = 0; 10462306a36Sopenharmony_ci attr->max_qp_rd_atom = 10562306a36Sopenharmony_ci min(dev->attr.max_ord_per_qp, dev->attr.max_ird_per_qp); 10662306a36Sopenharmony_ci attr->max_qp_init_rd_atom = dev->attr.max_ord_per_qp; 10762306a36Sopenharmony_ci attr->max_srq = dev->attr.max_srq; 10862306a36Sopenharmony_ci attr->max_srq_sge = dev->attr.max_srq_sge; 10962306a36Sopenharmony_ci attr->max_srq_wr = dev->attr.max_rqe; 11062306a36Sopenharmony_ci attr->local_ca_ack_delay = dev->attr.local_ca_ack_delay; 11162306a36Sopenharmony_ci attr->max_fast_reg_page_list_len = dev->attr.max_pages_per_frmr; 11262306a36Sopenharmony_ci attr->max_pkeys = 1; 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic inline void get_link_speed_and_width(struct ocrdma_dev *dev, 11762306a36Sopenharmony_ci u16 *ib_speed, u8 *ib_width) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci int status; 12062306a36Sopenharmony_ci u8 speed; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci status = ocrdma_mbx_get_link_speed(dev, &speed, NULL); 12362306a36Sopenharmony_ci if (status) 12462306a36Sopenharmony_ci speed = OCRDMA_PHYS_LINK_SPEED_ZERO; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci switch (speed) { 12762306a36Sopenharmony_ci case OCRDMA_PHYS_LINK_SPEED_1GBPS: 12862306a36Sopenharmony_ci *ib_speed = IB_SPEED_SDR; 12962306a36Sopenharmony_ci *ib_width = IB_WIDTH_1X; 13062306a36Sopenharmony_ci break; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci case OCRDMA_PHYS_LINK_SPEED_10GBPS: 13362306a36Sopenharmony_ci *ib_speed = IB_SPEED_QDR; 13462306a36Sopenharmony_ci *ib_width = IB_WIDTH_1X; 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci case OCRDMA_PHYS_LINK_SPEED_20GBPS: 13862306a36Sopenharmony_ci *ib_speed = IB_SPEED_DDR; 13962306a36Sopenharmony_ci *ib_width = IB_WIDTH_4X; 14062306a36Sopenharmony_ci break; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci case OCRDMA_PHYS_LINK_SPEED_40GBPS: 14362306a36Sopenharmony_ci *ib_speed = IB_SPEED_QDR; 14462306a36Sopenharmony_ci *ib_width = IB_WIDTH_4X; 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci default: 14862306a36Sopenharmony_ci /* Unsupported */ 14962306a36Sopenharmony_ci *ib_speed = IB_SPEED_SDR; 15062306a36Sopenharmony_ci *ib_width = IB_WIDTH_1X; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ciint ocrdma_query_port(struct ib_device *ibdev, 15562306a36Sopenharmony_ci u32 port, struct ib_port_attr *props) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci enum ib_port_state port_state; 15862306a36Sopenharmony_ci struct ocrdma_dev *dev; 15962306a36Sopenharmony_ci struct net_device *netdev; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* props being zeroed by the caller, avoid zeroing it here */ 16262306a36Sopenharmony_ci dev = get_ocrdma_dev(ibdev); 16362306a36Sopenharmony_ci netdev = dev->nic_info.netdev; 16462306a36Sopenharmony_ci if (netif_running(netdev) && netif_oper_up(netdev)) { 16562306a36Sopenharmony_ci port_state = IB_PORT_ACTIVE; 16662306a36Sopenharmony_ci props->phys_state = IB_PORT_PHYS_STATE_LINK_UP; 16762306a36Sopenharmony_ci } else { 16862306a36Sopenharmony_ci port_state = IB_PORT_DOWN; 16962306a36Sopenharmony_ci props->phys_state = IB_PORT_PHYS_STATE_DISABLED; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci props->max_mtu = IB_MTU_4096; 17262306a36Sopenharmony_ci props->active_mtu = iboe_get_mtu(netdev->mtu); 17362306a36Sopenharmony_ci props->lid = 0; 17462306a36Sopenharmony_ci props->lmc = 0; 17562306a36Sopenharmony_ci props->sm_lid = 0; 17662306a36Sopenharmony_ci props->sm_sl = 0; 17762306a36Sopenharmony_ci props->state = port_state; 17862306a36Sopenharmony_ci props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_REINIT_SUP | 17962306a36Sopenharmony_ci IB_PORT_DEVICE_MGMT_SUP | 18062306a36Sopenharmony_ci IB_PORT_VENDOR_CLASS_SUP; 18162306a36Sopenharmony_ci props->ip_gids = true; 18262306a36Sopenharmony_ci props->gid_tbl_len = OCRDMA_MAX_SGID; 18362306a36Sopenharmony_ci props->pkey_tbl_len = 1; 18462306a36Sopenharmony_ci props->bad_pkey_cntr = 0; 18562306a36Sopenharmony_ci props->qkey_viol_cntr = 0; 18662306a36Sopenharmony_ci get_link_speed_and_width(dev, &props->active_speed, 18762306a36Sopenharmony_ci &props->active_width); 18862306a36Sopenharmony_ci props->max_msg_sz = 0x80000000; 18962306a36Sopenharmony_ci props->max_vl_num = 4; 19062306a36Sopenharmony_ci return 0; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic int ocrdma_add_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr, 19462306a36Sopenharmony_ci unsigned long len) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct ocrdma_mm *mm; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci mm = kzalloc(sizeof(*mm), GFP_KERNEL); 19962306a36Sopenharmony_ci if (mm == NULL) 20062306a36Sopenharmony_ci return -ENOMEM; 20162306a36Sopenharmony_ci mm->key.phy_addr = phy_addr; 20262306a36Sopenharmony_ci mm->key.len = len; 20362306a36Sopenharmony_ci INIT_LIST_HEAD(&mm->entry); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci mutex_lock(&uctx->mm_list_lock); 20662306a36Sopenharmony_ci list_add_tail(&mm->entry, &uctx->mm_head); 20762306a36Sopenharmony_ci mutex_unlock(&uctx->mm_list_lock); 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void ocrdma_del_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr, 21262306a36Sopenharmony_ci unsigned long len) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct ocrdma_mm *mm, *tmp; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci mutex_lock(&uctx->mm_list_lock); 21762306a36Sopenharmony_ci list_for_each_entry_safe(mm, tmp, &uctx->mm_head, entry) { 21862306a36Sopenharmony_ci if (len != mm->key.len && phy_addr != mm->key.phy_addr) 21962306a36Sopenharmony_ci continue; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci list_del(&mm->entry); 22262306a36Sopenharmony_ci kfree(mm); 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci mutex_unlock(&uctx->mm_list_lock); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic bool ocrdma_search_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr, 22962306a36Sopenharmony_ci unsigned long len) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci bool found = false; 23262306a36Sopenharmony_ci struct ocrdma_mm *mm; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci mutex_lock(&uctx->mm_list_lock); 23562306a36Sopenharmony_ci list_for_each_entry(mm, &uctx->mm_head, entry) { 23662306a36Sopenharmony_ci if (len != mm->key.len && phy_addr != mm->key.phy_addr) 23762306a36Sopenharmony_ci continue; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci found = true; 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci mutex_unlock(&uctx->mm_list_lock); 24362306a36Sopenharmony_ci return found; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic u16 _ocrdma_pd_mgr_get_bitmap(struct ocrdma_dev *dev, bool dpp_pool) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci u16 pd_bitmap_idx = 0; 25062306a36Sopenharmony_ci unsigned long *pd_bitmap; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (dpp_pool) { 25362306a36Sopenharmony_ci pd_bitmap = dev->pd_mgr->pd_dpp_bitmap; 25462306a36Sopenharmony_ci pd_bitmap_idx = find_first_zero_bit(pd_bitmap, 25562306a36Sopenharmony_ci dev->pd_mgr->max_dpp_pd); 25662306a36Sopenharmony_ci __set_bit(pd_bitmap_idx, pd_bitmap); 25762306a36Sopenharmony_ci dev->pd_mgr->pd_dpp_count++; 25862306a36Sopenharmony_ci if (dev->pd_mgr->pd_dpp_count > dev->pd_mgr->pd_dpp_thrsh) 25962306a36Sopenharmony_ci dev->pd_mgr->pd_dpp_thrsh = dev->pd_mgr->pd_dpp_count; 26062306a36Sopenharmony_ci } else { 26162306a36Sopenharmony_ci pd_bitmap = dev->pd_mgr->pd_norm_bitmap; 26262306a36Sopenharmony_ci pd_bitmap_idx = find_first_zero_bit(pd_bitmap, 26362306a36Sopenharmony_ci dev->pd_mgr->max_normal_pd); 26462306a36Sopenharmony_ci __set_bit(pd_bitmap_idx, pd_bitmap); 26562306a36Sopenharmony_ci dev->pd_mgr->pd_norm_count++; 26662306a36Sopenharmony_ci if (dev->pd_mgr->pd_norm_count > dev->pd_mgr->pd_norm_thrsh) 26762306a36Sopenharmony_ci dev->pd_mgr->pd_norm_thrsh = dev->pd_mgr->pd_norm_count; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci return pd_bitmap_idx; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int _ocrdma_pd_mgr_put_bitmap(struct ocrdma_dev *dev, u16 pd_id, 27362306a36Sopenharmony_ci bool dpp_pool) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci u16 pd_count; 27662306a36Sopenharmony_ci u16 pd_bit_index; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci pd_count = dpp_pool ? dev->pd_mgr->pd_dpp_count : 27962306a36Sopenharmony_ci dev->pd_mgr->pd_norm_count; 28062306a36Sopenharmony_ci if (pd_count == 0) 28162306a36Sopenharmony_ci return -EINVAL; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (dpp_pool) { 28462306a36Sopenharmony_ci pd_bit_index = pd_id - dev->pd_mgr->pd_dpp_start; 28562306a36Sopenharmony_ci if (pd_bit_index >= dev->pd_mgr->max_dpp_pd) { 28662306a36Sopenharmony_ci return -EINVAL; 28762306a36Sopenharmony_ci } else { 28862306a36Sopenharmony_ci __clear_bit(pd_bit_index, dev->pd_mgr->pd_dpp_bitmap); 28962306a36Sopenharmony_ci dev->pd_mgr->pd_dpp_count--; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci } else { 29262306a36Sopenharmony_ci pd_bit_index = pd_id - dev->pd_mgr->pd_norm_start; 29362306a36Sopenharmony_ci if (pd_bit_index >= dev->pd_mgr->max_normal_pd) { 29462306a36Sopenharmony_ci return -EINVAL; 29562306a36Sopenharmony_ci } else { 29662306a36Sopenharmony_ci __clear_bit(pd_bit_index, dev->pd_mgr->pd_norm_bitmap); 29762306a36Sopenharmony_ci dev->pd_mgr->pd_norm_count--; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci return 0; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic int ocrdma_put_pd_num(struct ocrdma_dev *dev, u16 pd_id, 30562306a36Sopenharmony_ci bool dpp_pool) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci int status; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci mutex_lock(&dev->dev_lock); 31062306a36Sopenharmony_ci status = _ocrdma_pd_mgr_put_bitmap(dev, pd_id, dpp_pool); 31162306a36Sopenharmony_ci mutex_unlock(&dev->dev_lock); 31262306a36Sopenharmony_ci return status; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic int ocrdma_get_pd_num(struct ocrdma_dev *dev, struct ocrdma_pd *pd) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci u16 pd_idx = 0; 31862306a36Sopenharmony_ci int status = 0; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci mutex_lock(&dev->dev_lock); 32162306a36Sopenharmony_ci if (pd->dpp_enabled) { 32262306a36Sopenharmony_ci /* try allocating DPP PD, if not available then normal PD */ 32362306a36Sopenharmony_ci if (dev->pd_mgr->pd_dpp_count < dev->pd_mgr->max_dpp_pd) { 32462306a36Sopenharmony_ci pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, true); 32562306a36Sopenharmony_ci pd->id = dev->pd_mgr->pd_dpp_start + pd_idx; 32662306a36Sopenharmony_ci pd->dpp_page = dev->pd_mgr->dpp_page_index + pd_idx; 32762306a36Sopenharmony_ci } else if (dev->pd_mgr->pd_norm_count < 32862306a36Sopenharmony_ci dev->pd_mgr->max_normal_pd) { 32962306a36Sopenharmony_ci pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, false); 33062306a36Sopenharmony_ci pd->id = dev->pd_mgr->pd_norm_start + pd_idx; 33162306a36Sopenharmony_ci pd->dpp_enabled = false; 33262306a36Sopenharmony_ci } else { 33362306a36Sopenharmony_ci status = -EINVAL; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci } else { 33662306a36Sopenharmony_ci if (dev->pd_mgr->pd_norm_count < dev->pd_mgr->max_normal_pd) { 33762306a36Sopenharmony_ci pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, false); 33862306a36Sopenharmony_ci pd->id = dev->pd_mgr->pd_norm_start + pd_idx; 33962306a36Sopenharmony_ci } else { 34062306a36Sopenharmony_ci status = -EINVAL; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci mutex_unlock(&dev->dev_lock); 34462306a36Sopenharmony_ci return status; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/* 34862306a36Sopenharmony_ci * NOTE: 34962306a36Sopenharmony_ci * 35062306a36Sopenharmony_ci * ocrdma_ucontext must be used here because this function is also 35162306a36Sopenharmony_ci * called from ocrdma_alloc_ucontext where ib_udata does not have 35262306a36Sopenharmony_ci * valid ib_ucontext pointer. ib_uverbs_get_context does not call 35362306a36Sopenharmony_ci * uobj_{alloc|get_xxx} helpers which are used to store the 35462306a36Sopenharmony_ci * ib_ucontext in uverbs_attr_bundle wrapping the ib_udata. so 35562306a36Sopenharmony_ci * ib_udata does NOT imply valid ib_ucontext here! 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_cistatic int _ocrdma_alloc_pd(struct ocrdma_dev *dev, struct ocrdma_pd *pd, 35862306a36Sopenharmony_ci struct ocrdma_ucontext *uctx, 35962306a36Sopenharmony_ci struct ib_udata *udata) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci int status; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (udata && uctx && dev->attr.max_dpp_pds) { 36462306a36Sopenharmony_ci pd->dpp_enabled = 36562306a36Sopenharmony_ci ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R; 36662306a36Sopenharmony_ci pd->num_dpp_qp = 36762306a36Sopenharmony_ci pd->dpp_enabled ? (dev->nic_info.db_page_size / 36862306a36Sopenharmony_ci dev->attr.wqe_size) : 0; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (dev->pd_mgr->pd_prealloc_valid) 37262306a36Sopenharmony_ci return ocrdma_get_pd_num(dev, pd); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ciretry: 37562306a36Sopenharmony_ci status = ocrdma_mbx_alloc_pd(dev, pd); 37662306a36Sopenharmony_ci if (status) { 37762306a36Sopenharmony_ci if (pd->dpp_enabled) { 37862306a36Sopenharmony_ci pd->dpp_enabled = false; 37962306a36Sopenharmony_ci pd->num_dpp_qp = 0; 38062306a36Sopenharmony_ci goto retry; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci return status; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return 0; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic inline int is_ucontext_pd(struct ocrdma_ucontext *uctx, 38962306a36Sopenharmony_ci struct ocrdma_pd *pd) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci return (uctx->cntxt_pd == pd); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic void _ocrdma_dealloc_pd(struct ocrdma_dev *dev, 39562306a36Sopenharmony_ci struct ocrdma_pd *pd) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci if (dev->pd_mgr->pd_prealloc_valid) 39862306a36Sopenharmony_ci ocrdma_put_pd_num(dev, pd->id, pd->dpp_enabled); 39962306a36Sopenharmony_ci else 40062306a36Sopenharmony_ci ocrdma_mbx_dealloc_pd(dev, pd); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic int ocrdma_alloc_ucontext_pd(struct ocrdma_dev *dev, 40462306a36Sopenharmony_ci struct ocrdma_ucontext *uctx, 40562306a36Sopenharmony_ci struct ib_udata *udata) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct ib_device *ibdev = &dev->ibdev; 40862306a36Sopenharmony_ci struct ib_pd *pd; 40962306a36Sopenharmony_ci int status; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci pd = rdma_zalloc_drv_obj(ibdev, ib_pd); 41262306a36Sopenharmony_ci if (!pd) 41362306a36Sopenharmony_ci return -ENOMEM; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci pd->device = ibdev; 41662306a36Sopenharmony_ci uctx->cntxt_pd = get_ocrdma_pd(pd); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci status = _ocrdma_alloc_pd(dev, uctx->cntxt_pd, uctx, udata); 41962306a36Sopenharmony_ci if (status) { 42062306a36Sopenharmony_ci kfree(uctx->cntxt_pd); 42162306a36Sopenharmony_ci goto err; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci uctx->cntxt_pd->uctx = uctx; 42562306a36Sopenharmony_ci uctx->cntxt_pd->ibpd.device = &dev->ibdev; 42662306a36Sopenharmony_cierr: 42762306a36Sopenharmony_ci return status; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic void ocrdma_dealloc_ucontext_pd(struct ocrdma_ucontext *uctx) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct ocrdma_pd *pd = uctx->cntxt_pd; 43362306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (uctx->pd_in_use) { 43662306a36Sopenharmony_ci pr_err("%s(%d) Freeing in use pdid=0x%x.\n", 43762306a36Sopenharmony_ci __func__, dev->id, pd->id); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci uctx->cntxt_pd = NULL; 44062306a36Sopenharmony_ci _ocrdma_dealloc_pd(dev, pd); 44162306a36Sopenharmony_ci kfree(pd); 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic struct ocrdma_pd *ocrdma_get_ucontext_pd(struct ocrdma_ucontext *uctx) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct ocrdma_pd *pd = NULL; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci mutex_lock(&uctx->mm_list_lock); 44962306a36Sopenharmony_ci if (!uctx->pd_in_use) { 45062306a36Sopenharmony_ci uctx->pd_in_use = true; 45162306a36Sopenharmony_ci pd = uctx->cntxt_pd; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci mutex_unlock(&uctx->mm_list_lock); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci return pd; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic void ocrdma_release_ucontext_pd(struct ocrdma_ucontext *uctx) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci mutex_lock(&uctx->mm_list_lock); 46162306a36Sopenharmony_ci uctx->pd_in_use = false; 46262306a36Sopenharmony_ci mutex_unlock(&uctx->mm_list_lock); 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ciint ocrdma_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct ib_device *ibdev = uctx->device; 46862306a36Sopenharmony_ci int status; 46962306a36Sopenharmony_ci struct ocrdma_ucontext *ctx = get_ocrdma_ucontext(uctx); 47062306a36Sopenharmony_ci struct ocrdma_alloc_ucontext_resp resp = {}; 47162306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibdev); 47262306a36Sopenharmony_ci struct pci_dev *pdev = dev->nic_info.pdev; 47362306a36Sopenharmony_ci u32 map_len = roundup(sizeof(u32) * 2048, PAGE_SIZE); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (!udata) 47662306a36Sopenharmony_ci return -EFAULT; 47762306a36Sopenharmony_ci INIT_LIST_HEAD(&ctx->mm_head); 47862306a36Sopenharmony_ci mutex_init(&ctx->mm_list_lock); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci ctx->ah_tbl.va = dma_alloc_coherent(&pdev->dev, map_len, 48162306a36Sopenharmony_ci &ctx->ah_tbl.pa, GFP_KERNEL); 48262306a36Sopenharmony_ci if (!ctx->ah_tbl.va) 48362306a36Sopenharmony_ci return -ENOMEM; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci ctx->ah_tbl.len = map_len; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci resp.ah_tbl_len = ctx->ah_tbl.len; 48862306a36Sopenharmony_ci resp.ah_tbl_page = virt_to_phys(ctx->ah_tbl.va); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci status = ocrdma_add_mmap(ctx, resp.ah_tbl_page, resp.ah_tbl_len); 49162306a36Sopenharmony_ci if (status) 49262306a36Sopenharmony_ci goto map_err; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci status = ocrdma_alloc_ucontext_pd(dev, ctx, udata); 49562306a36Sopenharmony_ci if (status) 49662306a36Sopenharmony_ci goto pd_err; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci resp.dev_id = dev->id; 49962306a36Sopenharmony_ci resp.max_inline_data = dev->attr.max_inline_data; 50062306a36Sopenharmony_ci resp.wqe_size = dev->attr.wqe_size; 50162306a36Sopenharmony_ci resp.rqe_size = dev->attr.rqe_size; 50262306a36Sopenharmony_ci resp.dpp_wqe_size = dev->attr.wqe_size; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci memcpy(resp.fw_ver, dev->attr.fw_ver, sizeof(resp.fw_ver)); 50562306a36Sopenharmony_ci status = ib_copy_to_udata(udata, &resp, sizeof(resp)); 50662306a36Sopenharmony_ci if (status) 50762306a36Sopenharmony_ci goto cpy_err; 50862306a36Sopenharmony_ci return 0; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cicpy_err: 51162306a36Sopenharmony_ci ocrdma_dealloc_ucontext_pd(ctx); 51262306a36Sopenharmony_cipd_err: 51362306a36Sopenharmony_ci ocrdma_del_mmap(ctx, ctx->ah_tbl.pa, ctx->ah_tbl.len); 51462306a36Sopenharmony_cimap_err: 51562306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, ctx->ah_tbl.len, ctx->ah_tbl.va, 51662306a36Sopenharmony_ci ctx->ah_tbl.pa); 51762306a36Sopenharmony_ci return status; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_civoid ocrdma_dealloc_ucontext(struct ib_ucontext *ibctx) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct ocrdma_mm *mm, *tmp; 52362306a36Sopenharmony_ci struct ocrdma_ucontext *uctx = get_ocrdma_ucontext(ibctx); 52462306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibctx->device); 52562306a36Sopenharmony_ci struct pci_dev *pdev = dev->nic_info.pdev; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci ocrdma_dealloc_ucontext_pd(uctx); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci ocrdma_del_mmap(uctx, uctx->ah_tbl.pa, uctx->ah_tbl.len); 53062306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, uctx->ah_tbl.len, uctx->ah_tbl.va, 53162306a36Sopenharmony_ci uctx->ah_tbl.pa); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci list_for_each_entry_safe(mm, tmp, &uctx->mm_head, entry) { 53462306a36Sopenharmony_ci list_del(&mm->entry); 53562306a36Sopenharmony_ci kfree(mm); 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ciint ocrdma_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci struct ocrdma_ucontext *ucontext = get_ocrdma_ucontext(context); 54262306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(context->device); 54362306a36Sopenharmony_ci unsigned long vm_page = vma->vm_pgoff << PAGE_SHIFT; 54462306a36Sopenharmony_ci u64 unmapped_db = (u64) dev->nic_info.unmapped_db; 54562306a36Sopenharmony_ci unsigned long len = (vma->vm_end - vma->vm_start); 54662306a36Sopenharmony_ci int status; 54762306a36Sopenharmony_ci bool found; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (vma->vm_start & (PAGE_SIZE - 1)) 55062306a36Sopenharmony_ci return -EINVAL; 55162306a36Sopenharmony_ci found = ocrdma_search_mmap(ucontext, vma->vm_pgoff << PAGE_SHIFT, len); 55262306a36Sopenharmony_ci if (!found) 55362306a36Sopenharmony_ci return -EINVAL; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if ((vm_page >= unmapped_db) && (vm_page <= (unmapped_db + 55662306a36Sopenharmony_ci dev->nic_info.db_total_size)) && 55762306a36Sopenharmony_ci (len <= dev->nic_info.db_page_size)) { 55862306a36Sopenharmony_ci if (vma->vm_flags & VM_READ) 55962306a36Sopenharmony_ci return -EPERM; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 56262306a36Sopenharmony_ci status = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, 56362306a36Sopenharmony_ci len, vma->vm_page_prot); 56462306a36Sopenharmony_ci } else if (dev->nic_info.dpp_unmapped_len && 56562306a36Sopenharmony_ci (vm_page >= (u64) dev->nic_info.dpp_unmapped_addr) && 56662306a36Sopenharmony_ci (vm_page <= (u64) (dev->nic_info.dpp_unmapped_addr + 56762306a36Sopenharmony_ci dev->nic_info.dpp_unmapped_len)) && 56862306a36Sopenharmony_ci (len <= dev->nic_info.dpp_unmapped_len)) { 56962306a36Sopenharmony_ci if (vma->vm_flags & VM_READ) 57062306a36Sopenharmony_ci return -EPERM; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 57362306a36Sopenharmony_ci status = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, 57462306a36Sopenharmony_ci len, vma->vm_page_prot); 57562306a36Sopenharmony_ci } else { 57662306a36Sopenharmony_ci status = remap_pfn_range(vma, vma->vm_start, 57762306a36Sopenharmony_ci vma->vm_pgoff, len, vma->vm_page_prot); 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci return status; 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic int ocrdma_copy_pd_uresp(struct ocrdma_dev *dev, struct ocrdma_pd *pd, 58362306a36Sopenharmony_ci struct ib_udata *udata) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci int status; 58662306a36Sopenharmony_ci u64 db_page_addr; 58762306a36Sopenharmony_ci u64 dpp_page_addr = 0; 58862306a36Sopenharmony_ci u32 db_page_size; 58962306a36Sopenharmony_ci struct ocrdma_alloc_pd_uresp rsp; 59062306a36Sopenharmony_ci struct ocrdma_ucontext *uctx = rdma_udata_to_drv_context( 59162306a36Sopenharmony_ci udata, struct ocrdma_ucontext, ibucontext); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci memset(&rsp, 0, sizeof(rsp)); 59462306a36Sopenharmony_ci rsp.id = pd->id; 59562306a36Sopenharmony_ci rsp.dpp_enabled = pd->dpp_enabled; 59662306a36Sopenharmony_ci db_page_addr = ocrdma_get_db_addr(dev, pd->id); 59762306a36Sopenharmony_ci db_page_size = dev->nic_info.db_page_size; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci status = ocrdma_add_mmap(uctx, db_page_addr, db_page_size); 60062306a36Sopenharmony_ci if (status) 60162306a36Sopenharmony_ci return status; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (pd->dpp_enabled) { 60462306a36Sopenharmony_ci dpp_page_addr = dev->nic_info.dpp_unmapped_addr + 60562306a36Sopenharmony_ci (pd->id * PAGE_SIZE); 60662306a36Sopenharmony_ci status = ocrdma_add_mmap(uctx, dpp_page_addr, 60762306a36Sopenharmony_ci PAGE_SIZE); 60862306a36Sopenharmony_ci if (status) 60962306a36Sopenharmony_ci goto dpp_map_err; 61062306a36Sopenharmony_ci rsp.dpp_page_addr_hi = upper_32_bits(dpp_page_addr); 61162306a36Sopenharmony_ci rsp.dpp_page_addr_lo = dpp_page_addr; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci status = ib_copy_to_udata(udata, &rsp, sizeof(rsp)); 61562306a36Sopenharmony_ci if (status) 61662306a36Sopenharmony_ci goto ucopy_err; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci pd->uctx = uctx; 61962306a36Sopenharmony_ci return 0; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ciucopy_err: 62262306a36Sopenharmony_ci if (pd->dpp_enabled) 62362306a36Sopenharmony_ci ocrdma_del_mmap(pd->uctx, dpp_page_addr, PAGE_SIZE); 62462306a36Sopenharmony_cidpp_map_err: 62562306a36Sopenharmony_ci ocrdma_del_mmap(pd->uctx, db_page_addr, db_page_size); 62662306a36Sopenharmony_ci return status; 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ciint ocrdma_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci struct ib_device *ibdev = ibpd->device; 63262306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibdev); 63362306a36Sopenharmony_ci struct ocrdma_pd *pd; 63462306a36Sopenharmony_ci int status; 63562306a36Sopenharmony_ci u8 is_uctx_pd = false; 63662306a36Sopenharmony_ci struct ocrdma_ucontext *uctx = rdma_udata_to_drv_context( 63762306a36Sopenharmony_ci udata, struct ocrdma_ucontext, ibucontext); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci if (udata) { 64062306a36Sopenharmony_ci pd = ocrdma_get_ucontext_pd(uctx); 64162306a36Sopenharmony_ci if (pd) { 64262306a36Sopenharmony_ci is_uctx_pd = true; 64362306a36Sopenharmony_ci goto pd_mapping; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci pd = get_ocrdma_pd(ibpd); 64862306a36Sopenharmony_ci status = _ocrdma_alloc_pd(dev, pd, uctx, udata); 64962306a36Sopenharmony_ci if (status) 65062306a36Sopenharmony_ci goto exit; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cipd_mapping: 65362306a36Sopenharmony_ci if (udata) { 65462306a36Sopenharmony_ci status = ocrdma_copy_pd_uresp(dev, pd, udata); 65562306a36Sopenharmony_ci if (status) 65662306a36Sopenharmony_ci goto err; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci return 0; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cierr: 66162306a36Sopenharmony_ci if (is_uctx_pd) 66262306a36Sopenharmony_ci ocrdma_release_ucontext_pd(uctx); 66362306a36Sopenharmony_ci else 66462306a36Sopenharmony_ci _ocrdma_dealloc_pd(dev, pd); 66562306a36Sopenharmony_ciexit: 66662306a36Sopenharmony_ci return status; 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ciint ocrdma_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct ocrdma_pd *pd = get_ocrdma_pd(ibpd); 67262306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibpd->device); 67362306a36Sopenharmony_ci struct ocrdma_ucontext *uctx = NULL; 67462306a36Sopenharmony_ci u64 usr_db; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci uctx = pd->uctx; 67762306a36Sopenharmony_ci if (uctx) { 67862306a36Sopenharmony_ci u64 dpp_db = dev->nic_info.dpp_unmapped_addr + 67962306a36Sopenharmony_ci (pd->id * PAGE_SIZE); 68062306a36Sopenharmony_ci if (pd->dpp_enabled) 68162306a36Sopenharmony_ci ocrdma_del_mmap(pd->uctx, dpp_db, PAGE_SIZE); 68262306a36Sopenharmony_ci usr_db = ocrdma_get_db_addr(dev, pd->id); 68362306a36Sopenharmony_ci ocrdma_del_mmap(pd->uctx, usr_db, dev->nic_info.db_page_size); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (is_ucontext_pd(uctx, pd)) { 68662306a36Sopenharmony_ci ocrdma_release_ucontext_pd(uctx); 68762306a36Sopenharmony_ci return 0; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci _ocrdma_dealloc_pd(dev, pd); 69162306a36Sopenharmony_ci return 0; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int ocrdma_alloc_lkey(struct ocrdma_dev *dev, struct ocrdma_mr *mr, 69562306a36Sopenharmony_ci u32 pdid, int acc, u32 num_pbls, u32 addr_check) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci int status; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci mr->hwmr.fr_mr = 0; 70062306a36Sopenharmony_ci mr->hwmr.local_rd = 1; 70162306a36Sopenharmony_ci mr->hwmr.remote_rd = (acc & IB_ACCESS_REMOTE_READ) ? 1 : 0; 70262306a36Sopenharmony_ci mr->hwmr.remote_wr = (acc & IB_ACCESS_REMOTE_WRITE) ? 1 : 0; 70362306a36Sopenharmony_ci mr->hwmr.local_wr = (acc & IB_ACCESS_LOCAL_WRITE) ? 1 : 0; 70462306a36Sopenharmony_ci mr->hwmr.mw_bind = (acc & IB_ACCESS_MW_BIND) ? 1 : 0; 70562306a36Sopenharmony_ci mr->hwmr.remote_atomic = (acc & IB_ACCESS_REMOTE_ATOMIC) ? 1 : 0; 70662306a36Sopenharmony_ci mr->hwmr.num_pbls = num_pbls; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci status = ocrdma_mbx_alloc_lkey(dev, &mr->hwmr, pdid, addr_check); 70962306a36Sopenharmony_ci if (status) 71062306a36Sopenharmony_ci return status; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci mr->ibmr.lkey = mr->hwmr.lkey; 71362306a36Sopenharmony_ci if (mr->hwmr.remote_wr || mr->hwmr.remote_rd) 71462306a36Sopenharmony_ci mr->ibmr.rkey = mr->hwmr.lkey; 71562306a36Sopenharmony_ci return 0; 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistruct ib_mr *ocrdma_get_dma_mr(struct ib_pd *ibpd, int acc) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci int status; 72162306a36Sopenharmony_ci struct ocrdma_mr *mr; 72262306a36Sopenharmony_ci struct ocrdma_pd *pd = get_ocrdma_pd(ibpd); 72362306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibpd->device); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (acc & IB_ACCESS_REMOTE_WRITE && !(acc & IB_ACCESS_LOCAL_WRITE)) { 72662306a36Sopenharmony_ci pr_err("%s err, invalid access rights\n", __func__); 72762306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci mr = kzalloc(sizeof(*mr), GFP_KERNEL); 73162306a36Sopenharmony_ci if (!mr) 73262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci status = ocrdma_alloc_lkey(dev, mr, pd->id, acc, 0, 73562306a36Sopenharmony_ci OCRDMA_ADDR_CHECK_DISABLE); 73662306a36Sopenharmony_ci if (status) { 73762306a36Sopenharmony_ci kfree(mr); 73862306a36Sopenharmony_ci return ERR_PTR(status); 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci return &mr->ibmr; 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic void ocrdma_free_mr_pbl_tbl(struct ocrdma_dev *dev, 74562306a36Sopenharmony_ci struct ocrdma_hw_mr *mr) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct pci_dev *pdev = dev->nic_info.pdev; 74862306a36Sopenharmony_ci int i = 0; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (mr->pbl_table) { 75162306a36Sopenharmony_ci for (i = 0; i < mr->num_pbls; i++) { 75262306a36Sopenharmony_ci if (!mr->pbl_table[i].va) 75362306a36Sopenharmony_ci continue; 75462306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, mr->pbl_size, 75562306a36Sopenharmony_ci mr->pbl_table[i].va, 75662306a36Sopenharmony_ci mr->pbl_table[i].pa); 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci kfree(mr->pbl_table); 75962306a36Sopenharmony_ci mr->pbl_table = NULL; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic int ocrdma_get_pbl_info(struct ocrdma_dev *dev, struct ocrdma_mr *mr, 76462306a36Sopenharmony_ci u32 num_pbes) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci u32 num_pbls = 0; 76762306a36Sopenharmony_ci u32 idx = 0; 76862306a36Sopenharmony_ci int status = 0; 76962306a36Sopenharmony_ci u32 pbl_size; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci do { 77262306a36Sopenharmony_ci pbl_size = OCRDMA_MIN_HPAGE_SIZE * (1 << idx); 77362306a36Sopenharmony_ci if (pbl_size > MAX_OCRDMA_PBL_SIZE) { 77462306a36Sopenharmony_ci status = -EFAULT; 77562306a36Sopenharmony_ci break; 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci num_pbls = roundup(num_pbes, (pbl_size / sizeof(u64))); 77862306a36Sopenharmony_ci num_pbls = num_pbls / (pbl_size / sizeof(u64)); 77962306a36Sopenharmony_ci idx++; 78062306a36Sopenharmony_ci } while (num_pbls >= dev->attr.max_num_mr_pbl); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci mr->hwmr.num_pbes = num_pbes; 78362306a36Sopenharmony_ci mr->hwmr.num_pbls = num_pbls; 78462306a36Sopenharmony_ci mr->hwmr.pbl_size = pbl_size; 78562306a36Sopenharmony_ci return status; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic int ocrdma_build_pbl_tbl(struct ocrdma_dev *dev, struct ocrdma_hw_mr *mr) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci int status = 0; 79162306a36Sopenharmony_ci int i; 79262306a36Sopenharmony_ci u32 dma_len = mr->pbl_size; 79362306a36Sopenharmony_ci struct pci_dev *pdev = dev->nic_info.pdev; 79462306a36Sopenharmony_ci void *va; 79562306a36Sopenharmony_ci dma_addr_t pa; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci mr->pbl_table = kcalloc(mr->num_pbls, sizeof(struct ocrdma_pbl), 79862306a36Sopenharmony_ci GFP_KERNEL); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (!mr->pbl_table) 80162306a36Sopenharmony_ci return -ENOMEM; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci for (i = 0; i < mr->num_pbls; i++) { 80462306a36Sopenharmony_ci va = dma_alloc_coherent(&pdev->dev, dma_len, &pa, GFP_KERNEL); 80562306a36Sopenharmony_ci if (!va) { 80662306a36Sopenharmony_ci ocrdma_free_mr_pbl_tbl(dev, mr); 80762306a36Sopenharmony_ci status = -ENOMEM; 80862306a36Sopenharmony_ci break; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci mr->pbl_table[i].va = va; 81162306a36Sopenharmony_ci mr->pbl_table[i].pa = pa; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci return status; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic void build_user_pbes(struct ocrdma_dev *dev, struct ocrdma_mr *mr) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct ocrdma_pbe *pbe; 81962306a36Sopenharmony_ci struct ib_block_iter biter; 82062306a36Sopenharmony_ci struct ocrdma_pbl *pbl_tbl = mr->hwmr.pbl_table; 82162306a36Sopenharmony_ci int pbe_cnt; 82262306a36Sopenharmony_ci u64 pg_addr; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (!mr->hwmr.num_pbes) 82562306a36Sopenharmony_ci return; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci pbe = (struct ocrdma_pbe *)pbl_tbl->va; 82862306a36Sopenharmony_ci pbe_cnt = 0; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci rdma_umem_for_each_dma_block (mr->umem, &biter, PAGE_SIZE) { 83162306a36Sopenharmony_ci /* store the page address in pbe */ 83262306a36Sopenharmony_ci pg_addr = rdma_block_iter_dma_address(&biter); 83362306a36Sopenharmony_ci pbe->pa_lo = cpu_to_le32(pg_addr); 83462306a36Sopenharmony_ci pbe->pa_hi = cpu_to_le32(upper_32_bits(pg_addr)); 83562306a36Sopenharmony_ci pbe_cnt += 1; 83662306a36Sopenharmony_ci pbe++; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* if the given pbl is full storing the pbes, 83962306a36Sopenharmony_ci * move to next pbl. 84062306a36Sopenharmony_ci */ 84162306a36Sopenharmony_ci if (pbe_cnt == (mr->hwmr.pbl_size / sizeof(u64))) { 84262306a36Sopenharmony_ci pbl_tbl++; 84362306a36Sopenharmony_ci pbe = (struct ocrdma_pbe *)pbl_tbl->va; 84462306a36Sopenharmony_ci pbe_cnt = 0; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistruct ib_mr *ocrdma_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 len, 85062306a36Sopenharmony_ci u64 usr_addr, int acc, struct ib_udata *udata) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci int status = -ENOMEM; 85362306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibpd->device); 85462306a36Sopenharmony_ci struct ocrdma_mr *mr; 85562306a36Sopenharmony_ci struct ocrdma_pd *pd; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci pd = get_ocrdma_pd(ibpd); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (acc & IB_ACCESS_REMOTE_WRITE && !(acc & IB_ACCESS_LOCAL_WRITE)) 86062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci mr = kzalloc(sizeof(*mr), GFP_KERNEL); 86362306a36Sopenharmony_ci if (!mr) 86462306a36Sopenharmony_ci return ERR_PTR(status); 86562306a36Sopenharmony_ci mr->umem = ib_umem_get(ibpd->device, start, len, acc); 86662306a36Sopenharmony_ci if (IS_ERR(mr->umem)) { 86762306a36Sopenharmony_ci status = -EFAULT; 86862306a36Sopenharmony_ci goto umem_err; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci status = ocrdma_get_pbl_info( 87162306a36Sopenharmony_ci dev, mr, ib_umem_num_dma_blocks(mr->umem, PAGE_SIZE)); 87262306a36Sopenharmony_ci if (status) 87362306a36Sopenharmony_ci goto umem_err; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci mr->hwmr.pbe_size = PAGE_SIZE; 87662306a36Sopenharmony_ci mr->hwmr.va = usr_addr; 87762306a36Sopenharmony_ci mr->hwmr.len = len; 87862306a36Sopenharmony_ci mr->hwmr.remote_wr = (acc & IB_ACCESS_REMOTE_WRITE) ? 1 : 0; 87962306a36Sopenharmony_ci mr->hwmr.remote_rd = (acc & IB_ACCESS_REMOTE_READ) ? 1 : 0; 88062306a36Sopenharmony_ci mr->hwmr.local_wr = (acc & IB_ACCESS_LOCAL_WRITE) ? 1 : 0; 88162306a36Sopenharmony_ci mr->hwmr.local_rd = 1; 88262306a36Sopenharmony_ci mr->hwmr.remote_atomic = (acc & IB_ACCESS_REMOTE_ATOMIC) ? 1 : 0; 88362306a36Sopenharmony_ci status = ocrdma_build_pbl_tbl(dev, &mr->hwmr); 88462306a36Sopenharmony_ci if (status) 88562306a36Sopenharmony_ci goto umem_err; 88662306a36Sopenharmony_ci build_user_pbes(dev, mr); 88762306a36Sopenharmony_ci status = ocrdma_reg_mr(dev, &mr->hwmr, pd->id, acc); 88862306a36Sopenharmony_ci if (status) 88962306a36Sopenharmony_ci goto mbx_err; 89062306a36Sopenharmony_ci mr->ibmr.lkey = mr->hwmr.lkey; 89162306a36Sopenharmony_ci if (mr->hwmr.remote_wr || mr->hwmr.remote_rd) 89262306a36Sopenharmony_ci mr->ibmr.rkey = mr->hwmr.lkey; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci return &mr->ibmr; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cimbx_err: 89762306a36Sopenharmony_ci ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr); 89862306a36Sopenharmony_ciumem_err: 89962306a36Sopenharmony_ci kfree(mr); 90062306a36Sopenharmony_ci return ERR_PTR(status); 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ciint ocrdma_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct ocrdma_mr *mr = get_ocrdma_mr(ib_mr); 90662306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ib_mr->device); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci (void) ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci kfree(mr->pages); 91162306a36Sopenharmony_ci ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci /* it could be user registered memory. */ 91462306a36Sopenharmony_ci ib_umem_release(mr->umem); 91562306a36Sopenharmony_ci kfree(mr); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci /* Don't stop cleanup, in case FW is unresponsive */ 91862306a36Sopenharmony_ci if (dev->mqe_ctx.fw_error_state) { 91962306a36Sopenharmony_ci pr_err("%s(%d) fw not responding.\n", 92062306a36Sopenharmony_ci __func__, dev->id); 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci return 0; 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic int ocrdma_copy_cq_uresp(struct ocrdma_dev *dev, struct ocrdma_cq *cq, 92662306a36Sopenharmony_ci struct ib_udata *udata) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci int status; 92962306a36Sopenharmony_ci struct ocrdma_ucontext *uctx = rdma_udata_to_drv_context( 93062306a36Sopenharmony_ci udata, struct ocrdma_ucontext, ibucontext); 93162306a36Sopenharmony_ci struct ocrdma_create_cq_uresp uresp; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* this must be user flow! */ 93462306a36Sopenharmony_ci if (!udata) 93562306a36Sopenharmony_ci return -EINVAL; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci memset(&uresp, 0, sizeof(uresp)); 93862306a36Sopenharmony_ci uresp.cq_id = cq->id; 93962306a36Sopenharmony_ci uresp.page_size = PAGE_ALIGN(cq->len); 94062306a36Sopenharmony_ci uresp.num_pages = 1; 94162306a36Sopenharmony_ci uresp.max_hw_cqe = cq->max_hw_cqe; 94262306a36Sopenharmony_ci uresp.page_addr[0] = virt_to_phys(cq->va); 94362306a36Sopenharmony_ci uresp.db_page_addr = ocrdma_get_db_addr(dev, uctx->cntxt_pd->id); 94462306a36Sopenharmony_ci uresp.db_page_size = dev->nic_info.db_page_size; 94562306a36Sopenharmony_ci uresp.phase_change = cq->phase_change ? 1 : 0; 94662306a36Sopenharmony_ci status = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); 94762306a36Sopenharmony_ci if (status) { 94862306a36Sopenharmony_ci pr_err("%s(%d) copy error cqid=0x%x.\n", 94962306a36Sopenharmony_ci __func__, dev->id, cq->id); 95062306a36Sopenharmony_ci goto err; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci status = ocrdma_add_mmap(uctx, uresp.db_page_addr, uresp.db_page_size); 95362306a36Sopenharmony_ci if (status) 95462306a36Sopenharmony_ci goto err; 95562306a36Sopenharmony_ci status = ocrdma_add_mmap(uctx, uresp.page_addr[0], uresp.page_size); 95662306a36Sopenharmony_ci if (status) { 95762306a36Sopenharmony_ci ocrdma_del_mmap(uctx, uresp.db_page_addr, uresp.db_page_size); 95862306a36Sopenharmony_ci goto err; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci cq->ucontext = uctx; 96162306a36Sopenharmony_cierr: 96262306a36Sopenharmony_ci return status; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ciint ocrdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, 96662306a36Sopenharmony_ci struct ib_udata *udata) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci struct ib_device *ibdev = ibcq->device; 96962306a36Sopenharmony_ci int entries = attr->cqe; 97062306a36Sopenharmony_ci struct ocrdma_cq *cq = get_ocrdma_cq(ibcq); 97162306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibdev); 97262306a36Sopenharmony_ci struct ocrdma_ucontext *uctx = rdma_udata_to_drv_context( 97362306a36Sopenharmony_ci udata, struct ocrdma_ucontext, ibucontext); 97462306a36Sopenharmony_ci u16 pd_id = 0; 97562306a36Sopenharmony_ci int status; 97662306a36Sopenharmony_ci struct ocrdma_create_cq_ureq ureq; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (attr->flags) 97962306a36Sopenharmony_ci return -EOPNOTSUPP; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (udata) { 98262306a36Sopenharmony_ci if (ib_copy_from_udata(&ureq, udata, sizeof(ureq))) 98362306a36Sopenharmony_ci return -EFAULT; 98462306a36Sopenharmony_ci } else 98562306a36Sopenharmony_ci ureq.dpp_cq = 0; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci spin_lock_init(&cq->cq_lock); 98862306a36Sopenharmony_ci spin_lock_init(&cq->comp_handler_lock); 98962306a36Sopenharmony_ci INIT_LIST_HEAD(&cq->sq_head); 99062306a36Sopenharmony_ci INIT_LIST_HEAD(&cq->rq_head); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (udata) 99362306a36Sopenharmony_ci pd_id = uctx->cntxt_pd->id; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci status = ocrdma_mbx_create_cq(dev, cq, entries, ureq.dpp_cq, pd_id); 99662306a36Sopenharmony_ci if (status) 99762306a36Sopenharmony_ci return status; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci if (udata) { 100062306a36Sopenharmony_ci status = ocrdma_copy_cq_uresp(dev, cq, udata); 100162306a36Sopenharmony_ci if (status) 100262306a36Sopenharmony_ci goto ctx_err; 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci cq->phase = OCRDMA_CQE_VALID; 100562306a36Sopenharmony_ci dev->cq_tbl[cq->id] = cq; 100662306a36Sopenharmony_ci return 0; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cictx_err: 100962306a36Sopenharmony_ci ocrdma_mbx_destroy_cq(dev, cq); 101062306a36Sopenharmony_ci return status; 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ciint ocrdma_resize_cq(struct ib_cq *ibcq, int new_cnt, 101462306a36Sopenharmony_ci struct ib_udata *udata) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci int status = 0; 101762306a36Sopenharmony_ci struct ocrdma_cq *cq = get_ocrdma_cq(ibcq); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci if (new_cnt < 1 || new_cnt > cq->max_hw_cqe) { 102062306a36Sopenharmony_ci status = -EINVAL; 102162306a36Sopenharmony_ci return status; 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci ibcq->cqe = new_cnt; 102462306a36Sopenharmony_ci return status; 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_cistatic void ocrdma_flush_cq(struct ocrdma_cq *cq) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci int cqe_cnt; 103062306a36Sopenharmony_ci int valid_count = 0; 103162306a36Sopenharmony_ci unsigned long flags; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(cq->ibcq.device); 103462306a36Sopenharmony_ci struct ocrdma_cqe *cqe = NULL; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci cqe = cq->va; 103762306a36Sopenharmony_ci cqe_cnt = cq->cqe_cnt; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci /* Last irq might have scheduled a polling thread 104062306a36Sopenharmony_ci * sync-up with it before hard flushing. 104162306a36Sopenharmony_ci */ 104262306a36Sopenharmony_ci spin_lock_irqsave(&cq->cq_lock, flags); 104362306a36Sopenharmony_ci while (cqe_cnt) { 104462306a36Sopenharmony_ci if (is_cqe_valid(cq, cqe)) 104562306a36Sopenharmony_ci valid_count++; 104662306a36Sopenharmony_ci cqe++; 104762306a36Sopenharmony_ci cqe_cnt--; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci ocrdma_ring_cq_db(dev, cq->id, false, false, valid_count); 105062306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->cq_lock, flags); 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ciint ocrdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci struct ocrdma_cq *cq = get_ocrdma_cq(ibcq); 105662306a36Sopenharmony_ci struct ocrdma_eq *eq = NULL; 105762306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device); 105862306a36Sopenharmony_ci int pdid = 0; 105962306a36Sopenharmony_ci u32 irq, indx; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci dev->cq_tbl[cq->id] = NULL; 106262306a36Sopenharmony_ci indx = ocrdma_get_eq_table_index(dev, cq->eqn); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci eq = &dev->eq_tbl[indx]; 106562306a36Sopenharmony_ci irq = ocrdma_get_irq(dev, eq); 106662306a36Sopenharmony_ci synchronize_irq(irq); 106762306a36Sopenharmony_ci ocrdma_flush_cq(cq); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci ocrdma_mbx_destroy_cq(dev, cq); 107062306a36Sopenharmony_ci if (cq->ucontext) { 107162306a36Sopenharmony_ci pdid = cq->ucontext->cntxt_pd->id; 107262306a36Sopenharmony_ci ocrdma_del_mmap(cq->ucontext, (u64) cq->pa, 107362306a36Sopenharmony_ci PAGE_ALIGN(cq->len)); 107462306a36Sopenharmony_ci ocrdma_del_mmap(cq->ucontext, 107562306a36Sopenharmony_ci ocrdma_get_db_addr(dev, pdid), 107662306a36Sopenharmony_ci dev->nic_info.db_page_size); 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci return 0; 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_cistatic int ocrdma_add_qpn_map(struct ocrdma_dev *dev, struct ocrdma_qp *qp) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci int status = -EINVAL; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (qp->id < OCRDMA_MAX_QP && dev->qp_tbl[qp->id] == NULL) { 108662306a36Sopenharmony_ci dev->qp_tbl[qp->id] = qp; 108762306a36Sopenharmony_ci status = 0; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci return status; 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic void ocrdma_del_qpn_map(struct ocrdma_dev *dev, struct ocrdma_qp *qp) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci dev->qp_tbl[qp->id] = NULL; 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic int ocrdma_check_qp_params(struct ib_pd *ibpd, struct ocrdma_dev *dev, 109862306a36Sopenharmony_ci struct ib_qp_init_attr *attrs, 109962306a36Sopenharmony_ci struct ib_udata *udata) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci if ((attrs->qp_type != IB_QPT_GSI) && 110262306a36Sopenharmony_ci (attrs->qp_type != IB_QPT_RC) && 110362306a36Sopenharmony_ci (attrs->qp_type != IB_QPT_UC) && 110462306a36Sopenharmony_ci (attrs->qp_type != IB_QPT_UD)) { 110562306a36Sopenharmony_ci pr_err("%s(%d) unsupported qp type=0x%x requested\n", 110662306a36Sopenharmony_ci __func__, dev->id, attrs->qp_type); 110762306a36Sopenharmony_ci return -EOPNOTSUPP; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci /* Skip the check for QP1 to support CM size of 128 */ 111062306a36Sopenharmony_ci if ((attrs->qp_type != IB_QPT_GSI) && 111162306a36Sopenharmony_ci (attrs->cap.max_send_wr > dev->attr.max_wqe)) { 111262306a36Sopenharmony_ci pr_err("%s(%d) unsupported send_wr=0x%x requested\n", 111362306a36Sopenharmony_ci __func__, dev->id, attrs->cap.max_send_wr); 111462306a36Sopenharmony_ci pr_err("%s(%d) supported send_wr=0x%x\n", 111562306a36Sopenharmony_ci __func__, dev->id, dev->attr.max_wqe); 111662306a36Sopenharmony_ci return -EINVAL; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci if (!attrs->srq && (attrs->cap.max_recv_wr > dev->attr.max_rqe)) { 111962306a36Sopenharmony_ci pr_err("%s(%d) unsupported recv_wr=0x%x requested\n", 112062306a36Sopenharmony_ci __func__, dev->id, attrs->cap.max_recv_wr); 112162306a36Sopenharmony_ci pr_err("%s(%d) supported recv_wr=0x%x\n", 112262306a36Sopenharmony_ci __func__, dev->id, dev->attr.max_rqe); 112362306a36Sopenharmony_ci return -EINVAL; 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci if (attrs->cap.max_inline_data > dev->attr.max_inline_data) { 112662306a36Sopenharmony_ci pr_err("%s(%d) unsupported inline data size=0x%x requested\n", 112762306a36Sopenharmony_ci __func__, dev->id, attrs->cap.max_inline_data); 112862306a36Sopenharmony_ci pr_err("%s(%d) supported inline data size=0x%x\n", 112962306a36Sopenharmony_ci __func__, dev->id, dev->attr.max_inline_data); 113062306a36Sopenharmony_ci return -EINVAL; 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci if (attrs->cap.max_send_sge > dev->attr.max_send_sge) { 113362306a36Sopenharmony_ci pr_err("%s(%d) unsupported send_sge=0x%x requested\n", 113462306a36Sopenharmony_ci __func__, dev->id, attrs->cap.max_send_sge); 113562306a36Sopenharmony_ci pr_err("%s(%d) supported send_sge=0x%x\n", 113662306a36Sopenharmony_ci __func__, dev->id, dev->attr.max_send_sge); 113762306a36Sopenharmony_ci return -EINVAL; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci if (attrs->cap.max_recv_sge > dev->attr.max_recv_sge) { 114062306a36Sopenharmony_ci pr_err("%s(%d) unsupported recv_sge=0x%x requested\n", 114162306a36Sopenharmony_ci __func__, dev->id, attrs->cap.max_recv_sge); 114262306a36Sopenharmony_ci pr_err("%s(%d) supported recv_sge=0x%x\n", 114362306a36Sopenharmony_ci __func__, dev->id, dev->attr.max_recv_sge); 114462306a36Sopenharmony_ci return -EINVAL; 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci /* unprivileged user space cannot create special QP */ 114762306a36Sopenharmony_ci if (udata && attrs->qp_type == IB_QPT_GSI) { 114862306a36Sopenharmony_ci pr_err 114962306a36Sopenharmony_ci ("%s(%d) Userspace can't create special QPs of type=0x%x\n", 115062306a36Sopenharmony_ci __func__, dev->id, attrs->qp_type); 115162306a36Sopenharmony_ci return -EINVAL; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci /* allow creating only one GSI type of QP */ 115462306a36Sopenharmony_ci if (attrs->qp_type == IB_QPT_GSI && dev->gsi_qp_created) { 115562306a36Sopenharmony_ci pr_err("%s(%d) GSI special QPs already created.\n", 115662306a36Sopenharmony_ci __func__, dev->id); 115762306a36Sopenharmony_ci return -EINVAL; 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci /* verify consumer QPs are not trying to use GSI QP's CQ */ 116062306a36Sopenharmony_ci if ((attrs->qp_type != IB_QPT_GSI) && (dev->gsi_qp_created)) { 116162306a36Sopenharmony_ci if ((dev->gsi_sqcq == get_ocrdma_cq(attrs->send_cq)) || 116262306a36Sopenharmony_ci (dev->gsi_rqcq == get_ocrdma_cq(attrs->recv_cq))) { 116362306a36Sopenharmony_ci pr_err("%s(%d) Consumer QP cannot use GSI CQs.\n", 116462306a36Sopenharmony_ci __func__, dev->id); 116562306a36Sopenharmony_ci return -EINVAL; 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci return 0; 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_cistatic int ocrdma_copy_qp_uresp(struct ocrdma_qp *qp, 117262306a36Sopenharmony_ci struct ib_udata *udata, int dpp_offset, 117362306a36Sopenharmony_ci int dpp_credit_lmt, int srq) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci int status; 117662306a36Sopenharmony_ci u64 usr_db; 117762306a36Sopenharmony_ci struct ocrdma_create_qp_uresp uresp; 117862306a36Sopenharmony_ci struct ocrdma_pd *pd = qp->pd; 117962306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci memset(&uresp, 0, sizeof(uresp)); 118262306a36Sopenharmony_ci usr_db = dev->nic_info.unmapped_db + 118362306a36Sopenharmony_ci (pd->id * dev->nic_info.db_page_size); 118462306a36Sopenharmony_ci uresp.qp_id = qp->id; 118562306a36Sopenharmony_ci uresp.sq_dbid = qp->sq.dbid; 118662306a36Sopenharmony_ci uresp.num_sq_pages = 1; 118762306a36Sopenharmony_ci uresp.sq_page_size = PAGE_ALIGN(qp->sq.len); 118862306a36Sopenharmony_ci uresp.sq_page_addr[0] = virt_to_phys(qp->sq.va); 118962306a36Sopenharmony_ci uresp.num_wqe_allocated = qp->sq.max_cnt; 119062306a36Sopenharmony_ci if (!srq) { 119162306a36Sopenharmony_ci uresp.rq_dbid = qp->rq.dbid; 119262306a36Sopenharmony_ci uresp.num_rq_pages = 1; 119362306a36Sopenharmony_ci uresp.rq_page_size = PAGE_ALIGN(qp->rq.len); 119462306a36Sopenharmony_ci uresp.rq_page_addr[0] = virt_to_phys(qp->rq.va); 119562306a36Sopenharmony_ci uresp.num_rqe_allocated = qp->rq.max_cnt; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci uresp.db_page_addr = usr_db; 119862306a36Sopenharmony_ci uresp.db_page_size = dev->nic_info.db_page_size; 119962306a36Sopenharmony_ci uresp.db_sq_offset = OCRDMA_DB_GEN2_SQ_OFFSET; 120062306a36Sopenharmony_ci uresp.db_rq_offset = OCRDMA_DB_GEN2_RQ_OFFSET; 120162306a36Sopenharmony_ci uresp.db_shift = OCRDMA_DB_RQ_SHIFT; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (qp->dpp_enabled) { 120462306a36Sopenharmony_ci uresp.dpp_credit = dpp_credit_lmt; 120562306a36Sopenharmony_ci uresp.dpp_offset = dpp_offset; 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci status = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); 120862306a36Sopenharmony_ci if (status) { 120962306a36Sopenharmony_ci pr_err("%s(%d) user copy error.\n", __func__, dev->id); 121062306a36Sopenharmony_ci goto err; 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci status = ocrdma_add_mmap(pd->uctx, uresp.sq_page_addr[0], 121362306a36Sopenharmony_ci uresp.sq_page_size); 121462306a36Sopenharmony_ci if (status) 121562306a36Sopenharmony_ci goto err; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci if (!srq) { 121862306a36Sopenharmony_ci status = ocrdma_add_mmap(pd->uctx, uresp.rq_page_addr[0], 121962306a36Sopenharmony_ci uresp.rq_page_size); 122062306a36Sopenharmony_ci if (status) 122162306a36Sopenharmony_ci goto rq_map_err; 122262306a36Sopenharmony_ci } 122362306a36Sopenharmony_ci return status; 122462306a36Sopenharmony_cirq_map_err: 122562306a36Sopenharmony_ci ocrdma_del_mmap(pd->uctx, uresp.sq_page_addr[0], uresp.sq_page_size); 122662306a36Sopenharmony_cierr: 122762306a36Sopenharmony_ci return status; 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_cistatic void ocrdma_set_qp_db(struct ocrdma_dev *dev, struct ocrdma_qp *qp, 123162306a36Sopenharmony_ci struct ocrdma_pd *pd) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci if (ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R) { 123462306a36Sopenharmony_ci qp->sq_db = dev->nic_info.db + 123562306a36Sopenharmony_ci (pd->id * dev->nic_info.db_page_size) + 123662306a36Sopenharmony_ci OCRDMA_DB_GEN2_SQ_OFFSET; 123762306a36Sopenharmony_ci qp->rq_db = dev->nic_info.db + 123862306a36Sopenharmony_ci (pd->id * dev->nic_info.db_page_size) + 123962306a36Sopenharmony_ci OCRDMA_DB_GEN2_RQ_OFFSET; 124062306a36Sopenharmony_ci } else { 124162306a36Sopenharmony_ci qp->sq_db = dev->nic_info.db + 124262306a36Sopenharmony_ci (pd->id * dev->nic_info.db_page_size) + 124362306a36Sopenharmony_ci OCRDMA_DB_SQ_OFFSET; 124462306a36Sopenharmony_ci qp->rq_db = dev->nic_info.db + 124562306a36Sopenharmony_ci (pd->id * dev->nic_info.db_page_size) + 124662306a36Sopenharmony_ci OCRDMA_DB_RQ_OFFSET; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci} 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_cistatic int ocrdma_alloc_wr_id_tbl(struct ocrdma_qp *qp) 125162306a36Sopenharmony_ci{ 125262306a36Sopenharmony_ci qp->wqe_wr_id_tbl = 125362306a36Sopenharmony_ci kcalloc(qp->sq.max_cnt, sizeof(*(qp->wqe_wr_id_tbl)), 125462306a36Sopenharmony_ci GFP_KERNEL); 125562306a36Sopenharmony_ci if (qp->wqe_wr_id_tbl == NULL) 125662306a36Sopenharmony_ci return -ENOMEM; 125762306a36Sopenharmony_ci qp->rqe_wr_id_tbl = 125862306a36Sopenharmony_ci kcalloc(qp->rq.max_cnt, sizeof(u64), GFP_KERNEL); 125962306a36Sopenharmony_ci if (qp->rqe_wr_id_tbl == NULL) 126062306a36Sopenharmony_ci return -ENOMEM; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci return 0; 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_cistatic void ocrdma_set_qp_init_params(struct ocrdma_qp *qp, 126662306a36Sopenharmony_ci struct ocrdma_pd *pd, 126762306a36Sopenharmony_ci struct ib_qp_init_attr *attrs) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci qp->pd = pd; 127062306a36Sopenharmony_ci spin_lock_init(&qp->q_lock); 127162306a36Sopenharmony_ci INIT_LIST_HEAD(&qp->sq_entry); 127262306a36Sopenharmony_ci INIT_LIST_HEAD(&qp->rq_entry); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci qp->qp_type = attrs->qp_type; 127562306a36Sopenharmony_ci qp->cap_flags = OCRDMA_QP_INB_RD | OCRDMA_QP_INB_WR; 127662306a36Sopenharmony_ci qp->max_inline_data = attrs->cap.max_inline_data; 127762306a36Sopenharmony_ci qp->sq.max_sges = attrs->cap.max_send_sge; 127862306a36Sopenharmony_ci qp->rq.max_sges = attrs->cap.max_recv_sge; 127962306a36Sopenharmony_ci qp->state = OCRDMA_QPS_RST; 128062306a36Sopenharmony_ci qp->signaled = attrs->sq_sig_type == IB_SIGNAL_ALL_WR; 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic void ocrdma_store_gsi_qp_cq(struct ocrdma_dev *dev, 128462306a36Sopenharmony_ci struct ib_qp_init_attr *attrs) 128562306a36Sopenharmony_ci{ 128662306a36Sopenharmony_ci if (attrs->qp_type == IB_QPT_GSI) { 128762306a36Sopenharmony_ci dev->gsi_qp_created = 1; 128862306a36Sopenharmony_ci dev->gsi_sqcq = get_ocrdma_cq(attrs->send_cq); 128962306a36Sopenharmony_ci dev->gsi_rqcq = get_ocrdma_cq(attrs->recv_cq); 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ciint ocrdma_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, 129462306a36Sopenharmony_ci struct ib_udata *udata) 129562306a36Sopenharmony_ci{ 129662306a36Sopenharmony_ci int status; 129762306a36Sopenharmony_ci struct ib_pd *ibpd = ibqp->pd; 129862306a36Sopenharmony_ci struct ocrdma_pd *pd = get_ocrdma_pd(ibpd); 129962306a36Sopenharmony_ci struct ocrdma_qp *qp = get_ocrdma_qp(ibqp); 130062306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibqp->device); 130162306a36Sopenharmony_ci struct ocrdma_create_qp_ureq ureq; 130262306a36Sopenharmony_ci u16 dpp_credit_lmt, dpp_offset; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (attrs->create_flags) 130562306a36Sopenharmony_ci return -EOPNOTSUPP; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci status = ocrdma_check_qp_params(ibpd, dev, attrs, udata); 130862306a36Sopenharmony_ci if (status) 130962306a36Sopenharmony_ci goto gen_err; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci memset(&ureq, 0, sizeof(ureq)); 131262306a36Sopenharmony_ci if (udata) { 131362306a36Sopenharmony_ci if (ib_copy_from_udata(&ureq, udata, sizeof(ureq))) 131462306a36Sopenharmony_ci return -EFAULT; 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci ocrdma_set_qp_init_params(qp, pd, attrs); 131762306a36Sopenharmony_ci if (udata == NULL) 131862306a36Sopenharmony_ci qp->cap_flags |= (OCRDMA_QP_MW_BIND | OCRDMA_QP_LKEY0 | 131962306a36Sopenharmony_ci OCRDMA_QP_FAST_REG); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci mutex_lock(&dev->dev_lock); 132262306a36Sopenharmony_ci status = ocrdma_mbx_create_qp(qp, attrs, ureq.enable_dpp_cq, 132362306a36Sopenharmony_ci ureq.dpp_cq_id, 132462306a36Sopenharmony_ci &dpp_offset, &dpp_credit_lmt); 132562306a36Sopenharmony_ci if (status) 132662306a36Sopenharmony_ci goto mbx_err; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci /* user space QP's wr_id table are managed in library */ 132962306a36Sopenharmony_ci if (udata == NULL) { 133062306a36Sopenharmony_ci status = ocrdma_alloc_wr_id_tbl(qp); 133162306a36Sopenharmony_ci if (status) 133262306a36Sopenharmony_ci goto map_err; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci status = ocrdma_add_qpn_map(dev, qp); 133662306a36Sopenharmony_ci if (status) 133762306a36Sopenharmony_ci goto map_err; 133862306a36Sopenharmony_ci ocrdma_set_qp_db(dev, qp, pd); 133962306a36Sopenharmony_ci if (udata) { 134062306a36Sopenharmony_ci status = ocrdma_copy_qp_uresp(qp, udata, dpp_offset, 134162306a36Sopenharmony_ci dpp_credit_lmt, 134262306a36Sopenharmony_ci (attrs->srq != NULL)); 134362306a36Sopenharmony_ci if (status) 134462306a36Sopenharmony_ci goto cpy_err; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci ocrdma_store_gsi_qp_cq(dev, attrs); 134762306a36Sopenharmony_ci qp->ibqp.qp_num = qp->id; 134862306a36Sopenharmony_ci mutex_unlock(&dev->dev_lock); 134962306a36Sopenharmony_ci return 0; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_cicpy_err: 135262306a36Sopenharmony_ci ocrdma_del_qpn_map(dev, qp); 135362306a36Sopenharmony_cimap_err: 135462306a36Sopenharmony_ci ocrdma_mbx_destroy_qp(dev, qp); 135562306a36Sopenharmony_cimbx_err: 135662306a36Sopenharmony_ci mutex_unlock(&dev->dev_lock); 135762306a36Sopenharmony_ci kfree(qp->wqe_wr_id_tbl); 135862306a36Sopenharmony_ci kfree(qp->rqe_wr_id_tbl); 135962306a36Sopenharmony_ci pr_err("%s(%d) error=%d\n", __func__, dev->id, status); 136062306a36Sopenharmony_cigen_err: 136162306a36Sopenharmony_ci return status; 136262306a36Sopenharmony_ci} 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ciint _ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 136562306a36Sopenharmony_ci int attr_mask) 136662306a36Sopenharmony_ci{ 136762306a36Sopenharmony_ci int status = 0; 136862306a36Sopenharmony_ci struct ocrdma_qp *qp; 136962306a36Sopenharmony_ci struct ocrdma_dev *dev; 137062306a36Sopenharmony_ci enum ib_qp_state old_qps; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci qp = get_ocrdma_qp(ibqp); 137362306a36Sopenharmony_ci dev = get_ocrdma_dev(ibqp->device); 137462306a36Sopenharmony_ci if (attr_mask & IB_QP_STATE) 137562306a36Sopenharmony_ci status = ocrdma_qp_state_change(qp, attr->qp_state, &old_qps); 137662306a36Sopenharmony_ci /* if new and previous states are same hw doesn't need to 137762306a36Sopenharmony_ci * know about it. 137862306a36Sopenharmony_ci */ 137962306a36Sopenharmony_ci if (status < 0) 138062306a36Sopenharmony_ci return status; 138162306a36Sopenharmony_ci return ocrdma_mbx_modify_qp(dev, qp, attr, attr_mask); 138262306a36Sopenharmony_ci} 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ciint ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 138562306a36Sopenharmony_ci int attr_mask, struct ib_udata *udata) 138662306a36Sopenharmony_ci{ 138762306a36Sopenharmony_ci unsigned long flags; 138862306a36Sopenharmony_ci int status = -EINVAL; 138962306a36Sopenharmony_ci struct ocrdma_qp *qp; 139062306a36Sopenharmony_ci struct ocrdma_dev *dev; 139162306a36Sopenharmony_ci enum ib_qp_state old_qps, new_qps; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS) 139462306a36Sopenharmony_ci return -EOPNOTSUPP; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci qp = get_ocrdma_qp(ibqp); 139762306a36Sopenharmony_ci dev = get_ocrdma_dev(ibqp->device); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci /* syncronize with multiple context trying to change, retrive qps */ 140062306a36Sopenharmony_ci mutex_lock(&dev->dev_lock); 140162306a36Sopenharmony_ci /* syncronize with wqe, rqe posting and cqe processing contexts */ 140262306a36Sopenharmony_ci spin_lock_irqsave(&qp->q_lock, flags); 140362306a36Sopenharmony_ci old_qps = get_ibqp_state(qp->state); 140462306a36Sopenharmony_ci if (attr_mask & IB_QP_STATE) 140562306a36Sopenharmony_ci new_qps = attr->qp_state; 140662306a36Sopenharmony_ci else 140762306a36Sopenharmony_ci new_qps = old_qps; 140862306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci if (!ib_modify_qp_is_ok(old_qps, new_qps, ibqp->qp_type, attr_mask)) { 141162306a36Sopenharmony_ci pr_err("%s(%d) invalid attribute mask=0x%x specified for\n" 141262306a36Sopenharmony_ci "qpn=0x%x of type=0x%x old_qps=0x%x, new_qps=0x%x\n", 141362306a36Sopenharmony_ci __func__, dev->id, attr_mask, qp->id, ibqp->qp_type, 141462306a36Sopenharmony_ci old_qps, new_qps); 141562306a36Sopenharmony_ci goto param_err; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci status = _ocrdma_modify_qp(ibqp, attr, attr_mask); 141962306a36Sopenharmony_ci if (status > 0) 142062306a36Sopenharmony_ci status = 0; 142162306a36Sopenharmony_ciparam_err: 142262306a36Sopenharmony_ci mutex_unlock(&dev->dev_lock); 142362306a36Sopenharmony_ci return status; 142462306a36Sopenharmony_ci} 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_cistatic enum ib_mtu ocrdma_mtu_int_to_enum(u16 mtu) 142762306a36Sopenharmony_ci{ 142862306a36Sopenharmony_ci switch (mtu) { 142962306a36Sopenharmony_ci case 256: 143062306a36Sopenharmony_ci return IB_MTU_256; 143162306a36Sopenharmony_ci case 512: 143262306a36Sopenharmony_ci return IB_MTU_512; 143362306a36Sopenharmony_ci case 1024: 143462306a36Sopenharmony_ci return IB_MTU_1024; 143562306a36Sopenharmony_ci case 2048: 143662306a36Sopenharmony_ci return IB_MTU_2048; 143762306a36Sopenharmony_ci case 4096: 143862306a36Sopenharmony_ci return IB_MTU_4096; 143962306a36Sopenharmony_ci default: 144062306a36Sopenharmony_ci return IB_MTU_1024; 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci} 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_cistatic int ocrdma_to_ib_qp_acc_flags(int qp_cap_flags) 144562306a36Sopenharmony_ci{ 144662306a36Sopenharmony_ci int ib_qp_acc_flags = 0; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci if (qp_cap_flags & OCRDMA_QP_INB_WR) 144962306a36Sopenharmony_ci ib_qp_acc_flags |= IB_ACCESS_REMOTE_WRITE; 145062306a36Sopenharmony_ci if (qp_cap_flags & OCRDMA_QP_INB_RD) 145162306a36Sopenharmony_ci ib_qp_acc_flags |= IB_ACCESS_LOCAL_WRITE; 145262306a36Sopenharmony_ci return ib_qp_acc_flags; 145362306a36Sopenharmony_ci} 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ciint ocrdma_query_qp(struct ib_qp *ibqp, 145662306a36Sopenharmony_ci struct ib_qp_attr *qp_attr, 145762306a36Sopenharmony_ci int attr_mask, struct ib_qp_init_attr *qp_init_attr) 145862306a36Sopenharmony_ci{ 145962306a36Sopenharmony_ci int status; 146062306a36Sopenharmony_ci u32 qp_state; 146162306a36Sopenharmony_ci struct ocrdma_qp_params params; 146262306a36Sopenharmony_ci struct ocrdma_qp *qp = get_ocrdma_qp(ibqp); 146362306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibqp->device); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 146662306a36Sopenharmony_ci mutex_lock(&dev->dev_lock); 146762306a36Sopenharmony_ci status = ocrdma_mbx_query_qp(dev, qp, ¶ms); 146862306a36Sopenharmony_ci mutex_unlock(&dev->dev_lock); 146962306a36Sopenharmony_ci if (status) 147062306a36Sopenharmony_ci goto mbx_err; 147162306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_UD) 147262306a36Sopenharmony_ci qp_attr->qkey = params.qkey; 147362306a36Sopenharmony_ci qp_attr->path_mtu = 147462306a36Sopenharmony_ci ocrdma_mtu_int_to_enum(params.path_mtu_pkey_indx & 147562306a36Sopenharmony_ci OCRDMA_QP_PARAMS_PATH_MTU_MASK) >> 147662306a36Sopenharmony_ci OCRDMA_QP_PARAMS_PATH_MTU_SHIFT; 147762306a36Sopenharmony_ci qp_attr->path_mig_state = IB_MIG_MIGRATED; 147862306a36Sopenharmony_ci qp_attr->rq_psn = params.hop_lmt_rq_psn & OCRDMA_QP_PARAMS_RQ_PSN_MASK; 147962306a36Sopenharmony_ci qp_attr->sq_psn = params.tclass_sq_psn & OCRDMA_QP_PARAMS_SQ_PSN_MASK; 148062306a36Sopenharmony_ci qp_attr->dest_qp_num = 148162306a36Sopenharmony_ci params.ack_to_rnr_rtc_dest_qpn & OCRDMA_QP_PARAMS_DEST_QPN_MASK; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci qp_attr->qp_access_flags = ocrdma_to_ib_qp_acc_flags(qp->cap_flags); 148462306a36Sopenharmony_ci qp_attr->cap.max_send_wr = qp->sq.max_cnt - 1; 148562306a36Sopenharmony_ci qp_attr->cap.max_recv_wr = qp->rq.max_cnt - 1; 148662306a36Sopenharmony_ci qp_attr->cap.max_send_sge = qp->sq.max_sges; 148762306a36Sopenharmony_ci qp_attr->cap.max_recv_sge = qp->rq.max_sges; 148862306a36Sopenharmony_ci qp_attr->cap.max_inline_data = qp->max_inline_data; 148962306a36Sopenharmony_ci qp_init_attr->cap = qp_attr->cap; 149062306a36Sopenharmony_ci qp_attr->ah_attr.type = RDMA_AH_ATTR_TYPE_ROCE; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci rdma_ah_set_grh(&qp_attr->ah_attr, NULL, 149362306a36Sopenharmony_ci params.rnt_rc_sl_fl & 149462306a36Sopenharmony_ci OCRDMA_QP_PARAMS_FLOW_LABEL_MASK, 149562306a36Sopenharmony_ci qp->sgid_idx, 149662306a36Sopenharmony_ci (params.hop_lmt_rq_psn & 149762306a36Sopenharmony_ci OCRDMA_QP_PARAMS_HOP_LMT_MASK) >> 149862306a36Sopenharmony_ci OCRDMA_QP_PARAMS_HOP_LMT_SHIFT, 149962306a36Sopenharmony_ci (params.tclass_sq_psn & 150062306a36Sopenharmony_ci OCRDMA_QP_PARAMS_TCLASS_MASK) >> 150162306a36Sopenharmony_ci OCRDMA_QP_PARAMS_TCLASS_SHIFT); 150262306a36Sopenharmony_ci rdma_ah_set_dgid_raw(&qp_attr->ah_attr, ¶ms.dgid[0]); 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci rdma_ah_set_port_num(&qp_attr->ah_attr, 1); 150562306a36Sopenharmony_ci rdma_ah_set_sl(&qp_attr->ah_attr, (params.rnt_rc_sl_fl & 150662306a36Sopenharmony_ci OCRDMA_QP_PARAMS_SL_MASK) >> 150762306a36Sopenharmony_ci OCRDMA_QP_PARAMS_SL_SHIFT); 150862306a36Sopenharmony_ci qp_attr->timeout = (params.ack_to_rnr_rtc_dest_qpn & 150962306a36Sopenharmony_ci OCRDMA_QP_PARAMS_ACK_TIMEOUT_MASK) >> 151062306a36Sopenharmony_ci OCRDMA_QP_PARAMS_ACK_TIMEOUT_SHIFT; 151162306a36Sopenharmony_ci qp_attr->rnr_retry = (params.ack_to_rnr_rtc_dest_qpn & 151262306a36Sopenharmony_ci OCRDMA_QP_PARAMS_RNR_RETRY_CNT_MASK) >> 151362306a36Sopenharmony_ci OCRDMA_QP_PARAMS_RNR_RETRY_CNT_SHIFT; 151462306a36Sopenharmony_ci qp_attr->retry_cnt = 151562306a36Sopenharmony_ci (params.rnt_rc_sl_fl & OCRDMA_QP_PARAMS_RETRY_CNT_MASK) >> 151662306a36Sopenharmony_ci OCRDMA_QP_PARAMS_RETRY_CNT_SHIFT; 151762306a36Sopenharmony_ci qp_attr->min_rnr_timer = 0; 151862306a36Sopenharmony_ci qp_attr->pkey_index = 0; 151962306a36Sopenharmony_ci qp_attr->port_num = 1; 152062306a36Sopenharmony_ci rdma_ah_set_path_bits(&qp_attr->ah_attr, 0); 152162306a36Sopenharmony_ci rdma_ah_set_static_rate(&qp_attr->ah_attr, 0); 152262306a36Sopenharmony_ci qp_attr->alt_pkey_index = 0; 152362306a36Sopenharmony_ci qp_attr->alt_port_num = 0; 152462306a36Sopenharmony_ci qp_attr->alt_timeout = 0; 152562306a36Sopenharmony_ci memset(&qp_attr->alt_ah_attr, 0, sizeof(qp_attr->alt_ah_attr)); 152662306a36Sopenharmony_ci qp_state = (params.max_sge_recv_flags & OCRDMA_QP_PARAMS_STATE_MASK) >> 152762306a36Sopenharmony_ci OCRDMA_QP_PARAMS_STATE_SHIFT; 152862306a36Sopenharmony_ci qp_attr->qp_state = get_ibqp_state(qp_state); 152962306a36Sopenharmony_ci qp_attr->cur_qp_state = qp_attr->qp_state; 153062306a36Sopenharmony_ci qp_attr->sq_draining = (qp_state == OCRDMA_QPS_SQ_DRAINING) ? 1 : 0; 153162306a36Sopenharmony_ci qp_attr->max_dest_rd_atomic = 153262306a36Sopenharmony_ci params.max_ord_ird >> OCRDMA_QP_PARAMS_MAX_ORD_SHIFT; 153362306a36Sopenharmony_ci qp_attr->max_rd_atomic = 153462306a36Sopenharmony_ci params.max_ord_ird & OCRDMA_QP_PARAMS_MAX_IRD_MASK; 153562306a36Sopenharmony_ci qp_attr->en_sqd_async_notify = (params.max_sge_recv_flags & 153662306a36Sopenharmony_ci OCRDMA_QP_PARAMS_FLAGS_SQD_ASYNC) ? 1 : 0; 153762306a36Sopenharmony_ci /* Sync driver QP state with FW */ 153862306a36Sopenharmony_ci ocrdma_qp_state_change(qp, qp_attr->qp_state, NULL); 153962306a36Sopenharmony_cimbx_err: 154062306a36Sopenharmony_ci return status; 154162306a36Sopenharmony_ci} 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_cistatic void ocrdma_srq_toggle_bit(struct ocrdma_srq *srq, unsigned int idx) 154462306a36Sopenharmony_ci{ 154562306a36Sopenharmony_ci unsigned int i = idx / 32; 154662306a36Sopenharmony_ci u32 mask = (1U << (idx % 32)); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci srq->idx_bit_fields[i] ^= mask; 154962306a36Sopenharmony_ci} 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_cistatic int ocrdma_hwq_free_cnt(struct ocrdma_qp_hwq_info *q) 155262306a36Sopenharmony_ci{ 155362306a36Sopenharmony_ci return ((q->max_wqe_idx - q->head) + q->tail) % q->max_cnt; 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cistatic int is_hw_sq_empty(struct ocrdma_qp *qp) 155762306a36Sopenharmony_ci{ 155862306a36Sopenharmony_ci return (qp->sq.tail == qp->sq.head); 155962306a36Sopenharmony_ci} 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_cistatic int is_hw_rq_empty(struct ocrdma_qp *qp) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci return (qp->rq.tail == qp->rq.head); 156462306a36Sopenharmony_ci} 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_cistatic void *ocrdma_hwq_head(struct ocrdma_qp_hwq_info *q) 156762306a36Sopenharmony_ci{ 156862306a36Sopenharmony_ci return q->va + (q->head * q->entry_size); 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_cistatic void *ocrdma_hwq_head_from_idx(struct ocrdma_qp_hwq_info *q, 157262306a36Sopenharmony_ci u32 idx) 157362306a36Sopenharmony_ci{ 157462306a36Sopenharmony_ci return q->va + (idx * q->entry_size); 157562306a36Sopenharmony_ci} 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_cistatic void ocrdma_hwq_inc_head(struct ocrdma_qp_hwq_info *q) 157862306a36Sopenharmony_ci{ 157962306a36Sopenharmony_ci q->head = (q->head + 1) & q->max_wqe_idx; 158062306a36Sopenharmony_ci} 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_cistatic void ocrdma_hwq_inc_tail(struct ocrdma_qp_hwq_info *q) 158362306a36Sopenharmony_ci{ 158462306a36Sopenharmony_ci q->tail = (q->tail + 1) & q->max_wqe_idx; 158562306a36Sopenharmony_ci} 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci/* discard the cqe for a given QP */ 158862306a36Sopenharmony_cistatic void ocrdma_discard_cqes(struct ocrdma_qp *qp, struct ocrdma_cq *cq) 158962306a36Sopenharmony_ci{ 159062306a36Sopenharmony_ci unsigned long cq_flags; 159162306a36Sopenharmony_ci unsigned long flags; 159262306a36Sopenharmony_ci u32 cur_getp, stop_getp; 159362306a36Sopenharmony_ci struct ocrdma_cqe *cqe; 159462306a36Sopenharmony_ci u32 qpn = 0, wqe_idx = 0; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci spin_lock_irqsave(&cq->cq_lock, cq_flags); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci /* traverse through the CQEs in the hw CQ, 159962306a36Sopenharmony_ci * find the matching CQE for a given qp, 160062306a36Sopenharmony_ci * mark the matching one discarded by clearing qpn. 160162306a36Sopenharmony_ci * ring the doorbell in the poll_cq() as 160262306a36Sopenharmony_ci * we don't complete out of order cqe. 160362306a36Sopenharmony_ci */ 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci cur_getp = cq->getp; 160662306a36Sopenharmony_ci /* find upto when do we reap the cq. */ 160762306a36Sopenharmony_ci stop_getp = cur_getp; 160862306a36Sopenharmony_ci do { 160962306a36Sopenharmony_ci if (is_hw_sq_empty(qp) && (!qp->srq && is_hw_rq_empty(qp))) 161062306a36Sopenharmony_ci break; 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci cqe = cq->va + cur_getp; 161362306a36Sopenharmony_ci /* if (a) done reaping whole hw cq, or 161462306a36Sopenharmony_ci * (b) qp_xq becomes empty. 161562306a36Sopenharmony_ci * then exit 161662306a36Sopenharmony_ci */ 161762306a36Sopenharmony_ci qpn = cqe->cmn.qpn & OCRDMA_CQE_QPN_MASK; 161862306a36Sopenharmony_ci /* if previously discarded cqe found, skip that too. */ 161962306a36Sopenharmony_ci /* check for matching qp */ 162062306a36Sopenharmony_ci if (qpn == 0 || qpn != qp->id) 162162306a36Sopenharmony_ci goto skip_cqe; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci if (is_cqe_for_sq(cqe)) { 162462306a36Sopenharmony_ci ocrdma_hwq_inc_tail(&qp->sq); 162562306a36Sopenharmony_ci } else { 162662306a36Sopenharmony_ci if (qp->srq) { 162762306a36Sopenharmony_ci wqe_idx = (le32_to_cpu(cqe->rq.buftag_qpn) >> 162862306a36Sopenharmony_ci OCRDMA_CQE_BUFTAG_SHIFT) & 162962306a36Sopenharmony_ci qp->srq->rq.max_wqe_idx; 163062306a36Sopenharmony_ci BUG_ON(wqe_idx < 1); 163162306a36Sopenharmony_ci spin_lock_irqsave(&qp->srq->q_lock, flags); 163262306a36Sopenharmony_ci ocrdma_hwq_inc_tail(&qp->srq->rq); 163362306a36Sopenharmony_ci ocrdma_srq_toggle_bit(qp->srq, wqe_idx - 1); 163462306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->srq->q_lock, flags); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci } else { 163762306a36Sopenharmony_ci ocrdma_hwq_inc_tail(&qp->rq); 163862306a36Sopenharmony_ci } 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci /* mark cqe discarded so that it is not picked up later 164162306a36Sopenharmony_ci * in the poll_cq(). 164262306a36Sopenharmony_ci */ 164362306a36Sopenharmony_ci cqe->cmn.qpn = 0; 164462306a36Sopenharmony_ciskip_cqe: 164562306a36Sopenharmony_ci cur_getp = (cur_getp + 1) % cq->max_hw_cqe; 164662306a36Sopenharmony_ci } while (cur_getp != stop_getp); 164762306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->cq_lock, cq_flags); 164862306a36Sopenharmony_ci} 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_civoid ocrdma_del_flush_qp(struct ocrdma_qp *qp) 165162306a36Sopenharmony_ci{ 165262306a36Sopenharmony_ci int found = false; 165362306a36Sopenharmony_ci unsigned long flags; 165462306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device); 165562306a36Sopenharmony_ci /* sync with any active CQ poll */ 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci spin_lock_irqsave(&dev->flush_q_lock, flags); 165862306a36Sopenharmony_ci found = ocrdma_is_qp_in_sq_flushlist(qp->sq_cq, qp); 165962306a36Sopenharmony_ci if (found) 166062306a36Sopenharmony_ci list_del(&qp->sq_entry); 166162306a36Sopenharmony_ci if (!qp->srq) { 166262306a36Sopenharmony_ci found = ocrdma_is_qp_in_rq_flushlist(qp->rq_cq, qp); 166362306a36Sopenharmony_ci if (found) 166462306a36Sopenharmony_ci list_del(&qp->rq_entry); 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->flush_q_lock, flags); 166762306a36Sopenharmony_ci} 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ciint ocrdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) 167062306a36Sopenharmony_ci{ 167162306a36Sopenharmony_ci struct ocrdma_pd *pd; 167262306a36Sopenharmony_ci struct ocrdma_qp *qp; 167362306a36Sopenharmony_ci struct ocrdma_dev *dev; 167462306a36Sopenharmony_ci struct ib_qp_attr attrs; 167562306a36Sopenharmony_ci int attr_mask; 167662306a36Sopenharmony_ci unsigned long flags; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci qp = get_ocrdma_qp(ibqp); 167962306a36Sopenharmony_ci dev = get_ocrdma_dev(ibqp->device); 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci pd = qp->pd; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci /* change the QP state to ERROR */ 168462306a36Sopenharmony_ci if (qp->state != OCRDMA_QPS_RST) { 168562306a36Sopenharmony_ci attrs.qp_state = IB_QPS_ERR; 168662306a36Sopenharmony_ci attr_mask = IB_QP_STATE; 168762306a36Sopenharmony_ci _ocrdma_modify_qp(ibqp, &attrs, attr_mask); 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci /* ensure that CQEs for newly created QP (whose id may be same with 169062306a36Sopenharmony_ci * one which just getting destroyed are same), dont get 169162306a36Sopenharmony_ci * discarded until the old CQEs are discarded. 169262306a36Sopenharmony_ci */ 169362306a36Sopenharmony_ci mutex_lock(&dev->dev_lock); 169462306a36Sopenharmony_ci (void) ocrdma_mbx_destroy_qp(dev, qp); 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci /* 169762306a36Sopenharmony_ci * acquire CQ lock while destroy is in progress, in order to 169862306a36Sopenharmony_ci * protect against proessing in-flight CQEs for this QP. 169962306a36Sopenharmony_ci */ 170062306a36Sopenharmony_ci spin_lock_irqsave(&qp->sq_cq->cq_lock, flags); 170162306a36Sopenharmony_ci if (qp->rq_cq && (qp->rq_cq != qp->sq_cq)) { 170262306a36Sopenharmony_ci spin_lock(&qp->rq_cq->cq_lock); 170362306a36Sopenharmony_ci ocrdma_del_qpn_map(dev, qp); 170462306a36Sopenharmony_ci spin_unlock(&qp->rq_cq->cq_lock); 170562306a36Sopenharmony_ci } else { 170662306a36Sopenharmony_ci ocrdma_del_qpn_map(dev, qp); 170762306a36Sopenharmony_ci } 170862306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->sq_cq->cq_lock, flags); 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci if (!pd->uctx) { 171162306a36Sopenharmony_ci ocrdma_discard_cqes(qp, qp->sq_cq); 171262306a36Sopenharmony_ci ocrdma_discard_cqes(qp, qp->rq_cq); 171362306a36Sopenharmony_ci } 171462306a36Sopenharmony_ci mutex_unlock(&dev->dev_lock); 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci if (pd->uctx) { 171762306a36Sopenharmony_ci ocrdma_del_mmap(pd->uctx, (u64) qp->sq.pa, 171862306a36Sopenharmony_ci PAGE_ALIGN(qp->sq.len)); 171962306a36Sopenharmony_ci if (!qp->srq) 172062306a36Sopenharmony_ci ocrdma_del_mmap(pd->uctx, (u64) qp->rq.pa, 172162306a36Sopenharmony_ci PAGE_ALIGN(qp->rq.len)); 172262306a36Sopenharmony_ci } 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci ocrdma_del_flush_qp(qp); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci kfree(qp->wqe_wr_id_tbl); 172762306a36Sopenharmony_ci kfree(qp->rqe_wr_id_tbl); 172862306a36Sopenharmony_ci return 0; 172962306a36Sopenharmony_ci} 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_cistatic int ocrdma_copy_srq_uresp(struct ocrdma_dev *dev, struct ocrdma_srq *srq, 173262306a36Sopenharmony_ci struct ib_udata *udata) 173362306a36Sopenharmony_ci{ 173462306a36Sopenharmony_ci int status; 173562306a36Sopenharmony_ci struct ocrdma_create_srq_uresp uresp; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci memset(&uresp, 0, sizeof(uresp)); 173862306a36Sopenharmony_ci uresp.rq_dbid = srq->rq.dbid; 173962306a36Sopenharmony_ci uresp.num_rq_pages = 1; 174062306a36Sopenharmony_ci uresp.rq_page_addr[0] = virt_to_phys(srq->rq.va); 174162306a36Sopenharmony_ci uresp.rq_page_size = srq->rq.len; 174262306a36Sopenharmony_ci uresp.db_page_addr = dev->nic_info.unmapped_db + 174362306a36Sopenharmony_ci (srq->pd->id * dev->nic_info.db_page_size); 174462306a36Sopenharmony_ci uresp.db_page_size = dev->nic_info.db_page_size; 174562306a36Sopenharmony_ci uresp.num_rqe_allocated = srq->rq.max_cnt; 174662306a36Sopenharmony_ci if (ocrdma_get_asic_type(dev) == OCRDMA_ASIC_GEN_SKH_R) { 174762306a36Sopenharmony_ci uresp.db_rq_offset = OCRDMA_DB_GEN2_RQ_OFFSET; 174862306a36Sopenharmony_ci uresp.db_shift = 24; 174962306a36Sopenharmony_ci } else { 175062306a36Sopenharmony_ci uresp.db_rq_offset = OCRDMA_DB_RQ_OFFSET; 175162306a36Sopenharmony_ci uresp.db_shift = 16; 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci status = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); 175562306a36Sopenharmony_ci if (status) 175662306a36Sopenharmony_ci return status; 175762306a36Sopenharmony_ci status = ocrdma_add_mmap(srq->pd->uctx, uresp.rq_page_addr[0], 175862306a36Sopenharmony_ci uresp.rq_page_size); 175962306a36Sopenharmony_ci if (status) 176062306a36Sopenharmony_ci return status; 176162306a36Sopenharmony_ci return status; 176262306a36Sopenharmony_ci} 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ciint ocrdma_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init_attr, 176562306a36Sopenharmony_ci struct ib_udata *udata) 176662306a36Sopenharmony_ci{ 176762306a36Sopenharmony_ci int status; 176862306a36Sopenharmony_ci struct ocrdma_pd *pd = get_ocrdma_pd(ibsrq->pd); 176962306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibsrq->device); 177062306a36Sopenharmony_ci struct ocrdma_srq *srq = get_ocrdma_srq(ibsrq); 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci if (init_attr->srq_type != IB_SRQT_BASIC) 177362306a36Sopenharmony_ci return -EOPNOTSUPP; 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci if (init_attr->attr.max_sge > dev->attr.max_recv_sge) 177662306a36Sopenharmony_ci return -EINVAL; 177762306a36Sopenharmony_ci if (init_attr->attr.max_wr > dev->attr.max_rqe) 177862306a36Sopenharmony_ci return -EINVAL; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci spin_lock_init(&srq->q_lock); 178162306a36Sopenharmony_ci srq->pd = pd; 178262306a36Sopenharmony_ci srq->db = dev->nic_info.db + (pd->id * dev->nic_info.db_page_size); 178362306a36Sopenharmony_ci status = ocrdma_mbx_create_srq(dev, srq, init_attr, pd); 178462306a36Sopenharmony_ci if (status) 178562306a36Sopenharmony_ci return status; 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci if (!udata) { 178862306a36Sopenharmony_ci srq->rqe_wr_id_tbl = kcalloc(srq->rq.max_cnt, sizeof(u64), 178962306a36Sopenharmony_ci GFP_KERNEL); 179062306a36Sopenharmony_ci if (!srq->rqe_wr_id_tbl) { 179162306a36Sopenharmony_ci status = -ENOMEM; 179262306a36Sopenharmony_ci goto arm_err; 179362306a36Sopenharmony_ci } 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci srq->bit_fields_len = (srq->rq.max_cnt / 32) + 179662306a36Sopenharmony_ci (srq->rq.max_cnt % 32 ? 1 : 0); 179762306a36Sopenharmony_ci srq->idx_bit_fields = 179862306a36Sopenharmony_ci kmalloc_array(srq->bit_fields_len, sizeof(u32), 179962306a36Sopenharmony_ci GFP_KERNEL); 180062306a36Sopenharmony_ci if (!srq->idx_bit_fields) { 180162306a36Sopenharmony_ci status = -ENOMEM; 180262306a36Sopenharmony_ci goto arm_err; 180362306a36Sopenharmony_ci } 180462306a36Sopenharmony_ci memset(srq->idx_bit_fields, 0xff, 180562306a36Sopenharmony_ci srq->bit_fields_len * sizeof(u32)); 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci if (init_attr->attr.srq_limit) { 180962306a36Sopenharmony_ci status = ocrdma_mbx_modify_srq(srq, &init_attr->attr); 181062306a36Sopenharmony_ci if (status) 181162306a36Sopenharmony_ci goto arm_err; 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci if (udata) { 181562306a36Sopenharmony_ci status = ocrdma_copy_srq_uresp(dev, srq, udata); 181662306a36Sopenharmony_ci if (status) 181762306a36Sopenharmony_ci goto arm_err; 181862306a36Sopenharmony_ci } 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci return 0; 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ciarm_err: 182362306a36Sopenharmony_ci ocrdma_mbx_destroy_srq(dev, srq); 182462306a36Sopenharmony_ci kfree(srq->rqe_wr_id_tbl); 182562306a36Sopenharmony_ci kfree(srq->idx_bit_fields); 182662306a36Sopenharmony_ci return status; 182762306a36Sopenharmony_ci} 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ciint ocrdma_modify_srq(struct ib_srq *ibsrq, 183062306a36Sopenharmony_ci struct ib_srq_attr *srq_attr, 183162306a36Sopenharmony_ci enum ib_srq_attr_mask srq_attr_mask, 183262306a36Sopenharmony_ci struct ib_udata *udata) 183362306a36Sopenharmony_ci{ 183462306a36Sopenharmony_ci int status; 183562306a36Sopenharmony_ci struct ocrdma_srq *srq; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci srq = get_ocrdma_srq(ibsrq); 183862306a36Sopenharmony_ci if (srq_attr_mask & IB_SRQ_MAX_WR) 183962306a36Sopenharmony_ci status = -EINVAL; 184062306a36Sopenharmony_ci else 184162306a36Sopenharmony_ci status = ocrdma_mbx_modify_srq(srq, srq_attr); 184262306a36Sopenharmony_ci return status; 184362306a36Sopenharmony_ci} 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ciint ocrdma_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) 184662306a36Sopenharmony_ci{ 184762306a36Sopenharmony_ci struct ocrdma_srq *srq; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci srq = get_ocrdma_srq(ibsrq); 185062306a36Sopenharmony_ci return ocrdma_mbx_query_srq(srq, srq_attr); 185162306a36Sopenharmony_ci} 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ciint ocrdma_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata) 185462306a36Sopenharmony_ci{ 185562306a36Sopenharmony_ci struct ocrdma_srq *srq; 185662306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibsrq->device); 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci srq = get_ocrdma_srq(ibsrq); 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci ocrdma_mbx_destroy_srq(dev, srq); 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci if (srq->pd->uctx) 186362306a36Sopenharmony_ci ocrdma_del_mmap(srq->pd->uctx, (u64) srq->rq.pa, 186462306a36Sopenharmony_ci PAGE_ALIGN(srq->rq.len)); 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci kfree(srq->idx_bit_fields); 186762306a36Sopenharmony_ci kfree(srq->rqe_wr_id_tbl); 186862306a36Sopenharmony_ci return 0; 186962306a36Sopenharmony_ci} 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci/* unprivileged verbs and their support functions. */ 187262306a36Sopenharmony_cistatic void ocrdma_build_ud_hdr(struct ocrdma_qp *qp, 187362306a36Sopenharmony_ci struct ocrdma_hdr_wqe *hdr, 187462306a36Sopenharmony_ci const struct ib_send_wr *wr) 187562306a36Sopenharmony_ci{ 187662306a36Sopenharmony_ci struct ocrdma_ewqe_ud_hdr *ud_hdr = 187762306a36Sopenharmony_ci (struct ocrdma_ewqe_ud_hdr *)(hdr + 1); 187862306a36Sopenharmony_ci struct ocrdma_ah *ah = get_ocrdma_ah(ud_wr(wr)->ah); 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci ud_hdr->rsvd_dest_qpn = ud_wr(wr)->remote_qpn; 188162306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_GSI) 188262306a36Sopenharmony_ci ud_hdr->qkey = qp->qkey; 188362306a36Sopenharmony_ci else 188462306a36Sopenharmony_ci ud_hdr->qkey = ud_wr(wr)->remote_qkey; 188562306a36Sopenharmony_ci ud_hdr->rsvd_ahid = ah->id; 188662306a36Sopenharmony_ci ud_hdr->hdr_type = ah->hdr_type; 188762306a36Sopenharmony_ci if (ah->av->valid & OCRDMA_AV_VLAN_VALID) 188862306a36Sopenharmony_ci hdr->cw |= (OCRDMA_FLAG_AH_VLAN_PR << OCRDMA_WQE_FLAGS_SHIFT); 188962306a36Sopenharmony_ci} 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_cistatic void ocrdma_build_sges(struct ocrdma_hdr_wqe *hdr, 189262306a36Sopenharmony_ci struct ocrdma_sge *sge, int num_sge, 189362306a36Sopenharmony_ci struct ib_sge *sg_list) 189462306a36Sopenharmony_ci{ 189562306a36Sopenharmony_ci int i; 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci for (i = 0; i < num_sge; i++) { 189862306a36Sopenharmony_ci sge[i].lrkey = sg_list[i].lkey; 189962306a36Sopenharmony_ci sge[i].addr_lo = sg_list[i].addr; 190062306a36Sopenharmony_ci sge[i].addr_hi = upper_32_bits(sg_list[i].addr); 190162306a36Sopenharmony_ci sge[i].len = sg_list[i].length; 190262306a36Sopenharmony_ci hdr->total_len += sg_list[i].length; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci if (num_sge == 0) 190562306a36Sopenharmony_ci memset(sge, 0, sizeof(*sge)); 190662306a36Sopenharmony_ci} 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_cistatic inline uint32_t ocrdma_sglist_len(struct ib_sge *sg_list, int num_sge) 190962306a36Sopenharmony_ci{ 191062306a36Sopenharmony_ci uint32_t total_len = 0, i; 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci for (i = 0; i < num_sge; i++) 191362306a36Sopenharmony_ci total_len += sg_list[i].length; 191462306a36Sopenharmony_ci return total_len; 191562306a36Sopenharmony_ci} 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_cistatic int ocrdma_build_inline_sges(struct ocrdma_qp *qp, 191962306a36Sopenharmony_ci struct ocrdma_hdr_wqe *hdr, 192062306a36Sopenharmony_ci struct ocrdma_sge *sge, 192162306a36Sopenharmony_ci const struct ib_send_wr *wr, u32 wqe_size) 192262306a36Sopenharmony_ci{ 192362306a36Sopenharmony_ci int i; 192462306a36Sopenharmony_ci char *dpp_addr; 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_INLINE && qp->qp_type != IB_QPT_UD) { 192762306a36Sopenharmony_ci hdr->total_len = ocrdma_sglist_len(wr->sg_list, wr->num_sge); 192862306a36Sopenharmony_ci if (unlikely(hdr->total_len > qp->max_inline_data)) { 192962306a36Sopenharmony_ci pr_err("%s() supported_len=0x%x,\n" 193062306a36Sopenharmony_ci " unsupported len req=0x%x\n", __func__, 193162306a36Sopenharmony_ci qp->max_inline_data, hdr->total_len); 193262306a36Sopenharmony_ci return -EINVAL; 193362306a36Sopenharmony_ci } 193462306a36Sopenharmony_ci dpp_addr = (char *)sge; 193562306a36Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 193662306a36Sopenharmony_ci memcpy(dpp_addr, 193762306a36Sopenharmony_ci (void *)(unsigned long)wr->sg_list[i].addr, 193862306a36Sopenharmony_ci wr->sg_list[i].length); 193962306a36Sopenharmony_ci dpp_addr += wr->sg_list[i].length; 194062306a36Sopenharmony_ci } 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci wqe_size += roundup(hdr->total_len, OCRDMA_WQE_ALIGN_BYTES); 194362306a36Sopenharmony_ci if (0 == hdr->total_len) 194462306a36Sopenharmony_ci wqe_size += sizeof(struct ocrdma_sge); 194562306a36Sopenharmony_ci hdr->cw |= (OCRDMA_TYPE_INLINE << OCRDMA_WQE_TYPE_SHIFT); 194662306a36Sopenharmony_ci } else { 194762306a36Sopenharmony_ci ocrdma_build_sges(hdr, sge, wr->num_sge, wr->sg_list); 194862306a36Sopenharmony_ci if (wr->num_sge) 194962306a36Sopenharmony_ci wqe_size += (wr->num_sge * sizeof(struct ocrdma_sge)); 195062306a36Sopenharmony_ci else 195162306a36Sopenharmony_ci wqe_size += sizeof(struct ocrdma_sge); 195262306a36Sopenharmony_ci hdr->cw |= (OCRDMA_TYPE_LKEY << OCRDMA_WQE_TYPE_SHIFT); 195362306a36Sopenharmony_ci } 195462306a36Sopenharmony_ci hdr->cw |= ((wqe_size / OCRDMA_WQE_STRIDE) << OCRDMA_WQE_SIZE_SHIFT); 195562306a36Sopenharmony_ci return 0; 195662306a36Sopenharmony_ci} 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_cistatic int ocrdma_build_send(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr, 195962306a36Sopenharmony_ci const struct ib_send_wr *wr) 196062306a36Sopenharmony_ci{ 196162306a36Sopenharmony_ci struct ocrdma_sge *sge; 196262306a36Sopenharmony_ci u32 wqe_size = sizeof(*hdr); 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI) { 196562306a36Sopenharmony_ci ocrdma_build_ud_hdr(qp, hdr, wr); 196662306a36Sopenharmony_ci sge = (struct ocrdma_sge *)(hdr + 2); 196762306a36Sopenharmony_ci wqe_size += sizeof(struct ocrdma_ewqe_ud_hdr); 196862306a36Sopenharmony_ci } else { 196962306a36Sopenharmony_ci sge = (struct ocrdma_sge *)(hdr + 1); 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci return ocrdma_build_inline_sges(qp, hdr, sge, wr, wqe_size); 197362306a36Sopenharmony_ci} 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_cistatic int ocrdma_build_write(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr, 197662306a36Sopenharmony_ci const struct ib_send_wr *wr) 197762306a36Sopenharmony_ci{ 197862306a36Sopenharmony_ci int status; 197962306a36Sopenharmony_ci struct ocrdma_sge *ext_rw = (struct ocrdma_sge *)(hdr + 1); 198062306a36Sopenharmony_ci struct ocrdma_sge *sge = ext_rw + 1; 198162306a36Sopenharmony_ci u32 wqe_size = sizeof(*hdr) + sizeof(*ext_rw); 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci status = ocrdma_build_inline_sges(qp, hdr, sge, wr, wqe_size); 198462306a36Sopenharmony_ci if (status) 198562306a36Sopenharmony_ci return status; 198662306a36Sopenharmony_ci ext_rw->addr_lo = rdma_wr(wr)->remote_addr; 198762306a36Sopenharmony_ci ext_rw->addr_hi = upper_32_bits(rdma_wr(wr)->remote_addr); 198862306a36Sopenharmony_ci ext_rw->lrkey = rdma_wr(wr)->rkey; 198962306a36Sopenharmony_ci ext_rw->len = hdr->total_len; 199062306a36Sopenharmony_ci return 0; 199162306a36Sopenharmony_ci} 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_cistatic void ocrdma_build_read(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr, 199462306a36Sopenharmony_ci const struct ib_send_wr *wr) 199562306a36Sopenharmony_ci{ 199662306a36Sopenharmony_ci struct ocrdma_sge *ext_rw = (struct ocrdma_sge *)(hdr + 1); 199762306a36Sopenharmony_ci struct ocrdma_sge *sge = ext_rw + 1; 199862306a36Sopenharmony_ci u32 wqe_size = ((wr->num_sge + 1) * sizeof(struct ocrdma_sge)) + 199962306a36Sopenharmony_ci sizeof(struct ocrdma_hdr_wqe); 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci ocrdma_build_sges(hdr, sge, wr->num_sge, wr->sg_list); 200262306a36Sopenharmony_ci hdr->cw |= ((wqe_size / OCRDMA_WQE_STRIDE) << OCRDMA_WQE_SIZE_SHIFT); 200362306a36Sopenharmony_ci hdr->cw |= (OCRDMA_READ << OCRDMA_WQE_OPCODE_SHIFT); 200462306a36Sopenharmony_ci hdr->cw |= (OCRDMA_TYPE_LKEY << OCRDMA_WQE_TYPE_SHIFT); 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci ext_rw->addr_lo = rdma_wr(wr)->remote_addr; 200762306a36Sopenharmony_ci ext_rw->addr_hi = upper_32_bits(rdma_wr(wr)->remote_addr); 200862306a36Sopenharmony_ci ext_rw->lrkey = rdma_wr(wr)->rkey; 200962306a36Sopenharmony_ci ext_rw->len = hdr->total_len; 201062306a36Sopenharmony_ci} 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_cistatic int get_encoded_page_size(int pg_sz) 201362306a36Sopenharmony_ci{ 201462306a36Sopenharmony_ci /* Max size is 256M 4096 << 16 */ 201562306a36Sopenharmony_ci int i = 0; 201662306a36Sopenharmony_ci for (; i < 17; i++) 201762306a36Sopenharmony_ci if (pg_sz == (4096 << i)) 201862306a36Sopenharmony_ci break; 201962306a36Sopenharmony_ci return i; 202062306a36Sopenharmony_ci} 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_cistatic int ocrdma_build_reg(struct ocrdma_qp *qp, 202362306a36Sopenharmony_ci struct ocrdma_hdr_wqe *hdr, 202462306a36Sopenharmony_ci const struct ib_reg_wr *wr) 202562306a36Sopenharmony_ci{ 202662306a36Sopenharmony_ci u64 fbo; 202762306a36Sopenharmony_ci struct ocrdma_ewqe_fr *fast_reg = (struct ocrdma_ewqe_fr *)(hdr + 1); 202862306a36Sopenharmony_ci struct ocrdma_mr *mr = get_ocrdma_mr(wr->mr); 202962306a36Sopenharmony_ci struct ocrdma_pbl *pbl_tbl = mr->hwmr.pbl_table; 203062306a36Sopenharmony_ci struct ocrdma_pbe *pbe; 203162306a36Sopenharmony_ci u32 wqe_size = sizeof(*fast_reg) + sizeof(*hdr); 203262306a36Sopenharmony_ci int num_pbes = 0, i; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci wqe_size = roundup(wqe_size, OCRDMA_WQE_ALIGN_BYTES); 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci hdr->cw |= (OCRDMA_FR_MR << OCRDMA_WQE_OPCODE_SHIFT); 203762306a36Sopenharmony_ci hdr->cw |= ((wqe_size / OCRDMA_WQE_STRIDE) << OCRDMA_WQE_SIZE_SHIFT); 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci if (wr->access & IB_ACCESS_LOCAL_WRITE) 204062306a36Sopenharmony_ci hdr->rsvd_lkey_flags |= OCRDMA_LKEY_FLAG_LOCAL_WR; 204162306a36Sopenharmony_ci if (wr->access & IB_ACCESS_REMOTE_WRITE) 204262306a36Sopenharmony_ci hdr->rsvd_lkey_flags |= OCRDMA_LKEY_FLAG_REMOTE_WR; 204362306a36Sopenharmony_ci if (wr->access & IB_ACCESS_REMOTE_READ) 204462306a36Sopenharmony_ci hdr->rsvd_lkey_flags |= OCRDMA_LKEY_FLAG_REMOTE_RD; 204562306a36Sopenharmony_ci hdr->lkey = wr->key; 204662306a36Sopenharmony_ci hdr->total_len = mr->ibmr.length; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci fbo = mr->ibmr.iova - mr->pages[0]; 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci fast_reg->va_hi = upper_32_bits(mr->ibmr.iova); 205162306a36Sopenharmony_ci fast_reg->va_lo = (u32) (mr->ibmr.iova & 0xffffffff); 205262306a36Sopenharmony_ci fast_reg->fbo_hi = upper_32_bits(fbo); 205362306a36Sopenharmony_ci fast_reg->fbo_lo = (u32) fbo & 0xffffffff; 205462306a36Sopenharmony_ci fast_reg->num_sges = mr->npages; 205562306a36Sopenharmony_ci fast_reg->size_sge = get_encoded_page_size(mr->ibmr.page_size); 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci pbe = pbl_tbl->va; 205862306a36Sopenharmony_ci for (i = 0; i < mr->npages; i++) { 205962306a36Sopenharmony_ci u64 buf_addr = mr->pages[i]; 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci pbe->pa_lo = cpu_to_le32((u32) (buf_addr & PAGE_MASK)); 206262306a36Sopenharmony_ci pbe->pa_hi = cpu_to_le32((u32) upper_32_bits(buf_addr)); 206362306a36Sopenharmony_ci num_pbes += 1; 206462306a36Sopenharmony_ci pbe++; 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci /* if the pbl is full storing the pbes, 206762306a36Sopenharmony_ci * move to next pbl. 206862306a36Sopenharmony_ci */ 206962306a36Sopenharmony_ci if (num_pbes == (mr->hwmr.pbl_size/sizeof(u64))) { 207062306a36Sopenharmony_ci pbl_tbl++; 207162306a36Sopenharmony_ci pbe = (struct ocrdma_pbe *)pbl_tbl->va; 207262306a36Sopenharmony_ci } 207362306a36Sopenharmony_ci } 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci return 0; 207662306a36Sopenharmony_ci} 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_cistatic void ocrdma_ring_sq_db(struct ocrdma_qp *qp) 207962306a36Sopenharmony_ci{ 208062306a36Sopenharmony_ci u32 val = qp->sq.dbid | (1 << OCRDMA_DB_SQ_SHIFT); 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci iowrite32(val, qp->sq_db); 208362306a36Sopenharmony_ci} 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ciint ocrdma_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, 208662306a36Sopenharmony_ci const struct ib_send_wr **bad_wr) 208762306a36Sopenharmony_ci{ 208862306a36Sopenharmony_ci int status = 0; 208962306a36Sopenharmony_ci struct ocrdma_qp *qp = get_ocrdma_qp(ibqp); 209062306a36Sopenharmony_ci struct ocrdma_hdr_wqe *hdr; 209162306a36Sopenharmony_ci unsigned long flags; 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_ci spin_lock_irqsave(&qp->q_lock, flags); 209462306a36Sopenharmony_ci if (qp->state != OCRDMA_QPS_RTS && qp->state != OCRDMA_QPS_SQD) { 209562306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 209662306a36Sopenharmony_ci *bad_wr = wr; 209762306a36Sopenharmony_ci return -EINVAL; 209862306a36Sopenharmony_ci } 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci while (wr) { 210162306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_UD && 210262306a36Sopenharmony_ci (wr->opcode != IB_WR_SEND && 210362306a36Sopenharmony_ci wr->opcode != IB_WR_SEND_WITH_IMM)) { 210462306a36Sopenharmony_ci *bad_wr = wr; 210562306a36Sopenharmony_ci status = -EINVAL; 210662306a36Sopenharmony_ci break; 210762306a36Sopenharmony_ci } 210862306a36Sopenharmony_ci if (ocrdma_hwq_free_cnt(&qp->sq) == 0 || 210962306a36Sopenharmony_ci wr->num_sge > qp->sq.max_sges) { 211062306a36Sopenharmony_ci *bad_wr = wr; 211162306a36Sopenharmony_ci status = -ENOMEM; 211262306a36Sopenharmony_ci break; 211362306a36Sopenharmony_ci } 211462306a36Sopenharmony_ci hdr = ocrdma_hwq_head(&qp->sq); 211562306a36Sopenharmony_ci hdr->cw = 0; 211662306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_SIGNALED || qp->signaled) 211762306a36Sopenharmony_ci hdr->cw |= (OCRDMA_FLAG_SIG << OCRDMA_WQE_FLAGS_SHIFT); 211862306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_FENCE) 211962306a36Sopenharmony_ci hdr->cw |= 212062306a36Sopenharmony_ci (OCRDMA_FLAG_FENCE_L << OCRDMA_WQE_FLAGS_SHIFT); 212162306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_SOLICITED) 212262306a36Sopenharmony_ci hdr->cw |= 212362306a36Sopenharmony_ci (OCRDMA_FLAG_SOLICIT << OCRDMA_WQE_FLAGS_SHIFT); 212462306a36Sopenharmony_ci hdr->total_len = 0; 212562306a36Sopenharmony_ci switch (wr->opcode) { 212662306a36Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 212762306a36Sopenharmony_ci hdr->cw |= (OCRDMA_FLAG_IMM << OCRDMA_WQE_FLAGS_SHIFT); 212862306a36Sopenharmony_ci hdr->immdt = ntohl(wr->ex.imm_data); 212962306a36Sopenharmony_ci fallthrough; 213062306a36Sopenharmony_ci case IB_WR_SEND: 213162306a36Sopenharmony_ci hdr->cw |= (OCRDMA_SEND << OCRDMA_WQE_OPCODE_SHIFT); 213262306a36Sopenharmony_ci ocrdma_build_send(qp, hdr, wr); 213362306a36Sopenharmony_ci break; 213462306a36Sopenharmony_ci case IB_WR_SEND_WITH_INV: 213562306a36Sopenharmony_ci hdr->cw |= (OCRDMA_FLAG_INV << OCRDMA_WQE_FLAGS_SHIFT); 213662306a36Sopenharmony_ci hdr->cw |= (OCRDMA_SEND << OCRDMA_WQE_OPCODE_SHIFT); 213762306a36Sopenharmony_ci hdr->lkey = wr->ex.invalidate_rkey; 213862306a36Sopenharmony_ci status = ocrdma_build_send(qp, hdr, wr); 213962306a36Sopenharmony_ci break; 214062306a36Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 214162306a36Sopenharmony_ci hdr->cw |= (OCRDMA_FLAG_IMM << OCRDMA_WQE_FLAGS_SHIFT); 214262306a36Sopenharmony_ci hdr->immdt = ntohl(wr->ex.imm_data); 214362306a36Sopenharmony_ci fallthrough; 214462306a36Sopenharmony_ci case IB_WR_RDMA_WRITE: 214562306a36Sopenharmony_ci hdr->cw |= (OCRDMA_WRITE << OCRDMA_WQE_OPCODE_SHIFT); 214662306a36Sopenharmony_ci status = ocrdma_build_write(qp, hdr, wr); 214762306a36Sopenharmony_ci break; 214862306a36Sopenharmony_ci case IB_WR_RDMA_READ: 214962306a36Sopenharmony_ci ocrdma_build_read(qp, hdr, wr); 215062306a36Sopenharmony_ci break; 215162306a36Sopenharmony_ci case IB_WR_LOCAL_INV: 215262306a36Sopenharmony_ci hdr->cw |= 215362306a36Sopenharmony_ci (OCRDMA_LKEY_INV << OCRDMA_WQE_OPCODE_SHIFT); 215462306a36Sopenharmony_ci hdr->cw |= ((sizeof(struct ocrdma_hdr_wqe) + 215562306a36Sopenharmony_ci sizeof(struct ocrdma_sge)) / 215662306a36Sopenharmony_ci OCRDMA_WQE_STRIDE) << OCRDMA_WQE_SIZE_SHIFT; 215762306a36Sopenharmony_ci hdr->lkey = wr->ex.invalidate_rkey; 215862306a36Sopenharmony_ci break; 215962306a36Sopenharmony_ci case IB_WR_REG_MR: 216062306a36Sopenharmony_ci status = ocrdma_build_reg(qp, hdr, reg_wr(wr)); 216162306a36Sopenharmony_ci break; 216262306a36Sopenharmony_ci default: 216362306a36Sopenharmony_ci status = -EINVAL; 216462306a36Sopenharmony_ci break; 216562306a36Sopenharmony_ci } 216662306a36Sopenharmony_ci if (status) { 216762306a36Sopenharmony_ci *bad_wr = wr; 216862306a36Sopenharmony_ci break; 216962306a36Sopenharmony_ci } 217062306a36Sopenharmony_ci if (wr->send_flags & IB_SEND_SIGNALED || qp->signaled) 217162306a36Sopenharmony_ci qp->wqe_wr_id_tbl[qp->sq.head].signaled = 1; 217262306a36Sopenharmony_ci else 217362306a36Sopenharmony_ci qp->wqe_wr_id_tbl[qp->sq.head].signaled = 0; 217462306a36Sopenharmony_ci qp->wqe_wr_id_tbl[qp->sq.head].wrid = wr->wr_id; 217562306a36Sopenharmony_ci ocrdma_cpu_to_le32(hdr, ((hdr->cw >> OCRDMA_WQE_SIZE_SHIFT) & 217662306a36Sopenharmony_ci OCRDMA_WQE_SIZE_MASK) * OCRDMA_WQE_STRIDE); 217762306a36Sopenharmony_ci /* make sure wqe is written before adapter can access it */ 217862306a36Sopenharmony_ci wmb(); 217962306a36Sopenharmony_ci /* inform hw to start processing it */ 218062306a36Sopenharmony_ci ocrdma_ring_sq_db(qp); 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci /* update pointer, counter for next wr */ 218362306a36Sopenharmony_ci ocrdma_hwq_inc_head(&qp->sq); 218462306a36Sopenharmony_ci wr = wr->next; 218562306a36Sopenharmony_ci } 218662306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 218762306a36Sopenharmony_ci return status; 218862306a36Sopenharmony_ci} 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_cistatic void ocrdma_ring_rq_db(struct ocrdma_qp *qp) 219162306a36Sopenharmony_ci{ 219262306a36Sopenharmony_ci u32 val = qp->rq.dbid | (1 << OCRDMA_DB_RQ_SHIFT); 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci iowrite32(val, qp->rq_db); 219562306a36Sopenharmony_ci} 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_cistatic void ocrdma_build_rqe(struct ocrdma_hdr_wqe *rqe, 219862306a36Sopenharmony_ci const struct ib_recv_wr *wr, u16 tag) 219962306a36Sopenharmony_ci{ 220062306a36Sopenharmony_ci u32 wqe_size = 0; 220162306a36Sopenharmony_ci struct ocrdma_sge *sge; 220262306a36Sopenharmony_ci if (wr->num_sge) 220362306a36Sopenharmony_ci wqe_size = (wr->num_sge * sizeof(*sge)) + sizeof(*rqe); 220462306a36Sopenharmony_ci else 220562306a36Sopenharmony_ci wqe_size = sizeof(*sge) + sizeof(*rqe); 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci rqe->cw = ((wqe_size / OCRDMA_WQE_STRIDE) << 220862306a36Sopenharmony_ci OCRDMA_WQE_SIZE_SHIFT); 220962306a36Sopenharmony_ci rqe->cw |= (OCRDMA_FLAG_SIG << OCRDMA_WQE_FLAGS_SHIFT); 221062306a36Sopenharmony_ci rqe->cw |= (OCRDMA_TYPE_LKEY << OCRDMA_WQE_TYPE_SHIFT); 221162306a36Sopenharmony_ci rqe->total_len = 0; 221262306a36Sopenharmony_ci rqe->rsvd_tag = tag; 221362306a36Sopenharmony_ci sge = (struct ocrdma_sge *)(rqe + 1); 221462306a36Sopenharmony_ci ocrdma_build_sges(rqe, sge, wr->num_sge, wr->sg_list); 221562306a36Sopenharmony_ci ocrdma_cpu_to_le32(rqe, wqe_size); 221662306a36Sopenharmony_ci} 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ciint ocrdma_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, 221962306a36Sopenharmony_ci const struct ib_recv_wr **bad_wr) 222062306a36Sopenharmony_ci{ 222162306a36Sopenharmony_ci int status = 0; 222262306a36Sopenharmony_ci unsigned long flags; 222362306a36Sopenharmony_ci struct ocrdma_qp *qp = get_ocrdma_qp(ibqp); 222462306a36Sopenharmony_ci struct ocrdma_hdr_wqe *rqe; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci spin_lock_irqsave(&qp->q_lock, flags); 222762306a36Sopenharmony_ci if (qp->state == OCRDMA_QPS_RST || qp->state == OCRDMA_QPS_ERR) { 222862306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 222962306a36Sopenharmony_ci *bad_wr = wr; 223062306a36Sopenharmony_ci return -EINVAL; 223162306a36Sopenharmony_ci } 223262306a36Sopenharmony_ci while (wr) { 223362306a36Sopenharmony_ci if (ocrdma_hwq_free_cnt(&qp->rq) == 0 || 223462306a36Sopenharmony_ci wr->num_sge > qp->rq.max_sges) { 223562306a36Sopenharmony_ci *bad_wr = wr; 223662306a36Sopenharmony_ci status = -ENOMEM; 223762306a36Sopenharmony_ci break; 223862306a36Sopenharmony_ci } 223962306a36Sopenharmony_ci rqe = ocrdma_hwq_head(&qp->rq); 224062306a36Sopenharmony_ci ocrdma_build_rqe(rqe, wr, 0); 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci qp->rqe_wr_id_tbl[qp->rq.head] = wr->wr_id; 224362306a36Sopenharmony_ci /* make sure rqe is written before adapter can access it */ 224462306a36Sopenharmony_ci wmb(); 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci /* inform hw to start processing it */ 224762306a36Sopenharmony_ci ocrdma_ring_rq_db(qp); 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci /* update pointer, counter for next wr */ 225062306a36Sopenharmony_ci ocrdma_hwq_inc_head(&qp->rq); 225162306a36Sopenharmony_ci wr = wr->next; 225262306a36Sopenharmony_ci } 225362306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 225462306a36Sopenharmony_ci return status; 225562306a36Sopenharmony_ci} 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci/* cqe for srq's rqe can potentially arrive out of order. 225862306a36Sopenharmony_ci * index gives the entry in the shadow table where to store 225962306a36Sopenharmony_ci * the wr_id. tag/index is returned in cqe to reference back 226062306a36Sopenharmony_ci * for a given rqe. 226162306a36Sopenharmony_ci */ 226262306a36Sopenharmony_cistatic int ocrdma_srq_get_idx(struct ocrdma_srq *srq) 226362306a36Sopenharmony_ci{ 226462306a36Sopenharmony_ci int row = 0; 226562306a36Sopenharmony_ci int indx = 0; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci for (row = 0; row < srq->bit_fields_len; row++) { 226862306a36Sopenharmony_ci if (srq->idx_bit_fields[row]) { 226962306a36Sopenharmony_ci indx = ffs(srq->idx_bit_fields[row]); 227062306a36Sopenharmony_ci indx = (row * 32) + (indx - 1); 227162306a36Sopenharmony_ci BUG_ON(indx >= srq->rq.max_cnt); 227262306a36Sopenharmony_ci ocrdma_srq_toggle_bit(srq, indx); 227362306a36Sopenharmony_ci break; 227462306a36Sopenharmony_ci } 227562306a36Sopenharmony_ci } 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci BUG_ON(row == srq->bit_fields_len); 227862306a36Sopenharmony_ci return indx + 1; /* Use from index 1 */ 227962306a36Sopenharmony_ci} 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_cistatic void ocrdma_ring_srq_db(struct ocrdma_srq *srq) 228262306a36Sopenharmony_ci{ 228362306a36Sopenharmony_ci u32 val = srq->rq.dbid | (1 << 16); 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci iowrite32(val, srq->db + OCRDMA_DB_GEN2_SRQ_OFFSET); 228662306a36Sopenharmony_ci} 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ciint ocrdma_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, 228962306a36Sopenharmony_ci const struct ib_recv_wr **bad_wr) 229062306a36Sopenharmony_ci{ 229162306a36Sopenharmony_ci int status = 0; 229262306a36Sopenharmony_ci unsigned long flags; 229362306a36Sopenharmony_ci struct ocrdma_srq *srq; 229462306a36Sopenharmony_ci struct ocrdma_hdr_wqe *rqe; 229562306a36Sopenharmony_ci u16 tag; 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci srq = get_ocrdma_srq(ibsrq); 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci spin_lock_irqsave(&srq->q_lock, flags); 230062306a36Sopenharmony_ci while (wr) { 230162306a36Sopenharmony_ci if (ocrdma_hwq_free_cnt(&srq->rq) == 0 || 230262306a36Sopenharmony_ci wr->num_sge > srq->rq.max_sges) { 230362306a36Sopenharmony_ci status = -ENOMEM; 230462306a36Sopenharmony_ci *bad_wr = wr; 230562306a36Sopenharmony_ci break; 230662306a36Sopenharmony_ci } 230762306a36Sopenharmony_ci tag = ocrdma_srq_get_idx(srq); 230862306a36Sopenharmony_ci rqe = ocrdma_hwq_head(&srq->rq); 230962306a36Sopenharmony_ci ocrdma_build_rqe(rqe, wr, tag); 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci srq->rqe_wr_id_tbl[tag] = wr->wr_id; 231262306a36Sopenharmony_ci /* make sure rqe is written before adapter can perform DMA */ 231362306a36Sopenharmony_ci wmb(); 231462306a36Sopenharmony_ci /* inform hw to start processing it */ 231562306a36Sopenharmony_ci ocrdma_ring_srq_db(srq); 231662306a36Sopenharmony_ci /* update pointer, counter for next wr */ 231762306a36Sopenharmony_ci ocrdma_hwq_inc_head(&srq->rq); 231862306a36Sopenharmony_ci wr = wr->next; 231962306a36Sopenharmony_ci } 232062306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->q_lock, flags); 232162306a36Sopenharmony_ci return status; 232262306a36Sopenharmony_ci} 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_cistatic enum ib_wc_status ocrdma_to_ibwc_err(u16 status) 232562306a36Sopenharmony_ci{ 232662306a36Sopenharmony_ci enum ib_wc_status ibwc_status; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci switch (status) { 232962306a36Sopenharmony_ci case OCRDMA_CQE_GENERAL_ERR: 233062306a36Sopenharmony_ci ibwc_status = IB_WC_GENERAL_ERR; 233162306a36Sopenharmony_ci break; 233262306a36Sopenharmony_ci case OCRDMA_CQE_LOC_LEN_ERR: 233362306a36Sopenharmony_ci ibwc_status = IB_WC_LOC_LEN_ERR; 233462306a36Sopenharmony_ci break; 233562306a36Sopenharmony_ci case OCRDMA_CQE_LOC_QP_OP_ERR: 233662306a36Sopenharmony_ci ibwc_status = IB_WC_LOC_QP_OP_ERR; 233762306a36Sopenharmony_ci break; 233862306a36Sopenharmony_ci case OCRDMA_CQE_LOC_EEC_OP_ERR: 233962306a36Sopenharmony_ci ibwc_status = IB_WC_LOC_EEC_OP_ERR; 234062306a36Sopenharmony_ci break; 234162306a36Sopenharmony_ci case OCRDMA_CQE_LOC_PROT_ERR: 234262306a36Sopenharmony_ci ibwc_status = IB_WC_LOC_PROT_ERR; 234362306a36Sopenharmony_ci break; 234462306a36Sopenharmony_ci case OCRDMA_CQE_WR_FLUSH_ERR: 234562306a36Sopenharmony_ci ibwc_status = IB_WC_WR_FLUSH_ERR; 234662306a36Sopenharmony_ci break; 234762306a36Sopenharmony_ci case OCRDMA_CQE_MW_BIND_ERR: 234862306a36Sopenharmony_ci ibwc_status = IB_WC_MW_BIND_ERR; 234962306a36Sopenharmony_ci break; 235062306a36Sopenharmony_ci case OCRDMA_CQE_BAD_RESP_ERR: 235162306a36Sopenharmony_ci ibwc_status = IB_WC_BAD_RESP_ERR; 235262306a36Sopenharmony_ci break; 235362306a36Sopenharmony_ci case OCRDMA_CQE_LOC_ACCESS_ERR: 235462306a36Sopenharmony_ci ibwc_status = IB_WC_LOC_ACCESS_ERR; 235562306a36Sopenharmony_ci break; 235662306a36Sopenharmony_ci case OCRDMA_CQE_REM_INV_REQ_ERR: 235762306a36Sopenharmony_ci ibwc_status = IB_WC_REM_INV_REQ_ERR; 235862306a36Sopenharmony_ci break; 235962306a36Sopenharmony_ci case OCRDMA_CQE_REM_ACCESS_ERR: 236062306a36Sopenharmony_ci ibwc_status = IB_WC_REM_ACCESS_ERR; 236162306a36Sopenharmony_ci break; 236262306a36Sopenharmony_ci case OCRDMA_CQE_REM_OP_ERR: 236362306a36Sopenharmony_ci ibwc_status = IB_WC_REM_OP_ERR; 236462306a36Sopenharmony_ci break; 236562306a36Sopenharmony_ci case OCRDMA_CQE_RETRY_EXC_ERR: 236662306a36Sopenharmony_ci ibwc_status = IB_WC_RETRY_EXC_ERR; 236762306a36Sopenharmony_ci break; 236862306a36Sopenharmony_ci case OCRDMA_CQE_RNR_RETRY_EXC_ERR: 236962306a36Sopenharmony_ci ibwc_status = IB_WC_RNR_RETRY_EXC_ERR; 237062306a36Sopenharmony_ci break; 237162306a36Sopenharmony_ci case OCRDMA_CQE_LOC_RDD_VIOL_ERR: 237262306a36Sopenharmony_ci ibwc_status = IB_WC_LOC_RDD_VIOL_ERR; 237362306a36Sopenharmony_ci break; 237462306a36Sopenharmony_ci case OCRDMA_CQE_REM_INV_RD_REQ_ERR: 237562306a36Sopenharmony_ci ibwc_status = IB_WC_REM_INV_RD_REQ_ERR; 237662306a36Sopenharmony_ci break; 237762306a36Sopenharmony_ci case OCRDMA_CQE_REM_ABORT_ERR: 237862306a36Sopenharmony_ci ibwc_status = IB_WC_REM_ABORT_ERR; 237962306a36Sopenharmony_ci break; 238062306a36Sopenharmony_ci case OCRDMA_CQE_INV_EECN_ERR: 238162306a36Sopenharmony_ci ibwc_status = IB_WC_INV_EECN_ERR; 238262306a36Sopenharmony_ci break; 238362306a36Sopenharmony_ci case OCRDMA_CQE_INV_EEC_STATE_ERR: 238462306a36Sopenharmony_ci ibwc_status = IB_WC_INV_EEC_STATE_ERR; 238562306a36Sopenharmony_ci break; 238662306a36Sopenharmony_ci case OCRDMA_CQE_FATAL_ERR: 238762306a36Sopenharmony_ci ibwc_status = IB_WC_FATAL_ERR; 238862306a36Sopenharmony_ci break; 238962306a36Sopenharmony_ci case OCRDMA_CQE_RESP_TIMEOUT_ERR: 239062306a36Sopenharmony_ci ibwc_status = IB_WC_RESP_TIMEOUT_ERR; 239162306a36Sopenharmony_ci break; 239262306a36Sopenharmony_ci default: 239362306a36Sopenharmony_ci ibwc_status = IB_WC_GENERAL_ERR; 239462306a36Sopenharmony_ci break; 239562306a36Sopenharmony_ci } 239662306a36Sopenharmony_ci return ibwc_status; 239762306a36Sopenharmony_ci} 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_cistatic void ocrdma_update_wc(struct ocrdma_qp *qp, struct ib_wc *ibwc, 240062306a36Sopenharmony_ci u32 wqe_idx) 240162306a36Sopenharmony_ci{ 240262306a36Sopenharmony_ci struct ocrdma_hdr_wqe *hdr; 240362306a36Sopenharmony_ci struct ocrdma_sge *rw; 240462306a36Sopenharmony_ci int opcode; 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci hdr = ocrdma_hwq_head_from_idx(&qp->sq, wqe_idx); 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci ibwc->wr_id = qp->wqe_wr_id_tbl[wqe_idx].wrid; 240962306a36Sopenharmony_ci /* Undo the hdr->cw swap */ 241062306a36Sopenharmony_ci opcode = le32_to_cpu(hdr->cw) & OCRDMA_WQE_OPCODE_MASK; 241162306a36Sopenharmony_ci switch (opcode) { 241262306a36Sopenharmony_ci case OCRDMA_WRITE: 241362306a36Sopenharmony_ci ibwc->opcode = IB_WC_RDMA_WRITE; 241462306a36Sopenharmony_ci break; 241562306a36Sopenharmony_ci case OCRDMA_READ: 241662306a36Sopenharmony_ci rw = (struct ocrdma_sge *)(hdr + 1); 241762306a36Sopenharmony_ci ibwc->opcode = IB_WC_RDMA_READ; 241862306a36Sopenharmony_ci ibwc->byte_len = rw->len; 241962306a36Sopenharmony_ci break; 242062306a36Sopenharmony_ci case OCRDMA_SEND: 242162306a36Sopenharmony_ci ibwc->opcode = IB_WC_SEND; 242262306a36Sopenharmony_ci break; 242362306a36Sopenharmony_ci case OCRDMA_FR_MR: 242462306a36Sopenharmony_ci ibwc->opcode = IB_WC_REG_MR; 242562306a36Sopenharmony_ci break; 242662306a36Sopenharmony_ci case OCRDMA_LKEY_INV: 242762306a36Sopenharmony_ci ibwc->opcode = IB_WC_LOCAL_INV; 242862306a36Sopenharmony_ci break; 242962306a36Sopenharmony_ci default: 243062306a36Sopenharmony_ci ibwc->status = IB_WC_GENERAL_ERR; 243162306a36Sopenharmony_ci pr_err("%s() invalid opcode received = 0x%x\n", 243262306a36Sopenharmony_ci __func__, hdr->cw & OCRDMA_WQE_OPCODE_MASK); 243362306a36Sopenharmony_ci break; 243462306a36Sopenharmony_ci } 243562306a36Sopenharmony_ci} 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_cistatic void ocrdma_set_cqe_status_flushed(struct ocrdma_qp *qp, 243862306a36Sopenharmony_ci struct ocrdma_cqe *cqe) 243962306a36Sopenharmony_ci{ 244062306a36Sopenharmony_ci if (is_cqe_for_sq(cqe)) { 244162306a36Sopenharmony_ci cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu( 244262306a36Sopenharmony_ci cqe->flags_status_srcqpn) & 244362306a36Sopenharmony_ci ~OCRDMA_CQE_STATUS_MASK); 244462306a36Sopenharmony_ci cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu( 244562306a36Sopenharmony_ci cqe->flags_status_srcqpn) | 244662306a36Sopenharmony_ci (OCRDMA_CQE_WR_FLUSH_ERR << 244762306a36Sopenharmony_ci OCRDMA_CQE_STATUS_SHIFT)); 244862306a36Sopenharmony_ci } else { 244962306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI) { 245062306a36Sopenharmony_ci cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu( 245162306a36Sopenharmony_ci cqe->flags_status_srcqpn) & 245262306a36Sopenharmony_ci ~OCRDMA_CQE_UD_STATUS_MASK); 245362306a36Sopenharmony_ci cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu( 245462306a36Sopenharmony_ci cqe->flags_status_srcqpn) | 245562306a36Sopenharmony_ci (OCRDMA_CQE_WR_FLUSH_ERR << 245662306a36Sopenharmony_ci OCRDMA_CQE_UD_STATUS_SHIFT)); 245762306a36Sopenharmony_ci } else { 245862306a36Sopenharmony_ci cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu( 245962306a36Sopenharmony_ci cqe->flags_status_srcqpn) & 246062306a36Sopenharmony_ci ~OCRDMA_CQE_STATUS_MASK); 246162306a36Sopenharmony_ci cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu( 246262306a36Sopenharmony_ci cqe->flags_status_srcqpn) | 246362306a36Sopenharmony_ci (OCRDMA_CQE_WR_FLUSH_ERR << 246462306a36Sopenharmony_ci OCRDMA_CQE_STATUS_SHIFT)); 246562306a36Sopenharmony_ci } 246662306a36Sopenharmony_ci } 246762306a36Sopenharmony_ci} 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_cistatic bool ocrdma_update_err_cqe(struct ib_wc *ibwc, struct ocrdma_cqe *cqe, 247062306a36Sopenharmony_ci struct ocrdma_qp *qp, int status) 247162306a36Sopenharmony_ci{ 247262306a36Sopenharmony_ci bool expand = false; 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci ibwc->byte_len = 0; 247562306a36Sopenharmony_ci ibwc->qp = &qp->ibqp; 247662306a36Sopenharmony_ci ibwc->status = ocrdma_to_ibwc_err(status); 247762306a36Sopenharmony_ci 247862306a36Sopenharmony_ci ocrdma_flush_qp(qp); 247962306a36Sopenharmony_ci ocrdma_qp_state_change(qp, IB_QPS_ERR, NULL); 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci /* if wqe/rqe pending for which cqe needs to be returned, 248262306a36Sopenharmony_ci * trigger inflating it. 248362306a36Sopenharmony_ci */ 248462306a36Sopenharmony_ci if (!is_hw_rq_empty(qp) || !is_hw_sq_empty(qp)) { 248562306a36Sopenharmony_ci expand = true; 248662306a36Sopenharmony_ci ocrdma_set_cqe_status_flushed(qp, cqe); 248762306a36Sopenharmony_ci } 248862306a36Sopenharmony_ci return expand; 248962306a36Sopenharmony_ci} 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_cistatic int ocrdma_update_err_rcqe(struct ib_wc *ibwc, struct ocrdma_cqe *cqe, 249262306a36Sopenharmony_ci struct ocrdma_qp *qp, int status) 249362306a36Sopenharmony_ci{ 249462306a36Sopenharmony_ci ibwc->opcode = IB_WC_RECV; 249562306a36Sopenharmony_ci ibwc->wr_id = qp->rqe_wr_id_tbl[qp->rq.tail]; 249662306a36Sopenharmony_ci ocrdma_hwq_inc_tail(&qp->rq); 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci return ocrdma_update_err_cqe(ibwc, cqe, qp, status); 249962306a36Sopenharmony_ci} 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_cistatic int ocrdma_update_err_scqe(struct ib_wc *ibwc, struct ocrdma_cqe *cqe, 250262306a36Sopenharmony_ci struct ocrdma_qp *qp, int status) 250362306a36Sopenharmony_ci{ 250462306a36Sopenharmony_ci ocrdma_update_wc(qp, ibwc, qp->sq.tail); 250562306a36Sopenharmony_ci ocrdma_hwq_inc_tail(&qp->sq); 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci return ocrdma_update_err_cqe(ibwc, cqe, qp, status); 250862306a36Sopenharmony_ci} 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_cistatic bool ocrdma_poll_err_scqe(struct ocrdma_qp *qp, 251262306a36Sopenharmony_ci struct ocrdma_cqe *cqe, struct ib_wc *ibwc, 251362306a36Sopenharmony_ci bool *polled, bool *stop) 251462306a36Sopenharmony_ci{ 251562306a36Sopenharmony_ci bool expand; 251662306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device); 251762306a36Sopenharmony_ci int status = (le32_to_cpu(cqe->flags_status_srcqpn) & 251862306a36Sopenharmony_ci OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT; 251962306a36Sopenharmony_ci if (status < OCRDMA_MAX_CQE_ERR) 252062306a36Sopenharmony_ci atomic_inc(&dev->cqe_err_stats[status]); 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci /* when hw sq is empty, but rq is not empty, so we continue 252362306a36Sopenharmony_ci * to keep the cqe in order to get the cq event again. 252462306a36Sopenharmony_ci */ 252562306a36Sopenharmony_ci if (is_hw_sq_empty(qp) && !is_hw_rq_empty(qp)) { 252662306a36Sopenharmony_ci /* when cq for rq and sq is same, it is safe to return 252762306a36Sopenharmony_ci * flush cqe for RQEs. 252862306a36Sopenharmony_ci */ 252962306a36Sopenharmony_ci if (!qp->srq && (qp->sq_cq == qp->rq_cq)) { 253062306a36Sopenharmony_ci *polled = true; 253162306a36Sopenharmony_ci status = OCRDMA_CQE_WR_FLUSH_ERR; 253262306a36Sopenharmony_ci expand = ocrdma_update_err_rcqe(ibwc, cqe, qp, status); 253362306a36Sopenharmony_ci } else { 253462306a36Sopenharmony_ci /* stop processing further cqe as this cqe is used for 253562306a36Sopenharmony_ci * triggering cq event on buddy cq of RQ. 253662306a36Sopenharmony_ci * When QP is destroyed, this cqe will be removed 253762306a36Sopenharmony_ci * from the cq's hardware q. 253862306a36Sopenharmony_ci */ 253962306a36Sopenharmony_ci *polled = false; 254062306a36Sopenharmony_ci *stop = true; 254162306a36Sopenharmony_ci expand = false; 254262306a36Sopenharmony_ci } 254362306a36Sopenharmony_ci } else if (is_hw_sq_empty(qp)) { 254462306a36Sopenharmony_ci /* Do nothing */ 254562306a36Sopenharmony_ci expand = false; 254662306a36Sopenharmony_ci *polled = false; 254762306a36Sopenharmony_ci *stop = false; 254862306a36Sopenharmony_ci } else { 254962306a36Sopenharmony_ci *polled = true; 255062306a36Sopenharmony_ci expand = ocrdma_update_err_scqe(ibwc, cqe, qp, status); 255162306a36Sopenharmony_ci } 255262306a36Sopenharmony_ci return expand; 255362306a36Sopenharmony_ci} 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_cistatic bool ocrdma_poll_success_scqe(struct ocrdma_qp *qp, 255662306a36Sopenharmony_ci struct ocrdma_cqe *cqe, 255762306a36Sopenharmony_ci struct ib_wc *ibwc, bool *polled) 255862306a36Sopenharmony_ci{ 255962306a36Sopenharmony_ci bool expand = false; 256062306a36Sopenharmony_ci int tail = qp->sq.tail; 256162306a36Sopenharmony_ci u32 wqe_idx; 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci if (!qp->wqe_wr_id_tbl[tail].signaled) { 256462306a36Sopenharmony_ci *polled = false; /* WC cannot be consumed yet */ 256562306a36Sopenharmony_ci } else { 256662306a36Sopenharmony_ci ibwc->status = IB_WC_SUCCESS; 256762306a36Sopenharmony_ci ibwc->wc_flags = 0; 256862306a36Sopenharmony_ci ibwc->qp = &qp->ibqp; 256962306a36Sopenharmony_ci ocrdma_update_wc(qp, ibwc, tail); 257062306a36Sopenharmony_ci *polled = true; 257162306a36Sopenharmony_ci } 257262306a36Sopenharmony_ci wqe_idx = (le32_to_cpu(cqe->wq.wqeidx) & 257362306a36Sopenharmony_ci OCRDMA_CQE_WQEIDX_MASK) & qp->sq.max_wqe_idx; 257462306a36Sopenharmony_ci if (tail != wqe_idx) 257562306a36Sopenharmony_ci expand = true; /* Coalesced CQE can't be consumed yet */ 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci ocrdma_hwq_inc_tail(&qp->sq); 257862306a36Sopenharmony_ci return expand; 257962306a36Sopenharmony_ci} 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_cistatic bool ocrdma_poll_scqe(struct ocrdma_qp *qp, struct ocrdma_cqe *cqe, 258262306a36Sopenharmony_ci struct ib_wc *ibwc, bool *polled, bool *stop) 258362306a36Sopenharmony_ci{ 258462306a36Sopenharmony_ci int status; 258562306a36Sopenharmony_ci bool expand; 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci status = (le32_to_cpu(cqe->flags_status_srcqpn) & 258862306a36Sopenharmony_ci OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT; 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci if (status == OCRDMA_CQE_SUCCESS) 259162306a36Sopenharmony_ci expand = ocrdma_poll_success_scqe(qp, cqe, ibwc, polled); 259262306a36Sopenharmony_ci else 259362306a36Sopenharmony_ci expand = ocrdma_poll_err_scqe(qp, cqe, ibwc, polled, stop); 259462306a36Sopenharmony_ci return expand; 259562306a36Sopenharmony_ci} 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_cistatic int ocrdma_update_ud_rcqe(struct ocrdma_dev *dev, struct ib_wc *ibwc, 259862306a36Sopenharmony_ci struct ocrdma_cqe *cqe) 259962306a36Sopenharmony_ci{ 260062306a36Sopenharmony_ci int status; 260162306a36Sopenharmony_ci u16 hdr_type = 0; 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci status = (le32_to_cpu(cqe->flags_status_srcqpn) & 260462306a36Sopenharmony_ci OCRDMA_CQE_UD_STATUS_MASK) >> OCRDMA_CQE_UD_STATUS_SHIFT; 260562306a36Sopenharmony_ci ibwc->src_qp = le32_to_cpu(cqe->flags_status_srcqpn) & 260662306a36Sopenharmony_ci OCRDMA_CQE_SRCQP_MASK; 260762306a36Sopenharmony_ci ibwc->pkey_index = 0; 260862306a36Sopenharmony_ci ibwc->wc_flags = IB_WC_GRH; 260962306a36Sopenharmony_ci ibwc->byte_len = (le32_to_cpu(cqe->ud.rxlen_pkey) >> 261062306a36Sopenharmony_ci OCRDMA_CQE_UD_XFER_LEN_SHIFT) & 261162306a36Sopenharmony_ci OCRDMA_CQE_UD_XFER_LEN_MASK; 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci if (ocrdma_is_udp_encap_supported(dev)) { 261462306a36Sopenharmony_ci hdr_type = (le32_to_cpu(cqe->ud.rxlen_pkey) >> 261562306a36Sopenharmony_ci OCRDMA_CQE_UD_L3TYPE_SHIFT) & 261662306a36Sopenharmony_ci OCRDMA_CQE_UD_L3TYPE_MASK; 261762306a36Sopenharmony_ci ibwc->wc_flags |= IB_WC_WITH_NETWORK_HDR_TYPE; 261862306a36Sopenharmony_ci ibwc->network_hdr_type = hdr_type; 261962306a36Sopenharmony_ci } 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci return status; 262262306a36Sopenharmony_ci} 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_cistatic void ocrdma_update_free_srq_cqe(struct ib_wc *ibwc, 262562306a36Sopenharmony_ci struct ocrdma_cqe *cqe, 262662306a36Sopenharmony_ci struct ocrdma_qp *qp) 262762306a36Sopenharmony_ci{ 262862306a36Sopenharmony_ci unsigned long flags; 262962306a36Sopenharmony_ci struct ocrdma_srq *srq; 263062306a36Sopenharmony_ci u32 wqe_idx; 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci srq = get_ocrdma_srq(qp->ibqp.srq); 263362306a36Sopenharmony_ci wqe_idx = (le32_to_cpu(cqe->rq.buftag_qpn) >> 263462306a36Sopenharmony_ci OCRDMA_CQE_BUFTAG_SHIFT) & srq->rq.max_wqe_idx; 263562306a36Sopenharmony_ci BUG_ON(wqe_idx < 1); 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_ci ibwc->wr_id = srq->rqe_wr_id_tbl[wqe_idx]; 263862306a36Sopenharmony_ci spin_lock_irqsave(&srq->q_lock, flags); 263962306a36Sopenharmony_ci ocrdma_srq_toggle_bit(srq, wqe_idx - 1); 264062306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->q_lock, flags); 264162306a36Sopenharmony_ci ocrdma_hwq_inc_tail(&srq->rq); 264262306a36Sopenharmony_ci} 264362306a36Sopenharmony_ci 264462306a36Sopenharmony_cistatic bool ocrdma_poll_err_rcqe(struct ocrdma_qp *qp, struct ocrdma_cqe *cqe, 264562306a36Sopenharmony_ci struct ib_wc *ibwc, bool *polled, bool *stop, 264662306a36Sopenharmony_ci int status) 264762306a36Sopenharmony_ci{ 264862306a36Sopenharmony_ci bool expand; 264962306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device); 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci if (status < OCRDMA_MAX_CQE_ERR) 265262306a36Sopenharmony_ci atomic_inc(&dev->cqe_err_stats[status]); 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci /* when hw_rq is empty, but wq is not empty, so continue 265562306a36Sopenharmony_ci * to keep the cqe to get the cq event again. 265662306a36Sopenharmony_ci */ 265762306a36Sopenharmony_ci if (is_hw_rq_empty(qp) && !is_hw_sq_empty(qp)) { 265862306a36Sopenharmony_ci if (!qp->srq && (qp->sq_cq == qp->rq_cq)) { 265962306a36Sopenharmony_ci *polled = true; 266062306a36Sopenharmony_ci status = OCRDMA_CQE_WR_FLUSH_ERR; 266162306a36Sopenharmony_ci expand = ocrdma_update_err_scqe(ibwc, cqe, qp, status); 266262306a36Sopenharmony_ci } else { 266362306a36Sopenharmony_ci *polled = false; 266462306a36Sopenharmony_ci *stop = true; 266562306a36Sopenharmony_ci expand = false; 266662306a36Sopenharmony_ci } 266762306a36Sopenharmony_ci } else if (is_hw_rq_empty(qp)) { 266862306a36Sopenharmony_ci /* Do nothing */ 266962306a36Sopenharmony_ci expand = false; 267062306a36Sopenharmony_ci *polled = false; 267162306a36Sopenharmony_ci *stop = false; 267262306a36Sopenharmony_ci } else { 267362306a36Sopenharmony_ci *polled = true; 267462306a36Sopenharmony_ci expand = ocrdma_update_err_rcqe(ibwc, cqe, qp, status); 267562306a36Sopenharmony_ci } 267662306a36Sopenharmony_ci return expand; 267762306a36Sopenharmony_ci} 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_cistatic void ocrdma_poll_success_rcqe(struct ocrdma_qp *qp, 268062306a36Sopenharmony_ci struct ocrdma_cqe *cqe, struct ib_wc *ibwc) 268162306a36Sopenharmony_ci{ 268262306a36Sopenharmony_ci struct ocrdma_dev *dev; 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci dev = get_ocrdma_dev(qp->ibqp.device); 268562306a36Sopenharmony_ci ibwc->opcode = IB_WC_RECV; 268662306a36Sopenharmony_ci ibwc->qp = &qp->ibqp; 268762306a36Sopenharmony_ci ibwc->status = IB_WC_SUCCESS; 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI) 269062306a36Sopenharmony_ci ocrdma_update_ud_rcqe(dev, ibwc, cqe); 269162306a36Sopenharmony_ci else 269262306a36Sopenharmony_ci ibwc->byte_len = le32_to_cpu(cqe->rq.rxlen); 269362306a36Sopenharmony_ci 269462306a36Sopenharmony_ci if (is_cqe_imm(cqe)) { 269562306a36Sopenharmony_ci ibwc->ex.imm_data = htonl(le32_to_cpu(cqe->rq.lkey_immdt)); 269662306a36Sopenharmony_ci ibwc->wc_flags |= IB_WC_WITH_IMM; 269762306a36Sopenharmony_ci } else if (is_cqe_wr_imm(cqe)) { 269862306a36Sopenharmony_ci ibwc->opcode = IB_WC_RECV_RDMA_WITH_IMM; 269962306a36Sopenharmony_ci ibwc->ex.imm_data = htonl(le32_to_cpu(cqe->rq.lkey_immdt)); 270062306a36Sopenharmony_ci ibwc->wc_flags |= IB_WC_WITH_IMM; 270162306a36Sopenharmony_ci } else if (is_cqe_invalidated(cqe)) { 270262306a36Sopenharmony_ci ibwc->ex.invalidate_rkey = le32_to_cpu(cqe->rq.lkey_immdt); 270362306a36Sopenharmony_ci ibwc->wc_flags |= IB_WC_WITH_INVALIDATE; 270462306a36Sopenharmony_ci } 270562306a36Sopenharmony_ci if (qp->ibqp.srq) { 270662306a36Sopenharmony_ci ocrdma_update_free_srq_cqe(ibwc, cqe, qp); 270762306a36Sopenharmony_ci } else { 270862306a36Sopenharmony_ci ibwc->wr_id = qp->rqe_wr_id_tbl[qp->rq.tail]; 270962306a36Sopenharmony_ci ocrdma_hwq_inc_tail(&qp->rq); 271062306a36Sopenharmony_ci } 271162306a36Sopenharmony_ci} 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_cistatic bool ocrdma_poll_rcqe(struct ocrdma_qp *qp, struct ocrdma_cqe *cqe, 271462306a36Sopenharmony_ci struct ib_wc *ibwc, bool *polled, bool *stop) 271562306a36Sopenharmony_ci{ 271662306a36Sopenharmony_ci int status; 271762306a36Sopenharmony_ci bool expand = false; 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci ibwc->wc_flags = 0; 272062306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI) { 272162306a36Sopenharmony_ci status = (le32_to_cpu(cqe->flags_status_srcqpn) & 272262306a36Sopenharmony_ci OCRDMA_CQE_UD_STATUS_MASK) >> 272362306a36Sopenharmony_ci OCRDMA_CQE_UD_STATUS_SHIFT; 272462306a36Sopenharmony_ci } else { 272562306a36Sopenharmony_ci status = (le32_to_cpu(cqe->flags_status_srcqpn) & 272662306a36Sopenharmony_ci OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT; 272762306a36Sopenharmony_ci } 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci if (status == OCRDMA_CQE_SUCCESS) { 273062306a36Sopenharmony_ci *polled = true; 273162306a36Sopenharmony_ci ocrdma_poll_success_rcqe(qp, cqe, ibwc); 273262306a36Sopenharmony_ci } else { 273362306a36Sopenharmony_ci expand = ocrdma_poll_err_rcqe(qp, cqe, ibwc, polled, stop, 273462306a36Sopenharmony_ci status); 273562306a36Sopenharmony_ci } 273662306a36Sopenharmony_ci return expand; 273762306a36Sopenharmony_ci} 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_cistatic void ocrdma_change_cq_phase(struct ocrdma_cq *cq, struct ocrdma_cqe *cqe, 274062306a36Sopenharmony_ci u16 cur_getp) 274162306a36Sopenharmony_ci{ 274262306a36Sopenharmony_ci if (cq->phase_change) { 274362306a36Sopenharmony_ci if (cur_getp == 0) 274462306a36Sopenharmony_ci cq->phase = (~cq->phase & OCRDMA_CQE_VALID); 274562306a36Sopenharmony_ci } else { 274662306a36Sopenharmony_ci /* clear valid bit */ 274762306a36Sopenharmony_ci cqe->flags_status_srcqpn = 0; 274862306a36Sopenharmony_ci } 274962306a36Sopenharmony_ci} 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_cistatic int ocrdma_poll_hwcq(struct ocrdma_cq *cq, int num_entries, 275262306a36Sopenharmony_ci struct ib_wc *ibwc) 275362306a36Sopenharmony_ci{ 275462306a36Sopenharmony_ci u16 qpn = 0; 275562306a36Sopenharmony_ci int i = 0; 275662306a36Sopenharmony_ci bool expand = false; 275762306a36Sopenharmony_ci int polled_hw_cqes = 0; 275862306a36Sopenharmony_ci struct ocrdma_qp *qp = NULL; 275962306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(cq->ibcq.device); 276062306a36Sopenharmony_ci struct ocrdma_cqe *cqe; 276162306a36Sopenharmony_ci u16 cur_getp; bool polled = false; bool stop = false; 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci cur_getp = cq->getp; 276462306a36Sopenharmony_ci while (num_entries) { 276562306a36Sopenharmony_ci cqe = cq->va + cur_getp; 276662306a36Sopenharmony_ci /* check whether valid cqe or not */ 276762306a36Sopenharmony_ci if (!is_cqe_valid(cq, cqe)) 276862306a36Sopenharmony_ci break; 276962306a36Sopenharmony_ci qpn = (le32_to_cpu(cqe->cmn.qpn) & OCRDMA_CQE_QPN_MASK); 277062306a36Sopenharmony_ci /* ignore discarded cqe */ 277162306a36Sopenharmony_ci if (qpn == 0) 277262306a36Sopenharmony_ci goto skip_cqe; 277362306a36Sopenharmony_ci qp = dev->qp_tbl[qpn]; 277462306a36Sopenharmony_ci BUG_ON(qp == NULL); 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci if (is_cqe_for_sq(cqe)) { 277762306a36Sopenharmony_ci expand = ocrdma_poll_scqe(qp, cqe, ibwc, &polled, 277862306a36Sopenharmony_ci &stop); 277962306a36Sopenharmony_ci } else { 278062306a36Sopenharmony_ci expand = ocrdma_poll_rcqe(qp, cqe, ibwc, &polled, 278162306a36Sopenharmony_ci &stop); 278262306a36Sopenharmony_ci } 278362306a36Sopenharmony_ci if (expand) 278462306a36Sopenharmony_ci goto expand_cqe; 278562306a36Sopenharmony_ci if (stop) 278662306a36Sopenharmony_ci goto stop_cqe; 278762306a36Sopenharmony_ci /* clear qpn to avoid duplicate processing by discard_cqe() */ 278862306a36Sopenharmony_ci cqe->cmn.qpn = 0; 278962306a36Sopenharmony_ciskip_cqe: 279062306a36Sopenharmony_ci polled_hw_cqes += 1; 279162306a36Sopenharmony_ci cur_getp = (cur_getp + 1) % cq->max_hw_cqe; 279262306a36Sopenharmony_ci ocrdma_change_cq_phase(cq, cqe, cur_getp); 279362306a36Sopenharmony_ciexpand_cqe: 279462306a36Sopenharmony_ci if (polled) { 279562306a36Sopenharmony_ci num_entries -= 1; 279662306a36Sopenharmony_ci i += 1; 279762306a36Sopenharmony_ci ibwc = ibwc + 1; 279862306a36Sopenharmony_ci polled = false; 279962306a36Sopenharmony_ci } 280062306a36Sopenharmony_ci } 280162306a36Sopenharmony_cistop_cqe: 280262306a36Sopenharmony_ci cq->getp = cur_getp; 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci if (polled_hw_cqes) 280562306a36Sopenharmony_ci ocrdma_ring_cq_db(dev, cq->id, false, false, polled_hw_cqes); 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci return i; 280862306a36Sopenharmony_ci} 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_ci/* insert error cqe if the QP's SQ or RQ's CQ matches the CQ under poll. */ 281162306a36Sopenharmony_cistatic int ocrdma_add_err_cqe(struct ocrdma_cq *cq, int num_entries, 281262306a36Sopenharmony_ci struct ocrdma_qp *qp, struct ib_wc *ibwc) 281362306a36Sopenharmony_ci{ 281462306a36Sopenharmony_ci int err_cqes = 0; 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_ci while (num_entries) { 281762306a36Sopenharmony_ci if (is_hw_sq_empty(qp) && is_hw_rq_empty(qp)) 281862306a36Sopenharmony_ci break; 281962306a36Sopenharmony_ci if (!is_hw_sq_empty(qp) && qp->sq_cq == cq) { 282062306a36Sopenharmony_ci ocrdma_update_wc(qp, ibwc, qp->sq.tail); 282162306a36Sopenharmony_ci ocrdma_hwq_inc_tail(&qp->sq); 282262306a36Sopenharmony_ci } else if (!is_hw_rq_empty(qp) && qp->rq_cq == cq) { 282362306a36Sopenharmony_ci ibwc->wr_id = qp->rqe_wr_id_tbl[qp->rq.tail]; 282462306a36Sopenharmony_ci ocrdma_hwq_inc_tail(&qp->rq); 282562306a36Sopenharmony_ci } else { 282662306a36Sopenharmony_ci return err_cqes; 282762306a36Sopenharmony_ci } 282862306a36Sopenharmony_ci ibwc->byte_len = 0; 282962306a36Sopenharmony_ci ibwc->status = IB_WC_WR_FLUSH_ERR; 283062306a36Sopenharmony_ci ibwc = ibwc + 1; 283162306a36Sopenharmony_ci err_cqes += 1; 283262306a36Sopenharmony_ci num_entries -= 1; 283362306a36Sopenharmony_ci } 283462306a36Sopenharmony_ci return err_cqes; 283562306a36Sopenharmony_ci} 283662306a36Sopenharmony_ci 283762306a36Sopenharmony_ciint ocrdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) 283862306a36Sopenharmony_ci{ 283962306a36Sopenharmony_ci int cqes_to_poll = num_entries; 284062306a36Sopenharmony_ci struct ocrdma_cq *cq = get_ocrdma_cq(ibcq); 284162306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device); 284262306a36Sopenharmony_ci int num_os_cqe = 0, err_cqes = 0; 284362306a36Sopenharmony_ci struct ocrdma_qp *qp; 284462306a36Sopenharmony_ci unsigned long flags; 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci /* poll cqes from adapter CQ */ 284762306a36Sopenharmony_ci spin_lock_irqsave(&cq->cq_lock, flags); 284862306a36Sopenharmony_ci num_os_cqe = ocrdma_poll_hwcq(cq, cqes_to_poll, wc); 284962306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->cq_lock, flags); 285062306a36Sopenharmony_ci cqes_to_poll -= num_os_cqe; 285162306a36Sopenharmony_ci 285262306a36Sopenharmony_ci if (cqes_to_poll) { 285362306a36Sopenharmony_ci wc = wc + num_os_cqe; 285462306a36Sopenharmony_ci /* adapter returns single error cqe when qp moves to 285562306a36Sopenharmony_ci * error state. So insert error cqes with wc_status as 285662306a36Sopenharmony_ci * FLUSHED for pending WQEs and RQEs of QP's SQ and RQ 285762306a36Sopenharmony_ci * respectively which uses this CQ. 285862306a36Sopenharmony_ci */ 285962306a36Sopenharmony_ci spin_lock_irqsave(&dev->flush_q_lock, flags); 286062306a36Sopenharmony_ci list_for_each_entry(qp, &cq->sq_head, sq_entry) { 286162306a36Sopenharmony_ci if (cqes_to_poll == 0) 286262306a36Sopenharmony_ci break; 286362306a36Sopenharmony_ci err_cqes = ocrdma_add_err_cqe(cq, cqes_to_poll, qp, wc); 286462306a36Sopenharmony_ci cqes_to_poll -= err_cqes; 286562306a36Sopenharmony_ci num_os_cqe += err_cqes; 286662306a36Sopenharmony_ci wc = wc + err_cqes; 286762306a36Sopenharmony_ci } 286862306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->flush_q_lock, flags); 286962306a36Sopenharmony_ci } 287062306a36Sopenharmony_ci return num_os_cqe; 287162306a36Sopenharmony_ci} 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ciint ocrdma_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags cq_flags) 287462306a36Sopenharmony_ci{ 287562306a36Sopenharmony_ci struct ocrdma_cq *cq = get_ocrdma_cq(ibcq); 287662306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device); 287762306a36Sopenharmony_ci u16 cq_id; 287862306a36Sopenharmony_ci unsigned long flags; 287962306a36Sopenharmony_ci bool arm_needed = false, sol_needed = false; 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci cq_id = cq->id; 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci spin_lock_irqsave(&cq->cq_lock, flags); 288462306a36Sopenharmony_ci if (cq_flags & IB_CQ_NEXT_COMP || cq_flags & IB_CQ_SOLICITED) 288562306a36Sopenharmony_ci arm_needed = true; 288662306a36Sopenharmony_ci if (cq_flags & IB_CQ_SOLICITED) 288762306a36Sopenharmony_ci sol_needed = true; 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_ci ocrdma_ring_cq_db(dev, cq_id, arm_needed, sol_needed, 0); 289062306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->cq_lock, flags); 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci return 0; 289362306a36Sopenharmony_ci} 289462306a36Sopenharmony_ci 289562306a36Sopenharmony_cistruct ib_mr *ocrdma_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type, 289662306a36Sopenharmony_ci u32 max_num_sg) 289762306a36Sopenharmony_ci{ 289862306a36Sopenharmony_ci int status; 289962306a36Sopenharmony_ci struct ocrdma_mr *mr; 290062306a36Sopenharmony_ci struct ocrdma_pd *pd = get_ocrdma_pd(ibpd); 290162306a36Sopenharmony_ci struct ocrdma_dev *dev = get_ocrdma_dev(ibpd->device); 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci if (mr_type != IB_MR_TYPE_MEM_REG) 290462306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci if (max_num_sg > dev->attr.max_pages_per_frmr) 290762306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_ci mr = kzalloc(sizeof(*mr), GFP_KERNEL); 291062306a36Sopenharmony_ci if (!mr) 291162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci mr->pages = kcalloc(max_num_sg, sizeof(u64), GFP_KERNEL); 291462306a36Sopenharmony_ci if (!mr->pages) { 291562306a36Sopenharmony_ci status = -ENOMEM; 291662306a36Sopenharmony_ci goto pl_err; 291762306a36Sopenharmony_ci } 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci status = ocrdma_get_pbl_info(dev, mr, max_num_sg); 292062306a36Sopenharmony_ci if (status) 292162306a36Sopenharmony_ci goto pbl_err; 292262306a36Sopenharmony_ci mr->hwmr.fr_mr = 1; 292362306a36Sopenharmony_ci mr->hwmr.remote_rd = 0; 292462306a36Sopenharmony_ci mr->hwmr.remote_wr = 0; 292562306a36Sopenharmony_ci mr->hwmr.local_rd = 0; 292662306a36Sopenharmony_ci mr->hwmr.local_wr = 0; 292762306a36Sopenharmony_ci mr->hwmr.mw_bind = 0; 292862306a36Sopenharmony_ci status = ocrdma_build_pbl_tbl(dev, &mr->hwmr); 292962306a36Sopenharmony_ci if (status) 293062306a36Sopenharmony_ci goto pbl_err; 293162306a36Sopenharmony_ci status = ocrdma_reg_mr(dev, &mr->hwmr, pd->id, 0); 293262306a36Sopenharmony_ci if (status) 293362306a36Sopenharmony_ci goto mbx_err; 293462306a36Sopenharmony_ci mr->ibmr.rkey = mr->hwmr.lkey; 293562306a36Sopenharmony_ci mr->ibmr.lkey = mr->hwmr.lkey; 293662306a36Sopenharmony_ci dev->stag_arr[(mr->hwmr.lkey >> 8) & (OCRDMA_MAX_STAG - 1)] = 293762306a36Sopenharmony_ci (unsigned long) mr; 293862306a36Sopenharmony_ci return &mr->ibmr; 293962306a36Sopenharmony_cimbx_err: 294062306a36Sopenharmony_ci ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr); 294162306a36Sopenharmony_cipbl_err: 294262306a36Sopenharmony_ci kfree(mr->pages); 294362306a36Sopenharmony_cipl_err: 294462306a36Sopenharmony_ci kfree(mr); 294562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 294662306a36Sopenharmony_ci} 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_cistatic int ocrdma_set_page(struct ib_mr *ibmr, u64 addr) 294962306a36Sopenharmony_ci{ 295062306a36Sopenharmony_ci struct ocrdma_mr *mr = get_ocrdma_mr(ibmr); 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ci if (unlikely(mr->npages == mr->hwmr.num_pbes)) 295362306a36Sopenharmony_ci return -ENOMEM; 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_ci mr->pages[mr->npages++] = addr; 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci return 0; 295862306a36Sopenharmony_ci} 295962306a36Sopenharmony_ci 296062306a36Sopenharmony_ciint ocrdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, 296162306a36Sopenharmony_ci unsigned int *sg_offset) 296262306a36Sopenharmony_ci{ 296362306a36Sopenharmony_ci struct ocrdma_mr *mr = get_ocrdma_mr(ibmr); 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci mr->npages = 0; 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, ocrdma_set_page); 296862306a36Sopenharmony_ci} 2969