162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This software is available to you under a choice of one of two
562306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
862306a36Sopenharmony_ci * BSD license below:
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1162306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1262306a36Sopenharmony_ci *     conditions are met:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1562306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1662306a36Sopenharmony_ci *        disclaimer.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
1962306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2062306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2162306a36Sopenharmony_ci *        provided with the distribution.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3062306a36Sopenharmony_ci * SOFTWARE.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_ci#include <linux/init.h>
3462306a36Sopenharmony_ci#include <linux/slab.h>
3562306a36Sopenharmony_ci#include <linux/errno.h>
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include <rdma/ib_user_verbs.h>
3862306a36Sopenharmony_ci#include <rdma/ib_addr.h>
3962306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include "usnic_abi.h"
4262306a36Sopenharmony_ci#include "usnic_ib.h"
4362306a36Sopenharmony_ci#include "usnic_common_util.h"
4462306a36Sopenharmony_ci#include "usnic_ib_qp_grp.h"
4562306a36Sopenharmony_ci#include "usnic_ib_verbs.h"
4662306a36Sopenharmony_ci#include "usnic_fwd.h"
4762306a36Sopenharmony_ci#include "usnic_log.h"
4862306a36Sopenharmony_ci#include "usnic_uiom.h"
4962306a36Sopenharmony_ci#include "usnic_transport.h"
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define USNIC_DEFAULT_TRANSPORT USNIC_TRANSPORT_ROCE_CUSTOM
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ciconst struct usnic_vnic_res_spec min_transport_spec[USNIC_TRANSPORT_MAX] = {
5462306a36Sopenharmony_ci	{ /*USNIC_TRANSPORT_UNKNOWN*/
5562306a36Sopenharmony_ci		.resources = {
5662306a36Sopenharmony_ci			{.type = USNIC_VNIC_RES_TYPE_EOL,	.cnt = 0,},
5762306a36Sopenharmony_ci		},
5862306a36Sopenharmony_ci	},
5962306a36Sopenharmony_ci	{ /*USNIC_TRANSPORT_ROCE_CUSTOM*/
6062306a36Sopenharmony_ci		.resources = {
6162306a36Sopenharmony_ci			{.type = USNIC_VNIC_RES_TYPE_WQ,	.cnt = 1,},
6262306a36Sopenharmony_ci			{.type = USNIC_VNIC_RES_TYPE_RQ,	.cnt = 1,},
6362306a36Sopenharmony_ci			{.type = USNIC_VNIC_RES_TYPE_CQ,	.cnt = 1,},
6462306a36Sopenharmony_ci			{.type = USNIC_VNIC_RES_TYPE_EOL,	.cnt = 0,},
6562306a36Sopenharmony_ci		},
6662306a36Sopenharmony_ci	},
6762306a36Sopenharmony_ci	{ /*USNIC_TRANSPORT_IPV4_UDP*/
6862306a36Sopenharmony_ci		.resources = {
6962306a36Sopenharmony_ci			{.type = USNIC_VNIC_RES_TYPE_WQ,	.cnt = 1,},
7062306a36Sopenharmony_ci			{.type = USNIC_VNIC_RES_TYPE_RQ,	.cnt = 1,},
7162306a36Sopenharmony_ci			{.type = USNIC_VNIC_RES_TYPE_CQ,	.cnt = 1,},
7262306a36Sopenharmony_ci			{.type = USNIC_VNIC_RES_TYPE_EOL,	.cnt = 0,},
7362306a36Sopenharmony_ci		},
7462306a36Sopenharmony_ci	},
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic void usnic_ib_fw_string_to_u64(char *fw_ver_str, u64 *fw_ver)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	*fw_ver = *((u64 *)fw_ver_str);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic int usnic_ib_fill_create_qp_resp(struct usnic_ib_qp_grp *qp_grp,
8362306a36Sopenharmony_ci					struct ib_udata *udata)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct usnic_ib_dev *us_ibdev;
8662306a36Sopenharmony_ci	struct usnic_ib_create_qp_resp resp;
8762306a36Sopenharmony_ci	struct pci_dev *pdev;
8862306a36Sopenharmony_ci	struct vnic_dev_bar *bar;
8962306a36Sopenharmony_ci	struct usnic_vnic_res_chunk *chunk;
9062306a36Sopenharmony_ci	struct usnic_ib_qp_grp_flow *default_flow;
9162306a36Sopenharmony_ci	int i, err;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	memset(&resp, 0, sizeof(resp));
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	us_ibdev = qp_grp->vf->pf;
9662306a36Sopenharmony_ci	pdev = usnic_vnic_get_pdev(qp_grp->vf->vnic);
9762306a36Sopenharmony_ci	if (!pdev) {
9862306a36Sopenharmony_ci		usnic_err("Failed to get pdev of qp_grp %d\n",
9962306a36Sopenharmony_ci				qp_grp->grp_id);
10062306a36Sopenharmony_ci		return -EFAULT;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	bar = usnic_vnic_get_bar(qp_grp->vf->vnic, 0);
10462306a36Sopenharmony_ci	if (!bar) {
10562306a36Sopenharmony_ci		usnic_err("Failed to get bar0 of qp_grp %d vf %s",
10662306a36Sopenharmony_ci				qp_grp->grp_id, pci_name(pdev));
10762306a36Sopenharmony_ci		return -EFAULT;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	resp.vfid = usnic_vnic_get_index(qp_grp->vf->vnic);
11162306a36Sopenharmony_ci	resp.bar_bus_addr = bar->bus_addr;
11262306a36Sopenharmony_ci	resp.bar_len = bar->len;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ);
11562306a36Sopenharmony_ci	if (IS_ERR(chunk)) {
11662306a36Sopenharmony_ci		usnic_err("Failed to get chunk %s for qp_grp %d with err %ld\n",
11762306a36Sopenharmony_ci			usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_RQ),
11862306a36Sopenharmony_ci			qp_grp->grp_id,
11962306a36Sopenharmony_ci			PTR_ERR(chunk));
12062306a36Sopenharmony_ci		return PTR_ERR(chunk);
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	WARN_ON(chunk->type != USNIC_VNIC_RES_TYPE_RQ);
12462306a36Sopenharmony_ci	resp.rq_cnt = chunk->cnt;
12562306a36Sopenharmony_ci	for (i = 0; i < chunk->cnt; i++)
12662306a36Sopenharmony_ci		resp.rq_idx[i] = chunk->res[i]->vnic_idx;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_WQ);
12962306a36Sopenharmony_ci	if (IS_ERR(chunk)) {
13062306a36Sopenharmony_ci		usnic_err("Failed to get chunk %s for qp_grp %d with err %ld\n",
13162306a36Sopenharmony_ci			usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_WQ),
13262306a36Sopenharmony_ci			qp_grp->grp_id,
13362306a36Sopenharmony_ci			PTR_ERR(chunk));
13462306a36Sopenharmony_ci		return PTR_ERR(chunk);
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	WARN_ON(chunk->type != USNIC_VNIC_RES_TYPE_WQ);
13862306a36Sopenharmony_ci	resp.wq_cnt = chunk->cnt;
13962306a36Sopenharmony_ci	for (i = 0; i < chunk->cnt; i++)
14062306a36Sopenharmony_ci		resp.wq_idx[i] = chunk->res[i]->vnic_idx;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_CQ);
14362306a36Sopenharmony_ci	if (IS_ERR(chunk)) {
14462306a36Sopenharmony_ci		usnic_err("Failed to get chunk %s for qp_grp %d with err %ld\n",
14562306a36Sopenharmony_ci			usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_CQ),
14662306a36Sopenharmony_ci			qp_grp->grp_id,
14762306a36Sopenharmony_ci			PTR_ERR(chunk));
14862306a36Sopenharmony_ci		return PTR_ERR(chunk);
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	WARN_ON(chunk->type != USNIC_VNIC_RES_TYPE_CQ);
15262306a36Sopenharmony_ci	resp.cq_cnt = chunk->cnt;
15362306a36Sopenharmony_ci	for (i = 0; i < chunk->cnt; i++)
15462306a36Sopenharmony_ci		resp.cq_idx[i] = chunk->res[i]->vnic_idx;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	default_flow = list_first_entry(&qp_grp->flows_lst,
15762306a36Sopenharmony_ci					struct usnic_ib_qp_grp_flow, link);
15862306a36Sopenharmony_ci	resp.transport = default_flow->trans_type;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	err = ib_copy_to_udata(udata, &resp, sizeof(resp));
16162306a36Sopenharmony_ci	if (err) {
16262306a36Sopenharmony_ci		usnic_err("Failed to copy udata for %s",
16362306a36Sopenharmony_ci			  dev_name(&us_ibdev->ib_dev.dev));
16462306a36Sopenharmony_ci		return err;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return 0;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int
17162306a36Sopenharmony_cifind_free_vf_and_create_qp_grp(struct ib_qp *qp,
17262306a36Sopenharmony_ci			       struct usnic_transport_spec *trans_spec,
17362306a36Sopenharmony_ci			       struct usnic_vnic_res_spec *res_spec)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	struct usnic_ib_dev *us_ibdev = to_usdev(qp->device);
17662306a36Sopenharmony_ci	struct usnic_ib_pd *pd = to_upd(qp->pd);
17762306a36Sopenharmony_ci	struct usnic_ib_vf *vf;
17862306a36Sopenharmony_ci	struct usnic_vnic *vnic;
17962306a36Sopenharmony_ci	struct usnic_ib_qp_grp *qp_grp = to_uqp_grp(qp);
18062306a36Sopenharmony_ci	struct device *dev, **dev_list;
18162306a36Sopenharmony_ci	int i, ret;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	BUG_ON(!mutex_is_locked(&us_ibdev->usdev_lock));
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (list_empty(&us_ibdev->vf_dev_list)) {
18662306a36Sopenharmony_ci		usnic_info("No vfs to allocate\n");
18762306a36Sopenharmony_ci		return -ENOMEM;
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (usnic_ib_share_vf) {
19162306a36Sopenharmony_ci		/* Try to find resouces on a used vf which is in pd */
19262306a36Sopenharmony_ci		dev_list = usnic_uiom_get_dev_list(pd->umem_pd);
19362306a36Sopenharmony_ci		if (IS_ERR(dev_list))
19462306a36Sopenharmony_ci			return PTR_ERR(dev_list);
19562306a36Sopenharmony_ci		for (i = 0; dev_list[i]; i++) {
19662306a36Sopenharmony_ci			dev = dev_list[i];
19762306a36Sopenharmony_ci			vf = dev_get_drvdata(dev);
19862306a36Sopenharmony_ci			mutex_lock(&vf->lock);
19962306a36Sopenharmony_ci			vnic = vf->vnic;
20062306a36Sopenharmony_ci			if (!usnic_vnic_check_room(vnic, res_spec)) {
20162306a36Sopenharmony_ci				usnic_dbg("Found used vnic %s from %s\n",
20262306a36Sopenharmony_ci						dev_name(&us_ibdev->ib_dev.dev),
20362306a36Sopenharmony_ci						pci_name(usnic_vnic_get_pdev(
20462306a36Sopenharmony_ci									vnic)));
20562306a36Sopenharmony_ci				ret = usnic_ib_qp_grp_create(qp_grp,
20662306a36Sopenharmony_ci							     us_ibdev->ufdev,
20762306a36Sopenharmony_ci							     vf, pd, res_spec,
20862306a36Sopenharmony_ci							     trans_spec);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci				mutex_unlock(&vf->lock);
21162306a36Sopenharmony_ci				goto qp_grp_check;
21262306a36Sopenharmony_ci			}
21362306a36Sopenharmony_ci			mutex_unlock(&vf->lock);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		}
21662306a36Sopenharmony_ci		usnic_uiom_free_dev_list(dev_list);
21762306a36Sopenharmony_ci		dev_list = NULL;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/* Try to find resources on an unused vf */
22162306a36Sopenharmony_ci	list_for_each_entry(vf, &us_ibdev->vf_dev_list, link) {
22262306a36Sopenharmony_ci		mutex_lock(&vf->lock);
22362306a36Sopenharmony_ci		vnic = vf->vnic;
22462306a36Sopenharmony_ci		if (vf->qp_grp_ref_cnt == 0 &&
22562306a36Sopenharmony_ci		    usnic_vnic_check_room(vnic, res_spec) == 0) {
22662306a36Sopenharmony_ci			ret = usnic_ib_qp_grp_create(qp_grp, us_ibdev->ufdev,
22762306a36Sopenharmony_ci						     vf, pd, res_spec,
22862306a36Sopenharmony_ci						     trans_spec);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci			mutex_unlock(&vf->lock);
23162306a36Sopenharmony_ci			goto qp_grp_check;
23262306a36Sopenharmony_ci		}
23362306a36Sopenharmony_ci		mutex_unlock(&vf->lock);
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	usnic_info("No free qp grp found on %s\n",
23762306a36Sopenharmony_ci		   dev_name(&us_ibdev->ib_dev.dev));
23862306a36Sopenharmony_ci	return -ENOMEM;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ciqp_grp_check:
24162306a36Sopenharmony_ci	if (ret) {
24262306a36Sopenharmony_ci		usnic_err("Failed to allocate qp_grp\n");
24362306a36Sopenharmony_ci		if (usnic_ib_share_vf)
24462306a36Sopenharmony_ci			usnic_uiom_free_dev_list(dev_list);
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci	return ret;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic void qp_grp_destroy(struct usnic_ib_qp_grp *qp_grp)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct usnic_ib_vf *vf = qp_grp->vf;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	WARN_ON(qp_grp->state != IB_QPS_RESET);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	mutex_lock(&vf->lock);
25662306a36Sopenharmony_ci	usnic_ib_qp_grp_destroy(qp_grp);
25762306a36Sopenharmony_ci	mutex_unlock(&vf->lock);
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic int create_qp_validate_user_data(struct usnic_ib_create_qp_cmd cmd)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	if (cmd.spec.trans_type <= USNIC_TRANSPORT_UNKNOWN ||
26362306a36Sopenharmony_ci			cmd.spec.trans_type >= USNIC_TRANSPORT_MAX)
26462306a36Sopenharmony_ci		return -EINVAL;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return 0;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/* Start of ib callback functions */
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cienum rdma_link_layer usnic_ib_port_link_layer(struct ib_device *device,
27262306a36Sopenharmony_ci					      u32 port_num)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	return IB_LINK_LAYER_ETHERNET;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ciint usnic_ib_query_device(struct ib_device *ibdev,
27862306a36Sopenharmony_ci			  struct ib_device_attr *props,
27962306a36Sopenharmony_ci			  struct ib_udata *uhw)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	struct usnic_ib_dev *us_ibdev = to_usdev(ibdev);
28262306a36Sopenharmony_ci	union ib_gid gid;
28362306a36Sopenharmony_ci	struct ethtool_drvinfo info;
28462306a36Sopenharmony_ci	int qp_per_vf;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	usnic_dbg("\n");
28762306a36Sopenharmony_ci	if (uhw->inlen || uhw->outlen)
28862306a36Sopenharmony_ci		return -EINVAL;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	mutex_lock(&us_ibdev->usdev_lock);
29162306a36Sopenharmony_ci	us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info);
29262306a36Sopenharmony_ci	memset(props, 0, sizeof(*props));
29362306a36Sopenharmony_ci	usnic_mac_ip_to_gid(us_ibdev->ufdev->mac, us_ibdev->ufdev->inaddr,
29462306a36Sopenharmony_ci			&gid.raw[0]);
29562306a36Sopenharmony_ci	memcpy(&props->sys_image_guid, &gid.global.interface_id,
29662306a36Sopenharmony_ci		sizeof(gid.global.interface_id));
29762306a36Sopenharmony_ci	usnic_ib_fw_string_to_u64(&info.fw_version[0], &props->fw_ver);
29862306a36Sopenharmony_ci	props->max_mr_size = USNIC_UIOM_MAX_MR_SIZE;
29962306a36Sopenharmony_ci	props->page_size_cap = USNIC_UIOM_PAGE_SIZE;
30062306a36Sopenharmony_ci	props->vendor_id = PCI_VENDOR_ID_CISCO;
30162306a36Sopenharmony_ci	props->vendor_part_id = PCI_DEVICE_ID_CISCO_VIC_USPACE_NIC;
30262306a36Sopenharmony_ci	props->hw_ver = us_ibdev->pdev->subsystem_device;
30362306a36Sopenharmony_ci	qp_per_vf = max(us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_WQ],
30462306a36Sopenharmony_ci			us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_RQ]);
30562306a36Sopenharmony_ci	props->max_qp = qp_per_vf *
30662306a36Sopenharmony_ci		kref_read(&us_ibdev->vf_cnt);
30762306a36Sopenharmony_ci	props->device_cap_flags = IB_DEVICE_PORT_ACTIVE_EVENT |
30862306a36Sopenharmony_ci		IB_DEVICE_SYS_IMAGE_GUID;
30962306a36Sopenharmony_ci	props->kernel_cap_flags = IBK_BLOCK_MULTICAST_LOOPBACK;
31062306a36Sopenharmony_ci	props->max_cq = us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_CQ] *
31162306a36Sopenharmony_ci		kref_read(&us_ibdev->vf_cnt);
31262306a36Sopenharmony_ci	props->max_pd = USNIC_UIOM_MAX_PD_CNT;
31362306a36Sopenharmony_ci	props->max_mr = USNIC_UIOM_MAX_MR_CNT;
31462306a36Sopenharmony_ci	props->local_ca_ack_delay = 0;
31562306a36Sopenharmony_ci	props->max_pkeys = 0;
31662306a36Sopenharmony_ci	props->atomic_cap = IB_ATOMIC_NONE;
31762306a36Sopenharmony_ci	props->masked_atomic_cap = props->atomic_cap;
31862306a36Sopenharmony_ci	props->max_qp_rd_atom = 0;
31962306a36Sopenharmony_ci	props->max_qp_init_rd_atom = 0;
32062306a36Sopenharmony_ci	props->max_res_rd_atom = 0;
32162306a36Sopenharmony_ci	props->max_srq = 0;
32262306a36Sopenharmony_ci	props->max_srq_wr = 0;
32362306a36Sopenharmony_ci	props->max_srq_sge = 0;
32462306a36Sopenharmony_ci	props->max_fast_reg_page_list_len = 0;
32562306a36Sopenharmony_ci	props->max_mcast_grp = 0;
32662306a36Sopenharmony_ci	props->max_mcast_qp_attach = 0;
32762306a36Sopenharmony_ci	props->max_total_mcast_qp_attach = 0;
32862306a36Sopenharmony_ci	/* Owned by Userspace
32962306a36Sopenharmony_ci	 * max_qp_wr, max_sge, max_sge_rd, max_cqe */
33062306a36Sopenharmony_ci	mutex_unlock(&us_ibdev->usdev_lock);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return 0;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ciint usnic_ib_query_port(struct ib_device *ibdev, u32 port,
33662306a36Sopenharmony_ci				struct ib_port_attr *props)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct usnic_ib_dev *us_ibdev = to_usdev(ibdev);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	usnic_dbg("\n");
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (ib_get_eth_speed(ibdev, port, &props->active_speed,
34362306a36Sopenharmony_ci			     &props->active_width))
34462306a36Sopenharmony_ci		return -EINVAL;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	/*
34762306a36Sopenharmony_ci	 * usdev_lock is acquired after (and not before) ib_get_eth_speed call
34862306a36Sopenharmony_ci	 * because acquiring rtnl_lock in ib_get_eth_speed, while holding
34962306a36Sopenharmony_ci	 * usdev_lock could lead to a deadlock.
35062306a36Sopenharmony_ci	 */
35162306a36Sopenharmony_ci	mutex_lock(&us_ibdev->usdev_lock);
35262306a36Sopenharmony_ci	/* props being zeroed by the caller, avoid zeroing it here */
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	props->lid = 0;
35562306a36Sopenharmony_ci	props->lmc = 1;
35662306a36Sopenharmony_ci	props->sm_lid = 0;
35762306a36Sopenharmony_ci	props->sm_sl = 0;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (!us_ibdev->ufdev->link_up) {
36062306a36Sopenharmony_ci		props->state = IB_PORT_DOWN;
36162306a36Sopenharmony_ci		props->phys_state = IB_PORT_PHYS_STATE_DISABLED;
36262306a36Sopenharmony_ci	} else if (!us_ibdev->ufdev->inaddr) {
36362306a36Sopenharmony_ci		props->state = IB_PORT_INIT;
36462306a36Sopenharmony_ci		props->phys_state =
36562306a36Sopenharmony_ci			IB_PORT_PHYS_STATE_PORT_CONFIGURATION_TRAINING;
36662306a36Sopenharmony_ci	} else {
36762306a36Sopenharmony_ci		props->state = IB_PORT_ACTIVE;
36862306a36Sopenharmony_ci		props->phys_state = IB_PORT_PHYS_STATE_LINK_UP;
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	props->port_cap_flags = 0;
37262306a36Sopenharmony_ci	props->gid_tbl_len = 1;
37362306a36Sopenharmony_ci	props->bad_pkey_cntr = 0;
37462306a36Sopenharmony_ci	props->qkey_viol_cntr = 0;
37562306a36Sopenharmony_ci	props->max_mtu = IB_MTU_4096;
37662306a36Sopenharmony_ci	props->active_mtu = iboe_get_mtu(us_ibdev->ufdev->mtu);
37762306a36Sopenharmony_ci	/* Userspace will adjust for hdrs */
37862306a36Sopenharmony_ci	props->max_msg_sz = us_ibdev->ufdev->mtu;
37962306a36Sopenharmony_ci	props->max_vl_num = 1;
38062306a36Sopenharmony_ci	mutex_unlock(&us_ibdev->usdev_lock);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	return 0;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ciint usnic_ib_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr,
38662306a36Sopenharmony_ci				int qp_attr_mask,
38762306a36Sopenharmony_ci				struct ib_qp_init_attr *qp_init_attr)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct usnic_ib_qp_grp *qp_grp;
39062306a36Sopenharmony_ci	struct usnic_ib_vf *vf;
39162306a36Sopenharmony_ci	int err;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	usnic_dbg("\n");
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	memset(qp_attr, 0, sizeof(*qp_attr));
39662306a36Sopenharmony_ci	memset(qp_init_attr, 0, sizeof(*qp_init_attr));
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	qp_grp = to_uqp_grp(qp);
39962306a36Sopenharmony_ci	vf = qp_grp->vf;
40062306a36Sopenharmony_ci	mutex_lock(&vf->pf->usdev_lock);
40162306a36Sopenharmony_ci	usnic_dbg("\n");
40262306a36Sopenharmony_ci	qp_attr->qp_state = qp_grp->state;
40362306a36Sopenharmony_ci	qp_attr->cur_qp_state = qp_grp->state;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	switch (qp_grp->ibqp.qp_type) {
40662306a36Sopenharmony_ci	case IB_QPT_UD:
40762306a36Sopenharmony_ci		qp_attr->qkey = 0;
40862306a36Sopenharmony_ci		break;
40962306a36Sopenharmony_ci	default:
41062306a36Sopenharmony_ci		usnic_err("Unexpected qp_type %d\n", qp_grp->ibqp.qp_type);
41162306a36Sopenharmony_ci		err = -EINVAL;
41262306a36Sopenharmony_ci		goto err_out;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	mutex_unlock(&vf->pf->usdev_lock);
41662306a36Sopenharmony_ci	return 0;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cierr_out:
41962306a36Sopenharmony_ci	mutex_unlock(&vf->pf->usdev_lock);
42062306a36Sopenharmony_ci	return err;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ciint usnic_ib_query_gid(struct ib_device *ibdev, u32 port, int index,
42462306a36Sopenharmony_ci				union ib_gid *gid)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	struct usnic_ib_dev *us_ibdev = to_usdev(ibdev);
42862306a36Sopenharmony_ci	usnic_dbg("\n");
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	if (index > 1)
43162306a36Sopenharmony_ci		return -EINVAL;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	mutex_lock(&us_ibdev->usdev_lock);
43462306a36Sopenharmony_ci	memset(&(gid->raw[0]), 0, sizeof(gid->raw));
43562306a36Sopenharmony_ci	usnic_mac_ip_to_gid(us_ibdev->ufdev->mac, us_ibdev->ufdev->inaddr,
43662306a36Sopenharmony_ci			&gid->raw[0]);
43762306a36Sopenharmony_ci	mutex_unlock(&us_ibdev->usdev_lock);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	return 0;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ciint usnic_ib_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	struct usnic_ib_pd *pd = to_upd(ibpd);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	pd->umem_pd = usnic_uiom_alloc_pd(ibpd->device->dev.parent);
44762306a36Sopenharmony_ci	if (IS_ERR(pd->umem_pd))
44862306a36Sopenharmony_ci		return PTR_ERR(pd->umem_pd);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	return 0;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ciint usnic_ib_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	usnic_uiom_dealloc_pd((to_upd(pd))->umem_pd);
45662306a36Sopenharmony_ci	return 0;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ciint usnic_ib_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr,
46062306a36Sopenharmony_ci		       struct ib_udata *udata)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	int err;
46362306a36Sopenharmony_ci	struct usnic_ib_dev *us_ibdev;
46462306a36Sopenharmony_ci	struct usnic_ib_qp_grp *qp_grp = to_uqp_grp(ibqp);
46562306a36Sopenharmony_ci	struct usnic_ib_ucontext *ucontext = rdma_udata_to_drv_context(
46662306a36Sopenharmony_ci		udata, struct usnic_ib_ucontext, ibucontext);
46762306a36Sopenharmony_ci	int cq_cnt;
46862306a36Sopenharmony_ci	struct usnic_vnic_res_spec res_spec;
46962306a36Sopenharmony_ci	struct usnic_ib_create_qp_cmd cmd;
47062306a36Sopenharmony_ci	struct usnic_transport_spec trans_spec;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	usnic_dbg("\n");
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	us_ibdev = to_usdev(ibqp->device);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	if (init_attr->create_flags)
47762306a36Sopenharmony_ci		return -EOPNOTSUPP;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	err = ib_copy_from_udata(&cmd, udata, sizeof(cmd));
48062306a36Sopenharmony_ci	if (err) {
48162306a36Sopenharmony_ci		usnic_err("%s: cannot copy udata for create_qp\n",
48262306a36Sopenharmony_ci			  dev_name(&us_ibdev->ib_dev.dev));
48362306a36Sopenharmony_ci		return -EINVAL;
48462306a36Sopenharmony_ci	}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	err = create_qp_validate_user_data(cmd);
48762306a36Sopenharmony_ci	if (err) {
48862306a36Sopenharmony_ci		usnic_err("%s: Failed to validate user data\n",
48962306a36Sopenharmony_ci			  dev_name(&us_ibdev->ib_dev.dev));
49062306a36Sopenharmony_ci		return -EINVAL;
49162306a36Sopenharmony_ci	}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if (init_attr->qp_type != IB_QPT_UD) {
49462306a36Sopenharmony_ci		usnic_err("%s asked to make a non-UD QP: %d\n",
49562306a36Sopenharmony_ci			  dev_name(&us_ibdev->ib_dev.dev), init_attr->qp_type);
49662306a36Sopenharmony_ci		return -EOPNOTSUPP;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	trans_spec = cmd.spec;
50062306a36Sopenharmony_ci	mutex_lock(&us_ibdev->usdev_lock);
50162306a36Sopenharmony_ci	cq_cnt = (init_attr->send_cq == init_attr->recv_cq) ? 1 : 2;
50262306a36Sopenharmony_ci	res_spec = min_transport_spec[trans_spec.trans_type];
50362306a36Sopenharmony_ci	usnic_vnic_res_spec_update(&res_spec, USNIC_VNIC_RES_TYPE_CQ, cq_cnt);
50462306a36Sopenharmony_ci	err = find_free_vf_and_create_qp_grp(ibqp, &trans_spec, &res_spec);
50562306a36Sopenharmony_ci	if (err)
50662306a36Sopenharmony_ci		goto out_release_mutex;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	err = usnic_ib_fill_create_qp_resp(qp_grp, udata);
50962306a36Sopenharmony_ci	if (err) {
51062306a36Sopenharmony_ci		err = -EBUSY;
51162306a36Sopenharmony_ci		goto out_release_qp_grp;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	qp_grp->ctx = ucontext;
51562306a36Sopenharmony_ci	list_add_tail(&qp_grp->link, &ucontext->qp_grp_list);
51662306a36Sopenharmony_ci	usnic_ib_log_vf(qp_grp->vf);
51762306a36Sopenharmony_ci	mutex_unlock(&us_ibdev->usdev_lock);
51862306a36Sopenharmony_ci	return 0;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ciout_release_qp_grp:
52162306a36Sopenharmony_ci	qp_grp_destroy(qp_grp);
52262306a36Sopenharmony_ciout_release_mutex:
52362306a36Sopenharmony_ci	mutex_unlock(&us_ibdev->usdev_lock);
52462306a36Sopenharmony_ci	return err;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ciint usnic_ib_destroy_qp(struct ib_qp *qp, struct ib_udata *udata)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct usnic_ib_qp_grp *qp_grp;
53062306a36Sopenharmony_ci	struct usnic_ib_vf *vf;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	usnic_dbg("\n");
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	qp_grp = to_uqp_grp(qp);
53562306a36Sopenharmony_ci	vf = qp_grp->vf;
53662306a36Sopenharmony_ci	mutex_lock(&vf->pf->usdev_lock);
53762306a36Sopenharmony_ci	if (usnic_ib_qp_grp_modify(qp_grp, IB_QPS_RESET, NULL)) {
53862306a36Sopenharmony_ci		usnic_err("Failed to move qp grp %u to reset\n",
53962306a36Sopenharmony_ci				qp_grp->grp_id);
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	list_del(&qp_grp->link);
54362306a36Sopenharmony_ci	qp_grp_destroy(qp_grp);
54462306a36Sopenharmony_ci	mutex_unlock(&vf->pf->usdev_lock);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	return 0;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ciint usnic_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
55062306a36Sopenharmony_ci				int attr_mask, struct ib_udata *udata)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	struct usnic_ib_qp_grp *qp_grp;
55362306a36Sopenharmony_ci	int status;
55462306a36Sopenharmony_ci	usnic_dbg("\n");
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
55762306a36Sopenharmony_ci		return -EOPNOTSUPP;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	qp_grp = to_uqp_grp(ibqp);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	mutex_lock(&qp_grp->vf->pf->usdev_lock);
56262306a36Sopenharmony_ci	if ((attr_mask & IB_QP_PORT) && attr->port_num != 1) {
56362306a36Sopenharmony_ci		/* usnic devices only have one port */
56462306a36Sopenharmony_ci		status = -EINVAL;
56562306a36Sopenharmony_ci		goto out_unlock;
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci	if (attr_mask & IB_QP_STATE) {
56862306a36Sopenharmony_ci		status = usnic_ib_qp_grp_modify(qp_grp, attr->qp_state, NULL);
56962306a36Sopenharmony_ci	} else {
57062306a36Sopenharmony_ci		usnic_err("Unhandled request, attr_mask=0x%x\n", attr_mask);
57162306a36Sopenharmony_ci		status = -EINVAL;
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ciout_unlock:
57562306a36Sopenharmony_ci	mutex_unlock(&qp_grp->vf->pf->usdev_lock);
57662306a36Sopenharmony_ci	return status;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ciint usnic_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
58062306a36Sopenharmony_ci		       struct ib_udata *udata)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	if (attr->flags)
58362306a36Sopenharmony_ci		return -EOPNOTSUPP;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	return 0;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ciint usnic_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	return 0;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistruct ib_mr *usnic_ib_reg_mr(struct ib_pd *pd, u64 start, u64 length,
59462306a36Sopenharmony_ci					u64 virt_addr, int access_flags,
59562306a36Sopenharmony_ci					struct ib_udata *udata)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	struct usnic_ib_mr *mr;
59862306a36Sopenharmony_ci	int err;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	usnic_dbg("start 0x%llx va 0x%llx length 0x%llx\n", start,
60162306a36Sopenharmony_ci			virt_addr, length);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
60462306a36Sopenharmony_ci	if (!mr)
60562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	mr->umem = usnic_uiom_reg_get(to_upd(pd)->umem_pd, start, length,
60862306a36Sopenharmony_ci					access_flags, 0);
60962306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(mr->umem)) {
61062306a36Sopenharmony_ci		err = mr->umem ? PTR_ERR(mr->umem) : -EFAULT;
61162306a36Sopenharmony_ci		goto err_free;
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	mr->ibmr.lkey = mr->ibmr.rkey = 0;
61562306a36Sopenharmony_ci	return &mr->ibmr;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cierr_free:
61862306a36Sopenharmony_ci	kfree(mr);
61962306a36Sopenharmony_ci	return ERR_PTR(err);
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ciint usnic_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	struct usnic_ib_mr *mr = to_umr(ibmr);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	usnic_dbg("va 0x%lx length 0x%zx\n", mr->umem->va, mr->umem->length);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	usnic_uiom_reg_release(mr->umem);
62962306a36Sopenharmony_ci	kfree(mr);
63062306a36Sopenharmony_ci	return 0;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ciint usnic_ib_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct ib_device *ibdev = uctx->device;
63662306a36Sopenharmony_ci	struct usnic_ib_ucontext *context = to_ucontext(uctx);
63762306a36Sopenharmony_ci	struct usnic_ib_dev *us_ibdev = to_usdev(ibdev);
63862306a36Sopenharmony_ci	usnic_dbg("\n");
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	INIT_LIST_HEAD(&context->qp_grp_list);
64162306a36Sopenharmony_ci	mutex_lock(&us_ibdev->usdev_lock);
64262306a36Sopenharmony_ci	list_add_tail(&context->link, &us_ibdev->ctx_list);
64362306a36Sopenharmony_ci	mutex_unlock(&us_ibdev->usdev_lock);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	return 0;
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_civoid usnic_ib_dealloc_ucontext(struct ib_ucontext *ibcontext)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	struct usnic_ib_ucontext *context = to_uucontext(ibcontext);
65162306a36Sopenharmony_ci	struct usnic_ib_dev *us_ibdev = to_usdev(ibcontext->device);
65262306a36Sopenharmony_ci	usnic_dbg("\n");
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	mutex_lock(&us_ibdev->usdev_lock);
65562306a36Sopenharmony_ci	WARN_ON_ONCE(!list_empty(&context->qp_grp_list));
65662306a36Sopenharmony_ci	list_del(&context->link);
65762306a36Sopenharmony_ci	mutex_unlock(&us_ibdev->usdev_lock);
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ciint usnic_ib_mmap(struct ib_ucontext *context,
66162306a36Sopenharmony_ci				struct vm_area_struct *vma)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	struct usnic_ib_ucontext *uctx = to_ucontext(context);
66462306a36Sopenharmony_ci	struct usnic_ib_dev *us_ibdev;
66562306a36Sopenharmony_ci	struct usnic_ib_qp_grp *qp_grp;
66662306a36Sopenharmony_ci	struct usnic_ib_vf *vf;
66762306a36Sopenharmony_ci	struct vnic_dev_bar *bar;
66862306a36Sopenharmony_ci	dma_addr_t bus_addr;
66962306a36Sopenharmony_ci	unsigned int len;
67062306a36Sopenharmony_ci	unsigned int vfid;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	usnic_dbg("\n");
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	us_ibdev = to_usdev(context->device);
67562306a36Sopenharmony_ci	vm_flags_set(vma, VM_IO);
67662306a36Sopenharmony_ci	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
67762306a36Sopenharmony_ci	vfid = vma->vm_pgoff;
67862306a36Sopenharmony_ci	usnic_dbg("Page Offset %lu PAGE_SHIFT %u VFID %u\n",
67962306a36Sopenharmony_ci			vma->vm_pgoff, PAGE_SHIFT, vfid);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	mutex_lock(&us_ibdev->usdev_lock);
68262306a36Sopenharmony_ci	list_for_each_entry(qp_grp, &uctx->qp_grp_list, link) {
68362306a36Sopenharmony_ci		vf = qp_grp->vf;
68462306a36Sopenharmony_ci		if (usnic_vnic_get_index(vf->vnic) == vfid) {
68562306a36Sopenharmony_ci			bar = usnic_vnic_get_bar(vf->vnic, 0);
68662306a36Sopenharmony_ci			if ((vma->vm_end - vma->vm_start) != bar->len) {
68762306a36Sopenharmony_ci				usnic_err("Bar0 Len %lu - Request map %lu\n",
68862306a36Sopenharmony_ci						bar->len,
68962306a36Sopenharmony_ci						vma->vm_end - vma->vm_start);
69062306a36Sopenharmony_ci				mutex_unlock(&us_ibdev->usdev_lock);
69162306a36Sopenharmony_ci				return -EINVAL;
69262306a36Sopenharmony_ci			}
69362306a36Sopenharmony_ci			bus_addr = bar->bus_addr;
69462306a36Sopenharmony_ci			len = bar->len;
69562306a36Sopenharmony_ci			usnic_dbg("bus: %pa vaddr: %p size: %ld\n",
69662306a36Sopenharmony_ci					&bus_addr, bar->vaddr, bar->len);
69762306a36Sopenharmony_ci			mutex_unlock(&us_ibdev->usdev_lock);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci			return remap_pfn_range(vma,
70062306a36Sopenharmony_ci						vma->vm_start,
70162306a36Sopenharmony_ci						bus_addr >> PAGE_SHIFT,
70262306a36Sopenharmony_ci						len, vma->vm_page_prot);
70362306a36Sopenharmony_ci		}
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	mutex_unlock(&us_ibdev->usdev_lock);
70762306a36Sopenharmony_ci	usnic_err("No VF %u found\n", vfid);
70862306a36Sopenharmony_ci	return -EINVAL;
70962306a36Sopenharmony_ci}
710