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