xref: /openbmc/linux/drivers/infiniband/core/verbs.c (revision c1bd6cde)
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>
47dd5f03beSMatan Barak #include <rdma/ib_addr.h>
481da177e4SLinus Torvalds 
49ed4c54e5SOr Gerlitz #include "core_priv.h"
501da177e4SLinus Torvalds 
518385fd84SRoland Dreier __attribute_const__ int ib_rate_to_mult(enum ib_rate rate)
52bf6a9e31SJack Morgenstein {
53bf6a9e31SJack Morgenstein 	switch (rate) {
54bf6a9e31SJack Morgenstein 	case IB_RATE_2_5_GBPS: return  1;
55bf6a9e31SJack Morgenstein 	case IB_RATE_5_GBPS:   return  2;
56bf6a9e31SJack Morgenstein 	case IB_RATE_10_GBPS:  return  4;
57bf6a9e31SJack Morgenstein 	case IB_RATE_20_GBPS:  return  8;
58bf6a9e31SJack Morgenstein 	case IB_RATE_30_GBPS:  return 12;
59bf6a9e31SJack Morgenstein 	case IB_RATE_40_GBPS:  return 16;
60bf6a9e31SJack Morgenstein 	case IB_RATE_60_GBPS:  return 24;
61bf6a9e31SJack Morgenstein 	case IB_RATE_80_GBPS:  return 32;
62bf6a9e31SJack Morgenstein 	case IB_RATE_120_GBPS: return 48;
63bf6a9e31SJack Morgenstein 	default:	       return -1;
64bf6a9e31SJack Morgenstein 	}
65bf6a9e31SJack Morgenstein }
66bf6a9e31SJack Morgenstein EXPORT_SYMBOL(ib_rate_to_mult);
67bf6a9e31SJack Morgenstein 
688385fd84SRoland Dreier __attribute_const__ enum ib_rate mult_to_ib_rate(int mult)
69bf6a9e31SJack Morgenstein {
70bf6a9e31SJack Morgenstein 	switch (mult) {
71bf6a9e31SJack Morgenstein 	case 1:  return IB_RATE_2_5_GBPS;
72bf6a9e31SJack Morgenstein 	case 2:  return IB_RATE_5_GBPS;
73bf6a9e31SJack Morgenstein 	case 4:  return IB_RATE_10_GBPS;
74bf6a9e31SJack Morgenstein 	case 8:  return IB_RATE_20_GBPS;
75bf6a9e31SJack Morgenstein 	case 12: return IB_RATE_30_GBPS;
76bf6a9e31SJack Morgenstein 	case 16: return IB_RATE_40_GBPS;
77bf6a9e31SJack Morgenstein 	case 24: return IB_RATE_60_GBPS;
78bf6a9e31SJack Morgenstein 	case 32: return IB_RATE_80_GBPS;
79bf6a9e31SJack Morgenstein 	case 48: return IB_RATE_120_GBPS;
80bf6a9e31SJack Morgenstein 	default: return IB_RATE_PORT_CURRENT;
81bf6a9e31SJack Morgenstein 	}
82bf6a9e31SJack Morgenstein }
83bf6a9e31SJack Morgenstein EXPORT_SYMBOL(mult_to_ib_rate);
84bf6a9e31SJack Morgenstein 
858385fd84SRoland Dreier __attribute_const__ int ib_rate_to_mbps(enum ib_rate rate)
8671eeba16SMarcel Apfelbaum {
8771eeba16SMarcel Apfelbaum 	switch (rate) {
8871eeba16SMarcel Apfelbaum 	case IB_RATE_2_5_GBPS: return 2500;
8971eeba16SMarcel Apfelbaum 	case IB_RATE_5_GBPS:   return 5000;
9071eeba16SMarcel Apfelbaum 	case IB_RATE_10_GBPS:  return 10000;
9171eeba16SMarcel Apfelbaum 	case IB_RATE_20_GBPS:  return 20000;
9271eeba16SMarcel Apfelbaum 	case IB_RATE_30_GBPS:  return 30000;
9371eeba16SMarcel Apfelbaum 	case IB_RATE_40_GBPS:  return 40000;
9471eeba16SMarcel Apfelbaum 	case IB_RATE_60_GBPS:  return 60000;
9571eeba16SMarcel Apfelbaum 	case IB_RATE_80_GBPS:  return 80000;
9671eeba16SMarcel Apfelbaum 	case IB_RATE_120_GBPS: return 120000;
9771eeba16SMarcel Apfelbaum 	case IB_RATE_14_GBPS:  return 14062;
9871eeba16SMarcel Apfelbaum 	case IB_RATE_56_GBPS:  return 56250;
9971eeba16SMarcel Apfelbaum 	case IB_RATE_112_GBPS: return 112500;
10071eeba16SMarcel Apfelbaum 	case IB_RATE_168_GBPS: return 168750;
10171eeba16SMarcel Apfelbaum 	case IB_RATE_25_GBPS:  return 25781;
10271eeba16SMarcel Apfelbaum 	case IB_RATE_100_GBPS: return 103125;
10371eeba16SMarcel Apfelbaum 	case IB_RATE_200_GBPS: return 206250;
10471eeba16SMarcel Apfelbaum 	case IB_RATE_300_GBPS: return 309375;
10571eeba16SMarcel Apfelbaum 	default:	       return -1;
10671eeba16SMarcel Apfelbaum 	}
10771eeba16SMarcel Apfelbaum }
10871eeba16SMarcel Apfelbaum EXPORT_SYMBOL(ib_rate_to_mbps);
10971eeba16SMarcel Apfelbaum 
1108385fd84SRoland Dreier __attribute_const__ enum rdma_transport_type
11107ebafbaSTom Tucker rdma_node_get_transport(enum rdma_node_type node_type)
11207ebafbaSTom Tucker {
11307ebafbaSTom Tucker 	switch (node_type) {
11407ebafbaSTom Tucker 	case RDMA_NODE_IB_CA:
11507ebafbaSTom Tucker 	case RDMA_NODE_IB_SWITCH:
11607ebafbaSTom Tucker 	case RDMA_NODE_IB_ROUTER:
11707ebafbaSTom Tucker 		return RDMA_TRANSPORT_IB;
11807ebafbaSTom Tucker 	case RDMA_NODE_RNIC:
11907ebafbaSTom Tucker 		return RDMA_TRANSPORT_IWARP;
120180771a3SUpinder Malhi \(umalhi\) 	case RDMA_NODE_USNIC:
1215db5765eSUpinder Malhi 		return RDMA_TRANSPORT_USNIC;
1225db5765eSUpinder Malhi 	case RDMA_NODE_USNIC_UDP:
123248567f7SUpinder Malhi 		return RDMA_TRANSPORT_USNIC_UDP;
12407ebafbaSTom Tucker 	default:
12507ebafbaSTom Tucker 		BUG();
12607ebafbaSTom Tucker 		return 0;
12707ebafbaSTom Tucker 	}
12807ebafbaSTom Tucker }
12907ebafbaSTom Tucker EXPORT_SYMBOL(rdma_node_get_transport);
13007ebafbaSTom Tucker 
131a3f5adafSEli Cohen enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device, u8 port_num)
132a3f5adafSEli Cohen {
133a3f5adafSEli Cohen 	if (device->get_link_layer)
134a3f5adafSEli Cohen 		return device->get_link_layer(device, port_num);
135a3f5adafSEli Cohen 
136a3f5adafSEli Cohen 	switch (rdma_node_get_transport(device->node_type)) {
137a3f5adafSEli Cohen 	case RDMA_TRANSPORT_IB:
138a3f5adafSEli Cohen 		return IB_LINK_LAYER_INFINIBAND;
139a3f5adafSEli Cohen 	case RDMA_TRANSPORT_IWARP:
140180771a3SUpinder Malhi \(umalhi\) 	case RDMA_TRANSPORT_USNIC:
141248567f7SUpinder Malhi 	case RDMA_TRANSPORT_USNIC_UDP:
142a3f5adafSEli Cohen 		return IB_LINK_LAYER_ETHERNET;
143a3f5adafSEli Cohen 	default:
144a3f5adafSEli Cohen 		return IB_LINK_LAYER_UNSPECIFIED;
145a3f5adafSEli Cohen 	}
146a3f5adafSEli Cohen }
147a3f5adafSEli Cohen EXPORT_SYMBOL(rdma_port_get_link_layer);
148a3f5adafSEli Cohen 
1491da177e4SLinus Torvalds /* Protection domains */
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds struct ib_pd *ib_alloc_pd(struct ib_device *device)
1521da177e4SLinus Torvalds {
1531da177e4SLinus Torvalds 	struct ib_pd *pd;
1541da177e4SLinus Torvalds 
155b5e81bf5SRoland Dreier 	pd = device->alloc_pd(device, NULL, NULL);
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	if (!IS_ERR(pd)) {
1581da177e4SLinus Torvalds 		pd->device  = device;
159b5e81bf5SRoland Dreier 		pd->uobject = NULL;
1601da177e4SLinus Torvalds 		atomic_set(&pd->usecnt, 0);
1611da177e4SLinus Torvalds 	}
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 	return pd;
1641da177e4SLinus Torvalds }
1651da177e4SLinus Torvalds EXPORT_SYMBOL(ib_alloc_pd);
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds int ib_dealloc_pd(struct ib_pd *pd)
1681da177e4SLinus Torvalds {
1691da177e4SLinus Torvalds 	if (atomic_read(&pd->usecnt))
1701da177e4SLinus Torvalds 		return -EBUSY;
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds 	return pd->device->dealloc_pd(pd);
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dealloc_pd);
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds /* Address handles */
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
1791da177e4SLinus Torvalds {
1801da177e4SLinus Torvalds 	struct ib_ah *ah;
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds 	ah = pd->device->create_ah(pd, ah_attr);
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds 	if (!IS_ERR(ah)) {
1851da177e4SLinus Torvalds 		ah->device  = pd->device;
1861da177e4SLinus Torvalds 		ah->pd      = pd;
187b5e81bf5SRoland Dreier 		ah->uobject = NULL;
1881da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
1891da177e4SLinus Torvalds 	}
1901da177e4SLinus Torvalds 
1911da177e4SLinus Torvalds 	return ah;
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds EXPORT_SYMBOL(ib_create_ah);
1941da177e4SLinus Torvalds 
1954e00d694SSean Hefty int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc,
1964e00d694SSean Hefty 		       struct ib_grh *grh, struct ib_ah_attr *ah_attr)
197513789edSHal Rosenstock {
198513789edSHal Rosenstock 	u32 flow_class;
199513789edSHal Rosenstock 	u16 gid_index;
200513789edSHal Rosenstock 	int ret;
201dd5f03beSMatan Barak 	int is_eth = (rdma_port_get_link_layer(device, port_num) ==
202dd5f03beSMatan Barak 			IB_LINK_LAYER_ETHERNET);
203513789edSHal Rosenstock 
2044e00d694SSean Hefty 	memset(ah_attr, 0, sizeof *ah_attr);
205dd5f03beSMatan Barak 	if (is_eth) {
206dd5f03beSMatan Barak 		if (!(wc->wc_flags & IB_WC_GRH))
207dd5f03beSMatan Barak 			return -EPROTOTYPE;
208dd5f03beSMatan Barak 
209dd5f03beSMatan Barak 		if (wc->wc_flags & IB_WC_WITH_SMAC &&
210dd5f03beSMatan Barak 		    wc->wc_flags & IB_WC_WITH_VLAN) {
211dd5f03beSMatan Barak 			memcpy(ah_attr->dmac, wc->smac, ETH_ALEN);
212dd5f03beSMatan Barak 			ah_attr->vlan_id = wc->vlan_id;
213dd5f03beSMatan Barak 		} else {
214dd5f03beSMatan Barak 			ret = rdma_addr_find_dmac_by_grh(&grh->dgid, &grh->sgid,
215dd5f03beSMatan Barak 					ah_attr->dmac, &ah_attr->vlan_id);
216dd5f03beSMatan Barak 			if (ret)
217dd5f03beSMatan Barak 				return ret;
218dd5f03beSMatan Barak 		}
219dd5f03beSMatan Barak 	} else {
220dd5f03beSMatan Barak 		ah_attr->vlan_id = 0xffff;
221dd5f03beSMatan Barak 	}
222dd5f03beSMatan Barak 
2234e00d694SSean Hefty 	ah_attr->dlid = wc->slid;
2244e00d694SSean Hefty 	ah_attr->sl = wc->sl;
2254e00d694SSean Hefty 	ah_attr->src_path_bits = wc->dlid_path_bits;
2264e00d694SSean Hefty 	ah_attr->port_num = port_num;
227513789edSHal Rosenstock 
228513789edSHal Rosenstock 	if (wc->wc_flags & IB_WC_GRH) {
2294e00d694SSean Hefty 		ah_attr->ah_flags = IB_AH_GRH;
2304e00d694SSean Hefty 		ah_attr->grh.dgid = grh->sgid;
231513789edSHal Rosenstock 
2324e00d694SSean Hefty 		ret = ib_find_cached_gid(device, &grh->dgid, &port_num,
233513789edSHal Rosenstock 					 &gid_index);
234513789edSHal Rosenstock 		if (ret)
2354e00d694SSean Hefty 			return ret;
236513789edSHal Rosenstock 
2374e00d694SSean Hefty 		ah_attr->grh.sgid_index = (u8) gid_index;
238497677abSHal Rosenstock 		flow_class = be32_to_cpu(grh->version_tclass_flow);
2394e00d694SSean Hefty 		ah_attr->grh.flow_label = flow_class & 0xFFFFF;
24047645d8dSSean Hefty 		ah_attr->grh.hop_limit = 0xFF;
2414e00d694SSean Hefty 		ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
242513789edSHal Rosenstock 	}
2434e00d694SSean Hefty 	return 0;
2444e00d694SSean Hefty }
2454e00d694SSean Hefty EXPORT_SYMBOL(ib_init_ah_from_wc);
2464e00d694SSean Hefty 
2474e00d694SSean Hefty struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc,
2484e00d694SSean Hefty 				   struct ib_grh *grh, u8 port_num)
2494e00d694SSean Hefty {
2504e00d694SSean Hefty 	struct ib_ah_attr ah_attr;
2514e00d694SSean Hefty 	int ret;
2524e00d694SSean Hefty 
2534e00d694SSean Hefty 	ret = ib_init_ah_from_wc(pd->device, port_num, wc, grh, &ah_attr);
2544e00d694SSean Hefty 	if (ret)
2554e00d694SSean Hefty 		return ERR_PTR(ret);
256513789edSHal Rosenstock 
257513789edSHal Rosenstock 	return ib_create_ah(pd, &ah_attr);
258513789edSHal Rosenstock }
259513789edSHal Rosenstock EXPORT_SYMBOL(ib_create_ah_from_wc);
260513789edSHal Rosenstock 
2611da177e4SLinus Torvalds int ib_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
2621da177e4SLinus Torvalds {
2631da177e4SLinus Torvalds 	return ah->device->modify_ah ?
2641da177e4SLinus Torvalds 		ah->device->modify_ah(ah, ah_attr) :
2651da177e4SLinus Torvalds 		-ENOSYS;
2661da177e4SLinus Torvalds }
2671da177e4SLinus Torvalds EXPORT_SYMBOL(ib_modify_ah);
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds int ib_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
2701da177e4SLinus Torvalds {
2711da177e4SLinus Torvalds 	return ah->device->query_ah ?
2721da177e4SLinus Torvalds 		ah->device->query_ah(ah, ah_attr) :
2731da177e4SLinus Torvalds 		-ENOSYS;
2741da177e4SLinus Torvalds }
2751da177e4SLinus Torvalds EXPORT_SYMBOL(ib_query_ah);
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds int ib_destroy_ah(struct ib_ah *ah)
2781da177e4SLinus Torvalds {
2791da177e4SLinus Torvalds 	struct ib_pd *pd;
2801da177e4SLinus Torvalds 	int ret;
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds 	pd = ah->pd;
2831da177e4SLinus Torvalds 	ret = ah->device->destroy_ah(ah);
2841da177e4SLinus Torvalds 	if (!ret)
2851da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	return ret;
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds EXPORT_SYMBOL(ib_destroy_ah);
2901da177e4SLinus Torvalds 
291d41fcc67SRoland Dreier /* Shared receive queues */
292d41fcc67SRoland Dreier 
293d41fcc67SRoland Dreier struct ib_srq *ib_create_srq(struct ib_pd *pd,
294d41fcc67SRoland Dreier 			     struct ib_srq_init_attr *srq_init_attr)
295d41fcc67SRoland Dreier {
296d41fcc67SRoland Dreier 	struct ib_srq *srq;
297d41fcc67SRoland Dreier 
298d41fcc67SRoland Dreier 	if (!pd->device->create_srq)
299d41fcc67SRoland Dreier 		return ERR_PTR(-ENOSYS);
300d41fcc67SRoland Dreier 
301d41fcc67SRoland Dreier 	srq = pd->device->create_srq(pd, srq_init_attr, NULL);
302d41fcc67SRoland Dreier 
303d41fcc67SRoland Dreier 	if (!IS_ERR(srq)) {
304d41fcc67SRoland Dreier 		srq->device    	   = pd->device;
305d41fcc67SRoland Dreier 		srq->pd        	   = pd;
306d41fcc67SRoland Dreier 		srq->uobject       = NULL;
307d41fcc67SRoland Dreier 		srq->event_handler = srq_init_attr->event_handler;
308d41fcc67SRoland Dreier 		srq->srq_context   = srq_init_attr->srq_context;
30996104edaSSean Hefty 		srq->srq_type      = srq_init_attr->srq_type;
310418d5130SSean Hefty 		if (srq->srq_type == IB_SRQT_XRC) {
311418d5130SSean Hefty 			srq->ext.xrc.xrcd = srq_init_attr->ext.xrc.xrcd;
312418d5130SSean Hefty 			srq->ext.xrc.cq   = srq_init_attr->ext.xrc.cq;
313418d5130SSean Hefty 			atomic_inc(&srq->ext.xrc.xrcd->usecnt);
314418d5130SSean Hefty 			atomic_inc(&srq->ext.xrc.cq->usecnt);
315418d5130SSean Hefty 		}
316d41fcc67SRoland Dreier 		atomic_inc(&pd->usecnt);
317d41fcc67SRoland Dreier 		atomic_set(&srq->usecnt, 0);
318d41fcc67SRoland Dreier 	}
319d41fcc67SRoland Dreier 
320d41fcc67SRoland Dreier 	return srq;
321d41fcc67SRoland Dreier }
322d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_create_srq);
323d41fcc67SRoland Dreier 
324d41fcc67SRoland Dreier int ib_modify_srq(struct ib_srq *srq,
325d41fcc67SRoland Dreier 		  struct ib_srq_attr *srq_attr,
326d41fcc67SRoland Dreier 		  enum ib_srq_attr_mask srq_attr_mask)
327d41fcc67SRoland Dreier {
3287ce5eacbSDotan Barak 	return srq->device->modify_srq ?
3297ce5eacbSDotan Barak 		srq->device->modify_srq(srq, srq_attr, srq_attr_mask, NULL) :
3307ce5eacbSDotan Barak 		-ENOSYS;
331d41fcc67SRoland Dreier }
332d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_modify_srq);
333d41fcc67SRoland Dreier 
334d41fcc67SRoland Dreier int ib_query_srq(struct ib_srq *srq,
335d41fcc67SRoland Dreier 		 struct ib_srq_attr *srq_attr)
336d41fcc67SRoland Dreier {
337d41fcc67SRoland Dreier 	return srq->device->query_srq ?
338d41fcc67SRoland Dreier 		srq->device->query_srq(srq, srq_attr) : -ENOSYS;
339d41fcc67SRoland Dreier }
340d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_query_srq);
341d41fcc67SRoland Dreier 
342d41fcc67SRoland Dreier int ib_destroy_srq(struct ib_srq *srq)
343d41fcc67SRoland Dreier {
344d41fcc67SRoland Dreier 	struct ib_pd *pd;
345418d5130SSean Hefty 	enum ib_srq_type srq_type;
346418d5130SSean Hefty 	struct ib_xrcd *uninitialized_var(xrcd);
347418d5130SSean Hefty 	struct ib_cq *uninitialized_var(cq);
348d41fcc67SRoland Dreier 	int ret;
349d41fcc67SRoland Dreier 
350d41fcc67SRoland Dreier 	if (atomic_read(&srq->usecnt))
351d41fcc67SRoland Dreier 		return -EBUSY;
352d41fcc67SRoland Dreier 
353d41fcc67SRoland Dreier 	pd = srq->pd;
354418d5130SSean Hefty 	srq_type = srq->srq_type;
355418d5130SSean Hefty 	if (srq_type == IB_SRQT_XRC) {
356418d5130SSean Hefty 		xrcd = srq->ext.xrc.xrcd;
357418d5130SSean Hefty 		cq = srq->ext.xrc.cq;
358418d5130SSean Hefty 	}
359d41fcc67SRoland Dreier 
360d41fcc67SRoland Dreier 	ret = srq->device->destroy_srq(srq);
361418d5130SSean Hefty 	if (!ret) {
362d41fcc67SRoland Dreier 		atomic_dec(&pd->usecnt);
363418d5130SSean Hefty 		if (srq_type == IB_SRQT_XRC) {
364418d5130SSean Hefty 			atomic_dec(&xrcd->usecnt);
365418d5130SSean Hefty 			atomic_dec(&cq->usecnt);
366418d5130SSean Hefty 		}
367418d5130SSean Hefty 	}
368d41fcc67SRoland Dreier 
369d41fcc67SRoland Dreier 	return ret;
370d41fcc67SRoland Dreier }
371d41fcc67SRoland Dreier EXPORT_SYMBOL(ib_destroy_srq);
372d41fcc67SRoland Dreier 
3731da177e4SLinus Torvalds /* Queue pairs */
3741da177e4SLinus Torvalds 
3750e0ec7e0SSean Hefty static void __ib_shared_qp_event_handler(struct ib_event *event, void *context)
3760e0ec7e0SSean Hefty {
3770e0ec7e0SSean Hefty 	struct ib_qp *qp = context;
37873c40c61SYishai Hadas 	unsigned long flags;
3790e0ec7e0SSean Hefty 
38073c40c61SYishai Hadas 	spin_lock_irqsave(&qp->device->event_handler_lock, flags);
3810e0ec7e0SSean Hefty 	list_for_each_entry(event->element.qp, &qp->open_list, open_list)
382eec9e29fSShlomo Pongratz 		if (event->element.qp->event_handler)
3830e0ec7e0SSean Hefty 			event->element.qp->event_handler(event, event->element.qp->qp_context);
38473c40c61SYishai Hadas 	spin_unlock_irqrestore(&qp->device->event_handler_lock, flags);
3850e0ec7e0SSean Hefty }
3860e0ec7e0SSean Hefty 
387d3d72d90SSean Hefty static void __ib_insert_xrcd_qp(struct ib_xrcd *xrcd, struct ib_qp *qp)
388d3d72d90SSean Hefty {
389d3d72d90SSean Hefty 	mutex_lock(&xrcd->tgt_qp_mutex);
390d3d72d90SSean Hefty 	list_add(&qp->xrcd_list, &xrcd->tgt_qp_list);
391d3d72d90SSean Hefty 	mutex_unlock(&xrcd->tgt_qp_mutex);
392d3d72d90SSean Hefty }
393d3d72d90SSean Hefty 
3940e0ec7e0SSean Hefty static struct ib_qp *__ib_open_qp(struct ib_qp *real_qp,
3950e0ec7e0SSean Hefty 				  void (*event_handler)(struct ib_event *, void *),
3960e0ec7e0SSean Hefty 				  void *qp_context)
397d3d72d90SSean Hefty {
3980e0ec7e0SSean Hefty 	struct ib_qp *qp;
3990e0ec7e0SSean Hefty 	unsigned long flags;
4000e0ec7e0SSean Hefty 
4010e0ec7e0SSean Hefty 	qp = kzalloc(sizeof *qp, GFP_KERNEL);
4020e0ec7e0SSean Hefty 	if (!qp)
4030e0ec7e0SSean Hefty 		return ERR_PTR(-ENOMEM);
4040e0ec7e0SSean Hefty 
4050e0ec7e0SSean Hefty 	qp->real_qp = real_qp;
4060e0ec7e0SSean Hefty 	atomic_inc(&real_qp->usecnt);
4070e0ec7e0SSean Hefty 	qp->device = real_qp->device;
4080e0ec7e0SSean Hefty 	qp->event_handler = event_handler;
4090e0ec7e0SSean Hefty 	qp->qp_context = qp_context;
4100e0ec7e0SSean Hefty 	qp->qp_num = real_qp->qp_num;
4110e0ec7e0SSean Hefty 	qp->qp_type = real_qp->qp_type;
4120e0ec7e0SSean Hefty 
4130e0ec7e0SSean Hefty 	spin_lock_irqsave(&real_qp->device->event_handler_lock, flags);
4140e0ec7e0SSean Hefty 	list_add(&qp->open_list, &real_qp->open_list);
4150e0ec7e0SSean Hefty 	spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags);
4160e0ec7e0SSean Hefty 
4170e0ec7e0SSean Hefty 	return qp;
418d3d72d90SSean Hefty }
419d3d72d90SSean Hefty 
4200e0ec7e0SSean Hefty struct ib_qp *ib_open_qp(struct ib_xrcd *xrcd,
4210e0ec7e0SSean Hefty 			 struct ib_qp_open_attr *qp_open_attr)
4220e0ec7e0SSean Hefty {
4230e0ec7e0SSean Hefty 	struct ib_qp *qp, *real_qp;
4240e0ec7e0SSean Hefty 
4250e0ec7e0SSean Hefty 	if (qp_open_attr->qp_type != IB_QPT_XRC_TGT)
4260e0ec7e0SSean Hefty 		return ERR_PTR(-EINVAL);
4270e0ec7e0SSean Hefty 
4280e0ec7e0SSean Hefty 	qp = ERR_PTR(-EINVAL);
4290e0ec7e0SSean Hefty 	mutex_lock(&xrcd->tgt_qp_mutex);
4300e0ec7e0SSean Hefty 	list_for_each_entry(real_qp, &xrcd->tgt_qp_list, xrcd_list) {
4310e0ec7e0SSean Hefty 		if (real_qp->qp_num == qp_open_attr->qp_num) {
4320e0ec7e0SSean Hefty 			qp = __ib_open_qp(real_qp, qp_open_attr->event_handler,
4330e0ec7e0SSean Hefty 					  qp_open_attr->qp_context);
4340e0ec7e0SSean Hefty 			break;
4350e0ec7e0SSean Hefty 		}
4360e0ec7e0SSean Hefty 	}
4370e0ec7e0SSean Hefty 	mutex_unlock(&xrcd->tgt_qp_mutex);
4380e0ec7e0SSean Hefty 	return qp;
4390e0ec7e0SSean Hefty }
4400e0ec7e0SSean Hefty EXPORT_SYMBOL(ib_open_qp);
4410e0ec7e0SSean Hefty 
4421da177e4SLinus Torvalds struct ib_qp *ib_create_qp(struct ib_pd *pd,
4431da177e4SLinus Torvalds 			   struct ib_qp_init_attr *qp_init_attr)
4441da177e4SLinus Torvalds {
4450e0ec7e0SSean Hefty 	struct ib_qp *qp, *real_qp;
446b42b63cfSSean Hefty 	struct ib_device *device;
4471da177e4SLinus Torvalds 
448b42b63cfSSean Hefty 	device = pd ? pd->device : qp_init_attr->xrcd->device;
449b42b63cfSSean Hefty 	qp = device->create_qp(pd, qp_init_attr, NULL);
4501da177e4SLinus Torvalds 
4511da177e4SLinus Torvalds 	if (!IS_ERR(qp)) {
452b42b63cfSSean Hefty 		qp->device     = device;
4530e0ec7e0SSean Hefty 		qp->real_qp    = qp;
454b5e81bf5SRoland Dreier 		qp->uobject    = NULL;
4550e0ec7e0SSean Hefty 		qp->qp_type    = qp_init_attr->qp_type;
456b42b63cfSSean Hefty 
457e47e321aSBernd Schubert 		atomic_set(&qp->usecnt, 0);
458b42b63cfSSean Hefty 		if (qp_init_attr->qp_type == IB_QPT_XRC_TGT) {
4590e0ec7e0SSean Hefty 			qp->event_handler = __ib_shared_qp_event_handler;
4600e0ec7e0SSean Hefty 			qp->qp_context = qp;
461b42b63cfSSean Hefty 			qp->pd = NULL;
462b42b63cfSSean Hefty 			qp->send_cq = qp->recv_cq = NULL;
463b42b63cfSSean Hefty 			qp->srq = NULL;
464b42b63cfSSean Hefty 			qp->xrcd = qp_init_attr->xrcd;
465b42b63cfSSean Hefty 			atomic_inc(&qp_init_attr->xrcd->usecnt);
4660e0ec7e0SSean Hefty 			INIT_LIST_HEAD(&qp->open_list);
4670e0ec7e0SSean Hefty 
4680e0ec7e0SSean Hefty 			real_qp = qp;
4690e0ec7e0SSean Hefty 			qp = __ib_open_qp(real_qp, qp_init_attr->event_handler,
4700e0ec7e0SSean Hefty 					  qp_init_attr->qp_context);
4710e0ec7e0SSean Hefty 			if (!IS_ERR(qp))
4720e0ec7e0SSean Hefty 				__ib_insert_xrcd_qp(qp_init_attr->xrcd, real_qp);
4730e0ec7e0SSean Hefty 			else
4740e0ec7e0SSean Hefty 				real_qp->device->destroy_qp(real_qp);
475b42b63cfSSean Hefty 		} else {
4761da177e4SLinus Torvalds 			qp->event_handler = qp_init_attr->event_handler;
4771da177e4SLinus Torvalds 			qp->qp_context = qp_init_attr->qp_context;
478b42b63cfSSean Hefty 			if (qp_init_attr->qp_type == IB_QPT_XRC_INI) {
479b42b63cfSSean Hefty 				qp->recv_cq = NULL;
480b42b63cfSSean Hefty 				qp->srq = NULL;
481b42b63cfSSean Hefty 			} else {
482b42b63cfSSean Hefty 				qp->recv_cq = qp_init_attr->recv_cq;
483b42b63cfSSean Hefty 				atomic_inc(&qp_init_attr->recv_cq->usecnt);
484b42b63cfSSean Hefty 				qp->srq = qp_init_attr->srq;
485b42b63cfSSean Hefty 				if (qp->srq)
486b42b63cfSSean Hefty 					atomic_inc(&qp_init_attr->srq->usecnt);
487b42b63cfSSean Hefty 			}
488b42b63cfSSean Hefty 
4891da177e4SLinus Torvalds 			qp->pd	    = pd;
4901da177e4SLinus Torvalds 			qp->send_cq = qp_init_attr->send_cq;
491b42b63cfSSean Hefty 			qp->xrcd    = NULL;
492b42b63cfSSean Hefty 
4931da177e4SLinus Torvalds 			atomic_inc(&pd->usecnt);
4941da177e4SLinus Torvalds 			atomic_inc(&qp_init_attr->send_cq->usecnt);
495b42b63cfSSean Hefty 		}
4961da177e4SLinus Torvalds 	}
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 	return qp;
4991da177e4SLinus Torvalds }
5001da177e4SLinus Torvalds EXPORT_SYMBOL(ib_create_qp);
5011da177e4SLinus Torvalds 
5028a51866fSRoland Dreier static const struct {
5038a51866fSRoland Dreier 	int			valid;
504b42b63cfSSean Hefty 	enum ib_qp_attr_mask	req_param[IB_QPT_MAX];
505dd5f03beSMatan Barak 	enum ib_qp_attr_mask	req_param_add_eth[IB_QPT_MAX];
506b42b63cfSSean Hefty 	enum ib_qp_attr_mask	opt_param[IB_QPT_MAX];
507dd5f03beSMatan Barak 	enum ib_qp_attr_mask	opt_param_add_eth[IB_QPT_MAX];
5088a51866fSRoland Dreier } qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
5098a51866fSRoland Dreier 	[IB_QPS_RESET] = {
5108a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
5118a51866fSRoland Dreier 		[IB_QPS_INIT]  = {
5128a51866fSRoland Dreier 			.valid = 1,
5138a51866fSRoland Dreier 			.req_param = {
5148a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
5158a51866fSRoland Dreier 						IB_QP_PORT			|
5168a51866fSRoland Dreier 						IB_QP_QKEY),
517c938a616SOr Gerlitz 				[IB_QPT_RAW_PACKET] = IB_QP_PORT,
5188a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
5198a51866fSRoland Dreier 						IB_QP_PORT			|
5208a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
5218a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
5228a51866fSRoland Dreier 						IB_QP_PORT			|
5238a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
524b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_PKEY_INDEX		|
525b42b63cfSSean Hefty 						IB_QP_PORT			|
526b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS),
527b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_PKEY_INDEX		|
528b42b63cfSSean Hefty 						IB_QP_PORT			|
529b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS),
5308a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
5318a51866fSRoland Dreier 						IB_QP_QKEY),
5328a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
5338a51866fSRoland Dreier 						IB_QP_QKEY),
5348a51866fSRoland Dreier 			}
5358a51866fSRoland Dreier 		},
5368a51866fSRoland Dreier 	},
5378a51866fSRoland Dreier 	[IB_QPS_INIT]  = {
5388a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
5398a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
5408a51866fSRoland Dreier 		[IB_QPS_INIT]  = {
5418a51866fSRoland Dreier 			.valid = 1,
5428a51866fSRoland Dreier 			.opt_param = {
5438a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
5448a51866fSRoland Dreier 						IB_QP_PORT			|
5458a51866fSRoland Dreier 						IB_QP_QKEY),
5468a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
5478a51866fSRoland Dreier 						IB_QP_PORT			|
5488a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
5498a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
5508a51866fSRoland Dreier 						IB_QP_PORT			|
5518a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
552b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_PKEY_INDEX		|
553b42b63cfSSean Hefty 						IB_QP_PORT			|
554b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS),
555b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_PKEY_INDEX		|
556b42b63cfSSean Hefty 						IB_QP_PORT			|
557b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS),
5588a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
5598a51866fSRoland Dreier 						IB_QP_QKEY),
5608a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
5618a51866fSRoland Dreier 						IB_QP_QKEY),
5628a51866fSRoland Dreier 			}
5638a51866fSRoland Dreier 		},
5648a51866fSRoland Dreier 		[IB_QPS_RTR]   = {
5658a51866fSRoland Dreier 			.valid = 1,
5668a51866fSRoland Dreier 			.req_param = {
5678a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_AV			|
5688a51866fSRoland Dreier 						IB_QP_PATH_MTU			|
5698a51866fSRoland Dreier 						IB_QP_DEST_QPN			|
5708a51866fSRoland Dreier 						IB_QP_RQ_PSN),
5718a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_AV			|
5728a51866fSRoland Dreier 						IB_QP_PATH_MTU			|
5738a51866fSRoland Dreier 						IB_QP_DEST_QPN			|
5748a51866fSRoland Dreier 						IB_QP_RQ_PSN			|
5758a51866fSRoland Dreier 						IB_QP_MAX_DEST_RD_ATOMIC	|
5768a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER),
577b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_AV			|
578b42b63cfSSean Hefty 						IB_QP_PATH_MTU			|
579b42b63cfSSean Hefty 						IB_QP_DEST_QPN			|
580b42b63cfSSean Hefty 						IB_QP_RQ_PSN),
581b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_AV			|
582b42b63cfSSean Hefty 						IB_QP_PATH_MTU			|
583b42b63cfSSean Hefty 						IB_QP_DEST_QPN			|
584b42b63cfSSean Hefty 						IB_QP_RQ_PSN			|
585b42b63cfSSean Hefty 						IB_QP_MAX_DEST_RD_ATOMIC	|
586b42b63cfSSean Hefty 						IB_QP_MIN_RNR_TIMER),
5878a51866fSRoland Dreier 			},
588dd5f03beSMatan Barak 			.req_param_add_eth = {
589dd5f03beSMatan Barak 				[IB_QPT_RC]  = (IB_QP_SMAC),
590dd5f03beSMatan Barak 				[IB_QPT_UC]  = (IB_QP_SMAC),
591dd5f03beSMatan Barak 				[IB_QPT_XRC_INI]  = (IB_QP_SMAC),
592dd5f03beSMatan Barak 				[IB_QPT_XRC_TGT]  = (IB_QP_SMAC)
593dd5f03beSMatan Barak 			},
5948a51866fSRoland Dreier 			.opt_param = {
5958a51866fSRoland Dreier 				 [IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
5968a51866fSRoland Dreier 						 IB_QP_QKEY),
5978a51866fSRoland Dreier 				 [IB_QPT_UC]  = (IB_QP_ALT_PATH			|
5988a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
5998a51866fSRoland Dreier 						 IB_QP_PKEY_INDEX),
6008a51866fSRoland Dreier 				 [IB_QPT_RC]  = (IB_QP_ALT_PATH			|
6018a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
6028a51866fSRoland Dreier 						 IB_QP_PKEY_INDEX),
603b42b63cfSSean Hefty 				 [IB_QPT_XRC_INI] = (IB_QP_ALT_PATH		|
604b42b63cfSSean Hefty 						 IB_QP_ACCESS_FLAGS		|
605b42b63cfSSean Hefty 						 IB_QP_PKEY_INDEX),
606b42b63cfSSean Hefty 				 [IB_QPT_XRC_TGT] = (IB_QP_ALT_PATH		|
607b42b63cfSSean Hefty 						 IB_QP_ACCESS_FLAGS		|
608b42b63cfSSean Hefty 						 IB_QP_PKEY_INDEX),
6098a51866fSRoland Dreier 				 [IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
6108a51866fSRoland Dreier 						 IB_QP_QKEY),
6118a51866fSRoland Dreier 				 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
6128a51866fSRoland Dreier 						 IB_QP_QKEY),
613dd5f03beSMatan Barak 			 },
614dd5f03beSMatan Barak 			.opt_param_add_eth = {
615dd5f03beSMatan Barak 				[IB_QPT_RC]  = (IB_QP_ALT_SMAC			|
616dd5f03beSMatan Barak 						IB_QP_VID			|
617dd5f03beSMatan Barak 						IB_QP_ALT_VID),
618dd5f03beSMatan Barak 				[IB_QPT_UC]  = (IB_QP_ALT_SMAC			|
619dd5f03beSMatan Barak 						IB_QP_VID			|
620dd5f03beSMatan Barak 						IB_QP_ALT_VID),
621dd5f03beSMatan Barak 				[IB_QPT_XRC_INI]  = (IB_QP_ALT_SMAC			|
622dd5f03beSMatan Barak 						IB_QP_VID			|
623dd5f03beSMatan Barak 						IB_QP_ALT_VID),
624dd5f03beSMatan Barak 				[IB_QPT_XRC_TGT]  = (IB_QP_ALT_SMAC			|
625dd5f03beSMatan Barak 						IB_QP_VID			|
626dd5f03beSMatan Barak 						IB_QP_ALT_VID)
6278a51866fSRoland Dreier 			}
6288a51866fSRoland Dreier 		}
6298a51866fSRoland Dreier 	},
6308a51866fSRoland Dreier 	[IB_QPS_RTR]   = {
6318a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
6328a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
6338a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
6348a51866fSRoland Dreier 			.valid = 1,
6358a51866fSRoland Dreier 			.req_param = {
6368a51866fSRoland Dreier 				[IB_QPT_UD]  = IB_QP_SQ_PSN,
6378a51866fSRoland Dreier 				[IB_QPT_UC]  = IB_QP_SQ_PSN,
6388a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_TIMEOUT			|
6398a51866fSRoland Dreier 						IB_QP_RETRY_CNT			|
6408a51866fSRoland Dreier 						IB_QP_RNR_RETRY			|
6418a51866fSRoland Dreier 						IB_QP_SQ_PSN			|
6428a51866fSRoland Dreier 						IB_QP_MAX_QP_RD_ATOMIC),
643b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_TIMEOUT		|
644b42b63cfSSean Hefty 						IB_QP_RETRY_CNT			|
645b42b63cfSSean Hefty 						IB_QP_RNR_RETRY			|
646b42b63cfSSean Hefty 						IB_QP_SQ_PSN			|
647b42b63cfSSean Hefty 						IB_QP_MAX_QP_RD_ATOMIC),
648b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_TIMEOUT		|
649b42b63cfSSean Hefty 						IB_QP_SQ_PSN),
6508a51866fSRoland Dreier 				[IB_QPT_SMI] = IB_QP_SQ_PSN,
6518a51866fSRoland Dreier 				[IB_QPT_GSI] = IB_QP_SQ_PSN,
6528a51866fSRoland Dreier 			},
6538a51866fSRoland Dreier 			.opt_param = {
6548a51866fSRoland Dreier 				 [IB_QPT_UD]  = (IB_QP_CUR_STATE		|
6558a51866fSRoland Dreier 						 IB_QP_QKEY),
6568a51866fSRoland Dreier 				 [IB_QPT_UC]  = (IB_QP_CUR_STATE		|
6578a51866fSRoland Dreier 						 IB_QP_ALT_PATH			|
6588a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
6598a51866fSRoland Dreier 						 IB_QP_PATH_MIG_STATE),
6608a51866fSRoland Dreier 				 [IB_QPT_RC]  = (IB_QP_CUR_STATE		|
6618a51866fSRoland Dreier 						 IB_QP_ALT_PATH			|
6628a51866fSRoland Dreier 						 IB_QP_ACCESS_FLAGS		|
6638a51866fSRoland Dreier 						 IB_QP_MIN_RNR_TIMER		|
6648a51866fSRoland Dreier 						 IB_QP_PATH_MIG_STATE),
665b42b63cfSSean Hefty 				 [IB_QPT_XRC_INI] = (IB_QP_CUR_STATE		|
666b42b63cfSSean Hefty 						 IB_QP_ALT_PATH			|
667b42b63cfSSean Hefty 						 IB_QP_ACCESS_FLAGS		|
668b42b63cfSSean Hefty 						 IB_QP_PATH_MIG_STATE),
669b42b63cfSSean Hefty 				 [IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE		|
670b42b63cfSSean Hefty 						 IB_QP_ALT_PATH			|
671b42b63cfSSean Hefty 						 IB_QP_ACCESS_FLAGS		|
672b42b63cfSSean Hefty 						 IB_QP_MIN_RNR_TIMER		|
673b42b63cfSSean Hefty 						 IB_QP_PATH_MIG_STATE),
6748a51866fSRoland Dreier 				 [IB_QPT_SMI] = (IB_QP_CUR_STATE		|
6758a51866fSRoland Dreier 						 IB_QP_QKEY),
6768a51866fSRoland Dreier 				 [IB_QPT_GSI] = (IB_QP_CUR_STATE		|
6778a51866fSRoland Dreier 						 IB_QP_QKEY),
6788a51866fSRoland Dreier 			 }
6798a51866fSRoland Dreier 		}
6808a51866fSRoland Dreier 	},
6818a51866fSRoland Dreier 	[IB_QPS_RTS]   = {
6828a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
6838a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
6848a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
6858a51866fSRoland Dreier 			.valid = 1,
6868a51866fSRoland Dreier 			.opt_param = {
6878a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
6888a51866fSRoland Dreier 						IB_QP_QKEY),
6894546d31dSDotan Barak 				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
6904546d31dSDotan Barak 						IB_QP_ACCESS_FLAGS		|
6918a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
6928a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
6934546d31dSDotan Barak 				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
6944546d31dSDotan Barak 						IB_QP_ACCESS_FLAGS		|
6958a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
6968a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE		|
6978a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER),
698b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_CUR_STATE		|
699b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
700b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
701b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
702b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE		|
703b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
704b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
705b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE		|
706b42b63cfSSean Hefty 						IB_QP_MIN_RNR_TIMER),
7078a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
7088a51866fSRoland Dreier 						IB_QP_QKEY),
7098a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
7108a51866fSRoland Dreier 						IB_QP_QKEY),
7118a51866fSRoland Dreier 			}
7128a51866fSRoland Dreier 		},
7138a51866fSRoland Dreier 		[IB_QPS_SQD]   = {
7148a51866fSRoland Dreier 			.valid = 1,
7158a51866fSRoland Dreier 			.opt_param = {
7168a51866fSRoland Dreier 				[IB_QPT_UD]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
7178a51866fSRoland Dreier 				[IB_QPT_UC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
7188a51866fSRoland Dreier 				[IB_QPT_RC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
719b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
720b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = IB_QP_EN_SQD_ASYNC_NOTIFY, /* ??? */
7218a51866fSRoland Dreier 				[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
7228a51866fSRoland Dreier 				[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
7238a51866fSRoland Dreier 			}
7248a51866fSRoland Dreier 		},
7258a51866fSRoland Dreier 	},
7268a51866fSRoland Dreier 	[IB_QPS_SQD]   = {
7278a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
7288a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
7298a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
7308a51866fSRoland Dreier 			.valid = 1,
7318a51866fSRoland Dreier 			.opt_param = {
7328a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
7338a51866fSRoland Dreier 						IB_QP_QKEY),
7348a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
7358a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
7368a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
7378a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
7388a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
7398a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
7408a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
7418a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER		|
7428a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
743b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_CUR_STATE		|
744b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
745b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
746b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
747b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE		|
748b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
749b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
750b42b63cfSSean Hefty 						IB_QP_MIN_RNR_TIMER		|
751b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
7528a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
7538a51866fSRoland Dreier 						IB_QP_QKEY),
7548a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
7558a51866fSRoland Dreier 						IB_QP_QKEY),
7568a51866fSRoland Dreier 			}
7578a51866fSRoland Dreier 		},
7588a51866fSRoland Dreier 		[IB_QPS_SQD]   = {
7598a51866fSRoland Dreier 			.valid = 1,
7608a51866fSRoland Dreier 			.opt_param = {
7618a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
7628a51866fSRoland Dreier 						IB_QP_QKEY),
7638a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_AV			|
7648a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
7658a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
7668a51866fSRoland Dreier 						IB_QP_PKEY_INDEX		|
7678a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
7688a51866fSRoland Dreier 				[IB_QPT_RC]  = (IB_QP_PORT			|
7698a51866fSRoland Dreier 						IB_QP_AV			|
7708a51866fSRoland Dreier 						IB_QP_TIMEOUT			|
7718a51866fSRoland Dreier 						IB_QP_RETRY_CNT			|
7728a51866fSRoland Dreier 						IB_QP_RNR_RETRY			|
7738a51866fSRoland Dreier 						IB_QP_MAX_QP_RD_ATOMIC		|
7748a51866fSRoland Dreier 						IB_QP_MAX_DEST_RD_ATOMIC	|
7758a51866fSRoland Dreier 						IB_QP_ALT_PATH			|
7768a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS		|
7778a51866fSRoland Dreier 						IB_QP_PKEY_INDEX		|
7788a51866fSRoland Dreier 						IB_QP_MIN_RNR_TIMER		|
7798a51866fSRoland Dreier 						IB_QP_PATH_MIG_STATE),
780b42b63cfSSean Hefty 				[IB_QPT_XRC_INI] = (IB_QP_PORT			|
781b42b63cfSSean Hefty 						IB_QP_AV			|
782b42b63cfSSean Hefty 						IB_QP_TIMEOUT			|
783b42b63cfSSean Hefty 						IB_QP_RETRY_CNT			|
784b42b63cfSSean Hefty 						IB_QP_RNR_RETRY			|
785b42b63cfSSean Hefty 						IB_QP_MAX_QP_RD_ATOMIC		|
786b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
787b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
788b42b63cfSSean Hefty 						IB_QP_PKEY_INDEX		|
789b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
790b42b63cfSSean Hefty 				[IB_QPT_XRC_TGT] = (IB_QP_PORT			|
791b42b63cfSSean Hefty 						IB_QP_AV			|
792b42b63cfSSean Hefty 						IB_QP_TIMEOUT			|
793b42b63cfSSean Hefty 						IB_QP_MAX_DEST_RD_ATOMIC	|
794b42b63cfSSean Hefty 						IB_QP_ALT_PATH			|
795b42b63cfSSean Hefty 						IB_QP_ACCESS_FLAGS		|
796b42b63cfSSean Hefty 						IB_QP_PKEY_INDEX		|
797b42b63cfSSean Hefty 						IB_QP_MIN_RNR_TIMER		|
798b42b63cfSSean Hefty 						IB_QP_PATH_MIG_STATE),
7998a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
8008a51866fSRoland Dreier 						IB_QP_QKEY),
8018a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
8028a51866fSRoland Dreier 						IB_QP_QKEY),
8038a51866fSRoland Dreier 			}
8048a51866fSRoland Dreier 		}
8058a51866fSRoland Dreier 	},
8068a51866fSRoland Dreier 	[IB_QPS_SQE]   = {
8078a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
8088a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 },
8098a51866fSRoland Dreier 		[IB_QPS_RTS]   = {
8108a51866fSRoland Dreier 			.valid = 1,
8118a51866fSRoland Dreier 			.opt_param = {
8128a51866fSRoland Dreier 				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
8138a51866fSRoland Dreier 						IB_QP_QKEY),
8148a51866fSRoland Dreier 				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
8158a51866fSRoland Dreier 						IB_QP_ACCESS_FLAGS),
8168a51866fSRoland Dreier 				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
8178a51866fSRoland Dreier 						IB_QP_QKEY),
8188a51866fSRoland Dreier 				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
8198a51866fSRoland Dreier 						IB_QP_QKEY),
8208a51866fSRoland Dreier 			}
8218a51866fSRoland Dreier 		}
8228a51866fSRoland Dreier 	},
8238a51866fSRoland Dreier 	[IB_QPS_ERR] = {
8248a51866fSRoland Dreier 		[IB_QPS_RESET] = { .valid = 1 },
8258a51866fSRoland Dreier 		[IB_QPS_ERR] =   { .valid = 1 }
8268a51866fSRoland Dreier 	}
8278a51866fSRoland Dreier };
8288a51866fSRoland Dreier 
8298a51866fSRoland Dreier int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
830dd5f03beSMatan Barak 		       enum ib_qp_type type, enum ib_qp_attr_mask mask,
831dd5f03beSMatan Barak 		       enum rdma_link_layer ll)
8328a51866fSRoland Dreier {
8338a51866fSRoland Dreier 	enum ib_qp_attr_mask req_param, opt_param;
8348a51866fSRoland Dreier 
8358a51866fSRoland Dreier 	if (cur_state  < 0 || cur_state  > IB_QPS_ERR ||
8368a51866fSRoland Dreier 	    next_state < 0 || next_state > IB_QPS_ERR)
8378a51866fSRoland Dreier 		return 0;
8388a51866fSRoland Dreier 
8398a51866fSRoland Dreier 	if (mask & IB_QP_CUR_STATE  &&
8408a51866fSRoland Dreier 	    cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
8418a51866fSRoland Dreier 	    cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE)
8428a51866fSRoland Dreier 		return 0;
8438a51866fSRoland Dreier 
8448a51866fSRoland Dreier 	if (!qp_state_table[cur_state][next_state].valid)
8458a51866fSRoland Dreier 		return 0;
8468a51866fSRoland Dreier 
8478a51866fSRoland Dreier 	req_param = qp_state_table[cur_state][next_state].req_param[type];
8488a51866fSRoland Dreier 	opt_param = qp_state_table[cur_state][next_state].opt_param[type];
8498a51866fSRoland Dreier 
850dd5f03beSMatan Barak 	if (ll == IB_LINK_LAYER_ETHERNET) {
851dd5f03beSMatan Barak 		req_param |= qp_state_table[cur_state][next_state].
852dd5f03beSMatan Barak 			req_param_add_eth[type];
853dd5f03beSMatan Barak 		opt_param |= qp_state_table[cur_state][next_state].
854dd5f03beSMatan Barak 			opt_param_add_eth[type];
855dd5f03beSMatan Barak 	}
856dd5f03beSMatan Barak 
8578a51866fSRoland Dreier 	if ((mask & req_param) != req_param)
8588a51866fSRoland Dreier 		return 0;
8598a51866fSRoland Dreier 
8608a51866fSRoland Dreier 	if (mask & ~(req_param | opt_param | IB_QP_STATE))
8618a51866fSRoland Dreier 		return 0;
8628a51866fSRoland Dreier 
8638a51866fSRoland Dreier 	return 1;
8648a51866fSRoland Dreier }
8658a51866fSRoland Dreier EXPORT_SYMBOL(ib_modify_qp_is_ok);
8668a51866fSRoland Dreier 
867ed4c54e5SOr Gerlitz int ib_resolve_eth_l2_attrs(struct ib_qp *qp,
868ed4c54e5SOr Gerlitz 			    struct ib_qp_attr *qp_attr, int *qp_attr_mask)
869ed4c54e5SOr Gerlitz {
870ed4c54e5SOr Gerlitz 	int           ret = 0;
871ed4c54e5SOr Gerlitz 	union ib_gid  sgid;
872ed4c54e5SOr Gerlitz 
873ed4c54e5SOr Gerlitz 	if ((*qp_attr_mask & IB_QP_AV)  &&
874ed4c54e5SOr Gerlitz 	    (rdma_port_get_link_layer(qp->device, qp_attr->ah_attr.port_num) == IB_LINK_LAYER_ETHERNET)) {
875ed4c54e5SOr Gerlitz 		ret = ib_query_gid(qp->device, qp_attr->ah_attr.port_num,
876ed4c54e5SOr Gerlitz 				   qp_attr->ah_attr.grh.sgid_index, &sgid);
877ed4c54e5SOr Gerlitz 		if (ret)
878ed4c54e5SOr Gerlitz 			goto out;
879ed4c54e5SOr Gerlitz 		if (rdma_link_local_addr((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw)) {
880ed4c54e5SOr Gerlitz 			rdma_get_ll_mac((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw, qp_attr->ah_attr.dmac);
881ed4c54e5SOr Gerlitz 			rdma_get_ll_mac((struct in6_addr *)sgid.raw, qp_attr->smac);
882c1bd6cdeSMoni Shoua 			if (!(*qp_attr_mask & IB_QP_VID))
883ed4c54e5SOr Gerlitz 				qp_attr->vlan_id = rdma_get_vlan_id(&sgid);
884ed4c54e5SOr Gerlitz 		} else {
885ed4c54e5SOr Gerlitz 			ret = rdma_addr_find_dmac_by_grh(&sgid, &qp_attr->ah_attr.grh.dgid,
886ed4c54e5SOr Gerlitz 					qp_attr->ah_attr.dmac, &qp_attr->vlan_id);
887ed4c54e5SOr Gerlitz 			if (ret)
888ed4c54e5SOr Gerlitz 				goto out;
889ed4c54e5SOr Gerlitz 			ret = rdma_addr_find_smac_by_sgid(&sgid, qp_attr->smac, NULL);
890ed4c54e5SOr Gerlitz 			if (ret)
891ed4c54e5SOr Gerlitz 				goto out;
892ed4c54e5SOr Gerlitz 		}
893ed4c54e5SOr Gerlitz 		*qp_attr_mask |= IB_QP_SMAC;
894ed4c54e5SOr Gerlitz 		if (qp_attr->vlan_id < 0xFFFF)
895ed4c54e5SOr Gerlitz 			*qp_attr_mask |= IB_QP_VID;
896ed4c54e5SOr Gerlitz 	}
897ed4c54e5SOr Gerlitz out:
898ed4c54e5SOr Gerlitz 	return ret;
899ed4c54e5SOr Gerlitz }
900ed4c54e5SOr Gerlitz EXPORT_SYMBOL(ib_resolve_eth_l2_attrs);
901ed4c54e5SOr Gerlitz 
902ed4c54e5SOr Gerlitz 
9031da177e4SLinus Torvalds int ib_modify_qp(struct ib_qp *qp,
9041da177e4SLinus Torvalds 		 struct ib_qp_attr *qp_attr,
9051da177e4SLinus Torvalds 		 int qp_attr_mask)
9061da177e4SLinus Torvalds {
907ed4c54e5SOr Gerlitz 	int ret;
908ed4c54e5SOr Gerlitz 
909ed4c54e5SOr Gerlitz 	ret = ib_resolve_eth_l2_attrs(qp, qp_attr, &qp_attr_mask);
910ed4c54e5SOr Gerlitz 	if (ret)
911ed4c54e5SOr Gerlitz 		return ret;
912ed4c54e5SOr Gerlitz 
9130e0ec7e0SSean Hefty 	return qp->device->modify_qp(qp->real_qp, qp_attr, qp_attr_mask, NULL);
9141da177e4SLinus Torvalds }
9151da177e4SLinus Torvalds EXPORT_SYMBOL(ib_modify_qp);
9161da177e4SLinus Torvalds 
9171da177e4SLinus Torvalds int ib_query_qp(struct ib_qp *qp,
9181da177e4SLinus Torvalds 		struct ib_qp_attr *qp_attr,
9191da177e4SLinus Torvalds 		int qp_attr_mask,
9201da177e4SLinus Torvalds 		struct ib_qp_init_attr *qp_init_attr)
9211da177e4SLinus Torvalds {
9221da177e4SLinus Torvalds 	return qp->device->query_qp ?
9230e0ec7e0SSean Hefty 		qp->device->query_qp(qp->real_qp, qp_attr, qp_attr_mask, qp_init_attr) :
9241da177e4SLinus Torvalds 		-ENOSYS;
9251da177e4SLinus Torvalds }
9261da177e4SLinus Torvalds EXPORT_SYMBOL(ib_query_qp);
9271da177e4SLinus Torvalds 
9280e0ec7e0SSean Hefty int ib_close_qp(struct ib_qp *qp)
9290e0ec7e0SSean Hefty {
9300e0ec7e0SSean Hefty 	struct ib_qp *real_qp;
9310e0ec7e0SSean Hefty 	unsigned long flags;
9320e0ec7e0SSean Hefty 
9330e0ec7e0SSean Hefty 	real_qp = qp->real_qp;
9340e0ec7e0SSean Hefty 	if (real_qp == qp)
9350e0ec7e0SSean Hefty 		return -EINVAL;
9360e0ec7e0SSean Hefty 
9370e0ec7e0SSean Hefty 	spin_lock_irqsave(&real_qp->device->event_handler_lock, flags);
9380e0ec7e0SSean Hefty 	list_del(&qp->open_list);
9390e0ec7e0SSean Hefty 	spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags);
9400e0ec7e0SSean Hefty 
9410e0ec7e0SSean Hefty 	atomic_dec(&real_qp->usecnt);
9420e0ec7e0SSean Hefty 	kfree(qp);
9430e0ec7e0SSean Hefty 
9440e0ec7e0SSean Hefty 	return 0;
9450e0ec7e0SSean Hefty }
9460e0ec7e0SSean Hefty EXPORT_SYMBOL(ib_close_qp);
9470e0ec7e0SSean Hefty 
9480e0ec7e0SSean Hefty static int __ib_destroy_shared_qp(struct ib_qp *qp)
9490e0ec7e0SSean Hefty {
9500e0ec7e0SSean Hefty 	struct ib_xrcd *xrcd;
9510e0ec7e0SSean Hefty 	struct ib_qp *real_qp;
9520e0ec7e0SSean Hefty 	int ret;
9530e0ec7e0SSean Hefty 
9540e0ec7e0SSean Hefty 	real_qp = qp->real_qp;
9550e0ec7e0SSean Hefty 	xrcd = real_qp->xrcd;
9560e0ec7e0SSean Hefty 
9570e0ec7e0SSean Hefty 	mutex_lock(&xrcd->tgt_qp_mutex);
9580e0ec7e0SSean Hefty 	ib_close_qp(qp);
9590e0ec7e0SSean Hefty 	if (atomic_read(&real_qp->usecnt) == 0)
9600e0ec7e0SSean Hefty 		list_del(&real_qp->xrcd_list);
9610e0ec7e0SSean Hefty 	else
9620e0ec7e0SSean Hefty 		real_qp = NULL;
9630e0ec7e0SSean Hefty 	mutex_unlock(&xrcd->tgt_qp_mutex);
9640e0ec7e0SSean Hefty 
9650e0ec7e0SSean Hefty 	if (real_qp) {
9660e0ec7e0SSean Hefty 		ret = ib_destroy_qp(real_qp);
9670e0ec7e0SSean Hefty 		if (!ret)
9680e0ec7e0SSean Hefty 			atomic_dec(&xrcd->usecnt);
9690e0ec7e0SSean Hefty 		else
9700e0ec7e0SSean Hefty 			__ib_insert_xrcd_qp(xrcd, real_qp);
9710e0ec7e0SSean Hefty 	}
9720e0ec7e0SSean Hefty 
9730e0ec7e0SSean Hefty 	return 0;
9740e0ec7e0SSean Hefty }
9750e0ec7e0SSean Hefty 
9761da177e4SLinus Torvalds int ib_destroy_qp(struct ib_qp *qp)
9771da177e4SLinus Torvalds {
9781da177e4SLinus Torvalds 	struct ib_pd *pd;
9791da177e4SLinus Torvalds 	struct ib_cq *scq, *rcq;
9801da177e4SLinus Torvalds 	struct ib_srq *srq;
9811da177e4SLinus Torvalds 	int ret;
9821da177e4SLinus Torvalds 
9830e0ec7e0SSean Hefty 	if (atomic_read(&qp->usecnt))
9840e0ec7e0SSean Hefty 		return -EBUSY;
9850e0ec7e0SSean Hefty 
9860e0ec7e0SSean Hefty 	if (qp->real_qp != qp)
9870e0ec7e0SSean Hefty 		return __ib_destroy_shared_qp(qp);
9880e0ec7e0SSean Hefty 
9891da177e4SLinus Torvalds 	pd   = qp->pd;
9901da177e4SLinus Torvalds 	scq  = qp->send_cq;
9911da177e4SLinus Torvalds 	rcq  = qp->recv_cq;
9921da177e4SLinus Torvalds 	srq  = qp->srq;
9931da177e4SLinus Torvalds 
9941da177e4SLinus Torvalds 	ret = qp->device->destroy_qp(qp);
9951da177e4SLinus Torvalds 	if (!ret) {
996b42b63cfSSean Hefty 		if (pd)
9971da177e4SLinus Torvalds 			atomic_dec(&pd->usecnt);
998b42b63cfSSean Hefty 		if (scq)
9991da177e4SLinus Torvalds 			atomic_dec(&scq->usecnt);
1000b42b63cfSSean Hefty 		if (rcq)
10011da177e4SLinus Torvalds 			atomic_dec(&rcq->usecnt);
10021da177e4SLinus Torvalds 		if (srq)
10031da177e4SLinus Torvalds 			atomic_dec(&srq->usecnt);
10041da177e4SLinus Torvalds 	}
10051da177e4SLinus Torvalds 
10061da177e4SLinus Torvalds 	return ret;
10071da177e4SLinus Torvalds }
10081da177e4SLinus Torvalds EXPORT_SYMBOL(ib_destroy_qp);
10091da177e4SLinus Torvalds 
10101da177e4SLinus Torvalds /* Completion queues */
10111da177e4SLinus Torvalds 
10121da177e4SLinus Torvalds struct ib_cq *ib_create_cq(struct ib_device *device,
10131da177e4SLinus Torvalds 			   ib_comp_handler comp_handler,
10141da177e4SLinus Torvalds 			   void (*event_handler)(struct ib_event *, void *),
1015f4fd0b22SMichael S. Tsirkin 			   void *cq_context, int cqe, int comp_vector)
10161da177e4SLinus Torvalds {
10171da177e4SLinus Torvalds 	struct ib_cq *cq;
10181da177e4SLinus Torvalds 
1019f4fd0b22SMichael S. Tsirkin 	cq = device->create_cq(device, cqe, comp_vector, NULL, NULL);
10201da177e4SLinus Torvalds 
10211da177e4SLinus Torvalds 	if (!IS_ERR(cq)) {
10221da177e4SLinus Torvalds 		cq->device        = device;
1023b5e81bf5SRoland Dreier 		cq->uobject       = NULL;
10241da177e4SLinus Torvalds 		cq->comp_handler  = comp_handler;
10251da177e4SLinus Torvalds 		cq->event_handler = event_handler;
10261da177e4SLinus Torvalds 		cq->cq_context    = cq_context;
10271da177e4SLinus Torvalds 		atomic_set(&cq->usecnt, 0);
10281da177e4SLinus Torvalds 	}
10291da177e4SLinus Torvalds 
10301da177e4SLinus Torvalds 	return cq;
10311da177e4SLinus Torvalds }
10321da177e4SLinus Torvalds EXPORT_SYMBOL(ib_create_cq);
10331da177e4SLinus Torvalds 
10342dd57162SEli Cohen int ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
10352dd57162SEli Cohen {
10362dd57162SEli Cohen 	return cq->device->modify_cq ?
10372dd57162SEli Cohen 		cq->device->modify_cq(cq, cq_count, cq_period) : -ENOSYS;
10382dd57162SEli Cohen }
10392dd57162SEli Cohen EXPORT_SYMBOL(ib_modify_cq);
10402dd57162SEli Cohen 
10411da177e4SLinus Torvalds int ib_destroy_cq(struct ib_cq *cq)
10421da177e4SLinus Torvalds {
10431da177e4SLinus Torvalds 	if (atomic_read(&cq->usecnt))
10441da177e4SLinus Torvalds 		return -EBUSY;
10451da177e4SLinus Torvalds 
10461da177e4SLinus Torvalds 	return cq->device->destroy_cq(cq);
10471da177e4SLinus Torvalds }
10481da177e4SLinus Torvalds EXPORT_SYMBOL(ib_destroy_cq);
10491da177e4SLinus Torvalds 
1050a74cd4afSRoland Dreier int ib_resize_cq(struct ib_cq *cq, int cqe)
10511da177e4SLinus Torvalds {
105240de2e54SRoland Dreier 	return cq->device->resize_cq ?
105333b9b3eeSRoland Dreier 		cq->device->resize_cq(cq, cqe, NULL) : -ENOSYS;
10541da177e4SLinus Torvalds }
10551da177e4SLinus Torvalds EXPORT_SYMBOL(ib_resize_cq);
10561da177e4SLinus Torvalds 
10571da177e4SLinus Torvalds /* Memory regions */
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
10601da177e4SLinus Torvalds {
10611da177e4SLinus Torvalds 	struct ib_mr *mr;
10621c636f80SEli Cohen 	int err;
10631c636f80SEli Cohen 
10641c636f80SEli Cohen 	err = ib_check_mr_access(mr_access_flags);
10651c636f80SEli Cohen 	if (err)
10661c636f80SEli Cohen 		return ERR_PTR(err);
10671da177e4SLinus Torvalds 
10681da177e4SLinus Torvalds 	mr = pd->device->get_dma_mr(pd, mr_access_flags);
10691da177e4SLinus Torvalds 
10701da177e4SLinus Torvalds 	if (!IS_ERR(mr)) {
10711da177e4SLinus Torvalds 		mr->device  = pd->device;
10721da177e4SLinus Torvalds 		mr->pd      = pd;
1073b5e81bf5SRoland Dreier 		mr->uobject = NULL;
10741da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
10751da177e4SLinus Torvalds 		atomic_set(&mr->usecnt, 0);
10761da177e4SLinus Torvalds 	}
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds 	return mr;
10791da177e4SLinus Torvalds }
10801da177e4SLinus Torvalds EXPORT_SYMBOL(ib_get_dma_mr);
10811da177e4SLinus Torvalds 
10821da177e4SLinus Torvalds struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd,
10831da177e4SLinus Torvalds 			     struct ib_phys_buf *phys_buf_array,
10841da177e4SLinus Torvalds 			     int num_phys_buf,
10851da177e4SLinus Torvalds 			     int mr_access_flags,
10861da177e4SLinus Torvalds 			     u64 *iova_start)
10871da177e4SLinus Torvalds {
10881da177e4SLinus Torvalds 	struct ib_mr *mr;
10891c636f80SEli Cohen 	int err;
10901c636f80SEli Cohen 
10911c636f80SEli Cohen 	err = ib_check_mr_access(mr_access_flags);
10921c636f80SEli Cohen 	if (err)
10931c636f80SEli Cohen 		return ERR_PTR(err);
10941da177e4SLinus Torvalds 
10957ce5eacbSDotan Barak 	if (!pd->device->reg_phys_mr)
10967ce5eacbSDotan Barak 		return ERR_PTR(-ENOSYS);
10977ce5eacbSDotan Barak 
10981da177e4SLinus Torvalds 	mr = pd->device->reg_phys_mr(pd, phys_buf_array, num_phys_buf,
10991da177e4SLinus Torvalds 				     mr_access_flags, iova_start);
11001da177e4SLinus Torvalds 
11011da177e4SLinus Torvalds 	if (!IS_ERR(mr)) {
11021da177e4SLinus Torvalds 		mr->device  = pd->device;
11031da177e4SLinus Torvalds 		mr->pd      = pd;
1104b5e81bf5SRoland Dreier 		mr->uobject = NULL;
11051da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
11061da177e4SLinus Torvalds 		atomic_set(&mr->usecnt, 0);
11071da177e4SLinus Torvalds 	}
11081da177e4SLinus Torvalds 
11091da177e4SLinus Torvalds 	return mr;
11101da177e4SLinus Torvalds }
11111da177e4SLinus Torvalds EXPORT_SYMBOL(ib_reg_phys_mr);
11121da177e4SLinus Torvalds 
11131da177e4SLinus Torvalds int ib_rereg_phys_mr(struct ib_mr *mr,
11141da177e4SLinus Torvalds 		     int mr_rereg_mask,
11151da177e4SLinus Torvalds 		     struct ib_pd *pd,
11161da177e4SLinus Torvalds 		     struct ib_phys_buf *phys_buf_array,
11171da177e4SLinus Torvalds 		     int num_phys_buf,
11181da177e4SLinus Torvalds 		     int mr_access_flags,
11191da177e4SLinus Torvalds 		     u64 *iova_start)
11201da177e4SLinus Torvalds {
11211da177e4SLinus Torvalds 	struct ib_pd *old_pd;
11221da177e4SLinus Torvalds 	int ret;
11231da177e4SLinus Torvalds 
11241c636f80SEli Cohen 	ret = ib_check_mr_access(mr_access_flags);
11251c636f80SEli Cohen 	if (ret)
11261c636f80SEli Cohen 		return ret;
11271c636f80SEli Cohen 
11281da177e4SLinus Torvalds 	if (!mr->device->rereg_phys_mr)
11291da177e4SLinus Torvalds 		return -ENOSYS;
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds 	if (atomic_read(&mr->usecnt))
11321da177e4SLinus Torvalds 		return -EBUSY;
11331da177e4SLinus Torvalds 
11341da177e4SLinus Torvalds 	old_pd = mr->pd;
11351da177e4SLinus Torvalds 
11361da177e4SLinus Torvalds 	ret = mr->device->rereg_phys_mr(mr, mr_rereg_mask, pd,
11371da177e4SLinus Torvalds 					phys_buf_array, num_phys_buf,
11381da177e4SLinus Torvalds 					mr_access_flags, iova_start);
11391da177e4SLinus Torvalds 
11401da177e4SLinus Torvalds 	if (!ret && (mr_rereg_mask & IB_MR_REREG_PD)) {
11411da177e4SLinus Torvalds 		atomic_dec(&old_pd->usecnt);
11421da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
11431da177e4SLinus Torvalds 	}
11441da177e4SLinus Torvalds 
11451da177e4SLinus Torvalds 	return ret;
11461da177e4SLinus Torvalds }
11471da177e4SLinus Torvalds EXPORT_SYMBOL(ib_rereg_phys_mr);
11481da177e4SLinus Torvalds 
11491da177e4SLinus Torvalds int ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
11501da177e4SLinus Torvalds {
11511da177e4SLinus Torvalds 	return mr->device->query_mr ?
11521da177e4SLinus Torvalds 		mr->device->query_mr(mr, mr_attr) : -ENOSYS;
11531da177e4SLinus Torvalds }
11541da177e4SLinus Torvalds EXPORT_SYMBOL(ib_query_mr);
11551da177e4SLinus Torvalds 
11561da177e4SLinus Torvalds int ib_dereg_mr(struct ib_mr *mr)
11571da177e4SLinus Torvalds {
11581da177e4SLinus Torvalds 	struct ib_pd *pd;
11591da177e4SLinus Torvalds 	int ret;
11601da177e4SLinus Torvalds 
11611da177e4SLinus Torvalds 	if (atomic_read(&mr->usecnt))
11621da177e4SLinus Torvalds 		return -EBUSY;
11631da177e4SLinus Torvalds 
11641da177e4SLinus Torvalds 	pd = mr->pd;
11651da177e4SLinus Torvalds 	ret = mr->device->dereg_mr(mr);
11661da177e4SLinus Torvalds 	if (!ret)
11671da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
11681da177e4SLinus Torvalds 
11691da177e4SLinus Torvalds 	return ret;
11701da177e4SLinus Torvalds }
11711da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dereg_mr);
11721da177e4SLinus Torvalds 
117317cd3a2dSSagi Grimberg struct ib_mr *ib_create_mr(struct ib_pd *pd,
117417cd3a2dSSagi Grimberg 			   struct ib_mr_init_attr *mr_init_attr)
117517cd3a2dSSagi Grimberg {
117617cd3a2dSSagi Grimberg 	struct ib_mr *mr;
117717cd3a2dSSagi Grimberg 
117817cd3a2dSSagi Grimberg 	if (!pd->device->create_mr)
117917cd3a2dSSagi Grimberg 		return ERR_PTR(-ENOSYS);
118017cd3a2dSSagi Grimberg 
118117cd3a2dSSagi Grimberg 	mr = pd->device->create_mr(pd, mr_init_attr);
118217cd3a2dSSagi Grimberg 
118317cd3a2dSSagi Grimberg 	if (!IS_ERR(mr)) {
118417cd3a2dSSagi Grimberg 		mr->device  = pd->device;
118517cd3a2dSSagi Grimberg 		mr->pd      = pd;
118617cd3a2dSSagi Grimberg 		mr->uobject = NULL;
118717cd3a2dSSagi Grimberg 		atomic_inc(&pd->usecnt);
118817cd3a2dSSagi Grimberg 		atomic_set(&mr->usecnt, 0);
118917cd3a2dSSagi Grimberg 	}
119017cd3a2dSSagi Grimberg 
119117cd3a2dSSagi Grimberg 	return mr;
119217cd3a2dSSagi Grimberg }
119317cd3a2dSSagi Grimberg EXPORT_SYMBOL(ib_create_mr);
119417cd3a2dSSagi Grimberg 
119517cd3a2dSSagi Grimberg int ib_destroy_mr(struct ib_mr *mr)
119617cd3a2dSSagi Grimberg {
119717cd3a2dSSagi Grimberg 	struct ib_pd *pd;
119817cd3a2dSSagi Grimberg 	int ret;
119917cd3a2dSSagi Grimberg 
120017cd3a2dSSagi Grimberg 	if (atomic_read(&mr->usecnt))
120117cd3a2dSSagi Grimberg 		return -EBUSY;
120217cd3a2dSSagi Grimberg 
120317cd3a2dSSagi Grimberg 	pd = mr->pd;
120417cd3a2dSSagi Grimberg 	ret = mr->device->destroy_mr(mr);
120517cd3a2dSSagi Grimberg 	if (!ret)
120617cd3a2dSSagi Grimberg 		atomic_dec(&pd->usecnt);
120717cd3a2dSSagi Grimberg 
120817cd3a2dSSagi Grimberg 	return ret;
120917cd3a2dSSagi Grimberg }
121017cd3a2dSSagi Grimberg EXPORT_SYMBOL(ib_destroy_mr);
121117cd3a2dSSagi Grimberg 
121200f7ec36SSteve Wise struct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len)
121300f7ec36SSteve Wise {
121400f7ec36SSteve Wise 	struct ib_mr *mr;
121500f7ec36SSteve Wise 
121600f7ec36SSteve Wise 	if (!pd->device->alloc_fast_reg_mr)
121700f7ec36SSteve Wise 		return ERR_PTR(-ENOSYS);
121800f7ec36SSteve Wise 
121900f7ec36SSteve Wise 	mr = pd->device->alloc_fast_reg_mr(pd, max_page_list_len);
122000f7ec36SSteve Wise 
122100f7ec36SSteve Wise 	if (!IS_ERR(mr)) {
122200f7ec36SSteve Wise 		mr->device  = pd->device;
122300f7ec36SSteve Wise 		mr->pd      = pd;
122400f7ec36SSteve Wise 		mr->uobject = NULL;
122500f7ec36SSteve Wise 		atomic_inc(&pd->usecnt);
122600f7ec36SSteve Wise 		atomic_set(&mr->usecnt, 0);
122700f7ec36SSteve Wise 	}
122800f7ec36SSteve Wise 
122900f7ec36SSteve Wise 	return mr;
123000f7ec36SSteve Wise }
123100f7ec36SSteve Wise EXPORT_SYMBOL(ib_alloc_fast_reg_mr);
123200f7ec36SSteve Wise 
123300f7ec36SSteve Wise struct ib_fast_reg_page_list *ib_alloc_fast_reg_page_list(struct ib_device *device,
123400f7ec36SSteve Wise 							  int max_page_list_len)
123500f7ec36SSteve Wise {
123600f7ec36SSteve Wise 	struct ib_fast_reg_page_list *page_list;
123700f7ec36SSteve Wise 
123800f7ec36SSteve Wise 	if (!device->alloc_fast_reg_page_list)
123900f7ec36SSteve Wise 		return ERR_PTR(-ENOSYS);
124000f7ec36SSteve Wise 
124100f7ec36SSteve Wise 	page_list = device->alloc_fast_reg_page_list(device, max_page_list_len);
124200f7ec36SSteve Wise 
124300f7ec36SSteve Wise 	if (!IS_ERR(page_list)) {
124400f7ec36SSteve Wise 		page_list->device = device;
124500f7ec36SSteve Wise 		page_list->max_page_list_len = max_page_list_len;
124600f7ec36SSteve Wise 	}
124700f7ec36SSteve Wise 
124800f7ec36SSteve Wise 	return page_list;
124900f7ec36SSteve Wise }
125000f7ec36SSteve Wise EXPORT_SYMBOL(ib_alloc_fast_reg_page_list);
125100f7ec36SSteve Wise 
125200f7ec36SSteve Wise void ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list)
125300f7ec36SSteve Wise {
125400f7ec36SSteve Wise 	page_list->device->free_fast_reg_page_list(page_list);
125500f7ec36SSteve Wise }
125600f7ec36SSteve Wise EXPORT_SYMBOL(ib_free_fast_reg_page_list);
125700f7ec36SSteve Wise 
12581da177e4SLinus Torvalds /* Memory windows */
12591da177e4SLinus Torvalds 
12607083e42eSShani Michaeli struct ib_mw *ib_alloc_mw(struct ib_pd *pd, enum ib_mw_type type)
12611da177e4SLinus Torvalds {
12621da177e4SLinus Torvalds 	struct ib_mw *mw;
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds 	if (!pd->device->alloc_mw)
12651da177e4SLinus Torvalds 		return ERR_PTR(-ENOSYS);
12661da177e4SLinus Torvalds 
12677083e42eSShani Michaeli 	mw = pd->device->alloc_mw(pd, type);
12681da177e4SLinus Torvalds 	if (!IS_ERR(mw)) {
12691da177e4SLinus Torvalds 		mw->device  = pd->device;
12701da177e4SLinus Torvalds 		mw->pd      = pd;
1271b5e81bf5SRoland Dreier 		mw->uobject = NULL;
12727083e42eSShani Michaeli 		mw->type    = type;
12731da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
12741da177e4SLinus Torvalds 	}
12751da177e4SLinus Torvalds 
12761da177e4SLinus Torvalds 	return mw;
12771da177e4SLinus Torvalds }
12781da177e4SLinus Torvalds EXPORT_SYMBOL(ib_alloc_mw);
12791da177e4SLinus Torvalds 
12801da177e4SLinus Torvalds int ib_dealloc_mw(struct ib_mw *mw)
12811da177e4SLinus Torvalds {
12821da177e4SLinus Torvalds 	struct ib_pd *pd;
12831da177e4SLinus Torvalds 	int ret;
12841da177e4SLinus Torvalds 
12851da177e4SLinus Torvalds 	pd = mw->pd;
12861da177e4SLinus Torvalds 	ret = mw->device->dealloc_mw(mw);
12871da177e4SLinus Torvalds 	if (!ret)
12881da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
12891da177e4SLinus Torvalds 
12901da177e4SLinus Torvalds 	return ret;
12911da177e4SLinus Torvalds }
12921da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dealloc_mw);
12931da177e4SLinus Torvalds 
12941da177e4SLinus Torvalds /* "Fast" memory regions */
12951da177e4SLinus Torvalds 
12961da177e4SLinus Torvalds struct ib_fmr *ib_alloc_fmr(struct ib_pd *pd,
12971da177e4SLinus Torvalds 			    int mr_access_flags,
12981da177e4SLinus Torvalds 			    struct ib_fmr_attr *fmr_attr)
12991da177e4SLinus Torvalds {
13001da177e4SLinus Torvalds 	struct ib_fmr *fmr;
13011da177e4SLinus Torvalds 
13021da177e4SLinus Torvalds 	if (!pd->device->alloc_fmr)
13031da177e4SLinus Torvalds 		return ERR_PTR(-ENOSYS);
13041da177e4SLinus Torvalds 
13051da177e4SLinus Torvalds 	fmr = pd->device->alloc_fmr(pd, mr_access_flags, fmr_attr);
13061da177e4SLinus Torvalds 	if (!IS_ERR(fmr)) {
13071da177e4SLinus Torvalds 		fmr->device = pd->device;
13081da177e4SLinus Torvalds 		fmr->pd     = pd;
13091da177e4SLinus Torvalds 		atomic_inc(&pd->usecnt);
13101da177e4SLinus Torvalds 	}
13111da177e4SLinus Torvalds 
13121da177e4SLinus Torvalds 	return fmr;
13131da177e4SLinus Torvalds }
13141da177e4SLinus Torvalds EXPORT_SYMBOL(ib_alloc_fmr);
13151da177e4SLinus Torvalds 
13161da177e4SLinus Torvalds int ib_unmap_fmr(struct list_head *fmr_list)
13171da177e4SLinus Torvalds {
13181da177e4SLinus Torvalds 	struct ib_fmr *fmr;
13191da177e4SLinus Torvalds 
13201da177e4SLinus Torvalds 	if (list_empty(fmr_list))
13211da177e4SLinus Torvalds 		return 0;
13221da177e4SLinus Torvalds 
13231da177e4SLinus Torvalds 	fmr = list_entry(fmr_list->next, struct ib_fmr, list);
13241da177e4SLinus Torvalds 	return fmr->device->unmap_fmr(fmr_list);
13251da177e4SLinus Torvalds }
13261da177e4SLinus Torvalds EXPORT_SYMBOL(ib_unmap_fmr);
13271da177e4SLinus Torvalds 
13281da177e4SLinus Torvalds int ib_dealloc_fmr(struct ib_fmr *fmr)
13291da177e4SLinus Torvalds {
13301da177e4SLinus Torvalds 	struct ib_pd *pd;
13311da177e4SLinus Torvalds 	int ret;
13321da177e4SLinus Torvalds 
13331da177e4SLinus Torvalds 	pd = fmr->pd;
13341da177e4SLinus Torvalds 	ret = fmr->device->dealloc_fmr(fmr);
13351da177e4SLinus Torvalds 	if (!ret)
13361da177e4SLinus Torvalds 		atomic_dec(&pd->usecnt);
13371da177e4SLinus Torvalds 
13381da177e4SLinus Torvalds 	return ret;
13391da177e4SLinus Torvalds }
13401da177e4SLinus Torvalds EXPORT_SYMBOL(ib_dealloc_fmr);
13411da177e4SLinus Torvalds 
13421da177e4SLinus Torvalds /* Multicast groups */
13431da177e4SLinus Torvalds 
13441da177e4SLinus Torvalds int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
13451da177e4SLinus Torvalds {
1346c3bccbfbSOr Gerlitz 	int ret;
1347c3bccbfbSOr Gerlitz 
13480c33aeedSJack Morgenstein 	if (!qp->device->attach_mcast)
13490c33aeedSJack Morgenstein 		return -ENOSYS;
13500c33aeedSJack Morgenstein 	if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
13510c33aeedSJack Morgenstein 		return -EINVAL;
13520c33aeedSJack Morgenstein 
1353c3bccbfbSOr Gerlitz 	ret = qp->device->attach_mcast(qp, gid, lid);
1354c3bccbfbSOr Gerlitz 	if (!ret)
1355c3bccbfbSOr Gerlitz 		atomic_inc(&qp->usecnt);
1356c3bccbfbSOr Gerlitz 	return ret;
13571da177e4SLinus Torvalds }
13581da177e4SLinus Torvalds EXPORT_SYMBOL(ib_attach_mcast);
13591da177e4SLinus Torvalds 
13601da177e4SLinus Torvalds int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
13611da177e4SLinus Torvalds {
1362c3bccbfbSOr Gerlitz 	int ret;
1363c3bccbfbSOr Gerlitz 
13640c33aeedSJack Morgenstein 	if (!qp->device->detach_mcast)
13650c33aeedSJack Morgenstein 		return -ENOSYS;
13660c33aeedSJack Morgenstein 	if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
13670c33aeedSJack Morgenstein 		return -EINVAL;
13680c33aeedSJack Morgenstein 
1369c3bccbfbSOr Gerlitz 	ret = qp->device->detach_mcast(qp, gid, lid);
1370c3bccbfbSOr Gerlitz 	if (!ret)
1371c3bccbfbSOr Gerlitz 		atomic_dec(&qp->usecnt);
1372c3bccbfbSOr Gerlitz 	return ret;
13731da177e4SLinus Torvalds }
13741da177e4SLinus Torvalds EXPORT_SYMBOL(ib_detach_mcast);
137559991f94SSean Hefty 
137659991f94SSean Hefty struct ib_xrcd *ib_alloc_xrcd(struct ib_device *device)
137759991f94SSean Hefty {
137859991f94SSean Hefty 	struct ib_xrcd *xrcd;
137959991f94SSean Hefty 
138059991f94SSean Hefty 	if (!device->alloc_xrcd)
138159991f94SSean Hefty 		return ERR_PTR(-ENOSYS);
138259991f94SSean Hefty 
138359991f94SSean Hefty 	xrcd = device->alloc_xrcd(device, NULL, NULL);
138459991f94SSean Hefty 	if (!IS_ERR(xrcd)) {
138559991f94SSean Hefty 		xrcd->device = device;
138653d0bd1eSSean Hefty 		xrcd->inode = NULL;
138759991f94SSean Hefty 		atomic_set(&xrcd->usecnt, 0);
1388d3d72d90SSean Hefty 		mutex_init(&xrcd->tgt_qp_mutex);
1389d3d72d90SSean Hefty 		INIT_LIST_HEAD(&xrcd->tgt_qp_list);
139059991f94SSean Hefty 	}
139159991f94SSean Hefty 
139259991f94SSean Hefty 	return xrcd;
139359991f94SSean Hefty }
139459991f94SSean Hefty EXPORT_SYMBOL(ib_alloc_xrcd);
139559991f94SSean Hefty 
139659991f94SSean Hefty int ib_dealloc_xrcd(struct ib_xrcd *xrcd)
139759991f94SSean Hefty {
1398d3d72d90SSean Hefty 	struct ib_qp *qp;
1399d3d72d90SSean Hefty 	int ret;
1400d3d72d90SSean Hefty 
140159991f94SSean Hefty 	if (atomic_read(&xrcd->usecnt))
140259991f94SSean Hefty 		return -EBUSY;
140359991f94SSean Hefty 
1404d3d72d90SSean Hefty 	while (!list_empty(&xrcd->tgt_qp_list)) {
1405d3d72d90SSean Hefty 		qp = list_entry(xrcd->tgt_qp_list.next, struct ib_qp, xrcd_list);
1406d3d72d90SSean Hefty 		ret = ib_destroy_qp(qp);
1407d3d72d90SSean Hefty 		if (ret)
1408d3d72d90SSean Hefty 			return ret;
1409d3d72d90SSean Hefty 	}
1410d3d72d90SSean Hefty 
141159991f94SSean Hefty 	return xrcd->device->dealloc_xrcd(xrcd);
141259991f94SSean Hefty }
141359991f94SSean Hefty EXPORT_SYMBOL(ib_dealloc_xrcd);
1414319a441dSHadar Hen Zion 
1415319a441dSHadar Hen Zion struct ib_flow *ib_create_flow(struct ib_qp *qp,
1416319a441dSHadar Hen Zion 			       struct ib_flow_attr *flow_attr,
1417319a441dSHadar Hen Zion 			       int domain)
1418319a441dSHadar Hen Zion {
1419319a441dSHadar Hen Zion 	struct ib_flow *flow_id;
1420319a441dSHadar Hen Zion 	if (!qp->device->create_flow)
1421319a441dSHadar Hen Zion 		return ERR_PTR(-ENOSYS);
1422319a441dSHadar Hen Zion 
1423319a441dSHadar Hen Zion 	flow_id = qp->device->create_flow(qp, flow_attr, domain);
1424319a441dSHadar Hen Zion 	if (!IS_ERR(flow_id))
1425319a441dSHadar Hen Zion 		atomic_inc(&qp->usecnt);
1426319a441dSHadar Hen Zion 	return flow_id;
1427319a441dSHadar Hen Zion }
1428319a441dSHadar Hen Zion EXPORT_SYMBOL(ib_create_flow);
1429319a441dSHadar Hen Zion 
1430319a441dSHadar Hen Zion int ib_destroy_flow(struct ib_flow *flow_id)
1431319a441dSHadar Hen Zion {
1432319a441dSHadar Hen Zion 	int err;
1433319a441dSHadar Hen Zion 	struct ib_qp *qp = flow_id->qp;
1434319a441dSHadar Hen Zion 
1435319a441dSHadar Hen Zion 	err = qp->device->destroy_flow(flow_id);
1436319a441dSHadar Hen Zion 	if (!err)
1437319a441dSHadar Hen Zion 		atomic_dec(&qp->usecnt);
1438319a441dSHadar Hen Zion 	return err;
1439319a441dSHadar Hen Zion }
1440319a441dSHadar Hen Zion EXPORT_SYMBOL(ib_destroy_flow);
14411b01d335SSagi Grimberg 
14421b01d335SSagi Grimberg int ib_check_mr_status(struct ib_mr *mr, u32 check_mask,
14431b01d335SSagi Grimberg 		       struct ib_mr_status *mr_status)
14441b01d335SSagi Grimberg {
14451b01d335SSagi Grimberg 	return mr->device->check_mr_status ?
14461b01d335SSagi Grimberg 		mr->device->check_mr_status(mr, check_mask, mr_status) : -ENOSYS;
14471b01d335SSagi Grimberg }
14481b01d335SSagi Grimberg EXPORT_SYMBOL(ib_check_mr_status);
1449