xref: /OK3568_Linux_fs/kernel/drivers/infiniband/hw/usnic/usnic_ib_verbs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This software is available to you under a choice of one of two
5*4882a593Smuzhiyun  * licenses.  You may choose to be licensed under the terms of the GNU
6*4882a593Smuzhiyun  * General Public License (GPL) Version 2, available from the file
7*4882a593Smuzhiyun  * COPYING in the main directory of this source tree, or the
8*4882a593Smuzhiyun  * BSD license below:
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  *     Redistribution and use in source and binary forms, with or
11*4882a593Smuzhiyun  *     without modification, are permitted provided that the following
12*4882a593Smuzhiyun  *     conditions are met:
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  *      - Redistributions of source code must retain the above
15*4882a593Smuzhiyun  *        copyright notice, this list of conditions and the following
16*4882a593Smuzhiyun  *        disclaimer.
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  *      - Redistributions in binary form must reproduce the above
19*4882a593Smuzhiyun  *        copyright notice, this list of conditions and the following
20*4882a593Smuzhiyun  *        disclaimer in the documentation and/or other materials
21*4882a593Smuzhiyun  *        provided with the distribution.
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24*4882a593Smuzhiyun  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25*4882a593Smuzhiyun  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26*4882a593Smuzhiyun  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27*4882a593Smuzhiyun  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28*4882a593Smuzhiyun  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29*4882a593Smuzhiyun  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30*4882a593Smuzhiyun  * SOFTWARE.
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  */
33*4882a593Smuzhiyun #include <linux/module.h>
34*4882a593Smuzhiyun #include <linux/init.h>
35*4882a593Smuzhiyun #include <linux/slab.h>
36*4882a593Smuzhiyun #include <linux/errno.h>
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #include <rdma/ib_user_verbs.h>
39*4882a593Smuzhiyun #include <rdma/ib_addr.h>
40*4882a593Smuzhiyun #include <rdma/uverbs_ioctl.h>
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #include "usnic_abi.h"
43*4882a593Smuzhiyun #include "usnic_ib.h"
44*4882a593Smuzhiyun #include "usnic_common_util.h"
45*4882a593Smuzhiyun #include "usnic_ib_qp_grp.h"
46*4882a593Smuzhiyun #include "usnic_ib_verbs.h"
47*4882a593Smuzhiyun #include "usnic_fwd.h"
48*4882a593Smuzhiyun #include "usnic_log.h"
49*4882a593Smuzhiyun #include "usnic_uiom.h"
50*4882a593Smuzhiyun #include "usnic_transport.h"
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #define USNIC_DEFAULT_TRANSPORT USNIC_TRANSPORT_ROCE_CUSTOM
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun const struct usnic_vnic_res_spec min_transport_spec[USNIC_TRANSPORT_MAX] = {
55*4882a593Smuzhiyun 	{ /*USNIC_TRANSPORT_UNKNOWN*/
56*4882a593Smuzhiyun 		.resources = {
57*4882a593Smuzhiyun 			{.type = USNIC_VNIC_RES_TYPE_EOL,	.cnt = 0,},
58*4882a593Smuzhiyun 		},
59*4882a593Smuzhiyun 	},
60*4882a593Smuzhiyun 	{ /*USNIC_TRANSPORT_ROCE_CUSTOM*/
61*4882a593Smuzhiyun 		.resources = {
62*4882a593Smuzhiyun 			{.type = USNIC_VNIC_RES_TYPE_WQ,	.cnt = 1,},
63*4882a593Smuzhiyun 			{.type = USNIC_VNIC_RES_TYPE_RQ,	.cnt = 1,},
64*4882a593Smuzhiyun 			{.type = USNIC_VNIC_RES_TYPE_CQ,	.cnt = 1,},
65*4882a593Smuzhiyun 			{.type = USNIC_VNIC_RES_TYPE_EOL,	.cnt = 0,},
66*4882a593Smuzhiyun 		},
67*4882a593Smuzhiyun 	},
68*4882a593Smuzhiyun 	{ /*USNIC_TRANSPORT_IPV4_UDP*/
69*4882a593Smuzhiyun 		.resources = {
70*4882a593Smuzhiyun 			{.type = USNIC_VNIC_RES_TYPE_WQ,	.cnt = 1,},
71*4882a593Smuzhiyun 			{.type = USNIC_VNIC_RES_TYPE_RQ,	.cnt = 1,},
72*4882a593Smuzhiyun 			{.type = USNIC_VNIC_RES_TYPE_CQ,	.cnt = 1,},
73*4882a593Smuzhiyun 			{.type = USNIC_VNIC_RES_TYPE_EOL,	.cnt = 0,},
74*4882a593Smuzhiyun 		},
75*4882a593Smuzhiyun 	},
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun 
usnic_ib_fw_string_to_u64(char * fw_ver_str,u64 * fw_ver)78*4882a593Smuzhiyun static void usnic_ib_fw_string_to_u64(char *fw_ver_str, u64 *fw_ver)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	*fw_ver = *((u64 *)fw_ver_str);
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun 
usnic_ib_fill_create_qp_resp(struct usnic_ib_qp_grp * qp_grp,struct ib_udata * udata)83*4882a593Smuzhiyun static int usnic_ib_fill_create_qp_resp(struct usnic_ib_qp_grp *qp_grp,
84*4882a593Smuzhiyun 					struct ib_udata *udata)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	struct usnic_ib_dev *us_ibdev;
87*4882a593Smuzhiyun 	struct usnic_ib_create_qp_resp resp;
88*4882a593Smuzhiyun 	struct pci_dev *pdev;
89*4882a593Smuzhiyun 	struct vnic_dev_bar *bar;
90*4882a593Smuzhiyun 	struct usnic_vnic_res_chunk *chunk;
91*4882a593Smuzhiyun 	struct usnic_ib_qp_grp_flow *default_flow;
92*4882a593Smuzhiyun 	int i, err;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	memset(&resp, 0, sizeof(resp));
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	us_ibdev = qp_grp->vf->pf;
97*4882a593Smuzhiyun 	pdev = usnic_vnic_get_pdev(qp_grp->vf->vnic);
98*4882a593Smuzhiyun 	if (!pdev) {
99*4882a593Smuzhiyun 		usnic_err("Failed to get pdev of qp_grp %d\n",
100*4882a593Smuzhiyun 				qp_grp->grp_id);
101*4882a593Smuzhiyun 		return -EFAULT;
102*4882a593Smuzhiyun 	}
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	bar = usnic_vnic_get_bar(qp_grp->vf->vnic, 0);
105*4882a593Smuzhiyun 	if (!bar) {
106*4882a593Smuzhiyun 		usnic_err("Failed to get bar0 of qp_grp %d vf %s",
107*4882a593Smuzhiyun 				qp_grp->grp_id, pci_name(pdev));
108*4882a593Smuzhiyun 		return -EFAULT;
109*4882a593Smuzhiyun 	}
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	resp.vfid = usnic_vnic_get_index(qp_grp->vf->vnic);
112*4882a593Smuzhiyun 	resp.bar_bus_addr = bar->bus_addr;
113*4882a593Smuzhiyun 	resp.bar_len = bar->len;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ);
116*4882a593Smuzhiyun 	if (IS_ERR(chunk)) {
117*4882a593Smuzhiyun 		usnic_err("Failed to get chunk %s for qp_grp %d with err %ld\n",
118*4882a593Smuzhiyun 			usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_RQ),
119*4882a593Smuzhiyun 			qp_grp->grp_id,
120*4882a593Smuzhiyun 			PTR_ERR(chunk));
121*4882a593Smuzhiyun 		return PTR_ERR(chunk);
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	WARN_ON(chunk->type != USNIC_VNIC_RES_TYPE_RQ);
125*4882a593Smuzhiyun 	resp.rq_cnt = chunk->cnt;
126*4882a593Smuzhiyun 	for (i = 0; i < chunk->cnt; i++)
127*4882a593Smuzhiyun 		resp.rq_idx[i] = chunk->res[i]->vnic_idx;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_WQ);
130*4882a593Smuzhiyun 	if (IS_ERR(chunk)) {
131*4882a593Smuzhiyun 		usnic_err("Failed to get chunk %s for qp_grp %d with err %ld\n",
132*4882a593Smuzhiyun 			usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_WQ),
133*4882a593Smuzhiyun 			qp_grp->grp_id,
134*4882a593Smuzhiyun 			PTR_ERR(chunk));
135*4882a593Smuzhiyun 		return PTR_ERR(chunk);
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	WARN_ON(chunk->type != USNIC_VNIC_RES_TYPE_WQ);
139*4882a593Smuzhiyun 	resp.wq_cnt = chunk->cnt;
140*4882a593Smuzhiyun 	for (i = 0; i < chunk->cnt; i++)
141*4882a593Smuzhiyun 		resp.wq_idx[i] = chunk->res[i]->vnic_idx;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_CQ);
144*4882a593Smuzhiyun 	if (IS_ERR(chunk)) {
145*4882a593Smuzhiyun 		usnic_err("Failed to get chunk %s for qp_grp %d with err %ld\n",
146*4882a593Smuzhiyun 			usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_CQ),
147*4882a593Smuzhiyun 			qp_grp->grp_id,
148*4882a593Smuzhiyun 			PTR_ERR(chunk));
149*4882a593Smuzhiyun 		return PTR_ERR(chunk);
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	WARN_ON(chunk->type != USNIC_VNIC_RES_TYPE_CQ);
153*4882a593Smuzhiyun 	resp.cq_cnt = chunk->cnt;
154*4882a593Smuzhiyun 	for (i = 0; i < chunk->cnt; i++)
155*4882a593Smuzhiyun 		resp.cq_idx[i] = chunk->res[i]->vnic_idx;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	default_flow = list_first_entry(&qp_grp->flows_lst,
158*4882a593Smuzhiyun 					struct usnic_ib_qp_grp_flow, link);
159*4882a593Smuzhiyun 	resp.transport = default_flow->trans_type;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	err = ib_copy_to_udata(udata, &resp, sizeof(resp));
162*4882a593Smuzhiyun 	if (err) {
163*4882a593Smuzhiyun 		usnic_err("Failed to copy udata for %s",
164*4882a593Smuzhiyun 			  dev_name(&us_ibdev->ib_dev.dev));
165*4882a593Smuzhiyun 		return err;
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	return 0;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun static struct usnic_ib_qp_grp*
find_free_vf_and_create_qp_grp(struct usnic_ib_dev * us_ibdev,struct usnic_ib_pd * pd,struct usnic_transport_spec * trans_spec,struct usnic_vnic_res_spec * res_spec)172*4882a593Smuzhiyun find_free_vf_and_create_qp_grp(struct usnic_ib_dev *us_ibdev,
173*4882a593Smuzhiyun 				struct usnic_ib_pd *pd,
174*4882a593Smuzhiyun 				struct usnic_transport_spec *trans_spec,
175*4882a593Smuzhiyun 				struct usnic_vnic_res_spec *res_spec)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	struct usnic_ib_vf *vf;
178*4882a593Smuzhiyun 	struct usnic_vnic *vnic;
179*4882a593Smuzhiyun 	struct usnic_ib_qp_grp *qp_grp;
180*4882a593Smuzhiyun 	struct device *dev, **dev_list;
181*4882a593Smuzhiyun 	int i;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	BUG_ON(!mutex_is_locked(&us_ibdev->usdev_lock));
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	if (list_empty(&us_ibdev->vf_dev_list)) {
186*4882a593Smuzhiyun 		usnic_info("No vfs to allocate\n");
187*4882a593Smuzhiyun 		return NULL;
188*4882a593Smuzhiyun 	}
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	if (usnic_ib_share_vf) {
191*4882a593Smuzhiyun 		/* Try to find resouces on a used vf which is in pd */
192*4882a593Smuzhiyun 		dev_list = usnic_uiom_get_dev_list(pd->umem_pd);
193*4882a593Smuzhiyun 		if (IS_ERR(dev_list))
194*4882a593Smuzhiyun 			return ERR_CAST(dev_list);
195*4882a593Smuzhiyun 		for (i = 0; dev_list[i]; i++) {
196*4882a593Smuzhiyun 			dev = dev_list[i];
197*4882a593Smuzhiyun 			vf = dev_get_drvdata(dev);
198*4882a593Smuzhiyun 			spin_lock(&vf->lock);
199*4882a593Smuzhiyun 			vnic = vf->vnic;
200*4882a593Smuzhiyun 			if (!usnic_vnic_check_room(vnic, res_spec)) {
201*4882a593Smuzhiyun 				usnic_dbg("Found used vnic %s from %s\n",
202*4882a593Smuzhiyun 						dev_name(&us_ibdev->ib_dev.dev),
203*4882a593Smuzhiyun 						pci_name(usnic_vnic_get_pdev(
204*4882a593Smuzhiyun 									vnic)));
205*4882a593Smuzhiyun 				qp_grp = usnic_ib_qp_grp_create(us_ibdev->ufdev,
206*4882a593Smuzhiyun 								vf, pd,
207*4882a593Smuzhiyun 								res_spec,
208*4882a593Smuzhiyun 								trans_spec);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 				spin_unlock(&vf->lock);
211*4882a593Smuzhiyun 				goto qp_grp_check;
212*4882a593Smuzhiyun 			}
213*4882a593Smuzhiyun 			spin_unlock(&vf->lock);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 		}
216*4882a593Smuzhiyun 		usnic_uiom_free_dev_list(dev_list);
217*4882a593Smuzhiyun 		dev_list = NULL;
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	/* Try to find resources on an unused vf */
221*4882a593Smuzhiyun 	list_for_each_entry(vf, &us_ibdev->vf_dev_list, link) {
222*4882a593Smuzhiyun 		spin_lock(&vf->lock);
223*4882a593Smuzhiyun 		vnic = vf->vnic;
224*4882a593Smuzhiyun 		if (vf->qp_grp_ref_cnt == 0 &&
225*4882a593Smuzhiyun 		    usnic_vnic_check_room(vnic, res_spec) == 0) {
226*4882a593Smuzhiyun 			qp_grp = usnic_ib_qp_grp_create(us_ibdev->ufdev, vf,
227*4882a593Smuzhiyun 							pd, res_spec,
228*4882a593Smuzhiyun 							trans_spec);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 			spin_unlock(&vf->lock);
231*4882a593Smuzhiyun 			goto qp_grp_check;
232*4882a593Smuzhiyun 		}
233*4882a593Smuzhiyun 		spin_unlock(&vf->lock);
234*4882a593Smuzhiyun 	}
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	usnic_info("No free qp grp found on %s\n",
237*4882a593Smuzhiyun 		   dev_name(&us_ibdev->ib_dev.dev));
238*4882a593Smuzhiyun 	return ERR_PTR(-ENOMEM);
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun qp_grp_check:
241*4882a593Smuzhiyun 	if (IS_ERR_OR_NULL(qp_grp)) {
242*4882a593Smuzhiyun 		usnic_err("Failed to allocate qp_grp\n");
243*4882a593Smuzhiyun 		if (usnic_ib_share_vf)
244*4882a593Smuzhiyun 			usnic_uiom_free_dev_list(dev_list);
245*4882a593Smuzhiyun 		return ERR_PTR(qp_grp ? PTR_ERR(qp_grp) : -ENOMEM);
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 	return qp_grp;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun 
qp_grp_destroy(struct usnic_ib_qp_grp * qp_grp)250*4882a593Smuzhiyun static void qp_grp_destroy(struct usnic_ib_qp_grp *qp_grp)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	struct usnic_ib_vf *vf = qp_grp->vf;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	WARN_ON(qp_grp->state != IB_QPS_RESET);
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	spin_lock(&vf->lock);
257*4882a593Smuzhiyun 	usnic_ib_qp_grp_destroy(qp_grp);
258*4882a593Smuzhiyun 	spin_unlock(&vf->lock);
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun 
create_qp_validate_user_data(struct usnic_ib_create_qp_cmd cmd)261*4882a593Smuzhiyun static int create_qp_validate_user_data(struct usnic_ib_create_qp_cmd cmd)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun 	if (cmd.spec.trans_type <= USNIC_TRANSPORT_UNKNOWN ||
264*4882a593Smuzhiyun 			cmd.spec.trans_type >= USNIC_TRANSPORT_MAX)
265*4882a593Smuzhiyun 		return -EINVAL;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	return 0;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun /* Start of ib callback functions */
271*4882a593Smuzhiyun 
usnic_ib_port_link_layer(struct ib_device * device,u8 port_num)272*4882a593Smuzhiyun enum rdma_link_layer usnic_ib_port_link_layer(struct ib_device *device,
273*4882a593Smuzhiyun 						u8 port_num)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun 	return IB_LINK_LAYER_ETHERNET;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
usnic_ib_query_device(struct ib_device * ibdev,struct ib_device_attr * props,struct ib_udata * uhw)278*4882a593Smuzhiyun int usnic_ib_query_device(struct ib_device *ibdev,
279*4882a593Smuzhiyun 			  struct ib_device_attr *props,
280*4882a593Smuzhiyun 			  struct ib_udata *uhw)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun 	struct usnic_ib_dev *us_ibdev = to_usdev(ibdev);
283*4882a593Smuzhiyun 	union ib_gid gid;
284*4882a593Smuzhiyun 	struct ethtool_drvinfo info;
285*4882a593Smuzhiyun 	int qp_per_vf;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	usnic_dbg("\n");
288*4882a593Smuzhiyun 	if (uhw->inlen || uhw->outlen)
289*4882a593Smuzhiyun 		return -EINVAL;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	mutex_lock(&us_ibdev->usdev_lock);
292*4882a593Smuzhiyun 	us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info);
293*4882a593Smuzhiyun 	memset(props, 0, sizeof(*props));
294*4882a593Smuzhiyun 	usnic_mac_ip_to_gid(us_ibdev->ufdev->mac, us_ibdev->ufdev->inaddr,
295*4882a593Smuzhiyun 			&gid.raw[0]);
296*4882a593Smuzhiyun 	memcpy(&props->sys_image_guid, &gid.global.interface_id,
297*4882a593Smuzhiyun 		sizeof(gid.global.interface_id));
298*4882a593Smuzhiyun 	usnic_ib_fw_string_to_u64(&info.fw_version[0], &props->fw_ver);
299*4882a593Smuzhiyun 	props->max_mr_size = USNIC_UIOM_MAX_MR_SIZE;
300*4882a593Smuzhiyun 	props->page_size_cap = USNIC_UIOM_PAGE_SIZE;
301*4882a593Smuzhiyun 	props->vendor_id = PCI_VENDOR_ID_CISCO;
302*4882a593Smuzhiyun 	props->vendor_part_id = PCI_DEVICE_ID_CISCO_VIC_USPACE_NIC;
303*4882a593Smuzhiyun 	props->hw_ver = us_ibdev->pdev->subsystem_device;
304*4882a593Smuzhiyun 	qp_per_vf = max(us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_WQ],
305*4882a593Smuzhiyun 			us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_RQ]);
306*4882a593Smuzhiyun 	props->max_qp = qp_per_vf *
307*4882a593Smuzhiyun 		kref_read(&us_ibdev->vf_cnt);
308*4882a593Smuzhiyun 	props->device_cap_flags = IB_DEVICE_PORT_ACTIVE_EVENT |
309*4882a593Smuzhiyun 		IB_DEVICE_SYS_IMAGE_GUID | IB_DEVICE_BLOCK_MULTICAST_LOOPBACK;
310*4882a593Smuzhiyun 	props->max_cq = us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_CQ] *
311*4882a593Smuzhiyun 		kref_read(&us_ibdev->vf_cnt);
312*4882a593Smuzhiyun 	props->max_pd = USNIC_UIOM_MAX_PD_CNT;
313*4882a593Smuzhiyun 	props->max_mr = USNIC_UIOM_MAX_MR_CNT;
314*4882a593Smuzhiyun 	props->local_ca_ack_delay = 0;
315*4882a593Smuzhiyun 	props->max_pkeys = 0;
316*4882a593Smuzhiyun 	props->atomic_cap = IB_ATOMIC_NONE;
317*4882a593Smuzhiyun 	props->masked_atomic_cap = props->atomic_cap;
318*4882a593Smuzhiyun 	props->max_qp_rd_atom = 0;
319*4882a593Smuzhiyun 	props->max_qp_init_rd_atom = 0;
320*4882a593Smuzhiyun 	props->max_res_rd_atom = 0;
321*4882a593Smuzhiyun 	props->max_srq = 0;
322*4882a593Smuzhiyun 	props->max_srq_wr = 0;
323*4882a593Smuzhiyun 	props->max_srq_sge = 0;
324*4882a593Smuzhiyun 	props->max_fast_reg_page_list_len = 0;
325*4882a593Smuzhiyun 	props->max_mcast_grp = 0;
326*4882a593Smuzhiyun 	props->max_mcast_qp_attach = 0;
327*4882a593Smuzhiyun 	props->max_total_mcast_qp_attach = 0;
328*4882a593Smuzhiyun 	/* Owned by Userspace
329*4882a593Smuzhiyun 	 * max_qp_wr, max_sge, max_sge_rd, max_cqe */
330*4882a593Smuzhiyun 	mutex_unlock(&us_ibdev->usdev_lock);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	return 0;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun 
usnic_ib_query_port(struct ib_device * ibdev,u8 port,struct ib_port_attr * props)335*4882a593Smuzhiyun int usnic_ib_query_port(struct ib_device *ibdev, u8 port,
336*4882a593Smuzhiyun 				struct ib_port_attr *props)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun 	struct usnic_ib_dev *us_ibdev = to_usdev(ibdev);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	usnic_dbg("\n");
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	if (ib_get_eth_speed(ibdev, port, &props->active_speed,
343*4882a593Smuzhiyun 			     &props->active_width))
344*4882a593Smuzhiyun 		return -EINVAL;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	/*
347*4882a593Smuzhiyun 	 * usdev_lock is acquired after (and not before) ib_get_eth_speed call
348*4882a593Smuzhiyun 	 * because acquiring rtnl_lock in ib_get_eth_speed, while holding
349*4882a593Smuzhiyun 	 * usdev_lock could lead to a deadlock.
350*4882a593Smuzhiyun 	 */
351*4882a593Smuzhiyun 	mutex_lock(&us_ibdev->usdev_lock);
352*4882a593Smuzhiyun 	/* props being zeroed by the caller, avoid zeroing it here */
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	props->lid = 0;
355*4882a593Smuzhiyun 	props->lmc = 1;
356*4882a593Smuzhiyun 	props->sm_lid = 0;
357*4882a593Smuzhiyun 	props->sm_sl = 0;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	if (!us_ibdev->ufdev->link_up) {
360*4882a593Smuzhiyun 		props->state = IB_PORT_DOWN;
361*4882a593Smuzhiyun 		props->phys_state = IB_PORT_PHYS_STATE_DISABLED;
362*4882a593Smuzhiyun 	} else if (!us_ibdev->ufdev->inaddr) {
363*4882a593Smuzhiyun 		props->state = IB_PORT_INIT;
364*4882a593Smuzhiyun 		props->phys_state =
365*4882a593Smuzhiyun 			IB_PORT_PHYS_STATE_PORT_CONFIGURATION_TRAINING;
366*4882a593Smuzhiyun 	} else {
367*4882a593Smuzhiyun 		props->state = IB_PORT_ACTIVE;
368*4882a593Smuzhiyun 		props->phys_state = IB_PORT_PHYS_STATE_LINK_UP;
369*4882a593Smuzhiyun 	}
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	props->port_cap_flags = 0;
372*4882a593Smuzhiyun 	props->gid_tbl_len = 1;
373*4882a593Smuzhiyun 	props->bad_pkey_cntr = 0;
374*4882a593Smuzhiyun 	props->qkey_viol_cntr = 0;
375*4882a593Smuzhiyun 	props->max_mtu = IB_MTU_4096;
376*4882a593Smuzhiyun 	props->active_mtu = iboe_get_mtu(us_ibdev->ufdev->mtu);
377*4882a593Smuzhiyun 	/* Userspace will adjust for hdrs */
378*4882a593Smuzhiyun 	props->max_msg_sz = us_ibdev->ufdev->mtu;
379*4882a593Smuzhiyun 	props->max_vl_num = 1;
380*4882a593Smuzhiyun 	mutex_unlock(&us_ibdev->usdev_lock);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	return 0;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun 
usnic_ib_query_qp(struct ib_qp * qp,struct ib_qp_attr * qp_attr,int qp_attr_mask,struct ib_qp_init_attr * qp_init_attr)385*4882a593Smuzhiyun int usnic_ib_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr,
386*4882a593Smuzhiyun 				int qp_attr_mask,
387*4882a593Smuzhiyun 				struct ib_qp_init_attr *qp_init_attr)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun 	struct usnic_ib_qp_grp *qp_grp;
390*4882a593Smuzhiyun 	struct usnic_ib_vf *vf;
391*4882a593Smuzhiyun 	int err;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	usnic_dbg("\n");
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	memset(qp_attr, 0, sizeof(*qp_attr));
396*4882a593Smuzhiyun 	memset(qp_init_attr, 0, sizeof(*qp_init_attr));
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	qp_grp = to_uqp_grp(qp);
399*4882a593Smuzhiyun 	vf = qp_grp->vf;
400*4882a593Smuzhiyun 	mutex_lock(&vf->pf->usdev_lock);
401*4882a593Smuzhiyun 	usnic_dbg("\n");
402*4882a593Smuzhiyun 	qp_attr->qp_state = qp_grp->state;
403*4882a593Smuzhiyun 	qp_attr->cur_qp_state = qp_grp->state;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	switch (qp_grp->ibqp.qp_type) {
406*4882a593Smuzhiyun 	case IB_QPT_UD:
407*4882a593Smuzhiyun 		qp_attr->qkey = 0;
408*4882a593Smuzhiyun 		break;
409*4882a593Smuzhiyun 	default:
410*4882a593Smuzhiyun 		usnic_err("Unexpected qp_type %d\n", qp_grp->ibqp.qp_type);
411*4882a593Smuzhiyun 		err = -EINVAL;
412*4882a593Smuzhiyun 		goto err_out;
413*4882a593Smuzhiyun 	}
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	mutex_unlock(&vf->pf->usdev_lock);
416*4882a593Smuzhiyun 	return 0;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun err_out:
419*4882a593Smuzhiyun 	mutex_unlock(&vf->pf->usdev_lock);
420*4882a593Smuzhiyun 	return err;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
usnic_ib_query_gid(struct ib_device * ibdev,u8 port,int index,union ib_gid * gid)423*4882a593Smuzhiyun int usnic_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
424*4882a593Smuzhiyun 				union ib_gid *gid)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	struct usnic_ib_dev *us_ibdev = to_usdev(ibdev);
428*4882a593Smuzhiyun 	usnic_dbg("\n");
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	if (index > 1)
431*4882a593Smuzhiyun 		return -EINVAL;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	mutex_lock(&us_ibdev->usdev_lock);
434*4882a593Smuzhiyun 	memset(&(gid->raw[0]), 0, sizeof(gid->raw));
435*4882a593Smuzhiyun 	usnic_mac_ip_to_gid(us_ibdev->ufdev->mac, us_ibdev->ufdev->inaddr,
436*4882a593Smuzhiyun 			&gid->raw[0]);
437*4882a593Smuzhiyun 	mutex_unlock(&us_ibdev->usdev_lock);
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	return 0;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun 
usnic_ib_alloc_pd(struct ib_pd * ibpd,struct ib_udata * udata)442*4882a593Smuzhiyun int usnic_ib_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	struct usnic_ib_pd *pd = to_upd(ibpd);
445*4882a593Smuzhiyun 	void *umem_pd;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	umem_pd = pd->umem_pd = usnic_uiom_alloc_pd();
448*4882a593Smuzhiyun 	if (IS_ERR_OR_NULL(umem_pd)) {
449*4882a593Smuzhiyun 		return umem_pd ? PTR_ERR(umem_pd) : -ENOMEM;
450*4882a593Smuzhiyun 	}
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	return 0;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun 
usnic_ib_dealloc_pd(struct ib_pd * pd,struct ib_udata * udata)455*4882a593Smuzhiyun int usnic_ib_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun 	usnic_uiom_dealloc_pd((to_upd(pd))->umem_pd);
458*4882a593Smuzhiyun 	return 0;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun 
usnic_ib_create_qp(struct ib_pd * pd,struct ib_qp_init_attr * init_attr,struct ib_udata * udata)461*4882a593Smuzhiyun struct ib_qp *usnic_ib_create_qp(struct ib_pd *pd,
462*4882a593Smuzhiyun 					struct ib_qp_init_attr *init_attr,
463*4882a593Smuzhiyun 					struct ib_udata *udata)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun 	int err;
466*4882a593Smuzhiyun 	struct usnic_ib_dev *us_ibdev;
467*4882a593Smuzhiyun 	struct usnic_ib_qp_grp *qp_grp;
468*4882a593Smuzhiyun 	struct usnic_ib_ucontext *ucontext = rdma_udata_to_drv_context(
469*4882a593Smuzhiyun 		udata, struct usnic_ib_ucontext, ibucontext);
470*4882a593Smuzhiyun 	int cq_cnt;
471*4882a593Smuzhiyun 	struct usnic_vnic_res_spec res_spec;
472*4882a593Smuzhiyun 	struct usnic_ib_create_qp_cmd cmd;
473*4882a593Smuzhiyun 	struct usnic_transport_spec trans_spec;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	usnic_dbg("\n");
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	us_ibdev = to_usdev(pd->device);
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	if (init_attr->create_flags)
480*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	err = ib_copy_from_udata(&cmd, udata, sizeof(cmd));
483*4882a593Smuzhiyun 	if (err) {
484*4882a593Smuzhiyun 		usnic_err("%s: cannot copy udata for create_qp\n",
485*4882a593Smuzhiyun 			  dev_name(&us_ibdev->ib_dev.dev));
486*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
487*4882a593Smuzhiyun 	}
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	err = create_qp_validate_user_data(cmd);
490*4882a593Smuzhiyun 	if (err) {
491*4882a593Smuzhiyun 		usnic_err("%s: Failed to validate user data\n",
492*4882a593Smuzhiyun 			  dev_name(&us_ibdev->ib_dev.dev));
493*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
494*4882a593Smuzhiyun 	}
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	if (init_attr->qp_type != IB_QPT_UD) {
497*4882a593Smuzhiyun 		usnic_err("%s asked to make a non-UD QP: %d\n",
498*4882a593Smuzhiyun 			  dev_name(&us_ibdev->ib_dev.dev), init_attr->qp_type);
499*4882a593Smuzhiyun 		return ERR_PTR(-EOPNOTSUPP);
500*4882a593Smuzhiyun 	}
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	trans_spec = cmd.spec;
503*4882a593Smuzhiyun 	mutex_lock(&us_ibdev->usdev_lock);
504*4882a593Smuzhiyun 	cq_cnt = (init_attr->send_cq == init_attr->recv_cq) ? 1 : 2;
505*4882a593Smuzhiyun 	res_spec = min_transport_spec[trans_spec.trans_type];
506*4882a593Smuzhiyun 	usnic_vnic_res_spec_update(&res_spec, USNIC_VNIC_RES_TYPE_CQ, cq_cnt);
507*4882a593Smuzhiyun 	qp_grp = find_free_vf_and_create_qp_grp(us_ibdev, to_upd(pd),
508*4882a593Smuzhiyun 						&trans_spec,
509*4882a593Smuzhiyun 						&res_spec);
510*4882a593Smuzhiyun 	if (IS_ERR_OR_NULL(qp_grp)) {
511*4882a593Smuzhiyun 		err = qp_grp ? PTR_ERR(qp_grp) : -ENOMEM;
512*4882a593Smuzhiyun 		goto out_release_mutex;
513*4882a593Smuzhiyun 	}
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	err = usnic_ib_fill_create_qp_resp(qp_grp, udata);
516*4882a593Smuzhiyun 	if (err) {
517*4882a593Smuzhiyun 		err = -EBUSY;
518*4882a593Smuzhiyun 		goto out_release_qp_grp;
519*4882a593Smuzhiyun 	}
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	qp_grp->ctx = ucontext;
522*4882a593Smuzhiyun 	list_add_tail(&qp_grp->link, &ucontext->qp_grp_list);
523*4882a593Smuzhiyun 	usnic_ib_log_vf(qp_grp->vf);
524*4882a593Smuzhiyun 	mutex_unlock(&us_ibdev->usdev_lock);
525*4882a593Smuzhiyun 	return &qp_grp->ibqp;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun out_release_qp_grp:
528*4882a593Smuzhiyun 	qp_grp_destroy(qp_grp);
529*4882a593Smuzhiyun out_release_mutex:
530*4882a593Smuzhiyun 	mutex_unlock(&us_ibdev->usdev_lock);
531*4882a593Smuzhiyun 	return ERR_PTR(err);
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun 
usnic_ib_destroy_qp(struct ib_qp * qp,struct ib_udata * udata)534*4882a593Smuzhiyun int usnic_ib_destroy_qp(struct ib_qp *qp, struct ib_udata *udata)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun 	struct usnic_ib_qp_grp *qp_grp;
537*4882a593Smuzhiyun 	struct usnic_ib_vf *vf;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	usnic_dbg("\n");
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	qp_grp = to_uqp_grp(qp);
542*4882a593Smuzhiyun 	vf = qp_grp->vf;
543*4882a593Smuzhiyun 	mutex_lock(&vf->pf->usdev_lock);
544*4882a593Smuzhiyun 	if (usnic_ib_qp_grp_modify(qp_grp, IB_QPS_RESET, NULL)) {
545*4882a593Smuzhiyun 		usnic_err("Failed to move qp grp %u to reset\n",
546*4882a593Smuzhiyun 				qp_grp->grp_id);
547*4882a593Smuzhiyun 	}
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	list_del(&qp_grp->link);
550*4882a593Smuzhiyun 	qp_grp_destroy(qp_grp);
551*4882a593Smuzhiyun 	mutex_unlock(&vf->pf->usdev_lock);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	return 0;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun 
usnic_ib_modify_qp(struct ib_qp * ibqp,struct ib_qp_attr * attr,int attr_mask,struct ib_udata * udata)556*4882a593Smuzhiyun int usnic_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
557*4882a593Smuzhiyun 				int attr_mask, struct ib_udata *udata)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun 	struct usnic_ib_qp_grp *qp_grp;
560*4882a593Smuzhiyun 	int status;
561*4882a593Smuzhiyun 	usnic_dbg("\n");
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	qp_grp = to_uqp_grp(ibqp);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	mutex_lock(&qp_grp->vf->pf->usdev_lock);
566*4882a593Smuzhiyun 	if ((attr_mask & IB_QP_PORT) && attr->port_num != 1) {
567*4882a593Smuzhiyun 		/* usnic devices only have one port */
568*4882a593Smuzhiyun 		status = -EINVAL;
569*4882a593Smuzhiyun 		goto out_unlock;
570*4882a593Smuzhiyun 	}
571*4882a593Smuzhiyun 	if (attr_mask & IB_QP_STATE) {
572*4882a593Smuzhiyun 		status = usnic_ib_qp_grp_modify(qp_grp, attr->qp_state, NULL);
573*4882a593Smuzhiyun 	} else {
574*4882a593Smuzhiyun 		usnic_err("Unhandled request, attr_mask=0x%x\n", attr_mask);
575*4882a593Smuzhiyun 		status = -EINVAL;
576*4882a593Smuzhiyun 	}
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun out_unlock:
579*4882a593Smuzhiyun 	mutex_unlock(&qp_grp->vf->pf->usdev_lock);
580*4882a593Smuzhiyun 	return status;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun 
usnic_ib_create_cq(struct ib_cq * ibcq,const struct ib_cq_init_attr * attr,struct ib_udata * udata)583*4882a593Smuzhiyun int usnic_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
584*4882a593Smuzhiyun 		       struct ib_udata *udata)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun 	if (attr->flags)
587*4882a593Smuzhiyun 		return -EINVAL;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	return 0;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun 
usnic_ib_destroy_cq(struct ib_cq * cq,struct ib_udata * udata)592*4882a593Smuzhiyun int usnic_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)
593*4882a593Smuzhiyun {
594*4882a593Smuzhiyun 	return 0;
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun 
usnic_ib_reg_mr(struct ib_pd * pd,u64 start,u64 length,u64 virt_addr,int access_flags,struct ib_udata * udata)597*4882a593Smuzhiyun struct ib_mr *usnic_ib_reg_mr(struct ib_pd *pd, u64 start, u64 length,
598*4882a593Smuzhiyun 					u64 virt_addr, int access_flags,
599*4882a593Smuzhiyun 					struct ib_udata *udata)
600*4882a593Smuzhiyun {
601*4882a593Smuzhiyun 	struct usnic_ib_mr *mr;
602*4882a593Smuzhiyun 	int err;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	usnic_dbg("start 0x%llx va 0x%llx length 0x%llx\n", start,
605*4882a593Smuzhiyun 			virt_addr, length);
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
608*4882a593Smuzhiyun 	if (!mr)
609*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	mr->umem = usnic_uiom_reg_get(to_upd(pd)->umem_pd, start, length,
612*4882a593Smuzhiyun 					access_flags, 0);
613*4882a593Smuzhiyun 	if (IS_ERR_OR_NULL(mr->umem)) {
614*4882a593Smuzhiyun 		err = mr->umem ? PTR_ERR(mr->umem) : -EFAULT;
615*4882a593Smuzhiyun 		goto err_free;
616*4882a593Smuzhiyun 	}
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	mr->ibmr.lkey = mr->ibmr.rkey = 0;
619*4882a593Smuzhiyun 	return &mr->ibmr;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun err_free:
622*4882a593Smuzhiyun 	kfree(mr);
623*4882a593Smuzhiyun 	return ERR_PTR(err);
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun 
usnic_ib_dereg_mr(struct ib_mr * ibmr,struct ib_udata * udata)626*4882a593Smuzhiyun int usnic_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun 	struct usnic_ib_mr *mr = to_umr(ibmr);
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	usnic_dbg("va 0x%lx length 0x%zx\n", mr->umem->va, mr->umem->length);
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	usnic_uiom_reg_release(mr->umem);
633*4882a593Smuzhiyun 	kfree(mr);
634*4882a593Smuzhiyun 	return 0;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun 
usnic_ib_alloc_ucontext(struct ib_ucontext * uctx,struct ib_udata * udata)637*4882a593Smuzhiyun int usnic_ib_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun 	struct ib_device *ibdev = uctx->device;
640*4882a593Smuzhiyun 	struct usnic_ib_ucontext *context = to_ucontext(uctx);
641*4882a593Smuzhiyun 	struct usnic_ib_dev *us_ibdev = to_usdev(ibdev);
642*4882a593Smuzhiyun 	usnic_dbg("\n");
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 	INIT_LIST_HEAD(&context->qp_grp_list);
645*4882a593Smuzhiyun 	mutex_lock(&us_ibdev->usdev_lock);
646*4882a593Smuzhiyun 	list_add_tail(&context->link, &us_ibdev->ctx_list);
647*4882a593Smuzhiyun 	mutex_unlock(&us_ibdev->usdev_lock);
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	return 0;
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun 
usnic_ib_dealloc_ucontext(struct ib_ucontext * ibcontext)652*4882a593Smuzhiyun void usnic_ib_dealloc_ucontext(struct ib_ucontext *ibcontext)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun 	struct usnic_ib_ucontext *context = to_uucontext(ibcontext);
655*4882a593Smuzhiyun 	struct usnic_ib_dev *us_ibdev = to_usdev(ibcontext->device);
656*4882a593Smuzhiyun 	usnic_dbg("\n");
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	mutex_lock(&us_ibdev->usdev_lock);
659*4882a593Smuzhiyun 	WARN_ON_ONCE(!list_empty(&context->qp_grp_list));
660*4882a593Smuzhiyun 	list_del(&context->link);
661*4882a593Smuzhiyun 	mutex_unlock(&us_ibdev->usdev_lock);
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun 
usnic_ib_mmap(struct ib_ucontext * context,struct vm_area_struct * vma)664*4882a593Smuzhiyun int usnic_ib_mmap(struct ib_ucontext *context,
665*4882a593Smuzhiyun 				struct vm_area_struct *vma)
666*4882a593Smuzhiyun {
667*4882a593Smuzhiyun 	struct usnic_ib_ucontext *uctx = to_ucontext(context);
668*4882a593Smuzhiyun 	struct usnic_ib_dev *us_ibdev;
669*4882a593Smuzhiyun 	struct usnic_ib_qp_grp *qp_grp;
670*4882a593Smuzhiyun 	struct usnic_ib_vf *vf;
671*4882a593Smuzhiyun 	struct vnic_dev_bar *bar;
672*4882a593Smuzhiyun 	dma_addr_t bus_addr;
673*4882a593Smuzhiyun 	unsigned int len;
674*4882a593Smuzhiyun 	unsigned int vfid;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	usnic_dbg("\n");
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	us_ibdev = to_usdev(context->device);
679*4882a593Smuzhiyun 	vma->vm_flags |= VM_IO;
680*4882a593Smuzhiyun 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
681*4882a593Smuzhiyun 	vfid = vma->vm_pgoff;
682*4882a593Smuzhiyun 	usnic_dbg("Page Offset %lu PAGE_SHIFT %u VFID %u\n",
683*4882a593Smuzhiyun 			vma->vm_pgoff, PAGE_SHIFT, vfid);
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	mutex_lock(&us_ibdev->usdev_lock);
686*4882a593Smuzhiyun 	list_for_each_entry(qp_grp, &uctx->qp_grp_list, link) {
687*4882a593Smuzhiyun 		vf = qp_grp->vf;
688*4882a593Smuzhiyun 		if (usnic_vnic_get_index(vf->vnic) == vfid) {
689*4882a593Smuzhiyun 			bar = usnic_vnic_get_bar(vf->vnic, 0);
690*4882a593Smuzhiyun 			if ((vma->vm_end - vma->vm_start) != bar->len) {
691*4882a593Smuzhiyun 				usnic_err("Bar0 Len %lu - Request map %lu\n",
692*4882a593Smuzhiyun 						bar->len,
693*4882a593Smuzhiyun 						vma->vm_end - vma->vm_start);
694*4882a593Smuzhiyun 				mutex_unlock(&us_ibdev->usdev_lock);
695*4882a593Smuzhiyun 				return -EINVAL;
696*4882a593Smuzhiyun 			}
697*4882a593Smuzhiyun 			bus_addr = bar->bus_addr;
698*4882a593Smuzhiyun 			len = bar->len;
699*4882a593Smuzhiyun 			usnic_dbg("bus: %pa vaddr: %p size: %ld\n",
700*4882a593Smuzhiyun 					&bus_addr, bar->vaddr, bar->len);
701*4882a593Smuzhiyun 			mutex_unlock(&us_ibdev->usdev_lock);
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 			return remap_pfn_range(vma,
704*4882a593Smuzhiyun 						vma->vm_start,
705*4882a593Smuzhiyun 						bus_addr >> PAGE_SHIFT,
706*4882a593Smuzhiyun 						len, vma->vm_page_prot);
707*4882a593Smuzhiyun 		}
708*4882a593Smuzhiyun 	}
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	mutex_unlock(&us_ibdev->usdev_lock);
711*4882a593Smuzhiyun 	usnic_err("No VF %u found\n", vfid);
712*4882a593Smuzhiyun 	return -EINVAL;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun 
715