xref: /OK3568_Linux_fs/kernel/drivers/infiniband/sw/rdmavt/vt.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright(c) 2016 - 2018 Intel Corporation.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This file is provided under a dual BSD/GPLv2 license.  When using or
5*4882a593Smuzhiyun  * redistributing this file, you may do so under either license.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * GPL LICENSE SUMMARY
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify
10*4882a593Smuzhiyun  * it under the terms of version 2 of the GNU General Public License as
11*4882a593Smuzhiyun  * published by the Free Software Foundation.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful, but
14*4882a593Smuzhiyun  * WITHOUT ANY WARRANTY; without even the implied warranty of
15*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16*4882a593Smuzhiyun  * General Public License for more details.
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  * BSD LICENSE
19*4882a593Smuzhiyun  *
20*4882a593Smuzhiyun  * Redistribution and use in source and binary forms, with or without
21*4882a593Smuzhiyun  * modification, are permitted provided that the following conditions
22*4882a593Smuzhiyun  * are met:
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  *  - Redistributions of source code must retain the above copyright
25*4882a593Smuzhiyun  *    notice, this list of conditions and the following disclaimer.
26*4882a593Smuzhiyun  *  - Redistributions in binary form must reproduce the above copyright
27*4882a593Smuzhiyun  *    notice, this list of conditions and the following disclaimer in
28*4882a593Smuzhiyun  *    the documentation and/or other materials provided with the
29*4882a593Smuzhiyun  *    distribution.
30*4882a593Smuzhiyun  *  - Neither the name of Intel Corporation nor the names of its
31*4882a593Smuzhiyun  *    contributors may be used to endorse or promote products derived
32*4882a593Smuzhiyun  *    from this software without specific prior written permission.
33*4882a593Smuzhiyun  *
34*4882a593Smuzhiyun  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
35*4882a593Smuzhiyun  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
36*4882a593Smuzhiyun  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
37*4882a593Smuzhiyun  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
38*4882a593Smuzhiyun  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
39*4882a593Smuzhiyun  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
40*4882a593Smuzhiyun  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
41*4882a593Smuzhiyun  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
42*4882a593Smuzhiyun  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
43*4882a593Smuzhiyun  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
44*4882a593Smuzhiyun  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45*4882a593Smuzhiyun  *
46*4882a593Smuzhiyun  */
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #include <linux/module.h>
49*4882a593Smuzhiyun #include <linux/kernel.h>
50*4882a593Smuzhiyun #include <linux/dma-mapping.h>
51*4882a593Smuzhiyun #include "vt.h"
52*4882a593Smuzhiyun #include "cq.h"
53*4882a593Smuzhiyun #include "trace.h"
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define RVT_UVERBS_ABI_VERSION 2
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun MODULE_LICENSE("Dual BSD/GPL");
58*4882a593Smuzhiyun MODULE_DESCRIPTION("RDMA Verbs Transport Library");
59*4882a593Smuzhiyun 
rvt_init(void)60*4882a593Smuzhiyun static int rvt_init(void)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	int ret = rvt_driver_cq_init();
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	if (ret)
65*4882a593Smuzhiyun 		pr_err("Error in driver CQ init.\n");
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	return ret;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun module_init(rvt_init);
70*4882a593Smuzhiyun 
rvt_cleanup(void)71*4882a593Smuzhiyun static void rvt_cleanup(void)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	rvt_cq_exit();
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun module_exit(rvt_cleanup);
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun /**
78*4882a593Smuzhiyun  * rvt_alloc_device - allocate rdi
79*4882a593Smuzhiyun  * @size: how big of a structure to allocate
80*4882a593Smuzhiyun  * @nports: number of ports to allocate array slots for
81*4882a593Smuzhiyun  *
82*4882a593Smuzhiyun  * Use IB core device alloc to allocate space for the rdi which is assumed to be
83*4882a593Smuzhiyun  * inside of the ib_device. Any extra space that drivers require should be
84*4882a593Smuzhiyun  * included in size.
85*4882a593Smuzhiyun  *
86*4882a593Smuzhiyun  * We also allocate a port array based on the number of ports.
87*4882a593Smuzhiyun  *
88*4882a593Smuzhiyun  * Return: pointer to allocated rdi
89*4882a593Smuzhiyun  */
rvt_alloc_device(size_t size,int nports)90*4882a593Smuzhiyun struct rvt_dev_info *rvt_alloc_device(size_t size, int nports)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	struct rvt_dev_info *rdi;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	rdi = container_of(_ib_alloc_device(size), struct rvt_dev_info, ibdev);
95*4882a593Smuzhiyun 	if (!rdi)
96*4882a593Smuzhiyun 		return rdi;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	rdi->ports = kcalloc(nports, sizeof(*rdi->ports), GFP_KERNEL);
99*4882a593Smuzhiyun 	if (!rdi->ports)
100*4882a593Smuzhiyun 		ib_dealloc_device(&rdi->ibdev);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	return rdi;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun EXPORT_SYMBOL(rvt_alloc_device);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /**
107*4882a593Smuzhiyun  * rvt_dealloc_device - deallocate rdi
108*4882a593Smuzhiyun  * @rdi: structure to free
109*4882a593Smuzhiyun  *
110*4882a593Smuzhiyun  * Free a structure allocated with rvt_alloc_device()
111*4882a593Smuzhiyun  */
rvt_dealloc_device(struct rvt_dev_info * rdi)112*4882a593Smuzhiyun void rvt_dealloc_device(struct rvt_dev_info *rdi)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	kfree(rdi->ports);
115*4882a593Smuzhiyun 	ib_dealloc_device(&rdi->ibdev);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun EXPORT_SYMBOL(rvt_dealloc_device);
118*4882a593Smuzhiyun 
rvt_query_device(struct ib_device * ibdev,struct ib_device_attr * props,struct ib_udata * uhw)119*4882a593Smuzhiyun static int rvt_query_device(struct ib_device *ibdev,
120*4882a593Smuzhiyun 			    struct ib_device_attr *props,
121*4882a593Smuzhiyun 			    struct ib_udata *uhw)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	if (uhw->inlen || uhw->outlen)
126*4882a593Smuzhiyun 		return -EINVAL;
127*4882a593Smuzhiyun 	/*
128*4882a593Smuzhiyun 	 * Return rvt_dev_info.dparms.props contents
129*4882a593Smuzhiyun 	 */
130*4882a593Smuzhiyun 	*props = rdi->dparms.props;
131*4882a593Smuzhiyun 	return 0;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun 
rvt_modify_device(struct ib_device * device,int device_modify_mask,struct ib_device_modify * device_modify)134*4882a593Smuzhiyun static int rvt_modify_device(struct ib_device *device,
135*4882a593Smuzhiyun 			     int device_modify_mask,
136*4882a593Smuzhiyun 			     struct ib_device_modify *device_modify)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	/*
139*4882a593Smuzhiyun 	 * There is currently no need to supply this based on qib and hfi1.
140*4882a593Smuzhiyun 	 * Future drivers may need to implement this though.
141*4882a593Smuzhiyun 	 */
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	return -EOPNOTSUPP;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun /**
147*4882a593Smuzhiyun  * rvt_query_port: Passes the query port call to the driver
148*4882a593Smuzhiyun  * @ibdev: Verbs IB dev
149*4882a593Smuzhiyun  * @port_num: port number, 1 based from ib core
150*4882a593Smuzhiyun  * @props: structure to hold returned properties
151*4882a593Smuzhiyun  *
152*4882a593Smuzhiyun  * Return: 0 on success
153*4882a593Smuzhiyun  */
rvt_query_port(struct ib_device * ibdev,u8 port_num,struct ib_port_attr * props)154*4882a593Smuzhiyun static int rvt_query_port(struct ib_device *ibdev, u8 port_num,
155*4882a593Smuzhiyun 			  struct ib_port_attr *props)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
158*4882a593Smuzhiyun 	struct rvt_ibport *rvp;
159*4882a593Smuzhiyun 	int port_index = ibport_num_to_idx(ibdev, port_num);
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	if (port_index < 0)
162*4882a593Smuzhiyun 		return -EINVAL;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	rvp = rdi->ports[port_index];
165*4882a593Smuzhiyun 	/* props being zeroed by the caller, avoid zeroing it here */
166*4882a593Smuzhiyun 	props->sm_lid = rvp->sm_lid;
167*4882a593Smuzhiyun 	props->sm_sl = rvp->sm_sl;
168*4882a593Smuzhiyun 	props->port_cap_flags = rvp->port_cap_flags;
169*4882a593Smuzhiyun 	props->max_msg_sz = 0x80000000;
170*4882a593Smuzhiyun 	props->pkey_tbl_len = rvt_get_npkeys(rdi);
171*4882a593Smuzhiyun 	props->bad_pkey_cntr = rvp->pkey_violations;
172*4882a593Smuzhiyun 	props->qkey_viol_cntr = rvp->qkey_violations;
173*4882a593Smuzhiyun 	props->subnet_timeout = rvp->subnet_timeout;
174*4882a593Smuzhiyun 	props->init_type_reply = 0;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	/* Populate the remaining ib_port_attr elements */
177*4882a593Smuzhiyun 	return rdi->driver_f.query_port_state(rdi, port_num, props);
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun /**
181*4882a593Smuzhiyun  * rvt_modify_port
182*4882a593Smuzhiyun  * @ibdev: Verbs IB dev
183*4882a593Smuzhiyun  * @port_num: Port number, 1 based from ib core
184*4882a593Smuzhiyun  * @port_modify_mask: How to change the port
185*4882a593Smuzhiyun  * @props: Structure to fill in
186*4882a593Smuzhiyun  *
187*4882a593Smuzhiyun  * Return: 0 on success
188*4882a593Smuzhiyun  */
rvt_modify_port(struct ib_device * ibdev,u8 port_num,int port_modify_mask,struct ib_port_modify * props)189*4882a593Smuzhiyun static int rvt_modify_port(struct ib_device *ibdev, u8 port_num,
190*4882a593Smuzhiyun 			   int port_modify_mask, struct ib_port_modify *props)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
193*4882a593Smuzhiyun 	struct rvt_ibport *rvp;
194*4882a593Smuzhiyun 	int ret = 0;
195*4882a593Smuzhiyun 	int port_index = ibport_num_to_idx(ibdev, port_num);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	if (port_index < 0)
198*4882a593Smuzhiyun 		return -EINVAL;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	rvp = rdi->ports[port_index];
201*4882a593Smuzhiyun 	if (port_modify_mask & IB_PORT_OPA_MASK_CHG) {
202*4882a593Smuzhiyun 		rvp->port_cap3_flags |= props->set_port_cap_mask;
203*4882a593Smuzhiyun 		rvp->port_cap3_flags &= ~props->clr_port_cap_mask;
204*4882a593Smuzhiyun 	} else {
205*4882a593Smuzhiyun 		rvp->port_cap_flags |= props->set_port_cap_mask;
206*4882a593Smuzhiyun 		rvp->port_cap_flags &= ~props->clr_port_cap_mask;
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	if (props->set_port_cap_mask || props->clr_port_cap_mask)
210*4882a593Smuzhiyun 		rdi->driver_f.cap_mask_chg(rdi, port_num);
211*4882a593Smuzhiyun 	if (port_modify_mask & IB_PORT_SHUTDOWN)
212*4882a593Smuzhiyun 		ret = rdi->driver_f.shut_down_port(rdi, port_num);
213*4882a593Smuzhiyun 	if (port_modify_mask & IB_PORT_RESET_QKEY_CNTR)
214*4882a593Smuzhiyun 		rvp->qkey_violations = 0;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	return ret;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun /**
220*4882a593Smuzhiyun  * rvt_query_pkey - Return a pkey from the table at a given index
221*4882a593Smuzhiyun  * @ibdev: Verbs IB dev
222*4882a593Smuzhiyun  * @port_num: Port number, 1 based from ib core
223*4882a593Smuzhiyun  * @index: Index into pkey table
224*4882a593Smuzhiyun  * @pkey: returned pkey from the port pkey table
225*4882a593Smuzhiyun  *
226*4882a593Smuzhiyun  * Return: 0 on failure pkey otherwise
227*4882a593Smuzhiyun  */
rvt_query_pkey(struct ib_device * ibdev,u8 port_num,u16 index,u16 * pkey)228*4882a593Smuzhiyun static int rvt_query_pkey(struct ib_device *ibdev, u8 port_num, u16 index,
229*4882a593Smuzhiyun 			  u16 *pkey)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	/*
232*4882a593Smuzhiyun 	 * Driver will be responsible for keeping rvt_dev_info.pkey_table up to
233*4882a593Smuzhiyun 	 * date. This function will just return that value. There is no need to
234*4882a593Smuzhiyun 	 * lock, if a stale value is read and sent to the user so be it there is
235*4882a593Smuzhiyun 	 * no way to protect against that anyway.
236*4882a593Smuzhiyun 	 */
237*4882a593Smuzhiyun 	struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
238*4882a593Smuzhiyun 	int port_index;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	port_index = ibport_num_to_idx(ibdev, port_num);
241*4882a593Smuzhiyun 	if (port_index < 0)
242*4882a593Smuzhiyun 		return -EINVAL;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	if (index >= rvt_get_npkeys(rdi))
245*4882a593Smuzhiyun 		return -EINVAL;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	*pkey = rvt_get_pkey(rdi, port_index, index);
248*4882a593Smuzhiyun 	return 0;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun /**
252*4882a593Smuzhiyun  * rvt_query_gid - Return a gid from the table
253*4882a593Smuzhiyun  * @ibdev: Verbs IB dev
254*4882a593Smuzhiyun  * @port_num: Port number, 1 based from ib core
255*4882a593Smuzhiyun  * @guid_index: Index in table
256*4882a593Smuzhiyun  * @gid: Gid to return
257*4882a593Smuzhiyun  *
258*4882a593Smuzhiyun  * Return: 0 on success
259*4882a593Smuzhiyun  */
rvt_query_gid(struct ib_device * ibdev,u8 port_num,int guid_index,union ib_gid * gid)260*4882a593Smuzhiyun static int rvt_query_gid(struct ib_device *ibdev, u8 port_num,
261*4882a593Smuzhiyun 			 int guid_index, union ib_gid *gid)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun 	struct rvt_dev_info *rdi;
264*4882a593Smuzhiyun 	struct rvt_ibport *rvp;
265*4882a593Smuzhiyun 	int port_index;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	/*
268*4882a593Smuzhiyun 	 * Driver is responsible for updating the guid table. Which will be used
269*4882a593Smuzhiyun 	 * to craft the return value. This will work similar to how query_pkey()
270*4882a593Smuzhiyun 	 * is being done.
271*4882a593Smuzhiyun 	 */
272*4882a593Smuzhiyun 	port_index = ibport_num_to_idx(ibdev, port_num);
273*4882a593Smuzhiyun 	if (port_index < 0)
274*4882a593Smuzhiyun 		return -EINVAL;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	rdi = ib_to_rvt(ibdev);
277*4882a593Smuzhiyun 	rvp = rdi->ports[port_index];
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	gid->global.subnet_prefix = rvp->gid_prefix;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	return rdi->driver_f.get_guid_be(rdi, rvp, guid_index,
282*4882a593Smuzhiyun 					 &gid->global.interface_id);
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun /**
286*4882a593Smuzhiyun  * rvt_alloc_ucontext - Allocate a user context
287*4882a593Smuzhiyun  * @uctx: Verbs context
288*4882a593Smuzhiyun  * @udata: User data allocated
289*4882a593Smuzhiyun  */
rvt_alloc_ucontext(struct ib_ucontext * uctx,struct ib_udata * udata)290*4882a593Smuzhiyun static int rvt_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	return 0;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun /**
296*4882a593Smuzhiyun  * rvt_dealloc_ucontext - Free a user context
297*4882a593Smuzhiyun  * @context - Free this
298*4882a593Smuzhiyun  */
rvt_dealloc_ucontext(struct ib_ucontext * context)299*4882a593Smuzhiyun static void rvt_dealloc_ucontext(struct ib_ucontext *context)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	return;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun 
rvt_get_port_immutable(struct ib_device * ibdev,u8 port_num,struct ib_port_immutable * immutable)304*4882a593Smuzhiyun static int rvt_get_port_immutable(struct ib_device *ibdev, u8 port_num,
305*4882a593Smuzhiyun 				  struct ib_port_immutable *immutable)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun 	struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
308*4882a593Smuzhiyun 	struct ib_port_attr attr;
309*4882a593Smuzhiyun 	int err, port_index;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	port_index = ibport_num_to_idx(ibdev, port_num);
312*4882a593Smuzhiyun 	if (port_index < 0)
313*4882a593Smuzhiyun 		return -EINVAL;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	immutable->core_cap_flags = rdi->dparms.core_cap_flags;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	err = ib_query_port(ibdev, port_num, &attr);
318*4882a593Smuzhiyun 	if (err)
319*4882a593Smuzhiyun 		return err;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	immutable->pkey_tbl_len = attr.pkey_tbl_len;
322*4882a593Smuzhiyun 	immutable->gid_tbl_len = attr.gid_tbl_len;
323*4882a593Smuzhiyun 	immutable->max_mad_size = rdi->dparms.max_mad_size;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	return 0;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun enum {
329*4882a593Smuzhiyun 	MISC,
330*4882a593Smuzhiyun 	QUERY_DEVICE,
331*4882a593Smuzhiyun 	MODIFY_DEVICE,
332*4882a593Smuzhiyun 	QUERY_PORT,
333*4882a593Smuzhiyun 	MODIFY_PORT,
334*4882a593Smuzhiyun 	QUERY_PKEY,
335*4882a593Smuzhiyun 	QUERY_GID,
336*4882a593Smuzhiyun 	ALLOC_UCONTEXT,
337*4882a593Smuzhiyun 	DEALLOC_UCONTEXT,
338*4882a593Smuzhiyun 	GET_PORT_IMMUTABLE,
339*4882a593Smuzhiyun 	CREATE_QP,
340*4882a593Smuzhiyun 	MODIFY_QP,
341*4882a593Smuzhiyun 	DESTROY_QP,
342*4882a593Smuzhiyun 	QUERY_QP,
343*4882a593Smuzhiyun 	POST_SEND,
344*4882a593Smuzhiyun 	POST_RECV,
345*4882a593Smuzhiyun 	POST_SRQ_RECV,
346*4882a593Smuzhiyun 	CREATE_AH,
347*4882a593Smuzhiyun 	DESTROY_AH,
348*4882a593Smuzhiyun 	MODIFY_AH,
349*4882a593Smuzhiyun 	QUERY_AH,
350*4882a593Smuzhiyun 	CREATE_SRQ,
351*4882a593Smuzhiyun 	MODIFY_SRQ,
352*4882a593Smuzhiyun 	DESTROY_SRQ,
353*4882a593Smuzhiyun 	QUERY_SRQ,
354*4882a593Smuzhiyun 	ATTACH_MCAST,
355*4882a593Smuzhiyun 	DETACH_MCAST,
356*4882a593Smuzhiyun 	GET_DMA_MR,
357*4882a593Smuzhiyun 	REG_USER_MR,
358*4882a593Smuzhiyun 	DEREG_MR,
359*4882a593Smuzhiyun 	ALLOC_MR,
360*4882a593Smuzhiyun 	MAP_MR_SG,
361*4882a593Smuzhiyun 	ALLOC_FMR,
362*4882a593Smuzhiyun 	MAP_PHYS_FMR,
363*4882a593Smuzhiyun 	UNMAP_FMR,
364*4882a593Smuzhiyun 	DEALLOC_FMR,
365*4882a593Smuzhiyun 	MMAP,
366*4882a593Smuzhiyun 	CREATE_CQ,
367*4882a593Smuzhiyun 	DESTROY_CQ,
368*4882a593Smuzhiyun 	POLL_CQ,
369*4882a593Smuzhiyun 	REQ_NOTFIY_CQ,
370*4882a593Smuzhiyun 	RESIZE_CQ,
371*4882a593Smuzhiyun 	ALLOC_PD,
372*4882a593Smuzhiyun 	DEALLOC_PD,
373*4882a593Smuzhiyun 	_VERB_IDX_MAX /* Must always be last! */
374*4882a593Smuzhiyun };
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun static const struct ib_device_ops rvt_dev_ops = {
377*4882a593Smuzhiyun 	.uverbs_abi_ver = RVT_UVERBS_ABI_VERSION,
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	.alloc_mr = rvt_alloc_mr,
380*4882a593Smuzhiyun 	.alloc_pd = rvt_alloc_pd,
381*4882a593Smuzhiyun 	.alloc_ucontext = rvt_alloc_ucontext,
382*4882a593Smuzhiyun 	.attach_mcast = rvt_attach_mcast,
383*4882a593Smuzhiyun 	.create_ah = rvt_create_ah,
384*4882a593Smuzhiyun 	.create_cq = rvt_create_cq,
385*4882a593Smuzhiyun 	.create_qp = rvt_create_qp,
386*4882a593Smuzhiyun 	.create_srq = rvt_create_srq,
387*4882a593Smuzhiyun 	.dealloc_pd = rvt_dealloc_pd,
388*4882a593Smuzhiyun 	.dealloc_ucontext = rvt_dealloc_ucontext,
389*4882a593Smuzhiyun 	.dereg_mr = rvt_dereg_mr,
390*4882a593Smuzhiyun 	.destroy_ah = rvt_destroy_ah,
391*4882a593Smuzhiyun 	.destroy_cq = rvt_destroy_cq,
392*4882a593Smuzhiyun 	.destroy_qp = rvt_destroy_qp,
393*4882a593Smuzhiyun 	.destroy_srq = rvt_destroy_srq,
394*4882a593Smuzhiyun 	.detach_mcast = rvt_detach_mcast,
395*4882a593Smuzhiyun 	.get_dma_mr = rvt_get_dma_mr,
396*4882a593Smuzhiyun 	.get_port_immutable = rvt_get_port_immutable,
397*4882a593Smuzhiyun 	.map_mr_sg = rvt_map_mr_sg,
398*4882a593Smuzhiyun 	.mmap = rvt_mmap,
399*4882a593Smuzhiyun 	.modify_ah = rvt_modify_ah,
400*4882a593Smuzhiyun 	.modify_device = rvt_modify_device,
401*4882a593Smuzhiyun 	.modify_port = rvt_modify_port,
402*4882a593Smuzhiyun 	.modify_qp = rvt_modify_qp,
403*4882a593Smuzhiyun 	.modify_srq = rvt_modify_srq,
404*4882a593Smuzhiyun 	.poll_cq = rvt_poll_cq,
405*4882a593Smuzhiyun 	.post_recv = rvt_post_recv,
406*4882a593Smuzhiyun 	.post_send = rvt_post_send,
407*4882a593Smuzhiyun 	.post_srq_recv = rvt_post_srq_recv,
408*4882a593Smuzhiyun 	.query_ah = rvt_query_ah,
409*4882a593Smuzhiyun 	.query_device = rvt_query_device,
410*4882a593Smuzhiyun 	.query_gid = rvt_query_gid,
411*4882a593Smuzhiyun 	.query_pkey = rvt_query_pkey,
412*4882a593Smuzhiyun 	.query_port = rvt_query_port,
413*4882a593Smuzhiyun 	.query_qp = rvt_query_qp,
414*4882a593Smuzhiyun 	.query_srq = rvt_query_srq,
415*4882a593Smuzhiyun 	.reg_user_mr = rvt_reg_user_mr,
416*4882a593Smuzhiyun 	.req_notify_cq = rvt_req_notify_cq,
417*4882a593Smuzhiyun 	.resize_cq = rvt_resize_cq,
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	INIT_RDMA_OBJ_SIZE(ib_ah, rvt_ah, ibah),
420*4882a593Smuzhiyun 	INIT_RDMA_OBJ_SIZE(ib_cq, rvt_cq, ibcq),
421*4882a593Smuzhiyun 	INIT_RDMA_OBJ_SIZE(ib_pd, rvt_pd, ibpd),
422*4882a593Smuzhiyun 	INIT_RDMA_OBJ_SIZE(ib_srq, rvt_srq, ibsrq),
423*4882a593Smuzhiyun 	INIT_RDMA_OBJ_SIZE(ib_ucontext, rvt_ucontext, ibucontext),
424*4882a593Smuzhiyun };
425*4882a593Smuzhiyun 
check_support(struct rvt_dev_info * rdi,int verb)426*4882a593Smuzhiyun static noinline int check_support(struct rvt_dev_info *rdi, int verb)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	switch (verb) {
429*4882a593Smuzhiyun 	case MISC:
430*4882a593Smuzhiyun 		/*
431*4882a593Smuzhiyun 		 * These functions are not part of verbs specifically but are
432*4882a593Smuzhiyun 		 * required for rdmavt to function.
433*4882a593Smuzhiyun 		 */
434*4882a593Smuzhiyun 		if ((!rdi->ibdev.ops.init_port) ||
435*4882a593Smuzhiyun 		    (!rdi->driver_f.get_pci_dev))
436*4882a593Smuzhiyun 			return -EINVAL;
437*4882a593Smuzhiyun 		break;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	case MODIFY_DEVICE:
440*4882a593Smuzhiyun 		/*
441*4882a593Smuzhiyun 		 * rdmavt does not support modify device currently drivers must
442*4882a593Smuzhiyun 		 * provide.
443*4882a593Smuzhiyun 		 */
444*4882a593Smuzhiyun 		if (!rdi->ibdev.ops.modify_device)
445*4882a593Smuzhiyun 			return -EOPNOTSUPP;
446*4882a593Smuzhiyun 		break;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	case QUERY_PORT:
449*4882a593Smuzhiyun 		if (!rdi->ibdev.ops.query_port)
450*4882a593Smuzhiyun 			if (!rdi->driver_f.query_port_state)
451*4882a593Smuzhiyun 				return -EINVAL;
452*4882a593Smuzhiyun 		break;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	case MODIFY_PORT:
455*4882a593Smuzhiyun 		if (!rdi->ibdev.ops.modify_port)
456*4882a593Smuzhiyun 			if (!rdi->driver_f.cap_mask_chg ||
457*4882a593Smuzhiyun 			    !rdi->driver_f.shut_down_port)
458*4882a593Smuzhiyun 				return -EINVAL;
459*4882a593Smuzhiyun 		break;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	case QUERY_GID:
462*4882a593Smuzhiyun 		if (!rdi->ibdev.ops.query_gid)
463*4882a593Smuzhiyun 			if (!rdi->driver_f.get_guid_be)
464*4882a593Smuzhiyun 				return -EINVAL;
465*4882a593Smuzhiyun 		break;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	case CREATE_QP:
468*4882a593Smuzhiyun 		if (!rdi->ibdev.ops.create_qp)
469*4882a593Smuzhiyun 			if (!rdi->driver_f.qp_priv_alloc ||
470*4882a593Smuzhiyun 			    !rdi->driver_f.qp_priv_free ||
471*4882a593Smuzhiyun 			    !rdi->driver_f.notify_qp_reset ||
472*4882a593Smuzhiyun 			    !rdi->driver_f.flush_qp_waiters ||
473*4882a593Smuzhiyun 			    !rdi->driver_f.stop_send_queue ||
474*4882a593Smuzhiyun 			    !rdi->driver_f.quiesce_qp)
475*4882a593Smuzhiyun 				return -EINVAL;
476*4882a593Smuzhiyun 		break;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	case MODIFY_QP:
479*4882a593Smuzhiyun 		if (!rdi->ibdev.ops.modify_qp)
480*4882a593Smuzhiyun 			if (!rdi->driver_f.notify_qp_reset ||
481*4882a593Smuzhiyun 			    !rdi->driver_f.schedule_send ||
482*4882a593Smuzhiyun 			    !rdi->driver_f.get_pmtu_from_attr ||
483*4882a593Smuzhiyun 			    !rdi->driver_f.flush_qp_waiters ||
484*4882a593Smuzhiyun 			    !rdi->driver_f.stop_send_queue ||
485*4882a593Smuzhiyun 			    !rdi->driver_f.quiesce_qp ||
486*4882a593Smuzhiyun 			    !rdi->driver_f.notify_error_qp ||
487*4882a593Smuzhiyun 			    !rdi->driver_f.mtu_from_qp ||
488*4882a593Smuzhiyun 			    !rdi->driver_f.mtu_to_path_mtu)
489*4882a593Smuzhiyun 				return -EINVAL;
490*4882a593Smuzhiyun 		break;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	case DESTROY_QP:
493*4882a593Smuzhiyun 		if (!rdi->ibdev.ops.destroy_qp)
494*4882a593Smuzhiyun 			if (!rdi->driver_f.qp_priv_free ||
495*4882a593Smuzhiyun 			    !rdi->driver_f.notify_qp_reset ||
496*4882a593Smuzhiyun 			    !rdi->driver_f.flush_qp_waiters ||
497*4882a593Smuzhiyun 			    !rdi->driver_f.stop_send_queue ||
498*4882a593Smuzhiyun 			    !rdi->driver_f.quiesce_qp)
499*4882a593Smuzhiyun 				return -EINVAL;
500*4882a593Smuzhiyun 		break;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	case POST_SEND:
503*4882a593Smuzhiyun 		if (!rdi->ibdev.ops.post_send)
504*4882a593Smuzhiyun 			if (!rdi->driver_f.schedule_send ||
505*4882a593Smuzhiyun 			    !rdi->driver_f.do_send ||
506*4882a593Smuzhiyun 			    !rdi->post_parms)
507*4882a593Smuzhiyun 				return -EINVAL;
508*4882a593Smuzhiyun 		break;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	}
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	return 0;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun /**
516*4882a593Smuzhiyun  * rvt_register_device - register a driver
517*4882a593Smuzhiyun  * @rdi: main dev structure for all of rdmavt operations
518*4882a593Smuzhiyun  *
519*4882a593Smuzhiyun  * It is up to drivers to allocate the rdi and fill in the appropriate
520*4882a593Smuzhiyun  * information.
521*4882a593Smuzhiyun  *
522*4882a593Smuzhiyun  * Return: 0 on success otherwise an errno.
523*4882a593Smuzhiyun  */
rvt_register_device(struct rvt_dev_info * rdi)524*4882a593Smuzhiyun int rvt_register_device(struct rvt_dev_info *rdi)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun 	int ret = 0, i;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	if (!rdi)
529*4882a593Smuzhiyun 		return -EINVAL;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	/*
532*4882a593Smuzhiyun 	 * Check to ensure drivers have setup the required helpers for the verbs
533*4882a593Smuzhiyun 	 * they want rdmavt to handle
534*4882a593Smuzhiyun 	 */
535*4882a593Smuzhiyun 	for (i = 0; i < _VERB_IDX_MAX; i++)
536*4882a593Smuzhiyun 		if (check_support(rdi, i)) {
537*4882a593Smuzhiyun 			pr_err("Driver support req not met at %d\n", i);
538*4882a593Smuzhiyun 			return -EINVAL;
539*4882a593Smuzhiyun 		}
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	ib_set_device_ops(&rdi->ibdev, &rvt_dev_ops);
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	/* Once we get past here we can use rvt_pr macros and tracepoints */
544*4882a593Smuzhiyun 	trace_rvt_dbg(rdi, "Driver attempting registration");
545*4882a593Smuzhiyun 	rvt_mmap_init(rdi);
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	/* Queue Pairs */
548*4882a593Smuzhiyun 	ret = rvt_driver_qp_init(rdi);
549*4882a593Smuzhiyun 	if (ret) {
550*4882a593Smuzhiyun 		pr_err("Error in driver QP init.\n");
551*4882a593Smuzhiyun 		return -EINVAL;
552*4882a593Smuzhiyun 	}
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	/* Address Handle */
555*4882a593Smuzhiyun 	spin_lock_init(&rdi->n_ahs_lock);
556*4882a593Smuzhiyun 	rdi->n_ahs_allocated = 0;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	/* Shared Receive Queue */
559*4882a593Smuzhiyun 	rvt_driver_srq_init(rdi);
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	/* Multicast */
562*4882a593Smuzhiyun 	rvt_driver_mcast_init(rdi);
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	/* Mem Region */
565*4882a593Smuzhiyun 	ret = rvt_driver_mr_init(rdi);
566*4882a593Smuzhiyun 	if (ret) {
567*4882a593Smuzhiyun 		pr_err("Error in driver MR init.\n");
568*4882a593Smuzhiyun 		goto bail_no_mr;
569*4882a593Smuzhiyun 	}
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	/* Memory Working Set Size */
572*4882a593Smuzhiyun 	ret = rvt_wss_init(rdi);
573*4882a593Smuzhiyun 	if (ret) {
574*4882a593Smuzhiyun 		rvt_pr_err(rdi, "Error in WSS init.\n");
575*4882a593Smuzhiyun 		goto bail_mr;
576*4882a593Smuzhiyun 	}
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	/* Completion queues */
579*4882a593Smuzhiyun 	spin_lock_init(&rdi->n_cqs_lock);
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	/* Protection Domain */
582*4882a593Smuzhiyun 	spin_lock_init(&rdi->n_pds_lock);
583*4882a593Smuzhiyun 	rdi->n_pds_allocated = 0;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	/*
586*4882a593Smuzhiyun 	 * There are some things which could be set by underlying drivers but
587*4882a593Smuzhiyun 	 * really should be up to rdmavt to set. For instance drivers can't know
588*4882a593Smuzhiyun 	 * exactly which functions rdmavt supports, nor do they know the ABI
589*4882a593Smuzhiyun 	 * version, so we do all of this sort of stuff here.
590*4882a593Smuzhiyun 	 */
591*4882a593Smuzhiyun 	rdi->ibdev.uverbs_cmd_mask =
592*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_GET_CONTEXT)         |
593*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE)        |
594*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_QUERY_PORT)          |
595*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_ALLOC_PD)            |
596*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_DEALLOC_PD)          |
597*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_CREATE_AH)           |
598*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_MODIFY_AH)           |
599*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_QUERY_AH)            |
600*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_DESTROY_AH)          |
601*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_REG_MR)              |
602*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_DEREG_MR)            |
603*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
604*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_CREATE_CQ)           |
605*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_RESIZE_CQ)           |
606*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_DESTROY_CQ)          |
607*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_POLL_CQ)             |
608*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ)       |
609*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_CREATE_QP)           |
610*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_QUERY_QP)            |
611*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_MODIFY_QP)           |
612*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_DESTROY_QP)          |
613*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_POST_SEND)           |
614*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_POST_RECV)           |
615*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_ATTACH_MCAST)        |
616*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_DETACH_MCAST)        |
617*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_CREATE_SRQ)          |
618*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_MODIFY_SRQ)          |
619*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_QUERY_SRQ)           |
620*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ)         |
621*4882a593Smuzhiyun 		(1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);
622*4882a593Smuzhiyun 	rdi->ibdev.node_type = RDMA_NODE_IB_CA;
623*4882a593Smuzhiyun 	if (!rdi->ibdev.num_comp_vectors)
624*4882a593Smuzhiyun 		rdi->ibdev.num_comp_vectors = 1;
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	/* We are now good to announce we exist */
627*4882a593Smuzhiyun 	ret = ib_register_device(&rdi->ibdev, dev_name(&rdi->ibdev.dev), NULL);
628*4882a593Smuzhiyun 	if (ret) {
629*4882a593Smuzhiyun 		rvt_pr_err(rdi, "Failed to register driver with ib core.\n");
630*4882a593Smuzhiyun 		goto bail_wss;
631*4882a593Smuzhiyun 	}
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	rvt_create_mad_agents(rdi);
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	rvt_pr_info(rdi, "Registration with rdmavt done.\n");
636*4882a593Smuzhiyun 	return ret;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun bail_wss:
639*4882a593Smuzhiyun 	rvt_wss_exit(rdi);
640*4882a593Smuzhiyun bail_mr:
641*4882a593Smuzhiyun 	rvt_mr_exit(rdi);
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun bail_no_mr:
644*4882a593Smuzhiyun 	rvt_qp_exit(rdi);
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	return ret;
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun EXPORT_SYMBOL(rvt_register_device);
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun /**
651*4882a593Smuzhiyun  * rvt_unregister_device - remove a driver
652*4882a593Smuzhiyun  * @rdi: rvt dev struct
653*4882a593Smuzhiyun  */
rvt_unregister_device(struct rvt_dev_info * rdi)654*4882a593Smuzhiyun void rvt_unregister_device(struct rvt_dev_info *rdi)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun 	trace_rvt_dbg(rdi, "Driver is unregistering.");
657*4882a593Smuzhiyun 	if (!rdi)
658*4882a593Smuzhiyun 		return;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	rvt_free_mad_agents(rdi);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	ib_unregister_device(&rdi->ibdev);
663*4882a593Smuzhiyun 	rvt_wss_exit(rdi);
664*4882a593Smuzhiyun 	rvt_mr_exit(rdi);
665*4882a593Smuzhiyun 	rvt_qp_exit(rdi);
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun EXPORT_SYMBOL(rvt_unregister_device);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun /**
670*4882a593Smuzhiyun  * rvt_init_port - init internal data for driver port
671*4882a593Smuzhiyun  * @rdi: rvt_dev_info struct
672*4882a593Smuzhiyun  * @port: rvt port
673*4882a593Smuzhiyun  * @port_index: 0 based index of ports, different from IB core port num
674*4882a593Smuzhiyun  * @pkey_table: pkey_table for @port
675*4882a593Smuzhiyun  *
676*4882a593Smuzhiyun  * Keep track of a list of ports. No need to have a detach port.
677*4882a593Smuzhiyun  * They persist until the driver goes away.
678*4882a593Smuzhiyun  *
679*4882a593Smuzhiyun  * Return: always 0
680*4882a593Smuzhiyun  */
rvt_init_port(struct rvt_dev_info * rdi,struct rvt_ibport * port,int port_index,u16 * pkey_table)681*4882a593Smuzhiyun int rvt_init_port(struct rvt_dev_info *rdi, struct rvt_ibport *port,
682*4882a593Smuzhiyun 		  int port_index, u16 *pkey_table)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	rdi->ports[port_index] = port;
686*4882a593Smuzhiyun 	rdi->ports[port_index]->pkey_table = pkey_table;
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	return 0;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun EXPORT_SYMBOL(rvt_init_port);
691