xref: /openbmc/linux/drivers/infiniband/core/verbs.c (revision 9bc57e2d)
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  * $Id: verbs.c 1349 2004-12-16 21:09:43Z roland $
391da177e4SLinus Torvalds  */
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds #include <linux/errno.h>
421da177e4SLinus Torvalds #include <linux/err.h>
438c65b4a6STim Schmielau #include <linux/string.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 
821da177e4SLinus Torvalds /* Protection domains */
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds struct ib_pd *ib_alloc_pd(struct ib_device *device)
851da177e4SLinus Torvalds {
861da177e4SLinus Torvalds 	struct ib_pd *pd;
871da177e4SLinus Torvalds 
88b5e81bf5SRoland Dreier 	pd = device->alloc_pd(device, NULL, NULL);
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds 	if (!IS_ERR(pd)) {
911da177e4SLinus Torvalds 		pd->device  = device;
92b5e81bf5SRoland Dreier 		pd->uobject = NULL;
931da177e4SLinus Torvalds 		atomic_set(&pd->usecnt, 0);
941da177e4SLinus Torvalds 	}
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	return pd;
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds EXPORT_SYMBOL(ib_alloc_pd);
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds int ib_dealloc_pd(struct ib_pd *pd)
1011da177e4SLinus Torvalds {
1021da177e4SLinus Torvalds 	if (atomic_read(&pd->usecnt))
1031da177e4SLinus Torvalds 		return -EBUSY;
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	return pd->device->dealloc_pd(pd);
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dealloc_pd);
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds /* Address handles */
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
1121da177e4SLinus Torvalds {
1131da177e4SLinus Torvalds 	struct ib_ah *ah;
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds 	ah = pd->device->create_ah(pd, ah_attr);
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds 	if (!IS_ERR(ah)) {
1181da177e4SLinus Torvalds 		ah->device  = pd->device;
1191da177e4SLinus Torvalds 		ah->pd      = pd;
120b5e81bf5SRoland Dreier 		ah->uobject = NULL;
1211da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
1221da177e4SLinus Torvalds 	}
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds 	return ah;
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds EXPORT_SYMBOL(ib_create_ah);
1271da177e4SLinus Torvalds 
1284e00d694SSean Hefty int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc,
1294e00d694SSean Hefty 		       struct ib_grh *grh, struct ib_ah_attr *ah_attr)
130513789edSHal Rosenstock {
131513789edSHal Rosenstock 	u32 flow_class;
132513789edSHal Rosenstock 	u16 gid_index;
133513789edSHal Rosenstock 	int ret;
134513789edSHal Rosenstock 
1354e00d694SSean Hefty 	memset(ah_attr, 0, sizeof *ah_attr);
1364e00d694SSean Hefty 	ah_attr->dlid = wc->slid;
1374e00d694SSean Hefty 	ah_attr->sl = wc->sl;
1384e00d694SSean Hefty 	ah_attr->src_path_bits = wc->dlid_path_bits;
1394e00d694SSean Hefty 	ah_attr->port_num = port_num;
140513789edSHal Rosenstock 
141513789edSHal Rosenstock 	if (wc->wc_flags & IB_WC_GRH) {
1424e00d694SSean Hefty 		ah_attr->ah_flags = IB_AH_GRH;
1434e00d694SSean Hefty 		ah_attr->grh.dgid = grh->sgid;
144513789edSHal Rosenstock 
1454e00d694SSean Hefty 		ret = ib_find_cached_gid(device, &grh->dgid, &port_num,
146513789edSHal Rosenstock 					 &gid_index);
147513789edSHal Rosenstock 		if (ret)
1484e00d694SSean Hefty 			return ret;
149513789edSHal Rosenstock 
1504e00d694SSean Hefty 		ah_attr->grh.sgid_index = (u8) gid_index;
151497677abSHal Rosenstock 		flow_class = be32_to_cpu(grh->version_tclass_flow);
1524e00d694SSean Hefty 		ah_attr->grh.flow_label = flow_class & 0xFFFFF;
1534e00d694SSean Hefty 		ah_attr->grh.hop_limit = grh->hop_limit;
1544e00d694SSean Hefty 		ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
155513789edSHal Rosenstock 	}
1564e00d694SSean Hefty 	return 0;
1574e00d694SSean Hefty }
1584e00d694SSean Hefty EXPORT_SYMBOL(ib_init_ah_from_wc);
1594e00d694SSean Hefty 
1604e00d694SSean Hefty struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc,
1614e00d694SSean Hefty 				   struct ib_grh *grh, u8 port_num)
1624e00d694SSean Hefty {
1634e00d694SSean Hefty 	struct ib_ah_attr ah_attr;
1644e00d694SSean Hefty 	int ret;
1654e00d694SSean Hefty 
1664e00d694SSean Hefty 	ret = ib_init_ah_from_wc(pd->device, port_num, wc, grh, &ah_attr);
1674e00d694SSean Hefty 	if (ret)
1684e00d694SSean Hefty 		return ERR_PTR(ret);
169513789edSHal Rosenstock 
170513789edSHal Rosenstock 	return ib_create_ah(pd, &ah_attr);
171513789edSHal Rosenstock }
172513789edSHal Rosenstock EXPORT_SYMBOL(ib_create_ah_from_wc);
173513789edSHal Rosenstock 
1741da177e4SLinus Torvalds int ib_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
1751da177e4SLinus Torvalds {
1761da177e4SLinus Torvalds 	return ah->device->modify_ah ?
1771da177e4SLinus Torvalds 		ah->device->modify_ah(ah, ah_attr) :
1781da177e4SLinus Torvalds 		-ENOSYS;
1791da177e4SLinus Torvalds }
1801da177e4SLinus Torvalds EXPORT_SYMBOL(ib_modify_ah);
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds int ib_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
1831da177e4SLinus Torvalds {
1841da177e4SLinus Torvalds 	return ah->device->query_ah ?
1851da177e4SLinus Torvalds 		ah->device->query_ah(ah, ah_attr) :
1861da177e4SLinus Torvalds 		-ENOSYS;
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds EXPORT_SYMBOL(ib_query_ah);
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds int ib_destroy_ah(struct ib_ah *ah)
1911da177e4SLinus Torvalds {
1921da177e4SLinus Torvalds 	struct ib_pd *pd;
1931da177e4SLinus Torvalds 	int ret;
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds 	pd = ah->pd;
1961da177e4SLinus Torvalds 	ret = ah->device->destroy_ah(ah);
1971da177e4SLinus Torvalds 	if (!ret)
1981da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	return ret;
2011da177e4SLinus Torvalds }
2021da177e4SLinus Torvalds EXPORT_SYMBOL(ib_destroy_ah);
2031da177e4SLinus Torvalds 
204d41fcc67SRoland Dreier /* Shared receive queues */
205d41fcc67SRoland Dreier 
206d41fcc67SRoland Dreier struct ib_srq *ib_create_srq(struct ib_pd *pd,
207d41fcc67SRoland Dreier 			     struct ib_srq_init_attr *srq_init_attr)
208d41fcc67SRoland Dreier {
209d41fcc67SRoland Dreier 	struct ib_srq *srq;
210d41fcc67SRoland Dreier 
211d41fcc67SRoland Dreier 	if (!pd->device->create_srq)
212d41fcc67SRoland Dreier 		return ERR_PTR(-ENOSYS);
213d41fcc67SRoland Dreier 
214d41fcc67SRoland Dreier 	srq = pd->device->create_srq(pd, srq_init_attr, NULL);
215d41fcc67SRoland Dreier 
216d41fcc67SRoland Dreier 	if (!IS_ERR(srq)) {
217d41fcc67SRoland Dreier 		srq->device    	   = pd->device;
218d41fcc67SRoland Dreier 		srq->pd        	   = pd;
219d41fcc67SRoland Dreier 		srq->uobject       = NULL;
220d41fcc67SRoland Dreier 		srq->event_handler = srq_init_attr->event_handler;
221d41fcc67SRoland Dreier 		srq->srq_context   = srq_init_attr->srq_context;
222d41fcc67SRoland Dreier 		atomic_inc(&pd->usecnt);
223d41fcc67SRoland Dreier 		atomic_set(&srq->usecnt, 0);
224d41fcc67SRoland Dreier 	}
225d41fcc67SRoland Dreier 
226d41fcc67SRoland Dreier 	return srq;
227d41fcc67SRoland Dreier }
228d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_create_srq);
229d41fcc67SRoland Dreier 
230d41fcc67SRoland Dreier int ib_modify_srq(struct ib_srq *srq,
231d41fcc67SRoland Dreier 		  struct ib_srq_attr *srq_attr,
232d41fcc67SRoland Dreier 		  enum ib_srq_attr_mask srq_attr_mask)
233d41fcc67SRoland Dreier {
2349bc57e2dSRalph Campbell 	return srq->device->modify_srq(srq, srq_attr, srq_attr_mask, NULL);
235d41fcc67SRoland Dreier }
236d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_modify_srq);
237d41fcc67SRoland Dreier 
238d41fcc67SRoland Dreier int ib_query_srq(struct ib_srq *srq,
239d41fcc67SRoland Dreier 		 struct ib_srq_attr *srq_attr)
240d41fcc67SRoland Dreier {
241d41fcc67SRoland Dreier 	return srq->device->query_srq ?
242d41fcc67SRoland Dreier 		srq->device->query_srq(srq, srq_attr) : -ENOSYS;
243d41fcc67SRoland Dreier }
244d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_query_srq);
245d41fcc67SRoland Dreier 
246d41fcc67SRoland Dreier int ib_destroy_srq(struct ib_srq *srq)
247d41fcc67SRoland Dreier {
248d41fcc67SRoland Dreier 	struct ib_pd *pd;
249d41fcc67SRoland Dreier 	int ret;
250d41fcc67SRoland Dreier 
251d41fcc67SRoland Dreier 	if (atomic_read(&srq->usecnt))
252d41fcc67SRoland Dreier 		return -EBUSY;
253d41fcc67SRoland Dreier 
254d41fcc67SRoland Dreier 	pd = srq->pd;
255d41fcc67SRoland Dreier 
256d41fcc67SRoland Dreier 	ret = srq->device->destroy_srq(srq);
257d41fcc67SRoland Dreier 	if (!ret)
258d41fcc67SRoland Dreier 		atomic_dec(&pd->usecnt);
259d41fcc67SRoland Dreier 
260d41fcc67SRoland Dreier 	return ret;
261d41fcc67SRoland Dreier }
262d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_destroy_srq);
263d41fcc67SRoland Dreier 
2641da177e4SLinus Torvalds /* Queue pairs */
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds struct ib_qp *ib_create_qp(struct ib_pd *pd,
2671da177e4SLinus Torvalds 			   struct ib_qp_init_attr *qp_init_attr)
2681da177e4SLinus Torvalds {
2691da177e4SLinus Torvalds 	struct ib_qp *qp;
2701da177e4SLinus Torvalds 
271b5e81bf5SRoland Dreier 	qp = pd->device->create_qp(pd, qp_init_attr, NULL);
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 	if (!IS_ERR(qp)) {
2741da177e4SLinus Torvalds 		qp->device     	  = pd->device;
2751da177e4SLinus Torvalds 		qp->pd         	  = pd;
2761da177e4SLinus Torvalds 		qp->send_cq    	  = qp_init_attr->send_cq;
2771da177e4SLinus Torvalds 		qp->recv_cq    	  = qp_init_attr->recv_cq;
2781da177e4SLinus Torvalds 		qp->srq	       	  = qp_init_attr->srq;
279b5e81bf5SRoland Dreier 		qp->uobject       = NULL;
2801da177e4SLinus Torvalds 		qp->event_handler = qp_init_attr->event_handler;
2811da177e4SLinus Torvalds 		qp->qp_context    = qp_init_attr->qp_context;
2821da177e4SLinus Torvalds 		qp->qp_type	  = qp_init_attr->qp_type;
2831da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
2841da177e4SLinus Torvalds 		atomic_inc(&qp_init_attr->send_cq->usecnt);
2851da177e4SLinus Torvalds 		atomic_inc(&qp_init_attr->recv_cq->usecnt);
2861da177e4SLinus Torvalds 		if (qp_init_attr->srq)
2871da177e4SLinus Torvalds 			atomic_inc(&qp_init_attr->srq->usecnt);
2881da177e4SLinus Torvalds 	}
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds 	return qp;
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds EXPORT_SYMBOL(ib_create_qp);
2931da177e4SLinus Torvalds 
2948a51866fSRoland Dreier static const struct {
2958a51866fSRoland Dreier 	int			valid;
2968a51866fSRoland Dreier 	enum ib_qp_attr_mask	req_param[IB_QPT_RAW_ETY + 1];
2978a51866fSRoland Dreier 	enum ib_qp_attr_mask	opt_param[IB_QPT_RAW_ETY + 1];
2988a51866fSRoland Dreier } qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
2998a51866fSRoland Dreier 	[IB_QPS_RESET] = {
3008a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
3018a51866fSRoland Dreier 		[IB_QPS_ERR]   = { .valid = 1 },
3028a51866fSRoland Dreier 		[IB_QPS_INIT]  = {
3038a51866fSRoland Dreier 			.valid = 1,
3048a51866fSRoland Dreier 			.req_param = {
3058a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
3068a51866fSRoland Dreier 						IB_QP_PORT			|
3078a51866fSRoland Dreier 						IB_QP_QKEY),
3088a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
3098a51866fSRoland Dreier 						IB_QP_PORT			|
3108a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
3118a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
3128a51866fSRoland Dreier 						IB_QP_PORT			|
3138a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
3148a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
3158a51866fSRoland Dreier 						IB_QP_QKEY),
3168a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
3178a51866fSRoland Dreier 						IB_QP_QKEY),
3188a51866fSRoland Dreier 			}
3198a51866fSRoland Dreier 		},
3208a51866fSRoland Dreier 	},
3218a51866fSRoland Dreier 	[IB_QPS_INIT]  = {
3228a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
3238a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
3248a51866fSRoland Dreier 		[IB_QPS_INIT]  = {
3258a51866fSRoland Dreier 			.valid = 1,
3268a51866fSRoland Dreier 			.opt_param = {
3278a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
3288a51866fSRoland Dreier 						IB_QP_PORT			|
3298a51866fSRoland Dreier 						IB_QP_QKEY),
3308a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
3318a51866fSRoland Dreier 						IB_QP_PORT			|
3328a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
3338a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
3348a51866fSRoland Dreier 						IB_QP_PORT			|
3358a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
3368a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
3378a51866fSRoland Dreier 						IB_QP_QKEY),
3388a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
3398a51866fSRoland Dreier 						IB_QP_QKEY),
3408a51866fSRoland Dreier 			}
3418a51866fSRoland Dreier 		},
3428a51866fSRoland Dreier 		[IB_QPS_RTR]   = {
3438a51866fSRoland Dreier 			.valid = 1,
3448a51866fSRoland Dreier 			.req_param = {
3458a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_AV			|
3468a51866fSRoland Dreier 						IB_QP_PATH_MTU			|
3478a51866fSRoland Dreier 						IB_QP_DEST_QPN			|
3488a51866fSRoland Dreier 						IB_QP_RQ_PSN),
3498a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_AV			|
3508a51866fSRoland Dreier 						IB_QP_PATH_MTU			|
3518a51866fSRoland Dreier 						IB_QP_DEST_QPN			|
3528a51866fSRoland Dreier 						IB_QP_RQ_PSN			|
3538a51866fSRoland Dreier 						IB_QP_MAX_DEST_RD_ATOMIC	|
3548a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER),
3558a51866fSRoland Dreier 			},
3568a51866fSRoland Dreier 			.opt_param = {
3578a51866fSRoland Dreier 				 [IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
3588a51866fSRoland Dreier 						 IB_QP_QKEY),
3598a51866fSRoland Dreier 				 [IB_QPT_UC]  = (IB_QP_ALT_PATH			|
3608a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
3618a51866fSRoland Dreier 						 IB_QP_PKEY_INDEX),
3628a51866fSRoland Dreier 				 [IB_QPT_RC]  = (IB_QP_ALT_PATH			|
3638a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
3648a51866fSRoland Dreier 						 IB_QP_PKEY_INDEX),
3658a51866fSRoland Dreier 				 [IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
3668a51866fSRoland Dreier 						 IB_QP_QKEY),
3678a51866fSRoland Dreier 				 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
3688a51866fSRoland Dreier 						 IB_QP_QKEY),
3698a51866fSRoland Dreier 			 }
3708a51866fSRoland Dreier 		}
3718a51866fSRoland Dreier 	},
3728a51866fSRoland Dreier 	[IB_QPS_RTR]   = {
3738a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
3748a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
3758a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
3768a51866fSRoland Dreier 			.valid = 1,
3778a51866fSRoland Dreier 			.req_param = {
3788a51866fSRoland Dreier 				[IB_QPT_UD]  = IB_QP_SQ_PSN,
3798a51866fSRoland Dreier 				[IB_QPT_UC]  = IB_QP_SQ_PSN,
3808a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_TIMEOUT			|
3818a51866fSRoland Dreier 						IB_QP_RETRY_CNT			|
3828a51866fSRoland Dreier 						IB_QP_RNR_RETRY			|
3838a51866fSRoland Dreier 						IB_QP_SQ_PSN			|
3848a51866fSRoland Dreier 						IB_QP_MAX_QP_RD_ATOMIC),
3858a51866fSRoland Dreier 				[IB_QPT_SMI] = IB_QP_SQ_PSN,
3868a51866fSRoland Dreier 				[IB_QPT_GSI] = IB_QP_SQ_PSN,
3878a51866fSRoland Dreier 			},
3888a51866fSRoland Dreier 			.opt_param = {
3898a51866fSRoland Dreier 				 [IB_QPT_UD]  = (IB_QP_CUR_STATE		|
3908a51866fSRoland Dreier 						 IB_QP_QKEY),
3918a51866fSRoland Dreier 				 [IB_QPT_UC]  = (IB_QP_CUR_STATE		|
3928a51866fSRoland Dreier 						 IB_QP_ALT_PATH			|
3938a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
3948a51866fSRoland Dreier 						 IB_QP_PATH_MIG_STATE),
3958a51866fSRoland Dreier 				 [IB_QPT_RC]  = (IB_QP_CUR_STATE		|
3968a51866fSRoland Dreier 						 IB_QP_ALT_PATH			|
3978a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
3988a51866fSRoland Dreier 						 IB_QP_MIN_RNR_TIMER		|
3998a51866fSRoland Dreier 						 IB_QP_PATH_MIG_STATE),
4008a51866fSRoland Dreier 				 [IB_QPT_SMI] = (IB_QP_CUR_STATE		|
4018a51866fSRoland Dreier 						 IB_QP_QKEY),
4028a51866fSRoland Dreier 				 [IB_QPT_GSI] = (IB_QP_CUR_STATE		|
4038a51866fSRoland Dreier 						 IB_QP_QKEY),
4048a51866fSRoland Dreier 			 }
4058a51866fSRoland Dreier 		}
4068a51866fSRoland Dreier 	},
4078a51866fSRoland Dreier 	[IB_QPS_RTS]   = {
4088a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
4098a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
4108a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
4118a51866fSRoland Dreier 			.valid = 1,
4128a51866fSRoland Dreier 			.opt_param = {
4138a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
4148a51866fSRoland Dreier 						IB_QP_QKEY),
4154546d31dSDotan Barak 				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
4164546d31dSDotan Barak 						IB_QP_ACCESS_FLAGS		|
4178a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
4188a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
4194546d31dSDotan Barak 				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
4204546d31dSDotan Barak 						IB_QP_ACCESS_FLAGS		|
4218a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
4228a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE		|
4238a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER),
4248a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
4258a51866fSRoland Dreier 						IB_QP_QKEY),
4268a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
4278a51866fSRoland Dreier 						IB_QP_QKEY),
4288a51866fSRoland Dreier 			}
4298a51866fSRoland Dreier 		},
4308a51866fSRoland Dreier 		[IB_QPS_SQD]   = {
4318a51866fSRoland Dreier 			.valid = 1,
4328a51866fSRoland Dreier 			.opt_param = {
4338a51866fSRoland Dreier 				[IB_QPT_UD]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
4348a51866fSRoland Dreier 				[IB_QPT_UC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
4358a51866fSRoland Dreier 				[IB_QPT_RC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
4368a51866fSRoland Dreier 				[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
4378a51866fSRoland Dreier 				[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
4388a51866fSRoland Dreier 			}
4398a51866fSRoland Dreier 		},
4408a51866fSRoland Dreier 	},
4418a51866fSRoland Dreier 	[IB_QPS_SQD]   = {
4428a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
4438a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
4448a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
4458a51866fSRoland Dreier 			.valid = 1,
4468a51866fSRoland Dreier 			.opt_param = {
4478a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
4488a51866fSRoland Dreier 						IB_QP_QKEY),
4498a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
4508a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
4518a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
4528a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
4538a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
4548a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
4558a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
4568a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER		|
4578a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
4588a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
4598a51866fSRoland Dreier 						IB_QP_QKEY),
4608a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
4618a51866fSRoland Dreier 						IB_QP_QKEY),
4628a51866fSRoland Dreier 			}
4638a51866fSRoland Dreier 		},
4648a51866fSRoland Dreier 		[IB_QPS_SQD]   = {
4658a51866fSRoland Dreier 			.valid = 1,
4668a51866fSRoland Dreier 			.opt_param = {
4678a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
4688a51866fSRoland Dreier 						IB_QP_QKEY),
4698a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_AV			|
4708a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
4718a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
4728a51866fSRoland Dreier 						IB_QP_PKEY_INDEX		|
4738a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
4748a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_PORT			|
4758a51866fSRoland Dreier 						IB_QP_AV			|
4768a51866fSRoland Dreier 						IB_QP_TIMEOUT			|
4778a51866fSRoland Dreier 						IB_QP_RETRY_CNT			|
4788a51866fSRoland Dreier 						IB_QP_RNR_RETRY			|
4798a51866fSRoland Dreier 						IB_QP_MAX_QP_RD_ATOMIC		|
4808a51866fSRoland Dreier 						IB_QP_MAX_DEST_RD_ATOMIC	|
4818a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
4828a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
4838a51866fSRoland Dreier 						IB_QP_PKEY_INDEX		|
4848a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER		|
4858a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
4868a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
4878a51866fSRoland Dreier 						IB_QP_QKEY),
4888a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
4898a51866fSRoland Dreier 						IB_QP_QKEY),
4908a51866fSRoland Dreier 			}
4918a51866fSRoland Dreier 		}
4928a51866fSRoland Dreier 	},
4938a51866fSRoland Dreier 	[IB_QPS_SQE]   = {
4948a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
4958a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
4968a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
4978a51866fSRoland Dreier 			.valid = 1,
4988a51866fSRoland Dreier 			.opt_param = {
4998a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
5008a51866fSRoland Dreier 						IB_QP_QKEY),
5018a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
5028a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
5038a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
5048a51866fSRoland Dreier 						IB_QP_QKEY),
5058a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
5068a51866fSRoland Dreier 						IB_QP_QKEY),
5078a51866fSRoland Dreier 			}
5088a51866fSRoland Dreier 		}
5098a51866fSRoland Dreier 	},
5108a51866fSRoland Dreier 	[IB_QPS_ERR] = {
5118a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
5128a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 }
5138a51866fSRoland Dreier 	}
5148a51866fSRoland Dreier };
5158a51866fSRoland Dreier 
5168a51866fSRoland Dreier int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
5178a51866fSRoland Dreier 		       enum ib_qp_type type, enum ib_qp_attr_mask mask)
5188a51866fSRoland Dreier {
5198a51866fSRoland Dreier 	enum ib_qp_attr_mask req_param, opt_param;
5208a51866fSRoland Dreier 
5218a51866fSRoland Dreier 	if (cur_state  < 0 || cur_state  > IB_QPS_ERR ||
5228a51866fSRoland Dreier 	    next_state < 0 || next_state > IB_QPS_ERR)
5238a51866fSRoland Dreier 		return 0;
5248a51866fSRoland Dreier 
5258a51866fSRoland Dreier 	if (mask & IB_QP_CUR_STATE  &&
5268a51866fSRoland Dreier 	    cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
5278a51866fSRoland Dreier 	    cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE)
5288a51866fSRoland Dreier 		return 0;
5298a51866fSRoland Dreier 
5308a51866fSRoland Dreier 	if (!qp_state_table[cur_state][next_state].valid)
5318a51866fSRoland Dreier 		return 0;
5328a51866fSRoland Dreier 
5338a51866fSRoland Dreier 	req_param = qp_state_table[cur_state][next_state].req_param[type];
5348a51866fSRoland Dreier 	opt_param = qp_state_table[cur_state][next_state].opt_param[type];
5358a51866fSRoland Dreier 
5368a51866fSRoland Dreier 	if ((mask & req_param) != req_param)
5378a51866fSRoland Dreier 		return 0;
5388a51866fSRoland Dreier 
5398a51866fSRoland Dreier 	if (mask & ~(req_param | opt_param | IB_QP_STATE))
5408a51866fSRoland Dreier 		return 0;
5418a51866fSRoland Dreier 
5428a51866fSRoland Dreier 	return 1;
5438a51866fSRoland Dreier }
5448a51866fSRoland Dreier EXPORT_SYMBOL(ib_modify_qp_is_ok);
5458a51866fSRoland Dreier 
5461da177e4SLinus Torvalds int ib_modify_qp(struct ib_qp *qp,
5471da177e4SLinus Torvalds 		 struct ib_qp_attr *qp_attr,
5481da177e4SLinus Torvalds 		 int qp_attr_mask)
5491da177e4SLinus Torvalds {
5509bc57e2dSRalph Campbell 	return qp->device->modify_qp(qp, qp_attr, qp_attr_mask, NULL);
5511da177e4SLinus Torvalds }
5521da177e4SLinus Torvalds EXPORT_SYMBOL(ib_modify_qp);
5531da177e4SLinus Torvalds 
5541da177e4SLinus Torvalds int ib_query_qp(struct ib_qp *qp,
5551da177e4SLinus Torvalds 		struct ib_qp_attr *qp_attr,
5561da177e4SLinus Torvalds 		int qp_attr_mask,
5571da177e4SLinus Torvalds 		struct ib_qp_init_attr *qp_init_attr)
5581da177e4SLinus Torvalds {
5591da177e4SLinus Torvalds 	return qp->device->query_qp ?
5601da177e4SLinus Torvalds 		qp->device->query_qp(qp, qp_attr, qp_attr_mask, qp_init_attr) :
5611da177e4SLinus Torvalds 		-ENOSYS;
5621da177e4SLinus Torvalds }
5631da177e4SLinus Torvalds EXPORT_SYMBOL(ib_query_qp);
5641da177e4SLinus Torvalds 
5651da177e4SLinus Torvalds int ib_destroy_qp(struct ib_qp *qp)
5661da177e4SLinus Torvalds {
5671da177e4SLinus Torvalds 	struct ib_pd *pd;
5681da177e4SLinus Torvalds 	struct ib_cq *scq, *rcq;
5691da177e4SLinus Torvalds 	struct ib_srq *srq;
5701da177e4SLinus Torvalds 	int ret;
5711da177e4SLinus Torvalds 
5721da177e4SLinus Torvalds 	pd  = qp->pd;
5731da177e4SLinus Torvalds 	scq = qp->send_cq;
5741da177e4SLinus Torvalds 	rcq = qp->recv_cq;
5751da177e4SLinus Torvalds 	srq = qp->srq;
5761da177e4SLinus Torvalds 
5771da177e4SLinus Torvalds 	ret = qp->device->destroy_qp(qp);
5781da177e4SLinus Torvalds 	if (!ret) {
5791da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
5801da177e4SLinus Torvalds 		atomic_dec(&scq->usecnt);
5811da177e4SLinus Torvalds 		atomic_dec(&rcq->usecnt);
5821da177e4SLinus Torvalds 		if (srq)
5831da177e4SLinus Torvalds 			atomic_dec(&srq->usecnt);
5841da177e4SLinus Torvalds 	}
5851da177e4SLinus Torvalds 
5861da177e4SLinus Torvalds 	return ret;
5871da177e4SLinus Torvalds }
5881da177e4SLinus Torvalds EXPORT_SYMBOL(ib_destroy_qp);
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds /* Completion queues */
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds struct ib_cq *ib_create_cq(struct ib_device *device,
5931da177e4SLinus Torvalds 			   ib_comp_handler comp_handler,
5941da177e4SLinus Torvalds 			   void (*event_handler)(struct ib_event *, void *),
5951da177e4SLinus Torvalds 			   void *cq_context, int cqe)
5961da177e4SLinus Torvalds {
5971da177e4SLinus Torvalds 	struct ib_cq *cq;
5981da177e4SLinus Torvalds 
599b5e81bf5SRoland Dreier 	cq = device->create_cq(device, cqe, NULL, NULL);
6001da177e4SLinus Torvalds 
6011da177e4SLinus Torvalds 	if (!IS_ERR(cq)) {
6021da177e4SLinus Torvalds 		cq->device        = device;
603b5e81bf5SRoland Dreier 		cq->uobject       = NULL;
6041da177e4SLinus Torvalds 		cq->comp_handler  = comp_handler;
6051da177e4SLinus Torvalds 		cq->event_handler = event_handler;
6061da177e4SLinus Torvalds 		cq->cq_context    = cq_context;
6071da177e4SLinus Torvalds 		atomic_set(&cq->usecnt, 0);
6081da177e4SLinus Torvalds 	}
6091da177e4SLinus Torvalds 
6101da177e4SLinus Torvalds 	return cq;
6111da177e4SLinus Torvalds }
6121da177e4SLinus Torvalds EXPORT_SYMBOL(ib_create_cq);
6131da177e4SLinus Torvalds 
6141da177e4SLinus Torvalds int ib_destroy_cq(struct ib_cq *cq)
6151da177e4SLinus Torvalds {
6161da177e4SLinus Torvalds 	if (atomic_read(&cq->usecnt))
6171da177e4SLinus Torvalds 		return -EBUSY;
6181da177e4SLinus Torvalds 
6191da177e4SLinus Torvalds 	return cq->device->destroy_cq(cq);
6201da177e4SLinus Torvalds }
6211da177e4SLinus Torvalds EXPORT_SYMBOL(ib_destroy_cq);
6221da177e4SLinus Torvalds 
623a74cd4afSRoland Dreier int ib_resize_cq(struct ib_cq *cq, int cqe)
6241da177e4SLinus Torvalds {
62540de2e54SRoland Dreier 	return cq->device->resize_cq ?
62633b9b3eeSRoland Dreier 		cq->device->resize_cq(cq, cqe, NULL) : -ENOSYS;
6271da177e4SLinus Torvalds }
6281da177e4SLinus Torvalds EXPORT_SYMBOL(ib_resize_cq);
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds /* Memory regions */
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
6331da177e4SLinus Torvalds {
6341da177e4SLinus Torvalds 	struct ib_mr *mr;
6351da177e4SLinus Torvalds 
6361da177e4SLinus Torvalds 	mr = pd->device->get_dma_mr(pd, mr_access_flags);
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds 	if (!IS_ERR(mr)) {
6391da177e4SLinus Torvalds 		mr->device  = pd->device;
6401da177e4SLinus Torvalds 		mr->pd      = pd;
641b5e81bf5SRoland Dreier 		mr->uobject = NULL;
6421da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
6431da177e4SLinus Torvalds 		atomic_set(&mr->usecnt, 0);
6441da177e4SLinus Torvalds 	}
6451da177e4SLinus Torvalds 
6461da177e4SLinus Torvalds 	return mr;
6471da177e4SLinus Torvalds }
6481da177e4SLinus Torvalds EXPORT_SYMBOL(ib_get_dma_mr);
6491da177e4SLinus Torvalds 
6501da177e4SLinus Torvalds struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd,
6511da177e4SLinus Torvalds 			     struct ib_phys_buf *phys_buf_array,
6521da177e4SLinus Torvalds 			     int num_phys_buf,
6531da177e4SLinus Torvalds 			     int mr_access_flags,
6541da177e4SLinus Torvalds 			     u64 *iova_start)
6551da177e4SLinus Torvalds {
6561da177e4SLinus Torvalds 	struct ib_mr *mr;
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds 	mr = pd->device->reg_phys_mr(pd, phys_buf_array, num_phys_buf,
6591da177e4SLinus Torvalds 				     mr_access_flags, iova_start);
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 	if (!IS_ERR(mr)) {
6621da177e4SLinus Torvalds 		mr->device  = pd->device;
6631da177e4SLinus Torvalds 		mr->pd      = pd;
664b5e81bf5SRoland Dreier 		mr->uobject = NULL;
6651da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
6661da177e4SLinus Torvalds 		atomic_set(&mr->usecnt, 0);
6671da177e4SLinus Torvalds 	}
6681da177e4SLinus Torvalds 
6691da177e4SLinus Torvalds 	return mr;
6701da177e4SLinus Torvalds }
6711da177e4SLinus Torvalds EXPORT_SYMBOL(ib_reg_phys_mr);
6721da177e4SLinus Torvalds 
6731da177e4SLinus Torvalds int ib_rereg_phys_mr(struct ib_mr *mr,
6741da177e4SLinus Torvalds 		     int mr_rereg_mask,
6751da177e4SLinus Torvalds 		     struct ib_pd *pd,
6761da177e4SLinus Torvalds 		     struct ib_phys_buf *phys_buf_array,
6771da177e4SLinus Torvalds 		     int num_phys_buf,
6781da177e4SLinus Torvalds 		     int mr_access_flags,
6791da177e4SLinus Torvalds 		     u64 *iova_start)
6801da177e4SLinus Torvalds {
6811da177e4SLinus Torvalds 	struct ib_pd *old_pd;
6821da177e4SLinus Torvalds 	int ret;
6831da177e4SLinus Torvalds 
6841da177e4SLinus Torvalds 	if (!mr->device->rereg_phys_mr)
6851da177e4SLinus Torvalds 		return -ENOSYS;
6861da177e4SLinus Torvalds 
6871da177e4SLinus Torvalds 	if (atomic_read(&mr->usecnt))
6881da177e4SLinus Torvalds 		return -EBUSY;
6891da177e4SLinus Torvalds 
6901da177e4SLinus Torvalds 	old_pd = mr->pd;
6911da177e4SLinus Torvalds 
6921da177e4SLinus Torvalds 	ret = mr->device->rereg_phys_mr(mr, mr_rereg_mask, pd,
6931da177e4SLinus Torvalds 					phys_buf_array, num_phys_buf,
6941da177e4SLinus Torvalds 					mr_access_flags, iova_start);
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds 	if (!ret && (mr_rereg_mask & IB_MR_REREG_PD)) {
6971da177e4SLinus Torvalds 		atomic_dec(&old_pd->usecnt);
6981da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
6991da177e4SLinus Torvalds 	}
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	return ret;
7021da177e4SLinus Torvalds }
7031da177e4SLinus Torvalds EXPORT_SYMBOL(ib_rereg_phys_mr);
7041da177e4SLinus Torvalds 
7051da177e4SLinus Torvalds int ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
7061da177e4SLinus Torvalds {
7071da177e4SLinus Torvalds 	return mr->device->query_mr ?
7081da177e4SLinus Torvalds 		mr->device->query_mr(mr, mr_attr) : -ENOSYS;
7091da177e4SLinus Torvalds }
7101da177e4SLinus Torvalds EXPORT_SYMBOL(ib_query_mr);
7111da177e4SLinus Torvalds 
7121da177e4SLinus Torvalds int ib_dereg_mr(struct ib_mr *mr)
7131da177e4SLinus Torvalds {
7141da177e4SLinus Torvalds 	struct ib_pd *pd;
7151da177e4SLinus Torvalds 	int ret;
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds 	if (atomic_read(&mr->usecnt))
7181da177e4SLinus Torvalds 		return -EBUSY;
7191da177e4SLinus Torvalds 
7201da177e4SLinus Torvalds 	pd = mr->pd;
7211da177e4SLinus Torvalds 	ret = mr->device->dereg_mr(mr);
7221da177e4SLinus Torvalds 	if (!ret)
7231da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
7241da177e4SLinus Torvalds 
7251da177e4SLinus Torvalds 	return ret;
7261da177e4SLinus Torvalds }
7271da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dereg_mr);
7281da177e4SLinus Torvalds 
7291da177e4SLinus Torvalds /* Memory windows */
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds struct ib_mw *ib_alloc_mw(struct ib_pd *pd)
7321da177e4SLinus Torvalds {
7331da177e4SLinus Torvalds 	struct ib_mw *mw;
7341da177e4SLinus Torvalds 
7351da177e4SLinus Torvalds 	if (!pd->device->alloc_mw)
7361da177e4SLinus Torvalds 		return ERR_PTR(-ENOSYS);
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds 	mw = pd->device->alloc_mw(pd);
7391da177e4SLinus Torvalds 	if (!IS_ERR(mw)) {
7401da177e4SLinus Torvalds 		mw->device  = pd->device;
7411da177e4SLinus Torvalds 		mw->pd      = pd;
742b5e81bf5SRoland Dreier 		mw->uobject = NULL;
7431da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
7441da177e4SLinus Torvalds 	}
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds 	return mw;
7471da177e4SLinus Torvalds }
7481da177e4SLinus Torvalds EXPORT_SYMBOL(ib_alloc_mw);
7491da177e4SLinus Torvalds 
7501da177e4SLinus Torvalds int ib_dealloc_mw(struct ib_mw *mw)
7511da177e4SLinus Torvalds {
7521da177e4SLinus Torvalds 	struct ib_pd *pd;
7531da177e4SLinus Torvalds 	int ret;
7541da177e4SLinus Torvalds 
7551da177e4SLinus Torvalds 	pd = mw->pd;
7561da177e4SLinus Torvalds 	ret = mw->device->dealloc_mw(mw);
7571da177e4SLinus Torvalds 	if (!ret)
7581da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
7591da177e4SLinus Torvalds 
7601da177e4SLinus Torvalds 	return ret;
7611da177e4SLinus Torvalds }
7621da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dealloc_mw);
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds /* "Fast" memory regions */
7651da177e4SLinus Torvalds 
7661da177e4SLinus Torvalds struct ib_fmr *ib_alloc_fmr(struct ib_pd *pd,
7671da177e4SLinus Torvalds 			    int mr_access_flags,
7681da177e4SLinus Torvalds 			    struct ib_fmr_attr *fmr_attr)
7691da177e4SLinus Torvalds {
7701da177e4SLinus Torvalds 	struct ib_fmr *fmr;
7711da177e4SLinus Torvalds 
7721da177e4SLinus Torvalds 	if (!pd->device->alloc_fmr)
7731da177e4SLinus Torvalds 		return ERR_PTR(-ENOSYS);
7741da177e4SLinus Torvalds 
7751da177e4SLinus Torvalds 	fmr = pd->device->alloc_fmr(pd, mr_access_flags, fmr_attr);
7761da177e4SLinus Torvalds 	if (!IS_ERR(fmr)) {
7771da177e4SLinus Torvalds 		fmr->device = pd->device;
7781da177e4SLinus Torvalds 		fmr->pd     = pd;
7791da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
7801da177e4SLinus Torvalds 	}
7811da177e4SLinus Torvalds 
7821da177e4SLinus Torvalds 	return fmr;
7831da177e4SLinus Torvalds }
7841da177e4SLinus Torvalds EXPORT_SYMBOL(ib_alloc_fmr);
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds int ib_unmap_fmr(struct list_head *fmr_list)
7871da177e4SLinus Torvalds {
7881da177e4SLinus Torvalds 	struct ib_fmr *fmr;
7891da177e4SLinus Torvalds 
7901da177e4SLinus Torvalds 	if (list_empty(fmr_list))
7911da177e4SLinus Torvalds 		return 0;
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds 	fmr = list_entry(fmr_list->next, struct ib_fmr, list);
7941da177e4SLinus Torvalds 	return fmr->device->unmap_fmr(fmr_list);
7951da177e4SLinus Torvalds }
7961da177e4SLinus Torvalds EXPORT_SYMBOL(ib_unmap_fmr);
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds int ib_dealloc_fmr(struct ib_fmr *fmr)
7991da177e4SLinus Torvalds {
8001da177e4SLinus Torvalds 	struct ib_pd *pd;
8011da177e4SLinus Torvalds 	int ret;
8021da177e4SLinus Torvalds 
8031da177e4SLinus Torvalds 	pd = fmr->pd;
8041da177e4SLinus Torvalds 	ret = fmr->device->dealloc_fmr(fmr);
8051da177e4SLinus Torvalds 	if (!ret)
8061da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds 	return ret;
8091da177e4SLinus Torvalds }
8101da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dealloc_fmr);
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds /* Multicast groups */
8131da177e4SLinus Torvalds 
8141da177e4SLinus Torvalds int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
8151da177e4SLinus Torvalds {
8160c33aeedSJack Morgenstein 	if (!qp->device->attach_mcast)
8170c33aeedSJack Morgenstein 		return -ENOSYS;
8180c33aeedSJack Morgenstein 	if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
8190c33aeedSJack Morgenstein 		return -EINVAL;
8200c33aeedSJack Morgenstein 
8210c33aeedSJack Morgenstein 	return qp->device->attach_mcast(qp, gid, lid);
8221da177e4SLinus Torvalds }
8231da177e4SLinus Torvalds EXPORT_SYMBOL(ib_attach_mcast);
8241da177e4SLinus Torvalds 
8251da177e4SLinus Torvalds int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
8261da177e4SLinus Torvalds {
8270c33aeedSJack Morgenstein 	if (!qp->device->detach_mcast)
8280c33aeedSJack Morgenstein 		return -ENOSYS;
8290c33aeedSJack Morgenstein 	if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
8300c33aeedSJack Morgenstein 		return -EINVAL;
8310c33aeedSJack Morgenstein 
8320c33aeedSJack Morgenstein 	return qp->device->detach_mcast(qp, gid, lid);
8331da177e4SLinus Torvalds }
8341da177e4SLinus Torvalds EXPORT_SYMBOL(ib_detach_mcast);
835