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(&params, 0, sizeof(params));
146662306a36Sopenharmony_ci	mutex_lock(&dev->dev_lock);
146762306a36Sopenharmony_ci	status = ocrdma_mbx_query_qp(dev, qp, &params);
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, &params.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