xref: /openbmc/linux/drivers/infiniband/core/verbs.c (revision 7083e42e)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright (c) 2004 Mellanox Technologies Ltd.  All rights reserved.
31da177e4SLinus Torvalds  * Copyright (c) 2004 Infinicon Corporation.  All rights reserved.
41da177e4SLinus Torvalds  * Copyright (c) 2004 Intel Corporation.  All rights reserved.
51da177e4SLinus Torvalds  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
61da177e4SLinus Torvalds  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
72a1d9b7fSRoland Dreier  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
833b9b3eeSRoland Dreier  * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * This software is available to you under a choice of one of two
111da177e4SLinus Torvalds  * licenses.  You may choose to be licensed under the terms of the GNU
121da177e4SLinus Torvalds  * General Public License (GPL) Version 2, available from the file
131da177e4SLinus Torvalds  * COPYING in the main directory of this source tree, or the
141da177e4SLinus Torvalds  * OpenIB.org BSD license below:
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  *     Redistribution and use in source and binary forms, with or
171da177e4SLinus Torvalds  *     without modification, are permitted provided that the following
181da177e4SLinus Torvalds  *     conditions are met:
191da177e4SLinus Torvalds  *
201da177e4SLinus Torvalds  *      - Redistributions of source code must retain the above
211da177e4SLinus Torvalds  *        copyright notice, this list of conditions and the following
221da177e4SLinus Torvalds  *        disclaimer.
231da177e4SLinus Torvalds  *
241da177e4SLinus Torvalds  *      - Redistributions in binary form must reproduce the above
251da177e4SLinus Torvalds  *        copyright notice, this list of conditions and the following
261da177e4SLinus Torvalds  *        disclaimer in the documentation and/or other materials
271da177e4SLinus Torvalds  *        provided with the distribution.
281da177e4SLinus Torvalds  *
291da177e4SLinus Torvalds  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
301da177e4SLinus Torvalds  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
311da177e4SLinus Torvalds  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
321da177e4SLinus Torvalds  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
331da177e4SLinus Torvalds  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
341da177e4SLinus Torvalds  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
351da177e4SLinus Torvalds  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
361da177e4SLinus Torvalds  * SOFTWARE.
371da177e4SLinus Torvalds  */
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds #include <linux/errno.h>
401da177e4SLinus Torvalds #include <linux/err.h>
41b108d976SPaul Gortmaker #include <linux/export.h>
428c65b4a6STim Schmielau #include <linux/string.h>
430e0ec7e0SSean Hefty #include <linux/slab.h>
441da177e4SLinus Torvalds 
45a4d61e84SRoland Dreier #include <rdma/ib_verbs.h>
46a4d61e84SRoland Dreier #include <rdma/ib_cache.h>
471da177e4SLinus Torvalds 
48bf6a9e31SJack Morgenstein int ib_rate_to_mult(enum ib_rate rate)
49bf6a9e31SJack Morgenstein {
50bf6a9e31SJack Morgenstein 	switch (rate) {
51bf6a9e31SJack Morgenstein 	case IB_RATE_2_5_GBPS: return  1;
52bf6a9e31SJack Morgenstein 	case IB_RATE_5_GBPS:   return  2;
53bf6a9e31SJack Morgenstein 	case IB_RATE_10_GBPS:  return  4;
54bf6a9e31SJack Morgenstein 	case IB_RATE_20_GBPS:  return  8;
55bf6a9e31SJack Morgenstein 	case IB_RATE_30_GBPS:  return 12;
56bf6a9e31SJack Morgenstein 	case IB_RATE_40_GBPS:  return 16;
57bf6a9e31SJack Morgenstein 	case IB_RATE_60_GBPS:  return 24;
58bf6a9e31SJack Morgenstein 	case IB_RATE_80_GBPS:  return 32;
59bf6a9e31SJack Morgenstein 	case IB_RATE_120_GBPS: return 48;
60bf6a9e31SJack Morgenstein 	default:	       return -1;
61bf6a9e31SJack Morgenstein 	}
62bf6a9e31SJack Morgenstein }
63bf6a9e31SJack Morgenstein EXPORT_SYMBOL(ib_rate_to_mult);
64bf6a9e31SJack Morgenstein 
65bf6a9e31SJack Morgenstein enum ib_rate mult_to_ib_rate(int mult)
66bf6a9e31SJack Morgenstein {
67bf6a9e31SJack Morgenstein 	switch (mult) {
68bf6a9e31SJack Morgenstein 	case 1:  return IB_RATE_2_5_GBPS;
69bf6a9e31SJack Morgenstein 	case 2:  return IB_RATE_5_GBPS;
70bf6a9e31SJack Morgenstein 	case 4:  return IB_RATE_10_GBPS;
71bf6a9e31SJack Morgenstein 	case 8:  return IB_RATE_20_GBPS;
72bf6a9e31SJack Morgenstein 	case 12: return IB_RATE_30_GBPS;
73bf6a9e31SJack Morgenstein 	case 16: return IB_RATE_40_GBPS;
74bf6a9e31SJack Morgenstein 	case 24: return IB_RATE_60_GBPS;
75bf6a9e31SJack Morgenstein 	case 32: return IB_RATE_80_GBPS;
76bf6a9e31SJack Morgenstein 	case 48: return IB_RATE_120_GBPS;
77bf6a9e31SJack Morgenstein 	default: return IB_RATE_PORT_CURRENT;
78bf6a9e31SJack Morgenstein 	}
79bf6a9e31SJack Morgenstein }
80bf6a9e31SJack Morgenstein EXPORT_SYMBOL(mult_to_ib_rate);
81bf6a9e31SJack Morgenstein 
8271eeba16SMarcel Apfelbaum int ib_rate_to_mbps(enum ib_rate rate)
8371eeba16SMarcel Apfelbaum {
8471eeba16SMarcel Apfelbaum 	switch (rate) {
8571eeba16SMarcel Apfelbaum 	case IB_RATE_2_5_GBPS: return 2500;
8671eeba16SMarcel Apfelbaum 	case IB_RATE_5_GBPS:   return 5000;
8771eeba16SMarcel Apfelbaum 	case IB_RATE_10_GBPS:  return 10000;
8871eeba16SMarcel Apfelbaum 	case IB_RATE_20_GBPS:  return 20000;
8971eeba16SMarcel Apfelbaum 	case IB_RATE_30_GBPS:  return 30000;
9071eeba16SMarcel Apfelbaum 	case IB_RATE_40_GBPS:  return 40000;
9171eeba16SMarcel Apfelbaum 	case IB_RATE_60_GBPS:  return 60000;
9271eeba16SMarcel Apfelbaum 	case IB_RATE_80_GBPS:  return 80000;
9371eeba16SMarcel Apfelbaum 	case IB_RATE_120_GBPS: return 120000;
9471eeba16SMarcel Apfelbaum 	case IB_RATE_14_GBPS:  return 14062;
9571eeba16SMarcel Apfelbaum 	case IB_RATE_56_GBPS:  return 56250;
9671eeba16SMarcel Apfelbaum 	case IB_RATE_112_GBPS: return 112500;
9771eeba16SMarcel Apfelbaum 	case IB_RATE_168_GBPS: return 168750;
9871eeba16SMarcel Apfelbaum 	case IB_RATE_25_GBPS:  return 25781;
9971eeba16SMarcel Apfelbaum 	case IB_RATE_100_GBPS: return 103125;
10071eeba16SMarcel Apfelbaum 	case IB_RATE_200_GBPS: return 206250;
10171eeba16SMarcel Apfelbaum 	case IB_RATE_300_GBPS: return 309375;
10271eeba16SMarcel Apfelbaum 	default:	       return -1;
10371eeba16SMarcel Apfelbaum 	}
10471eeba16SMarcel Apfelbaum }
10571eeba16SMarcel Apfelbaum EXPORT_SYMBOL(ib_rate_to_mbps);
10671eeba16SMarcel Apfelbaum 
10707ebafbaSTom Tucker enum rdma_transport_type
10807ebafbaSTom Tucker rdma_node_get_transport(enum rdma_node_type node_type)
10907ebafbaSTom Tucker {
11007ebafbaSTom Tucker 	switch (node_type) {
11107ebafbaSTom Tucker 	case RDMA_NODE_IB_CA:
11207ebafbaSTom Tucker 	case RDMA_NODE_IB_SWITCH:
11307ebafbaSTom Tucker 	case RDMA_NODE_IB_ROUTER:
11407ebafbaSTom Tucker 		return RDMA_TRANSPORT_IB;
11507ebafbaSTom Tucker 	case RDMA_NODE_RNIC:
11607ebafbaSTom Tucker 		return RDMA_TRANSPORT_IWARP;
11707ebafbaSTom Tucker 	default:
11807ebafbaSTom Tucker 		BUG();
11907ebafbaSTom Tucker 		return 0;
12007ebafbaSTom Tucker 	}
12107ebafbaSTom Tucker }
12207ebafbaSTom Tucker EXPORT_SYMBOL(rdma_node_get_transport);
12307ebafbaSTom Tucker 
124a3f5adafSEli Cohen enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device, u8 port_num)
125a3f5adafSEli Cohen {
126a3f5adafSEli Cohen 	if (device->get_link_layer)
127a3f5adafSEli Cohen 		return device->get_link_layer(device, port_num);
128a3f5adafSEli Cohen 
129a3f5adafSEli Cohen 	switch (rdma_node_get_transport(device->node_type)) {
130a3f5adafSEli Cohen 	case RDMA_TRANSPORT_IB:
131a3f5adafSEli Cohen 		return IB_LINK_LAYER_INFINIBAND;
132a3f5adafSEli Cohen 	case RDMA_TRANSPORT_IWARP:
133a3f5adafSEli Cohen 		return IB_LINK_LAYER_ETHERNET;
134a3f5adafSEli Cohen 	default:
135a3f5adafSEli Cohen 		return IB_LINK_LAYER_UNSPECIFIED;
136a3f5adafSEli Cohen 	}
137a3f5adafSEli Cohen }
138a3f5adafSEli Cohen EXPORT_SYMBOL(rdma_port_get_link_layer);
139a3f5adafSEli Cohen 
1401da177e4SLinus Torvalds /* Protection domains */
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds struct ib_pd *ib_alloc_pd(struct ib_device *device)
1431da177e4SLinus Torvalds {
1441da177e4SLinus Torvalds 	struct ib_pd *pd;
1451da177e4SLinus Torvalds 
146b5e81bf5SRoland Dreier 	pd = device->alloc_pd(device, NULL, NULL);
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds 	if (!IS_ERR(pd)) {
1491da177e4SLinus Torvalds 		pd->device  = device;
150b5e81bf5SRoland Dreier 		pd->uobject = NULL;
1511da177e4SLinus Torvalds 		atomic_set(&pd->usecnt, 0);
1521da177e4SLinus Torvalds 	}
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	return pd;
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds EXPORT_SYMBOL(ib_alloc_pd);
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds int ib_dealloc_pd(struct ib_pd *pd)
1591da177e4SLinus Torvalds {
1601da177e4SLinus Torvalds 	if (atomic_read(&pd->usecnt))
1611da177e4SLinus Torvalds 		return -EBUSY;
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 	return pd->device->dealloc_pd(pd);
1641da177e4SLinus Torvalds }
1651da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dealloc_pd);
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds /* Address handles */
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
1701da177e4SLinus Torvalds {
1711da177e4SLinus Torvalds 	struct ib_ah *ah;
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds 	ah = pd->device->create_ah(pd, ah_attr);
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	if (!IS_ERR(ah)) {
1761da177e4SLinus Torvalds 		ah->device  = pd->device;
1771da177e4SLinus Torvalds 		ah->pd      = pd;
178b5e81bf5SRoland Dreier 		ah->uobject = NULL;
1791da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
1801da177e4SLinus Torvalds 	}
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds 	return ah;
1831da177e4SLinus Torvalds }
1841da177e4SLinus Torvalds EXPORT_SYMBOL(ib_create_ah);
1851da177e4SLinus Torvalds 
1864e00d694SSean Hefty int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc,
1874e00d694SSean Hefty 		       struct ib_grh *grh, struct ib_ah_attr *ah_attr)
188513789edSHal Rosenstock {
189513789edSHal Rosenstock 	u32 flow_class;
190513789edSHal Rosenstock 	u16 gid_index;
191513789edSHal Rosenstock 	int ret;
192513789edSHal Rosenstock 
1934e00d694SSean Hefty 	memset(ah_attr, 0, sizeof *ah_attr);
1944e00d694SSean Hefty 	ah_attr->dlid = wc->slid;
1954e00d694SSean Hefty 	ah_attr->sl = wc->sl;
1964e00d694SSean Hefty 	ah_attr->src_path_bits = wc->dlid_path_bits;
1974e00d694SSean Hefty 	ah_attr->port_num = port_num;
198513789edSHal Rosenstock 
199513789edSHal Rosenstock 	if (wc->wc_flags & IB_WC_GRH) {
2004e00d694SSean Hefty 		ah_attr->ah_flags = IB_AH_GRH;
2014e00d694SSean Hefty 		ah_attr->grh.dgid = grh->sgid;
202513789edSHal Rosenstock 
2034e00d694SSean Hefty 		ret = ib_find_cached_gid(device, &grh->dgid, &port_num,
204513789edSHal Rosenstock 					 &gid_index);
205513789edSHal Rosenstock 		if (ret)
2064e00d694SSean Hefty 			return ret;
207513789edSHal Rosenstock 
2084e00d694SSean Hefty 		ah_attr->grh.sgid_index = (u8) gid_index;
209497677abSHal Rosenstock 		flow_class = be32_to_cpu(grh->version_tclass_flow);
2104e00d694SSean Hefty 		ah_attr->grh.flow_label = flow_class & 0xFFFFF;
21147645d8dSSean Hefty 		ah_attr->grh.hop_limit = 0xFF;
2124e00d694SSean Hefty 		ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
213513789edSHal Rosenstock 	}
2144e00d694SSean Hefty 	return 0;
2154e00d694SSean Hefty }
2164e00d694SSean Hefty EXPORT_SYMBOL(ib_init_ah_from_wc);
2174e00d694SSean Hefty 
2184e00d694SSean Hefty struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc,
2194e00d694SSean Hefty 				   struct ib_grh *grh, u8 port_num)
2204e00d694SSean Hefty {
2214e00d694SSean Hefty 	struct ib_ah_attr ah_attr;
2224e00d694SSean Hefty 	int ret;
2234e00d694SSean Hefty 
2244e00d694SSean Hefty 	ret = ib_init_ah_from_wc(pd->device, port_num, wc, grh, &ah_attr);
2254e00d694SSean Hefty 	if (ret)
2264e00d694SSean Hefty 		return ERR_PTR(ret);
227513789edSHal Rosenstock 
228513789edSHal Rosenstock 	return ib_create_ah(pd, &ah_attr);
229513789edSHal Rosenstock }
230513789edSHal Rosenstock EXPORT_SYMBOL(ib_create_ah_from_wc);
231513789edSHal Rosenstock 
2321da177e4SLinus Torvalds int ib_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
2331da177e4SLinus Torvalds {
2341da177e4SLinus Torvalds 	return ah->device->modify_ah ?
2351da177e4SLinus Torvalds 		ah->device->modify_ah(ah, ah_attr) :
2361da177e4SLinus Torvalds 		-ENOSYS;
2371da177e4SLinus Torvalds }
2381da177e4SLinus Torvalds EXPORT_SYMBOL(ib_modify_ah);
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds int ib_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
2411da177e4SLinus Torvalds {
2421da177e4SLinus Torvalds 	return ah->device->query_ah ?
2431da177e4SLinus Torvalds 		ah->device->query_ah(ah, ah_attr) :
2441da177e4SLinus Torvalds 		-ENOSYS;
2451da177e4SLinus Torvalds }
2461da177e4SLinus Torvalds EXPORT_SYMBOL(ib_query_ah);
2471da177e4SLinus Torvalds 
2481da177e4SLinus Torvalds int ib_destroy_ah(struct ib_ah *ah)
2491da177e4SLinus Torvalds {
2501da177e4SLinus Torvalds 	struct ib_pd *pd;
2511da177e4SLinus Torvalds 	int ret;
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds 	pd = ah->pd;
2541da177e4SLinus Torvalds 	ret = ah->device->destroy_ah(ah);
2551da177e4SLinus Torvalds 	if (!ret)
2561da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	return ret;
2591da177e4SLinus Torvalds }
2601da177e4SLinus Torvalds EXPORT_SYMBOL(ib_destroy_ah);
2611da177e4SLinus Torvalds 
262d41fcc67SRoland Dreier /* Shared receive queues */
263d41fcc67SRoland Dreier 
264d41fcc67SRoland Dreier struct ib_srq *ib_create_srq(struct ib_pd *pd,
265d41fcc67SRoland Dreier 			     struct ib_srq_init_attr *srq_init_attr)
266d41fcc67SRoland Dreier {
267d41fcc67SRoland Dreier 	struct ib_srq *srq;
268d41fcc67SRoland Dreier 
269d41fcc67SRoland Dreier 	if (!pd->device->create_srq)
270d41fcc67SRoland Dreier 		return ERR_PTR(-ENOSYS);
271d41fcc67SRoland Dreier 
272d41fcc67SRoland Dreier 	srq = pd->device->create_srq(pd, srq_init_attr, NULL);
273d41fcc67SRoland Dreier 
274d41fcc67SRoland Dreier 	if (!IS_ERR(srq)) {
275d41fcc67SRoland Dreier 		srq->device    	   = pd->device;
276d41fcc67SRoland Dreier 		srq->pd        	   = pd;
277d41fcc67SRoland Dreier 		srq->uobject       = NULL;
278d41fcc67SRoland Dreier 		srq->event_handler = srq_init_attr->event_handler;
279d41fcc67SRoland Dreier 		srq->srq_context   = srq_init_attr->srq_context;
28096104edaSSean Hefty 		srq->srq_type      = srq_init_attr->srq_type;
281418d5130SSean Hefty 		if (srq->srq_type == IB_SRQT_XRC) {
282418d5130SSean Hefty 			srq->ext.xrc.xrcd = srq_init_attr->ext.xrc.xrcd;
283418d5130SSean Hefty 			srq->ext.xrc.cq   = srq_init_attr->ext.xrc.cq;
284418d5130SSean Hefty 			atomic_inc(&srq->ext.xrc.xrcd->usecnt);
285418d5130SSean Hefty 			atomic_inc(&srq->ext.xrc.cq->usecnt);
286418d5130SSean Hefty 		}
287d41fcc67SRoland Dreier 		atomic_inc(&pd->usecnt);
288d41fcc67SRoland Dreier 		atomic_set(&srq->usecnt, 0);
289d41fcc67SRoland Dreier 	}
290d41fcc67SRoland Dreier 
291d41fcc67SRoland Dreier 	return srq;
292d41fcc67SRoland Dreier }
293d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_create_srq);
294d41fcc67SRoland Dreier 
295d41fcc67SRoland Dreier int ib_modify_srq(struct ib_srq *srq,
296d41fcc67SRoland Dreier 		  struct ib_srq_attr *srq_attr,
297d41fcc67SRoland Dreier 		  enum ib_srq_attr_mask srq_attr_mask)
298d41fcc67SRoland Dreier {
2997ce5eacbSDotan Barak 	return srq->device->modify_srq ?
3007ce5eacbSDotan Barak 		srq->device->modify_srq(srq, srq_attr, srq_attr_mask, NULL) :
3017ce5eacbSDotan Barak 		-ENOSYS;
302d41fcc67SRoland Dreier }
303d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_modify_srq);
304d41fcc67SRoland Dreier 
305d41fcc67SRoland Dreier int ib_query_srq(struct ib_srq *srq,
306d41fcc67SRoland Dreier 		 struct ib_srq_attr *srq_attr)
307d41fcc67SRoland Dreier {
308d41fcc67SRoland Dreier 	return srq->device->query_srq ?
309d41fcc67SRoland Dreier 		srq->device->query_srq(srq, srq_attr) : -ENOSYS;
310d41fcc67SRoland Dreier }
311d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_query_srq);
312d41fcc67SRoland Dreier 
313d41fcc67SRoland Dreier int ib_destroy_srq(struct ib_srq *srq)
314d41fcc67SRoland Dreier {
315d41fcc67SRoland Dreier 	struct ib_pd *pd;
316418d5130SSean Hefty 	enum ib_srq_type srq_type;
317418d5130SSean Hefty 	struct ib_xrcd *uninitialized_var(xrcd);
318418d5130SSean Hefty 	struct ib_cq *uninitialized_var(cq);
319d41fcc67SRoland Dreier 	int ret;
320d41fcc67SRoland Dreier 
321d41fcc67SRoland Dreier 	if (atomic_read(&srq->usecnt))
322d41fcc67SRoland Dreier 		return -EBUSY;
323d41fcc67SRoland Dreier 
324d41fcc67SRoland Dreier 	pd = srq->pd;
325418d5130SSean Hefty 	srq_type = srq->srq_type;
326418d5130SSean Hefty 	if (srq_type == IB_SRQT_XRC) {
327418d5130SSean Hefty 		xrcd = srq->ext.xrc.xrcd;
328418d5130SSean Hefty 		cq = srq->ext.xrc.cq;
329418d5130SSean Hefty 	}
330d41fcc67SRoland Dreier 
331d41fcc67SRoland Dreier 	ret = srq->device->destroy_srq(srq);
332418d5130SSean Hefty 	if (!ret) {
333d41fcc67SRoland Dreier 		atomic_dec(&pd->usecnt);
334418d5130SSean Hefty 		if (srq_type == IB_SRQT_XRC) {
335418d5130SSean Hefty 			atomic_dec(&xrcd->usecnt);
336418d5130SSean Hefty 			atomic_dec(&cq->usecnt);
337418d5130SSean Hefty 		}
338418d5130SSean Hefty 	}
339d41fcc67SRoland Dreier 
340d41fcc67SRoland Dreier 	return ret;
341d41fcc67SRoland Dreier }
342d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_destroy_srq);
343d41fcc67SRoland Dreier 
3441da177e4SLinus Torvalds /* Queue pairs */
3451da177e4SLinus Torvalds 
3460e0ec7e0SSean Hefty static void __ib_shared_qp_event_handler(struct ib_event *event, void *context)
3470e0ec7e0SSean Hefty {
3480e0ec7e0SSean Hefty 	struct ib_qp *qp = context;
3490e0ec7e0SSean Hefty 
3500e0ec7e0SSean Hefty 	list_for_each_entry(event->element.qp, &qp->open_list, open_list)
3510e0ec7e0SSean Hefty 		event->element.qp->event_handler(event, event->element.qp->qp_context);
3520e0ec7e0SSean Hefty }
3530e0ec7e0SSean Hefty 
354d3d72d90SSean Hefty static void __ib_insert_xrcd_qp(struct ib_xrcd *xrcd, struct ib_qp *qp)
355d3d72d90SSean Hefty {
356d3d72d90SSean Hefty 	mutex_lock(&xrcd->tgt_qp_mutex);
357d3d72d90SSean Hefty 	list_add(&qp->xrcd_list, &xrcd->tgt_qp_list);
358d3d72d90SSean Hefty 	mutex_unlock(&xrcd->tgt_qp_mutex);
359d3d72d90SSean Hefty }
360d3d72d90SSean Hefty 
3610e0ec7e0SSean Hefty static struct ib_qp *__ib_open_qp(struct ib_qp *real_qp,
3620e0ec7e0SSean Hefty 				  void (*event_handler)(struct ib_event *, void *),
3630e0ec7e0SSean Hefty 				  void *qp_context)
364d3d72d90SSean Hefty {
3650e0ec7e0SSean Hefty 	struct ib_qp *qp;
3660e0ec7e0SSean Hefty 	unsigned long flags;
3670e0ec7e0SSean Hefty 
3680e0ec7e0SSean Hefty 	qp = kzalloc(sizeof *qp, GFP_KERNEL);
3690e0ec7e0SSean Hefty 	if (!qp)
3700e0ec7e0SSean Hefty 		return ERR_PTR(-ENOMEM);
3710e0ec7e0SSean Hefty 
3720e0ec7e0SSean Hefty 	qp->real_qp = real_qp;
3730e0ec7e0SSean Hefty 	atomic_inc(&real_qp->usecnt);
3740e0ec7e0SSean Hefty 	qp->device = real_qp->device;
3750e0ec7e0SSean Hefty 	qp->event_handler = event_handler;
3760e0ec7e0SSean Hefty 	qp->qp_context = qp_context;
3770e0ec7e0SSean Hefty 	qp->qp_num = real_qp->qp_num;
3780e0ec7e0SSean Hefty 	qp->qp_type = real_qp->qp_type;
3790e0ec7e0SSean Hefty 
3800e0ec7e0SSean Hefty 	spin_lock_irqsave(&real_qp->device->event_handler_lock, flags);
3810e0ec7e0SSean Hefty 	list_add(&qp->open_list, &real_qp->open_list);
3820e0ec7e0SSean Hefty 	spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags);
3830e0ec7e0SSean Hefty 
3840e0ec7e0SSean Hefty 	return qp;
385d3d72d90SSean Hefty }
386d3d72d90SSean Hefty 
3870e0ec7e0SSean Hefty struct ib_qp *ib_open_qp(struct ib_xrcd *xrcd,
3880e0ec7e0SSean Hefty 			 struct ib_qp_open_attr *qp_open_attr)
3890e0ec7e0SSean Hefty {
3900e0ec7e0SSean Hefty 	struct ib_qp *qp, *real_qp;
3910e0ec7e0SSean Hefty 
3920e0ec7e0SSean Hefty 	if (qp_open_attr->qp_type != IB_QPT_XRC_TGT)
3930e0ec7e0SSean Hefty 		return ERR_PTR(-EINVAL);
3940e0ec7e0SSean Hefty 
3950e0ec7e0SSean Hefty 	qp = ERR_PTR(-EINVAL);
3960e0ec7e0SSean Hefty 	mutex_lock(&xrcd->tgt_qp_mutex);
3970e0ec7e0SSean Hefty 	list_for_each_entry(real_qp, &xrcd->tgt_qp_list, xrcd_list) {
3980e0ec7e0SSean Hefty 		if (real_qp->qp_num == qp_open_attr->qp_num) {
3990e0ec7e0SSean Hefty 			qp = __ib_open_qp(real_qp, qp_open_attr->event_handler,
4000e0ec7e0SSean Hefty 					  qp_open_attr->qp_context);
4010e0ec7e0SSean Hefty 			break;
4020e0ec7e0SSean Hefty 		}
4030e0ec7e0SSean Hefty 	}
4040e0ec7e0SSean Hefty 	mutex_unlock(&xrcd->tgt_qp_mutex);
4050e0ec7e0SSean Hefty 	return qp;
4060e0ec7e0SSean Hefty }
4070e0ec7e0SSean Hefty EXPORT_SYMBOL(ib_open_qp);
4080e0ec7e0SSean Hefty 
4091da177e4SLinus Torvalds struct ib_qp *ib_create_qp(struct ib_pd *pd,
4101da177e4SLinus Torvalds 			   struct ib_qp_init_attr *qp_init_attr)
4111da177e4SLinus Torvalds {
4120e0ec7e0SSean Hefty 	struct ib_qp *qp, *real_qp;
413b42b63cfSSean Hefty 	struct ib_device *device;
4141da177e4SLinus Torvalds 
415b42b63cfSSean Hefty 	device = pd ? pd->device : qp_init_attr->xrcd->device;
416b42b63cfSSean Hefty 	qp = device->create_qp(pd, qp_init_attr, NULL);
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds 	if (!IS_ERR(qp)) {
419b42b63cfSSean Hefty 		qp->device     = device;
4200e0ec7e0SSean Hefty 		qp->real_qp    = qp;
421b5e81bf5SRoland Dreier 		qp->uobject    = NULL;
4220e0ec7e0SSean Hefty 		qp->qp_type    = qp_init_attr->qp_type;
423b42b63cfSSean Hefty 
424e47e321aSBernd Schubert 		atomic_set(&qp->usecnt, 0);
425b42b63cfSSean Hefty 		if (qp_init_attr->qp_type == IB_QPT_XRC_TGT) {
4260e0ec7e0SSean Hefty 			qp->event_handler = __ib_shared_qp_event_handler;
4270e0ec7e0SSean Hefty 			qp->qp_context = qp;
428b42b63cfSSean Hefty 			qp->pd = NULL;
429b42b63cfSSean Hefty 			qp->send_cq = qp->recv_cq = NULL;
430b42b63cfSSean Hefty 			qp->srq = NULL;
431b42b63cfSSean Hefty 			qp->xrcd = qp_init_attr->xrcd;
432b42b63cfSSean Hefty 			atomic_inc(&qp_init_attr->xrcd->usecnt);
4330e0ec7e0SSean Hefty 			INIT_LIST_HEAD(&qp->open_list);
4340e0ec7e0SSean Hefty 
4350e0ec7e0SSean Hefty 			real_qp = qp;
4360e0ec7e0SSean Hefty 			qp = __ib_open_qp(real_qp, qp_init_attr->event_handler,
4370e0ec7e0SSean Hefty 					  qp_init_attr->qp_context);
4380e0ec7e0SSean Hefty 			if (!IS_ERR(qp))
4390e0ec7e0SSean Hefty 				__ib_insert_xrcd_qp(qp_init_attr->xrcd, real_qp);
4400e0ec7e0SSean Hefty 			else
4410e0ec7e0SSean Hefty 				real_qp->device->destroy_qp(real_qp);
442b42b63cfSSean Hefty 		} else {
4431da177e4SLinus Torvalds 			qp->event_handler = qp_init_attr->event_handler;
4441da177e4SLinus Torvalds 			qp->qp_context = qp_init_attr->qp_context;
445b42b63cfSSean Hefty 			if (qp_init_attr->qp_type == IB_QPT_XRC_INI) {
446b42b63cfSSean Hefty 				qp->recv_cq = NULL;
447b42b63cfSSean Hefty 				qp->srq = NULL;
448b42b63cfSSean Hefty 			} else {
449b42b63cfSSean Hefty 				qp->recv_cq = qp_init_attr->recv_cq;
450b42b63cfSSean Hefty 				atomic_inc(&qp_init_attr->recv_cq->usecnt);
451b42b63cfSSean Hefty 				qp->srq = qp_init_attr->srq;
452b42b63cfSSean Hefty 				if (qp->srq)
453b42b63cfSSean Hefty 					atomic_inc(&qp_init_attr->srq->usecnt);
454b42b63cfSSean Hefty 			}
455b42b63cfSSean Hefty 
4561da177e4SLinus Torvalds 			qp->pd	    = pd;
4571da177e4SLinus Torvalds 			qp->send_cq = qp_init_attr->send_cq;
458b42b63cfSSean Hefty 			qp->xrcd    = NULL;
459b42b63cfSSean Hefty 
4601da177e4SLinus Torvalds 			atomic_inc(&pd->usecnt);
4611da177e4SLinus Torvalds 			atomic_inc(&qp_init_attr->send_cq->usecnt);
462b42b63cfSSean Hefty 		}
4631da177e4SLinus Torvalds 	}
4641da177e4SLinus Torvalds 
4651da177e4SLinus Torvalds 	return qp;
4661da177e4SLinus Torvalds }
4671da177e4SLinus Torvalds EXPORT_SYMBOL(ib_create_qp);
4681da177e4SLinus Torvalds 
4698a51866fSRoland Dreier static const struct {
4708a51866fSRoland Dreier 	int			valid;
471b42b63cfSSean Hefty 	enum ib_qp_attr_mask	req_param[IB_QPT_MAX];
472b42b63cfSSean Hefty 	enum ib_qp_attr_mask	opt_param[IB_QPT_MAX];
4738a51866fSRoland Dreier } qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
4748a51866fSRoland Dreier 	[IB_QPS_RESET] = {
4758a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
4768a51866fSRoland Dreier 		[IB_QPS_INIT]  = {
4778a51866fSRoland Dreier 			.valid = 1,
4788a51866fSRoland Dreier 			.req_param = {
4798a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
4808a51866fSRoland Dreier 						IB_QP_PORT			|
4818a51866fSRoland Dreier 						IB_QP_QKEY),
482c938a616SOr Gerlitz 				[IB_QPT_RAW_PACKET] = IB_QP_PORT,
4838a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
4848a51866fSRoland Dreier 						IB_QP_PORT			|
4858a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
4868a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
4878a51866fSRoland Dreier 						IB_QP_PORT			|
4888a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
489b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_PKEY_INDEX		|
490b42b63cfSSean Hefty 						IB_QP_PORT			|
491b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS),
492b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_PKEY_INDEX		|
493b42b63cfSSean Hefty 						IB_QP_PORT			|
494b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS),
4958a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
4968a51866fSRoland Dreier 						IB_QP_QKEY),
4978a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
4988a51866fSRoland Dreier 						IB_QP_QKEY),
4998a51866fSRoland Dreier 			}
5008a51866fSRoland Dreier 		},
5018a51866fSRoland Dreier 	},
5028a51866fSRoland Dreier 	[IB_QPS_INIT]  = {
5038a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
5048a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
5058a51866fSRoland Dreier 		[IB_QPS_INIT]  = {
5068a51866fSRoland Dreier 			.valid = 1,
5078a51866fSRoland Dreier 			.opt_param = {
5088a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
5098a51866fSRoland Dreier 						IB_QP_PORT			|
5108a51866fSRoland Dreier 						IB_QP_QKEY),
5118a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
5128a51866fSRoland Dreier 						IB_QP_PORT			|
5138a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
5148a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
5158a51866fSRoland Dreier 						IB_QP_PORT			|
5168a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
517b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_PKEY_INDEX		|
518b42b63cfSSean Hefty 						IB_QP_PORT			|
519b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS),
520b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_PKEY_INDEX		|
521b42b63cfSSean Hefty 						IB_QP_PORT			|
522b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS),
5238a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
5248a51866fSRoland Dreier 						IB_QP_QKEY),
5258a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
5268a51866fSRoland Dreier 						IB_QP_QKEY),
5278a51866fSRoland Dreier 			}
5288a51866fSRoland Dreier 		},
5298a51866fSRoland Dreier 		[IB_QPS_RTR]   = {
5308a51866fSRoland Dreier 			.valid = 1,
5318a51866fSRoland Dreier 			.req_param = {
5328a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_AV			|
5338a51866fSRoland Dreier 						IB_QP_PATH_MTU			|
5348a51866fSRoland Dreier 						IB_QP_DEST_QPN			|
5358a51866fSRoland Dreier 						IB_QP_RQ_PSN),
5368a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_AV			|
5378a51866fSRoland Dreier 						IB_QP_PATH_MTU			|
5388a51866fSRoland Dreier 						IB_QP_DEST_QPN			|
5398a51866fSRoland Dreier 						IB_QP_RQ_PSN			|
5408a51866fSRoland Dreier 						IB_QP_MAX_DEST_RD_ATOMIC	|
5418a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER),
542b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_AV			|
543b42b63cfSSean Hefty 						IB_QP_PATH_MTU			|
544b42b63cfSSean Hefty 						IB_QP_DEST_QPN			|
545b42b63cfSSean Hefty 						IB_QP_RQ_PSN),
546b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_AV			|
547b42b63cfSSean Hefty 						IB_QP_PATH_MTU			|
548b42b63cfSSean Hefty 						IB_QP_DEST_QPN			|
549b42b63cfSSean Hefty 						IB_QP_RQ_PSN			|
550b42b63cfSSean Hefty 						IB_QP_MAX_DEST_RD_ATOMIC	|
551b42b63cfSSean Hefty 						IB_QP_MIN_RNR_TIMER),
5528a51866fSRoland Dreier 			},
5538a51866fSRoland Dreier 			.opt_param = {
5548a51866fSRoland Dreier 				 [IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
5558a51866fSRoland Dreier 						 IB_QP_QKEY),
5568a51866fSRoland Dreier 				 [IB_QPT_UC]  = (IB_QP_ALT_PATH			|
5578a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
5588a51866fSRoland Dreier 						 IB_QP_PKEY_INDEX),
5598a51866fSRoland Dreier 				 [IB_QPT_RC]  = (IB_QP_ALT_PATH			|
5608a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
5618a51866fSRoland Dreier 						 IB_QP_PKEY_INDEX),
562b42b63cfSSean Hefty 				 [IB_QPT_XRC_INI] = (IB_QP_ALT_PATH		|
563b42b63cfSSean Hefty 						 IB_QP_ACCESS_FLAGS		|
564b42b63cfSSean Hefty 						 IB_QP_PKEY_INDEX),
565b42b63cfSSean Hefty 				 [IB_QPT_XRC_TGT] = (IB_QP_ALT_PATH		|
566b42b63cfSSean Hefty 						 IB_QP_ACCESS_FLAGS		|
567b42b63cfSSean Hefty 						 IB_QP_PKEY_INDEX),
5688a51866fSRoland Dreier 				 [IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
5698a51866fSRoland Dreier 						 IB_QP_QKEY),
5708a51866fSRoland Dreier 				 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
5718a51866fSRoland Dreier 						 IB_QP_QKEY),
5728a51866fSRoland Dreier 			 }
5738a51866fSRoland Dreier 		}
5748a51866fSRoland Dreier 	},
5758a51866fSRoland Dreier 	[IB_QPS_RTR]   = {
5768a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
5778a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
5788a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
5798a51866fSRoland Dreier 			.valid = 1,
5808a51866fSRoland Dreier 			.req_param = {
5818a51866fSRoland Dreier 				[IB_QPT_UD]  = IB_QP_SQ_PSN,
5828a51866fSRoland Dreier 				[IB_QPT_UC]  = IB_QP_SQ_PSN,
5838a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_TIMEOUT			|
5848a51866fSRoland Dreier 						IB_QP_RETRY_CNT			|
5858a51866fSRoland Dreier 						IB_QP_RNR_RETRY			|
5868a51866fSRoland Dreier 						IB_QP_SQ_PSN			|
5878a51866fSRoland Dreier 						IB_QP_MAX_QP_RD_ATOMIC),
588b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_TIMEOUT		|
589b42b63cfSSean Hefty 						IB_QP_RETRY_CNT			|
590b42b63cfSSean Hefty 						IB_QP_RNR_RETRY			|
591b42b63cfSSean Hefty 						IB_QP_SQ_PSN			|
592b42b63cfSSean Hefty 						IB_QP_MAX_QP_RD_ATOMIC),
593b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_TIMEOUT		|
594b42b63cfSSean Hefty 						IB_QP_SQ_PSN),
5958a51866fSRoland Dreier 				[IB_QPT_SMI] = IB_QP_SQ_PSN,
5968a51866fSRoland Dreier 				[IB_QPT_GSI] = IB_QP_SQ_PSN,
5978a51866fSRoland Dreier 			},
5988a51866fSRoland Dreier 			.opt_param = {
5998a51866fSRoland Dreier 				 [IB_QPT_UD]  = (IB_QP_CUR_STATE		|
6008a51866fSRoland Dreier 						 IB_QP_QKEY),
6018a51866fSRoland Dreier 				 [IB_QPT_UC]  = (IB_QP_CUR_STATE		|
6028a51866fSRoland Dreier 						 IB_QP_ALT_PATH			|
6038a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
6048a51866fSRoland Dreier 						 IB_QP_PATH_MIG_STATE),
6058a51866fSRoland Dreier 				 [IB_QPT_RC]  = (IB_QP_CUR_STATE		|
6068a51866fSRoland Dreier 						 IB_QP_ALT_PATH			|
6078a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
6088a51866fSRoland Dreier 						 IB_QP_MIN_RNR_TIMER		|
6098a51866fSRoland Dreier 						 IB_QP_PATH_MIG_STATE),
610b42b63cfSSean Hefty 				 [IB_QPT_XRC_INI] = (IB_QP_CUR_STATE		|
611b42b63cfSSean Hefty 						 IB_QP_ALT_PATH			|
612b42b63cfSSean Hefty 						 IB_QP_ACCESS_FLAGS		|
613b42b63cfSSean Hefty 						 IB_QP_PATH_MIG_STATE),
614b42b63cfSSean Hefty 				 [IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE		|
615b42b63cfSSean Hefty 						 IB_QP_ALT_PATH			|
616b42b63cfSSean Hefty 						 IB_QP_ACCESS_FLAGS		|
617b42b63cfSSean Hefty 						 IB_QP_MIN_RNR_TIMER		|
618b42b63cfSSean Hefty 						 IB_QP_PATH_MIG_STATE),
6198a51866fSRoland Dreier 				 [IB_QPT_SMI] = (IB_QP_CUR_STATE		|
6208a51866fSRoland Dreier 						 IB_QP_QKEY),
6218a51866fSRoland Dreier 				 [IB_QPT_GSI] = (IB_QP_CUR_STATE		|
6228a51866fSRoland Dreier 						 IB_QP_QKEY),
6238a51866fSRoland Dreier 			 }
6248a51866fSRoland Dreier 		}
6258a51866fSRoland Dreier 	},
6268a51866fSRoland Dreier 	[IB_QPS_RTS]   = {
6278a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
6288a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
6298a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
6308a51866fSRoland Dreier 			.valid = 1,
6318a51866fSRoland Dreier 			.opt_param = {
6328a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
6338a51866fSRoland Dreier 						IB_QP_QKEY),
6344546d31dSDotan Barak 				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
6354546d31dSDotan Barak 						IB_QP_ACCESS_FLAGS		|
6368a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
6378a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
6384546d31dSDotan Barak 				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
6394546d31dSDotan Barak 						IB_QP_ACCESS_FLAGS		|
6408a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
6418a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE		|
6428a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER),
643b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_CUR_STATE		|
644b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
645b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
646b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
647b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE		|
648b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
649b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
650b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE		|
651b42b63cfSSean Hefty 						IB_QP_MIN_RNR_TIMER),
6528a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
6538a51866fSRoland Dreier 						IB_QP_QKEY),
6548a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
6558a51866fSRoland Dreier 						IB_QP_QKEY),
6568a51866fSRoland Dreier 			}
6578a51866fSRoland Dreier 		},
6588a51866fSRoland Dreier 		[IB_QPS_SQD]   = {
6598a51866fSRoland Dreier 			.valid = 1,
6608a51866fSRoland Dreier 			.opt_param = {
6618a51866fSRoland Dreier 				[IB_QPT_UD]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
6628a51866fSRoland Dreier 				[IB_QPT_UC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
6638a51866fSRoland Dreier 				[IB_QPT_RC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
664b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
665b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = IB_QP_EN_SQD_ASYNC_NOTIFY, /* ??? */
6668a51866fSRoland Dreier 				[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
6678a51866fSRoland Dreier 				[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
6688a51866fSRoland Dreier 			}
6698a51866fSRoland Dreier 		},
6708a51866fSRoland Dreier 	},
6718a51866fSRoland Dreier 	[IB_QPS_SQD]   = {
6728a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
6738a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
6748a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
6758a51866fSRoland Dreier 			.valid = 1,
6768a51866fSRoland Dreier 			.opt_param = {
6778a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
6788a51866fSRoland Dreier 						IB_QP_QKEY),
6798a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
6808a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
6818a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
6828a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
6838a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
6848a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
6858a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
6868a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER		|
6878a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
688b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_CUR_STATE		|
689b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
690b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
691b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
692b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE		|
693b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
694b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
695b42b63cfSSean Hefty 						IB_QP_MIN_RNR_TIMER		|
696b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
6978a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
6988a51866fSRoland Dreier 						IB_QP_QKEY),
6998a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
7008a51866fSRoland Dreier 						IB_QP_QKEY),
7018a51866fSRoland Dreier 			}
7028a51866fSRoland Dreier 		},
7038a51866fSRoland Dreier 		[IB_QPS_SQD]   = {
7048a51866fSRoland Dreier 			.valid = 1,
7058a51866fSRoland Dreier 			.opt_param = {
7068a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
7078a51866fSRoland Dreier 						IB_QP_QKEY),
7088a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_AV			|
7098a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
7108a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
7118a51866fSRoland Dreier 						IB_QP_PKEY_INDEX		|
7128a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
7138a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_PORT			|
7148a51866fSRoland Dreier 						IB_QP_AV			|
7158a51866fSRoland Dreier 						IB_QP_TIMEOUT			|
7168a51866fSRoland Dreier 						IB_QP_RETRY_CNT			|
7178a51866fSRoland Dreier 						IB_QP_RNR_RETRY			|
7188a51866fSRoland Dreier 						IB_QP_MAX_QP_RD_ATOMIC		|
7198a51866fSRoland Dreier 						IB_QP_MAX_DEST_RD_ATOMIC	|
7208a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
7218a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
7228a51866fSRoland Dreier 						IB_QP_PKEY_INDEX		|
7238a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER		|
7248a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
725b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_PORT			|
726b42b63cfSSean Hefty 						IB_QP_AV			|
727b42b63cfSSean Hefty 						IB_QP_TIMEOUT			|
728b42b63cfSSean Hefty 						IB_QP_RETRY_CNT			|
729b42b63cfSSean Hefty 						IB_QP_RNR_RETRY			|
730b42b63cfSSean Hefty 						IB_QP_MAX_QP_RD_ATOMIC		|
731b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
732b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
733b42b63cfSSean Hefty 						IB_QP_PKEY_INDEX		|
734b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
735b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_PORT			|
736b42b63cfSSean Hefty 						IB_QP_AV			|
737b42b63cfSSean Hefty 						IB_QP_TIMEOUT			|
738b42b63cfSSean Hefty 						IB_QP_MAX_DEST_RD_ATOMIC	|
739b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
740b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
741b42b63cfSSean Hefty 						IB_QP_PKEY_INDEX		|
742b42b63cfSSean Hefty 						IB_QP_MIN_RNR_TIMER		|
743b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
7448a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
7458a51866fSRoland Dreier 						IB_QP_QKEY),
7468a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
7478a51866fSRoland Dreier 						IB_QP_QKEY),
7488a51866fSRoland Dreier 			}
7498a51866fSRoland Dreier 		}
7508a51866fSRoland Dreier 	},
7518a51866fSRoland Dreier 	[IB_QPS_SQE]   = {
7528a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
7538a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
7548a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
7558a51866fSRoland Dreier 			.valid = 1,
7568a51866fSRoland Dreier 			.opt_param = {
7578a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
7588a51866fSRoland Dreier 						IB_QP_QKEY),
7598a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
7608a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
7618a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
7628a51866fSRoland Dreier 						IB_QP_QKEY),
7638a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
7648a51866fSRoland Dreier 						IB_QP_QKEY),
7658a51866fSRoland Dreier 			}
7668a51866fSRoland Dreier 		}
7678a51866fSRoland Dreier 	},
7688a51866fSRoland Dreier 	[IB_QPS_ERR] = {
7698a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
7708a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 }
7718a51866fSRoland Dreier 	}
7728a51866fSRoland Dreier };
7738a51866fSRoland Dreier 
7748a51866fSRoland Dreier int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
7758a51866fSRoland Dreier 		       enum ib_qp_type type, enum ib_qp_attr_mask mask)
7768a51866fSRoland Dreier {
7778a51866fSRoland Dreier 	enum ib_qp_attr_mask req_param, opt_param;
7788a51866fSRoland Dreier 
7798a51866fSRoland Dreier 	if (cur_state  < 0 || cur_state  > IB_QPS_ERR ||
7808a51866fSRoland Dreier 	    next_state < 0 || next_state > IB_QPS_ERR)
7818a51866fSRoland Dreier 		return 0;
7828a51866fSRoland Dreier 
7838a51866fSRoland Dreier 	if (mask & IB_QP_CUR_STATE  &&
7848a51866fSRoland Dreier 	    cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
7858a51866fSRoland Dreier 	    cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE)
7868a51866fSRoland Dreier 		return 0;
7878a51866fSRoland Dreier 
7888a51866fSRoland Dreier 	if (!qp_state_table[cur_state][next_state].valid)
7898a51866fSRoland Dreier 		return 0;
7908a51866fSRoland Dreier 
7918a51866fSRoland Dreier 	req_param = qp_state_table[cur_state][next_state].req_param[type];
7928a51866fSRoland Dreier 	opt_param = qp_state_table[cur_state][next_state].opt_param[type];
7938a51866fSRoland Dreier 
7948a51866fSRoland Dreier 	if ((mask & req_param) != req_param)
7958a51866fSRoland Dreier 		return 0;
7968a51866fSRoland Dreier 
7978a51866fSRoland Dreier 	if (mask & ~(req_param | opt_param | IB_QP_STATE))
7988a51866fSRoland Dreier 		return 0;
7998a51866fSRoland Dreier 
8008a51866fSRoland Dreier 	return 1;
8018a51866fSRoland Dreier }
8028a51866fSRoland Dreier EXPORT_SYMBOL(ib_modify_qp_is_ok);
8038a51866fSRoland Dreier 
8041da177e4SLinus Torvalds int ib_modify_qp(struct ib_qp *qp,
8051da177e4SLinus Torvalds 		 struct ib_qp_attr *qp_attr,
8061da177e4SLinus Torvalds 		 int qp_attr_mask)
8071da177e4SLinus Torvalds {
8080e0ec7e0SSean Hefty 	return qp->device->modify_qp(qp->real_qp, qp_attr, qp_attr_mask, NULL);
8091da177e4SLinus Torvalds }
8101da177e4SLinus Torvalds EXPORT_SYMBOL(ib_modify_qp);
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds int ib_query_qp(struct ib_qp *qp,
8131da177e4SLinus Torvalds 		struct ib_qp_attr *qp_attr,
8141da177e4SLinus Torvalds 		int qp_attr_mask,
8151da177e4SLinus Torvalds 		struct ib_qp_init_attr *qp_init_attr)
8161da177e4SLinus Torvalds {
8171da177e4SLinus Torvalds 	return qp->device->query_qp ?
8180e0ec7e0SSean Hefty 		qp->device->query_qp(qp->real_qp, qp_attr, qp_attr_mask, qp_init_attr) :
8191da177e4SLinus Torvalds 		-ENOSYS;
8201da177e4SLinus Torvalds }
8211da177e4SLinus Torvalds EXPORT_SYMBOL(ib_query_qp);
8221da177e4SLinus Torvalds 
8230e0ec7e0SSean Hefty int ib_close_qp(struct ib_qp *qp)
8240e0ec7e0SSean Hefty {
8250e0ec7e0SSean Hefty 	struct ib_qp *real_qp;
8260e0ec7e0SSean Hefty 	unsigned long flags;
8270e0ec7e0SSean Hefty 
8280e0ec7e0SSean Hefty 	real_qp = qp->real_qp;
8290e0ec7e0SSean Hefty 	if (real_qp == qp)
8300e0ec7e0SSean Hefty 		return -EINVAL;
8310e0ec7e0SSean Hefty 
8320e0ec7e0SSean Hefty 	spin_lock_irqsave(&real_qp->device->event_handler_lock, flags);
8330e0ec7e0SSean Hefty 	list_del(&qp->open_list);
8340e0ec7e0SSean Hefty 	spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags);
8350e0ec7e0SSean Hefty 
8360e0ec7e0SSean Hefty 	atomic_dec(&real_qp->usecnt);
8370e0ec7e0SSean Hefty 	kfree(qp);
8380e0ec7e0SSean Hefty 
8390e0ec7e0SSean Hefty 	return 0;
8400e0ec7e0SSean Hefty }
8410e0ec7e0SSean Hefty EXPORT_SYMBOL(ib_close_qp);
8420e0ec7e0SSean Hefty 
8430e0ec7e0SSean Hefty static int __ib_destroy_shared_qp(struct ib_qp *qp)
8440e0ec7e0SSean Hefty {
8450e0ec7e0SSean Hefty 	struct ib_xrcd *xrcd;
8460e0ec7e0SSean Hefty 	struct ib_qp *real_qp;
8470e0ec7e0SSean Hefty 	int ret;
8480e0ec7e0SSean Hefty 
8490e0ec7e0SSean Hefty 	real_qp = qp->real_qp;
8500e0ec7e0SSean Hefty 	xrcd = real_qp->xrcd;
8510e0ec7e0SSean Hefty 
8520e0ec7e0SSean Hefty 	mutex_lock(&xrcd->tgt_qp_mutex);
8530e0ec7e0SSean Hefty 	ib_close_qp(qp);
8540e0ec7e0SSean Hefty 	if (atomic_read(&real_qp->usecnt) == 0)
8550e0ec7e0SSean Hefty 		list_del(&real_qp->xrcd_list);
8560e0ec7e0SSean Hefty 	else
8570e0ec7e0SSean Hefty 		real_qp = NULL;
8580e0ec7e0SSean Hefty 	mutex_unlock(&xrcd->tgt_qp_mutex);
8590e0ec7e0SSean Hefty 
8600e0ec7e0SSean Hefty 	if (real_qp) {
8610e0ec7e0SSean Hefty 		ret = ib_destroy_qp(real_qp);
8620e0ec7e0SSean Hefty 		if (!ret)
8630e0ec7e0SSean Hefty 			atomic_dec(&xrcd->usecnt);
8640e0ec7e0SSean Hefty 		else
8650e0ec7e0SSean Hefty 			__ib_insert_xrcd_qp(xrcd, real_qp);
8660e0ec7e0SSean Hefty 	}
8670e0ec7e0SSean Hefty 
8680e0ec7e0SSean Hefty 	return 0;
8690e0ec7e0SSean Hefty }
8700e0ec7e0SSean Hefty 
8711da177e4SLinus Torvalds int ib_destroy_qp(struct ib_qp *qp)
8721da177e4SLinus Torvalds {
8731da177e4SLinus Torvalds 	struct ib_pd *pd;
8741da177e4SLinus Torvalds 	struct ib_cq *scq, *rcq;
8751da177e4SLinus Torvalds 	struct ib_srq *srq;
8761da177e4SLinus Torvalds 	int ret;
8771da177e4SLinus Torvalds 
8780e0ec7e0SSean Hefty 	if (atomic_read(&qp->usecnt))
8790e0ec7e0SSean Hefty 		return -EBUSY;
8800e0ec7e0SSean Hefty 
8810e0ec7e0SSean Hefty 	if (qp->real_qp != qp)
8820e0ec7e0SSean Hefty 		return __ib_destroy_shared_qp(qp);
8830e0ec7e0SSean Hefty 
8841da177e4SLinus Torvalds 	pd   = qp->pd;
8851da177e4SLinus Torvalds 	scq  = qp->send_cq;
8861da177e4SLinus Torvalds 	rcq  = qp->recv_cq;
8871da177e4SLinus Torvalds 	srq  = qp->srq;
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds 	ret = qp->device->destroy_qp(qp);
8901da177e4SLinus Torvalds 	if (!ret) {
891b42b63cfSSean Hefty 		if (pd)
8921da177e4SLinus Torvalds 			atomic_dec(&pd->usecnt);
893b42b63cfSSean Hefty 		if (scq)
8941da177e4SLinus Torvalds 			atomic_dec(&scq->usecnt);
895b42b63cfSSean Hefty 		if (rcq)
8961da177e4SLinus Torvalds 			atomic_dec(&rcq->usecnt);
8971da177e4SLinus Torvalds 		if (srq)
8981da177e4SLinus Torvalds 			atomic_dec(&srq->usecnt);
8991da177e4SLinus Torvalds 	}
9001da177e4SLinus Torvalds 
9011da177e4SLinus Torvalds 	return ret;
9021da177e4SLinus Torvalds }
9031da177e4SLinus Torvalds EXPORT_SYMBOL(ib_destroy_qp);
9041da177e4SLinus Torvalds 
9051da177e4SLinus Torvalds /* Completion queues */
9061da177e4SLinus Torvalds 
9071da177e4SLinus Torvalds struct ib_cq *ib_create_cq(struct ib_device *device,
9081da177e4SLinus Torvalds 			   ib_comp_handler comp_handler,
9091da177e4SLinus Torvalds 			   void (*event_handler)(struct ib_event *, void *),
910f4fd0b22SMichael S. Tsirkin 			   void *cq_context, int cqe, int comp_vector)
9111da177e4SLinus Torvalds {
9121da177e4SLinus Torvalds 	struct ib_cq *cq;
9131da177e4SLinus Torvalds 
914f4fd0b22SMichael S. Tsirkin 	cq = device->create_cq(device, cqe, comp_vector, NULL, NULL);
9151da177e4SLinus Torvalds 
9161da177e4SLinus Torvalds 	if (!IS_ERR(cq)) {
9171da177e4SLinus Torvalds 		cq->device        = device;
918b5e81bf5SRoland Dreier 		cq->uobject       = NULL;
9191da177e4SLinus Torvalds 		cq->comp_handler  = comp_handler;
9201da177e4SLinus Torvalds 		cq->event_handler = event_handler;
9211da177e4SLinus Torvalds 		cq->cq_context    = cq_context;
9221da177e4SLinus Torvalds 		atomic_set(&cq->usecnt, 0);
9231da177e4SLinus Torvalds 	}
9241da177e4SLinus Torvalds 
9251da177e4SLinus Torvalds 	return cq;
9261da177e4SLinus Torvalds }
9271da177e4SLinus Torvalds EXPORT_SYMBOL(ib_create_cq);
9281da177e4SLinus Torvalds 
9292dd57162SEli Cohen int ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
9302dd57162SEli Cohen {
9312dd57162SEli Cohen 	return cq->device->modify_cq ?
9322dd57162SEli Cohen 		cq->device->modify_cq(cq, cq_count, cq_period) : -ENOSYS;
9332dd57162SEli Cohen }
9342dd57162SEli Cohen EXPORT_SYMBOL(ib_modify_cq);
9352dd57162SEli Cohen 
9361da177e4SLinus Torvalds int ib_destroy_cq(struct ib_cq *cq)
9371da177e4SLinus Torvalds {
9381da177e4SLinus Torvalds 	if (atomic_read(&cq->usecnt))
9391da177e4SLinus Torvalds 		return -EBUSY;
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds 	return cq->device->destroy_cq(cq);
9421da177e4SLinus Torvalds }
9431da177e4SLinus Torvalds EXPORT_SYMBOL(ib_destroy_cq);
9441da177e4SLinus Torvalds 
945a74cd4afSRoland Dreier int ib_resize_cq(struct ib_cq *cq, int cqe)
9461da177e4SLinus Torvalds {
94740de2e54SRoland Dreier 	return cq->device->resize_cq ?
94833b9b3eeSRoland Dreier 		cq->device->resize_cq(cq, cqe, NULL) : -ENOSYS;
9491da177e4SLinus Torvalds }
9501da177e4SLinus Torvalds EXPORT_SYMBOL(ib_resize_cq);
9511da177e4SLinus Torvalds 
9521da177e4SLinus Torvalds /* Memory regions */
9531da177e4SLinus Torvalds 
9541da177e4SLinus Torvalds struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
9551da177e4SLinus Torvalds {
9561da177e4SLinus Torvalds 	struct ib_mr *mr;
9571da177e4SLinus Torvalds 
9581da177e4SLinus Torvalds 	mr = pd->device->get_dma_mr(pd, mr_access_flags);
9591da177e4SLinus Torvalds 
9601da177e4SLinus Torvalds 	if (!IS_ERR(mr)) {
9611da177e4SLinus Torvalds 		mr->device  = pd->device;
9621da177e4SLinus Torvalds 		mr->pd      = pd;
963b5e81bf5SRoland Dreier 		mr->uobject = NULL;
9641da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
9651da177e4SLinus Torvalds 		atomic_set(&mr->usecnt, 0);
9661da177e4SLinus Torvalds 	}
9671da177e4SLinus Torvalds 
9681da177e4SLinus Torvalds 	return mr;
9691da177e4SLinus Torvalds }
9701da177e4SLinus Torvalds EXPORT_SYMBOL(ib_get_dma_mr);
9711da177e4SLinus Torvalds 
9721da177e4SLinus Torvalds struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd,
9731da177e4SLinus Torvalds 			     struct ib_phys_buf *phys_buf_array,
9741da177e4SLinus Torvalds 			     int num_phys_buf,
9751da177e4SLinus Torvalds 			     int mr_access_flags,
9761da177e4SLinus Torvalds 			     u64 *iova_start)
9771da177e4SLinus Torvalds {
9781da177e4SLinus Torvalds 	struct ib_mr *mr;
9791da177e4SLinus Torvalds 
9807ce5eacbSDotan Barak 	if (!pd->device->reg_phys_mr)
9817ce5eacbSDotan Barak 		return ERR_PTR(-ENOSYS);
9827ce5eacbSDotan Barak 
9831da177e4SLinus Torvalds 	mr = pd->device->reg_phys_mr(pd, phys_buf_array, num_phys_buf,
9841da177e4SLinus Torvalds 				     mr_access_flags, iova_start);
9851da177e4SLinus Torvalds 
9861da177e4SLinus Torvalds 	if (!IS_ERR(mr)) {
9871da177e4SLinus Torvalds 		mr->device  = pd->device;
9881da177e4SLinus Torvalds 		mr->pd      = pd;
989b5e81bf5SRoland Dreier 		mr->uobject = NULL;
9901da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
9911da177e4SLinus Torvalds 		atomic_set(&mr->usecnt, 0);
9921da177e4SLinus Torvalds 	}
9931da177e4SLinus Torvalds 
9941da177e4SLinus Torvalds 	return mr;
9951da177e4SLinus Torvalds }
9961da177e4SLinus Torvalds EXPORT_SYMBOL(ib_reg_phys_mr);
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds int ib_rereg_phys_mr(struct ib_mr *mr,
9991da177e4SLinus Torvalds 		     int mr_rereg_mask,
10001da177e4SLinus Torvalds 		     struct ib_pd *pd,
10011da177e4SLinus Torvalds 		     struct ib_phys_buf *phys_buf_array,
10021da177e4SLinus Torvalds 		     int num_phys_buf,
10031da177e4SLinus Torvalds 		     int mr_access_flags,
10041da177e4SLinus Torvalds 		     u64 *iova_start)
10051da177e4SLinus Torvalds {
10061da177e4SLinus Torvalds 	struct ib_pd *old_pd;
10071da177e4SLinus Torvalds 	int ret;
10081da177e4SLinus Torvalds 
10091da177e4SLinus Torvalds 	if (!mr->device->rereg_phys_mr)
10101da177e4SLinus Torvalds 		return -ENOSYS;
10111da177e4SLinus Torvalds 
10121da177e4SLinus Torvalds 	if (atomic_read(&mr->usecnt))
10131da177e4SLinus Torvalds 		return -EBUSY;
10141da177e4SLinus Torvalds 
10151da177e4SLinus Torvalds 	old_pd = mr->pd;
10161da177e4SLinus Torvalds 
10171da177e4SLinus Torvalds 	ret = mr->device->rereg_phys_mr(mr, mr_rereg_mask, pd,
10181da177e4SLinus Torvalds 					phys_buf_array, num_phys_buf,
10191da177e4SLinus Torvalds 					mr_access_flags, iova_start);
10201da177e4SLinus Torvalds 
10211da177e4SLinus Torvalds 	if (!ret && (mr_rereg_mask & IB_MR_REREG_PD)) {
10221da177e4SLinus Torvalds 		atomic_dec(&old_pd->usecnt);
10231da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
10241da177e4SLinus Torvalds 	}
10251da177e4SLinus Torvalds 
10261da177e4SLinus Torvalds 	return ret;
10271da177e4SLinus Torvalds }
10281da177e4SLinus Torvalds EXPORT_SYMBOL(ib_rereg_phys_mr);
10291da177e4SLinus Torvalds 
10301da177e4SLinus Torvalds int ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
10311da177e4SLinus Torvalds {
10321da177e4SLinus Torvalds 	return mr->device->query_mr ?
10331da177e4SLinus Torvalds 		mr->device->query_mr(mr, mr_attr) : -ENOSYS;
10341da177e4SLinus Torvalds }
10351da177e4SLinus Torvalds EXPORT_SYMBOL(ib_query_mr);
10361da177e4SLinus Torvalds 
10371da177e4SLinus Torvalds int ib_dereg_mr(struct ib_mr *mr)
10381da177e4SLinus Torvalds {
10391da177e4SLinus Torvalds 	struct ib_pd *pd;
10401da177e4SLinus Torvalds 	int ret;
10411da177e4SLinus Torvalds 
10421da177e4SLinus Torvalds 	if (atomic_read(&mr->usecnt))
10431da177e4SLinus Torvalds 		return -EBUSY;
10441da177e4SLinus Torvalds 
10451da177e4SLinus Torvalds 	pd = mr->pd;
10461da177e4SLinus Torvalds 	ret = mr->device->dereg_mr(mr);
10471da177e4SLinus Torvalds 	if (!ret)
10481da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
10491da177e4SLinus Torvalds 
10501da177e4SLinus Torvalds 	return ret;
10511da177e4SLinus Torvalds }
10521da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dereg_mr);
10531da177e4SLinus Torvalds 
105400f7ec36SSteve Wise struct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len)
105500f7ec36SSteve Wise {
105600f7ec36SSteve Wise 	struct ib_mr *mr;
105700f7ec36SSteve Wise 
105800f7ec36SSteve Wise 	if (!pd->device->alloc_fast_reg_mr)
105900f7ec36SSteve Wise 		return ERR_PTR(-ENOSYS);
106000f7ec36SSteve Wise 
106100f7ec36SSteve Wise 	mr = pd->device->alloc_fast_reg_mr(pd, max_page_list_len);
106200f7ec36SSteve Wise 
106300f7ec36SSteve Wise 	if (!IS_ERR(mr)) {
106400f7ec36SSteve Wise 		mr->device  = pd->device;
106500f7ec36SSteve Wise 		mr->pd      = pd;
106600f7ec36SSteve Wise 		mr->uobject = NULL;
106700f7ec36SSteve Wise 		atomic_inc(&pd->usecnt);
106800f7ec36SSteve Wise 		atomic_set(&mr->usecnt, 0);
106900f7ec36SSteve Wise 	}
107000f7ec36SSteve Wise 
107100f7ec36SSteve Wise 	return mr;
107200f7ec36SSteve Wise }
107300f7ec36SSteve Wise EXPORT_SYMBOL(ib_alloc_fast_reg_mr);
107400f7ec36SSteve Wise 
107500f7ec36SSteve Wise struct ib_fast_reg_page_list *ib_alloc_fast_reg_page_list(struct ib_device *device,
107600f7ec36SSteve Wise 							  int max_page_list_len)
107700f7ec36SSteve Wise {
107800f7ec36SSteve Wise 	struct ib_fast_reg_page_list *page_list;
107900f7ec36SSteve Wise 
108000f7ec36SSteve Wise 	if (!device->alloc_fast_reg_page_list)
108100f7ec36SSteve Wise 		return ERR_PTR(-ENOSYS);
108200f7ec36SSteve Wise 
108300f7ec36SSteve Wise 	page_list = device->alloc_fast_reg_page_list(device, max_page_list_len);
108400f7ec36SSteve Wise 
108500f7ec36SSteve Wise 	if (!IS_ERR(page_list)) {
108600f7ec36SSteve Wise 		page_list->device = device;
108700f7ec36SSteve Wise 		page_list->max_page_list_len = max_page_list_len;
108800f7ec36SSteve Wise 	}
108900f7ec36SSteve Wise 
109000f7ec36SSteve Wise 	return page_list;
109100f7ec36SSteve Wise }
109200f7ec36SSteve Wise EXPORT_SYMBOL(ib_alloc_fast_reg_page_list);
109300f7ec36SSteve Wise 
109400f7ec36SSteve Wise void ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list)
109500f7ec36SSteve Wise {
109600f7ec36SSteve Wise 	page_list->device->free_fast_reg_page_list(page_list);
109700f7ec36SSteve Wise }
109800f7ec36SSteve Wise EXPORT_SYMBOL(ib_free_fast_reg_page_list);
109900f7ec36SSteve Wise 
11001da177e4SLinus Torvalds /* Memory windows */
11011da177e4SLinus Torvalds 
11027083e42eSShani Michaeli struct ib_mw *ib_alloc_mw(struct ib_pd *pd, enum ib_mw_type type)
11031da177e4SLinus Torvalds {
11041da177e4SLinus Torvalds 	struct ib_mw *mw;
11051da177e4SLinus Torvalds 
11061da177e4SLinus Torvalds 	if (!pd->device->alloc_mw)
11071da177e4SLinus Torvalds 		return ERR_PTR(-ENOSYS);
11081da177e4SLinus Torvalds 
11097083e42eSShani Michaeli 	mw = pd->device->alloc_mw(pd, type);
11101da177e4SLinus Torvalds 	if (!IS_ERR(mw)) {
11111da177e4SLinus Torvalds 		mw->device  = pd->device;
11121da177e4SLinus Torvalds 		mw->pd      = pd;
1113b5e81bf5SRoland Dreier 		mw->uobject = NULL;
11147083e42eSShani Michaeli 		mw->type    = type;
11151da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
11161da177e4SLinus Torvalds 	}
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds 	return mw;
11191da177e4SLinus Torvalds }
11201da177e4SLinus Torvalds EXPORT_SYMBOL(ib_alloc_mw);
11211da177e4SLinus Torvalds 
11221da177e4SLinus Torvalds int ib_dealloc_mw(struct ib_mw *mw)
11231da177e4SLinus Torvalds {
11241da177e4SLinus Torvalds 	struct ib_pd *pd;
11251da177e4SLinus Torvalds 	int ret;
11261da177e4SLinus Torvalds 
11271da177e4SLinus Torvalds 	pd = mw->pd;
11281da177e4SLinus Torvalds 	ret = mw->device->dealloc_mw(mw);
11291da177e4SLinus Torvalds 	if (!ret)
11301da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
11311da177e4SLinus Torvalds 
11321da177e4SLinus Torvalds 	return ret;
11331da177e4SLinus Torvalds }
11341da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dealloc_mw);
11351da177e4SLinus Torvalds 
11361da177e4SLinus Torvalds /* "Fast" memory regions */
11371da177e4SLinus Torvalds 
11381da177e4SLinus Torvalds struct ib_fmr *ib_alloc_fmr(struct ib_pd *pd,
11391da177e4SLinus Torvalds 			    int mr_access_flags,
11401da177e4SLinus Torvalds 			    struct ib_fmr_attr *fmr_attr)
11411da177e4SLinus Torvalds {
11421da177e4SLinus Torvalds 	struct ib_fmr *fmr;
11431da177e4SLinus Torvalds 
11441da177e4SLinus Torvalds 	if (!pd->device->alloc_fmr)
11451da177e4SLinus Torvalds 		return ERR_PTR(-ENOSYS);
11461da177e4SLinus Torvalds 
11471da177e4SLinus Torvalds 	fmr = pd->device->alloc_fmr(pd, mr_access_flags, fmr_attr);
11481da177e4SLinus Torvalds 	if (!IS_ERR(fmr)) {
11491da177e4SLinus Torvalds 		fmr->device = pd->device;
11501da177e4SLinus Torvalds 		fmr->pd     = pd;
11511da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
11521da177e4SLinus Torvalds 	}
11531da177e4SLinus Torvalds 
11541da177e4SLinus Torvalds 	return fmr;
11551da177e4SLinus Torvalds }
11561da177e4SLinus Torvalds EXPORT_SYMBOL(ib_alloc_fmr);
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds int ib_unmap_fmr(struct list_head *fmr_list)
11591da177e4SLinus Torvalds {
11601da177e4SLinus Torvalds 	struct ib_fmr *fmr;
11611da177e4SLinus Torvalds 
11621da177e4SLinus Torvalds 	if (list_empty(fmr_list))
11631da177e4SLinus Torvalds 		return 0;
11641da177e4SLinus Torvalds 
11651da177e4SLinus Torvalds 	fmr = list_entry(fmr_list->next, struct ib_fmr, list);
11661da177e4SLinus Torvalds 	return fmr->device->unmap_fmr(fmr_list);
11671da177e4SLinus Torvalds }
11681da177e4SLinus Torvalds EXPORT_SYMBOL(ib_unmap_fmr);
11691da177e4SLinus Torvalds 
11701da177e4SLinus Torvalds int ib_dealloc_fmr(struct ib_fmr *fmr)
11711da177e4SLinus Torvalds {
11721da177e4SLinus Torvalds 	struct ib_pd *pd;
11731da177e4SLinus Torvalds 	int ret;
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds 	pd = fmr->pd;
11761da177e4SLinus Torvalds 	ret = fmr->device->dealloc_fmr(fmr);
11771da177e4SLinus Torvalds 	if (!ret)
11781da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
11791da177e4SLinus Torvalds 
11801da177e4SLinus Torvalds 	return ret;
11811da177e4SLinus Torvalds }
11821da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dealloc_fmr);
11831da177e4SLinus Torvalds 
11841da177e4SLinus Torvalds /* Multicast groups */
11851da177e4SLinus Torvalds 
11861da177e4SLinus Torvalds int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
11871da177e4SLinus Torvalds {
1188c3bccbfbSOr Gerlitz 	int ret;
1189c3bccbfbSOr Gerlitz 
11900c33aeedSJack Morgenstein 	if (!qp->device->attach_mcast)
11910c33aeedSJack Morgenstein 		return -ENOSYS;
11920c33aeedSJack Morgenstein 	if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
11930c33aeedSJack Morgenstein 		return -EINVAL;
11940c33aeedSJack Morgenstein 
1195c3bccbfbSOr Gerlitz 	ret = qp->device->attach_mcast(qp, gid, lid);
1196c3bccbfbSOr Gerlitz 	if (!ret)
1197c3bccbfbSOr Gerlitz 		atomic_inc(&qp->usecnt);
1198c3bccbfbSOr Gerlitz 	return ret;
11991da177e4SLinus Torvalds }
12001da177e4SLinus Torvalds EXPORT_SYMBOL(ib_attach_mcast);
12011da177e4SLinus Torvalds 
12021da177e4SLinus Torvalds int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
12031da177e4SLinus Torvalds {
1204c3bccbfbSOr Gerlitz 	int ret;
1205c3bccbfbSOr Gerlitz 
12060c33aeedSJack Morgenstein 	if (!qp->device->detach_mcast)
12070c33aeedSJack Morgenstein 		return -ENOSYS;
12080c33aeedSJack Morgenstein 	if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
12090c33aeedSJack Morgenstein 		return -EINVAL;
12100c33aeedSJack Morgenstein 
1211c3bccbfbSOr Gerlitz 	ret = qp->device->detach_mcast(qp, gid, lid);
1212c3bccbfbSOr Gerlitz 	if (!ret)
1213c3bccbfbSOr Gerlitz 		atomic_dec(&qp->usecnt);
1214c3bccbfbSOr Gerlitz 	return ret;
12151da177e4SLinus Torvalds }
12161da177e4SLinus Torvalds EXPORT_SYMBOL(ib_detach_mcast);
121759991f94SSean Hefty 
121859991f94SSean Hefty struct ib_xrcd *ib_alloc_xrcd(struct ib_device *device)
121959991f94SSean Hefty {
122059991f94SSean Hefty 	struct ib_xrcd *xrcd;
122159991f94SSean Hefty 
122259991f94SSean Hefty 	if (!device->alloc_xrcd)
122359991f94SSean Hefty 		return ERR_PTR(-ENOSYS);
122459991f94SSean Hefty 
122559991f94SSean Hefty 	xrcd = device->alloc_xrcd(device, NULL, NULL);
122659991f94SSean Hefty 	if (!IS_ERR(xrcd)) {
122759991f94SSean Hefty 		xrcd->device = device;
122853d0bd1eSSean Hefty 		xrcd->inode = NULL;
122959991f94SSean Hefty 		atomic_set(&xrcd->usecnt, 0);
1230d3d72d90SSean Hefty 		mutex_init(&xrcd->tgt_qp_mutex);
1231d3d72d90SSean Hefty 		INIT_LIST_HEAD(&xrcd->tgt_qp_list);
123259991f94SSean Hefty 	}
123359991f94SSean Hefty 
123459991f94SSean Hefty 	return xrcd;
123559991f94SSean Hefty }
123659991f94SSean Hefty EXPORT_SYMBOL(ib_alloc_xrcd);
123759991f94SSean Hefty 
123859991f94SSean Hefty int ib_dealloc_xrcd(struct ib_xrcd *xrcd)
123959991f94SSean Hefty {
1240d3d72d90SSean Hefty 	struct ib_qp *qp;
1241d3d72d90SSean Hefty 	int ret;
1242d3d72d90SSean Hefty 
124359991f94SSean Hefty 	if (atomic_read(&xrcd->usecnt))
124459991f94SSean Hefty 		return -EBUSY;
124559991f94SSean Hefty 
1246d3d72d90SSean Hefty 	while (!list_empty(&xrcd->tgt_qp_list)) {
1247d3d72d90SSean Hefty 		qp = list_entry(xrcd->tgt_qp_list.next, struct ib_qp, xrcd_list);
1248d3d72d90SSean Hefty 		ret = ib_destroy_qp(qp);
1249d3d72d90SSean Hefty 		if (ret)
1250d3d72d90SSean Hefty 			return ret;
1251d3d72d90SSean Hefty 	}
1252d3d72d90SSean Hefty 
125359991f94SSean Hefty 	return xrcd->device->dealloc_xrcd(xrcd);
125459991f94SSean Hefty }
125559991f94SSean Hefty EXPORT_SYMBOL(ib_dealloc_xrcd);
1256