162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
262306a36Sopenharmony_ci/* Copyright (c) 2015 - 2021 Intel Corporation */
362306a36Sopenharmony_ci#include "main.h"
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/**
662306a36Sopenharmony_ci * irdma_query_device - get device attributes
762306a36Sopenharmony_ci * @ibdev: device pointer from stack
862306a36Sopenharmony_ci * @props: returning device attributes
962306a36Sopenharmony_ci * @udata: user data
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_cistatic int irdma_query_device(struct ib_device *ibdev,
1262306a36Sopenharmony_ci			      struct ib_device_attr *props,
1362306a36Sopenharmony_ci			      struct ib_udata *udata)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibdev);
1662306a36Sopenharmony_ci	struct irdma_pci_f *rf = iwdev->rf;
1762306a36Sopenharmony_ci	struct pci_dev *pcidev = iwdev->rf->pcidev;
1862306a36Sopenharmony_ci	struct irdma_hw_attrs *hw_attrs = &rf->sc_dev.hw_attrs;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	if (udata->inlen || udata->outlen)
2162306a36Sopenharmony_ci		return -EINVAL;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	memset(props, 0, sizeof(*props));
2462306a36Sopenharmony_ci	addrconf_addr_eui48((u8 *)&props->sys_image_guid,
2562306a36Sopenharmony_ci			    iwdev->netdev->dev_addr);
2662306a36Sopenharmony_ci	props->fw_ver = (u64)irdma_fw_major_ver(&rf->sc_dev) << 32 |
2762306a36Sopenharmony_ci			irdma_fw_minor_ver(&rf->sc_dev);
2862306a36Sopenharmony_ci	props->device_cap_flags = IB_DEVICE_MEM_WINDOW |
2962306a36Sopenharmony_ci				  IB_DEVICE_MEM_MGT_EXTENSIONS;
3062306a36Sopenharmony_ci	props->kernel_cap_flags = IBK_LOCAL_DMA_LKEY;
3162306a36Sopenharmony_ci	props->vendor_id = pcidev->vendor;
3262306a36Sopenharmony_ci	props->vendor_part_id = pcidev->device;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	props->hw_ver = rf->pcidev->revision;
3562306a36Sopenharmony_ci	props->page_size_cap = hw_attrs->page_size_cap;
3662306a36Sopenharmony_ci	props->max_mr_size = hw_attrs->max_mr_size;
3762306a36Sopenharmony_ci	props->max_qp = rf->max_qp - rf->used_qps;
3862306a36Sopenharmony_ci	props->max_qp_wr = hw_attrs->max_qp_wr;
3962306a36Sopenharmony_ci	props->max_send_sge = hw_attrs->uk_attrs.max_hw_wq_frags;
4062306a36Sopenharmony_ci	props->max_recv_sge = hw_attrs->uk_attrs.max_hw_wq_frags;
4162306a36Sopenharmony_ci	props->max_cq = rf->max_cq - rf->used_cqs;
4262306a36Sopenharmony_ci	props->max_cqe = rf->max_cqe - 1;
4362306a36Sopenharmony_ci	props->max_mr = rf->max_mr - rf->used_mrs;
4462306a36Sopenharmony_ci	props->max_mw = props->max_mr;
4562306a36Sopenharmony_ci	props->max_pd = rf->max_pd - rf->used_pds;
4662306a36Sopenharmony_ci	props->max_sge_rd = hw_attrs->uk_attrs.max_hw_read_sges;
4762306a36Sopenharmony_ci	props->max_qp_rd_atom = hw_attrs->max_hw_ird;
4862306a36Sopenharmony_ci	props->max_qp_init_rd_atom = hw_attrs->max_hw_ord;
4962306a36Sopenharmony_ci	if (rdma_protocol_roce(ibdev, 1)) {
5062306a36Sopenharmony_ci		props->device_cap_flags |= IB_DEVICE_RC_RNR_NAK_GEN;
5162306a36Sopenharmony_ci		props->max_pkeys = IRDMA_PKEY_TBL_SZ;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	props->max_ah = rf->max_ah;
5562306a36Sopenharmony_ci	props->max_mcast_grp = rf->max_mcg;
5662306a36Sopenharmony_ci	props->max_mcast_qp_attach = IRDMA_MAX_MGS_PER_CTX;
5762306a36Sopenharmony_ci	props->max_total_mcast_qp_attach = rf->max_qp * IRDMA_MAX_MGS_PER_CTX;
5862306a36Sopenharmony_ci	props->max_fast_reg_page_list_len = IRDMA_MAX_PAGES_PER_FMR;
5962306a36Sopenharmony_ci#define HCA_CLOCK_TIMESTAMP_MASK 0x1ffff
6062306a36Sopenharmony_ci	if (hw_attrs->uk_attrs.hw_rev >= IRDMA_GEN_2)
6162306a36Sopenharmony_ci		props->timestamp_mask = HCA_CLOCK_TIMESTAMP_MASK;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return 0;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/**
6762306a36Sopenharmony_ci * irdma_query_port - get port attributes
6862306a36Sopenharmony_ci * @ibdev: device pointer from stack
6962306a36Sopenharmony_ci * @port: port number for query
7062306a36Sopenharmony_ci * @props: returning device attributes
7162306a36Sopenharmony_ci */
7262306a36Sopenharmony_cistatic int irdma_query_port(struct ib_device *ibdev, u32 port,
7362306a36Sopenharmony_ci			    struct ib_port_attr *props)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibdev);
7662306a36Sopenharmony_ci	struct net_device *netdev = iwdev->netdev;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* no need to zero out pros here. done by caller */
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	props->max_mtu = IB_MTU_4096;
8162306a36Sopenharmony_ci	props->active_mtu = ib_mtu_int_to_enum(netdev->mtu);
8262306a36Sopenharmony_ci	props->lid = 1;
8362306a36Sopenharmony_ci	props->lmc = 0;
8462306a36Sopenharmony_ci	props->sm_lid = 0;
8562306a36Sopenharmony_ci	props->sm_sl = 0;
8662306a36Sopenharmony_ci	if (netif_carrier_ok(netdev) && netif_running(netdev)) {
8762306a36Sopenharmony_ci		props->state = IB_PORT_ACTIVE;
8862306a36Sopenharmony_ci		props->phys_state = IB_PORT_PHYS_STATE_LINK_UP;
8962306a36Sopenharmony_ci	} else {
9062306a36Sopenharmony_ci		props->state = IB_PORT_DOWN;
9162306a36Sopenharmony_ci		props->phys_state = IB_PORT_PHYS_STATE_DISABLED;
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	ib_get_eth_speed(ibdev, port, &props->active_speed,
9562306a36Sopenharmony_ci			 &props->active_width);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (rdma_protocol_roce(ibdev, 1)) {
9862306a36Sopenharmony_ci		props->gid_tbl_len = 32;
9962306a36Sopenharmony_ci		props->ip_gids = true;
10062306a36Sopenharmony_ci		props->pkey_tbl_len = IRDMA_PKEY_TBL_SZ;
10162306a36Sopenharmony_ci	} else {
10262306a36Sopenharmony_ci		props->gid_tbl_len = 1;
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci	props->qkey_viol_cntr = 0;
10562306a36Sopenharmony_ci	props->port_cap_flags |= IB_PORT_CM_SUP | IB_PORT_REINIT_SUP;
10662306a36Sopenharmony_ci	props->max_msg_sz = iwdev->rf->sc_dev.hw_attrs.max_hw_outbound_msg_size;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	return 0;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/**
11262306a36Sopenharmony_ci * irdma_disassociate_ucontext - Disassociate user context
11362306a36Sopenharmony_ci * @context: ib user context
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_cistatic void irdma_disassociate_ucontext(struct ib_ucontext *context)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic int irdma_mmap_legacy(struct irdma_ucontext *ucontext,
12062306a36Sopenharmony_ci			     struct vm_area_struct *vma)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	u64 pfn;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (vma->vm_pgoff || vma->vm_end - vma->vm_start != PAGE_SIZE)
12562306a36Sopenharmony_ci		return -EINVAL;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	vma->vm_private_data = ucontext;
12862306a36Sopenharmony_ci	pfn = ((uintptr_t)ucontext->iwdev->rf->sc_dev.hw_regs[IRDMA_DB_ADDR_OFFSET] +
12962306a36Sopenharmony_ci	       pci_resource_start(ucontext->iwdev->rf->pcidev, 0)) >> PAGE_SHIFT;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	return rdma_user_mmap_io(&ucontext->ibucontext, vma, pfn, PAGE_SIZE,
13262306a36Sopenharmony_ci				 pgprot_noncached(vma->vm_page_prot), NULL);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic void irdma_mmap_free(struct rdma_user_mmap_entry *rdma_entry)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct irdma_user_mmap_entry *entry = to_irdma_mmap_entry(rdma_entry);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	kfree(entry);
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic struct rdma_user_mmap_entry*
14362306a36Sopenharmony_ciirdma_user_mmap_entry_insert(struct irdma_ucontext *ucontext, u64 bar_offset,
14462306a36Sopenharmony_ci			     enum irdma_mmap_flag mmap_flag, u64 *mmap_offset)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	struct irdma_user_mmap_entry *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
14762306a36Sopenharmony_ci	int ret;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (!entry)
15062306a36Sopenharmony_ci		return NULL;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	entry->bar_offset = bar_offset;
15362306a36Sopenharmony_ci	entry->mmap_flag = mmap_flag;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	ret = rdma_user_mmap_entry_insert(&ucontext->ibucontext,
15662306a36Sopenharmony_ci					  &entry->rdma_entry, PAGE_SIZE);
15762306a36Sopenharmony_ci	if (ret) {
15862306a36Sopenharmony_ci		kfree(entry);
15962306a36Sopenharmony_ci		return NULL;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci	*mmap_offset = rdma_user_mmap_get_offset(&entry->rdma_entry);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	return &entry->rdma_entry;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/**
16762306a36Sopenharmony_ci * irdma_mmap - user memory map
16862306a36Sopenharmony_ci * @context: context created during alloc
16962306a36Sopenharmony_ci * @vma: kernel info for user memory map
17062306a36Sopenharmony_ci */
17162306a36Sopenharmony_cistatic int irdma_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct rdma_user_mmap_entry *rdma_entry;
17462306a36Sopenharmony_ci	struct irdma_user_mmap_entry *entry;
17562306a36Sopenharmony_ci	struct irdma_ucontext *ucontext;
17662306a36Sopenharmony_ci	u64 pfn;
17762306a36Sopenharmony_ci	int ret;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	ucontext = to_ucontext(context);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	/* Legacy support for libi40iw with hard-coded mmap key */
18262306a36Sopenharmony_ci	if (ucontext->legacy_mode)
18362306a36Sopenharmony_ci		return irdma_mmap_legacy(ucontext, vma);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	rdma_entry = rdma_user_mmap_entry_get(&ucontext->ibucontext, vma);
18662306a36Sopenharmony_ci	if (!rdma_entry) {
18762306a36Sopenharmony_ci		ibdev_dbg(&ucontext->iwdev->ibdev,
18862306a36Sopenharmony_ci			  "VERBS: pgoff[0x%lx] does not have valid entry\n",
18962306a36Sopenharmony_ci			  vma->vm_pgoff);
19062306a36Sopenharmony_ci		return -EINVAL;
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	entry = to_irdma_mmap_entry(rdma_entry);
19462306a36Sopenharmony_ci	ibdev_dbg(&ucontext->iwdev->ibdev,
19562306a36Sopenharmony_ci		  "VERBS: bar_offset [0x%llx] mmap_flag [%d]\n",
19662306a36Sopenharmony_ci		  entry->bar_offset, entry->mmap_flag);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	pfn = (entry->bar_offset +
19962306a36Sopenharmony_ci	      pci_resource_start(ucontext->iwdev->rf->pcidev, 0)) >> PAGE_SHIFT;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	switch (entry->mmap_flag) {
20262306a36Sopenharmony_ci	case IRDMA_MMAP_IO_NC:
20362306a36Sopenharmony_ci		ret = rdma_user_mmap_io(context, vma, pfn, PAGE_SIZE,
20462306a36Sopenharmony_ci					pgprot_noncached(vma->vm_page_prot),
20562306a36Sopenharmony_ci					rdma_entry);
20662306a36Sopenharmony_ci		break;
20762306a36Sopenharmony_ci	case IRDMA_MMAP_IO_WC:
20862306a36Sopenharmony_ci		ret = rdma_user_mmap_io(context, vma, pfn, PAGE_SIZE,
20962306a36Sopenharmony_ci					pgprot_writecombine(vma->vm_page_prot),
21062306a36Sopenharmony_ci					rdma_entry);
21162306a36Sopenharmony_ci		break;
21262306a36Sopenharmony_ci	default:
21362306a36Sopenharmony_ci		ret = -EINVAL;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (ret)
21762306a36Sopenharmony_ci		ibdev_dbg(&ucontext->iwdev->ibdev,
21862306a36Sopenharmony_ci			  "VERBS: bar_offset [0x%llx] mmap_flag[%d] err[%d]\n",
21962306a36Sopenharmony_ci			  entry->bar_offset, entry->mmap_flag, ret);
22062306a36Sopenharmony_ci	rdma_user_mmap_entry_put(rdma_entry);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	return ret;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/**
22662306a36Sopenharmony_ci * irdma_alloc_push_page - allocate a push page for qp
22762306a36Sopenharmony_ci * @iwqp: qp pointer
22862306a36Sopenharmony_ci */
22962306a36Sopenharmony_cistatic void irdma_alloc_push_page(struct irdma_qp *iwqp)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
23262306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
23362306a36Sopenharmony_ci	struct irdma_device *iwdev = iwqp->iwdev;
23462306a36Sopenharmony_ci	struct irdma_sc_qp *qp = &iwqp->sc_qp;
23562306a36Sopenharmony_ci	int status;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
23862306a36Sopenharmony_ci	if (!cqp_request)
23962306a36Sopenharmony_ci		return;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
24262306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_MANAGE_PUSH_PAGE;
24362306a36Sopenharmony_ci	cqp_info->post_sq = 1;
24462306a36Sopenharmony_ci	cqp_info->in.u.manage_push_page.info.push_idx = 0;
24562306a36Sopenharmony_ci	cqp_info->in.u.manage_push_page.info.qs_handle =
24662306a36Sopenharmony_ci		qp->vsi->qos[qp->user_pri].qs_handle;
24762306a36Sopenharmony_ci	cqp_info->in.u.manage_push_page.info.free_page = 0;
24862306a36Sopenharmony_ci	cqp_info->in.u.manage_push_page.info.push_page_type = 0;
24962306a36Sopenharmony_ci	cqp_info->in.u.manage_push_page.cqp = &iwdev->rf->cqp.sc_cqp;
25062306a36Sopenharmony_ci	cqp_info->in.u.manage_push_page.scratch = (uintptr_t)cqp_request;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
25362306a36Sopenharmony_ci	if (!status && cqp_request->compl_info.op_ret_val <
25462306a36Sopenharmony_ci	    iwdev->rf->sc_dev.hw_attrs.max_hw_device_pages) {
25562306a36Sopenharmony_ci		qp->push_idx = cqp_request->compl_info.op_ret_val;
25662306a36Sopenharmony_ci		qp->push_offset = 0;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/**
26362306a36Sopenharmony_ci * irdma_alloc_ucontext - Allocate the user context data structure
26462306a36Sopenharmony_ci * @uctx: uverbs context pointer
26562306a36Sopenharmony_ci * @udata: user data
26662306a36Sopenharmony_ci *
26762306a36Sopenharmony_ci * This keeps track of all objects associated with a particular
26862306a36Sopenharmony_ci * user-mode client.
26962306a36Sopenharmony_ci */
27062306a36Sopenharmony_cistatic int irdma_alloc_ucontext(struct ib_ucontext *uctx,
27162306a36Sopenharmony_ci				struct ib_udata *udata)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci#define IRDMA_ALLOC_UCTX_MIN_REQ_LEN offsetofend(struct irdma_alloc_ucontext_req, rsvd8)
27462306a36Sopenharmony_ci#define IRDMA_ALLOC_UCTX_MIN_RESP_LEN offsetofend(struct irdma_alloc_ucontext_resp, rsvd)
27562306a36Sopenharmony_ci	struct ib_device *ibdev = uctx->device;
27662306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibdev);
27762306a36Sopenharmony_ci	struct irdma_alloc_ucontext_req req = {};
27862306a36Sopenharmony_ci	struct irdma_alloc_ucontext_resp uresp = {};
27962306a36Sopenharmony_ci	struct irdma_ucontext *ucontext = to_ucontext(uctx);
28062306a36Sopenharmony_ci	struct irdma_uk_attrs *uk_attrs = &iwdev->rf->sc_dev.hw_attrs.uk_attrs;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (udata->inlen < IRDMA_ALLOC_UCTX_MIN_REQ_LEN ||
28362306a36Sopenharmony_ci	    udata->outlen < IRDMA_ALLOC_UCTX_MIN_RESP_LEN)
28462306a36Sopenharmony_ci		return -EINVAL;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	if (ib_copy_from_udata(&req, udata, min(sizeof(req), udata->inlen)))
28762306a36Sopenharmony_ci		return -EINVAL;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (req.userspace_ver < 4 || req.userspace_ver > IRDMA_ABI_VER)
29062306a36Sopenharmony_ci		goto ver_error;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	ucontext->iwdev = iwdev;
29362306a36Sopenharmony_ci	ucontext->abi_ver = req.userspace_ver;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (req.comp_mask & IRDMA_ALLOC_UCTX_USE_RAW_ATTR)
29662306a36Sopenharmony_ci		ucontext->use_raw_attrs = true;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	/* GEN_1 legacy support with libi40iw */
29962306a36Sopenharmony_ci	if (udata->outlen == IRDMA_ALLOC_UCTX_MIN_RESP_LEN) {
30062306a36Sopenharmony_ci		if (uk_attrs->hw_rev != IRDMA_GEN_1)
30162306a36Sopenharmony_ci			return -EOPNOTSUPP;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci		ucontext->legacy_mode = true;
30462306a36Sopenharmony_ci		uresp.max_qps = iwdev->rf->max_qp;
30562306a36Sopenharmony_ci		uresp.max_pds = iwdev->rf->sc_dev.hw_attrs.max_hw_pds;
30662306a36Sopenharmony_ci		uresp.wq_size = iwdev->rf->sc_dev.hw_attrs.max_qp_wr * 2;
30762306a36Sopenharmony_ci		uresp.kernel_ver = req.userspace_ver;
30862306a36Sopenharmony_ci		if (ib_copy_to_udata(udata, &uresp,
30962306a36Sopenharmony_ci				     min(sizeof(uresp), udata->outlen)))
31062306a36Sopenharmony_ci			return -EFAULT;
31162306a36Sopenharmony_ci	} else {
31262306a36Sopenharmony_ci		u64 bar_off = (uintptr_t)iwdev->rf->sc_dev.hw_regs[IRDMA_DB_ADDR_OFFSET];
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci		ucontext->db_mmap_entry =
31562306a36Sopenharmony_ci			irdma_user_mmap_entry_insert(ucontext, bar_off,
31662306a36Sopenharmony_ci						     IRDMA_MMAP_IO_NC,
31762306a36Sopenharmony_ci						     &uresp.db_mmap_key);
31862306a36Sopenharmony_ci		if (!ucontext->db_mmap_entry)
31962306a36Sopenharmony_ci			return -ENOMEM;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci		uresp.kernel_ver = IRDMA_ABI_VER;
32262306a36Sopenharmony_ci		uresp.feature_flags = uk_attrs->feature_flags;
32362306a36Sopenharmony_ci		uresp.max_hw_wq_frags = uk_attrs->max_hw_wq_frags;
32462306a36Sopenharmony_ci		uresp.max_hw_read_sges = uk_attrs->max_hw_read_sges;
32562306a36Sopenharmony_ci		uresp.max_hw_inline = uk_attrs->max_hw_inline;
32662306a36Sopenharmony_ci		uresp.max_hw_rq_quanta = uk_attrs->max_hw_rq_quanta;
32762306a36Sopenharmony_ci		uresp.max_hw_wq_quanta = uk_attrs->max_hw_wq_quanta;
32862306a36Sopenharmony_ci		uresp.max_hw_sq_chunk = uk_attrs->max_hw_sq_chunk;
32962306a36Sopenharmony_ci		uresp.max_hw_cq_size = uk_attrs->max_hw_cq_size;
33062306a36Sopenharmony_ci		uresp.min_hw_cq_size = uk_attrs->min_hw_cq_size;
33162306a36Sopenharmony_ci		uresp.hw_rev = uk_attrs->hw_rev;
33262306a36Sopenharmony_ci		uresp.comp_mask |= IRDMA_ALLOC_UCTX_USE_RAW_ATTR;
33362306a36Sopenharmony_ci		uresp.min_hw_wq_size = uk_attrs->min_hw_wq_size;
33462306a36Sopenharmony_ci		uresp.comp_mask |= IRDMA_ALLOC_UCTX_MIN_HW_WQ_SIZE;
33562306a36Sopenharmony_ci		if (ib_copy_to_udata(udata, &uresp,
33662306a36Sopenharmony_ci				     min(sizeof(uresp), udata->outlen))) {
33762306a36Sopenharmony_ci			rdma_user_mmap_entry_remove(ucontext->db_mmap_entry);
33862306a36Sopenharmony_ci			return -EFAULT;
33962306a36Sopenharmony_ci		}
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	INIT_LIST_HEAD(&ucontext->cq_reg_mem_list);
34362306a36Sopenharmony_ci	spin_lock_init(&ucontext->cq_reg_mem_list_lock);
34462306a36Sopenharmony_ci	INIT_LIST_HEAD(&ucontext->qp_reg_mem_list);
34562306a36Sopenharmony_ci	spin_lock_init(&ucontext->qp_reg_mem_list_lock);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	return 0;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_civer_error:
35062306a36Sopenharmony_ci	ibdev_err(&iwdev->ibdev,
35162306a36Sopenharmony_ci		  "Invalid userspace driver version detected. Detected version %d, should be %d\n",
35262306a36Sopenharmony_ci		  req.userspace_ver, IRDMA_ABI_VER);
35362306a36Sopenharmony_ci	return -EINVAL;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/**
35762306a36Sopenharmony_ci * irdma_dealloc_ucontext - deallocate the user context data structure
35862306a36Sopenharmony_ci * @context: user context created during alloc
35962306a36Sopenharmony_ci */
36062306a36Sopenharmony_cistatic void irdma_dealloc_ucontext(struct ib_ucontext *context)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct irdma_ucontext *ucontext = to_ucontext(context);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	rdma_user_mmap_entry_remove(ucontext->db_mmap_entry);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/**
36862306a36Sopenharmony_ci * irdma_alloc_pd - allocate protection domain
36962306a36Sopenharmony_ci * @pd: PD pointer
37062306a36Sopenharmony_ci * @udata: user data
37162306a36Sopenharmony_ci */
37262306a36Sopenharmony_cistatic int irdma_alloc_pd(struct ib_pd *pd, struct ib_udata *udata)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci#define IRDMA_ALLOC_PD_MIN_RESP_LEN offsetofend(struct irdma_alloc_pd_resp, rsvd)
37562306a36Sopenharmony_ci	struct irdma_pd *iwpd = to_iwpd(pd);
37662306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(pd->device);
37762306a36Sopenharmony_ci	struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
37862306a36Sopenharmony_ci	struct irdma_pci_f *rf = iwdev->rf;
37962306a36Sopenharmony_ci	struct irdma_alloc_pd_resp uresp = {};
38062306a36Sopenharmony_ci	struct irdma_sc_pd *sc_pd;
38162306a36Sopenharmony_ci	u32 pd_id = 0;
38262306a36Sopenharmony_ci	int err;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	if (udata && udata->outlen < IRDMA_ALLOC_PD_MIN_RESP_LEN)
38562306a36Sopenharmony_ci		return -EINVAL;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	err = irdma_alloc_rsrc(rf, rf->allocated_pds, rf->max_pd, &pd_id,
38862306a36Sopenharmony_ci			       &rf->next_pd);
38962306a36Sopenharmony_ci	if (err)
39062306a36Sopenharmony_ci		return err;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	sc_pd = &iwpd->sc_pd;
39362306a36Sopenharmony_ci	if (udata) {
39462306a36Sopenharmony_ci		struct irdma_ucontext *ucontext =
39562306a36Sopenharmony_ci			rdma_udata_to_drv_context(udata, struct irdma_ucontext,
39662306a36Sopenharmony_ci						  ibucontext);
39762306a36Sopenharmony_ci		irdma_sc_pd_init(dev, sc_pd, pd_id, ucontext->abi_ver);
39862306a36Sopenharmony_ci		uresp.pd_id = pd_id;
39962306a36Sopenharmony_ci		if (ib_copy_to_udata(udata, &uresp,
40062306a36Sopenharmony_ci				     min(sizeof(uresp), udata->outlen))) {
40162306a36Sopenharmony_ci			err = -EFAULT;
40262306a36Sopenharmony_ci			goto error;
40362306a36Sopenharmony_ci		}
40462306a36Sopenharmony_ci	} else {
40562306a36Sopenharmony_ci		irdma_sc_pd_init(dev, sc_pd, pd_id, IRDMA_ABI_VER);
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	return 0;
40962306a36Sopenharmony_cierror:
41062306a36Sopenharmony_ci	irdma_free_rsrc(rf, rf->allocated_pds, pd_id);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return err;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/**
41662306a36Sopenharmony_ci * irdma_dealloc_pd - deallocate pd
41762306a36Sopenharmony_ci * @ibpd: ptr of pd to be deallocated
41862306a36Sopenharmony_ci * @udata: user data
41962306a36Sopenharmony_ci */
42062306a36Sopenharmony_cistatic int irdma_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct irdma_pd *iwpd = to_iwpd(ibpd);
42362306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibpd->device);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	irdma_free_rsrc(iwdev->rf, iwdev->rf->allocated_pds, iwpd->sc_pd.pd_id);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	return 0;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci/**
43162306a36Sopenharmony_ci * irdma_get_pbl - Retrieve pbl from a list given a virtual
43262306a36Sopenharmony_ci * address
43362306a36Sopenharmony_ci * @va: user virtual address
43462306a36Sopenharmony_ci * @pbl_list: pbl list to search in (QP's or CQ's)
43562306a36Sopenharmony_ci */
43662306a36Sopenharmony_cistatic struct irdma_pbl *irdma_get_pbl(unsigned long va,
43762306a36Sopenharmony_ci				       struct list_head *pbl_list)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct irdma_pbl *iwpbl;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	list_for_each_entry (iwpbl, pbl_list, list) {
44262306a36Sopenharmony_ci		if (iwpbl->user_base == va) {
44362306a36Sopenharmony_ci			list_del(&iwpbl->list);
44462306a36Sopenharmony_ci			iwpbl->on_list = false;
44562306a36Sopenharmony_ci			return iwpbl;
44662306a36Sopenharmony_ci		}
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	return NULL;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci/**
45362306a36Sopenharmony_ci * irdma_clean_cqes - clean cq entries for qp
45462306a36Sopenharmony_ci * @iwqp: qp ptr (user or kernel)
45562306a36Sopenharmony_ci * @iwcq: cq ptr
45662306a36Sopenharmony_ci */
45762306a36Sopenharmony_cistatic void irdma_clean_cqes(struct irdma_qp *iwqp, struct irdma_cq *iwcq)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct irdma_cq_uk *ukcq = &iwcq->sc_cq.cq_uk;
46062306a36Sopenharmony_ci	unsigned long flags;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	spin_lock_irqsave(&iwcq->lock, flags);
46362306a36Sopenharmony_ci	irdma_uk_clean_cq(&iwqp->sc_qp.qp_uk, ukcq);
46462306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwcq->lock, flags);
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic void irdma_remove_push_mmap_entries(struct irdma_qp *iwqp)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	if (iwqp->push_db_mmap_entry) {
47062306a36Sopenharmony_ci		rdma_user_mmap_entry_remove(iwqp->push_db_mmap_entry);
47162306a36Sopenharmony_ci		iwqp->push_db_mmap_entry = NULL;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci	if (iwqp->push_wqe_mmap_entry) {
47462306a36Sopenharmony_ci		rdma_user_mmap_entry_remove(iwqp->push_wqe_mmap_entry);
47562306a36Sopenharmony_ci		iwqp->push_wqe_mmap_entry = NULL;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic int irdma_setup_push_mmap_entries(struct irdma_ucontext *ucontext,
48062306a36Sopenharmony_ci					 struct irdma_qp *iwqp,
48162306a36Sopenharmony_ci					 u64 *push_wqe_mmap_key,
48262306a36Sopenharmony_ci					 u64 *push_db_mmap_key)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct irdma_device *iwdev = ucontext->iwdev;
48562306a36Sopenharmony_ci	u64 rsvd, bar_off;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	rsvd = IRDMA_PF_BAR_RSVD;
48862306a36Sopenharmony_ci	bar_off = (uintptr_t)iwdev->rf->sc_dev.hw_regs[IRDMA_DB_ADDR_OFFSET];
48962306a36Sopenharmony_ci	/* skip over db page */
49062306a36Sopenharmony_ci	bar_off += IRDMA_HW_PAGE_SIZE;
49162306a36Sopenharmony_ci	/* push wqe page */
49262306a36Sopenharmony_ci	bar_off += rsvd + iwqp->sc_qp.push_idx * IRDMA_HW_PAGE_SIZE;
49362306a36Sopenharmony_ci	iwqp->push_wqe_mmap_entry = irdma_user_mmap_entry_insert(ucontext,
49462306a36Sopenharmony_ci					bar_off, IRDMA_MMAP_IO_WC,
49562306a36Sopenharmony_ci					push_wqe_mmap_key);
49662306a36Sopenharmony_ci	if (!iwqp->push_wqe_mmap_entry)
49762306a36Sopenharmony_ci		return -ENOMEM;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	/* push doorbell page */
50062306a36Sopenharmony_ci	bar_off += IRDMA_HW_PAGE_SIZE;
50162306a36Sopenharmony_ci	iwqp->push_db_mmap_entry = irdma_user_mmap_entry_insert(ucontext,
50262306a36Sopenharmony_ci					bar_off, IRDMA_MMAP_IO_NC,
50362306a36Sopenharmony_ci					push_db_mmap_key);
50462306a36Sopenharmony_ci	if (!iwqp->push_db_mmap_entry) {
50562306a36Sopenharmony_ci		rdma_user_mmap_entry_remove(iwqp->push_wqe_mmap_entry);
50662306a36Sopenharmony_ci		return -ENOMEM;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	return 0;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci/**
51362306a36Sopenharmony_ci * irdma_destroy_qp - destroy qp
51462306a36Sopenharmony_ci * @ibqp: qp's ib pointer also to get to device's qp address
51562306a36Sopenharmony_ci * @udata: user data
51662306a36Sopenharmony_ci */
51762306a36Sopenharmony_cistatic int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	struct irdma_qp *iwqp = to_iwqp(ibqp);
52062306a36Sopenharmony_ci	struct irdma_device *iwdev = iwqp->iwdev;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	iwqp->sc_qp.qp_uk.destroy_pending = true;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	if (iwqp->iwarp_state == IRDMA_QP_STATE_RTS)
52562306a36Sopenharmony_ci		irdma_modify_qp_to_err(&iwqp->sc_qp);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	if (!iwqp->user_mode)
52862306a36Sopenharmony_ci		cancel_delayed_work_sync(&iwqp->dwork_flush);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (!iwqp->user_mode) {
53162306a36Sopenharmony_ci		if (iwqp->iwscq) {
53262306a36Sopenharmony_ci			irdma_clean_cqes(iwqp, iwqp->iwscq);
53362306a36Sopenharmony_ci			if (iwqp->iwrcq != iwqp->iwscq)
53462306a36Sopenharmony_ci				irdma_clean_cqes(iwqp, iwqp->iwrcq);
53562306a36Sopenharmony_ci		}
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	irdma_qp_rem_ref(&iwqp->ibqp);
53962306a36Sopenharmony_ci	wait_for_completion(&iwqp->free_qp);
54062306a36Sopenharmony_ci	irdma_free_lsmm_rsrc(iwqp);
54162306a36Sopenharmony_ci	irdma_cqp_qp_destroy_cmd(&iwdev->rf->sc_dev, &iwqp->sc_qp);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	irdma_remove_push_mmap_entries(iwqp);
54462306a36Sopenharmony_ci	irdma_free_qp_rsrc(iwqp);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	return 0;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci/**
55062306a36Sopenharmony_ci * irdma_setup_virt_qp - setup for allocation of virtual qp
55162306a36Sopenharmony_ci * @iwdev: irdma device
55262306a36Sopenharmony_ci * @iwqp: qp ptr
55362306a36Sopenharmony_ci * @init_info: initialize info to return
55462306a36Sopenharmony_ci */
55562306a36Sopenharmony_cistatic void irdma_setup_virt_qp(struct irdma_device *iwdev,
55662306a36Sopenharmony_ci			       struct irdma_qp *iwqp,
55762306a36Sopenharmony_ci			       struct irdma_qp_init_info *init_info)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	struct irdma_pbl *iwpbl = iwqp->iwpbl;
56062306a36Sopenharmony_ci	struct irdma_qp_mr *qpmr = &iwpbl->qp_mr;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	iwqp->page = qpmr->sq_page;
56362306a36Sopenharmony_ci	init_info->shadow_area_pa = qpmr->shadow;
56462306a36Sopenharmony_ci	if (iwpbl->pbl_allocated) {
56562306a36Sopenharmony_ci		init_info->virtual_map = true;
56662306a36Sopenharmony_ci		init_info->sq_pa = qpmr->sq_pbl.idx;
56762306a36Sopenharmony_ci		init_info->rq_pa = qpmr->rq_pbl.idx;
56862306a36Sopenharmony_ci	} else {
56962306a36Sopenharmony_ci		init_info->sq_pa = qpmr->sq_pbl.addr;
57062306a36Sopenharmony_ci		init_info->rq_pa = qpmr->rq_pbl.addr;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci/**
57562306a36Sopenharmony_ci * irdma_setup_umode_qp - setup sq and rq size in user mode qp
57662306a36Sopenharmony_ci * @udata: udata
57762306a36Sopenharmony_ci * @iwdev: iwarp device
57862306a36Sopenharmony_ci * @iwqp: qp ptr (user or kernel)
57962306a36Sopenharmony_ci * @info: initialize info to return
58062306a36Sopenharmony_ci * @init_attr: Initial QP create attributes
58162306a36Sopenharmony_ci */
58262306a36Sopenharmony_cistatic int irdma_setup_umode_qp(struct ib_udata *udata,
58362306a36Sopenharmony_ci				struct irdma_device *iwdev,
58462306a36Sopenharmony_ci				struct irdma_qp *iwqp,
58562306a36Sopenharmony_ci				struct irdma_qp_init_info *info,
58662306a36Sopenharmony_ci				struct ib_qp_init_attr *init_attr)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	struct irdma_ucontext *ucontext = rdma_udata_to_drv_context(udata,
58962306a36Sopenharmony_ci				struct irdma_ucontext, ibucontext);
59062306a36Sopenharmony_ci	struct irdma_qp_uk_init_info *ukinfo = &info->qp_uk_init_info;
59162306a36Sopenharmony_ci	struct irdma_create_qp_req req;
59262306a36Sopenharmony_ci	unsigned long flags;
59362306a36Sopenharmony_ci	int ret;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	ret = ib_copy_from_udata(&req, udata,
59662306a36Sopenharmony_ci				 min(sizeof(req), udata->inlen));
59762306a36Sopenharmony_ci	if (ret) {
59862306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev, "VERBS: ib_copy_from_data fail\n");
59962306a36Sopenharmony_ci		return ret;
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	iwqp->ctx_info.qp_compl_ctx = req.user_compl_ctx;
60362306a36Sopenharmony_ci	iwqp->user_mode = 1;
60462306a36Sopenharmony_ci	if (req.user_wqe_bufs) {
60562306a36Sopenharmony_ci		info->qp_uk_init_info.legacy_mode = ucontext->legacy_mode;
60662306a36Sopenharmony_ci		spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
60762306a36Sopenharmony_ci		iwqp->iwpbl = irdma_get_pbl((unsigned long)req.user_wqe_bufs,
60862306a36Sopenharmony_ci					    &ucontext->qp_reg_mem_list);
60962306a36Sopenharmony_ci		spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci		if (!iwqp->iwpbl) {
61262306a36Sopenharmony_ci			ret = -ENODATA;
61362306a36Sopenharmony_ci			ibdev_dbg(&iwdev->ibdev, "VERBS: no pbl info\n");
61462306a36Sopenharmony_ci			return ret;
61562306a36Sopenharmony_ci		}
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	if (!ucontext->use_raw_attrs) {
61962306a36Sopenharmony_ci		/**
62062306a36Sopenharmony_ci		 * Maintain backward compat with older ABI which passes sq and
62162306a36Sopenharmony_ci		 * rq depth in quanta in cap.max_send_wr and cap.max_recv_wr.
62262306a36Sopenharmony_ci		 * There is no way to compute the correct value of
62362306a36Sopenharmony_ci		 * iwqp->max_send_wr/max_recv_wr in the kernel.
62462306a36Sopenharmony_ci		 */
62562306a36Sopenharmony_ci		iwqp->max_send_wr = init_attr->cap.max_send_wr;
62662306a36Sopenharmony_ci		iwqp->max_recv_wr = init_attr->cap.max_recv_wr;
62762306a36Sopenharmony_ci		ukinfo->sq_size = init_attr->cap.max_send_wr;
62862306a36Sopenharmony_ci		ukinfo->rq_size = init_attr->cap.max_recv_wr;
62962306a36Sopenharmony_ci		irdma_uk_calc_shift_wq(ukinfo, &ukinfo->sq_shift,
63062306a36Sopenharmony_ci				       &ukinfo->rq_shift);
63162306a36Sopenharmony_ci	} else {
63262306a36Sopenharmony_ci		ret = irdma_uk_calc_depth_shift_sq(ukinfo, &ukinfo->sq_depth,
63362306a36Sopenharmony_ci						   &ukinfo->sq_shift);
63462306a36Sopenharmony_ci		if (ret)
63562306a36Sopenharmony_ci			return ret;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		ret = irdma_uk_calc_depth_shift_rq(ukinfo, &ukinfo->rq_depth,
63862306a36Sopenharmony_ci						   &ukinfo->rq_shift);
63962306a36Sopenharmony_ci		if (ret)
64062306a36Sopenharmony_ci			return ret;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci		iwqp->max_send_wr =
64362306a36Sopenharmony_ci			(ukinfo->sq_depth - IRDMA_SQ_RSVD) >> ukinfo->sq_shift;
64462306a36Sopenharmony_ci		iwqp->max_recv_wr =
64562306a36Sopenharmony_ci			(ukinfo->rq_depth - IRDMA_RQ_RSVD) >> ukinfo->rq_shift;
64662306a36Sopenharmony_ci		ukinfo->sq_size = ukinfo->sq_depth >> ukinfo->sq_shift;
64762306a36Sopenharmony_ci		ukinfo->rq_size = ukinfo->rq_depth >> ukinfo->rq_shift;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	irdma_setup_virt_qp(iwdev, iwqp, info);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	return 0;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci/**
65662306a36Sopenharmony_ci * irdma_setup_kmode_qp - setup initialization for kernel mode qp
65762306a36Sopenharmony_ci * @iwdev: iwarp device
65862306a36Sopenharmony_ci * @iwqp: qp ptr (user or kernel)
65962306a36Sopenharmony_ci * @info: initialize info to return
66062306a36Sopenharmony_ci * @init_attr: Initial QP create attributes
66162306a36Sopenharmony_ci */
66262306a36Sopenharmony_cistatic int irdma_setup_kmode_qp(struct irdma_device *iwdev,
66362306a36Sopenharmony_ci				struct irdma_qp *iwqp,
66462306a36Sopenharmony_ci				struct irdma_qp_init_info *info,
66562306a36Sopenharmony_ci				struct ib_qp_init_attr *init_attr)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	struct irdma_dma_mem *mem = &iwqp->kqp.dma_mem;
66862306a36Sopenharmony_ci	u32 size;
66962306a36Sopenharmony_ci	int status;
67062306a36Sopenharmony_ci	struct irdma_qp_uk_init_info *ukinfo = &info->qp_uk_init_info;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	status = irdma_uk_calc_depth_shift_sq(ukinfo, &ukinfo->sq_depth,
67362306a36Sopenharmony_ci					      &ukinfo->sq_shift);
67462306a36Sopenharmony_ci	if (status)
67562306a36Sopenharmony_ci		return status;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	status = irdma_uk_calc_depth_shift_rq(ukinfo, &ukinfo->rq_depth,
67862306a36Sopenharmony_ci					      &ukinfo->rq_shift);
67962306a36Sopenharmony_ci	if (status)
68062306a36Sopenharmony_ci		return status;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	iwqp->kqp.sq_wrid_mem =
68362306a36Sopenharmony_ci		kcalloc(ukinfo->sq_depth, sizeof(*iwqp->kqp.sq_wrid_mem), GFP_KERNEL);
68462306a36Sopenharmony_ci	if (!iwqp->kqp.sq_wrid_mem)
68562306a36Sopenharmony_ci		return -ENOMEM;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	iwqp->kqp.rq_wrid_mem =
68862306a36Sopenharmony_ci		kcalloc(ukinfo->rq_depth, sizeof(*iwqp->kqp.rq_wrid_mem), GFP_KERNEL);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	if (!iwqp->kqp.rq_wrid_mem) {
69162306a36Sopenharmony_ci		kfree(iwqp->kqp.sq_wrid_mem);
69262306a36Sopenharmony_ci		iwqp->kqp.sq_wrid_mem = NULL;
69362306a36Sopenharmony_ci		return -ENOMEM;
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	ukinfo->sq_wrtrk_array = iwqp->kqp.sq_wrid_mem;
69762306a36Sopenharmony_ci	ukinfo->rq_wrid_array = iwqp->kqp.rq_wrid_mem;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	size = (ukinfo->sq_depth + ukinfo->rq_depth) * IRDMA_QP_WQE_MIN_SIZE;
70062306a36Sopenharmony_ci	size += (IRDMA_SHADOW_AREA_SIZE << 3);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	mem->size = ALIGN(size, 256);
70362306a36Sopenharmony_ci	mem->va = dma_alloc_coherent(iwdev->rf->hw.device, mem->size,
70462306a36Sopenharmony_ci				     &mem->pa, GFP_KERNEL);
70562306a36Sopenharmony_ci	if (!mem->va) {
70662306a36Sopenharmony_ci		kfree(iwqp->kqp.sq_wrid_mem);
70762306a36Sopenharmony_ci		iwqp->kqp.sq_wrid_mem = NULL;
70862306a36Sopenharmony_ci		kfree(iwqp->kqp.rq_wrid_mem);
70962306a36Sopenharmony_ci		iwqp->kqp.rq_wrid_mem = NULL;
71062306a36Sopenharmony_ci		return -ENOMEM;
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	ukinfo->sq = mem->va;
71462306a36Sopenharmony_ci	info->sq_pa = mem->pa;
71562306a36Sopenharmony_ci	ukinfo->rq = &ukinfo->sq[ukinfo->sq_depth];
71662306a36Sopenharmony_ci	info->rq_pa = info->sq_pa + (ukinfo->sq_depth * IRDMA_QP_WQE_MIN_SIZE);
71762306a36Sopenharmony_ci	ukinfo->shadow_area = ukinfo->rq[ukinfo->rq_depth].elem;
71862306a36Sopenharmony_ci	info->shadow_area_pa =
71962306a36Sopenharmony_ci		info->rq_pa + (ukinfo->rq_depth * IRDMA_QP_WQE_MIN_SIZE);
72062306a36Sopenharmony_ci	ukinfo->sq_size = ukinfo->sq_depth >> ukinfo->sq_shift;
72162306a36Sopenharmony_ci	ukinfo->rq_size = ukinfo->rq_depth >> ukinfo->rq_shift;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	iwqp->max_send_wr = (ukinfo->sq_depth - IRDMA_SQ_RSVD) >> ukinfo->sq_shift;
72462306a36Sopenharmony_ci	iwqp->max_recv_wr = (ukinfo->rq_depth - IRDMA_RQ_RSVD) >> ukinfo->rq_shift;
72562306a36Sopenharmony_ci	init_attr->cap.max_send_wr = iwqp->max_send_wr;
72662306a36Sopenharmony_ci	init_attr->cap.max_recv_wr = iwqp->max_recv_wr;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	return 0;
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic int irdma_cqp_create_qp_cmd(struct irdma_qp *iwqp)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	struct irdma_pci_f *rf = iwqp->iwdev->rf;
73462306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
73562306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
73662306a36Sopenharmony_ci	struct irdma_create_qp_info *qp_info;
73762306a36Sopenharmony_ci	int status;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
74062306a36Sopenharmony_ci	if (!cqp_request)
74162306a36Sopenharmony_ci		return -ENOMEM;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
74462306a36Sopenharmony_ci	qp_info = &cqp_request->info.in.u.qp_create.info;
74562306a36Sopenharmony_ci	memset(qp_info, 0, sizeof(*qp_info));
74662306a36Sopenharmony_ci	qp_info->mac_valid = true;
74762306a36Sopenharmony_ci	qp_info->cq_num_valid = true;
74862306a36Sopenharmony_ci	qp_info->next_iwarp_state = IRDMA_QP_STATE_IDLE;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_QP_CREATE;
75162306a36Sopenharmony_ci	cqp_info->post_sq = 1;
75262306a36Sopenharmony_ci	cqp_info->in.u.qp_create.qp = &iwqp->sc_qp;
75362306a36Sopenharmony_ci	cqp_info->in.u.qp_create.scratch = (uintptr_t)cqp_request;
75462306a36Sopenharmony_ci	status = irdma_handle_cqp_op(rf, cqp_request);
75562306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	return status;
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic void irdma_roce_fill_and_set_qpctx_info(struct irdma_qp *iwqp,
76162306a36Sopenharmony_ci					       struct irdma_qp_host_ctx_info *ctx_info)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	struct irdma_device *iwdev = iwqp->iwdev;
76462306a36Sopenharmony_ci	struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
76562306a36Sopenharmony_ci	struct irdma_roce_offload_info *roce_info;
76662306a36Sopenharmony_ci	struct irdma_udp_offload_info *udp_info;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	udp_info = &iwqp->udp_info;
76962306a36Sopenharmony_ci	udp_info->snd_mss = ib_mtu_enum_to_int(ib_mtu_int_to_enum(iwdev->vsi.mtu));
77062306a36Sopenharmony_ci	udp_info->cwnd = iwdev->roce_cwnd;
77162306a36Sopenharmony_ci	udp_info->rexmit_thresh = 2;
77262306a36Sopenharmony_ci	udp_info->rnr_nak_thresh = 2;
77362306a36Sopenharmony_ci	udp_info->src_port = 0xc000;
77462306a36Sopenharmony_ci	udp_info->dst_port = ROCE_V2_UDP_DPORT;
77562306a36Sopenharmony_ci	roce_info = &iwqp->roce_info;
77662306a36Sopenharmony_ci	ether_addr_copy(roce_info->mac_addr, iwdev->netdev->dev_addr);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	roce_info->rd_en = true;
77962306a36Sopenharmony_ci	roce_info->wr_rdresp_en = true;
78062306a36Sopenharmony_ci	roce_info->bind_en = true;
78162306a36Sopenharmony_ci	roce_info->dcqcn_en = false;
78262306a36Sopenharmony_ci	roce_info->rtomin = 5;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	roce_info->ack_credits = iwdev->roce_ackcreds;
78562306a36Sopenharmony_ci	roce_info->ird_size = dev->hw_attrs.max_hw_ird;
78662306a36Sopenharmony_ci	roce_info->ord_size = dev->hw_attrs.max_hw_ord;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (!iwqp->user_mode) {
78962306a36Sopenharmony_ci		roce_info->priv_mode_en = true;
79062306a36Sopenharmony_ci		roce_info->fast_reg_en = true;
79162306a36Sopenharmony_ci		roce_info->udprivcq_en = true;
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci	roce_info->roce_tver = 0;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	ctx_info->roce_info = &iwqp->roce_info;
79662306a36Sopenharmony_ci	ctx_info->udp_info = &iwqp->udp_info;
79762306a36Sopenharmony_ci	irdma_sc_qp_setctx_roce(&iwqp->sc_qp, iwqp->host_ctx.va, ctx_info);
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cistatic void irdma_iw_fill_and_set_qpctx_info(struct irdma_qp *iwqp,
80162306a36Sopenharmony_ci					     struct irdma_qp_host_ctx_info *ctx_info)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct irdma_device *iwdev = iwqp->iwdev;
80462306a36Sopenharmony_ci	struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
80562306a36Sopenharmony_ci	struct irdma_iwarp_offload_info *iwarp_info;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	iwarp_info = &iwqp->iwarp_info;
80862306a36Sopenharmony_ci	ether_addr_copy(iwarp_info->mac_addr, iwdev->netdev->dev_addr);
80962306a36Sopenharmony_ci	iwarp_info->rd_en = true;
81062306a36Sopenharmony_ci	iwarp_info->wr_rdresp_en = true;
81162306a36Sopenharmony_ci	iwarp_info->bind_en = true;
81262306a36Sopenharmony_ci	iwarp_info->ecn_en = true;
81362306a36Sopenharmony_ci	iwarp_info->rtomin = 5;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	if (dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
81662306a36Sopenharmony_ci		iwarp_info->ib_rd_en = true;
81762306a36Sopenharmony_ci	if (!iwqp->user_mode) {
81862306a36Sopenharmony_ci		iwarp_info->priv_mode_en = true;
81962306a36Sopenharmony_ci		iwarp_info->fast_reg_en = true;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci	iwarp_info->ddp_ver = 1;
82262306a36Sopenharmony_ci	iwarp_info->rdmap_ver = 1;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	ctx_info->iwarp_info = &iwqp->iwarp_info;
82562306a36Sopenharmony_ci	ctx_info->iwarp_info_valid = true;
82662306a36Sopenharmony_ci	irdma_sc_qp_setctx(&iwqp->sc_qp, iwqp->host_ctx.va, ctx_info);
82762306a36Sopenharmony_ci	ctx_info->iwarp_info_valid = false;
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cistatic int irdma_validate_qp_attrs(struct ib_qp_init_attr *init_attr,
83162306a36Sopenharmony_ci				   struct irdma_device *iwdev)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
83462306a36Sopenharmony_ci	struct irdma_uk_attrs *uk_attrs = &dev->hw_attrs.uk_attrs;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (init_attr->create_flags)
83762306a36Sopenharmony_ci		return -EOPNOTSUPP;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	if (init_attr->cap.max_inline_data > uk_attrs->max_hw_inline ||
84062306a36Sopenharmony_ci	    init_attr->cap.max_send_sge > uk_attrs->max_hw_wq_frags ||
84162306a36Sopenharmony_ci	    init_attr->cap.max_recv_sge > uk_attrs->max_hw_wq_frags ||
84262306a36Sopenharmony_ci	    init_attr->cap.max_send_wr > uk_attrs->max_hw_wq_quanta ||
84362306a36Sopenharmony_ci	    init_attr->cap.max_recv_wr > uk_attrs->max_hw_rq_quanta)
84462306a36Sopenharmony_ci		return -EINVAL;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	if (rdma_protocol_roce(&iwdev->ibdev, 1)) {
84762306a36Sopenharmony_ci		if (init_attr->qp_type != IB_QPT_RC &&
84862306a36Sopenharmony_ci		    init_attr->qp_type != IB_QPT_UD &&
84962306a36Sopenharmony_ci		    init_attr->qp_type != IB_QPT_GSI)
85062306a36Sopenharmony_ci			return -EOPNOTSUPP;
85162306a36Sopenharmony_ci	} else {
85262306a36Sopenharmony_ci		if (init_attr->qp_type != IB_QPT_RC)
85362306a36Sopenharmony_ci			return -EOPNOTSUPP;
85462306a36Sopenharmony_ci	}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	return 0;
85762306a36Sopenharmony_ci}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_cistatic void irdma_flush_worker(struct work_struct *work)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	struct delayed_work *dwork = to_delayed_work(work);
86262306a36Sopenharmony_ci	struct irdma_qp *iwqp = container_of(dwork, struct irdma_qp, dwork_flush);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	irdma_generate_flush_completions(iwqp);
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci/**
86862306a36Sopenharmony_ci * irdma_create_qp - create qp
86962306a36Sopenharmony_ci * @ibqp: ptr of qp
87062306a36Sopenharmony_ci * @init_attr: attributes for qp
87162306a36Sopenharmony_ci * @udata: user data for create qp
87262306a36Sopenharmony_ci */
87362306a36Sopenharmony_cistatic int irdma_create_qp(struct ib_qp *ibqp,
87462306a36Sopenharmony_ci			   struct ib_qp_init_attr *init_attr,
87562306a36Sopenharmony_ci			   struct ib_udata *udata)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci#define IRDMA_CREATE_QP_MIN_REQ_LEN offsetofend(struct irdma_create_qp_req, user_compl_ctx)
87862306a36Sopenharmony_ci#define IRDMA_CREATE_QP_MIN_RESP_LEN offsetofend(struct irdma_create_qp_resp, rsvd)
87962306a36Sopenharmony_ci	struct ib_pd *ibpd = ibqp->pd;
88062306a36Sopenharmony_ci	struct irdma_pd *iwpd = to_iwpd(ibpd);
88162306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibpd->device);
88262306a36Sopenharmony_ci	struct irdma_pci_f *rf = iwdev->rf;
88362306a36Sopenharmony_ci	struct irdma_qp *iwqp = to_iwqp(ibqp);
88462306a36Sopenharmony_ci	struct irdma_create_qp_resp uresp = {};
88562306a36Sopenharmony_ci	u32 qp_num = 0;
88662306a36Sopenharmony_ci	int err_code;
88762306a36Sopenharmony_ci	struct irdma_sc_qp *qp;
88862306a36Sopenharmony_ci	struct irdma_sc_dev *dev = &rf->sc_dev;
88962306a36Sopenharmony_ci	struct irdma_uk_attrs *uk_attrs = &dev->hw_attrs.uk_attrs;
89062306a36Sopenharmony_ci	struct irdma_qp_init_info init_info = {};
89162306a36Sopenharmony_ci	struct irdma_qp_host_ctx_info *ctx_info;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	err_code = irdma_validate_qp_attrs(init_attr, iwdev);
89462306a36Sopenharmony_ci	if (err_code)
89562306a36Sopenharmony_ci		return err_code;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	if (udata && (udata->inlen < IRDMA_CREATE_QP_MIN_REQ_LEN ||
89862306a36Sopenharmony_ci		      udata->outlen < IRDMA_CREATE_QP_MIN_RESP_LEN))
89962306a36Sopenharmony_ci		return -EINVAL;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	init_info.vsi = &iwdev->vsi;
90262306a36Sopenharmony_ci	init_info.qp_uk_init_info.uk_attrs = uk_attrs;
90362306a36Sopenharmony_ci	init_info.qp_uk_init_info.sq_size = init_attr->cap.max_send_wr;
90462306a36Sopenharmony_ci	init_info.qp_uk_init_info.rq_size = init_attr->cap.max_recv_wr;
90562306a36Sopenharmony_ci	init_info.qp_uk_init_info.max_sq_frag_cnt = init_attr->cap.max_send_sge;
90662306a36Sopenharmony_ci	init_info.qp_uk_init_info.max_rq_frag_cnt = init_attr->cap.max_recv_sge;
90762306a36Sopenharmony_ci	init_info.qp_uk_init_info.max_inline_data = init_attr->cap.max_inline_data;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	qp = &iwqp->sc_qp;
91062306a36Sopenharmony_ci	qp->qp_uk.back_qp = iwqp;
91162306a36Sopenharmony_ci	qp->push_idx = IRDMA_INVALID_PUSH_PAGE_INDEX;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	iwqp->iwdev = iwdev;
91462306a36Sopenharmony_ci	iwqp->q2_ctx_mem.size = ALIGN(IRDMA_Q2_BUF_SIZE + IRDMA_QP_CTX_SIZE,
91562306a36Sopenharmony_ci				      256);
91662306a36Sopenharmony_ci	iwqp->q2_ctx_mem.va = dma_alloc_coherent(dev->hw->device,
91762306a36Sopenharmony_ci						 iwqp->q2_ctx_mem.size,
91862306a36Sopenharmony_ci						 &iwqp->q2_ctx_mem.pa,
91962306a36Sopenharmony_ci						 GFP_KERNEL);
92062306a36Sopenharmony_ci	if (!iwqp->q2_ctx_mem.va)
92162306a36Sopenharmony_ci		return -ENOMEM;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	init_info.q2 = iwqp->q2_ctx_mem.va;
92462306a36Sopenharmony_ci	init_info.q2_pa = iwqp->q2_ctx_mem.pa;
92562306a36Sopenharmony_ci	init_info.host_ctx = (__le64 *)(init_info.q2 + IRDMA_Q2_BUF_SIZE);
92662306a36Sopenharmony_ci	init_info.host_ctx_pa = init_info.q2_pa + IRDMA_Q2_BUF_SIZE;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	if (init_attr->qp_type == IB_QPT_GSI)
92962306a36Sopenharmony_ci		qp_num = 1;
93062306a36Sopenharmony_ci	else
93162306a36Sopenharmony_ci		err_code = irdma_alloc_rsrc(rf, rf->allocated_qps, rf->max_qp,
93262306a36Sopenharmony_ci					    &qp_num, &rf->next_qp);
93362306a36Sopenharmony_ci	if (err_code)
93462306a36Sopenharmony_ci		goto error;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	iwqp->iwpd = iwpd;
93762306a36Sopenharmony_ci	iwqp->ibqp.qp_num = qp_num;
93862306a36Sopenharmony_ci	qp = &iwqp->sc_qp;
93962306a36Sopenharmony_ci	iwqp->iwscq = to_iwcq(init_attr->send_cq);
94062306a36Sopenharmony_ci	iwqp->iwrcq = to_iwcq(init_attr->recv_cq);
94162306a36Sopenharmony_ci	iwqp->host_ctx.va = init_info.host_ctx;
94262306a36Sopenharmony_ci	iwqp->host_ctx.pa = init_info.host_ctx_pa;
94362306a36Sopenharmony_ci	iwqp->host_ctx.size = IRDMA_QP_CTX_SIZE;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	init_info.pd = &iwpd->sc_pd;
94662306a36Sopenharmony_ci	init_info.qp_uk_init_info.qp_id = qp_num;
94762306a36Sopenharmony_ci	if (!rdma_protocol_roce(&iwdev->ibdev, 1))
94862306a36Sopenharmony_ci		init_info.qp_uk_init_info.first_sq_wq = 1;
94962306a36Sopenharmony_ci	iwqp->ctx_info.qp_compl_ctx = (uintptr_t)qp;
95062306a36Sopenharmony_ci	init_waitqueue_head(&iwqp->waitq);
95162306a36Sopenharmony_ci	init_waitqueue_head(&iwqp->mod_qp_waitq);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	if (udata) {
95462306a36Sopenharmony_ci		init_info.qp_uk_init_info.abi_ver = iwpd->sc_pd.abi_ver;
95562306a36Sopenharmony_ci		err_code = irdma_setup_umode_qp(udata, iwdev, iwqp, &init_info,
95662306a36Sopenharmony_ci						init_attr);
95762306a36Sopenharmony_ci	} else {
95862306a36Sopenharmony_ci		INIT_DELAYED_WORK(&iwqp->dwork_flush, irdma_flush_worker);
95962306a36Sopenharmony_ci		init_info.qp_uk_init_info.abi_ver = IRDMA_ABI_VER;
96062306a36Sopenharmony_ci		err_code = irdma_setup_kmode_qp(iwdev, iwqp, &init_info, init_attr);
96162306a36Sopenharmony_ci	}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	if (err_code) {
96462306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev, "VERBS: setup qp failed\n");
96562306a36Sopenharmony_ci		goto error;
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	if (rdma_protocol_roce(&iwdev->ibdev, 1)) {
96962306a36Sopenharmony_ci		if (init_attr->qp_type == IB_QPT_RC) {
97062306a36Sopenharmony_ci			init_info.qp_uk_init_info.type = IRDMA_QP_TYPE_ROCE_RC;
97162306a36Sopenharmony_ci			init_info.qp_uk_init_info.qp_caps = IRDMA_SEND_WITH_IMM |
97262306a36Sopenharmony_ci							    IRDMA_WRITE_WITH_IMM |
97362306a36Sopenharmony_ci							    IRDMA_ROCE;
97462306a36Sopenharmony_ci		} else {
97562306a36Sopenharmony_ci			init_info.qp_uk_init_info.type = IRDMA_QP_TYPE_ROCE_UD;
97662306a36Sopenharmony_ci			init_info.qp_uk_init_info.qp_caps = IRDMA_SEND_WITH_IMM |
97762306a36Sopenharmony_ci							    IRDMA_ROCE;
97862306a36Sopenharmony_ci		}
97962306a36Sopenharmony_ci	} else {
98062306a36Sopenharmony_ci		init_info.qp_uk_init_info.type = IRDMA_QP_TYPE_IWARP;
98162306a36Sopenharmony_ci		init_info.qp_uk_init_info.qp_caps = IRDMA_WRITE_WITH_IMM;
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	if (dev->hw_attrs.uk_attrs.hw_rev > IRDMA_GEN_1)
98562306a36Sopenharmony_ci		init_info.qp_uk_init_info.qp_caps |= IRDMA_PUSH_MODE;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	err_code = irdma_sc_qp_init(qp, &init_info);
98862306a36Sopenharmony_ci	if (err_code) {
98962306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev, "VERBS: qp_init fail\n");
99062306a36Sopenharmony_ci		goto error;
99162306a36Sopenharmony_ci	}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	ctx_info = &iwqp->ctx_info;
99462306a36Sopenharmony_ci	ctx_info->send_cq_num = iwqp->iwscq->sc_cq.cq_uk.cq_id;
99562306a36Sopenharmony_ci	ctx_info->rcv_cq_num = iwqp->iwrcq->sc_cq.cq_uk.cq_id;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	if (rdma_protocol_roce(&iwdev->ibdev, 1))
99862306a36Sopenharmony_ci		irdma_roce_fill_and_set_qpctx_info(iwqp, ctx_info);
99962306a36Sopenharmony_ci	else
100062306a36Sopenharmony_ci		irdma_iw_fill_and_set_qpctx_info(iwqp, ctx_info);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	err_code = irdma_cqp_create_qp_cmd(iwqp);
100362306a36Sopenharmony_ci	if (err_code)
100462306a36Sopenharmony_ci		goto error;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	refcount_set(&iwqp->refcnt, 1);
100762306a36Sopenharmony_ci	spin_lock_init(&iwqp->lock);
100862306a36Sopenharmony_ci	spin_lock_init(&iwqp->sc_qp.pfpdu.lock);
100962306a36Sopenharmony_ci	iwqp->sig_all = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR;
101062306a36Sopenharmony_ci	rf->qp_table[qp_num] = iwqp;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	if (rdma_protocol_roce(&iwdev->ibdev, 1)) {
101362306a36Sopenharmony_ci		if (dev->ws_add(&iwdev->vsi, 0)) {
101462306a36Sopenharmony_ci			irdma_cqp_qp_destroy_cmd(&rf->sc_dev, &iwqp->sc_qp);
101562306a36Sopenharmony_ci			err_code = -EINVAL;
101662306a36Sopenharmony_ci			goto error;
101762306a36Sopenharmony_ci		}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci		irdma_qp_add_qos(&iwqp->sc_qp);
102062306a36Sopenharmony_ci	}
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	if (udata) {
102362306a36Sopenharmony_ci		/* GEN_1 legacy support with libi40iw does not have expanded uresp struct */
102462306a36Sopenharmony_ci		if (udata->outlen < sizeof(uresp)) {
102562306a36Sopenharmony_ci			uresp.lsmm = 1;
102662306a36Sopenharmony_ci			uresp.push_idx = IRDMA_INVALID_PUSH_PAGE_INDEX_GEN_1;
102762306a36Sopenharmony_ci		} else {
102862306a36Sopenharmony_ci			if (rdma_protocol_iwarp(&iwdev->ibdev, 1))
102962306a36Sopenharmony_ci				uresp.lsmm = 1;
103062306a36Sopenharmony_ci		}
103162306a36Sopenharmony_ci		uresp.actual_sq_size = init_info.qp_uk_init_info.sq_size;
103262306a36Sopenharmony_ci		uresp.actual_rq_size = init_info.qp_uk_init_info.rq_size;
103362306a36Sopenharmony_ci		uresp.qp_id = qp_num;
103462306a36Sopenharmony_ci		uresp.qp_caps = qp->qp_uk.qp_caps;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci		err_code = ib_copy_to_udata(udata, &uresp,
103762306a36Sopenharmony_ci					    min(sizeof(uresp), udata->outlen));
103862306a36Sopenharmony_ci		if (err_code) {
103962306a36Sopenharmony_ci			ibdev_dbg(&iwdev->ibdev, "VERBS: copy_to_udata failed\n");
104062306a36Sopenharmony_ci			irdma_destroy_qp(&iwqp->ibqp, udata);
104162306a36Sopenharmony_ci			return err_code;
104262306a36Sopenharmony_ci		}
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	init_completion(&iwqp->free_qp);
104662306a36Sopenharmony_ci	return 0;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cierror:
104962306a36Sopenharmony_ci	irdma_free_qp_rsrc(iwqp);
105062306a36Sopenharmony_ci	return err_code;
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic int irdma_get_ib_acc_flags(struct irdma_qp *iwqp)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	int acc_flags = 0;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	if (rdma_protocol_roce(iwqp->ibqp.device, 1)) {
105862306a36Sopenharmony_ci		if (iwqp->roce_info.wr_rdresp_en) {
105962306a36Sopenharmony_ci			acc_flags |= IB_ACCESS_LOCAL_WRITE;
106062306a36Sopenharmony_ci			acc_flags |= IB_ACCESS_REMOTE_WRITE;
106162306a36Sopenharmony_ci		}
106262306a36Sopenharmony_ci		if (iwqp->roce_info.rd_en)
106362306a36Sopenharmony_ci			acc_flags |= IB_ACCESS_REMOTE_READ;
106462306a36Sopenharmony_ci		if (iwqp->roce_info.bind_en)
106562306a36Sopenharmony_ci			acc_flags |= IB_ACCESS_MW_BIND;
106662306a36Sopenharmony_ci	} else {
106762306a36Sopenharmony_ci		if (iwqp->iwarp_info.wr_rdresp_en) {
106862306a36Sopenharmony_ci			acc_flags |= IB_ACCESS_LOCAL_WRITE;
106962306a36Sopenharmony_ci			acc_flags |= IB_ACCESS_REMOTE_WRITE;
107062306a36Sopenharmony_ci		}
107162306a36Sopenharmony_ci		if (iwqp->iwarp_info.rd_en)
107262306a36Sopenharmony_ci			acc_flags |= IB_ACCESS_REMOTE_READ;
107362306a36Sopenharmony_ci		if (iwqp->iwarp_info.bind_en)
107462306a36Sopenharmony_ci			acc_flags |= IB_ACCESS_MW_BIND;
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci	return acc_flags;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci/**
108062306a36Sopenharmony_ci * irdma_query_qp - query qp attributes
108162306a36Sopenharmony_ci * @ibqp: qp pointer
108262306a36Sopenharmony_ci * @attr: attributes pointer
108362306a36Sopenharmony_ci * @attr_mask: Not used
108462306a36Sopenharmony_ci * @init_attr: qp attributes to return
108562306a36Sopenharmony_ci */
108662306a36Sopenharmony_cistatic int irdma_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
108762306a36Sopenharmony_ci			  int attr_mask, struct ib_qp_init_attr *init_attr)
108862306a36Sopenharmony_ci{
108962306a36Sopenharmony_ci	struct irdma_qp *iwqp = to_iwqp(ibqp);
109062306a36Sopenharmony_ci	struct irdma_sc_qp *qp = &iwqp->sc_qp;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	memset(attr, 0, sizeof(*attr));
109362306a36Sopenharmony_ci	memset(init_attr, 0, sizeof(*init_attr));
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	attr->qp_state = iwqp->ibqp_state;
109662306a36Sopenharmony_ci	attr->cur_qp_state = iwqp->ibqp_state;
109762306a36Sopenharmony_ci	attr->cap.max_send_wr = iwqp->max_send_wr;
109862306a36Sopenharmony_ci	attr->cap.max_recv_wr = iwqp->max_recv_wr;
109962306a36Sopenharmony_ci	attr->cap.max_inline_data = qp->qp_uk.max_inline_data;
110062306a36Sopenharmony_ci	attr->cap.max_send_sge = qp->qp_uk.max_sq_frag_cnt;
110162306a36Sopenharmony_ci	attr->cap.max_recv_sge = qp->qp_uk.max_rq_frag_cnt;
110262306a36Sopenharmony_ci	attr->qp_access_flags = irdma_get_ib_acc_flags(iwqp);
110362306a36Sopenharmony_ci	attr->port_num = 1;
110462306a36Sopenharmony_ci	if (rdma_protocol_roce(ibqp->device, 1)) {
110562306a36Sopenharmony_ci		attr->path_mtu = ib_mtu_int_to_enum(iwqp->udp_info.snd_mss);
110662306a36Sopenharmony_ci		attr->qkey = iwqp->roce_info.qkey;
110762306a36Sopenharmony_ci		attr->rq_psn = iwqp->udp_info.epsn;
110862306a36Sopenharmony_ci		attr->sq_psn = iwqp->udp_info.psn_nxt;
110962306a36Sopenharmony_ci		attr->dest_qp_num = iwqp->roce_info.dest_qp;
111062306a36Sopenharmony_ci		attr->pkey_index = iwqp->roce_info.p_key;
111162306a36Sopenharmony_ci		attr->retry_cnt = iwqp->udp_info.rexmit_thresh;
111262306a36Sopenharmony_ci		attr->rnr_retry = iwqp->udp_info.rnr_nak_thresh;
111362306a36Sopenharmony_ci		attr->max_rd_atomic = iwqp->roce_info.ord_size;
111462306a36Sopenharmony_ci		attr->max_dest_rd_atomic = iwqp->roce_info.ird_size;
111562306a36Sopenharmony_ci	}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	init_attr->event_handler = iwqp->ibqp.event_handler;
111862306a36Sopenharmony_ci	init_attr->qp_context = iwqp->ibqp.qp_context;
111962306a36Sopenharmony_ci	init_attr->send_cq = iwqp->ibqp.send_cq;
112062306a36Sopenharmony_ci	init_attr->recv_cq = iwqp->ibqp.recv_cq;
112162306a36Sopenharmony_ci	init_attr->cap = attr->cap;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	return 0;
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci/**
112762306a36Sopenharmony_ci * irdma_query_pkey - Query partition key
112862306a36Sopenharmony_ci * @ibdev: device pointer from stack
112962306a36Sopenharmony_ci * @port: port number
113062306a36Sopenharmony_ci * @index: index of pkey
113162306a36Sopenharmony_ci * @pkey: pointer to store the pkey
113262306a36Sopenharmony_ci */
113362306a36Sopenharmony_cistatic int irdma_query_pkey(struct ib_device *ibdev, u32 port, u16 index,
113462306a36Sopenharmony_ci			    u16 *pkey)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci	if (index >= IRDMA_PKEY_TBL_SZ)
113762306a36Sopenharmony_ci		return -EINVAL;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	*pkey = IRDMA_DEFAULT_PKEY;
114062306a36Sopenharmony_ci	return 0;
114162306a36Sopenharmony_ci}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_cistatic u8 irdma_roce_get_vlan_prio(const struct ib_gid_attr *attr, u8 prio)
114462306a36Sopenharmony_ci{
114562306a36Sopenharmony_ci	struct net_device *ndev;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	rcu_read_lock();
114862306a36Sopenharmony_ci	ndev = rcu_dereference(attr->ndev);
114962306a36Sopenharmony_ci	if (!ndev)
115062306a36Sopenharmony_ci		goto exit;
115162306a36Sopenharmony_ci	if (is_vlan_dev(ndev)) {
115262306a36Sopenharmony_ci		u16 vlan_qos = vlan_dev_get_egress_qos_mask(ndev, prio);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci		prio = (vlan_qos & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ciexit:
115762306a36Sopenharmony_ci	rcu_read_unlock();
115862306a36Sopenharmony_ci	return prio;
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_cistatic int irdma_wait_for_suspend(struct irdma_qp *iwqp)
116262306a36Sopenharmony_ci{
116362306a36Sopenharmony_ci	if (!wait_event_timeout(iwqp->iwdev->suspend_wq,
116462306a36Sopenharmony_ci				!iwqp->suspend_pending,
116562306a36Sopenharmony_ci				msecs_to_jiffies(IRDMA_EVENT_TIMEOUT_MS))) {
116662306a36Sopenharmony_ci		iwqp->suspend_pending = false;
116762306a36Sopenharmony_ci		ibdev_warn(&iwqp->iwdev->ibdev,
116862306a36Sopenharmony_ci			   "modify_qp timed out waiting for suspend. qp_id = %d, last_ae = 0x%x\n",
116962306a36Sopenharmony_ci			   iwqp->ibqp.qp_num, iwqp->last_aeq);
117062306a36Sopenharmony_ci		return -EBUSY;
117162306a36Sopenharmony_ci	}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	return 0;
117462306a36Sopenharmony_ci}
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci/**
117762306a36Sopenharmony_ci * irdma_modify_qp_roce - modify qp request
117862306a36Sopenharmony_ci * @ibqp: qp's pointer for modify
117962306a36Sopenharmony_ci * @attr: access attributes
118062306a36Sopenharmony_ci * @attr_mask: state mask
118162306a36Sopenharmony_ci * @udata: user data
118262306a36Sopenharmony_ci */
118362306a36Sopenharmony_ciint irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr,
118462306a36Sopenharmony_ci			 int attr_mask, struct ib_udata *udata)
118562306a36Sopenharmony_ci{
118662306a36Sopenharmony_ci#define IRDMA_MODIFY_QP_MIN_REQ_LEN offsetofend(struct irdma_modify_qp_req, rq_flush)
118762306a36Sopenharmony_ci#define IRDMA_MODIFY_QP_MIN_RESP_LEN offsetofend(struct irdma_modify_qp_resp, push_valid)
118862306a36Sopenharmony_ci	struct irdma_pd *iwpd = to_iwpd(ibqp->pd);
118962306a36Sopenharmony_ci	struct irdma_qp *iwqp = to_iwqp(ibqp);
119062306a36Sopenharmony_ci	struct irdma_device *iwdev = iwqp->iwdev;
119162306a36Sopenharmony_ci	struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
119262306a36Sopenharmony_ci	struct irdma_qp_host_ctx_info *ctx_info;
119362306a36Sopenharmony_ci	struct irdma_roce_offload_info *roce_info;
119462306a36Sopenharmony_ci	struct irdma_udp_offload_info *udp_info;
119562306a36Sopenharmony_ci	struct irdma_modify_qp_info info = {};
119662306a36Sopenharmony_ci	struct irdma_modify_qp_resp uresp = {};
119762306a36Sopenharmony_ci	struct irdma_modify_qp_req ureq = {};
119862306a36Sopenharmony_ci	unsigned long flags;
119962306a36Sopenharmony_ci	u8 issue_modify_qp = 0;
120062306a36Sopenharmony_ci	int ret = 0;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	ctx_info = &iwqp->ctx_info;
120362306a36Sopenharmony_ci	roce_info = &iwqp->roce_info;
120462306a36Sopenharmony_ci	udp_info = &iwqp->udp_info;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	if (udata) {
120762306a36Sopenharmony_ci		/* udata inlen/outlen can be 0 when supporting legacy libi40iw */
120862306a36Sopenharmony_ci		if ((udata->inlen && udata->inlen < IRDMA_MODIFY_QP_MIN_REQ_LEN) ||
120962306a36Sopenharmony_ci		    (udata->outlen && udata->outlen < IRDMA_MODIFY_QP_MIN_RESP_LEN))
121062306a36Sopenharmony_ci			return -EINVAL;
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
121462306a36Sopenharmony_ci		return -EOPNOTSUPP;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	if (attr_mask & IB_QP_DEST_QPN)
121762306a36Sopenharmony_ci		roce_info->dest_qp = attr->dest_qp_num;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	if (attr_mask & IB_QP_PKEY_INDEX) {
122062306a36Sopenharmony_ci		ret = irdma_query_pkey(ibqp->device, 0, attr->pkey_index,
122162306a36Sopenharmony_ci				       &roce_info->p_key);
122262306a36Sopenharmony_ci		if (ret)
122362306a36Sopenharmony_ci			return ret;
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	if (attr_mask & IB_QP_QKEY)
122762306a36Sopenharmony_ci		roce_info->qkey = attr->qkey;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	if (attr_mask & IB_QP_PATH_MTU)
123062306a36Sopenharmony_ci		udp_info->snd_mss = ib_mtu_enum_to_int(attr->path_mtu);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	if (attr_mask & IB_QP_SQ_PSN) {
123362306a36Sopenharmony_ci		udp_info->psn_nxt = attr->sq_psn;
123462306a36Sopenharmony_ci		udp_info->lsn =  0xffff;
123562306a36Sopenharmony_ci		udp_info->psn_una = attr->sq_psn;
123662306a36Sopenharmony_ci		udp_info->psn_max = attr->sq_psn;
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	if (attr_mask & IB_QP_RQ_PSN)
124062306a36Sopenharmony_ci		udp_info->epsn = attr->rq_psn;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	if (attr_mask & IB_QP_RNR_RETRY)
124362306a36Sopenharmony_ci		udp_info->rnr_nak_thresh = attr->rnr_retry;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (attr_mask & IB_QP_RETRY_CNT)
124662306a36Sopenharmony_ci		udp_info->rexmit_thresh = attr->retry_cnt;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	ctx_info->roce_info->pd_id = iwpd->sc_pd.pd_id;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	if (attr_mask & IB_QP_AV) {
125162306a36Sopenharmony_ci		struct irdma_av *av = &iwqp->roce_ah.av;
125262306a36Sopenharmony_ci		const struct ib_gid_attr *sgid_attr =
125362306a36Sopenharmony_ci				attr->ah_attr.grh.sgid_attr;
125462306a36Sopenharmony_ci		u16 vlan_id = VLAN_N_VID;
125562306a36Sopenharmony_ci		u32 local_ip[4];
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci		memset(&iwqp->roce_ah, 0, sizeof(iwqp->roce_ah));
125862306a36Sopenharmony_ci		if (attr->ah_attr.ah_flags & IB_AH_GRH) {
125962306a36Sopenharmony_ci			udp_info->ttl = attr->ah_attr.grh.hop_limit;
126062306a36Sopenharmony_ci			udp_info->flow_label = attr->ah_attr.grh.flow_label;
126162306a36Sopenharmony_ci			udp_info->tos = attr->ah_attr.grh.traffic_class;
126262306a36Sopenharmony_ci			udp_info->src_port =
126362306a36Sopenharmony_ci				rdma_get_udp_sport(udp_info->flow_label,
126462306a36Sopenharmony_ci						   ibqp->qp_num,
126562306a36Sopenharmony_ci						   roce_info->dest_qp);
126662306a36Sopenharmony_ci			irdma_qp_rem_qos(&iwqp->sc_qp);
126762306a36Sopenharmony_ci			dev->ws_remove(iwqp->sc_qp.vsi, ctx_info->user_pri);
126862306a36Sopenharmony_ci			if (iwqp->sc_qp.vsi->dscp_mode)
126962306a36Sopenharmony_ci				ctx_info->user_pri =
127062306a36Sopenharmony_ci				iwqp->sc_qp.vsi->dscp_map[irdma_tos2dscp(udp_info->tos)];
127162306a36Sopenharmony_ci			else
127262306a36Sopenharmony_ci				ctx_info->user_pri = rt_tos2priority(udp_info->tos);
127362306a36Sopenharmony_ci		}
127462306a36Sopenharmony_ci		ret = rdma_read_gid_l2_fields(sgid_attr, &vlan_id,
127562306a36Sopenharmony_ci					      ctx_info->roce_info->mac_addr);
127662306a36Sopenharmony_ci		if (ret)
127762306a36Sopenharmony_ci			return ret;
127862306a36Sopenharmony_ci		ctx_info->user_pri = irdma_roce_get_vlan_prio(sgid_attr,
127962306a36Sopenharmony_ci							      ctx_info->user_pri);
128062306a36Sopenharmony_ci		if (dev->ws_add(iwqp->sc_qp.vsi, ctx_info->user_pri))
128162306a36Sopenharmony_ci			return -ENOMEM;
128262306a36Sopenharmony_ci		iwqp->sc_qp.user_pri = ctx_info->user_pri;
128362306a36Sopenharmony_ci		irdma_qp_add_qos(&iwqp->sc_qp);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci		if (vlan_id >= VLAN_N_VID && iwdev->dcb_vlan_mode)
128662306a36Sopenharmony_ci			vlan_id = 0;
128762306a36Sopenharmony_ci		if (vlan_id < VLAN_N_VID) {
128862306a36Sopenharmony_ci			udp_info->insert_vlan_tag = true;
128962306a36Sopenharmony_ci			udp_info->vlan_tag = vlan_id |
129062306a36Sopenharmony_ci				ctx_info->user_pri << VLAN_PRIO_SHIFT;
129162306a36Sopenharmony_ci		} else {
129262306a36Sopenharmony_ci			udp_info->insert_vlan_tag = false;
129362306a36Sopenharmony_ci		}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci		av->attrs = attr->ah_attr;
129662306a36Sopenharmony_ci		rdma_gid2ip((struct sockaddr *)&av->sgid_addr, &sgid_attr->gid);
129762306a36Sopenharmony_ci		rdma_gid2ip((struct sockaddr *)&av->dgid_addr, &attr->ah_attr.grh.dgid);
129862306a36Sopenharmony_ci		av->net_type = rdma_gid_attr_network_type(sgid_attr);
129962306a36Sopenharmony_ci		if (av->net_type == RDMA_NETWORK_IPV6) {
130062306a36Sopenharmony_ci			__be32 *daddr =
130162306a36Sopenharmony_ci				av->dgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32;
130262306a36Sopenharmony_ci			__be32 *saddr =
130362306a36Sopenharmony_ci				av->sgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci			irdma_copy_ip_ntohl(&udp_info->dest_ip_addr[0], daddr);
130662306a36Sopenharmony_ci			irdma_copy_ip_ntohl(&udp_info->local_ipaddr[0], saddr);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci			udp_info->ipv4 = false;
130962306a36Sopenharmony_ci			irdma_copy_ip_ntohl(local_ip, daddr);
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci		} else if (av->net_type == RDMA_NETWORK_IPV4) {
131262306a36Sopenharmony_ci			__be32 saddr = av->sgid_addr.saddr_in.sin_addr.s_addr;
131362306a36Sopenharmony_ci			__be32 daddr = av->dgid_addr.saddr_in.sin_addr.s_addr;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci			local_ip[0] = ntohl(daddr);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci			udp_info->ipv4 = true;
131862306a36Sopenharmony_ci			udp_info->dest_ip_addr[0] = 0;
131962306a36Sopenharmony_ci			udp_info->dest_ip_addr[1] = 0;
132062306a36Sopenharmony_ci			udp_info->dest_ip_addr[2] = 0;
132162306a36Sopenharmony_ci			udp_info->dest_ip_addr[3] = local_ip[0];
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci			udp_info->local_ipaddr[0] = 0;
132462306a36Sopenharmony_ci			udp_info->local_ipaddr[1] = 0;
132562306a36Sopenharmony_ci			udp_info->local_ipaddr[2] = 0;
132662306a36Sopenharmony_ci			udp_info->local_ipaddr[3] = ntohl(saddr);
132762306a36Sopenharmony_ci		}
132862306a36Sopenharmony_ci		udp_info->arp_idx =
132962306a36Sopenharmony_ci			irdma_add_arp(iwdev->rf, local_ip, udp_info->ipv4,
133062306a36Sopenharmony_ci				      attr->ah_attr.roce.dmac);
133162306a36Sopenharmony_ci	}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
133462306a36Sopenharmony_ci		if (attr->max_rd_atomic > dev->hw_attrs.max_hw_ord) {
133562306a36Sopenharmony_ci			ibdev_err(&iwdev->ibdev,
133662306a36Sopenharmony_ci				  "rd_atomic = %d, above max_hw_ord=%d\n",
133762306a36Sopenharmony_ci				  attr->max_rd_atomic,
133862306a36Sopenharmony_ci				  dev->hw_attrs.max_hw_ord);
133962306a36Sopenharmony_ci			return -EINVAL;
134062306a36Sopenharmony_ci		}
134162306a36Sopenharmony_ci		if (attr->max_rd_atomic)
134262306a36Sopenharmony_ci			roce_info->ord_size = attr->max_rd_atomic;
134362306a36Sopenharmony_ci		info.ord_valid = true;
134462306a36Sopenharmony_ci	}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
134762306a36Sopenharmony_ci		if (attr->max_dest_rd_atomic > dev->hw_attrs.max_hw_ird) {
134862306a36Sopenharmony_ci			ibdev_err(&iwdev->ibdev,
134962306a36Sopenharmony_ci				  "rd_atomic = %d, above max_hw_ird=%d\n",
135062306a36Sopenharmony_ci				   attr->max_rd_atomic,
135162306a36Sopenharmony_ci				   dev->hw_attrs.max_hw_ird);
135262306a36Sopenharmony_ci			return -EINVAL;
135362306a36Sopenharmony_ci		}
135462306a36Sopenharmony_ci		if (attr->max_dest_rd_atomic)
135562306a36Sopenharmony_ci			roce_info->ird_size = attr->max_dest_rd_atomic;
135662306a36Sopenharmony_ci	}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	if (attr_mask & IB_QP_ACCESS_FLAGS) {
135962306a36Sopenharmony_ci		if (attr->qp_access_flags & IB_ACCESS_LOCAL_WRITE)
136062306a36Sopenharmony_ci			roce_info->wr_rdresp_en = true;
136162306a36Sopenharmony_ci		if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE)
136262306a36Sopenharmony_ci			roce_info->wr_rdresp_en = true;
136362306a36Sopenharmony_ci		if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ)
136462306a36Sopenharmony_ci			roce_info->rd_en = true;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	wait_event(iwqp->mod_qp_waitq, !atomic_read(&iwqp->hw_mod_qp_pend));
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	ibdev_dbg(&iwdev->ibdev,
137062306a36Sopenharmony_ci		  "VERBS: caller: %pS qp_id=%d to_ibqpstate=%d ibqpstate=%d irdma_qpstate=%d attr_mask=0x%x\n",
137162306a36Sopenharmony_ci		  __builtin_return_address(0), ibqp->qp_num, attr->qp_state,
137262306a36Sopenharmony_ci		  iwqp->ibqp_state, iwqp->iwarp_state, attr_mask);
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	spin_lock_irqsave(&iwqp->lock, flags);
137562306a36Sopenharmony_ci	if (attr_mask & IB_QP_STATE) {
137662306a36Sopenharmony_ci		if (!ib_modify_qp_is_ok(iwqp->ibqp_state, attr->qp_state,
137762306a36Sopenharmony_ci					iwqp->ibqp.qp_type, attr_mask)) {
137862306a36Sopenharmony_ci			ibdev_warn(&iwdev->ibdev, "modify_qp invalid for qp_id=%d, old_state=0x%x, new_state=0x%x\n",
137962306a36Sopenharmony_ci				   iwqp->ibqp.qp_num, iwqp->ibqp_state,
138062306a36Sopenharmony_ci				   attr->qp_state);
138162306a36Sopenharmony_ci			ret = -EINVAL;
138262306a36Sopenharmony_ci			goto exit;
138362306a36Sopenharmony_ci		}
138462306a36Sopenharmony_ci		info.curr_iwarp_state = iwqp->iwarp_state;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci		switch (attr->qp_state) {
138762306a36Sopenharmony_ci		case IB_QPS_INIT:
138862306a36Sopenharmony_ci			if (iwqp->iwarp_state > IRDMA_QP_STATE_IDLE) {
138962306a36Sopenharmony_ci				ret = -EINVAL;
139062306a36Sopenharmony_ci				goto exit;
139162306a36Sopenharmony_ci			}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci			if (iwqp->iwarp_state == IRDMA_QP_STATE_INVALID) {
139462306a36Sopenharmony_ci				info.next_iwarp_state = IRDMA_QP_STATE_IDLE;
139562306a36Sopenharmony_ci				issue_modify_qp = 1;
139662306a36Sopenharmony_ci			}
139762306a36Sopenharmony_ci			break;
139862306a36Sopenharmony_ci		case IB_QPS_RTR:
139962306a36Sopenharmony_ci			if (iwqp->iwarp_state > IRDMA_QP_STATE_IDLE) {
140062306a36Sopenharmony_ci				ret = -EINVAL;
140162306a36Sopenharmony_ci				goto exit;
140262306a36Sopenharmony_ci			}
140362306a36Sopenharmony_ci			info.arp_cache_idx_valid = true;
140462306a36Sopenharmony_ci			info.cq_num_valid = true;
140562306a36Sopenharmony_ci			info.next_iwarp_state = IRDMA_QP_STATE_RTR;
140662306a36Sopenharmony_ci			issue_modify_qp = 1;
140762306a36Sopenharmony_ci			break;
140862306a36Sopenharmony_ci		case IB_QPS_RTS:
140962306a36Sopenharmony_ci			if (iwqp->ibqp_state < IB_QPS_RTR ||
141062306a36Sopenharmony_ci			    iwqp->ibqp_state == IB_QPS_ERR) {
141162306a36Sopenharmony_ci				ret = -EINVAL;
141262306a36Sopenharmony_ci				goto exit;
141362306a36Sopenharmony_ci			}
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci			info.arp_cache_idx_valid = true;
141662306a36Sopenharmony_ci			info.cq_num_valid = true;
141762306a36Sopenharmony_ci			info.ord_valid = true;
141862306a36Sopenharmony_ci			info.next_iwarp_state = IRDMA_QP_STATE_RTS;
141962306a36Sopenharmony_ci			issue_modify_qp = 1;
142062306a36Sopenharmony_ci			if (iwdev->push_mode && udata &&
142162306a36Sopenharmony_ci			    iwqp->sc_qp.push_idx == IRDMA_INVALID_PUSH_PAGE_INDEX &&
142262306a36Sopenharmony_ci			    dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
142362306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwqp->lock, flags);
142462306a36Sopenharmony_ci				irdma_alloc_push_page(iwqp);
142562306a36Sopenharmony_ci				spin_lock_irqsave(&iwqp->lock, flags);
142662306a36Sopenharmony_ci			}
142762306a36Sopenharmony_ci			break;
142862306a36Sopenharmony_ci		case IB_QPS_SQD:
142962306a36Sopenharmony_ci			if (iwqp->iwarp_state == IRDMA_QP_STATE_SQD)
143062306a36Sopenharmony_ci				goto exit;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci			if (iwqp->iwarp_state != IRDMA_QP_STATE_RTS) {
143362306a36Sopenharmony_ci				ret = -EINVAL;
143462306a36Sopenharmony_ci				goto exit;
143562306a36Sopenharmony_ci			}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci			info.next_iwarp_state = IRDMA_QP_STATE_SQD;
143862306a36Sopenharmony_ci			issue_modify_qp = 1;
143962306a36Sopenharmony_ci			iwqp->suspend_pending = true;
144062306a36Sopenharmony_ci			break;
144162306a36Sopenharmony_ci		case IB_QPS_SQE:
144262306a36Sopenharmony_ci		case IB_QPS_ERR:
144362306a36Sopenharmony_ci		case IB_QPS_RESET:
144462306a36Sopenharmony_ci			if (iwqp->iwarp_state == IRDMA_QP_STATE_ERROR) {
144562306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwqp->lock, flags);
144662306a36Sopenharmony_ci				if (udata && udata->inlen) {
144762306a36Sopenharmony_ci					if (ib_copy_from_udata(&ureq, udata,
144862306a36Sopenharmony_ci					    min(sizeof(ureq), udata->inlen)))
144962306a36Sopenharmony_ci						return -EINVAL;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci					irdma_flush_wqes(iwqp,
145262306a36Sopenharmony_ci					    (ureq.sq_flush ? IRDMA_FLUSH_SQ : 0) |
145362306a36Sopenharmony_ci					    (ureq.rq_flush ? IRDMA_FLUSH_RQ : 0) |
145462306a36Sopenharmony_ci					    IRDMA_REFLUSH);
145562306a36Sopenharmony_ci				}
145662306a36Sopenharmony_ci				return 0;
145762306a36Sopenharmony_ci			}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci			info.next_iwarp_state = IRDMA_QP_STATE_ERROR;
146062306a36Sopenharmony_ci			issue_modify_qp = 1;
146162306a36Sopenharmony_ci			break;
146262306a36Sopenharmony_ci		default:
146362306a36Sopenharmony_ci			ret = -EINVAL;
146462306a36Sopenharmony_ci			goto exit;
146562306a36Sopenharmony_ci		}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci		iwqp->ibqp_state = attr->qp_state;
146862306a36Sopenharmony_ci	}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	ctx_info->send_cq_num = iwqp->iwscq->sc_cq.cq_uk.cq_id;
147162306a36Sopenharmony_ci	ctx_info->rcv_cq_num = iwqp->iwrcq->sc_cq.cq_uk.cq_id;
147262306a36Sopenharmony_ci	irdma_sc_qp_setctx_roce(&iwqp->sc_qp, iwqp->host_ctx.va, ctx_info);
147362306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwqp->lock, flags);
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	if (attr_mask & IB_QP_STATE) {
147662306a36Sopenharmony_ci		if (issue_modify_qp) {
147762306a36Sopenharmony_ci			ctx_info->rem_endpoint_idx = udp_info->arp_idx;
147862306a36Sopenharmony_ci			if (irdma_hw_modify_qp(iwdev, iwqp, &info, true))
147962306a36Sopenharmony_ci				return -EINVAL;
148062306a36Sopenharmony_ci			if (info.next_iwarp_state == IRDMA_QP_STATE_SQD) {
148162306a36Sopenharmony_ci				ret = irdma_wait_for_suspend(iwqp);
148262306a36Sopenharmony_ci				if (ret)
148362306a36Sopenharmony_ci					return ret;
148462306a36Sopenharmony_ci			}
148562306a36Sopenharmony_ci			spin_lock_irqsave(&iwqp->lock, flags);
148662306a36Sopenharmony_ci			if (iwqp->iwarp_state == info.curr_iwarp_state) {
148762306a36Sopenharmony_ci				iwqp->iwarp_state = info.next_iwarp_state;
148862306a36Sopenharmony_ci				iwqp->ibqp_state = attr->qp_state;
148962306a36Sopenharmony_ci			}
149062306a36Sopenharmony_ci			if (iwqp->ibqp_state > IB_QPS_RTS &&
149162306a36Sopenharmony_ci			    !iwqp->flush_issued) {
149262306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwqp->lock, flags);
149362306a36Sopenharmony_ci				irdma_flush_wqes(iwqp, IRDMA_FLUSH_SQ |
149462306a36Sopenharmony_ci						       IRDMA_FLUSH_RQ |
149562306a36Sopenharmony_ci						       IRDMA_FLUSH_WAIT);
149662306a36Sopenharmony_ci				iwqp->flush_issued = 1;
149762306a36Sopenharmony_ci			} else {
149862306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwqp->lock, flags);
149962306a36Sopenharmony_ci			}
150062306a36Sopenharmony_ci		} else {
150162306a36Sopenharmony_ci			iwqp->ibqp_state = attr->qp_state;
150262306a36Sopenharmony_ci		}
150362306a36Sopenharmony_ci		if (udata && udata->outlen && dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
150462306a36Sopenharmony_ci			struct irdma_ucontext *ucontext;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci			ucontext = rdma_udata_to_drv_context(udata,
150762306a36Sopenharmony_ci					struct irdma_ucontext, ibucontext);
150862306a36Sopenharmony_ci			if (iwqp->sc_qp.push_idx != IRDMA_INVALID_PUSH_PAGE_INDEX &&
150962306a36Sopenharmony_ci			    !iwqp->push_wqe_mmap_entry &&
151062306a36Sopenharmony_ci			    !irdma_setup_push_mmap_entries(ucontext, iwqp,
151162306a36Sopenharmony_ci				&uresp.push_wqe_mmap_key, &uresp.push_db_mmap_key)) {
151262306a36Sopenharmony_ci				uresp.push_valid = 1;
151362306a36Sopenharmony_ci				uresp.push_offset = iwqp->sc_qp.push_offset;
151462306a36Sopenharmony_ci			}
151562306a36Sopenharmony_ci			ret = ib_copy_to_udata(udata, &uresp, min(sizeof(uresp),
151662306a36Sopenharmony_ci					       udata->outlen));
151762306a36Sopenharmony_ci			if (ret) {
151862306a36Sopenharmony_ci				irdma_remove_push_mmap_entries(iwqp);
151962306a36Sopenharmony_ci				ibdev_dbg(&iwdev->ibdev,
152062306a36Sopenharmony_ci					  "VERBS: copy_to_udata failed\n");
152162306a36Sopenharmony_ci				return ret;
152262306a36Sopenharmony_ci			}
152362306a36Sopenharmony_ci		}
152462306a36Sopenharmony_ci	}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	return 0;
152762306a36Sopenharmony_ciexit:
152862306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwqp->lock, flags);
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	return ret;
153162306a36Sopenharmony_ci}
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci/**
153462306a36Sopenharmony_ci * irdma_modify_qp - modify qp request
153562306a36Sopenharmony_ci * @ibqp: qp's pointer for modify
153662306a36Sopenharmony_ci * @attr: access attributes
153762306a36Sopenharmony_ci * @attr_mask: state mask
153862306a36Sopenharmony_ci * @udata: user data
153962306a36Sopenharmony_ci */
154062306a36Sopenharmony_ciint irdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
154162306a36Sopenharmony_ci		    struct ib_udata *udata)
154262306a36Sopenharmony_ci{
154362306a36Sopenharmony_ci#define IRDMA_MODIFY_QP_MIN_REQ_LEN offsetofend(struct irdma_modify_qp_req, rq_flush)
154462306a36Sopenharmony_ci#define IRDMA_MODIFY_QP_MIN_RESP_LEN offsetofend(struct irdma_modify_qp_resp, push_valid)
154562306a36Sopenharmony_ci	struct irdma_qp *iwqp = to_iwqp(ibqp);
154662306a36Sopenharmony_ci	struct irdma_device *iwdev = iwqp->iwdev;
154762306a36Sopenharmony_ci	struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
154862306a36Sopenharmony_ci	struct irdma_qp_host_ctx_info *ctx_info;
154962306a36Sopenharmony_ci	struct irdma_tcp_offload_info *tcp_info;
155062306a36Sopenharmony_ci	struct irdma_iwarp_offload_info *offload_info;
155162306a36Sopenharmony_ci	struct irdma_modify_qp_info info = {};
155262306a36Sopenharmony_ci	struct irdma_modify_qp_resp uresp = {};
155362306a36Sopenharmony_ci	struct irdma_modify_qp_req ureq = {};
155462306a36Sopenharmony_ci	u8 issue_modify_qp = 0;
155562306a36Sopenharmony_ci	u8 dont_wait = 0;
155662306a36Sopenharmony_ci	int err;
155762306a36Sopenharmony_ci	unsigned long flags;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	if (udata) {
156062306a36Sopenharmony_ci		/* udata inlen/outlen can be 0 when supporting legacy libi40iw */
156162306a36Sopenharmony_ci		if ((udata->inlen && udata->inlen < IRDMA_MODIFY_QP_MIN_REQ_LEN) ||
156262306a36Sopenharmony_ci		    (udata->outlen && udata->outlen < IRDMA_MODIFY_QP_MIN_RESP_LEN))
156362306a36Sopenharmony_ci			return -EINVAL;
156462306a36Sopenharmony_ci	}
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
156762306a36Sopenharmony_ci		return -EOPNOTSUPP;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	ctx_info = &iwqp->ctx_info;
157062306a36Sopenharmony_ci	offload_info = &iwqp->iwarp_info;
157162306a36Sopenharmony_ci	tcp_info = &iwqp->tcp_info;
157262306a36Sopenharmony_ci	wait_event(iwqp->mod_qp_waitq, !atomic_read(&iwqp->hw_mod_qp_pend));
157362306a36Sopenharmony_ci	ibdev_dbg(&iwdev->ibdev,
157462306a36Sopenharmony_ci		  "VERBS: caller: %pS qp_id=%d to_ibqpstate=%d ibqpstate=%d irdma_qpstate=%d last_aeq=%d hw_tcp_state=%d hw_iwarp_state=%d attr_mask=0x%x\n",
157562306a36Sopenharmony_ci		  __builtin_return_address(0), ibqp->qp_num, attr->qp_state,
157662306a36Sopenharmony_ci		  iwqp->ibqp_state, iwqp->iwarp_state, iwqp->last_aeq,
157762306a36Sopenharmony_ci		  iwqp->hw_tcp_state, iwqp->hw_iwarp_state, attr_mask);
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	spin_lock_irqsave(&iwqp->lock, flags);
158062306a36Sopenharmony_ci	if (attr_mask & IB_QP_STATE) {
158162306a36Sopenharmony_ci		info.curr_iwarp_state = iwqp->iwarp_state;
158262306a36Sopenharmony_ci		switch (attr->qp_state) {
158362306a36Sopenharmony_ci		case IB_QPS_INIT:
158462306a36Sopenharmony_ci		case IB_QPS_RTR:
158562306a36Sopenharmony_ci			if (iwqp->iwarp_state > IRDMA_QP_STATE_IDLE) {
158662306a36Sopenharmony_ci				err = -EINVAL;
158762306a36Sopenharmony_ci				goto exit;
158862306a36Sopenharmony_ci			}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci			if (iwqp->iwarp_state == IRDMA_QP_STATE_INVALID) {
159162306a36Sopenharmony_ci				info.next_iwarp_state = IRDMA_QP_STATE_IDLE;
159262306a36Sopenharmony_ci				issue_modify_qp = 1;
159362306a36Sopenharmony_ci			}
159462306a36Sopenharmony_ci			if (iwdev->push_mode && udata &&
159562306a36Sopenharmony_ci			    iwqp->sc_qp.push_idx == IRDMA_INVALID_PUSH_PAGE_INDEX &&
159662306a36Sopenharmony_ci			    dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
159762306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwqp->lock, flags);
159862306a36Sopenharmony_ci				irdma_alloc_push_page(iwqp);
159962306a36Sopenharmony_ci				spin_lock_irqsave(&iwqp->lock, flags);
160062306a36Sopenharmony_ci			}
160162306a36Sopenharmony_ci			break;
160262306a36Sopenharmony_ci		case IB_QPS_RTS:
160362306a36Sopenharmony_ci			if (iwqp->iwarp_state > IRDMA_QP_STATE_RTS ||
160462306a36Sopenharmony_ci			    !iwqp->cm_id) {
160562306a36Sopenharmony_ci				err = -EINVAL;
160662306a36Sopenharmony_ci				goto exit;
160762306a36Sopenharmony_ci			}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci			issue_modify_qp = 1;
161062306a36Sopenharmony_ci			iwqp->hw_tcp_state = IRDMA_TCP_STATE_ESTABLISHED;
161162306a36Sopenharmony_ci			iwqp->hte_added = 1;
161262306a36Sopenharmony_ci			info.next_iwarp_state = IRDMA_QP_STATE_RTS;
161362306a36Sopenharmony_ci			info.tcp_ctx_valid = true;
161462306a36Sopenharmony_ci			info.ord_valid = true;
161562306a36Sopenharmony_ci			info.arp_cache_idx_valid = true;
161662306a36Sopenharmony_ci			info.cq_num_valid = true;
161762306a36Sopenharmony_ci			break;
161862306a36Sopenharmony_ci		case IB_QPS_SQD:
161962306a36Sopenharmony_ci			if (iwqp->hw_iwarp_state > IRDMA_QP_STATE_RTS) {
162062306a36Sopenharmony_ci				err = 0;
162162306a36Sopenharmony_ci				goto exit;
162262306a36Sopenharmony_ci			}
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci			if (iwqp->iwarp_state == IRDMA_QP_STATE_CLOSING ||
162562306a36Sopenharmony_ci			    iwqp->iwarp_state < IRDMA_QP_STATE_RTS) {
162662306a36Sopenharmony_ci				err = 0;
162762306a36Sopenharmony_ci				goto exit;
162862306a36Sopenharmony_ci			}
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci			if (iwqp->iwarp_state > IRDMA_QP_STATE_CLOSING) {
163162306a36Sopenharmony_ci				err = -EINVAL;
163262306a36Sopenharmony_ci				goto exit;
163362306a36Sopenharmony_ci			}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci			info.next_iwarp_state = IRDMA_QP_STATE_CLOSING;
163662306a36Sopenharmony_ci			issue_modify_qp = 1;
163762306a36Sopenharmony_ci			break;
163862306a36Sopenharmony_ci		case IB_QPS_SQE:
163962306a36Sopenharmony_ci			if (iwqp->iwarp_state >= IRDMA_QP_STATE_TERMINATE) {
164062306a36Sopenharmony_ci				err = -EINVAL;
164162306a36Sopenharmony_ci				goto exit;
164262306a36Sopenharmony_ci			}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci			info.next_iwarp_state = IRDMA_QP_STATE_TERMINATE;
164562306a36Sopenharmony_ci			issue_modify_qp = 1;
164662306a36Sopenharmony_ci			break;
164762306a36Sopenharmony_ci		case IB_QPS_ERR:
164862306a36Sopenharmony_ci		case IB_QPS_RESET:
164962306a36Sopenharmony_ci			if (iwqp->iwarp_state == IRDMA_QP_STATE_ERROR) {
165062306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwqp->lock, flags);
165162306a36Sopenharmony_ci				if (udata && udata->inlen) {
165262306a36Sopenharmony_ci					if (ib_copy_from_udata(&ureq, udata,
165362306a36Sopenharmony_ci					    min(sizeof(ureq), udata->inlen)))
165462306a36Sopenharmony_ci						return -EINVAL;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci					irdma_flush_wqes(iwqp,
165762306a36Sopenharmony_ci					    (ureq.sq_flush ? IRDMA_FLUSH_SQ : 0) |
165862306a36Sopenharmony_ci					    (ureq.rq_flush ? IRDMA_FLUSH_RQ : 0) |
165962306a36Sopenharmony_ci					    IRDMA_REFLUSH);
166062306a36Sopenharmony_ci				}
166162306a36Sopenharmony_ci				return 0;
166262306a36Sopenharmony_ci			}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci			if (iwqp->sc_qp.term_flags) {
166562306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwqp->lock, flags);
166662306a36Sopenharmony_ci				irdma_terminate_del_timer(&iwqp->sc_qp);
166762306a36Sopenharmony_ci				spin_lock_irqsave(&iwqp->lock, flags);
166862306a36Sopenharmony_ci			}
166962306a36Sopenharmony_ci			info.next_iwarp_state = IRDMA_QP_STATE_ERROR;
167062306a36Sopenharmony_ci			if (iwqp->hw_tcp_state > IRDMA_TCP_STATE_CLOSED &&
167162306a36Sopenharmony_ci			    iwdev->iw_status &&
167262306a36Sopenharmony_ci			    iwqp->hw_tcp_state != IRDMA_TCP_STATE_TIME_WAIT)
167362306a36Sopenharmony_ci				info.reset_tcp_conn = true;
167462306a36Sopenharmony_ci			else
167562306a36Sopenharmony_ci				dont_wait = 1;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci			issue_modify_qp = 1;
167862306a36Sopenharmony_ci			info.next_iwarp_state = IRDMA_QP_STATE_ERROR;
167962306a36Sopenharmony_ci			break;
168062306a36Sopenharmony_ci		default:
168162306a36Sopenharmony_ci			err = -EINVAL;
168262306a36Sopenharmony_ci			goto exit;
168362306a36Sopenharmony_ci		}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci		iwqp->ibqp_state = attr->qp_state;
168662306a36Sopenharmony_ci	}
168762306a36Sopenharmony_ci	if (attr_mask & IB_QP_ACCESS_FLAGS) {
168862306a36Sopenharmony_ci		ctx_info->iwarp_info_valid = true;
168962306a36Sopenharmony_ci		if (attr->qp_access_flags & IB_ACCESS_LOCAL_WRITE)
169062306a36Sopenharmony_ci			offload_info->wr_rdresp_en = true;
169162306a36Sopenharmony_ci		if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE)
169262306a36Sopenharmony_ci			offload_info->wr_rdresp_en = true;
169362306a36Sopenharmony_ci		if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ)
169462306a36Sopenharmony_ci			offload_info->rd_en = true;
169562306a36Sopenharmony_ci	}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	if (ctx_info->iwarp_info_valid) {
169862306a36Sopenharmony_ci		ctx_info->send_cq_num = iwqp->iwscq->sc_cq.cq_uk.cq_id;
169962306a36Sopenharmony_ci		ctx_info->rcv_cq_num = iwqp->iwrcq->sc_cq.cq_uk.cq_id;
170062306a36Sopenharmony_ci		irdma_sc_qp_setctx(&iwqp->sc_qp, iwqp->host_ctx.va, ctx_info);
170162306a36Sopenharmony_ci	}
170262306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwqp->lock, flags);
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	if (attr_mask & IB_QP_STATE) {
170562306a36Sopenharmony_ci		if (issue_modify_qp) {
170662306a36Sopenharmony_ci			ctx_info->rem_endpoint_idx = tcp_info->arp_idx;
170762306a36Sopenharmony_ci			if (irdma_hw_modify_qp(iwdev, iwqp, &info, true))
170862306a36Sopenharmony_ci				return -EINVAL;
170962306a36Sopenharmony_ci		}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci		spin_lock_irqsave(&iwqp->lock, flags);
171262306a36Sopenharmony_ci		if (iwqp->iwarp_state == info.curr_iwarp_state) {
171362306a36Sopenharmony_ci			iwqp->iwarp_state = info.next_iwarp_state;
171462306a36Sopenharmony_ci			iwqp->ibqp_state = attr->qp_state;
171562306a36Sopenharmony_ci		}
171662306a36Sopenharmony_ci		spin_unlock_irqrestore(&iwqp->lock, flags);
171762306a36Sopenharmony_ci	}
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	if (issue_modify_qp && iwqp->ibqp_state > IB_QPS_RTS) {
172062306a36Sopenharmony_ci		if (dont_wait) {
172162306a36Sopenharmony_ci			if (iwqp->hw_tcp_state) {
172262306a36Sopenharmony_ci				spin_lock_irqsave(&iwqp->lock, flags);
172362306a36Sopenharmony_ci				iwqp->hw_tcp_state = IRDMA_TCP_STATE_CLOSED;
172462306a36Sopenharmony_ci				iwqp->last_aeq = IRDMA_AE_RESET_SENT;
172562306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwqp->lock, flags);
172662306a36Sopenharmony_ci			}
172762306a36Sopenharmony_ci			irdma_cm_disconn(iwqp);
172862306a36Sopenharmony_ci		} else {
172962306a36Sopenharmony_ci			int close_timer_started;
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci			spin_lock_irqsave(&iwdev->cm_core.ht_lock, flags);
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci			if (iwqp->cm_node) {
173462306a36Sopenharmony_ci				refcount_inc(&iwqp->cm_node->refcnt);
173562306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwdev->cm_core.ht_lock, flags);
173662306a36Sopenharmony_ci				close_timer_started = atomic_inc_return(&iwqp->close_timer_started);
173762306a36Sopenharmony_ci				if (iwqp->cm_id && close_timer_started == 1)
173862306a36Sopenharmony_ci					irdma_schedule_cm_timer(iwqp->cm_node,
173962306a36Sopenharmony_ci						(struct irdma_puda_buf *)iwqp,
174062306a36Sopenharmony_ci						IRDMA_TIMER_TYPE_CLOSE, 1, 0);
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci				irdma_rem_ref_cm_node(iwqp->cm_node);
174362306a36Sopenharmony_ci			} else {
174462306a36Sopenharmony_ci				spin_unlock_irqrestore(&iwdev->cm_core.ht_lock, flags);
174562306a36Sopenharmony_ci			}
174662306a36Sopenharmony_ci		}
174762306a36Sopenharmony_ci	}
174862306a36Sopenharmony_ci	if (attr_mask & IB_QP_STATE && udata && udata->outlen &&
174962306a36Sopenharmony_ci	    dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2) {
175062306a36Sopenharmony_ci		struct irdma_ucontext *ucontext;
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci		ucontext = rdma_udata_to_drv_context(udata,
175362306a36Sopenharmony_ci					struct irdma_ucontext, ibucontext);
175462306a36Sopenharmony_ci		if (iwqp->sc_qp.push_idx != IRDMA_INVALID_PUSH_PAGE_INDEX &&
175562306a36Sopenharmony_ci		    !iwqp->push_wqe_mmap_entry &&
175662306a36Sopenharmony_ci		    !irdma_setup_push_mmap_entries(ucontext, iwqp,
175762306a36Sopenharmony_ci			&uresp.push_wqe_mmap_key, &uresp.push_db_mmap_key)) {
175862306a36Sopenharmony_ci			uresp.push_valid = 1;
175962306a36Sopenharmony_ci			uresp.push_offset = iwqp->sc_qp.push_offset;
176062306a36Sopenharmony_ci		}
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci		err = ib_copy_to_udata(udata, &uresp, min(sizeof(uresp),
176362306a36Sopenharmony_ci				       udata->outlen));
176462306a36Sopenharmony_ci		if (err) {
176562306a36Sopenharmony_ci			irdma_remove_push_mmap_entries(iwqp);
176662306a36Sopenharmony_ci			ibdev_dbg(&iwdev->ibdev,
176762306a36Sopenharmony_ci				  "VERBS: copy_to_udata failed\n");
176862306a36Sopenharmony_ci			return err;
176962306a36Sopenharmony_ci		}
177062306a36Sopenharmony_ci	}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	return 0;
177362306a36Sopenharmony_ciexit:
177462306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwqp->lock, flags);
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	return err;
177762306a36Sopenharmony_ci}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci/**
178062306a36Sopenharmony_ci * irdma_cq_free_rsrc - free up resources for cq
178162306a36Sopenharmony_ci * @rf: RDMA PCI function
178262306a36Sopenharmony_ci * @iwcq: cq ptr
178362306a36Sopenharmony_ci */
178462306a36Sopenharmony_cistatic void irdma_cq_free_rsrc(struct irdma_pci_f *rf, struct irdma_cq *iwcq)
178562306a36Sopenharmony_ci{
178662306a36Sopenharmony_ci	struct irdma_sc_cq *cq = &iwcq->sc_cq;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	if (!iwcq->user_mode) {
178962306a36Sopenharmony_ci		dma_free_coherent(rf->sc_dev.hw->device, iwcq->kmem.size,
179062306a36Sopenharmony_ci				  iwcq->kmem.va, iwcq->kmem.pa);
179162306a36Sopenharmony_ci		iwcq->kmem.va = NULL;
179262306a36Sopenharmony_ci		dma_free_coherent(rf->sc_dev.hw->device,
179362306a36Sopenharmony_ci				  iwcq->kmem_shadow.size,
179462306a36Sopenharmony_ci				  iwcq->kmem_shadow.va, iwcq->kmem_shadow.pa);
179562306a36Sopenharmony_ci		iwcq->kmem_shadow.va = NULL;
179662306a36Sopenharmony_ci	}
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	irdma_free_rsrc(rf, rf->allocated_cqs, cq->cq_uk.cq_id);
179962306a36Sopenharmony_ci}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci/**
180262306a36Sopenharmony_ci * irdma_free_cqbuf - worker to free a cq buffer
180362306a36Sopenharmony_ci * @work: provides access to the cq buffer to free
180462306a36Sopenharmony_ci */
180562306a36Sopenharmony_cistatic void irdma_free_cqbuf(struct work_struct *work)
180662306a36Sopenharmony_ci{
180762306a36Sopenharmony_ci	struct irdma_cq_buf *cq_buf = container_of(work, struct irdma_cq_buf, work);
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	dma_free_coherent(cq_buf->hw->device, cq_buf->kmem_buf.size,
181062306a36Sopenharmony_ci			  cq_buf->kmem_buf.va, cq_buf->kmem_buf.pa);
181162306a36Sopenharmony_ci	cq_buf->kmem_buf.va = NULL;
181262306a36Sopenharmony_ci	kfree(cq_buf);
181362306a36Sopenharmony_ci}
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci/**
181662306a36Sopenharmony_ci * irdma_process_resize_list - remove resized cq buffers from the resize_list
181762306a36Sopenharmony_ci * @iwcq: cq which owns the resize_list
181862306a36Sopenharmony_ci * @iwdev: irdma device
181962306a36Sopenharmony_ci * @lcqe_buf: the buffer where the last cqe is received
182062306a36Sopenharmony_ci */
182162306a36Sopenharmony_cistatic int irdma_process_resize_list(struct irdma_cq *iwcq,
182262306a36Sopenharmony_ci				     struct irdma_device *iwdev,
182362306a36Sopenharmony_ci				     struct irdma_cq_buf *lcqe_buf)
182462306a36Sopenharmony_ci{
182562306a36Sopenharmony_ci	struct list_head *tmp_node, *list_node;
182662306a36Sopenharmony_ci	struct irdma_cq_buf *cq_buf;
182762306a36Sopenharmony_ci	int cnt = 0;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	list_for_each_safe(list_node, tmp_node, &iwcq->resize_list) {
183062306a36Sopenharmony_ci		cq_buf = list_entry(list_node, struct irdma_cq_buf, list);
183162306a36Sopenharmony_ci		if (cq_buf == lcqe_buf)
183262306a36Sopenharmony_ci			return cnt;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci		list_del(&cq_buf->list);
183562306a36Sopenharmony_ci		queue_work(iwdev->cleanup_wq, &cq_buf->work);
183662306a36Sopenharmony_ci		cnt++;
183762306a36Sopenharmony_ci	}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	return cnt;
184062306a36Sopenharmony_ci}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci/**
184362306a36Sopenharmony_ci * irdma_destroy_cq - destroy cq
184462306a36Sopenharmony_ci * @ib_cq: cq pointer
184562306a36Sopenharmony_ci * @udata: user data
184662306a36Sopenharmony_ci */
184762306a36Sopenharmony_cistatic int irdma_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
184862306a36Sopenharmony_ci{
184962306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ib_cq->device);
185062306a36Sopenharmony_ci	struct irdma_cq *iwcq = to_iwcq(ib_cq);
185162306a36Sopenharmony_ci	struct irdma_sc_cq *cq = &iwcq->sc_cq;
185262306a36Sopenharmony_ci	struct irdma_sc_dev *dev = cq->dev;
185362306a36Sopenharmony_ci	struct irdma_sc_ceq *ceq = dev->ceq[cq->ceq_id];
185462306a36Sopenharmony_ci	struct irdma_ceq *iwceq = container_of(ceq, struct irdma_ceq, sc_ceq);
185562306a36Sopenharmony_ci	unsigned long flags;
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	spin_lock_irqsave(&iwcq->lock, flags);
185862306a36Sopenharmony_ci	if (!list_empty(&iwcq->cmpl_generated))
185962306a36Sopenharmony_ci		irdma_remove_cmpls_list(iwcq);
186062306a36Sopenharmony_ci	if (!list_empty(&iwcq->resize_list))
186162306a36Sopenharmony_ci		irdma_process_resize_list(iwcq, iwdev, NULL);
186262306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwcq->lock, flags);
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	irdma_cq_rem_ref(ib_cq);
186562306a36Sopenharmony_ci	wait_for_completion(&iwcq->free_cq);
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	irdma_cq_wq_destroy(iwdev->rf, cq);
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	spin_lock_irqsave(&iwceq->ce_lock, flags);
187062306a36Sopenharmony_ci	irdma_sc_cleanup_ceqes(cq, ceq);
187162306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwceq->ce_lock, flags);
187262306a36Sopenharmony_ci	irdma_cq_free_rsrc(iwdev->rf, iwcq);
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	return 0;
187562306a36Sopenharmony_ci}
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci/**
187862306a36Sopenharmony_ci * irdma_resize_cq - resize cq
187962306a36Sopenharmony_ci * @ibcq: cq to be resized
188062306a36Sopenharmony_ci * @entries: desired cq size
188162306a36Sopenharmony_ci * @udata: user data
188262306a36Sopenharmony_ci */
188362306a36Sopenharmony_cistatic int irdma_resize_cq(struct ib_cq *ibcq, int entries,
188462306a36Sopenharmony_ci			   struct ib_udata *udata)
188562306a36Sopenharmony_ci{
188662306a36Sopenharmony_ci#define IRDMA_RESIZE_CQ_MIN_REQ_LEN offsetofend(struct irdma_resize_cq_req, user_cq_buffer)
188762306a36Sopenharmony_ci	struct irdma_cq *iwcq = to_iwcq(ibcq);
188862306a36Sopenharmony_ci	struct irdma_sc_dev *dev = iwcq->sc_cq.dev;
188962306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
189062306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
189162306a36Sopenharmony_ci	struct irdma_modify_cq_info *m_info;
189262306a36Sopenharmony_ci	struct irdma_modify_cq_info info = {};
189362306a36Sopenharmony_ci	struct irdma_dma_mem kmem_buf;
189462306a36Sopenharmony_ci	struct irdma_cq_mr *cqmr_buf;
189562306a36Sopenharmony_ci	struct irdma_pbl *iwpbl_buf;
189662306a36Sopenharmony_ci	struct irdma_device *iwdev;
189762306a36Sopenharmony_ci	struct irdma_pci_f *rf;
189862306a36Sopenharmony_ci	struct irdma_cq_buf *cq_buf = NULL;
189962306a36Sopenharmony_ci	unsigned long flags;
190062306a36Sopenharmony_ci	int ret;
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	iwdev = to_iwdev(ibcq->device);
190362306a36Sopenharmony_ci	rf = iwdev->rf;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	if (!(rf->sc_dev.hw_attrs.uk_attrs.feature_flags &
190662306a36Sopenharmony_ci	    IRDMA_FEATURE_CQ_RESIZE))
190762306a36Sopenharmony_ci		return -EOPNOTSUPP;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	if (udata && udata->inlen < IRDMA_RESIZE_CQ_MIN_REQ_LEN)
191062306a36Sopenharmony_ci		return -EINVAL;
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	if (entries > rf->max_cqe)
191362306a36Sopenharmony_ci		return -EINVAL;
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	if (!iwcq->user_mode) {
191662306a36Sopenharmony_ci		entries++;
191762306a36Sopenharmony_ci		if (rf->sc_dev.hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
191862306a36Sopenharmony_ci			entries *= 2;
191962306a36Sopenharmony_ci	}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	info.cq_size = max(entries, 4);
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	if (info.cq_size == iwcq->sc_cq.cq_uk.cq_size - 1)
192462306a36Sopenharmony_ci		return 0;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	if (udata) {
192762306a36Sopenharmony_ci		struct irdma_resize_cq_req req = {};
192862306a36Sopenharmony_ci		struct irdma_ucontext *ucontext =
192962306a36Sopenharmony_ci			rdma_udata_to_drv_context(udata, struct irdma_ucontext,
193062306a36Sopenharmony_ci						  ibucontext);
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci		/* CQ resize not supported with legacy GEN_1 libi40iw */
193362306a36Sopenharmony_ci		if (ucontext->legacy_mode)
193462306a36Sopenharmony_ci			return -EOPNOTSUPP;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci		if (ib_copy_from_udata(&req, udata,
193762306a36Sopenharmony_ci				       min(sizeof(req), udata->inlen)))
193862306a36Sopenharmony_ci			return -EINVAL;
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci		spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
194162306a36Sopenharmony_ci		iwpbl_buf = irdma_get_pbl((unsigned long)req.user_cq_buffer,
194262306a36Sopenharmony_ci					  &ucontext->cq_reg_mem_list);
194362306a36Sopenharmony_ci		spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci		if (!iwpbl_buf)
194662306a36Sopenharmony_ci			return -ENOMEM;
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci		cqmr_buf = &iwpbl_buf->cq_mr;
194962306a36Sopenharmony_ci		if (iwpbl_buf->pbl_allocated) {
195062306a36Sopenharmony_ci			info.virtual_map = true;
195162306a36Sopenharmony_ci			info.pbl_chunk_size = 1;
195262306a36Sopenharmony_ci			info.first_pm_pbl_idx = cqmr_buf->cq_pbl.idx;
195362306a36Sopenharmony_ci		} else {
195462306a36Sopenharmony_ci			info.cq_pa = cqmr_buf->cq_pbl.addr;
195562306a36Sopenharmony_ci		}
195662306a36Sopenharmony_ci	} else {
195762306a36Sopenharmony_ci		/* Kmode CQ resize */
195862306a36Sopenharmony_ci		int rsize;
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci		rsize = info.cq_size * sizeof(struct irdma_cqe);
196162306a36Sopenharmony_ci		kmem_buf.size = ALIGN(round_up(rsize, 256), 256);
196262306a36Sopenharmony_ci		kmem_buf.va = dma_alloc_coherent(dev->hw->device,
196362306a36Sopenharmony_ci						 kmem_buf.size, &kmem_buf.pa,
196462306a36Sopenharmony_ci						 GFP_KERNEL);
196562306a36Sopenharmony_ci		if (!kmem_buf.va)
196662306a36Sopenharmony_ci			return -ENOMEM;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci		info.cq_base = kmem_buf.va;
196962306a36Sopenharmony_ci		info.cq_pa = kmem_buf.pa;
197062306a36Sopenharmony_ci		cq_buf = kzalloc(sizeof(*cq_buf), GFP_KERNEL);
197162306a36Sopenharmony_ci		if (!cq_buf) {
197262306a36Sopenharmony_ci			ret = -ENOMEM;
197362306a36Sopenharmony_ci			goto error;
197462306a36Sopenharmony_ci		}
197562306a36Sopenharmony_ci	}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
197862306a36Sopenharmony_ci	if (!cqp_request) {
197962306a36Sopenharmony_ci		ret = -ENOMEM;
198062306a36Sopenharmony_ci		goto error;
198162306a36Sopenharmony_ci	}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	info.shadow_read_threshold = iwcq->sc_cq.shadow_read_threshold;
198462306a36Sopenharmony_ci	info.cq_resize = true;
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
198762306a36Sopenharmony_ci	m_info = &cqp_info->in.u.cq_modify.info;
198862306a36Sopenharmony_ci	memcpy(m_info, &info, sizeof(*m_info));
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_CQ_MODIFY;
199162306a36Sopenharmony_ci	cqp_info->in.u.cq_modify.cq = &iwcq->sc_cq;
199262306a36Sopenharmony_ci	cqp_info->in.u.cq_modify.scratch = (uintptr_t)cqp_request;
199362306a36Sopenharmony_ci	cqp_info->post_sq = 1;
199462306a36Sopenharmony_ci	ret = irdma_handle_cqp_op(rf, cqp_request);
199562306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
199662306a36Sopenharmony_ci	if (ret)
199762306a36Sopenharmony_ci		goto error;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	spin_lock_irqsave(&iwcq->lock, flags);
200062306a36Sopenharmony_ci	if (cq_buf) {
200162306a36Sopenharmony_ci		cq_buf->kmem_buf = iwcq->kmem;
200262306a36Sopenharmony_ci		cq_buf->hw = dev->hw;
200362306a36Sopenharmony_ci		memcpy(&cq_buf->cq_uk, &iwcq->sc_cq.cq_uk, sizeof(cq_buf->cq_uk));
200462306a36Sopenharmony_ci		INIT_WORK(&cq_buf->work, irdma_free_cqbuf);
200562306a36Sopenharmony_ci		list_add_tail(&cq_buf->list, &iwcq->resize_list);
200662306a36Sopenharmony_ci		iwcq->kmem = kmem_buf;
200762306a36Sopenharmony_ci	}
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	irdma_sc_cq_resize(&iwcq->sc_cq, &info);
201062306a36Sopenharmony_ci	ibcq->cqe = info.cq_size - 1;
201162306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwcq->lock, flags);
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	return 0;
201462306a36Sopenharmony_cierror:
201562306a36Sopenharmony_ci	if (!udata) {
201662306a36Sopenharmony_ci		dma_free_coherent(dev->hw->device, kmem_buf.size, kmem_buf.va,
201762306a36Sopenharmony_ci				  kmem_buf.pa);
201862306a36Sopenharmony_ci		kmem_buf.va = NULL;
201962306a36Sopenharmony_ci	}
202062306a36Sopenharmony_ci	kfree(cq_buf);
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	return ret;
202362306a36Sopenharmony_ci}
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_cistatic inline int cq_validate_flags(u32 flags, u8 hw_rev)
202662306a36Sopenharmony_ci{
202762306a36Sopenharmony_ci	/* GEN1 does not support CQ create flags */
202862306a36Sopenharmony_ci	if (hw_rev == IRDMA_GEN_1)
202962306a36Sopenharmony_ci		return flags ? -EOPNOTSUPP : 0;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	return flags & ~IB_UVERBS_CQ_FLAGS_TIMESTAMP_COMPLETION ? -EOPNOTSUPP : 0;
203262306a36Sopenharmony_ci}
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci/**
203562306a36Sopenharmony_ci * irdma_create_cq - create cq
203662306a36Sopenharmony_ci * @ibcq: CQ allocated
203762306a36Sopenharmony_ci * @attr: attributes for cq
203862306a36Sopenharmony_ci * @udata: user data
203962306a36Sopenharmony_ci */
204062306a36Sopenharmony_cistatic int irdma_create_cq(struct ib_cq *ibcq,
204162306a36Sopenharmony_ci			   const struct ib_cq_init_attr *attr,
204262306a36Sopenharmony_ci			   struct ib_udata *udata)
204362306a36Sopenharmony_ci{
204462306a36Sopenharmony_ci#define IRDMA_CREATE_CQ_MIN_REQ_LEN offsetofend(struct irdma_create_cq_req, user_cq_buf)
204562306a36Sopenharmony_ci#define IRDMA_CREATE_CQ_MIN_RESP_LEN offsetofend(struct irdma_create_cq_resp, cq_size)
204662306a36Sopenharmony_ci	struct ib_device *ibdev = ibcq->device;
204762306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibdev);
204862306a36Sopenharmony_ci	struct irdma_pci_f *rf = iwdev->rf;
204962306a36Sopenharmony_ci	struct irdma_cq *iwcq = to_iwcq(ibcq);
205062306a36Sopenharmony_ci	u32 cq_num = 0;
205162306a36Sopenharmony_ci	struct irdma_sc_cq *cq;
205262306a36Sopenharmony_ci	struct irdma_sc_dev *dev = &rf->sc_dev;
205362306a36Sopenharmony_ci	struct irdma_cq_init_info info = {};
205462306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
205562306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
205662306a36Sopenharmony_ci	struct irdma_cq_uk_init_info *ukinfo = &info.cq_uk_init_info;
205762306a36Sopenharmony_ci	unsigned long flags;
205862306a36Sopenharmony_ci	int err_code;
205962306a36Sopenharmony_ci	int entries = attr->cqe;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	err_code = cq_validate_flags(attr->flags, dev->hw_attrs.uk_attrs.hw_rev);
206262306a36Sopenharmony_ci	if (err_code)
206362306a36Sopenharmony_ci		return err_code;
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	if (udata && (udata->inlen < IRDMA_CREATE_CQ_MIN_REQ_LEN ||
206662306a36Sopenharmony_ci		      udata->outlen < IRDMA_CREATE_CQ_MIN_RESP_LEN))
206762306a36Sopenharmony_ci		return -EINVAL;
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	err_code = irdma_alloc_rsrc(rf, rf->allocated_cqs, rf->max_cq, &cq_num,
207062306a36Sopenharmony_ci				    &rf->next_cq);
207162306a36Sopenharmony_ci	if (err_code)
207262306a36Sopenharmony_ci		return err_code;
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	cq = &iwcq->sc_cq;
207562306a36Sopenharmony_ci	cq->back_cq = iwcq;
207662306a36Sopenharmony_ci	refcount_set(&iwcq->refcnt, 1);
207762306a36Sopenharmony_ci	spin_lock_init(&iwcq->lock);
207862306a36Sopenharmony_ci	INIT_LIST_HEAD(&iwcq->resize_list);
207962306a36Sopenharmony_ci	INIT_LIST_HEAD(&iwcq->cmpl_generated);
208062306a36Sopenharmony_ci	info.dev = dev;
208162306a36Sopenharmony_ci	ukinfo->cq_size = max(entries, 4);
208262306a36Sopenharmony_ci	ukinfo->cq_id = cq_num;
208362306a36Sopenharmony_ci	iwcq->ibcq.cqe = info.cq_uk_init_info.cq_size;
208462306a36Sopenharmony_ci	if (attr->comp_vector < rf->ceqs_count)
208562306a36Sopenharmony_ci		info.ceq_id = attr->comp_vector;
208662306a36Sopenharmony_ci	info.ceq_id_valid = true;
208762306a36Sopenharmony_ci	info.ceqe_mask = 1;
208862306a36Sopenharmony_ci	info.type = IRDMA_CQ_TYPE_IWARP;
208962306a36Sopenharmony_ci	info.vsi = &iwdev->vsi;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	if (udata) {
209262306a36Sopenharmony_ci		struct irdma_ucontext *ucontext;
209362306a36Sopenharmony_ci		struct irdma_create_cq_req req = {};
209462306a36Sopenharmony_ci		struct irdma_cq_mr *cqmr;
209562306a36Sopenharmony_ci		struct irdma_pbl *iwpbl;
209662306a36Sopenharmony_ci		struct irdma_pbl *iwpbl_shadow;
209762306a36Sopenharmony_ci		struct irdma_cq_mr *cqmr_shadow;
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci		iwcq->user_mode = true;
210062306a36Sopenharmony_ci		ucontext =
210162306a36Sopenharmony_ci			rdma_udata_to_drv_context(udata, struct irdma_ucontext,
210262306a36Sopenharmony_ci						  ibucontext);
210362306a36Sopenharmony_ci		if (ib_copy_from_udata(&req, udata,
210462306a36Sopenharmony_ci				       min(sizeof(req), udata->inlen))) {
210562306a36Sopenharmony_ci			err_code = -EFAULT;
210662306a36Sopenharmony_ci			goto cq_free_rsrc;
210762306a36Sopenharmony_ci		}
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci		spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
211062306a36Sopenharmony_ci		iwpbl = irdma_get_pbl((unsigned long)req.user_cq_buf,
211162306a36Sopenharmony_ci				      &ucontext->cq_reg_mem_list);
211262306a36Sopenharmony_ci		spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
211362306a36Sopenharmony_ci		if (!iwpbl) {
211462306a36Sopenharmony_ci			err_code = -EPROTO;
211562306a36Sopenharmony_ci			goto cq_free_rsrc;
211662306a36Sopenharmony_ci		}
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci		iwcq->iwpbl = iwpbl;
211962306a36Sopenharmony_ci		iwcq->cq_mem_size = 0;
212062306a36Sopenharmony_ci		cqmr = &iwpbl->cq_mr;
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci		if (rf->sc_dev.hw_attrs.uk_attrs.feature_flags &
212362306a36Sopenharmony_ci		    IRDMA_FEATURE_CQ_RESIZE && !ucontext->legacy_mode) {
212462306a36Sopenharmony_ci			spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
212562306a36Sopenharmony_ci			iwpbl_shadow = irdma_get_pbl(
212662306a36Sopenharmony_ci					(unsigned long)req.user_shadow_area,
212762306a36Sopenharmony_ci					&ucontext->cq_reg_mem_list);
212862306a36Sopenharmony_ci			spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci			if (!iwpbl_shadow) {
213162306a36Sopenharmony_ci				err_code = -EPROTO;
213262306a36Sopenharmony_ci				goto cq_free_rsrc;
213362306a36Sopenharmony_ci			}
213462306a36Sopenharmony_ci			iwcq->iwpbl_shadow = iwpbl_shadow;
213562306a36Sopenharmony_ci			cqmr_shadow = &iwpbl_shadow->cq_mr;
213662306a36Sopenharmony_ci			info.shadow_area_pa = cqmr_shadow->cq_pbl.addr;
213762306a36Sopenharmony_ci			cqmr->split = true;
213862306a36Sopenharmony_ci		} else {
213962306a36Sopenharmony_ci			info.shadow_area_pa = cqmr->shadow;
214062306a36Sopenharmony_ci		}
214162306a36Sopenharmony_ci		if (iwpbl->pbl_allocated) {
214262306a36Sopenharmony_ci			info.virtual_map = true;
214362306a36Sopenharmony_ci			info.pbl_chunk_size = 1;
214462306a36Sopenharmony_ci			info.first_pm_pbl_idx = cqmr->cq_pbl.idx;
214562306a36Sopenharmony_ci		} else {
214662306a36Sopenharmony_ci			info.cq_base_pa = cqmr->cq_pbl.addr;
214762306a36Sopenharmony_ci		}
214862306a36Sopenharmony_ci	} else {
214962306a36Sopenharmony_ci		/* Kmode allocations */
215062306a36Sopenharmony_ci		int rsize;
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci		if (entries < 1 || entries > rf->max_cqe) {
215362306a36Sopenharmony_ci			err_code = -EINVAL;
215462306a36Sopenharmony_ci			goto cq_free_rsrc;
215562306a36Sopenharmony_ci		}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci		entries++;
215862306a36Sopenharmony_ci		if (dev->hw_attrs.uk_attrs.hw_rev >= IRDMA_GEN_2)
215962306a36Sopenharmony_ci			entries *= 2;
216062306a36Sopenharmony_ci		ukinfo->cq_size = entries;
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci		rsize = info.cq_uk_init_info.cq_size * sizeof(struct irdma_cqe);
216362306a36Sopenharmony_ci		iwcq->kmem.size = ALIGN(round_up(rsize, 256), 256);
216462306a36Sopenharmony_ci		iwcq->kmem.va = dma_alloc_coherent(dev->hw->device,
216562306a36Sopenharmony_ci						   iwcq->kmem.size,
216662306a36Sopenharmony_ci						   &iwcq->kmem.pa, GFP_KERNEL);
216762306a36Sopenharmony_ci		if (!iwcq->kmem.va) {
216862306a36Sopenharmony_ci			err_code = -ENOMEM;
216962306a36Sopenharmony_ci			goto cq_free_rsrc;
217062306a36Sopenharmony_ci		}
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci		iwcq->kmem_shadow.size = ALIGN(IRDMA_SHADOW_AREA_SIZE << 3,
217362306a36Sopenharmony_ci					       64);
217462306a36Sopenharmony_ci		iwcq->kmem_shadow.va = dma_alloc_coherent(dev->hw->device,
217562306a36Sopenharmony_ci							  iwcq->kmem_shadow.size,
217662306a36Sopenharmony_ci							  &iwcq->kmem_shadow.pa,
217762306a36Sopenharmony_ci							  GFP_KERNEL);
217862306a36Sopenharmony_ci		if (!iwcq->kmem_shadow.va) {
217962306a36Sopenharmony_ci			err_code = -ENOMEM;
218062306a36Sopenharmony_ci			goto cq_free_rsrc;
218162306a36Sopenharmony_ci		}
218262306a36Sopenharmony_ci		info.shadow_area_pa = iwcq->kmem_shadow.pa;
218362306a36Sopenharmony_ci		ukinfo->shadow_area = iwcq->kmem_shadow.va;
218462306a36Sopenharmony_ci		ukinfo->cq_base = iwcq->kmem.va;
218562306a36Sopenharmony_ci		info.cq_base_pa = iwcq->kmem.pa;
218662306a36Sopenharmony_ci	}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	info.shadow_read_threshold = min(info.cq_uk_init_info.cq_size / 2,
218962306a36Sopenharmony_ci					 (u32)IRDMA_MAX_CQ_READ_THRESH);
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci	if (irdma_sc_cq_init(cq, &info)) {
219262306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev, "VERBS: init cq fail\n");
219362306a36Sopenharmony_ci		err_code = -EPROTO;
219462306a36Sopenharmony_ci		goto cq_free_rsrc;
219562306a36Sopenharmony_ci	}
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&rf->cqp, true);
219862306a36Sopenharmony_ci	if (!cqp_request) {
219962306a36Sopenharmony_ci		err_code = -ENOMEM;
220062306a36Sopenharmony_ci		goto cq_free_rsrc;
220162306a36Sopenharmony_ci	}
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
220462306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_CQ_CREATE;
220562306a36Sopenharmony_ci	cqp_info->post_sq = 1;
220662306a36Sopenharmony_ci	cqp_info->in.u.cq_create.cq = cq;
220762306a36Sopenharmony_ci	cqp_info->in.u.cq_create.check_overflow = true;
220862306a36Sopenharmony_ci	cqp_info->in.u.cq_create.scratch = (uintptr_t)cqp_request;
220962306a36Sopenharmony_ci	err_code = irdma_handle_cqp_op(rf, cqp_request);
221062306a36Sopenharmony_ci	irdma_put_cqp_request(&rf->cqp, cqp_request);
221162306a36Sopenharmony_ci	if (err_code)
221262306a36Sopenharmony_ci		goto cq_free_rsrc;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	if (udata) {
221562306a36Sopenharmony_ci		struct irdma_create_cq_resp resp = {};
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci		resp.cq_id = info.cq_uk_init_info.cq_id;
221862306a36Sopenharmony_ci		resp.cq_size = info.cq_uk_init_info.cq_size;
221962306a36Sopenharmony_ci		if (ib_copy_to_udata(udata, &resp,
222062306a36Sopenharmony_ci				     min(sizeof(resp), udata->outlen))) {
222162306a36Sopenharmony_ci			ibdev_dbg(&iwdev->ibdev,
222262306a36Sopenharmony_ci				  "VERBS: copy to user data\n");
222362306a36Sopenharmony_ci			err_code = -EPROTO;
222462306a36Sopenharmony_ci			goto cq_destroy;
222562306a36Sopenharmony_ci		}
222662306a36Sopenharmony_ci	}
222762306a36Sopenharmony_ci	rf->cq_table[cq_num] = iwcq;
222862306a36Sopenharmony_ci	init_completion(&iwcq->free_cq);
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	return 0;
223162306a36Sopenharmony_cicq_destroy:
223262306a36Sopenharmony_ci	irdma_cq_wq_destroy(rf, cq);
223362306a36Sopenharmony_cicq_free_rsrc:
223462306a36Sopenharmony_ci	irdma_cq_free_rsrc(rf, iwcq);
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci	return err_code;
223762306a36Sopenharmony_ci}
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci/**
224062306a36Sopenharmony_ci * irdma_get_mr_access - get hw MR access permissions from IB access flags
224162306a36Sopenharmony_ci * @access: IB access flags
224262306a36Sopenharmony_ci */
224362306a36Sopenharmony_cistatic inline u16 irdma_get_mr_access(int access)
224462306a36Sopenharmony_ci{
224562306a36Sopenharmony_ci	u16 hw_access = 0;
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	hw_access |= (access & IB_ACCESS_LOCAL_WRITE) ?
224862306a36Sopenharmony_ci		     IRDMA_ACCESS_FLAGS_LOCALWRITE : 0;
224962306a36Sopenharmony_ci	hw_access |= (access & IB_ACCESS_REMOTE_WRITE) ?
225062306a36Sopenharmony_ci		     IRDMA_ACCESS_FLAGS_REMOTEWRITE : 0;
225162306a36Sopenharmony_ci	hw_access |= (access & IB_ACCESS_REMOTE_READ) ?
225262306a36Sopenharmony_ci		     IRDMA_ACCESS_FLAGS_REMOTEREAD : 0;
225362306a36Sopenharmony_ci	hw_access |= (access & IB_ACCESS_MW_BIND) ?
225462306a36Sopenharmony_ci		     IRDMA_ACCESS_FLAGS_BIND_WINDOW : 0;
225562306a36Sopenharmony_ci	hw_access |= (access & IB_ZERO_BASED) ?
225662306a36Sopenharmony_ci		     IRDMA_ACCESS_FLAGS_ZERO_BASED : 0;
225762306a36Sopenharmony_ci	hw_access |= IRDMA_ACCESS_FLAGS_LOCALREAD;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	return hw_access;
226062306a36Sopenharmony_ci}
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci/**
226362306a36Sopenharmony_ci * irdma_free_stag - free stag resource
226462306a36Sopenharmony_ci * @iwdev: irdma device
226562306a36Sopenharmony_ci * @stag: stag to free
226662306a36Sopenharmony_ci */
226762306a36Sopenharmony_cistatic void irdma_free_stag(struct irdma_device *iwdev, u32 stag)
226862306a36Sopenharmony_ci{
226962306a36Sopenharmony_ci	u32 stag_idx;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	stag_idx = (stag & iwdev->rf->mr_stagmask) >> IRDMA_CQPSQ_STAG_IDX_S;
227262306a36Sopenharmony_ci	irdma_free_rsrc(iwdev->rf, iwdev->rf->allocated_mrs, stag_idx);
227362306a36Sopenharmony_ci}
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci/**
227662306a36Sopenharmony_ci * irdma_create_stag - create random stag
227762306a36Sopenharmony_ci * @iwdev: irdma device
227862306a36Sopenharmony_ci */
227962306a36Sopenharmony_cistatic u32 irdma_create_stag(struct irdma_device *iwdev)
228062306a36Sopenharmony_ci{
228162306a36Sopenharmony_ci	u32 stag = 0;
228262306a36Sopenharmony_ci	u32 stag_index = 0;
228362306a36Sopenharmony_ci	u32 next_stag_index;
228462306a36Sopenharmony_ci	u32 driver_key;
228562306a36Sopenharmony_ci	u32 random;
228662306a36Sopenharmony_ci	u8 consumer_key;
228762306a36Sopenharmony_ci	int ret;
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci	get_random_bytes(&random, sizeof(random));
229062306a36Sopenharmony_ci	consumer_key = (u8)random;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	driver_key = random & ~iwdev->rf->mr_stagmask;
229362306a36Sopenharmony_ci	next_stag_index = (random & iwdev->rf->mr_stagmask) >> 8;
229462306a36Sopenharmony_ci	next_stag_index %= iwdev->rf->max_mr;
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	ret = irdma_alloc_rsrc(iwdev->rf, iwdev->rf->allocated_mrs,
229762306a36Sopenharmony_ci			       iwdev->rf->max_mr, &stag_index,
229862306a36Sopenharmony_ci			       &next_stag_index);
229962306a36Sopenharmony_ci	if (ret)
230062306a36Sopenharmony_ci		return stag;
230162306a36Sopenharmony_ci	stag = stag_index << IRDMA_CQPSQ_STAG_IDX_S;
230262306a36Sopenharmony_ci	stag |= driver_key;
230362306a36Sopenharmony_ci	stag += (u32)consumer_key;
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	return stag;
230662306a36Sopenharmony_ci}
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci/**
230962306a36Sopenharmony_ci * irdma_next_pbl_addr - Get next pbl address
231062306a36Sopenharmony_ci * @pbl: pointer to a pble
231162306a36Sopenharmony_ci * @pinfo: info pointer
231262306a36Sopenharmony_ci * @idx: index
231362306a36Sopenharmony_ci */
231462306a36Sopenharmony_cistatic inline u64 *irdma_next_pbl_addr(u64 *pbl, struct irdma_pble_info **pinfo,
231562306a36Sopenharmony_ci				       u32 *idx)
231662306a36Sopenharmony_ci{
231762306a36Sopenharmony_ci	*idx += 1;
231862306a36Sopenharmony_ci	if (!(*pinfo) || *idx != (*pinfo)->cnt)
231962306a36Sopenharmony_ci		return ++pbl;
232062306a36Sopenharmony_ci	*idx = 0;
232162306a36Sopenharmony_ci	(*pinfo)++;
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci	return (*pinfo)->addr;
232462306a36Sopenharmony_ci}
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci/**
232762306a36Sopenharmony_ci * irdma_copy_user_pgaddrs - copy user page address to pble's os locally
232862306a36Sopenharmony_ci * @iwmr: iwmr for IB's user page addresses
232962306a36Sopenharmony_ci * @pbl: ple pointer to save 1 level or 0 level pble
233062306a36Sopenharmony_ci * @level: indicated level 0, 1 or 2
233162306a36Sopenharmony_ci */
233262306a36Sopenharmony_cistatic void irdma_copy_user_pgaddrs(struct irdma_mr *iwmr, u64 *pbl,
233362306a36Sopenharmony_ci				    enum irdma_pble_level level)
233462306a36Sopenharmony_ci{
233562306a36Sopenharmony_ci	struct ib_umem *region = iwmr->region;
233662306a36Sopenharmony_ci	struct irdma_pbl *iwpbl = &iwmr->iwpbl;
233762306a36Sopenharmony_ci	struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
233862306a36Sopenharmony_ci	struct irdma_pble_info *pinfo;
233962306a36Sopenharmony_ci	struct ib_block_iter biter;
234062306a36Sopenharmony_ci	u32 idx = 0;
234162306a36Sopenharmony_ci	u32 pbl_cnt = 0;
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	pinfo = (level == PBLE_LEVEL_1) ? NULL : palloc->level2.leaf;
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	if (iwmr->type == IRDMA_MEMREG_TYPE_QP)
234662306a36Sopenharmony_ci		iwpbl->qp_mr.sq_page = sg_page(region->sgt_append.sgt.sgl);
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	rdma_umem_for_each_dma_block(region, &biter, iwmr->page_size) {
234962306a36Sopenharmony_ci		*pbl = rdma_block_iter_dma_address(&biter);
235062306a36Sopenharmony_ci		if (++pbl_cnt == palloc->total_cnt)
235162306a36Sopenharmony_ci			break;
235262306a36Sopenharmony_ci		pbl = irdma_next_pbl_addr(pbl, &pinfo, &idx);
235362306a36Sopenharmony_ci	}
235462306a36Sopenharmony_ci}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci/**
235762306a36Sopenharmony_ci * irdma_check_mem_contiguous - check if pbls stored in arr are contiguous
235862306a36Sopenharmony_ci * @arr: lvl1 pbl array
235962306a36Sopenharmony_ci * @npages: page count
236062306a36Sopenharmony_ci * @pg_size: page size
236162306a36Sopenharmony_ci *
236262306a36Sopenharmony_ci */
236362306a36Sopenharmony_cistatic bool irdma_check_mem_contiguous(u64 *arr, u32 npages, u32 pg_size)
236462306a36Sopenharmony_ci{
236562306a36Sopenharmony_ci	u32 pg_idx;
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	for (pg_idx = 0; pg_idx < npages; pg_idx++) {
236862306a36Sopenharmony_ci		if ((*arr + (pg_size * pg_idx)) != arr[pg_idx])
236962306a36Sopenharmony_ci			return false;
237062306a36Sopenharmony_ci	}
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	return true;
237362306a36Sopenharmony_ci}
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci/**
237662306a36Sopenharmony_ci * irdma_check_mr_contiguous - check if MR is physically contiguous
237762306a36Sopenharmony_ci * @palloc: pbl allocation struct
237862306a36Sopenharmony_ci * @pg_size: page size
237962306a36Sopenharmony_ci */
238062306a36Sopenharmony_cistatic bool irdma_check_mr_contiguous(struct irdma_pble_alloc *palloc,
238162306a36Sopenharmony_ci				      u32 pg_size)
238262306a36Sopenharmony_ci{
238362306a36Sopenharmony_ci	struct irdma_pble_level2 *lvl2 = &palloc->level2;
238462306a36Sopenharmony_ci	struct irdma_pble_info *leaf = lvl2->leaf;
238562306a36Sopenharmony_ci	u64 *arr = NULL;
238662306a36Sopenharmony_ci	u64 *start_addr = NULL;
238762306a36Sopenharmony_ci	int i;
238862306a36Sopenharmony_ci	bool ret;
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci	if (palloc->level == PBLE_LEVEL_1) {
239162306a36Sopenharmony_ci		arr = palloc->level1.addr;
239262306a36Sopenharmony_ci		ret = irdma_check_mem_contiguous(arr, palloc->total_cnt,
239362306a36Sopenharmony_ci						 pg_size);
239462306a36Sopenharmony_ci		return ret;
239562306a36Sopenharmony_ci	}
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci	start_addr = leaf->addr;
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	for (i = 0; i < lvl2->leaf_cnt; i++, leaf++) {
240062306a36Sopenharmony_ci		arr = leaf->addr;
240162306a36Sopenharmony_ci		if ((*start_addr + (i * pg_size * PBLE_PER_PAGE)) != *arr)
240262306a36Sopenharmony_ci			return false;
240362306a36Sopenharmony_ci		ret = irdma_check_mem_contiguous(arr, leaf->cnt, pg_size);
240462306a36Sopenharmony_ci		if (!ret)
240562306a36Sopenharmony_ci			return false;
240662306a36Sopenharmony_ci	}
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	return true;
240962306a36Sopenharmony_ci}
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci/**
241262306a36Sopenharmony_ci * irdma_setup_pbles - copy user pg address to pble's
241362306a36Sopenharmony_ci * @rf: RDMA PCI function
241462306a36Sopenharmony_ci * @iwmr: mr pointer for this memory registration
241562306a36Sopenharmony_ci * @lvl: requested pble levels
241662306a36Sopenharmony_ci */
241762306a36Sopenharmony_cistatic int irdma_setup_pbles(struct irdma_pci_f *rf, struct irdma_mr *iwmr,
241862306a36Sopenharmony_ci			     u8 lvl)
241962306a36Sopenharmony_ci{
242062306a36Sopenharmony_ci	struct irdma_pbl *iwpbl = &iwmr->iwpbl;
242162306a36Sopenharmony_ci	struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
242262306a36Sopenharmony_ci	struct irdma_pble_info *pinfo;
242362306a36Sopenharmony_ci	u64 *pbl;
242462306a36Sopenharmony_ci	int status;
242562306a36Sopenharmony_ci	enum irdma_pble_level level = PBLE_LEVEL_1;
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci	if (lvl) {
242862306a36Sopenharmony_ci		status = irdma_get_pble(rf->pble_rsrc, palloc, iwmr->page_cnt,
242962306a36Sopenharmony_ci					lvl);
243062306a36Sopenharmony_ci		if (status)
243162306a36Sopenharmony_ci			return status;
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_ci		iwpbl->pbl_allocated = true;
243462306a36Sopenharmony_ci		level = palloc->level;
243562306a36Sopenharmony_ci		pinfo = (level == PBLE_LEVEL_1) ? &palloc->level1 :
243662306a36Sopenharmony_ci						  palloc->level2.leaf;
243762306a36Sopenharmony_ci		pbl = pinfo->addr;
243862306a36Sopenharmony_ci	} else {
243962306a36Sopenharmony_ci		pbl = iwmr->pgaddrmem;
244062306a36Sopenharmony_ci	}
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	irdma_copy_user_pgaddrs(iwmr, pbl, level);
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	if (lvl)
244562306a36Sopenharmony_ci		iwmr->pgaddrmem[0] = *pbl;
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	return 0;
244862306a36Sopenharmony_ci}
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci/**
245162306a36Sopenharmony_ci * irdma_handle_q_mem - handle memory for qp and cq
245262306a36Sopenharmony_ci * @iwdev: irdma device
245362306a36Sopenharmony_ci * @req: information for q memory management
245462306a36Sopenharmony_ci * @iwpbl: pble struct
245562306a36Sopenharmony_ci * @lvl: pble level mask
245662306a36Sopenharmony_ci */
245762306a36Sopenharmony_cistatic int irdma_handle_q_mem(struct irdma_device *iwdev,
245862306a36Sopenharmony_ci			      struct irdma_mem_reg_req *req,
245962306a36Sopenharmony_ci			      struct irdma_pbl *iwpbl, u8 lvl)
246062306a36Sopenharmony_ci{
246162306a36Sopenharmony_ci	struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
246262306a36Sopenharmony_ci	struct irdma_mr *iwmr = iwpbl->iwmr;
246362306a36Sopenharmony_ci	struct irdma_qp_mr *qpmr = &iwpbl->qp_mr;
246462306a36Sopenharmony_ci	struct irdma_cq_mr *cqmr = &iwpbl->cq_mr;
246562306a36Sopenharmony_ci	struct irdma_hmc_pble *hmc_p;
246662306a36Sopenharmony_ci	u64 *arr = iwmr->pgaddrmem;
246762306a36Sopenharmony_ci	u32 pg_size, total;
246862306a36Sopenharmony_ci	int err = 0;
246962306a36Sopenharmony_ci	bool ret = true;
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	pg_size = iwmr->page_size;
247262306a36Sopenharmony_ci	err = irdma_setup_pbles(iwdev->rf, iwmr, lvl);
247362306a36Sopenharmony_ci	if (err)
247462306a36Sopenharmony_ci		return err;
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	if (lvl)
247762306a36Sopenharmony_ci		arr = palloc->level1.addr;
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	switch (iwmr->type) {
248062306a36Sopenharmony_ci	case IRDMA_MEMREG_TYPE_QP:
248162306a36Sopenharmony_ci		total = req->sq_pages + req->rq_pages;
248262306a36Sopenharmony_ci		hmc_p = &qpmr->sq_pbl;
248362306a36Sopenharmony_ci		qpmr->shadow = (dma_addr_t)arr[total];
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci		if (lvl) {
248662306a36Sopenharmony_ci			ret = irdma_check_mem_contiguous(arr, req->sq_pages,
248762306a36Sopenharmony_ci							 pg_size);
248862306a36Sopenharmony_ci			if (ret)
248962306a36Sopenharmony_ci				ret = irdma_check_mem_contiguous(&arr[req->sq_pages],
249062306a36Sopenharmony_ci								 req->rq_pages,
249162306a36Sopenharmony_ci								 pg_size);
249262306a36Sopenharmony_ci		}
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci		if (!ret) {
249562306a36Sopenharmony_ci			hmc_p->idx = palloc->level1.idx;
249662306a36Sopenharmony_ci			hmc_p = &qpmr->rq_pbl;
249762306a36Sopenharmony_ci			hmc_p->idx = palloc->level1.idx + req->sq_pages;
249862306a36Sopenharmony_ci		} else {
249962306a36Sopenharmony_ci			hmc_p->addr = arr[0];
250062306a36Sopenharmony_ci			hmc_p = &qpmr->rq_pbl;
250162306a36Sopenharmony_ci			hmc_p->addr = arr[req->sq_pages];
250262306a36Sopenharmony_ci		}
250362306a36Sopenharmony_ci		break;
250462306a36Sopenharmony_ci	case IRDMA_MEMREG_TYPE_CQ:
250562306a36Sopenharmony_ci		hmc_p = &cqmr->cq_pbl;
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci		if (!cqmr->split)
250862306a36Sopenharmony_ci			cqmr->shadow = (dma_addr_t)arr[req->cq_pages];
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci		if (lvl)
251162306a36Sopenharmony_ci			ret = irdma_check_mem_contiguous(arr, req->cq_pages,
251262306a36Sopenharmony_ci							 pg_size);
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci		if (!ret)
251562306a36Sopenharmony_ci			hmc_p->idx = palloc->level1.idx;
251662306a36Sopenharmony_ci		else
251762306a36Sopenharmony_ci			hmc_p->addr = arr[0];
251862306a36Sopenharmony_ci	break;
251962306a36Sopenharmony_ci	default:
252062306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev, "VERBS: MR type error\n");
252162306a36Sopenharmony_ci		err = -EINVAL;
252262306a36Sopenharmony_ci	}
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci	if (lvl && ret) {
252562306a36Sopenharmony_ci		irdma_free_pble(iwdev->rf->pble_rsrc, palloc);
252662306a36Sopenharmony_ci		iwpbl->pbl_allocated = false;
252762306a36Sopenharmony_ci	}
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	return err;
253062306a36Sopenharmony_ci}
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci/**
253362306a36Sopenharmony_ci * irdma_hw_alloc_mw - create the hw memory window
253462306a36Sopenharmony_ci * @iwdev: irdma device
253562306a36Sopenharmony_ci * @iwmr: pointer to memory window info
253662306a36Sopenharmony_ci */
253762306a36Sopenharmony_cistatic int irdma_hw_alloc_mw(struct irdma_device *iwdev, struct irdma_mr *iwmr)
253862306a36Sopenharmony_ci{
253962306a36Sopenharmony_ci	struct irdma_mw_alloc_info *info;
254062306a36Sopenharmony_ci	struct irdma_pd *iwpd = to_iwpd(iwmr->ibmr.pd);
254162306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
254262306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
254362306a36Sopenharmony_ci	int status;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
254662306a36Sopenharmony_ci	if (!cqp_request)
254762306a36Sopenharmony_ci		return -ENOMEM;
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
255062306a36Sopenharmony_ci	info = &cqp_info->in.u.mw_alloc.info;
255162306a36Sopenharmony_ci	memset(info, 0, sizeof(*info));
255262306a36Sopenharmony_ci	if (iwmr->ibmw.type == IB_MW_TYPE_1)
255362306a36Sopenharmony_ci		info->mw_wide = true;
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	info->page_size = PAGE_SIZE;
255662306a36Sopenharmony_ci	info->mw_stag_index = iwmr->stag >> IRDMA_CQPSQ_STAG_IDX_S;
255762306a36Sopenharmony_ci	info->pd_id = iwpd->sc_pd.pd_id;
255862306a36Sopenharmony_ci	info->remote_access = true;
255962306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_MW_ALLOC;
256062306a36Sopenharmony_ci	cqp_info->post_sq = 1;
256162306a36Sopenharmony_ci	cqp_info->in.u.mw_alloc.dev = &iwdev->rf->sc_dev;
256262306a36Sopenharmony_ci	cqp_info->in.u.mw_alloc.scratch = (uintptr_t)cqp_request;
256362306a36Sopenharmony_ci	status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
256462306a36Sopenharmony_ci	irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	return status;
256762306a36Sopenharmony_ci}
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci/**
257062306a36Sopenharmony_ci * irdma_alloc_mw - Allocate memory window
257162306a36Sopenharmony_ci * @ibmw: Memory Window
257262306a36Sopenharmony_ci * @udata: user data pointer
257362306a36Sopenharmony_ci */
257462306a36Sopenharmony_cistatic int irdma_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
257562306a36Sopenharmony_ci{
257662306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibmw->device);
257762306a36Sopenharmony_ci	struct irdma_mr *iwmr = to_iwmw(ibmw);
257862306a36Sopenharmony_ci	int err_code;
257962306a36Sopenharmony_ci	u32 stag;
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	stag = irdma_create_stag(iwdev);
258262306a36Sopenharmony_ci	if (!stag)
258362306a36Sopenharmony_ci		return -ENOMEM;
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci	iwmr->stag = stag;
258662306a36Sopenharmony_ci	ibmw->rkey = stag;
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	err_code = irdma_hw_alloc_mw(iwdev, iwmr);
258962306a36Sopenharmony_ci	if (err_code) {
259062306a36Sopenharmony_ci		irdma_free_stag(iwdev, stag);
259162306a36Sopenharmony_ci		return err_code;
259262306a36Sopenharmony_ci	}
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci	return 0;
259562306a36Sopenharmony_ci}
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci/**
259862306a36Sopenharmony_ci * irdma_dealloc_mw - Dealloc memory window
259962306a36Sopenharmony_ci * @ibmw: memory window structure.
260062306a36Sopenharmony_ci */
260162306a36Sopenharmony_cistatic int irdma_dealloc_mw(struct ib_mw *ibmw)
260262306a36Sopenharmony_ci{
260362306a36Sopenharmony_ci	struct ib_pd *ibpd = ibmw->pd;
260462306a36Sopenharmony_ci	struct irdma_pd *iwpd = to_iwpd(ibpd);
260562306a36Sopenharmony_ci	struct irdma_mr *iwmr = to_iwmr((struct ib_mr *)ibmw);
260662306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibmw->device);
260762306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
260862306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
260962306a36Sopenharmony_ci	struct irdma_dealloc_stag_info *info;
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
261262306a36Sopenharmony_ci	if (!cqp_request)
261362306a36Sopenharmony_ci		return -ENOMEM;
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
261662306a36Sopenharmony_ci	info = &cqp_info->in.u.dealloc_stag.info;
261762306a36Sopenharmony_ci	memset(info, 0, sizeof(*info));
261862306a36Sopenharmony_ci	info->pd_id = iwpd->sc_pd.pd_id;
261962306a36Sopenharmony_ci	info->stag_idx = ibmw->rkey >> IRDMA_CQPSQ_STAG_IDX_S;
262062306a36Sopenharmony_ci	info->mr = false;
262162306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_DEALLOC_STAG;
262262306a36Sopenharmony_ci	cqp_info->post_sq = 1;
262362306a36Sopenharmony_ci	cqp_info->in.u.dealloc_stag.dev = &iwdev->rf->sc_dev;
262462306a36Sopenharmony_ci	cqp_info->in.u.dealloc_stag.scratch = (uintptr_t)cqp_request;
262562306a36Sopenharmony_ci	irdma_handle_cqp_op(iwdev->rf, cqp_request);
262662306a36Sopenharmony_ci	irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
262762306a36Sopenharmony_ci	irdma_free_stag(iwdev, iwmr->stag);
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	return 0;
263062306a36Sopenharmony_ci}
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci/**
263362306a36Sopenharmony_ci * irdma_hw_alloc_stag - cqp command to allocate stag
263462306a36Sopenharmony_ci * @iwdev: irdma device
263562306a36Sopenharmony_ci * @iwmr: irdma mr pointer
263662306a36Sopenharmony_ci */
263762306a36Sopenharmony_cistatic int irdma_hw_alloc_stag(struct irdma_device *iwdev,
263862306a36Sopenharmony_ci			       struct irdma_mr *iwmr)
263962306a36Sopenharmony_ci{
264062306a36Sopenharmony_ci	struct irdma_allocate_stag_info *info;
264162306a36Sopenharmony_ci	struct ib_pd *pd = iwmr->ibmr.pd;
264262306a36Sopenharmony_ci	struct irdma_pd *iwpd = to_iwpd(pd);
264362306a36Sopenharmony_ci	int status;
264462306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
264562306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
264862306a36Sopenharmony_ci	if (!cqp_request)
264962306a36Sopenharmony_ci		return -ENOMEM;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
265262306a36Sopenharmony_ci	info = &cqp_info->in.u.alloc_stag.info;
265362306a36Sopenharmony_ci	memset(info, 0, sizeof(*info));
265462306a36Sopenharmony_ci	info->page_size = PAGE_SIZE;
265562306a36Sopenharmony_ci	info->stag_idx = iwmr->stag >> IRDMA_CQPSQ_STAG_IDX_S;
265662306a36Sopenharmony_ci	info->pd_id = iwpd->sc_pd.pd_id;
265762306a36Sopenharmony_ci	info->total_len = iwmr->len;
265862306a36Sopenharmony_ci	info->all_memory = pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY;
265962306a36Sopenharmony_ci	info->remote_access = true;
266062306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_ALLOC_STAG;
266162306a36Sopenharmony_ci	cqp_info->post_sq = 1;
266262306a36Sopenharmony_ci	cqp_info->in.u.alloc_stag.dev = &iwdev->rf->sc_dev;
266362306a36Sopenharmony_ci	cqp_info->in.u.alloc_stag.scratch = (uintptr_t)cqp_request;
266462306a36Sopenharmony_ci	status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
266562306a36Sopenharmony_ci	irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	return status;
266862306a36Sopenharmony_ci}
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci/**
267162306a36Sopenharmony_ci * irdma_alloc_mr - register stag for fast memory registration
267262306a36Sopenharmony_ci * @pd: ibpd pointer
267362306a36Sopenharmony_ci * @mr_type: memory for stag registrion
267462306a36Sopenharmony_ci * @max_num_sg: man number of pages
267562306a36Sopenharmony_ci */
267662306a36Sopenharmony_cistatic struct ib_mr *irdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
267762306a36Sopenharmony_ci				    u32 max_num_sg)
267862306a36Sopenharmony_ci{
267962306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(pd->device);
268062306a36Sopenharmony_ci	struct irdma_pble_alloc *palloc;
268162306a36Sopenharmony_ci	struct irdma_pbl *iwpbl;
268262306a36Sopenharmony_ci	struct irdma_mr *iwmr;
268362306a36Sopenharmony_ci	u32 stag;
268462306a36Sopenharmony_ci	int err_code;
268562306a36Sopenharmony_ci
268662306a36Sopenharmony_ci	iwmr = kzalloc(sizeof(*iwmr), GFP_KERNEL);
268762306a36Sopenharmony_ci	if (!iwmr)
268862306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	stag = irdma_create_stag(iwdev);
269162306a36Sopenharmony_ci	if (!stag) {
269262306a36Sopenharmony_ci		err_code = -ENOMEM;
269362306a36Sopenharmony_ci		goto err;
269462306a36Sopenharmony_ci	}
269562306a36Sopenharmony_ci
269662306a36Sopenharmony_ci	iwmr->stag = stag;
269762306a36Sopenharmony_ci	iwmr->ibmr.rkey = stag;
269862306a36Sopenharmony_ci	iwmr->ibmr.lkey = stag;
269962306a36Sopenharmony_ci	iwmr->ibmr.pd = pd;
270062306a36Sopenharmony_ci	iwmr->ibmr.device = pd->device;
270162306a36Sopenharmony_ci	iwpbl = &iwmr->iwpbl;
270262306a36Sopenharmony_ci	iwpbl->iwmr = iwmr;
270362306a36Sopenharmony_ci	iwmr->type = IRDMA_MEMREG_TYPE_MEM;
270462306a36Sopenharmony_ci	palloc = &iwpbl->pble_alloc;
270562306a36Sopenharmony_ci	iwmr->page_cnt = max_num_sg;
270662306a36Sopenharmony_ci	/* Use system PAGE_SIZE as the sg page sizes are unknown at this point */
270762306a36Sopenharmony_ci	iwmr->len = max_num_sg * PAGE_SIZE;
270862306a36Sopenharmony_ci	err_code = irdma_get_pble(iwdev->rf->pble_rsrc, palloc, iwmr->page_cnt,
270962306a36Sopenharmony_ci				  false);
271062306a36Sopenharmony_ci	if (err_code)
271162306a36Sopenharmony_ci		goto err_get_pble;
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	err_code = irdma_hw_alloc_stag(iwdev, iwmr);
271462306a36Sopenharmony_ci	if (err_code)
271562306a36Sopenharmony_ci		goto err_alloc_stag;
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci	iwpbl->pbl_allocated = true;
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	return &iwmr->ibmr;
272062306a36Sopenharmony_cierr_alloc_stag:
272162306a36Sopenharmony_ci	irdma_free_pble(iwdev->rf->pble_rsrc, palloc);
272262306a36Sopenharmony_cierr_get_pble:
272362306a36Sopenharmony_ci	irdma_free_stag(iwdev, stag);
272462306a36Sopenharmony_cierr:
272562306a36Sopenharmony_ci	kfree(iwmr);
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	return ERR_PTR(err_code);
272862306a36Sopenharmony_ci}
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci/**
273162306a36Sopenharmony_ci * irdma_set_page - populate pbl list for fmr
273262306a36Sopenharmony_ci * @ibmr: ib mem to access iwarp mr pointer
273362306a36Sopenharmony_ci * @addr: page dma address fro pbl list
273462306a36Sopenharmony_ci */
273562306a36Sopenharmony_cistatic int irdma_set_page(struct ib_mr *ibmr, u64 addr)
273662306a36Sopenharmony_ci{
273762306a36Sopenharmony_ci	struct irdma_mr *iwmr = to_iwmr(ibmr);
273862306a36Sopenharmony_ci	struct irdma_pbl *iwpbl = &iwmr->iwpbl;
273962306a36Sopenharmony_ci	struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
274062306a36Sopenharmony_ci	u64 *pbl;
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci	if (unlikely(iwmr->npages == iwmr->page_cnt))
274362306a36Sopenharmony_ci		return -ENOMEM;
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci	if (palloc->level == PBLE_LEVEL_2) {
274662306a36Sopenharmony_ci		struct irdma_pble_info *palloc_info =
274762306a36Sopenharmony_ci			palloc->level2.leaf + (iwmr->npages >> PBLE_512_SHIFT);
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci		palloc_info->addr[iwmr->npages & (PBLE_PER_PAGE - 1)] = addr;
275062306a36Sopenharmony_ci	} else {
275162306a36Sopenharmony_ci		pbl = palloc->level1.addr;
275262306a36Sopenharmony_ci		pbl[iwmr->npages] = addr;
275362306a36Sopenharmony_ci	}
275462306a36Sopenharmony_ci	iwmr->npages++;
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci	return 0;
275762306a36Sopenharmony_ci}
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci/**
276062306a36Sopenharmony_ci * irdma_map_mr_sg - map of sg list for fmr
276162306a36Sopenharmony_ci * @ibmr: ib mem to access iwarp mr pointer
276262306a36Sopenharmony_ci * @sg: scatter gather list
276362306a36Sopenharmony_ci * @sg_nents: number of sg pages
276462306a36Sopenharmony_ci * @sg_offset: scatter gather list for fmr
276562306a36Sopenharmony_ci */
276662306a36Sopenharmony_cistatic int irdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
276762306a36Sopenharmony_ci			   int sg_nents, unsigned int *sg_offset)
276862306a36Sopenharmony_ci{
276962306a36Sopenharmony_ci	struct irdma_mr *iwmr = to_iwmr(ibmr);
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci	iwmr->npages = 0;
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci	return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, irdma_set_page);
277462306a36Sopenharmony_ci}
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci/**
277762306a36Sopenharmony_ci * irdma_hwreg_mr - send cqp command for memory registration
277862306a36Sopenharmony_ci * @iwdev: irdma device
277962306a36Sopenharmony_ci * @iwmr: irdma mr pointer
278062306a36Sopenharmony_ci * @access: access for MR
278162306a36Sopenharmony_ci */
278262306a36Sopenharmony_cistatic int irdma_hwreg_mr(struct irdma_device *iwdev, struct irdma_mr *iwmr,
278362306a36Sopenharmony_ci			  u16 access)
278462306a36Sopenharmony_ci{
278562306a36Sopenharmony_ci	struct irdma_pbl *iwpbl = &iwmr->iwpbl;
278662306a36Sopenharmony_ci	struct irdma_reg_ns_stag_info *stag_info;
278762306a36Sopenharmony_ci	struct ib_pd *pd = iwmr->ibmr.pd;
278862306a36Sopenharmony_ci	struct irdma_pd *iwpd = to_iwpd(pd);
278962306a36Sopenharmony_ci	struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
279062306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
279162306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
279262306a36Sopenharmony_ci	int ret;
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
279562306a36Sopenharmony_ci	if (!cqp_request)
279662306a36Sopenharmony_ci		return -ENOMEM;
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
279962306a36Sopenharmony_ci	stag_info = &cqp_info->in.u.mr_reg_non_shared.info;
280062306a36Sopenharmony_ci	memset(stag_info, 0, sizeof(*stag_info));
280162306a36Sopenharmony_ci	stag_info->va = iwpbl->user_base;
280262306a36Sopenharmony_ci	stag_info->stag_idx = iwmr->stag >> IRDMA_CQPSQ_STAG_IDX_S;
280362306a36Sopenharmony_ci	stag_info->stag_key = (u8)iwmr->stag;
280462306a36Sopenharmony_ci	stag_info->total_len = iwmr->len;
280562306a36Sopenharmony_ci	stag_info->access_rights = irdma_get_mr_access(access);
280662306a36Sopenharmony_ci	stag_info->pd_id = iwpd->sc_pd.pd_id;
280762306a36Sopenharmony_ci	stag_info->all_memory = pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY;
280862306a36Sopenharmony_ci	if (stag_info->access_rights & IRDMA_ACCESS_FLAGS_ZERO_BASED)
280962306a36Sopenharmony_ci		stag_info->addr_type = IRDMA_ADDR_TYPE_ZERO_BASED;
281062306a36Sopenharmony_ci	else
281162306a36Sopenharmony_ci		stag_info->addr_type = IRDMA_ADDR_TYPE_VA_BASED;
281262306a36Sopenharmony_ci	stag_info->page_size = iwmr->page_size;
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci	if (iwpbl->pbl_allocated) {
281562306a36Sopenharmony_ci		if (palloc->level == PBLE_LEVEL_1) {
281662306a36Sopenharmony_ci			stag_info->first_pm_pbl_index = palloc->level1.idx;
281762306a36Sopenharmony_ci			stag_info->chunk_size = 1;
281862306a36Sopenharmony_ci		} else {
281962306a36Sopenharmony_ci			stag_info->first_pm_pbl_index = palloc->level2.root.idx;
282062306a36Sopenharmony_ci			stag_info->chunk_size = 3;
282162306a36Sopenharmony_ci		}
282262306a36Sopenharmony_ci	} else {
282362306a36Sopenharmony_ci		stag_info->reg_addr_pa = iwmr->pgaddrmem[0];
282462306a36Sopenharmony_ci	}
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_MR_REG_NON_SHARED;
282762306a36Sopenharmony_ci	cqp_info->post_sq = 1;
282862306a36Sopenharmony_ci	cqp_info->in.u.mr_reg_non_shared.dev = &iwdev->rf->sc_dev;
282962306a36Sopenharmony_ci	cqp_info->in.u.mr_reg_non_shared.scratch = (uintptr_t)cqp_request;
283062306a36Sopenharmony_ci	ret = irdma_handle_cqp_op(iwdev->rf, cqp_request);
283162306a36Sopenharmony_ci	irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci	return ret;
283462306a36Sopenharmony_ci}
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_cistatic int irdma_reg_user_mr_type_mem(struct irdma_mr *iwmr, int access)
283762306a36Sopenharmony_ci{
283862306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(iwmr->ibmr.device);
283962306a36Sopenharmony_ci	struct irdma_pbl *iwpbl = &iwmr->iwpbl;
284062306a36Sopenharmony_ci	u32 stag;
284162306a36Sopenharmony_ci	u8 lvl;
284262306a36Sopenharmony_ci	int err;
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	lvl = iwmr->page_cnt != 1 ? PBLE_LEVEL_1 | PBLE_LEVEL_2 : PBLE_LEVEL_0;
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci	err = irdma_setup_pbles(iwdev->rf, iwmr, lvl);
284762306a36Sopenharmony_ci	if (err)
284862306a36Sopenharmony_ci		return err;
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	if (lvl) {
285162306a36Sopenharmony_ci		err = irdma_check_mr_contiguous(&iwpbl->pble_alloc,
285262306a36Sopenharmony_ci						iwmr->page_size);
285362306a36Sopenharmony_ci		if (err) {
285462306a36Sopenharmony_ci			irdma_free_pble(iwdev->rf->pble_rsrc, &iwpbl->pble_alloc);
285562306a36Sopenharmony_ci			iwpbl->pbl_allocated = false;
285662306a36Sopenharmony_ci		}
285762306a36Sopenharmony_ci	}
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci	stag = irdma_create_stag(iwdev);
286062306a36Sopenharmony_ci	if (!stag) {
286162306a36Sopenharmony_ci		err = -ENOMEM;
286262306a36Sopenharmony_ci		goto free_pble;
286362306a36Sopenharmony_ci	}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	iwmr->stag = stag;
286662306a36Sopenharmony_ci	iwmr->ibmr.rkey = stag;
286762306a36Sopenharmony_ci	iwmr->ibmr.lkey = stag;
286862306a36Sopenharmony_ci	err = irdma_hwreg_mr(iwdev, iwmr, access);
286962306a36Sopenharmony_ci	if (err)
287062306a36Sopenharmony_ci		goto err_hwreg;
287162306a36Sopenharmony_ci
287262306a36Sopenharmony_ci	return 0;
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_cierr_hwreg:
287562306a36Sopenharmony_ci	irdma_free_stag(iwdev, stag);
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_cifree_pble:
287862306a36Sopenharmony_ci	if (iwpbl->pble_alloc.level != PBLE_LEVEL_0 && iwpbl->pbl_allocated)
287962306a36Sopenharmony_ci		irdma_free_pble(iwdev->rf->pble_rsrc, &iwpbl->pble_alloc);
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci	return err;
288262306a36Sopenharmony_ci}
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_cistatic struct irdma_mr *irdma_alloc_iwmr(struct ib_umem *region,
288562306a36Sopenharmony_ci					 struct ib_pd *pd, u64 virt,
288662306a36Sopenharmony_ci					 enum irdma_memreg_type reg_type)
288762306a36Sopenharmony_ci{
288862306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(pd->device);
288962306a36Sopenharmony_ci	struct irdma_pbl *iwpbl;
289062306a36Sopenharmony_ci	struct irdma_mr *iwmr;
289162306a36Sopenharmony_ci	unsigned long pgsz_bitmap;
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	iwmr = kzalloc(sizeof(*iwmr), GFP_KERNEL);
289462306a36Sopenharmony_ci	if (!iwmr)
289562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci	iwpbl = &iwmr->iwpbl;
289862306a36Sopenharmony_ci	iwpbl->iwmr = iwmr;
289962306a36Sopenharmony_ci	iwmr->region = region;
290062306a36Sopenharmony_ci	iwmr->ibmr.pd = pd;
290162306a36Sopenharmony_ci	iwmr->ibmr.device = pd->device;
290262306a36Sopenharmony_ci	iwmr->ibmr.iova = virt;
290362306a36Sopenharmony_ci	iwmr->type = reg_type;
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_ci	pgsz_bitmap = (reg_type == IRDMA_MEMREG_TYPE_MEM) ?
290662306a36Sopenharmony_ci		iwdev->rf->sc_dev.hw_attrs.page_size_cap : SZ_4K;
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci	iwmr->page_size = ib_umem_find_best_pgsz(region, pgsz_bitmap, virt);
290962306a36Sopenharmony_ci	if (unlikely(!iwmr->page_size)) {
291062306a36Sopenharmony_ci		kfree(iwmr);
291162306a36Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
291262306a36Sopenharmony_ci	}
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	iwmr->len = region->length;
291562306a36Sopenharmony_ci	iwpbl->user_base = virt;
291662306a36Sopenharmony_ci	iwmr->page_cnt = ib_umem_num_dma_blocks(region, iwmr->page_size);
291762306a36Sopenharmony_ci
291862306a36Sopenharmony_ci	return iwmr;
291962306a36Sopenharmony_ci}
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_cistatic void irdma_free_iwmr(struct irdma_mr *iwmr)
292262306a36Sopenharmony_ci{
292362306a36Sopenharmony_ci	kfree(iwmr);
292462306a36Sopenharmony_ci}
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_cistatic int irdma_reg_user_mr_type_qp(struct irdma_mem_reg_req req,
292762306a36Sopenharmony_ci				     struct ib_udata *udata,
292862306a36Sopenharmony_ci				     struct irdma_mr *iwmr)
292962306a36Sopenharmony_ci{
293062306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(iwmr->ibmr.device);
293162306a36Sopenharmony_ci	struct irdma_pbl *iwpbl = &iwmr->iwpbl;
293262306a36Sopenharmony_ci	struct irdma_ucontext *ucontext = NULL;
293362306a36Sopenharmony_ci	unsigned long flags;
293462306a36Sopenharmony_ci	u32 total;
293562306a36Sopenharmony_ci	int err;
293662306a36Sopenharmony_ci	u8 lvl;
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	/* iWarp: Catch page not starting on OS page boundary */
293962306a36Sopenharmony_ci	if (!rdma_protocol_roce(&iwdev->ibdev, 1) &&
294062306a36Sopenharmony_ci	    ib_umem_offset(iwmr->region))
294162306a36Sopenharmony_ci		return -EINVAL;
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci	total = req.sq_pages + req.rq_pages + 1;
294462306a36Sopenharmony_ci	if (total > iwmr->page_cnt)
294562306a36Sopenharmony_ci		return -EINVAL;
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_ci	total = req.sq_pages + req.rq_pages;
294862306a36Sopenharmony_ci	lvl = total > 2 ? PBLE_LEVEL_1 : PBLE_LEVEL_0;
294962306a36Sopenharmony_ci	err = irdma_handle_q_mem(iwdev, &req, iwpbl, lvl);
295062306a36Sopenharmony_ci	if (err)
295162306a36Sopenharmony_ci		return err;
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	ucontext = rdma_udata_to_drv_context(udata, struct irdma_ucontext,
295462306a36Sopenharmony_ci					     ibucontext);
295562306a36Sopenharmony_ci	spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
295662306a36Sopenharmony_ci	list_add_tail(&iwpbl->list, &ucontext->qp_reg_mem_list);
295762306a36Sopenharmony_ci	iwpbl->on_list = true;
295862306a36Sopenharmony_ci	spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	return 0;
296162306a36Sopenharmony_ci}
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_cistatic int irdma_reg_user_mr_type_cq(struct irdma_mem_reg_req req,
296462306a36Sopenharmony_ci				     struct ib_udata *udata,
296562306a36Sopenharmony_ci				     struct irdma_mr *iwmr)
296662306a36Sopenharmony_ci{
296762306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(iwmr->ibmr.device);
296862306a36Sopenharmony_ci	struct irdma_pbl *iwpbl = &iwmr->iwpbl;
296962306a36Sopenharmony_ci	struct irdma_ucontext *ucontext = NULL;
297062306a36Sopenharmony_ci	u8 shadow_pgcnt = 1;
297162306a36Sopenharmony_ci	unsigned long flags;
297262306a36Sopenharmony_ci	u32 total;
297362306a36Sopenharmony_ci	int err;
297462306a36Sopenharmony_ci	u8 lvl;
297562306a36Sopenharmony_ci
297662306a36Sopenharmony_ci	if (iwdev->rf->sc_dev.hw_attrs.uk_attrs.feature_flags & IRDMA_FEATURE_CQ_RESIZE)
297762306a36Sopenharmony_ci		shadow_pgcnt = 0;
297862306a36Sopenharmony_ci	total = req.cq_pages + shadow_pgcnt;
297962306a36Sopenharmony_ci	if (total > iwmr->page_cnt)
298062306a36Sopenharmony_ci		return -EINVAL;
298162306a36Sopenharmony_ci
298262306a36Sopenharmony_ci	lvl = req.cq_pages > 1 ? PBLE_LEVEL_1 : PBLE_LEVEL_0;
298362306a36Sopenharmony_ci	err = irdma_handle_q_mem(iwdev, &req, iwpbl, lvl);
298462306a36Sopenharmony_ci	if (err)
298562306a36Sopenharmony_ci		return err;
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci	ucontext = rdma_udata_to_drv_context(udata, struct irdma_ucontext,
298862306a36Sopenharmony_ci					     ibucontext);
298962306a36Sopenharmony_ci	spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
299062306a36Sopenharmony_ci	list_add_tail(&iwpbl->list, &ucontext->cq_reg_mem_list);
299162306a36Sopenharmony_ci	iwpbl->on_list = true;
299262306a36Sopenharmony_ci	spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ci	return 0;
299562306a36Sopenharmony_ci}
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci/**
299862306a36Sopenharmony_ci * irdma_reg_user_mr - Register a user memory region
299962306a36Sopenharmony_ci * @pd: ptr of pd
300062306a36Sopenharmony_ci * @start: virtual start address
300162306a36Sopenharmony_ci * @len: length of mr
300262306a36Sopenharmony_ci * @virt: virtual address
300362306a36Sopenharmony_ci * @access: access of mr
300462306a36Sopenharmony_ci * @udata: user data
300562306a36Sopenharmony_ci */
300662306a36Sopenharmony_cistatic struct ib_mr *irdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
300762306a36Sopenharmony_ci				       u64 virt, int access,
300862306a36Sopenharmony_ci				       struct ib_udata *udata)
300962306a36Sopenharmony_ci{
301062306a36Sopenharmony_ci#define IRDMA_MEM_REG_MIN_REQ_LEN offsetofend(struct irdma_mem_reg_req, sq_pages)
301162306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(pd->device);
301262306a36Sopenharmony_ci	struct irdma_mem_reg_req req = {};
301362306a36Sopenharmony_ci	struct ib_umem *region = NULL;
301462306a36Sopenharmony_ci	struct irdma_mr *iwmr = NULL;
301562306a36Sopenharmony_ci	int err;
301662306a36Sopenharmony_ci
301762306a36Sopenharmony_ci	if (len > iwdev->rf->sc_dev.hw_attrs.max_mr_size)
301862306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
301962306a36Sopenharmony_ci
302062306a36Sopenharmony_ci	if (udata->inlen < IRDMA_MEM_REG_MIN_REQ_LEN)
302162306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci	region = ib_umem_get(pd->device, start, len, access);
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci	if (IS_ERR(region)) {
302662306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev,
302762306a36Sopenharmony_ci			  "VERBS: Failed to create ib_umem region\n");
302862306a36Sopenharmony_ci		return (struct ib_mr *)region;
302962306a36Sopenharmony_ci	}
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	if (ib_copy_from_udata(&req, udata, min(sizeof(req), udata->inlen))) {
303262306a36Sopenharmony_ci		ib_umem_release(region);
303362306a36Sopenharmony_ci		return ERR_PTR(-EFAULT);
303462306a36Sopenharmony_ci	}
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	iwmr = irdma_alloc_iwmr(region, pd, virt, req.reg_type);
303762306a36Sopenharmony_ci	if (IS_ERR(iwmr)) {
303862306a36Sopenharmony_ci		ib_umem_release(region);
303962306a36Sopenharmony_ci		return (struct ib_mr *)iwmr;
304062306a36Sopenharmony_ci	}
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	switch (req.reg_type) {
304362306a36Sopenharmony_ci	case IRDMA_MEMREG_TYPE_QP:
304462306a36Sopenharmony_ci		err = irdma_reg_user_mr_type_qp(req, udata, iwmr);
304562306a36Sopenharmony_ci		if (err)
304662306a36Sopenharmony_ci			goto error;
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci		break;
304962306a36Sopenharmony_ci	case IRDMA_MEMREG_TYPE_CQ:
305062306a36Sopenharmony_ci		err = irdma_reg_user_mr_type_cq(req, udata, iwmr);
305162306a36Sopenharmony_ci		if (err)
305262306a36Sopenharmony_ci			goto error;
305362306a36Sopenharmony_ci		break;
305462306a36Sopenharmony_ci	case IRDMA_MEMREG_TYPE_MEM:
305562306a36Sopenharmony_ci		err = irdma_reg_user_mr_type_mem(iwmr, access);
305662306a36Sopenharmony_ci		if (err)
305762306a36Sopenharmony_ci			goto error;
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci		break;
306062306a36Sopenharmony_ci	default:
306162306a36Sopenharmony_ci		err = -EINVAL;
306262306a36Sopenharmony_ci		goto error;
306362306a36Sopenharmony_ci	}
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci	return &iwmr->ibmr;
306662306a36Sopenharmony_cierror:
306762306a36Sopenharmony_ci	ib_umem_release(region);
306862306a36Sopenharmony_ci	irdma_free_iwmr(iwmr);
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci	return ERR_PTR(err);
307162306a36Sopenharmony_ci}
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_cistatic struct ib_mr *irdma_reg_user_mr_dmabuf(struct ib_pd *pd, u64 start,
307462306a36Sopenharmony_ci					      u64 len, u64 virt,
307562306a36Sopenharmony_ci					      int fd, int access,
307662306a36Sopenharmony_ci					      struct ib_udata *udata)
307762306a36Sopenharmony_ci{
307862306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(pd->device);
307962306a36Sopenharmony_ci	struct ib_umem_dmabuf *umem_dmabuf;
308062306a36Sopenharmony_ci	struct irdma_mr *iwmr;
308162306a36Sopenharmony_ci	int err;
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_ci	if (len > iwdev->rf->sc_dev.hw_attrs.max_mr_size)
308462306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_ci	umem_dmabuf = ib_umem_dmabuf_get_pinned(pd->device, start, len, fd, access);
308762306a36Sopenharmony_ci	if (IS_ERR(umem_dmabuf)) {
308862306a36Sopenharmony_ci		err = PTR_ERR(umem_dmabuf);
308962306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev, "Failed to get dmabuf umem[%d]\n", err);
309062306a36Sopenharmony_ci		return ERR_PTR(err);
309162306a36Sopenharmony_ci	}
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci	iwmr = irdma_alloc_iwmr(&umem_dmabuf->umem, pd, virt, IRDMA_MEMREG_TYPE_MEM);
309462306a36Sopenharmony_ci	if (IS_ERR(iwmr)) {
309562306a36Sopenharmony_ci		err = PTR_ERR(iwmr);
309662306a36Sopenharmony_ci		goto err_release;
309762306a36Sopenharmony_ci	}
309862306a36Sopenharmony_ci
309962306a36Sopenharmony_ci	err = irdma_reg_user_mr_type_mem(iwmr, access);
310062306a36Sopenharmony_ci	if (err)
310162306a36Sopenharmony_ci		goto err_iwmr;
310262306a36Sopenharmony_ci
310362306a36Sopenharmony_ci	return &iwmr->ibmr;
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_cierr_iwmr:
310662306a36Sopenharmony_ci	irdma_free_iwmr(iwmr);
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_cierr_release:
310962306a36Sopenharmony_ci	ib_umem_release(&umem_dmabuf->umem);
311062306a36Sopenharmony_ci
311162306a36Sopenharmony_ci	return ERR_PTR(err);
311262306a36Sopenharmony_ci}
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci/**
311562306a36Sopenharmony_ci * irdma_reg_phys_mr - register kernel physical memory
311662306a36Sopenharmony_ci * @pd: ibpd pointer
311762306a36Sopenharmony_ci * @addr: physical address of memory to register
311862306a36Sopenharmony_ci * @size: size of memory to register
311962306a36Sopenharmony_ci * @access: Access rights
312062306a36Sopenharmony_ci * @iova_start: start of virtual address for physical buffers
312162306a36Sopenharmony_ci */
312262306a36Sopenharmony_cistruct ib_mr *irdma_reg_phys_mr(struct ib_pd *pd, u64 addr, u64 size, int access,
312362306a36Sopenharmony_ci				u64 *iova_start)
312462306a36Sopenharmony_ci{
312562306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(pd->device);
312662306a36Sopenharmony_ci	struct irdma_pbl *iwpbl;
312762306a36Sopenharmony_ci	struct irdma_mr *iwmr;
312862306a36Sopenharmony_ci	u32 stag;
312962306a36Sopenharmony_ci	int ret;
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	iwmr = kzalloc(sizeof(*iwmr), GFP_KERNEL);
313262306a36Sopenharmony_ci	if (!iwmr)
313362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
313462306a36Sopenharmony_ci
313562306a36Sopenharmony_ci	iwmr->ibmr.pd = pd;
313662306a36Sopenharmony_ci	iwmr->ibmr.device = pd->device;
313762306a36Sopenharmony_ci	iwpbl = &iwmr->iwpbl;
313862306a36Sopenharmony_ci	iwpbl->iwmr = iwmr;
313962306a36Sopenharmony_ci	iwmr->type = IRDMA_MEMREG_TYPE_MEM;
314062306a36Sopenharmony_ci	iwpbl->user_base = *iova_start;
314162306a36Sopenharmony_ci	stag = irdma_create_stag(iwdev);
314262306a36Sopenharmony_ci	if (!stag) {
314362306a36Sopenharmony_ci		ret = -ENOMEM;
314462306a36Sopenharmony_ci		goto err;
314562306a36Sopenharmony_ci	}
314662306a36Sopenharmony_ci
314762306a36Sopenharmony_ci	iwmr->stag = stag;
314862306a36Sopenharmony_ci	iwmr->ibmr.iova = *iova_start;
314962306a36Sopenharmony_ci	iwmr->ibmr.rkey = stag;
315062306a36Sopenharmony_ci	iwmr->ibmr.lkey = stag;
315162306a36Sopenharmony_ci	iwmr->page_cnt = 1;
315262306a36Sopenharmony_ci	iwmr->pgaddrmem[0] = addr;
315362306a36Sopenharmony_ci	iwmr->len = size;
315462306a36Sopenharmony_ci	iwmr->page_size = SZ_4K;
315562306a36Sopenharmony_ci	ret = irdma_hwreg_mr(iwdev, iwmr, access);
315662306a36Sopenharmony_ci	if (ret) {
315762306a36Sopenharmony_ci		irdma_free_stag(iwdev, stag);
315862306a36Sopenharmony_ci		goto err;
315962306a36Sopenharmony_ci	}
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_ci	return &iwmr->ibmr;
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_cierr:
316462306a36Sopenharmony_ci	kfree(iwmr);
316562306a36Sopenharmony_ci
316662306a36Sopenharmony_ci	return ERR_PTR(ret);
316762306a36Sopenharmony_ci}
316862306a36Sopenharmony_ci
316962306a36Sopenharmony_ci/**
317062306a36Sopenharmony_ci * irdma_get_dma_mr - register physical mem
317162306a36Sopenharmony_ci * @pd: ptr of pd
317262306a36Sopenharmony_ci * @acc: access for memory
317362306a36Sopenharmony_ci */
317462306a36Sopenharmony_cistatic struct ib_mr *irdma_get_dma_mr(struct ib_pd *pd, int acc)
317562306a36Sopenharmony_ci{
317662306a36Sopenharmony_ci	u64 kva = 0;
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci	return irdma_reg_phys_mr(pd, 0, 0, acc, &kva);
317962306a36Sopenharmony_ci}
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_ci/**
318262306a36Sopenharmony_ci * irdma_del_memlist - Deleting pbl list entries for CQ/QP
318362306a36Sopenharmony_ci * @iwmr: iwmr for IB's user page addresses
318462306a36Sopenharmony_ci * @ucontext: ptr to user context
318562306a36Sopenharmony_ci */
318662306a36Sopenharmony_cistatic void irdma_del_memlist(struct irdma_mr *iwmr,
318762306a36Sopenharmony_ci			      struct irdma_ucontext *ucontext)
318862306a36Sopenharmony_ci{
318962306a36Sopenharmony_ci	struct irdma_pbl *iwpbl = &iwmr->iwpbl;
319062306a36Sopenharmony_ci	unsigned long flags;
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	switch (iwmr->type) {
319362306a36Sopenharmony_ci	case IRDMA_MEMREG_TYPE_CQ:
319462306a36Sopenharmony_ci		spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
319562306a36Sopenharmony_ci		if (iwpbl->on_list) {
319662306a36Sopenharmony_ci			iwpbl->on_list = false;
319762306a36Sopenharmony_ci			list_del(&iwpbl->list);
319862306a36Sopenharmony_ci		}
319962306a36Sopenharmony_ci		spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
320062306a36Sopenharmony_ci		break;
320162306a36Sopenharmony_ci	case IRDMA_MEMREG_TYPE_QP:
320262306a36Sopenharmony_ci		spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
320362306a36Sopenharmony_ci		if (iwpbl->on_list) {
320462306a36Sopenharmony_ci			iwpbl->on_list = false;
320562306a36Sopenharmony_ci			list_del(&iwpbl->list);
320662306a36Sopenharmony_ci		}
320762306a36Sopenharmony_ci		spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
320862306a36Sopenharmony_ci		break;
320962306a36Sopenharmony_ci	default:
321062306a36Sopenharmony_ci		break;
321162306a36Sopenharmony_ci	}
321262306a36Sopenharmony_ci}
321362306a36Sopenharmony_ci
321462306a36Sopenharmony_ci/**
321562306a36Sopenharmony_ci * irdma_dereg_mr - deregister mr
321662306a36Sopenharmony_ci * @ib_mr: mr ptr for dereg
321762306a36Sopenharmony_ci * @udata: user data
321862306a36Sopenharmony_ci */
321962306a36Sopenharmony_cistatic int irdma_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
322062306a36Sopenharmony_ci{
322162306a36Sopenharmony_ci	struct ib_pd *ibpd = ib_mr->pd;
322262306a36Sopenharmony_ci	struct irdma_pd *iwpd = to_iwpd(ibpd);
322362306a36Sopenharmony_ci	struct irdma_mr *iwmr = to_iwmr(ib_mr);
322462306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ib_mr->device);
322562306a36Sopenharmony_ci	struct irdma_dealloc_stag_info *info;
322662306a36Sopenharmony_ci	struct irdma_pbl *iwpbl = &iwmr->iwpbl;
322762306a36Sopenharmony_ci	struct irdma_pble_alloc *palloc = &iwpbl->pble_alloc;
322862306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
322962306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
323062306a36Sopenharmony_ci	int status;
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci	if (iwmr->type != IRDMA_MEMREG_TYPE_MEM) {
323362306a36Sopenharmony_ci		if (iwmr->region) {
323462306a36Sopenharmony_ci			struct irdma_ucontext *ucontext;
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci			ucontext = rdma_udata_to_drv_context(udata,
323762306a36Sopenharmony_ci						struct irdma_ucontext,
323862306a36Sopenharmony_ci						ibucontext);
323962306a36Sopenharmony_ci			irdma_del_memlist(iwmr, ucontext);
324062306a36Sopenharmony_ci		}
324162306a36Sopenharmony_ci		goto done;
324262306a36Sopenharmony_ci	}
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
324562306a36Sopenharmony_ci	if (!cqp_request)
324662306a36Sopenharmony_ci		return -ENOMEM;
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
324962306a36Sopenharmony_ci	info = &cqp_info->in.u.dealloc_stag.info;
325062306a36Sopenharmony_ci	memset(info, 0, sizeof(*info));
325162306a36Sopenharmony_ci	info->pd_id = iwpd->sc_pd.pd_id;
325262306a36Sopenharmony_ci	info->stag_idx = ib_mr->rkey >> IRDMA_CQPSQ_STAG_IDX_S;
325362306a36Sopenharmony_ci	info->mr = true;
325462306a36Sopenharmony_ci	if (iwpbl->pbl_allocated)
325562306a36Sopenharmony_ci		info->dealloc_pbl = true;
325662306a36Sopenharmony_ci
325762306a36Sopenharmony_ci	cqp_info->cqp_cmd = IRDMA_OP_DEALLOC_STAG;
325862306a36Sopenharmony_ci	cqp_info->post_sq = 1;
325962306a36Sopenharmony_ci	cqp_info->in.u.dealloc_stag.dev = &iwdev->rf->sc_dev;
326062306a36Sopenharmony_ci	cqp_info->in.u.dealloc_stag.scratch = (uintptr_t)cqp_request;
326162306a36Sopenharmony_ci	status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
326262306a36Sopenharmony_ci	irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
326362306a36Sopenharmony_ci	if (status)
326462306a36Sopenharmony_ci		return status;
326562306a36Sopenharmony_ci
326662306a36Sopenharmony_ci	irdma_free_stag(iwdev, iwmr->stag);
326762306a36Sopenharmony_cidone:
326862306a36Sopenharmony_ci	if (iwpbl->pbl_allocated)
326962306a36Sopenharmony_ci		irdma_free_pble(iwdev->rf->pble_rsrc, palloc);
327062306a36Sopenharmony_ci	ib_umem_release(iwmr->region);
327162306a36Sopenharmony_ci	kfree(iwmr);
327262306a36Sopenharmony_ci
327362306a36Sopenharmony_ci	return 0;
327462306a36Sopenharmony_ci}
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci/**
327762306a36Sopenharmony_ci * irdma_post_send -  kernel application wr
327862306a36Sopenharmony_ci * @ibqp: qp ptr for wr
327962306a36Sopenharmony_ci * @ib_wr: work request ptr
328062306a36Sopenharmony_ci * @bad_wr: return of bad wr if err
328162306a36Sopenharmony_ci */
328262306a36Sopenharmony_cistatic int irdma_post_send(struct ib_qp *ibqp,
328362306a36Sopenharmony_ci			   const struct ib_send_wr *ib_wr,
328462306a36Sopenharmony_ci			   const struct ib_send_wr **bad_wr)
328562306a36Sopenharmony_ci{
328662306a36Sopenharmony_ci	struct irdma_qp *iwqp;
328762306a36Sopenharmony_ci	struct irdma_qp_uk *ukqp;
328862306a36Sopenharmony_ci	struct irdma_sc_dev *dev;
328962306a36Sopenharmony_ci	struct irdma_post_sq_info info;
329062306a36Sopenharmony_ci	int err = 0;
329162306a36Sopenharmony_ci	unsigned long flags;
329262306a36Sopenharmony_ci	bool inv_stag;
329362306a36Sopenharmony_ci	struct irdma_ah *ah;
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	iwqp = to_iwqp(ibqp);
329662306a36Sopenharmony_ci	ukqp = &iwqp->sc_qp.qp_uk;
329762306a36Sopenharmony_ci	dev = &iwqp->iwdev->rf->sc_dev;
329862306a36Sopenharmony_ci
329962306a36Sopenharmony_ci	spin_lock_irqsave(&iwqp->lock, flags);
330062306a36Sopenharmony_ci	while (ib_wr) {
330162306a36Sopenharmony_ci		memset(&info, 0, sizeof(info));
330262306a36Sopenharmony_ci		inv_stag = false;
330362306a36Sopenharmony_ci		info.wr_id = (ib_wr->wr_id);
330462306a36Sopenharmony_ci		if ((ib_wr->send_flags & IB_SEND_SIGNALED) || iwqp->sig_all)
330562306a36Sopenharmony_ci			info.signaled = true;
330662306a36Sopenharmony_ci		if (ib_wr->send_flags & IB_SEND_FENCE)
330762306a36Sopenharmony_ci			info.read_fence = true;
330862306a36Sopenharmony_ci		switch (ib_wr->opcode) {
330962306a36Sopenharmony_ci		case IB_WR_SEND_WITH_IMM:
331062306a36Sopenharmony_ci			if (ukqp->qp_caps & IRDMA_SEND_WITH_IMM) {
331162306a36Sopenharmony_ci				info.imm_data_valid = true;
331262306a36Sopenharmony_ci				info.imm_data = ntohl(ib_wr->ex.imm_data);
331362306a36Sopenharmony_ci			} else {
331462306a36Sopenharmony_ci				err = -EINVAL;
331562306a36Sopenharmony_ci				break;
331662306a36Sopenharmony_ci			}
331762306a36Sopenharmony_ci			fallthrough;
331862306a36Sopenharmony_ci		case IB_WR_SEND:
331962306a36Sopenharmony_ci		case IB_WR_SEND_WITH_INV:
332062306a36Sopenharmony_ci			if (ib_wr->opcode == IB_WR_SEND ||
332162306a36Sopenharmony_ci			    ib_wr->opcode == IB_WR_SEND_WITH_IMM) {
332262306a36Sopenharmony_ci				if (ib_wr->send_flags & IB_SEND_SOLICITED)
332362306a36Sopenharmony_ci					info.op_type = IRDMA_OP_TYPE_SEND_SOL;
332462306a36Sopenharmony_ci				else
332562306a36Sopenharmony_ci					info.op_type = IRDMA_OP_TYPE_SEND;
332662306a36Sopenharmony_ci			} else {
332762306a36Sopenharmony_ci				if (ib_wr->send_flags & IB_SEND_SOLICITED)
332862306a36Sopenharmony_ci					info.op_type = IRDMA_OP_TYPE_SEND_SOL_INV;
332962306a36Sopenharmony_ci				else
333062306a36Sopenharmony_ci					info.op_type = IRDMA_OP_TYPE_SEND_INV;
333162306a36Sopenharmony_ci				info.stag_to_inv = ib_wr->ex.invalidate_rkey;
333262306a36Sopenharmony_ci			}
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci			info.op.send.num_sges = ib_wr->num_sge;
333562306a36Sopenharmony_ci			info.op.send.sg_list = ib_wr->sg_list;
333662306a36Sopenharmony_ci			if (iwqp->ibqp.qp_type == IB_QPT_UD ||
333762306a36Sopenharmony_ci			    iwqp->ibqp.qp_type == IB_QPT_GSI) {
333862306a36Sopenharmony_ci				ah = to_iwah(ud_wr(ib_wr)->ah);
333962306a36Sopenharmony_ci				info.op.send.ah_id = ah->sc_ah.ah_info.ah_idx;
334062306a36Sopenharmony_ci				info.op.send.qkey = ud_wr(ib_wr)->remote_qkey;
334162306a36Sopenharmony_ci				info.op.send.dest_qp = ud_wr(ib_wr)->remote_qpn;
334262306a36Sopenharmony_ci			}
334362306a36Sopenharmony_ci
334462306a36Sopenharmony_ci			if (ib_wr->send_flags & IB_SEND_INLINE)
334562306a36Sopenharmony_ci				err = irdma_uk_inline_send(ukqp, &info, false);
334662306a36Sopenharmony_ci			else
334762306a36Sopenharmony_ci				err = irdma_uk_send(ukqp, &info, false);
334862306a36Sopenharmony_ci			break;
334962306a36Sopenharmony_ci		case IB_WR_RDMA_WRITE_WITH_IMM:
335062306a36Sopenharmony_ci			if (ukqp->qp_caps & IRDMA_WRITE_WITH_IMM) {
335162306a36Sopenharmony_ci				info.imm_data_valid = true;
335262306a36Sopenharmony_ci				info.imm_data = ntohl(ib_wr->ex.imm_data);
335362306a36Sopenharmony_ci			} else {
335462306a36Sopenharmony_ci				err = -EINVAL;
335562306a36Sopenharmony_ci				break;
335662306a36Sopenharmony_ci			}
335762306a36Sopenharmony_ci			fallthrough;
335862306a36Sopenharmony_ci		case IB_WR_RDMA_WRITE:
335962306a36Sopenharmony_ci			if (ib_wr->send_flags & IB_SEND_SOLICITED)
336062306a36Sopenharmony_ci				info.op_type = IRDMA_OP_TYPE_RDMA_WRITE_SOL;
336162306a36Sopenharmony_ci			else
336262306a36Sopenharmony_ci				info.op_type = IRDMA_OP_TYPE_RDMA_WRITE;
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci			info.op.rdma_write.num_lo_sges = ib_wr->num_sge;
336562306a36Sopenharmony_ci			info.op.rdma_write.lo_sg_list = ib_wr->sg_list;
336662306a36Sopenharmony_ci			info.op.rdma_write.rem_addr.addr =
336762306a36Sopenharmony_ci				rdma_wr(ib_wr)->remote_addr;
336862306a36Sopenharmony_ci			info.op.rdma_write.rem_addr.lkey = rdma_wr(ib_wr)->rkey;
336962306a36Sopenharmony_ci			if (ib_wr->send_flags & IB_SEND_INLINE)
337062306a36Sopenharmony_ci				err = irdma_uk_inline_rdma_write(ukqp, &info, false);
337162306a36Sopenharmony_ci			else
337262306a36Sopenharmony_ci				err = irdma_uk_rdma_write(ukqp, &info, false);
337362306a36Sopenharmony_ci			break;
337462306a36Sopenharmony_ci		case IB_WR_RDMA_READ_WITH_INV:
337562306a36Sopenharmony_ci			inv_stag = true;
337662306a36Sopenharmony_ci			fallthrough;
337762306a36Sopenharmony_ci		case IB_WR_RDMA_READ:
337862306a36Sopenharmony_ci			if (ib_wr->num_sge >
337962306a36Sopenharmony_ci			    dev->hw_attrs.uk_attrs.max_hw_read_sges) {
338062306a36Sopenharmony_ci				err = -EINVAL;
338162306a36Sopenharmony_ci				break;
338262306a36Sopenharmony_ci			}
338362306a36Sopenharmony_ci			info.op_type = IRDMA_OP_TYPE_RDMA_READ;
338462306a36Sopenharmony_ci			info.op.rdma_read.rem_addr.addr = rdma_wr(ib_wr)->remote_addr;
338562306a36Sopenharmony_ci			info.op.rdma_read.rem_addr.lkey = rdma_wr(ib_wr)->rkey;
338662306a36Sopenharmony_ci			info.op.rdma_read.lo_sg_list = (void *)ib_wr->sg_list;
338762306a36Sopenharmony_ci			info.op.rdma_read.num_lo_sges = ib_wr->num_sge;
338862306a36Sopenharmony_ci			err = irdma_uk_rdma_read(ukqp, &info, inv_stag, false);
338962306a36Sopenharmony_ci			break;
339062306a36Sopenharmony_ci		case IB_WR_LOCAL_INV:
339162306a36Sopenharmony_ci			info.op_type = IRDMA_OP_TYPE_INV_STAG;
339262306a36Sopenharmony_ci			info.local_fence = info.read_fence;
339362306a36Sopenharmony_ci			info.op.inv_local_stag.target_stag = ib_wr->ex.invalidate_rkey;
339462306a36Sopenharmony_ci			err = irdma_uk_stag_local_invalidate(ukqp, &info, true);
339562306a36Sopenharmony_ci			break;
339662306a36Sopenharmony_ci		case IB_WR_REG_MR: {
339762306a36Sopenharmony_ci			struct irdma_mr *iwmr = to_iwmr(reg_wr(ib_wr)->mr);
339862306a36Sopenharmony_ci			struct irdma_pble_alloc *palloc = &iwmr->iwpbl.pble_alloc;
339962306a36Sopenharmony_ci			struct irdma_fast_reg_stag_info stag_info = {};
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_ci			stag_info.signaled = info.signaled;
340262306a36Sopenharmony_ci			stag_info.read_fence = info.read_fence;
340362306a36Sopenharmony_ci			stag_info.access_rights = irdma_get_mr_access(reg_wr(ib_wr)->access);
340462306a36Sopenharmony_ci			stag_info.stag_key = reg_wr(ib_wr)->key & 0xff;
340562306a36Sopenharmony_ci			stag_info.stag_idx = reg_wr(ib_wr)->key >> 8;
340662306a36Sopenharmony_ci			stag_info.page_size = reg_wr(ib_wr)->mr->page_size;
340762306a36Sopenharmony_ci			stag_info.wr_id = ib_wr->wr_id;
340862306a36Sopenharmony_ci			stag_info.addr_type = IRDMA_ADDR_TYPE_VA_BASED;
340962306a36Sopenharmony_ci			stag_info.va = (void *)(uintptr_t)iwmr->ibmr.iova;
341062306a36Sopenharmony_ci			stag_info.total_len = iwmr->ibmr.length;
341162306a36Sopenharmony_ci			stag_info.reg_addr_pa = *palloc->level1.addr;
341262306a36Sopenharmony_ci			stag_info.first_pm_pbl_index = palloc->level1.idx;
341362306a36Sopenharmony_ci			stag_info.local_fence = ib_wr->send_flags & IB_SEND_FENCE;
341462306a36Sopenharmony_ci			if (iwmr->npages > IRDMA_MIN_PAGES_PER_FMR)
341562306a36Sopenharmony_ci				stag_info.chunk_size = 1;
341662306a36Sopenharmony_ci			err = irdma_sc_mr_fast_register(&iwqp->sc_qp, &stag_info,
341762306a36Sopenharmony_ci							true);
341862306a36Sopenharmony_ci			break;
341962306a36Sopenharmony_ci		}
342062306a36Sopenharmony_ci		default:
342162306a36Sopenharmony_ci			err = -EINVAL;
342262306a36Sopenharmony_ci			ibdev_dbg(&iwqp->iwdev->ibdev,
342362306a36Sopenharmony_ci				  "VERBS: upost_send bad opcode = 0x%x\n",
342462306a36Sopenharmony_ci				  ib_wr->opcode);
342562306a36Sopenharmony_ci			break;
342662306a36Sopenharmony_ci		}
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci		if (err)
342962306a36Sopenharmony_ci			break;
343062306a36Sopenharmony_ci		ib_wr = ib_wr->next;
343162306a36Sopenharmony_ci	}
343262306a36Sopenharmony_ci
343362306a36Sopenharmony_ci	if (!iwqp->flush_issued) {
343462306a36Sopenharmony_ci		if (iwqp->hw_iwarp_state <= IRDMA_QP_STATE_RTS)
343562306a36Sopenharmony_ci			irdma_uk_qp_post_wr(ukqp);
343662306a36Sopenharmony_ci		spin_unlock_irqrestore(&iwqp->lock, flags);
343762306a36Sopenharmony_ci	} else {
343862306a36Sopenharmony_ci		spin_unlock_irqrestore(&iwqp->lock, flags);
343962306a36Sopenharmony_ci		mod_delayed_work(iwqp->iwdev->cleanup_wq, &iwqp->dwork_flush,
344062306a36Sopenharmony_ci				 msecs_to_jiffies(IRDMA_FLUSH_DELAY_MS));
344162306a36Sopenharmony_ci	}
344262306a36Sopenharmony_ci	if (err)
344362306a36Sopenharmony_ci		*bad_wr = ib_wr;
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci	return err;
344662306a36Sopenharmony_ci}
344762306a36Sopenharmony_ci
344862306a36Sopenharmony_ci/**
344962306a36Sopenharmony_ci * irdma_post_recv - post receive wr for kernel application
345062306a36Sopenharmony_ci * @ibqp: ib qp pointer
345162306a36Sopenharmony_ci * @ib_wr: work request for receive
345262306a36Sopenharmony_ci * @bad_wr: bad wr caused an error
345362306a36Sopenharmony_ci */
345462306a36Sopenharmony_cistatic int irdma_post_recv(struct ib_qp *ibqp,
345562306a36Sopenharmony_ci			   const struct ib_recv_wr *ib_wr,
345662306a36Sopenharmony_ci			   const struct ib_recv_wr **bad_wr)
345762306a36Sopenharmony_ci{
345862306a36Sopenharmony_ci	struct irdma_qp *iwqp;
345962306a36Sopenharmony_ci	struct irdma_qp_uk *ukqp;
346062306a36Sopenharmony_ci	struct irdma_post_rq_info post_recv = {};
346162306a36Sopenharmony_ci	unsigned long flags;
346262306a36Sopenharmony_ci	int err = 0;
346362306a36Sopenharmony_ci
346462306a36Sopenharmony_ci	iwqp = to_iwqp(ibqp);
346562306a36Sopenharmony_ci	ukqp = &iwqp->sc_qp.qp_uk;
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ci	spin_lock_irqsave(&iwqp->lock, flags);
346862306a36Sopenharmony_ci	while (ib_wr) {
346962306a36Sopenharmony_ci		post_recv.num_sges = ib_wr->num_sge;
347062306a36Sopenharmony_ci		post_recv.wr_id = ib_wr->wr_id;
347162306a36Sopenharmony_ci		post_recv.sg_list = ib_wr->sg_list;
347262306a36Sopenharmony_ci		err = irdma_uk_post_receive(ukqp, &post_recv);
347362306a36Sopenharmony_ci		if (err) {
347462306a36Sopenharmony_ci			ibdev_dbg(&iwqp->iwdev->ibdev,
347562306a36Sopenharmony_ci				  "VERBS: post_recv err %d\n", err);
347662306a36Sopenharmony_ci			goto out;
347762306a36Sopenharmony_ci		}
347862306a36Sopenharmony_ci
347962306a36Sopenharmony_ci		ib_wr = ib_wr->next;
348062306a36Sopenharmony_ci	}
348162306a36Sopenharmony_ci
348262306a36Sopenharmony_ciout:
348362306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwqp->lock, flags);
348462306a36Sopenharmony_ci	if (iwqp->flush_issued)
348562306a36Sopenharmony_ci		mod_delayed_work(iwqp->iwdev->cleanup_wq, &iwqp->dwork_flush,
348662306a36Sopenharmony_ci				 msecs_to_jiffies(IRDMA_FLUSH_DELAY_MS));
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_ci	if (err)
348962306a36Sopenharmony_ci		*bad_wr = ib_wr;
349062306a36Sopenharmony_ci
349162306a36Sopenharmony_ci	return err;
349262306a36Sopenharmony_ci}
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci/**
349562306a36Sopenharmony_ci * irdma_flush_err_to_ib_wc_status - return change flush error code to IB status
349662306a36Sopenharmony_ci * @opcode: iwarp flush code
349762306a36Sopenharmony_ci */
349862306a36Sopenharmony_cistatic enum ib_wc_status irdma_flush_err_to_ib_wc_status(enum irdma_flush_opcode opcode)
349962306a36Sopenharmony_ci{
350062306a36Sopenharmony_ci	switch (opcode) {
350162306a36Sopenharmony_ci	case FLUSH_PROT_ERR:
350262306a36Sopenharmony_ci		return IB_WC_LOC_PROT_ERR;
350362306a36Sopenharmony_ci	case FLUSH_REM_ACCESS_ERR:
350462306a36Sopenharmony_ci		return IB_WC_REM_ACCESS_ERR;
350562306a36Sopenharmony_ci	case FLUSH_LOC_QP_OP_ERR:
350662306a36Sopenharmony_ci		return IB_WC_LOC_QP_OP_ERR;
350762306a36Sopenharmony_ci	case FLUSH_REM_OP_ERR:
350862306a36Sopenharmony_ci		return IB_WC_REM_OP_ERR;
350962306a36Sopenharmony_ci	case FLUSH_LOC_LEN_ERR:
351062306a36Sopenharmony_ci		return IB_WC_LOC_LEN_ERR;
351162306a36Sopenharmony_ci	case FLUSH_GENERAL_ERR:
351262306a36Sopenharmony_ci		return IB_WC_WR_FLUSH_ERR;
351362306a36Sopenharmony_ci	case FLUSH_RETRY_EXC_ERR:
351462306a36Sopenharmony_ci		return IB_WC_RETRY_EXC_ERR;
351562306a36Sopenharmony_ci	case FLUSH_MW_BIND_ERR:
351662306a36Sopenharmony_ci		return IB_WC_MW_BIND_ERR;
351762306a36Sopenharmony_ci	case FLUSH_REM_INV_REQ_ERR:
351862306a36Sopenharmony_ci		return IB_WC_REM_INV_REQ_ERR;
351962306a36Sopenharmony_ci	case FLUSH_FATAL_ERR:
352062306a36Sopenharmony_ci	default:
352162306a36Sopenharmony_ci		return IB_WC_FATAL_ERR;
352262306a36Sopenharmony_ci	}
352362306a36Sopenharmony_ci}
352462306a36Sopenharmony_ci
352562306a36Sopenharmony_ci/**
352662306a36Sopenharmony_ci * irdma_process_cqe - process cqe info
352762306a36Sopenharmony_ci * @entry: processed cqe
352862306a36Sopenharmony_ci * @cq_poll_info: cqe info
352962306a36Sopenharmony_ci */
353062306a36Sopenharmony_cistatic void irdma_process_cqe(struct ib_wc *entry,
353162306a36Sopenharmony_ci			      struct irdma_cq_poll_info *cq_poll_info)
353262306a36Sopenharmony_ci{
353362306a36Sopenharmony_ci	struct irdma_sc_qp *qp;
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_ci	entry->wc_flags = 0;
353662306a36Sopenharmony_ci	entry->pkey_index = 0;
353762306a36Sopenharmony_ci	entry->wr_id = cq_poll_info->wr_id;
353862306a36Sopenharmony_ci
353962306a36Sopenharmony_ci	qp = cq_poll_info->qp_handle;
354062306a36Sopenharmony_ci	entry->qp = qp->qp_uk.back_qp;
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_ci	if (cq_poll_info->error) {
354362306a36Sopenharmony_ci		entry->status = (cq_poll_info->comp_status == IRDMA_COMPL_STATUS_FLUSHED) ?
354462306a36Sopenharmony_ci				irdma_flush_err_to_ib_wc_status(cq_poll_info->minor_err) : IB_WC_GENERAL_ERR;
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci		entry->vendor_err = cq_poll_info->major_err << 16 |
354762306a36Sopenharmony_ci				    cq_poll_info->minor_err;
354862306a36Sopenharmony_ci	} else {
354962306a36Sopenharmony_ci		entry->status = IB_WC_SUCCESS;
355062306a36Sopenharmony_ci		if (cq_poll_info->imm_valid) {
355162306a36Sopenharmony_ci			entry->ex.imm_data = htonl(cq_poll_info->imm_data);
355262306a36Sopenharmony_ci			entry->wc_flags |= IB_WC_WITH_IMM;
355362306a36Sopenharmony_ci		}
355462306a36Sopenharmony_ci		if (cq_poll_info->ud_smac_valid) {
355562306a36Sopenharmony_ci			ether_addr_copy(entry->smac, cq_poll_info->ud_smac);
355662306a36Sopenharmony_ci			entry->wc_flags |= IB_WC_WITH_SMAC;
355762306a36Sopenharmony_ci		}
355862306a36Sopenharmony_ci
355962306a36Sopenharmony_ci		if (cq_poll_info->ud_vlan_valid) {
356062306a36Sopenharmony_ci			u16 vlan = cq_poll_info->ud_vlan & VLAN_VID_MASK;
356162306a36Sopenharmony_ci
356262306a36Sopenharmony_ci			entry->sl = cq_poll_info->ud_vlan >> VLAN_PRIO_SHIFT;
356362306a36Sopenharmony_ci			if (vlan) {
356462306a36Sopenharmony_ci				entry->vlan_id = vlan;
356562306a36Sopenharmony_ci				entry->wc_flags |= IB_WC_WITH_VLAN;
356662306a36Sopenharmony_ci			}
356762306a36Sopenharmony_ci		} else {
356862306a36Sopenharmony_ci			entry->sl = 0;
356962306a36Sopenharmony_ci		}
357062306a36Sopenharmony_ci	}
357162306a36Sopenharmony_ci
357262306a36Sopenharmony_ci	if (cq_poll_info->q_type == IRDMA_CQE_QTYPE_SQ) {
357362306a36Sopenharmony_ci		set_ib_wc_op_sq(cq_poll_info, entry);
357462306a36Sopenharmony_ci	} else {
357562306a36Sopenharmony_ci		set_ib_wc_op_rq(cq_poll_info, entry,
357662306a36Sopenharmony_ci				qp->qp_uk.qp_caps & IRDMA_SEND_WITH_IMM);
357762306a36Sopenharmony_ci		if (qp->qp_uk.qp_type != IRDMA_QP_TYPE_ROCE_UD &&
357862306a36Sopenharmony_ci		    cq_poll_info->stag_invalid_set) {
357962306a36Sopenharmony_ci			entry->ex.invalidate_rkey = cq_poll_info->inv_stag;
358062306a36Sopenharmony_ci			entry->wc_flags |= IB_WC_WITH_INVALIDATE;
358162306a36Sopenharmony_ci		}
358262306a36Sopenharmony_ci	}
358362306a36Sopenharmony_ci
358462306a36Sopenharmony_ci	if (qp->qp_uk.qp_type == IRDMA_QP_TYPE_ROCE_UD) {
358562306a36Sopenharmony_ci		entry->src_qp = cq_poll_info->ud_src_qpn;
358662306a36Sopenharmony_ci		entry->slid = 0;
358762306a36Sopenharmony_ci		entry->wc_flags |=
358862306a36Sopenharmony_ci			(IB_WC_GRH | IB_WC_WITH_NETWORK_HDR_TYPE);
358962306a36Sopenharmony_ci		entry->network_hdr_type = cq_poll_info->ipv4 ?
359062306a36Sopenharmony_ci						  RDMA_NETWORK_IPV4 :
359162306a36Sopenharmony_ci						  RDMA_NETWORK_IPV6;
359262306a36Sopenharmony_ci	} else {
359362306a36Sopenharmony_ci		entry->src_qp = cq_poll_info->qp_id;
359462306a36Sopenharmony_ci	}
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci	entry->byte_len = cq_poll_info->bytes_xfered;
359762306a36Sopenharmony_ci}
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_ci/**
360062306a36Sopenharmony_ci * irdma_poll_one - poll one entry of the CQ
360162306a36Sopenharmony_ci * @ukcq: ukcq to poll
360262306a36Sopenharmony_ci * @cur_cqe: current CQE info to be filled in
360362306a36Sopenharmony_ci * @entry: ibv_wc object to be filled for non-extended CQ or NULL for extended CQ
360462306a36Sopenharmony_ci *
360562306a36Sopenharmony_ci * Returns the internal irdma device error code or 0 on success
360662306a36Sopenharmony_ci */
360762306a36Sopenharmony_cistatic inline int irdma_poll_one(struct irdma_cq_uk *ukcq,
360862306a36Sopenharmony_ci				 struct irdma_cq_poll_info *cur_cqe,
360962306a36Sopenharmony_ci				 struct ib_wc *entry)
361062306a36Sopenharmony_ci{
361162306a36Sopenharmony_ci	int ret = irdma_uk_cq_poll_cmpl(ukcq, cur_cqe);
361262306a36Sopenharmony_ci
361362306a36Sopenharmony_ci	if (ret)
361462306a36Sopenharmony_ci		return ret;
361562306a36Sopenharmony_ci
361662306a36Sopenharmony_ci	irdma_process_cqe(entry, cur_cqe);
361762306a36Sopenharmony_ci
361862306a36Sopenharmony_ci	return 0;
361962306a36Sopenharmony_ci}
362062306a36Sopenharmony_ci
362162306a36Sopenharmony_ci/**
362262306a36Sopenharmony_ci * __irdma_poll_cq - poll cq for completion (kernel apps)
362362306a36Sopenharmony_ci * @iwcq: cq to poll
362462306a36Sopenharmony_ci * @num_entries: number of entries to poll
362562306a36Sopenharmony_ci * @entry: wr of a completed entry
362662306a36Sopenharmony_ci */
362762306a36Sopenharmony_cistatic int __irdma_poll_cq(struct irdma_cq *iwcq, int num_entries, struct ib_wc *entry)
362862306a36Sopenharmony_ci{
362962306a36Sopenharmony_ci	struct list_head *tmp_node, *list_node;
363062306a36Sopenharmony_ci	struct irdma_cq_buf *last_buf = NULL;
363162306a36Sopenharmony_ci	struct irdma_cq_poll_info *cur_cqe = &iwcq->cur_cqe;
363262306a36Sopenharmony_ci	struct irdma_cq_buf *cq_buf;
363362306a36Sopenharmony_ci	int ret;
363462306a36Sopenharmony_ci	struct irdma_device *iwdev;
363562306a36Sopenharmony_ci	struct irdma_cq_uk *ukcq;
363662306a36Sopenharmony_ci	bool cq_new_cqe = false;
363762306a36Sopenharmony_ci	int resized_bufs = 0;
363862306a36Sopenharmony_ci	int npolled = 0;
363962306a36Sopenharmony_ci
364062306a36Sopenharmony_ci	iwdev = to_iwdev(iwcq->ibcq.device);
364162306a36Sopenharmony_ci	ukcq = &iwcq->sc_cq.cq_uk;
364262306a36Sopenharmony_ci
364362306a36Sopenharmony_ci	/* go through the list of previously resized CQ buffers */
364462306a36Sopenharmony_ci	list_for_each_safe(list_node, tmp_node, &iwcq->resize_list) {
364562306a36Sopenharmony_ci		cq_buf = container_of(list_node, struct irdma_cq_buf, list);
364662306a36Sopenharmony_ci		while (npolled < num_entries) {
364762306a36Sopenharmony_ci			ret = irdma_poll_one(&cq_buf->cq_uk, cur_cqe, entry + npolled);
364862306a36Sopenharmony_ci			if (!ret) {
364962306a36Sopenharmony_ci				++npolled;
365062306a36Sopenharmony_ci				cq_new_cqe = true;
365162306a36Sopenharmony_ci				continue;
365262306a36Sopenharmony_ci			}
365362306a36Sopenharmony_ci			if (ret == -ENOENT)
365462306a36Sopenharmony_ci				break;
365562306a36Sopenharmony_ci			 /* QP using the CQ is destroyed. Skip reporting this CQE */
365662306a36Sopenharmony_ci			if (ret == -EFAULT) {
365762306a36Sopenharmony_ci				cq_new_cqe = true;
365862306a36Sopenharmony_ci				continue;
365962306a36Sopenharmony_ci			}
366062306a36Sopenharmony_ci			goto error;
366162306a36Sopenharmony_ci		}
366262306a36Sopenharmony_ci
366362306a36Sopenharmony_ci		/* save the resized CQ buffer which received the last cqe */
366462306a36Sopenharmony_ci		if (cq_new_cqe)
366562306a36Sopenharmony_ci			last_buf = cq_buf;
366662306a36Sopenharmony_ci		cq_new_cqe = false;
366762306a36Sopenharmony_ci	}
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci	/* check the current CQ for new cqes */
367062306a36Sopenharmony_ci	while (npolled < num_entries) {
367162306a36Sopenharmony_ci		ret = irdma_poll_one(ukcq, cur_cqe, entry + npolled);
367262306a36Sopenharmony_ci		if (ret == -ENOENT) {
367362306a36Sopenharmony_ci			ret = irdma_generated_cmpls(iwcq, cur_cqe);
367462306a36Sopenharmony_ci			if (!ret)
367562306a36Sopenharmony_ci				irdma_process_cqe(entry + npolled, cur_cqe);
367662306a36Sopenharmony_ci		}
367762306a36Sopenharmony_ci		if (!ret) {
367862306a36Sopenharmony_ci			++npolled;
367962306a36Sopenharmony_ci			cq_new_cqe = true;
368062306a36Sopenharmony_ci			continue;
368162306a36Sopenharmony_ci		}
368262306a36Sopenharmony_ci
368362306a36Sopenharmony_ci		if (ret == -ENOENT)
368462306a36Sopenharmony_ci			break;
368562306a36Sopenharmony_ci		/* QP using the CQ is destroyed. Skip reporting this CQE */
368662306a36Sopenharmony_ci		if (ret == -EFAULT) {
368762306a36Sopenharmony_ci			cq_new_cqe = true;
368862306a36Sopenharmony_ci			continue;
368962306a36Sopenharmony_ci		}
369062306a36Sopenharmony_ci		goto error;
369162306a36Sopenharmony_ci	}
369262306a36Sopenharmony_ci
369362306a36Sopenharmony_ci	if (cq_new_cqe)
369462306a36Sopenharmony_ci		/* all previous CQ resizes are complete */
369562306a36Sopenharmony_ci		resized_bufs = irdma_process_resize_list(iwcq, iwdev, NULL);
369662306a36Sopenharmony_ci	else if (last_buf)
369762306a36Sopenharmony_ci		/* only CQ resizes up to the last_buf are complete */
369862306a36Sopenharmony_ci		resized_bufs = irdma_process_resize_list(iwcq, iwdev, last_buf);
369962306a36Sopenharmony_ci	if (resized_bufs)
370062306a36Sopenharmony_ci		/* report to the HW the number of complete CQ resizes */
370162306a36Sopenharmony_ci		irdma_uk_cq_set_resized_cnt(ukcq, resized_bufs);
370262306a36Sopenharmony_ci
370362306a36Sopenharmony_ci	return npolled;
370462306a36Sopenharmony_cierror:
370562306a36Sopenharmony_ci	ibdev_dbg(&iwdev->ibdev, "%s: Error polling CQ, irdma_err: %d\n",
370662306a36Sopenharmony_ci		  __func__, ret);
370762306a36Sopenharmony_ci
370862306a36Sopenharmony_ci	return ret;
370962306a36Sopenharmony_ci}
371062306a36Sopenharmony_ci
371162306a36Sopenharmony_ci/**
371262306a36Sopenharmony_ci * irdma_poll_cq - poll cq for completion (kernel apps)
371362306a36Sopenharmony_ci * @ibcq: cq to poll
371462306a36Sopenharmony_ci * @num_entries: number of entries to poll
371562306a36Sopenharmony_ci * @entry: wr of a completed entry
371662306a36Sopenharmony_ci */
371762306a36Sopenharmony_cistatic int irdma_poll_cq(struct ib_cq *ibcq, int num_entries,
371862306a36Sopenharmony_ci			 struct ib_wc *entry)
371962306a36Sopenharmony_ci{
372062306a36Sopenharmony_ci	struct irdma_cq *iwcq;
372162306a36Sopenharmony_ci	unsigned long flags;
372262306a36Sopenharmony_ci	int ret;
372362306a36Sopenharmony_ci
372462306a36Sopenharmony_ci	iwcq = to_iwcq(ibcq);
372562306a36Sopenharmony_ci
372662306a36Sopenharmony_ci	spin_lock_irqsave(&iwcq->lock, flags);
372762306a36Sopenharmony_ci	ret = __irdma_poll_cq(iwcq, num_entries, entry);
372862306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwcq->lock, flags);
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_ci	return ret;
373162306a36Sopenharmony_ci}
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci/**
373462306a36Sopenharmony_ci * irdma_req_notify_cq - arm cq kernel application
373562306a36Sopenharmony_ci * @ibcq: cq to arm
373662306a36Sopenharmony_ci * @notify_flags: notofication flags
373762306a36Sopenharmony_ci */
373862306a36Sopenharmony_cistatic int irdma_req_notify_cq(struct ib_cq *ibcq,
373962306a36Sopenharmony_ci			       enum ib_cq_notify_flags notify_flags)
374062306a36Sopenharmony_ci{
374162306a36Sopenharmony_ci	struct irdma_cq *iwcq;
374262306a36Sopenharmony_ci	struct irdma_cq_uk *ukcq;
374362306a36Sopenharmony_ci	unsigned long flags;
374462306a36Sopenharmony_ci	enum irdma_cmpl_notify cq_notify;
374562306a36Sopenharmony_ci	bool promo_event = false;
374662306a36Sopenharmony_ci	int ret = 0;
374762306a36Sopenharmony_ci
374862306a36Sopenharmony_ci	cq_notify = notify_flags == IB_CQ_SOLICITED ?
374962306a36Sopenharmony_ci		    IRDMA_CQ_COMPL_SOLICITED : IRDMA_CQ_COMPL_EVENT;
375062306a36Sopenharmony_ci	iwcq = to_iwcq(ibcq);
375162306a36Sopenharmony_ci	ukcq = &iwcq->sc_cq.cq_uk;
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci	spin_lock_irqsave(&iwcq->lock, flags);
375462306a36Sopenharmony_ci	/* Only promote to arm the CQ for any event if the last arm event was solicited. */
375562306a36Sopenharmony_ci	if (iwcq->last_notify == IRDMA_CQ_COMPL_SOLICITED && notify_flags != IB_CQ_SOLICITED)
375662306a36Sopenharmony_ci		promo_event = true;
375762306a36Sopenharmony_ci
375862306a36Sopenharmony_ci	if (!atomic_cmpxchg(&iwcq->armed, 0, 1) || promo_event) {
375962306a36Sopenharmony_ci		iwcq->last_notify = cq_notify;
376062306a36Sopenharmony_ci		irdma_uk_cq_request_notification(ukcq, cq_notify);
376162306a36Sopenharmony_ci	}
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_ci	if ((notify_flags & IB_CQ_REPORT_MISSED_EVENTS) &&
376462306a36Sopenharmony_ci	    (!irdma_cq_empty(iwcq) || !list_empty(&iwcq->cmpl_generated)))
376562306a36Sopenharmony_ci		ret = 1;
376662306a36Sopenharmony_ci	spin_unlock_irqrestore(&iwcq->lock, flags);
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_ci	return ret;
376962306a36Sopenharmony_ci}
377062306a36Sopenharmony_ci
377162306a36Sopenharmony_cistatic int irdma_roce_port_immutable(struct ib_device *ibdev, u32 port_num,
377262306a36Sopenharmony_ci				     struct ib_port_immutable *immutable)
377362306a36Sopenharmony_ci{
377462306a36Sopenharmony_ci	struct ib_port_attr attr;
377562306a36Sopenharmony_ci	int err;
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ci	immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP;
377862306a36Sopenharmony_ci	err = ib_query_port(ibdev, port_num, &attr);
377962306a36Sopenharmony_ci	if (err)
378062306a36Sopenharmony_ci		return err;
378162306a36Sopenharmony_ci
378262306a36Sopenharmony_ci	immutable->max_mad_size = IB_MGMT_MAD_SIZE;
378362306a36Sopenharmony_ci	immutable->pkey_tbl_len = attr.pkey_tbl_len;
378462306a36Sopenharmony_ci	immutable->gid_tbl_len = attr.gid_tbl_len;
378562306a36Sopenharmony_ci
378662306a36Sopenharmony_ci	return 0;
378762306a36Sopenharmony_ci}
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_cistatic int irdma_iw_port_immutable(struct ib_device *ibdev, u32 port_num,
379062306a36Sopenharmony_ci				   struct ib_port_immutable *immutable)
379162306a36Sopenharmony_ci{
379262306a36Sopenharmony_ci	struct ib_port_attr attr;
379362306a36Sopenharmony_ci	int err;
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci	immutable->core_cap_flags = RDMA_CORE_PORT_IWARP;
379662306a36Sopenharmony_ci	err = ib_query_port(ibdev, port_num, &attr);
379762306a36Sopenharmony_ci	if (err)
379862306a36Sopenharmony_ci		return err;
379962306a36Sopenharmony_ci	immutable->gid_tbl_len = attr.gid_tbl_len;
380062306a36Sopenharmony_ci
380162306a36Sopenharmony_ci	return 0;
380262306a36Sopenharmony_ci}
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_cistatic const struct rdma_stat_desc irdma_hw_stat_names[] = {
380562306a36Sopenharmony_ci	/* gen1 - 32-bit */
380662306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4RXDISCARD].name		= "ip4InDiscards",
380762306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4RXTRUNC].name		= "ip4InTruncatedPkts",
380862306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4TXNOROUTE].name		= "ip4OutNoRoutes",
380962306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6RXDISCARD].name		= "ip6InDiscards",
381062306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6RXTRUNC].name		= "ip6InTruncatedPkts",
381162306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6TXNOROUTE].name		= "ip6OutNoRoutes",
381262306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_TCPRTXSEG].name		= "tcpRetransSegs",
381362306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_TCPRXOPTERR].name		= "tcpInOptErrors",
381462306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_TCPRXPROTOERR].name	= "tcpInProtoErrors",
381562306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_RXVLANERR].name		= "rxVlanErrors",
381662306a36Sopenharmony_ci	/* gen1 - 64-bit */
381762306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4RXOCTS].name		= "ip4InOctets",
381862306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4RXPKTS].name		= "ip4InPkts",
381962306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4RXFRAGS].name		= "ip4InReasmRqd",
382062306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4RXMCPKTS].name		= "ip4InMcastPkts",
382162306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4TXOCTS].name		= "ip4OutOctets",
382262306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4TXPKTS].name		= "ip4OutPkts",
382362306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4TXFRAGS].name		= "ip4OutSegRqd",
382462306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4TXMCPKTS].name		= "ip4OutMcastPkts",
382562306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6RXOCTS].name		= "ip6InOctets",
382662306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6RXPKTS].name		= "ip6InPkts",
382762306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6RXFRAGS].name		= "ip6InReasmRqd",
382862306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6RXMCPKTS].name		= "ip6InMcastPkts",
382962306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6TXOCTS].name		= "ip6OutOctets",
383062306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6TXPKTS].name		= "ip6OutPkts",
383162306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6TXFRAGS].name		= "ip6OutSegRqd",
383262306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6TXMCPKTS].name		= "ip6OutMcastPkts",
383362306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_TCPRXSEGS].name		= "tcpInSegs",
383462306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_TCPTXSEG].name		= "tcpOutSegs",
383562306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_RDMARXRDS].name		= "iwInRdmaReads",
383662306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_RDMARXSNDS].name		= "iwInRdmaSends",
383762306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_RDMARXWRS].name		= "iwInRdmaWrites",
383862306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_RDMATXRDS].name		= "iwOutRdmaReads",
383962306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_RDMATXSNDS].name		= "iwOutRdmaSends",
384062306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_RDMATXWRS].name		= "iwOutRdmaWrites",
384162306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_RDMAVBND].name		= "iwRdmaBnd",
384262306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_RDMAVINV].name		= "iwRdmaInv",
384362306a36Sopenharmony_ci
384462306a36Sopenharmony_ci	/* gen2 - 32-bit */
384562306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_RXRPCNPHANDLED].name	= "cnpHandled",
384662306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_RXRPCNPIGNORED].name	= "cnpIgnored",
384762306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_TXNPCNPSENT].name		= "cnpSent",
384862306a36Sopenharmony_ci	/* gen2 - 64-bit */
384962306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4RXMCOCTS].name		= "ip4InMcastOctets",
385062306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP4TXMCOCTS].name		= "ip4OutMcastOctets",
385162306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6RXMCOCTS].name		= "ip6InMcastOctets",
385262306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_IP6TXMCOCTS].name		= "ip6OutMcastOctets",
385362306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_UDPRXPKTS].name		= "RxUDP",
385462306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_UDPTXPKTS].name		= "TxUDP",
385562306a36Sopenharmony_ci	[IRDMA_HW_STAT_INDEX_RXNPECNMARKEDPKTS].name	= "RxECNMrkd",
385662306a36Sopenharmony_ci
385762306a36Sopenharmony_ci};
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_cistatic void irdma_get_dev_fw_str(struct ib_device *dev, char *str)
386062306a36Sopenharmony_ci{
386162306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(dev);
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_ci	snprintf(str, IB_FW_VERSION_NAME_MAX, "%u.%u",
386462306a36Sopenharmony_ci		 irdma_fw_major_ver(&iwdev->rf->sc_dev),
386562306a36Sopenharmony_ci		 irdma_fw_minor_ver(&iwdev->rf->sc_dev));
386662306a36Sopenharmony_ci}
386762306a36Sopenharmony_ci
386862306a36Sopenharmony_ci/**
386962306a36Sopenharmony_ci * irdma_alloc_hw_port_stats - Allocate a hw stats structure
387062306a36Sopenharmony_ci * @ibdev: device pointer from stack
387162306a36Sopenharmony_ci * @port_num: port number
387262306a36Sopenharmony_ci */
387362306a36Sopenharmony_cistatic struct rdma_hw_stats *irdma_alloc_hw_port_stats(struct ib_device *ibdev,
387462306a36Sopenharmony_ci						       u32 port_num)
387562306a36Sopenharmony_ci{
387662306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibdev);
387762306a36Sopenharmony_ci	struct irdma_sc_dev *dev = &iwdev->rf->sc_dev;
387862306a36Sopenharmony_ci
387962306a36Sopenharmony_ci	int num_counters = dev->hw_attrs.max_stat_idx;
388062306a36Sopenharmony_ci	unsigned long lifespan = RDMA_HW_STATS_DEFAULT_LIFESPAN;
388162306a36Sopenharmony_ci
388262306a36Sopenharmony_ci	return rdma_alloc_hw_stats_struct(irdma_hw_stat_names, num_counters,
388362306a36Sopenharmony_ci					  lifespan);
388462306a36Sopenharmony_ci}
388562306a36Sopenharmony_ci
388662306a36Sopenharmony_ci/**
388762306a36Sopenharmony_ci * irdma_get_hw_stats - Populates the rdma_hw_stats structure
388862306a36Sopenharmony_ci * @ibdev: device pointer from stack
388962306a36Sopenharmony_ci * @stats: stats pointer from stack
389062306a36Sopenharmony_ci * @port_num: port number
389162306a36Sopenharmony_ci * @index: which hw counter the stack is requesting we update
389262306a36Sopenharmony_ci */
389362306a36Sopenharmony_cistatic int irdma_get_hw_stats(struct ib_device *ibdev,
389462306a36Sopenharmony_ci			      struct rdma_hw_stats *stats, u32 port_num,
389562306a36Sopenharmony_ci			      int index)
389662306a36Sopenharmony_ci{
389762306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibdev);
389862306a36Sopenharmony_ci	struct irdma_dev_hw_stats *hw_stats = &iwdev->vsi.pestat->hw_stats;
389962306a36Sopenharmony_ci
390062306a36Sopenharmony_ci	if (iwdev->rf->rdma_ver >= IRDMA_GEN_2)
390162306a36Sopenharmony_ci		irdma_cqp_gather_stats_cmd(&iwdev->rf->sc_dev, iwdev->vsi.pestat, true);
390262306a36Sopenharmony_ci	else
390362306a36Sopenharmony_ci		irdma_cqp_gather_stats_gen1(&iwdev->rf->sc_dev, iwdev->vsi.pestat);
390462306a36Sopenharmony_ci
390562306a36Sopenharmony_ci	memcpy(&stats->value[0], hw_stats, sizeof(u64) * stats->num_counters);
390662306a36Sopenharmony_ci
390762306a36Sopenharmony_ci	return stats->num_counters;
390862306a36Sopenharmony_ci}
390962306a36Sopenharmony_ci
391062306a36Sopenharmony_ci/**
391162306a36Sopenharmony_ci * irdma_query_gid - Query port GID
391262306a36Sopenharmony_ci * @ibdev: device pointer from stack
391362306a36Sopenharmony_ci * @port: port number
391462306a36Sopenharmony_ci * @index: Entry index
391562306a36Sopenharmony_ci * @gid: Global ID
391662306a36Sopenharmony_ci */
391762306a36Sopenharmony_cistatic int irdma_query_gid(struct ib_device *ibdev, u32 port, int index,
391862306a36Sopenharmony_ci			   union ib_gid *gid)
391962306a36Sopenharmony_ci{
392062306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibdev);
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_ci	memset(gid->raw, 0, sizeof(gid->raw));
392362306a36Sopenharmony_ci	ether_addr_copy(gid->raw, iwdev->netdev->dev_addr);
392462306a36Sopenharmony_ci
392562306a36Sopenharmony_ci	return 0;
392662306a36Sopenharmony_ci}
392762306a36Sopenharmony_ci
392862306a36Sopenharmony_ci/**
392962306a36Sopenharmony_ci * mcast_list_add -  Add a new mcast item to list
393062306a36Sopenharmony_ci * @rf: RDMA PCI function
393162306a36Sopenharmony_ci * @new_elem: pointer to element to add
393262306a36Sopenharmony_ci */
393362306a36Sopenharmony_cistatic void mcast_list_add(struct irdma_pci_f *rf,
393462306a36Sopenharmony_ci			   struct mc_table_list *new_elem)
393562306a36Sopenharmony_ci{
393662306a36Sopenharmony_ci	list_add(&new_elem->list, &rf->mc_qht_list.list);
393762306a36Sopenharmony_ci}
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci/**
394062306a36Sopenharmony_ci * mcast_list_del - Remove an mcast item from list
394162306a36Sopenharmony_ci * @mc_qht_elem: pointer to mcast table list element
394262306a36Sopenharmony_ci */
394362306a36Sopenharmony_cistatic void mcast_list_del(struct mc_table_list *mc_qht_elem)
394462306a36Sopenharmony_ci{
394562306a36Sopenharmony_ci	if (mc_qht_elem)
394662306a36Sopenharmony_ci		list_del(&mc_qht_elem->list);
394762306a36Sopenharmony_ci}
394862306a36Sopenharmony_ci
394962306a36Sopenharmony_ci/**
395062306a36Sopenharmony_ci * mcast_list_lookup_ip - Search mcast list for address
395162306a36Sopenharmony_ci * @rf: RDMA PCI function
395262306a36Sopenharmony_ci * @ip_mcast: pointer to mcast IP address
395362306a36Sopenharmony_ci */
395462306a36Sopenharmony_cistatic struct mc_table_list *mcast_list_lookup_ip(struct irdma_pci_f *rf,
395562306a36Sopenharmony_ci						  u32 *ip_mcast)
395662306a36Sopenharmony_ci{
395762306a36Sopenharmony_ci	struct mc_table_list *mc_qht_el;
395862306a36Sopenharmony_ci	struct list_head *pos, *q;
395962306a36Sopenharmony_ci
396062306a36Sopenharmony_ci	list_for_each_safe (pos, q, &rf->mc_qht_list.list) {
396162306a36Sopenharmony_ci		mc_qht_el = list_entry(pos, struct mc_table_list, list);
396262306a36Sopenharmony_ci		if (!memcmp(mc_qht_el->mc_info.dest_ip, ip_mcast,
396362306a36Sopenharmony_ci			    sizeof(mc_qht_el->mc_info.dest_ip)))
396462306a36Sopenharmony_ci			return mc_qht_el;
396562306a36Sopenharmony_ci	}
396662306a36Sopenharmony_ci
396762306a36Sopenharmony_ci	return NULL;
396862306a36Sopenharmony_ci}
396962306a36Sopenharmony_ci
397062306a36Sopenharmony_ci/**
397162306a36Sopenharmony_ci * irdma_mcast_cqp_op - perform a mcast cqp operation
397262306a36Sopenharmony_ci * @iwdev: irdma device
397362306a36Sopenharmony_ci * @mc_grp_ctx: mcast group info
397462306a36Sopenharmony_ci * @op: operation
397562306a36Sopenharmony_ci *
397662306a36Sopenharmony_ci * returns error status
397762306a36Sopenharmony_ci */
397862306a36Sopenharmony_cistatic int irdma_mcast_cqp_op(struct irdma_device *iwdev,
397962306a36Sopenharmony_ci			      struct irdma_mcast_grp_info *mc_grp_ctx, u8 op)
398062306a36Sopenharmony_ci{
398162306a36Sopenharmony_ci	struct cqp_cmds_info *cqp_info;
398262306a36Sopenharmony_ci	struct irdma_cqp_request *cqp_request;
398362306a36Sopenharmony_ci	int status;
398462306a36Sopenharmony_ci
398562306a36Sopenharmony_ci	cqp_request = irdma_alloc_and_get_cqp_request(&iwdev->rf->cqp, true);
398662306a36Sopenharmony_ci	if (!cqp_request)
398762306a36Sopenharmony_ci		return -ENOMEM;
398862306a36Sopenharmony_ci
398962306a36Sopenharmony_ci	cqp_request->info.in.u.mc_create.info = *mc_grp_ctx;
399062306a36Sopenharmony_ci	cqp_info = &cqp_request->info;
399162306a36Sopenharmony_ci	cqp_info->cqp_cmd = op;
399262306a36Sopenharmony_ci	cqp_info->post_sq = 1;
399362306a36Sopenharmony_ci	cqp_info->in.u.mc_create.scratch = (uintptr_t)cqp_request;
399462306a36Sopenharmony_ci	cqp_info->in.u.mc_create.cqp = &iwdev->rf->cqp.sc_cqp;
399562306a36Sopenharmony_ci	status = irdma_handle_cqp_op(iwdev->rf, cqp_request);
399662306a36Sopenharmony_ci	irdma_put_cqp_request(&iwdev->rf->cqp, cqp_request);
399762306a36Sopenharmony_ci
399862306a36Sopenharmony_ci	return status;
399962306a36Sopenharmony_ci}
400062306a36Sopenharmony_ci
400162306a36Sopenharmony_ci/**
400262306a36Sopenharmony_ci * irdma_mcast_mac - Get the multicast MAC for an IP address
400362306a36Sopenharmony_ci * @ip_addr: IPv4 or IPv6 address
400462306a36Sopenharmony_ci * @mac: pointer to result MAC address
400562306a36Sopenharmony_ci * @ipv4: flag indicating IPv4 or IPv6
400662306a36Sopenharmony_ci *
400762306a36Sopenharmony_ci */
400862306a36Sopenharmony_civoid irdma_mcast_mac(u32 *ip_addr, u8 *mac, bool ipv4)
400962306a36Sopenharmony_ci{
401062306a36Sopenharmony_ci	u8 *ip = (u8 *)ip_addr;
401162306a36Sopenharmony_ci
401262306a36Sopenharmony_ci	if (ipv4) {
401362306a36Sopenharmony_ci		unsigned char mac4[ETH_ALEN] = {0x01, 0x00, 0x5E, 0x00,
401462306a36Sopenharmony_ci						0x00, 0x00};
401562306a36Sopenharmony_ci
401662306a36Sopenharmony_ci		mac4[3] = ip[2] & 0x7F;
401762306a36Sopenharmony_ci		mac4[4] = ip[1];
401862306a36Sopenharmony_ci		mac4[5] = ip[0];
401962306a36Sopenharmony_ci		ether_addr_copy(mac, mac4);
402062306a36Sopenharmony_ci	} else {
402162306a36Sopenharmony_ci		unsigned char mac6[ETH_ALEN] = {0x33, 0x33, 0x00, 0x00,
402262306a36Sopenharmony_ci						0x00, 0x00};
402362306a36Sopenharmony_ci
402462306a36Sopenharmony_ci		mac6[2] = ip[3];
402562306a36Sopenharmony_ci		mac6[3] = ip[2];
402662306a36Sopenharmony_ci		mac6[4] = ip[1];
402762306a36Sopenharmony_ci		mac6[5] = ip[0];
402862306a36Sopenharmony_ci		ether_addr_copy(mac, mac6);
402962306a36Sopenharmony_ci	}
403062306a36Sopenharmony_ci}
403162306a36Sopenharmony_ci
403262306a36Sopenharmony_ci/**
403362306a36Sopenharmony_ci * irdma_attach_mcast - attach a qp to a multicast group
403462306a36Sopenharmony_ci * @ibqp: ptr to qp
403562306a36Sopenharmony_ci * @ibgid: pointer to global ID
403662306a36Sopenharmony_ci * @lid: local ID
403762306a36Sopenharmony_ci *
403862306a36Sopenharmony_ci * returns error status
403962306a36Sopenharmony_ci */
404062306a36Sopenharmony_cistatic int irdma_attach_mcast(struct ib_qp *ibqp, union ib_gid *ibgid, u16 lid)
404162306a36Sopenharmony_ci{
404262306a36Sopenharmony_ci	struct irdma_qp *iwqp = to_iwqp(ibqp);
404362306a36Sopenharmony_ci	struct irdma_device *iwdev = iwqp->iwdev;
404462306a36Sopenharmony_ci	struct irdma_pci_f *rf = iwdev->rf;
404562306a36Sopenharmony_ci	struct mc_table_list *mc_qht_elem;
404662306a36Sopenharmony_ci	struct irdma_mcast_grp_ctx_entry_info mcg_info = {};
404762306a36Sopenharmony_ci	unsigned long flags;
404862306a36Sopenharmony_ci	u32 ip_addr[4] = {};
404962306a36Sopenharmony_ci	u32 mgn;
405062306a36Sopenharmony_ci	u32 no_mgs;
405162306a36Sopenharmony_ci	int ret = 0;
405262306a36Sopenharmony_ci	bool ipv4;
405362306a36Sopenharmony_ci	u16 vlan_id;
405462306a36Sopenharmony_ci	union irdma_sockaddr sgid_addr;
405562306a36Sopenharmony_ci	unsigned char dmac[ETH_ALEN];
405662306a36Sopenharmony_ci
405762306a36Sopenharmony_ci	rdma_gid2ip((struct sockaddr *)&sgid_addr, ibgid);
405862306a36Sopenharmony_ci
405962306a36Sopenharmony_ci	if (!ipv6_addr_v4mapped((struct in6_addr *)ibgid)) {
406062306a36Sopenharmony_ci		irdma_copy_ip_ntohl(ip_addr,
406162306a36Sopenharmony_ci				    sgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32);
406262306a36Sopenharmony_ci		irdma_get_vlan_mac_ipv6(ip_addr, &vlan_id, NULL);
406362306a36Sopenharmony_ci		ipv4 = false;
406462306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev,
406562306a36Sopenharmony_ci			  "VERBS: qp_id=%d, IP6address=%pI6\n", ibqp->qp_num,
406662306a36Sopenharmony_ci			  ip_addr);
406762306a36Sopenharmony_ci		irdma_mcast_mac(ip_addr, dmac, false);
406862306a36Sopenharmony_ci	} else {
406962306a36Sopenharmony_ci		ip_addr[0] = ntohl(sgid_addr.saddr_in.sin_addr.s_addr);
407062306a36Sopenharmony_ci		ipv4 = true;
407162306a36Sopenharmony_ci		vlan_id = irdma_get_vlan_ipv4(ip_addr);
407262306a36Sopenharmony_ci		irdma_mcast_mac(ip_addr, dmac, true);
407362306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev,
407462306a36Sopenharmony_ci			  "VERBS: qp_id=%d, IP4address=%pI4, MAC=%pM\n",
407562306a36Sopenharmony_ci			  ibqp->qp_num, ip_addr, dmac);
407662306a36Sopenharmony_ci	}
407762306a36Sopenharmony_ci
407862306a36Sopenharmony_ci	spin_lock_irqsave(&rf->qh_list_lock, flags);
407962306a36Sopenharmony_ci	mc_qht_elem = mcast_list_lookup_ip(rf, ip_addr);
408062306a36Sopenharmony_ci	if (!mc_qht_elem) {
408162306a36Sopenharmony_ci		struct irdma_dma_mem *dma_mem_mc;
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_ci		spin_unlock_irqrestore(&rf->qh_list_lock, flags);
408462306a36Sopenharmony_ci		mc_qht_elem = kzalloc(sizeof(*mc_qht_elem), GFP_KERNEL);
408562306a36Sopenharmony_ci		if (!mc_qht_elem)
408662306a36Sopenharmony_ci			return -ENOMEM;
408762306a36Sopenharmony_ci
408862306a36Sopenharmony_ci		mc_qht_elem->mc_info.ipv4_valid = ipv4;
408962306a36Sopenharmony_ci		memcpy(mc_qht_elem->mc_info.dest_ip, ip_addr,
409062306a36Sopenharmony_ci		       sizeof(mc_qht_elem->mc_info.dest_ip));
409162306a36Sopenharmony_ci		ret = irdma_alloc_rsrc(rf, rf->allocated_mcgs, rf->max_mcg,
409262306a36Sopenharmony_ci				       &mgn, &rf->next_mcg);
409362306a36Sopenharmony_ci		if (ret) {
409462306a36Sopenharmony_ci			kfree(mc_qht_elem);
409562306a36Sopenharmony_ci			return -ENOMEM;
409662306a36Sopenharmony_ci		}
409762306a36Sopenharmony_ci
409862306a36Sopenharmony_ci		mc_qht_elem->mc_info.mgn = mgn;
409962306a36Sopenharmony_ci		dma_mem_mc = &mc_qht_elem->mc_grp_ctx.dma_mem_mc;
410062306a36Sopenharmony_ci		dma_mem_mc->size = ALIGN(sizeof(u64) * IRDMA_MAX_MGS_PER_CTX,
410162306a36Sopenharmony_ci					 IRDMA_HW_PAGE_SIZE);
410262306a36Sopenharmony_ci		dma_mem_mc->va = dma_alloc_coherent(rf->hw.device,
410362306a36Sopenharmony_ci						    dma_mem_mc->size,
410462306a36Sopenharmony_ci						    &dma_mem_mc->pa,
410562306a36Sopenharmony_ci						    GFP_KERNEL);
410662306a36Sopenharmony_ci		if (!dma_mem_mc->va) {
410762306a36Sopenharmony_ci			irdma_free_rsrc(rf, rf->allocated_mcgs, mgn);
410862306a36Sopenharmony_ci			kfree(mc_qht_elem);
410962306a36Sopenharmony_ci			return -ENOMEM;
411062306a36Sopenharmony_ci		}
411162306a36Sopenharmony_ci
411262306a36Sopenharmony_ci		mc_qht_elem->mc_grp_ctx.mg_id = (u16)mgn;
411362306a36Sopenharmony_ci		memcpy(mc_qht_elem->mc_grp_ctx.dest_ip_addr, ip_addr,
411462306a36Sopenharmony_ci		       sizeof(mc_qht_elem->mc_grp_ctx.dest_ip_addr));
411562306a36Sopenharmony_ci		mc_qht_elem->mc_grp_ctx.ipv4_valid = ipv4;
411662306a36Sopenharmony_ci		mc_qht_elem->mc_grp_ctx.vlan_id = vlan_id;
411762306a36Sopenharmony_ci		if (vlan_id < VLAN_N_VID)
411862306a36Sopenharmony_ci			mc_qht_elem->mc_grp_ctx.vlan_valid = true;
411962306a36Sopenharmony_ci		mc_qht_elem->mc_grp_ctx.hmc_fcn_id = iwdev->rf->sc_dev.hmc_fn_id;
412062306a36Sopenharmony_ci		mc_qht_elem->mc_grp_ctx.qs_handle =
412162306a36Sopenharmony_ci			iwqp->sc_qp.vsi->qos[iwqp->sc_qp.user_pri].qs_handle;
412262306a36Sopenharmony_ci		ether_addr_copy(mc_qht_elem->mc_grp_ctx.dest_mac_addr, dmac);
412362306a36Sopenharmony_ci
412462306a36Sopenharmony_ci		spin_lock_irqsave(&rf->qh_list_lock, flags);
412562306a36Sopenharmony_ci		mcast_list_add(rf, mc_qht_elem);
412662306a36Sopenharmony_ci	} else {
412762306a36Sopenharmony_ci		if (mc_qht_elem->mc_grp_ctx.no_of_mgs ==
412862306a36Sopenharmony_ci		    IRDMA_MAX_MGS_PER_CTX) {
412962306a36Sopenharmony_ci			spin_unlock_irqrestore(&rf->qh_list_lock, flags);
413062306a36Sopenharmony_ci			return -ENOMEM;
413162306a36Sopenharmony_ci		}
413262306a36Sopenharmony_ci	}
413362306a36Sopenharmony_ci
413462306a36Sopenharmony_ci	mcg_info.qp_id = iwqp->ibqp.qp_num;
413562306a36Sopenharmony_ci	no_mgs = mc_qht_elem->mc_grp_ctx.no_of_mgs;
413662306a36Sopenharmony_ci	irdma_sc_add_mcast_grp(&mc_qht_elem->mc_grp_ctx, &mcg_info);
413762306a36Sopenharmony_ci	spin_unlock_irqrestore(&rf->qh_list_lock, flags);
413862306a36Sopenharmony_ci
413962306a36Sopenharmony_ci	/* Only if there is a change do we need to modify or create */
414062306a36Sopenharmony_ci	if (!no_mgs) {
414162306a36Sopenharmony_ci		ret = irdma_mcast_cqp_op(iwdev, &mc_qht_elem->mc_grp_ctx,
414262306a36Sopenharmony_ci					 IRDMA_OP_MC_CREATE);
414362306a36Sopenharmony_ci	} else if (no_mgs != mc_qht_elem->mc_grp_ctx.no_of_mgs) {
414462306a36Sopenharmony_ci		ret = irdma_mcast_cqp_op(iwdev, &mc_qht_elem->mc_grp_ctx,
414562306a36Sopenharmony_ci					 IRDMA_OP_MC_MODIFY);
414662306a36Sopenharmony_ci	} else {
414762306a36Sopenharmony_ci		return 0;
414862306a36Sopenharmony_ci	}
414962306a36Sopenharmony_ci
415062306a36Sopenharmony_ci	if (ret)
415162306a36Sopenharmony_ci		goto error;
415262306a36Sopenharmony_ci
415362306a36Sopenharmony_ci	return 0;
415462306a36Sopenharmony_ci
415562306a36Sopenharmony_cierror:
415662306a36Sopenharmony_ci	irdma_sc_del_mcast_grp(&mc_qht_elem->mc_grp_ctx, &mcg_info);
415762306a36Sopenharmony_ci	if (!mc_qht_elem->mc_grp_ctx.no_of_mgs) {
415862306a36Sopenharmony_ci		mcast_list_del(mc_qht_elem);
415962306a36Sopenharmony_ci		dma_free_coherent(rf->hw.device,
416062306a36Sopenharmony_ci				  mc_qht_elem->mc_grp_ctx.dma_mem_mc.size,
416162306a36Sopenharmony_ci				  mc_qht_elem->mc_grp_ctx.dma_mem_mc.va,
416262306a36Sopenharmony_ci				  mc_qht_elem->mc_grp_ctx.dma_mem_mc.pa);
416362306a36Sopenharmony_ci		mc_qht_elem->mc_grp_ctx.dma_mem_mc.va = NULL;
416462306a36Sopenharmony_ci		irdma_free_rsrc(rf, rf->allocated_mcgs,
416562306a36Sopenharmony_ci				mc_qht_elem->mc_grp_ctx.mg_id);
416662306a36Sopenharmony_ci		kfree(mc_qht_elem);
416762306a36Sopenharmony_ci	}
416862306a36Sopenharmony_ci
416962306a36Sopenharmony_ci	return ret;
417062306a36Sopenharmony_ci}
417162306a36Sopenharmony_ci
417262306a36Sopenharmony_ci/**
417362306a36Sopenharmony_ci * irdma_detach_mcast - detach a qp from a multicast group
417462306a36Sopenharmony_ci * @ibqp: ptr to qp
417562306a36Sopenharmony_ci * @ibgid: pointer to global ID
417662306a36Sopenharmony_ci * @lid: local ID
417762306a36Sopenharmony_ci *
417862306a36Sopenharmony_ci * returns error status
417962306a36Sopenharmony_ci */
418062306a36Sopenharmony_cistatic int irdma_detach_mcast(struct ib_qp *ibqp, union ib_gid *ibgid, u16 lid)
418162306a36Sopenharmony_ci{
418262306a36Sopenharmony_ci	struct irdma_qp *iwqp = to_iwqp(ibqp);
418362306a36Sopenharmony_ci	struct irdma_device *iwdev = iwqp->iwdev;
418462306a36Sopenharmony_ci	struct irdma_pci_f *rf = iwdev->rf;
418562306a36Sopenharmony_ci	u32 ip_addr[4] = {};
418662306a36Sopenharmony_ci	struct mc_table_list *mc_qht_elem;
418762306a36Sopenharmony_ci	struct irdma_mcast_grp_ctx_entry_info mcg_info = {};
418862306a36Sopenharmony_ci	int ret;
418962306a36Sopenharmony_ci	unsigned long flags;
419062306a36Sopenharmony_ci	union irdma_sockaddr sgid_addr;
419162306a36Sopenharmony_ci
419262306a36Sopenharmony_ci	rdma_gid2ip((struct sockaddr *)&sgid_addr, ibgid);
419362306a36Sopenharmony_ci	if (!ipv6_addr_v4mapped((struct in6_addr *)ibgid))
419462306a36Sopenharmony_ci		irdma_copy_ip_ntohl(ip_addr,
419562306a36Sopenharmony_ci				    sgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32);
419662306a36Sopenharmony_ci	else
419762306a36Sopenharmony_ci		ip_addr[0] = ntohl(sgid_addr.saddr_in.sin_addr.s_addr);
419862306a36Sopenharmony_ci
419962306a36Sopenharmony_ci	spin_lock_irqsave(&rf->qh_list_lock, flags);
420062306a36Sopenharmony_ci	mc_qht_elem = mcast_list_lookup_ip(rf, ip_addr);
420162306a36Sopenharmony_ci	if (!mc_qht_elem) {
420262306a36Sopenharmony_ci		spin_unlock_irqrestore(&rf->qh_list_lock, flags);
420362306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev,
420462306a36Sopenharmony_ci			  "VERBS: address not found MCG\n");
420562306a36Sopenharmony_ci		return 0;
420662306a36Sopenharmony_ci	}
420762306a36Sopenharmony_ci
420862306a36Sopenharmony_ci	mcg_info.qp_id = iwqp->ibqp.qp_num;
420962306a36Sopenharmony_ci	irdma_sc_del_mcast_grp(&mc_qht_elem->mc_grp_ctx, &mcg_info);
421062306a36Sopenharmony_ci	if (!mc_qht_elem->mc_grp_ctx.no_of_mgs) {
421162306a36Sopenharmony_ci		mcast_list_del(mc_qht_elem);
421262306a36Sopenharmony_ci		spin_unlock_irqrestore(&rf->qh_list_lock, flags);
421362306a36Sopenharmony_ci		ret = irdma_mcast_cqp_op(iwdev, &mc_qht_elem->mc_grp_ctx,
421462306a36Sopenharmony_ci					 IRDMA_OP_MC_DESTROY);
421562306a36Sopenharmony_ci		if (ret) {
421662306a36Sopenharmony_ci			ibdev_dbg(&iwdev->ibdev,
421762306a36Sopenharmony_ci				  "VERBS: failed MC_DESTROY MCG\n");
421862306a36Sopenharmony_ci			spin_lock_irqsave(&rf->qh_list_lock, flags);
421962306a36Sopenharmony_ci			mcast_list_add(rf, mc_qht_elem);
422062306a36Sopenharmony_ci			spin_unlock_irqrestore(&rf->qh_list_lock, flags);
422162306a36Sopenharmony_ci			return -EAGAIN;
422262306a36Sopenharmony_ci		}
422362306a36Sopenharmony_ci
422462306a36Sopenharmony_ci		dma_free_coherent(rf->hw.device,
422562306a36Sopenharmony_ci				  mc_qht_elem->mc_grp_ctx.dma_mem_mc.size,
422662306a36Sopenharmony_ci				  mc_qht_elem->mc_grp_ctx.dma_mem_mc.va,
422762306a36Sopenharmony_ci				  mc_qht_elem->mc_grp_ctx.dma_mem_mc.pa);
422862306a36Sopenharmony_ci		mc_qht_elem->mc_grp_ctx.dma_mem_mc.va = NULL;
422962306a36Sopenharmony_ci		irdma_free_rsrc(rf, rf->allocated_mcgs,
423062306a36Sopenharmony_ci				mc_qht_elem->mc_grp_ctx.mg_id);
423162306a36Sopenharmony_ci		kfree(mc_qht_elem);
423262306a36Sopenharmony_ci	} else {
423362306a36Sopenharmony_ci		spin_unlock_irqrestore(&rf->qh_list_lock, flags);
423462306a36Sopenharmony_ci		ret = irdma_mcast_cqp_op(iwdev, &mc_qht_elem->mc_grp_ctx,
423562306a36Sopenharmony_ci					 IRDMA_OP_MC_MODIFY);
423662306a36Sopenharmony_ci		if (ret) {
423762306a36Sopenharmony_ci			ibdev_dbg(&iwdev->ibdev,
423862306a36Sopenharmony_ci				  "VERBS: failed Modify MCG\n");
423962306a36Sopenharmony_ci			return ret;
424062306a36Sopenharmony_ci		}
424162306a36Sopenharmony_ci	}
424262306a36Sopenharmony_ci
424362306a36Sopenharmony_ci	return 0;
424462306a36Sopenharmony_ci}
424562306a36Sopenharmony_ci
424662306a36Sopenharmony_cistatic int irdma_create_hw_ah(struct irdma_device *iwdev, struct irdma_ah *ah, bool sleep)
424762306a36Sopenharmony_ci{
424862306a36Sopenharmony_ci	struct irdma_pci_f *rf = iwdev->rf;
424962306a36Sopenharmony_ci	int err;
425062306a36Sopenharmony_ci
425162306a36Sopenharmony_ci	err = irdma_alloc_rsrc(rf, rf->allocated_ahs, rf->max_ah, &ah->sc_ah.ah_info.ah_idx,
425262306a36Sopenharmony_ci			       &rf->next_ah);
425362306a36Sopenharmony_ci	if (err)
425462306a36Sopenharmony_ci		return err;
425562306a36Sopenharmony_ci
425662306a36Sopenharmony_ci	err = irdma_ah_cqp_op(rf, &ah->sc_ah, IRDMA_OP_AH_CREATE, sleep,
425762306a36Sopenharmony_ci			      irdma_gsi_ud_qp_ah_cb, &ah->sc_ah);
425862306a36Sopenharmony_ci
425962306a36Sopenharmony_ci	if (err) {
426062306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev, "VERBS: CQP-OP Create AH fail");
426162306a36Sopenharmony_ci		goto err_ah_create;
426262306a36Sopenharmony_ci	}
426362306a36Sopenharmony_ci
426462306a36Sopenharmony_ci	if (!sleep) {
426562306a36Sopenharmony_ci		int cnt = CQP_COMPL_WAIT_TIME_MS * CQP_TIMEOUT_THRESHOLD;
426662306a36Sopenharmony_ci
426762306a36Sopenharmony_ci		do {
426862306a36Sopenharmony_ci			irdma_cqp_ce_handler(rf, &rf->ccq.sc_cq);
426962306a36Sopenharmony_ci			mdelay(1);
427062306a36Sopenharmony_ci		} while (!ah->sc_ah.ah_info.ah_valid && --cnt);
427162306a36Sopenharmony_ci
427262306a36Sopenharmony_ci		if (!cnt) {
427362306a36Sopenharmony_ci			ibdev_dbg(&iwdev->ibdev, "VERBS: CQP create AH timed out");
427462306a36Sopenharmony_ci			err = -ETIMEDOUT;
427562306a36Sopenharmony_ci			goto err_ah_create;
427662306a36Sopenharmony_ci		}
427762306a36Sopenharmony_ci	}
427862306a36Sopenharmony_ci	return 0;
427962306a36Sopenharmony_ci
428062306a36Sopenharmony_cierr_ah_create:
428162306a36Sopenharmony_ci	irdma_free_rsrc(iwdev->rf, iwdev->rf->allocated_ahs, ah->sc_ah.ah_info.ah_idx);
428262306a36Sopenharmony_ci
428362306a36Sopenharmony_ci	return err;
428462306a36Sopenharmony_ci}
428562306a36Sopenharmony_ci
428662306a36Sopenharmony_cistatic int irdma_setup_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *attr)
428762306a36Sopenharmony_ci{
428862306a36Sopenharmony_ci	struct irdma_pd *pd = to_iwpd(ibah->pd);
428962306a36Sopenharmony_ci	struct irdma_ah *ah = container_of(ibah, struct irdma_ah, ibah);
429062306a36Sopenharmony_ci	struct rdma_ah_attr *ah_attr = attr->ah_attr;
429162306a36Sopenharmony_ci	const struct ib_gid_attr *sgid_attr;
429262306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibah->pd->device);
429362306a36Sopenharmony_ci	struct irdma_pci_f *rf = iwdev->rf;
429462306a36Sopenharmony_ci	struct irdma_sc_ah *sc_ah;
429562306a36Sopenharmony_ci	struct irdma_ah_info *ah_info;
429662306a36Sopenharmony_ci	union irdma_sockaddr sgid_addr, dgid_addr;
429762306a36Sopenharmony_ci	int err;
429862306a36Sopenharmony_ci	u8 dmac[ETH_ALEN];
429962306a36Sopenharmony_ci
430062306a36Sopenharmony_ci	ah->pd = pd;
430162306a36Sopenharmony_ci	sc_ah = &ah->sc_ah;
430262306a36Sopenharmony_ci	sc_ah->ah_info.vsi = &iwdev->vsi;
430362306a36Sopenharmony_ci	irdma_sc_init_ah(&rf->sc_dev, sc_ah);
430462306a36Sopenharmony_ci	ah->sgid_index = ah_attr->grh.sgid_index;
430562306a36Sopenharmony_ci	sgid_attr = ah_attr->grh.sgid_attr;
430662306a36Sopenharmony_ci	memcpy(&ah->dgid, &ah_attr->grh.dgid, sizeof(ah->dgid));
430762306a36Sopenharmony_ci	rdma_gid2ip((struct sockaddr *)&sgid_addr, &sgid_attr->gid);
430862306a36Sopenharmony_ci	rdma_gid2ip((struct sockaddr *)&dgid_addr, &ah_attr->grh.dgid);
430962306a36Sopenharmony_ci	ah->av.attrs = *ah_attr;
431062306a36Sopenharmony_ci	ah->av.net_type = rdma_gid_attr_network_type(sgid_attr);
431162306a36Sopenharmony_ci	ah_info = &sc_ah->ah_info;
431262306a36Sopenharmony_ci	ah_info->pd_idx = pd->sc_pd.pd_id;
431362306a36Sopenharmony_ci	if (ah_attr->ah_flags & IB_AH_GRH) {
431462306a36Sopenharmony_ci		ah_info->flow_label = ah_attr->grh.flow_label;
431562306a36Sopenharmony_ci		ah_info->hop_ttl = ah_attr->grh.hop_limit;
431662306a36Sopenharmony_ci		ah_info->tc_tos = ah_attr->grh.traffic_class;
431762306a36Sopenharmony_ci	}
431862306a36Sopenharmony_ci
431962306a36Sopenharmony_ci	ether_addr_copy(dmac, ah_attr->roce.dmac);
432062306a36Sopenharmony_ci	if (ah->av.net_type == RDMA_NETWORK_IPV4) {
432162306a36Sopenharmony_ci		ah_info->ipv4_valid = true;
432262306a36Sopenharmony_ci		ah_info->dest_ip_addr[0] =
432362306a36Sopenharmony_ci			ntohl(dgid_addr.saddr_in.sin_addr.s_addr);
432462306a36Sopenharmony_ci		ah_info->src_ip_addr[0] =
432562306a36Sopenharmony_ci			ntohl(sgid_addr.saddr_in.sin_addr.s_addr);
432662306a36Sopenharmony_ci		ah_info->do_lpbk = irdma_ipv4_is_lpb(ah_info->src_ip_addr[0],
432762306a36Sopenharmony_ci						     ah_info->dest_ip_addr[0]);
432862306a36Sopenharmony_ci		if (ipv4_is_multicast(dgid_addr.saddr_in.sin_addr.s_addr)) {
432962306a36Sopenharmony_ci			ah_info->do_lpbk = true;
433062306a36Sopenharmony_ci			irdma_mcast_mac(ah_info->dest_ip_addr, dmac, true);
433162306a36Sopenharmony_ci		}
433262306a36Sopenharmony_ci	} else {
433362306a36Sopenharmony_ci		irdma_copy_ip_ntohl(ah_info->dest_ip_addr,
433462306a36Sopenharmony_ci				    dgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32);
433562306a36Sopenharmony_ci		irdma_copy_ip_ntohl(ah_info->src_ip_addr,
433662306a36Sopenharmony_ci				    sgid_addr.saddr_in6.sin6_addr.in6_u.u6_addr32);
433762306a36Sopenharmony_ci		ah_info->do_lpbk = irdma_ipv6_is_lpb(ah_info->src_ip_addr,
433862306a36Sopenharmony_ci						     ah_info->dest_ip_addr);
433962306a36Sopenharmony_ci		if (rdma_is_multicast_addr(&dgid_addr.saddr_in6.sin6_addr)) {
434062306a36Sopenharmony_ci			ah_info->do_lpbk = true;
434162306a36Sopenharmony_ci			irdma_mcast_mac(ah_info->dest_ip_addr, dmac, false);
434262306a36Sopenharmony_ci		}
434362306a36Sopenharmony_ci	}
434462306a36Sopenharmony_ci
434562306a36Sopenharmony_ci	err = rdma_read_gid_l2_fields(sgid_attr, &ah_info->vlan_tag,
434662306a36Sopenharmony_ci				      ah_info->mac_addr);
434762306a36Sopenharmony_ci	if (err)
434862306a36Sopenharmony_ci		return err;
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_ci	ah_info->dst_arpindex = irdma_add_arp(iwdev->rf, ah_info->dest_ip_addr,
435162306a36Sopenharmony_ci					      ah_info->ipv4_valid, dmac);
435262306a36Sopenharmony_ci
435362306a36Sopenharmony_ci	if (ah_info->dst_arpindex == -1)
435462306a36Sopenharmony_ci		return -EINVAL;
435562306a36Sopenharmony_ci
435662306a36Sopenharmony_ci	if (ah_info->vlan_tag >= VLAN_N_VID && iwdev->dcb_vlan_mode)
435762306a36Sopenharmony_ci		ah_info->vlan_tag = 0;
435862306a36Sopenharmony_ci
435962306a36Sopenharmony_ci	if (ah_info->vlan_tag < VLAN_N_VID) {
436062306a36Sopenharmony_ci		u8 prio = rt_tos2priority(ah_info->tc_tos);
436162306a36Sopenharmony_ci
436262306a36Sopenharmony_ci		prio = irdma_roce_get_vlan_prio(sgid_attr, prio);
436362306a36Sopenharmony_ci
436462306a36Sopenharmony_ci		ah_info->vlan_tag |= (u16)prio << VLAN_PRIO_SHIFT;
436562306a36Sopenharmony_ci		ah_info->insert_vlan_tag = true;
436662306a36Sopenharmony_ci	}
436762306a36Sopenharmony_ci
436862306a36Sopenharmony_ci	return 0;
436962306a36Sopenharmony_ci}
437062306a36Sopenharmony_ci
437162306a36Sopenharmony_ci/**
437262306a36Sopenharmony_ci * irdma_ah_exists - Check for existing identical AH
437362306a36Sopenharmony_ci * @iwdev: irdma device
437462306a36Sopenharmony_ci * @new_ah: AH to check for
437562306a36Sopenharmony_ci *
437662306a36Sopenharmony_ci * returns true if AH is found, false if not found.
437762306a36Sopenharmony_ci */
437862306a36Sopenharmony_cistatic bool irdma_ah_exists(struct irdma_device *iwdev,
437962306a36Sopenharmony_ci			    struct irdma_ah *new_ah)
438062306a36Sopenharmony_ci{
438162306a36Sopenharmony_ci	struct irdma_ah *ah;
438262306a36Sopenharmony_ci	u32 key = new_ah->sc_ah.ah_info.dest_ip_addr[0] ^
438362306a36Sopenharmony_ci		  new_ah->sc_ah.ah_info.dest_ip_addr[1] ^
438462306a36Sopenharmony_ci		  new_ah->sc_ah.ah_info.dest_ip_addr[2] ^
438562306a36Sopenharmony_ci		  new_ah->sc_ah.ah_info.dest_ip_addr[3];
438662306a36Sopenharmony_ci
438762306a36Sopenharmony_ci	hash_for_each_possible(iwdev->ah_hash_tbl, ah, list, key) {
438862306a36Sopenharmony_ci		/* Set ah_valid and ah_id the same so memcmp can work */
438962306a36Sopenharmony_ci		new_ah->sc_ah.ah_info.ah_idx = ah->sc_ah.ah_info.ah_idx;
439062306a36Sopenharmony_ci		new_ah->sc_ah.ah_info.ah_valid = ah->sc_ah.ah_info.ah_valid;
439162306a36Sopenharmony_ci		if (!memcmp(&ah->sc_ah.ah_info, &new_ah->sc_ah.ah_info,
439262306a36Sopenharmony_ci			    sizeof(ah->sc_ah.ah_info))) {
439362306a36Sopenharmony_ci			refcount_inc(&ah->refcnt);
439462306a36Sopenharmony_ci			new_ah->parent_ah = ah;
439562306a36Sopenharmony_ci			return true;
439662306a36Sopenharmony_ci		}
439762306a36Sopenharmony_ci	}
439862306a36Sopenharmony_ci
439962306a36Sopenharmony_ci	return false;
440062306a36Sopenharmony_ci}
440162306a36Sopenharmony_ci
440262306a36Sopenharmony_ci/**
440362306a36Sopenharmony_ci * irdma_destroy_ah - Destroy address handle
440462306a36Sopenharmony_ci * @ibah: pointer to address handle
440562306a36Sopenharmony_ci * @ah_flags: flags for sleepable
440662306a36Sopenharmony_ci */
440762306a36Sopenharmony_cistatic int irdma_destroy_ah(struct ib_ah *ibah, u32 ah_flags)
440862306a36Sopenharmony_ci{
440962306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibah->device);
441062306a36Sopenharmony_ci	struct irdma_ah *ah = to_iwah(ibah);
441162306a36Sopenharmony_ci
441262306a36Sopenharmony_ci	if ((ah_flags & RDMA_DESTROY_AH_SLEEPABLE) && ah->parent_ah) {
441362306a36Sopenharmony_ci		mutex_lock(&iwdev->ah_tbl_lock);
441462306a36Sopenharmony_ci		if (!refcount_dec_and_test(&ah->parent_ah->refcnt)) {
441562306a36Sopenharmony_ci			mutex_unlock(&iwdev->ah_tbl_lock);
441662306a36Sopenharmony_ci			return 0;
441762306a36Sopenharmony_ci		}
441862306a36Sopenharmony_ci		hash_del(&ah->parent_ah->list);
441962306a36Sopenharmony_ci		kfree(ah->parent_ah);
442062306a36Sopenharmony_ci		mutex_unlock(&iwdev->ah_tbl_lock);
442162306a36Sopenharmony_ci	}
442262306a36Sopenharmony_ci
442362306a36Sopenharmony_ci	irdma_ah_cqp_op(iwdev->rf, &ah->sc_ah, IRDMA_OP_AH_DESTROY,
442462306a36Sopenharmony_ci			false, NULL, ah);
442562306a36Sopenharmony_ci
442662306a36Sopenharmony_ci	irdma_free_rsrc(iwdev->rf, iwdev->rf->allocated_ahs,
442762306a36Sopenharmony_ci			ah->sc_ah.ah_info.ah_idx);
442862306a36Sopenharmony_ci
442962306a36Sopenharmony_ci	return 0;
443062306a36Sopenharmony_ci}
443162306a36Sopenharmony_ci
443262306a36Sopenharmony_ci/**
443362306a36Sopenharmony_ci * irdma_create_user_ah - create user address handle
443462306a36Sopenharmony_ci * @ibah: address handle
443562306a36Sopenharmony_ci * @attr: address handle attributes
443662306a36Sopenharmony_ci * @udata: User data
443762306a36Sopenharmony_ci *
443862306a36Sopenharmony_ci * returns 0 on success, error otherwise
443962306a36Sopenharmony_ci */
444062306a36Sopenharmony_cistatic int irdma_create_user_ah(struct ib_ah *ibah,
444162306a36Sopenharmony_ci				struct rdma_ah_init_attr *attr,
444262306a36Sopenharmony_ci				struct ib_udata *udata)
444362306a36Sopenharmony_ci{
444462306a36Sopenharmony_ci#define IRDMA_CREATE_AH_MIN_RESP_LEN offsetofend(struct irdma_create_ah_resp, rsvd)
444562306a36Sopenharmony_ci	struct irdma_ah *ah = container_of(ibah, struct irdma_ah, ibah);
444662306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibah->pd->device);
444762306a36Sopenharmony_ci	struct irdma_create_ah_resp uresp;
444862306a36Sopenharmony_ci	struct irdma_ah *parent_ah;
444962306a36Sopenharmony_ci	int err;
445062306a36Sopenharmony_ci
445162306a36Sopenharmony_ci	if (udata && udata->outlen < IRDMA_CREATE_AH_MIN_RESP_LEN)
445262306a36Sopenharmony_ci		return -EINVAL;
445362306a36Sopenharmony_ci
445462306a36Sopenharmony_ci	err = irdma_setup_ah(ibah, attr);
445562306a36Sopenharmony_ci	if (err)
445662306a36Sopenharmony_ci		return err;
445762306a36Sopenharmony_ci	mutex_lock(&iwdev->ah_tbl_lock);
445862306a36Sopenharmony_ci	if (!irdma_ah_exists(iwdev, ah)) {
445962306a36Sopenharmony_ci		err = irdma_create_hw_ah(iwdev, ah, true);
446062306a36Sopenharmony_ci		if (err) {
446162306a36Sopenharmony_ci			mutex_unlock(&iwdev->ah_tbl_lock);
446262306a36Sopenharmony_ci			return err;
446362306a36Sopenharmony_ci		}
446462306a36Sopenharmony_ci		/* Add new AH to list */
446562306a36Sopenharmony_ci		parent_ah = kmemdup(ah, sizeof(*ah), GFP_KERNEL);
446662306a36Sopenharmony_ci		if (parent_ah) {
446762306a36Sopenharmony_ci			u32 key = parent_ah->sc_ah.ah_info.dest_ip_addr[0] ^
446862306a36Sopenharmony_ci				  parent_ah->sc_ah.ah_info.dest_ip_addr[1] ^
446962306a36Sopenharmony_ci				  parent_ah->sc_ah.ah_info.dest_ip_addr[2] ^
447062306a36Sopenharmony_ci				  parent_ah->sc_ah.ah_info.dest_ip_addr[3];
447162306a36Sopenharmony_ci
447262306a36Sopenharmony_ci			ah->parent_ah = parent_ah;
447362306a36Sopenharmony_ci			hash_add(iwdev->ah_hash_tbl, &parent_ah->list, key);
447462306a36Sopenharmony_ci			refcount_set(&parent_ah->refcnt, 1);
447562306a36Sopenharmony_ci		}
447662306a36Sopenharmony_ci	}
447762306a36Sopenharmony_ci	mutex_unlock(&iwdev->ah_tbl_lock);
447862306a36Sopenharmony_ci
447962306a36Sopenharmony_ci	uresp.ah_id = ah->sc_ah.ah_info.ah_idx;
448062306a36Sopenharmony_ci	err = ib_copy_to_udata(udata, &uresp, min(sizeof(uresp), udata->outlen));
448162306a36Sopenharmony_ci	if (err)
448262306a36Sopenharmony_ci		irdma_destroy_ah(ibah, attr->flags);
448362306a36Sopenharmony_ci
448462306a36Sopenharmony_ci	return err;
448562306a36Sopenharmony_ci}
448662306a36Sopenharmony_ci
448762306a36Sopenharmony_ci/**
448862306a36Sopenharmony_ci * irdma_create_ah - create address handle
448962306a36Sopenharmony_ci * @ibah: address handle
449062306a36Sopenharmony_ci * @attr: address handle attributes
449162306a36Sopenharmony_ci * @udata: NULL
449262306a36Sopenharmony_ci *
449362306a36Sopenharmony_ci * returns 0 on success, error otherwise
449462306a36Sopenharmony_ci */
449562306a36Sopenharmony_cistatic int irdma_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *attr,
449662306a36Sopenharmony_ci			   struct ib_udata *udata)
449762306a36Sopenharmony_ci{
449862306a36Sopenharmony_ci	struct irdma_ah *ah = container_of(ibah, struct irdma_ah, ibah);
449962306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibah->pd->device);
450062306a36Sopenharmony_ci	int err;
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci	err = irdma_setup_ah(ibah, attr);
450362306a36Sopenharmony_ci	if (err)
450462306a36Sopenharmony_ci		return err;
450562306a36Sopenharmony_ci	err = irdma_create_hw_ah(iwdev, ah, attr->flags & RDMA_CREATE_AH_SLEEPABLE);
450662306a36Sopenharmony_ci
450762306a36Sopenharmony_ci	return err;
450862306a36Sopenharmony_ci}
450962306a36Sopenharmony_ci
451062306a36Sopenharmony_ci/**
451162306a36Sopenharmony_ci * irdma_query_ah - Query address handle
451262306a36Sopenharmony_ci * @ibah: pointer to address handle
451362306a36Sopenharmony_ci * @ah_attr: address handle attributes
451462306a36Sopenharmony_ci */
451562306a36Sopenharmony_cistatic int irdma_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr)
451662306a36Sopenharmony_ci{
451762306a36Sopenharmony_ci	struct irdma_ah *ah = to_iwah(ibah);
451862306a36Sopenharmony_ci
451962306a36Sopenharmony_ci	memset(ah_attr, 0, sizeof(*ah_attr));
452062306a36Sopenharmony_ci	if (ah->av.attrs.ah_flags & IB_AH_GRH) {
452162306a36Sopenharmony_ci		ah_attr->ah_flags = IB_AH_GRH;
452262306a36Sopenharmony_ci		ah_attr->grh.flow_label = ah->sc_ah.ah_info.flow_label;
452362306a36Sopenharmony_ci		ah_attr->grh.traffic_class = ah->sc_ah.ah_info.tc_tos;
452462306a36Sopenharmony_ci		ah_attr->grh.hop_limit = ah->sc_ah.ah_info.hop_ttl;
452562306a36Sopenharmony_ci		ah_attr->grh.sgid_index = ah->sgid_index;
452662306a36Sopenharmony_ci		memcpy(&ah_attr->grh.dgid, &ah->dgid,
452762306a36Sopenharmony_ci		       sizeof(ah_attr->grh.dgid));
452862306a36Sopenharmony_ci	}
452962306a36Sopenharmony_ci
453062306a36Sopenharmony_ci	return 0;
453162306a36Sopenharmony_ci}
453262306a36Sopenharmony_ci
453362306a36Sopenharmony_cistatic enum rdma_link_layer irdma_get_link_layer(struct ib_device *ibdev,
453462306a36Sopenharmony_ci						 u32 port_num)
453562306a36Sopenharmony_ci{
453662306a36Sopenharmony_ci	return IB_LINK_LAYER_ETHERNET;
453762306a36Sopenharmony_ci}
453862306a36Sopenharmony_ci
453962306a36Sopenharmony_cistatic const struct ib_device_ops irdma_roce_dev_ops = {
454062306a36Sopenharmony_ci	.attach_mcast = irdma_attach_mcast,
454162306a36Sopenharmony_ci	.create_ah = irdma_create_ah,
454262306a36Sopenharmony_ci	.create_user_ah = irdma_create_user_ah,
454362306a36Sopenharmony_ci	.destroy_ah = irdma_destroy_ah,
454462306a36Sopenharmony_ci	.detach_mcast = irdma_detach_mcast,
454562306a36Sopenharmony_ci	.get_link_layer = irdma_get_link_layer,
454662306a36Sopenharmony_ci	.get_port_immutable = irdma_roce_port_immutable,
454762306a36Sopenharmony_ci	.modify_qp = irdma_modify_qp_roce,
454862306a36Sopenharmony_ci	.query_ah = irdma_query_ah,
454962306a36Sopenharmony_ci	.query_pkey = irdma_query_pkey,
455062306a36Sopenharmony_ci};
455162306a36Sopenharmony_ci
455262306a36Sopenharmony_cistatic const struct ib_device_ops irdma_iw_dev_ops = {
455362306a36Sopenharmony_ci	.get_port_immutable = irdma_iw_port_immutable,
455462306a36Sopenharmony_ci	.iw_accept = irdma_accept,
455562306a36Sopenharmony_ci	.iw_add_ref = irdma_qp_add_ref,
455662306a36Sopenharmony_ci	.iw_connect = irdma_connect,
455762306a36Sopenharmony_ci	.iw_create_listen = irdma_create_listen,
455862306a36Sopenharmony_ci	.iw_destroy_listen = irdma_destroy_listen,
455962306a36Sopenharmony_ci	.iw_get_qp = irdma_get_qp,
456062306a36Sopenharmony_ci	.iw_reject = irdma_reject,
456162306a36Sopenharmony_ci	.iw_rem_ref = irdma_qp_rem_ref,
456262306a36Sopenharmony_ci	.modify_qp = irdma_modify_qp,
456362306a36Sopenharmony_ci	.query_gid = irdma_query_gid,
456462306a36Sopenharmony_ci};
456562306a36Sopenharmony_ci
456662306a36Sopenharmony_cistatic const struct ib_device_ops irdma_dev_ops = {
456762306a36Sopenharmony_ci	.owner = THIS_MODULE,
456862306a36Sopenharmony_ci	.driver_id = RDMA_DRIVER_IRDMA,
456962306a36Sopenharmony_ci	.uverbs_abi_ver = IRDMA_ABI_VER,
457062306a36Sopenharmony_ci
457162306a36Sopenharmony_ci	.alloc_hw_port_stats = irdma_alloc_hw_port_stats,
457262306a36Sopenharmony_ci	.alloc_mr = irdma_alloc_mr,
457362306a36Sopenharmony_ci	.alloc_mw = irdma_alloc_mw,
457462306a36Sopenharmony_ci	.alloc_pd = irdma_alloc_pd,
457562306a36Sopenharmony_ci	.alloc_ucontext = irdma_alloc_ucontext,
457662306a36Sopenharmony_ci	.create_cq = irdma_create_cq,
457762306a36Sopenharmony_ci	.create_qp = irdma_create_qp,
457862306a36Sopenharmony_ci	.dealloc_driver = irdma_ib_dealloc_device,
457962306a36Sopenharmony_ci	.dealloc_mw = irdma_dealloc_mw,
458062306a36Sopenharmony_ci	.dealloc_pd = irdma_dealloc_pd,
458162306a36Sopenharmony_ci	.dealloc_ucontext = irdma_dealloc_ucontext,
458262306a36Sopenharmony_ci	.dereg_mr = irdma_dereg_mr,
458362306a36Sopenharmony_ci	.destroy_cq = irdma_destroy_cq,
458462306a36Sopenharmony_ci	.destroy_qp = irdma_destroy_qp,
458562306a36Sopenharmony_ci	.disassociate_ucontext = irdma_disassociate_ucontext,
458662306a36Sopenharmony_ci	.get_dev_fw_str = irdma_get_dev_fw_str,
458762306a36Sopenharmony_ci	.get_dma_mr = irdma_get_dma_mr,
458862306a36Sopenharmony_ci	.get_hw_stats = irdma_get_hw_stats,
458962306a36Sopenharmony_ci	.map_mr_sg = irdma_map_mr_sg,
459062306a36Sopenharmony_ci	.mmap = irdma_mmap,
459162306a36Sopenharmony_ci	.mmap_free = irdma_mmap_free,
459262306a36Sopenharmony_ci	.poll_cq = irdma_poll_cq,
459362306a36Sopenharmony_ci	.post_recv = irdma_post_recv,
459462306a36Sopenharmony_ci	.post_send = irdma_post_send,
459562306a36Sopenharmony_ci	.query_device = irdma_query_device,
459662306a36Sopenharmony_ci	.query_port = irdma_query_port,
459762306a36Sopenharmony_ci	.query_qp = irdma_query_qp,
459862306a36Sopenharmony_ci	.reg_user_mr = irdma_reg_user_mr,
459962306a36Sopenharmony_ci	.reg_user_mr_dmabuf = irdma_reg_user_mr_dmabuf,
460062306a36Sopenharmony_ci	.req_notify_cq = irdma_req_notify_cq,
460162306a36Sopenharmony_ci	.resize_cq = irdma_resize_cq,
460262306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_pd, irdma_pd, ibpd),
460362306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_ucontext, irdma_ucontext, ibucontext),
460462306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_ah, irdma_ah, ibah),
460562306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_cq, irdma_cq, ibcq),
460662306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_mw, irdma_mr, ibmw),
460762306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_qp, irdma_qp, ibqp),
460862306a36Sopenharmony_ci};
460962306a36Sopenharmony_ci
461062306a36Sopenharmony_ci/**
461162306a36Sopenharmony_ci * irdma_init_roce_device - initialization of roce rdma device
461262306a36Sopenharmony_ci * @iwdev: irdma device
461362306a36Sopenharmony_ci */
461462306a36Sopenharmony_cistatic void irdma_init_roce_device(struct irdma_device *iwdev)
461562306a36Sopenharmony_ci{
461662306a36Sopenharmony_ci	iwdev->ibdev.node_type = RDMA_NODE_IB_CA;
461762306a36Sopenharmony_ci	addrconf_addr_eui48((u8 *)&iwdev->ibdev.node_guid,
461862306a36Sopenharmony_ci			    iwdev->netdev->dev_addr);
461962306a36Sopenharmony_ci	ib_set_device_ops(&iwdev->ibdev, &irdma_roce_dev_ops);
462062306a36Sopenharmony_ci}
462162306a36Sopenharmony_ci
462262306a36Sopenharmony_ci/**
462362306a36Sopenharmony_ci * irdma_init_iw_device - initialization of iwarp rdma device
462462306a36Sopenharmony_ci * @iwdev: irdma device
462562306a36Sopenharmony_ci */
462662306a36Sopenharmony_cistatic void irdma_init_iw_device(struct irdma_device *iwdev)
462762306a36Sopenharmony_ci{
462862306a36Sopenharmony_ci	struct net_device *netdev = iwdev->netdev;
462962306a36Sopenharmony_ci
463062306a36Sopenharmony_ci	iwdev->ibdev.node_type = RDMA_NODE_RNIC;
463162306a36Sopenharmony_ci	addrconf_addr_eui48((u8 *)&iwdev->ibdev.node_guid,
463262306a36Sopenharmony_ci			    netdev->dev_addr);
463362306a36Sopenharmony_ci	memcpy(iwdev->ibdev.iw_ifname, netdev->name,
463462306a36Sopenharmony_ci	       sizeof(iwdev->ibdev.iw_ifname));
463562306a36Sopenharmony_ci	ib_set_device_ops(&iwdev->ibdev, &irdma_iw_dev_ops);
463662306a36Sopenharmony_ci}
463762306a36Sopenharmony_ci
463862306a36Sopenharmony_ci/**
463962306a36Sopenharmony_ci * irdma_init_rdma_device - initialization of rdma device
464062306a36Sopenharmony_ci * @iwdev: irdma device
464162306a36Sopenharmony_ci */
464262306a36Sopenharmony_cistatic void irdma_init_rdma_device(struct irdma_device *iwdev)
464362306a36Sopenharmony_ci{
464462306a36Sopenharmony_ci	struct pci_dev *pcidev = iwdev->rf->pcidev;
464562306a36Sopenharmony_ci
464662306a36Sopenharmony_ci	if (iwdev->roce_mode)
464762306a36Sopenharmony_ci		irdma_init_roce_device(iwdev);
464862306a36Sopenharmony_ci	else
464962306a36Sopenharmony_ci		irdma_init_iw_device(iwdev);
465062306a36Sopenharmony_ci
465162306a36Sopenharmony_ci	iwdev->ibdev.phys_port_cnt = 1;
465262306a36Sopenharmony_ci	iwdev->ibdev.num_comp_vectors = iwdev->rf->ceqs_count;
465362306a36Sopenharmony_ci	iwdev->ibdev.dev.parent = &pcidev->dev;
465462306a36Sopenharmony_ci	ib_set_device_ops(&iwdev->ibdev, &irdma_dev_ops);
465562306a36Sopenharmony_ci}
465662306a36Sopenharmony_ci
465762306a36Sopenharmony_ci/**
465862306a36Sopenharmony_ci * irdma_port_ibevent - indicate port event
465962306a36Sopenharmony_ci * @iwdev: irdma device
466062306a36Sopenharmony_ci */
466162306a36Sopenharmony_civoid irdma_port_ibevent(struct irdma_device *iwdev)
466262306a36Sopenharmony_ci{
466362306a36Sopenharmony_ci	struct ib_event event;
466462306a36Sopenharmony_ci
466562306a36Sopenharmony_ci	event.device = &iwdev->ibdev;
466662306a36Sopenharmony_ci	event.element.port_num = 1;
466762306a36Sopenharmony_ci	event.event =
466862306a36Sopenharmony_ci		iwdev->iw_status ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
466962306a36Sopenharmony_ci	ib_dispatch_event(&event);
467062306a36Sopenharmony_ci}
467162306a36Sopenharmony_ci
467262306a36Sopenharmony_ci/**
467362306a36Sopenharmony_ci * irdma_ib_unregister_device - unregister rdma device from IB
467462306a36Sopenharmony_ci * core
467562306a36Sopenharmony_ci * @iwdev: irdma device
467662306a36Sopenharmony_ci */
467762306a36Sopenharmony_civoid irdma_ib_unregister_device(struct irdma_device *iwdev)
467862306a36Sopenharmony_ci{
467962306a36Sopenharmony_ci	iwdev->iw_status = 0;
468062306a36Sopenharmony_ci	irdma_port_ibevent(iwdev);
468162306a36Sopenharmony_ci	ib_unregister_device(&iwdev->ibdev);
468262306a36Sopenharmony_ci}
468362306a36Sopenharmony_ci
468462306a36Sopenharmony_ci/**
468562306a36Sopenharmony_ci * irdma_ib_register_device - register irdma device to IB core
468662306a36Sopenharmony_ci * @iwdev: irdma device
468762306a36Sopenharmony_ci */
468862306a36Sopenharmony_ciint irdma_ib_register_device(struct irdma_device *iwdev)
468962306a36Sopenharmony_ci{
469062306a36Sopenharmony_ci	int ret;
469162306a36Sopenharmony_ci
469262306a36Sopenharmony_ci	irdma_init_rdma_device(iwdev);
469362306a36Sopenharmony_ci
469462306a36Sopenharmony_ci	ret = ib_device_set_netdev(&iwdev->ibdev, iwdev->netdev, 1);
469562306a36Sopenharmony_ci	if (ret)
469662306a36Sopenharmony_ci		goto error;
469762306a36Sopenharmony_ci	dma_set_max_seg_size(iwdev->rf->hw.device, UINT_MAX);
469862306a36Sopenharmony_ci	ret = ib_register_device(&iwdev->ibdev, "irdma%d", iwdev->rf->hw.device);
469962306a36Sopenharmony_ci	if (ret)
470062306a36Sopenharmony_ci		goto error;
470162306a36Sopenharmony_ci
470262306a36Sopenharmony_ci	iwdev->iw_status = 1;
470362306a36Sopenharmony_ci	irdma_port_ibevent(iwdev);
470462306a36Sopenharmony_ci
470562306a36Sopenharmony_ci	return 0;
470662306a36Sopenharmony_ci
470762306a36Sopenharmony_cierror:
470862306a36Sopenharmony_ci	if (ret)
470962306a36Sopenharmony_ci		ibdev_dbg(&iwdev->ibdev, "VERBS: Register RDMA device fail\n");
471062306a36Sopenharmony_ci
471162306a36Sopenharmony_ci	return ret;
471262306a36Sopenharmony_ci}
471362306a36Sopenharmony_ci
471462306a36Sopenharmony_ci/**
471562306a36Sopenharmony_ci * irdma_ib_dealloc_device
471662306a36Sopenharmony_ci * @ibdev: ib device
471762306a36Sopenharmony_ci *
471862306a36Sopenharmony_ci * callback from ibdev dealloc_driver to deallocate resources
471962306a36Sopenharmony_ci * unber irdma device
472062306a36Sopenharmony_ci */
472162306a36Sopenharmony_civoid irdma_ib_dealloc_device(struct ib_device *ibdev)
472262306a36Sopenharmony_ci{
472362306a36Sopenharmony_ci	struct irdma_device *iwdev = to_iwdev(ibdev);
472462306a36Sopenharmony_ci
472562306a36Sopenharmony_ci	irdma_rt_deinit_hw(iwdev);
472662306a36Sopenharmony_ci	irdma_ctrl_deinit_hw(iwdev->rf);
472762306a36Sopenharmony_ci	kfree(iwdev->rf);
472862306a36Sopenharmony_ci}
4729