1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004 Mellanox Technologies Ltd.  All rights reserved.
3219820Sjeff * Copyright (c) 2004 Infinicon Corporation.  All rights reserved.
4219820Sjeff * Copyright (c) 2004 Intel Corporation.  All rights reserved.
5219820Sjeff * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
6219820Sjeff * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
7219820Sjeff * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
8219820Sjeff * Copyright (c) 2005, 2006 Cisco Systems.  All rights reserved.
9219820Sjeff *
10219820Sjeff * This software is available to you under a choice of one of two
11219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
12219820Sjeff * General Public License (GPL) Version 2, available from the file
13219820Sjeff * COPYING in the main directory of this source tree, or the
14219820Sjeff * OpenIB.org BSD license below:
15219820Sjeff *
16219820Sjeff *     Redistribution and use in source and binary forms, with or
17219820Sjeff *     without modification, are permitted provided that the following
18219820Sjeff *     conditions are met:
19219820Sjeff *
20219820Sjeff *      - Redistributions of source code must retain the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer.
23219820Sjeff *
24219820Sjeff *      - Redistributions in binary form must reproduce the above
25219820Sjeff *        copyright notice, this list of conditions and the following
26219820Sjeff *        disclaimer in the documentation and/or other materials
27219820Sjeff *        provided with the distribution.
28219820Sjeff *
29219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
33219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
34219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
35219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36219820Sjeff * SOFTWARE.
37219820Sjeff */
38219820Sjeff
39219820Sjeff#include <linux/errno.h>
40219820Sjeff#include <linux/err.h>
41278886Shselasky#include <linux/module.h>
42219820Sjeff#include <linux/string.h>
43278886Shselasky#include <linux/slab.h>
44219820Sjeff
45219820Sjeff#include <rdma/ib_verbs.h>
46219820Sjeff#include <rdma/ib_cache.h>
47278886Shselasky#include <rdma/ib_addr.h>
48219820Sjeff
49219820Sjeffint ib_rate_to_mult(enum ib_rate rate)
50219820Sjeff{
51219820Sjeff	switch (rate) {
52219820Sjeff	case IB_RATE_2_5_GBPS: return  1;
53219820Sjeff	case IB_RATE_5_GBPS:   return  2;
54219820Sjeff	case IB_RATE_10_GBPS:  return  4;
55219820Sjeff	case IB_RATE_20_GBPS:  return  8;
56219820Sjeff	case IB_RATE_30_GBPS:  return 12;
57219820Sjeff	case IB_RATE_40_GBPS:  return 16;
58219820Sjeff	case IB_RATE_60_GBPS:  return 24;
59219820Sjeff	case IB_RATE_80_GBPS:  return 32;
60219820Sjeff	case IB_RATE_120_GBPS: return 48;
61219820Sjeff	default:	       return -1;
62219820Sjeff	}
63219820Sjeff}
64219820SjeffEXPORT_SYMBOL(ib_rate_to_mult);
65219820Sjeff
66219820Sjeffenum ib_rate mult_to_ib_rate(int mult)
67219820Sjeff{
68219820Sjeff	switch (mult) {
69219820Sjeff	case 1:  return IB_RATE_2_5_GBPS;
70219820Sjeff	case 2:  return IB_RATE_5_GBPS;
71219820Sjeff	case 4:  return IB_RATE_10_GBPS;
72219820Sjeff	case 8:  return IB_RATE_20_GBPS;
73219820Sjeff	case 12: return IB_RATE_30_GBPS;
74219820Sjeff	case 16: return IB_RATE_40_GBPS;
75219820Sjeff	case 24: return IB_RATE_60_GBPS;
76219820Sjeff	case 32: return IB_RATE_80_GBPS;
77219820Sjeff	case 48: return IB_RATE_120_GBPS;
78219820Sjeff	default: return IB_RATE_PORT_CURRENT;
79219820Sjeff	}
80219820Sjeff}
81219820SjeffEXPORT_SYMBOL(mult_to_ib_rate);
82219820Sjeff
83278886Shselaskyint ib_rate_to_mbps(enum ib_rate rate)
84278886Shselasky{
85278886Shselasky	switch (rate) {
86278886Shselasky	case IB_RATE_2_5_GBPS: return 2500;
87278886Shselasky	case IB_RATE_5_GBPS:   return 5000;
88278886Shselasky	case IB_RATE_10_GBPS:  return 10000;
89278886Shselasky	case IB_RATE_20_GBPS:  return 20000;
90278886Shselasky	case IB_RATE_30_GBPS:  return 30000;
91278886Shselasky	case IB_RATE_40_GBPS:  return 40000;
92278886Shselasky	case IB_RATE_60_GBPS:  return 60000;
93278886Shselasky	case IB_RATE_80_GBPS:  return 80000;
94278886Shselasky	case IB_RATE_120_GBPS: return 120000;
95278886Shselasky	case IB_RATE_14_GBPS:  return 14062;
96278886Shselasky	case IB_RATE_56_GBPS:  return 56250;
97278886Shselasky	case IB_RATE_112_GBPS: return 112500;
98278886Shselasky	case IB_RATE_168_GBPS: return 168750;
99278886Shselasky	case IB_RATE_25_GBPS:  return 25781;
100278886Shselasky	case IB_RATE_100_GBPS: return 103125;
101278886Shselasky	case IB_RATE_200_GBPS: return 206250;
102278886Shselasky	case IB_RATE_300_GBPS: return 309375;
103278886Shselasky	default:	       return -1;
104278886Shselasky	}
105278886Shselasky}
106278886ShselaskyEXPORT_SYMBOL(ib_rate_to_mbps);
107278886Shselasky
108219820Sjeffenum rdma_transport_type
109219820Sjeffrdma_node_get_transport(enum rdma_node_type node_type)
110219820Sjeff{
111219820Sjeff	switch (node_type) {
112219820Sjeff	case RDMA_NODE_IB_CA:
113219820Sjeff	case RDMA_NODE_IB_SWITCH:
114219820Sjeff	case RDMA_NODE_IB_ROUTER:
115219820Sjeff		return RDMA_TRANSPORT_IB;
116219820Sjeff	case RDMA_NODE_RNIC:
117219820Sjeff		return RDMA_TRANSPORT_IWARP;
118278886Shselasky	case RDMA_NODE_MIC:
119278886Shselasky		return RDMA_TRANSPORT_SCIF;
120219820Sjeff	default:
121219820Sjeff		BUG();
122219820Sjeff		return 0;
123219820Sjeff	}
124219820Sjeff}
125219820SjeffEXPORT_SYMBOL(rdma_node_get_transport);
126219820Sjeff
127219820Sjeffenum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device, u8 port_num)
128219820Sjeff{
129219820Sjeff	if (device->get_link_layer)
130219820Sjeff		return device->get_link_layer(device, port_num);
131219820Sjeff
132219820Sjeff	switch (rdma_node_get_transport(device->node_type)) {
133219820Sjeff	case RDMA_TRANSPORT_IB:
134219820Sjeff		return IB_LINK_LAYER_INFINIBAND;
135219820Sjeff	case RDMA_TRANSPORT_IWARP:
136219820Sjeff		return IB_LINK_LAYER_ETHERNET;
137278886Shselasky	case RDMA_TRANSPORT_SCIF:
138278886Shselasky		return IB_LINK_LAYER_SCIF;
139219820Sjeff	default:
140219820Sjeff		return IB_LINK_LAYER_UNSPECIFIED;
141219820Sjeff	}
142219820Sjeff}
143219820SjeffEXPORT_SYMBOL(rdma_port_get_link_layer);
144219820Sjeff
145219820Sjeff/* Protection domains */
146219820Sjeff
147219820Sjeffstruct ib_pd *ib_alloc_pd(struct ib_device *device)
148219820Sjeff{
149219820Sjeff	struct ib_pd *pd;
150219820Sjeff
151219820Sjeff	pd = device->alloc_pd(device, NULL, NULL);
152219820Sjeff
153219820Sjeff	if (!IS_ERR(pd)) {
154219820Sjeff		pd->device  = device;
155219820Sjeff		pd->uobject = NULL;
156219820Sjeff		atomic_set(&pd->usecnt, 0);
157219820Sjeff	}
158219820Sjeff
159219820Sjeff	return pd;
160219820Sjeff}
161219820SjeffEXPORT_SYMBOL(ib_alloc_pd);
162219820Sjeff
163219820Sjeffint ib_dealloc_pd(struct ib_pd *pd)
164219820Sjeff{
165219820Sjeff	if (atomic_read(&pd->usecnt))
166219820Sjeff		return -EBUSY;
167219820Sjeff
168219820Sjeff	return pd->device->dealloc_pd(pd);
169219820Sjeff}
170219820SjeffEXPORT_SYMBOL(ib_dealloc_pd);
171219820Sjeff
172219820Sjeff/* Address handles */
173219820Sjeff
174219820Sjeffstruct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
175219820Sjeff{
176219820Sjeff	struct ib_ah *ah;
177219820Sjeff
178219820Sjeff	ah = pd->device->create_ah(pd, ah_attr);
179219820Sjeff
180219820Sjeff	if (!IS_ERR(ah)) {
181219820Sjeff		ah->device  = pd->device;
182219820Sjeff		ah->pd      = pd;
183219820Sjeff		ah->uobject = NULL;
184219820Sjeff		atomic_inc(&pd->usecnt);
185219820Sjeff	}
186219820Sjeff
187219820Sjeff	return ah;
188219820Sjeff}
189219820SjeffEXPORT_SYMBOL(ib_create_ah);
190219820Sjeff
191219820Sjeffint ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc,
192219820Sjeff		       struct ib_grh *grh, struct ib_ah_attr *ah_attr)
193219820Sjeff{
194219820Sjeff	u32 flow_class;
195219820Sjeff	u16 gid_index;
196219820Sjeff	int ret;
197278886Shselasky	int is_eth = (rdma_port_get_link_layer(device, port_num) ==
198278886Shselasky			IB_LINK_LAYER_ETHERNET);
199219820Sjeff
200219820Sjeff	memset(ah_attr, 0, sizeof *ah_attr);
201278886Shselasky	if (is_eth) {
202278886Shselasky		if (!(wc->wc_flags & IB_WC_GRH))
203278886Shselasky			return -EPROTOTYPE;
204278886Shselasky
205278886Shselasky		if (wc->wc_flags & IB_WC_WITH_SMAC &&
206278886Shselasky		    wc->wc_flags & IB_WC_WITH_VLAN) {
207278886Shselasky			memcpy(ah_attr->dmac, wc->smac, ETH_ALEN);
208278886Shselasky			ah_attr->vlan_id = wc->vlan_id;
209278886Shselasky		} else {
210298486Shselasky			u32 scope_id = rdma_get_ipv6_scope_id(device, port_num);
211278886Shselasky			ret = rdma_addr_find_dmac_by_grh(&grh->dgid, &grh->sgid,
212298486Shselasky					 ah_attr->dmac, &ah_attr->vlan_id,
213298486Shselasky					 scope_id);
214278886Shselasky			if (ret)
215278886Shselasky				return ret;
216278886Shselasky		}
217278886Shselasky	} else {
218278886Shselasky		ah_attr->vlan_id = 0xffff;
219278886Shselasky	}
220278886Shselasky
221278886Shselasky
222219820Sjeff	ah_attr->dlid = wc->slid;
223219820Sjeff	ah_attr->sl = wc->sl;
224219820Sjeff	ah_attr->src_path_bits = wc->dlid_path_bits;
225219820Sjeff	ah_attr->port_num = port_num;
226219820Sjeff
227219820Sjeff	if (wc->wc_flags & IB_WC_GRH) {
228219820Sjeff		ah_attr->ah_flags = IB_AH_GRH;
229219820Sjeff		ah_attr->grh.dgid = grh->sgid;
230219820Sjeff
231219820Sjeff		ret = ib_find_cached_gid(device, &grh->dgid, &port_num,
232219820Sjeff					 &gid_index);
233219820Sjeff		if (ret)
234219820Sjeff			return ret;
235219820Sjeff
236219820Sjeff		ah_attr->grh.sgid_index = (u8) gid_index;
237219820Sjeff		flow_class = be32_to_cpu(grh->version_tclass_flow);
238219820Sjeff		ah_attr->grh.flow_label = flow_class & 0xFFFFF;
239219820Sjeff		ah_attr->grh.hop_limit = 0xFF;
240219820Sjeff		ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
241219820Sjeff	}
242219820Sjeff	return 0;
243219820Sjeff}
244219820SjeffEXPORT_SYMBOL(ib_init_ah_from_wc);
245219820Sjeff
246219820Sjeffstruct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc,
247219820Sjeff				   struct ib_grh *grh, u8 port_num)
248219820Sjeff{
249219820Sjeff	struct ib_ah_attr ah_attr;
250219820Sjeff	int ret;
251219820Sjeff
252219820Sjeff	ret = ib_init_ah_from_wc(pd->device, port_num, wc, grh, &ah_attr);
253219820Sjeff	if (ret)
254219820Sjeff		return ERR_PTR(ret);
255219820Sjeff
256219820Sjeff	return ib_create_ah(pd, &ah_attr);
257219820Sjeff}
258219820SjeffEXPORT_SYMBOL(ib_create_ah_from_wc);
259219820Sjeff
260219820Sjeffint ib_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
261219820Sjeff{
262219820Sjeff	return ah->device->modify_ah ?
263219820Sjeff		ah->device->modify_ah(ah, ah_attr) :
264219820Sjeff		-ENOSYS;
265219820Sjeff}
266219820SjeffEXPORT_SYMBOL(ib_modify_ah);
267219820Sjeff
268219820Sjeffint ib_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
269219820Sjeff{
270219820Sjeff	return ah->device->query_ah ?
271219820Sjeff		ah->device->query_ah(ah, ah_attr) :
272219820Sjeff		-ENOSYS;
273219820Sjeff}
274219820SjeffEXPORT_SYMBOL(ib_query_ah);
275219820Sjeff
276219820Sjeffint ib_destroy_ah(struct ib_ah *ah)
277219820Sjeff{
278219820Sjeff	struct ib_pd *pd;
279219820Sjeff	int ret;
280219820Sjeff
281219820Sjeff	pd = ah->pd;
282219820Sjeff	ret = ah->device->destroy_ah(ah);
283219820Sjeff	if (!ret)
284219820Sjeff		atomic_dec(&pd->usecnt);
285219820Sjeff
286219820Sjeff	return ret;
287219820Sjeff}
288219820SjeffEXPORT_SYMBOL(ib_destroy_ah);
289219820Sjeff
290219820Sjeff/* Shared receive queues */
291219820Sjeff
292219820Sjeffstruct ib_srq *ib_create_srq(struct ib_pd *pd,
293219820Sjeff			     struct ib_srq_init_attr *srq_init_attr)
294219820Sjeff{
295219820Sjeff	struct ib_srq *srq;
296219820Sjeff
297219820Sjeff	if (!pd->device->create_srq)
298219820Sjeff		return ERR_PTR(-ENOSYS);
299219820Sjeff
300219820Sjeff	srq = pd->device->create_srq(pd, srq_init_attr, NULL);
301219820Sjeff
302219820Sjeff	if (!IS_ERR(srq)) {
303219820Sjeff		srq->device    	   = pd->device;
304219820Sjeff		srq->pd        	   = pd;
305219820Sjeff		srq->uobject       = NULL;
306219820Sjeff		srq->event_handler = srq_init_attr->event_handler;
307219820Sjeff		srq->srq_context   = srq_init_attr->srq_context;
308278886Shselasky		srq->srq_type      = srq_init_attr->srq_type;
309278886Shselasky		if (srq->srq_type == IB_SRQT_XRC) {
310278886Shselasky			srq->ext.xrc.xrcd = srq_init_attr->ext.xrc.xrcd;
311278886Shselasky			srq->ext.xrc.cq   = srq_init_attr->ext.xrc.cq;
312278886Shselasky			atomic_inc(&srq->ext.xrc.xrcd->usecnt);
313278886Shselasky			atomic_inc(&srq->ext.xrc.cq->usecnt);
314278886Shselasky	}
315219820Sjeff		atomic_inc(&pd->usecnt);
316219820Sjeff		atomic_set(&srq->usecnt, 0);
317219820Sjeff	}
318219820Sjeff
319219820Sjeff	return srq;
320219820Sjeff}
321219820SjeffEXPORT_SYMBOL(ib_create_srq);
322219820Sjeff
323219820Sjeffint ib_modify_srq(struct ib_srq *srq,
324219820Sjeff		  struct ib_srq_attr *srq_attr,
325219820Sjeff		  enum ib_srq_attr_mask srq_attr_mask)
326219820Sjeff{
327219820Sjeff	return srq->device->modify_srq ?
328219820Sjeff		srq->device->modify_srq(srq, srq_attr, srq_attr_mask, NULL) :
329219820Sjeff		-ENOSYS;
330219820Sjeff}
331219820SjeffEXPORT_SYMBOL(ib_modify_srq);
332219820Sjeff
333219820Sjeffint ib_query_srq(struct ib_srq *srq,
334219820Sjeff		 struct ib_srq_attr *srq_attr)
335219820Sjeff{
336219820Sjeff	return srq->device->query_srq ?
337219820Sjeff		srq->device->query_srq(srq, srq_attr) : -ENOSYS;
338219820Sjeff}
339219820SjeffEXPORT_SYMBOL(ib_query_srq);
340219820Sjeff
341278886Shselaskyint ib_query_values(struct ib_device *device,
342278886Shselasky		   int q_values, struct ib_device_values *values)
343278886Shselasky{
344278886Shselasky	return device->query_values ?
345278886Shselasky		device->query_values(device, q_values, values) : -ENOSYS;
346278886Shselasky}
347278886ShselaskyEXPORT_SYMBOL(ib_query_values);
348278886Shselasky
349219820Sjeffint ib_destroy_srq(struct ib_srq *srq)
350219820Sjeff{
351219820Sjeff	struct ib_pd *pd;
352278886Shselasky	enum ib_srq_type srq_type;
353278886Shselasky	struct ib_xrcd *uninitialized_var(xrcd);
354278886Shselasky	struct ib_cq *uninitialized_var(cq);
355219820Sjeff	int ret;
356219820Sjeff
357219820Sjeff	if (atomic_read(&srq->usecnt))
358219820Sjeff		return -EBUSY;
359219820Sjeff
360219820Sjeff	pd = srq->pd;
361278886Shselasky	srq_type = srq->srq_type;
362278886Shselasky	if (srq_type == IB_SRQT_XRC) {
363255932Salfred	xrcd = srq->ext.xrc.xrcd;
364278886Shselasky		cq = srq->ext.xrc.cq;
365278886Shselasky	}
366219820Sjeff
367219820Sjeff	ret = srq->device->destroy_srq(srq);
368219820Sjeff	if (!ret) {
369219820Sjeff		atomic_dec(&pd->usecnt);
370278886Shselasky		if (srq_type == IB_SRQT_XRC) {
371219820Sjeff			atomic_dec(&xrcd->usecnt);
372278886Shselasky			atomic_dec(&cq->usecnt);
373278886Shselasky		}
374219820Sjeff	}
375219820Sjeff
376219820Sjeff	return ret;
377219820Sjeff}
378219820SjeffEXPORT_SYMBOL(ib_destroy_srq);
379219820Sjeff
380219820Sjeff/* Queue pairs */
381219820Sjeff
382278886Shselaskystatic void __ib_shared_qp_event_handler(struct ib_event *event, void *context)
383278886Shselasky{
384278886Shselasky	struct ib_qp *qp = context;
385278886Shselasky	unsigned long flags;
386278886Shselasky
387278886Shselasky	/* The code below must be synced with deletions of existing qps (ib_close_qp) --
388278886Shselasky	*   because a qp from the list may be closed during the scan, resulting in a kernel Oops.
389278886Shselasky	*/
390278886Shselasky	spin_lock_irqsave(&qp->device->event_handler_lock, flags);
391278886Shselasky	list_for_each_entry(event->element.qp, &qp->open_list, open_list)
392278886Shselasky		if (event->element.qp->event_handler)
393278886Shselasky			event->element.qp->event_handler(event, event->element.qp->qp_context);
394278886Shselasky	spin_unlock_irqrestore(&qp->device->event_handler_lock, flags);
395278886Shselasky}
396278886Shselasky
397278886Shselaskystatic void __ib_insert_xrcd_qp(struct ib_xrcd *xrcd, struct ib_qp *qp)
398278886Shselasky{
399278886Shselasky	mutex_lock(&xrcd->tgt_qp_mutex);
400278886Shselasky	list_add(&qp->xrcd_list, &xrcd->tgt_qp_list);
401278886Shselasky	mutex_unlock(&xrcd->tgt_qp_mutex);
402278886Shselasky}
403278886Shselasky
404278886Shselaskystatic struct ib_qp *__ib_open_qp(struct ib_qp *real_qp,
405278886Shselasky				  void (*event_handler)(struct ib_event *, void *),
406278886Shselasky				  void *qp_context)
407278886Shselasky{
408278886Shselasky	struct ib_qp *qp;
409278886Shselasky	unsigned long flags;
410278886Shselasky
411278886Shselasky	qp = kzalloc(sizeof *qp, GFP_KERNEL);
412278886Shselasky	if (!qp)
413278886Shselasky		return ERR_PTR(-ENOMEM);
414278886Shselasky
415278886Shselasky	qp->real_qp = real_qp;
416278886Shselasky	atomic_inc(&real_qp->usecnt);
417278886Shselasky	qp->device = real_qp->device;
418278886Shselasky	qp->event_handler = event_handler;
419278886Shselasky	qp->qp_context = qp_context;
420278886Shselasky	qp->qp_num = real_qp->qp_num;
421278886Shselasky	qp->qp_type = real_qp->qp_type;
422278886Shselasky
423278886Shselasky	spin_lock_irqsave(&real_qp->device->event_handler_lock, flags);
424278886Shselasky	list_add(&qp->open_list, &real_qp->open_list);
425278886Shselasky	spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags);
426278886Shselasky
427278886Shselasky	return qp;
428278886Shselasky}
429278886Shselasky
430278886Shselaskystruct ib_qp *ib_open_qp(struct ib_xrcd *xrcd,
431278886Shselasky			 struct ib_qp_open_attr *qp_open_attr)
432278886Shselasky{
433278886Shselasky	struct ib_qp *qp, *real_qp;
434278886Shselasky
435278886Shselasky	if (qp_open_attr->qp_type != IB_QPT_XRC_TGT)
436278886Shselasky		return ERR_PTR(-EINVAL);
437278886Shselasky
438278886Shselasky	qp = ERR_PTR(-EINVAL);
439278886Shselasky	mutex_lock(&xrcd->tgt_qp_mutex);
440278886Shselasky	list_for_each_entry(real_qp, &xrcd->tgt_qp_list, xrcd_list) {
441278886Shselasky		if (real_qp->qp_num == qp_open_attr->qp_num) {
442278886Shselasky			qp = __ib_open_qp(real_qp, qp_open_attr->event_handler,
443278886Shselasky					  qp_open_attr->qp_context);
444278886Shselasky			break;
445278886Shselasky		}
446278886Shselasky	}
447278886Shselasky	mutex_unlock(&xrcd->tgt_qp_mutex);
448278886Shselasky	return qp;
449278886Shselasky}
450278886ShselaskyEXPORT_SYMBOL(ib_open_qp);
451278886Shselasky
452219820Sjeffstruct ib_qp *ib_create_qp(struct ib_pd *pd,
453219820Sjeff			   struct ib_qp_init_attr *qp_init_attr)
454219820Sjeff{
455278886Shselasky	struct ib_qp *qp, *real_qp;
456278886Shselasky	struct ib_device *device;
457219820Sjeff
458278886Shselasky	device = pd ? pd->device : qp_init_attr->xrcd->device;
459278886Shselasky	qp = device->create_qp(pd, qp_init_attr, NULL);
460219820Sjeff
461219820Sjeff	if (!IS_ERR(qp)) {
462278886Shselasky		qp->device     = device;
463278886Shselasky		qp->real_qp    = qp;
464219820Sjeff		qp->uobject       = NULL;
465278886Shselasky		qp->qp_type    = qp_init_attr->qp_type;
466278886Shselasky
467278886Shselasky		atomic_set(&qp->usecnt, 0);
468278886Shselasky		if (qp_init_attr->qp_type == IB_QPT_XRC_TGT) {
469278886Shselasky			qp->event_handler = __ib_shared_qp_event_handler;
470278886Shselasky			qp->qp_context = qp;
471278886Shselasky			qp->pd = NULL;
472278886Shselasky			qp->send_cq = qp->recv_cq = NULL;
473278886Shselasky			qp->srq = NULL;
474278886Shselasky			qp->xrcd = qp_init_attr->xrcd;
475278886Shselasky			atomic_inc(&qp_init_attr->xrcd->usecnt);
476278886Shselasky			INIT_LIST_HEAD(&qp->open_list);
477278886Shselasky
478278886Shselasky			real_qp = qp;
479278886Shselasky			qp = __ib_open_qp(real_qp, qp_init_attr->event_handler,
480278886Shselasky					  qp_init_attr->qp_context);
481278886Shselasky			if (!IS_ERR(qp))
482278886Shselasky				__ib_insert_xrcd_qp(qp_init_attr->xrcd, real_qp);
483278886Shselasky			else
484278886Shselasky				real_qp->device->destroy_qp(real_qp);
485278886Shselasky		} else {
486219820Sjeff		qp->event_handler = qp_init_attr->event_handler;
487219820Sjeff		qp->qp_context    = qp_init_attr->qp_context;
488278886Shselasky			if (qp_init_attr->qp_type == IB_QPT_XRC_INI) {
489278886Shselasky				qp->recv_cq = NULL;
490278886Shselasky				qp->srq = NULL;
491278886Shselasky			} else {
492278886Shselasky				qp->recv_cq = qp_init_attr->recv_cq;
493219820Sjeff		atomic_inc(&qp_init_attr->recv_cq->usecnt);
494278886Shselasky				qp->srq = qp_init_attr->srq;
495278886Shselasky				if (qp->srq)
496219820Sjeff			atomic_inc(&qp_init_attr->srq->usecnt);
497278886Shselasky			}
498278886Shselasky
499278886Shselasky			qp->pd	    = pd;
500278886Shselasky			qp->send_cq = qp_init_attr->send_cq;
501278886Shselasky			qp->xrcd    = NULL;
502278886Shselasky
503278886Shselasky			atomic_inc(&pd->usecnt);
504278886Shselasky			atomic_inc(&qp_init_attr->send_cq->usecnt);
505278886Shselasky		}
506219820Sjeff	}
507219820Sjeff
508219820Sjeff	return qp;
509219820Sjeff}
510219820SjeffEXPORT_SYMBOL(ib_create_qp);
511219820Sjeff
512219820Sjeffstatic const struct {
513219820Sjeff	int			valid;
514278886Shselasky	enum ib_qp_attr_mask	req_param[IB_QPT_MAX];
515278886Shselasky	enum ib_qp_attr_mask	req_param_add_eth[IB_QPT_MAX];
516278886Shselasky	enum ib_qp_attr_mask	opt_param[IB_QPT_MAX];
517278886Shselasky	enum ib_qp_attr_mask	opt_param_add_eth[IB_QPT_MAX];
518219820Sjeff} qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
519219820Sjeff	[IB_QPS_RESET] = {
520219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
521219820Sjeff		[IB_QPS_INIT]  = {
522219820Sjeff			.valid = 1,
523219820Sjeff			.req_param = {
524219820Sjeff				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
525219820Sjeff						IB_QP_PORT			|
526219820Sjeff						IB_QP_QKEY),
527255932Salfred				[IB_QPT_RAW_PACKET] = IB_QP_PORT,
528219820Sjeff				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
529219820Sjeff						IB_QP_PORT			|
530219820Sjeff						IB_QP_ACCESS_FLAGS),
531219820Sjeff				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
532219820Sjeff						IB_QP_PORT			|
533219820Sjeff						IB_QP_ACCESS_FLAGS),
534278886Shselasky				[IB_QPT_DC_INI]  = (IB_QP_PKEY_INDEX		|
535278886Shselasky						    IB_QP_PORT			|
536278886Shselasky						    IB_QP_ACCESS_FLAGS		|
537278886Shselasky						    IB_QP_DC_KEY),
538278886Shselasky				[IB_QPT_XRC_INI] = (IB_QP_PKEY_INDEX		|
539278886Shselasky						    IB_QP_PORT			|
540278886Shselasky						    IB_QP_ACCESS_FLAGS),
541278886Shselasky				[IB_QPT_XRC_TGT] = (IB_QP_PKEY_INDEX		|
542219820Sjeff						IB_QP_PORT			|
543219820Sjeff						IB_QP_ACCESS_FLAGS),
544219820Sjeff				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
545219820Sjeff						IB_QP_QKEY),
546219820Sjeff				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
547219820Sjeff						IB_QP_QKEY),
548278886Shselasky			},
549278886Shselasky			.opt_param = {
550278886Shselasky				[IB_QPT_UD]  = IB_QP_GROUP_RSS,
551278886Shselasky				[IB_QPT_RAW_PACKET] = IB_QP_GROUP_RSS
552219820Sjeff			}
553219820Sjeff		},
554219820Sjeff	},
555219820Sjeff	[IB_QPS_INIT]  = {
556219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
557219820Sjeff		[IB_QPS_ERR] =   { .valid = 1 },
558219820Sjeff		[IB_QPS_INIT]  = {
559219820Sjeff			.valid = 1,
560219820Sjeff			.opt_param = {
561219820Sjeff				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
562219820Sjeff						IB_QP_PORT			|
563219820Sjeff						IB_QP_QKEY),
564219820Sjeff				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
565219820Sjeff						IB_QP_PORT			|
566219820Sjeff						IB_QP_ACCESS_FLAGS),
567219820Sjeff				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
568219820Sjeff						IB_QP_PORT			|
569219820Sjeff						IB_QP_ACCESS_FLAGS),
570278886Shselasky				[IB_QPT_DC_INI]  = (IB_QP_PKEY_INDEX		|
571278886Shselasky						    IB_QP_PORT			|
572278886Shselasky						    IB_QP_ACCESS_FLAGS),
573278886Shselasky				[IB_QPT_XRC_INI] = (IB_QP_PKEY_INDEX		|
574219820Sjeff						IB_QP_PORT			|
575219820Sjeff						IB_QP_ACCESS_FLAGS),
576278886Shselasky				[IB_QPT_XRC_TGT] = (IB_QP_PKEY_INDEX		|
577278886Shselasky						IB_QP_PORT			|
578278886Shselasky						IB_QP_ACCESS_FLAGS),
579219820Sjeff				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
580219820Sjeff						IB_QP_QKEY),
581219820Sjeff				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
582219820Sjeff						IB_QP_QKEY),
583219820Sjeff			}
584219820Sjeff		},
585219820Sjeff		[IB_QPS_RTR]   = {
586219820Sjeff			.valid = 1,
587219820Sjeff			.req_param = {
588219820Sjeff				[IB_QPT_UC]  = (IB_QP_AV			|
589219820Sjeff						IB_QP_PATH_MTU			|
590219820Sjeff						IB_QP_DEST_QPN			|
591219820Sjeff						IB_QP_RQ_PSN),
592219820Sjeff				[IB_QPT_RC]  = (IB_QP_AV			|
593219820Sjeff						IB_QP_PATH_MTU			|
594219820Sjeff						IB_QP_DEST_QPN			|
595219820Sjeff						IB_QP_RQ_PSN			|
596219820Sjeff						IB_QP_MAX_DEST_RD_ATOMIC	|
597219820Sjeff						IB_QP_MIN_RNR_TIMER),
598278886Shselasky				[IB_QPT_DC_INI]  = (IB_QP_PATH_MTU		|
599278886Shselasky						    IB_QP_MAX_DEST_RD_ATOMIC	|
600278886Shselasky						    IB_QP_MIN_RNR_TIMER),
601278886Shselasky				[IB_QPT_XRC_INI] = (IB_QP_AV			|
602219820Sjeff						IB_QP_PATH_MTU			|
603219820Sjeff						IB_QP_DEST_QPN			|
604278886Shselasky						IB_QP_RQ_PSN),
605278886Shselasky				[IB_QPT_XRC_TGT] = (IB_QP_AV			|
606278886Shselasky						IB_QP_PATH_MTU			|
607278886Shselasky						IB_QP_DEST_QPN			|
608219820Sjeff						IB_QP_RQ_PSN			|
609219820Sjeff						IB_QP_MAX_DEST_RD_ATOMIC	|
610219820Sjeff						IB_QP_MIN_RNR_TIMER),
611219820Sjeff			},
612278886Shselasky			.req_param_add_eth = {
613278886Shselasky				[IB_QPT_RC]  = (IB_QP_SMAC),
614278886Shselasky				[IB_QPT_UC]  = (IB_QP_SMAC),
615278886Shselasky				[IB_QPT_XRC_INI] = (IB_QP_SMAC),
616278886Shselasky				[IB_QPT_XRC_TGT] = (IB_QP_SMAC)
617278886Shselasky			},
618219820Sjeff			.opt_param = {
619219820Sjeff				 [IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
620219820Sjeff						 IB_QP_QKEY),
621219820Sjeff				 [IB_QPT_UC]  = (IB_QP_ALT_PATH			|
622219820Sjeff						 IB_QP_ACCESS_FLAGS		|
623219820Sjeff						 IB_QP_PKEY_INDEX),
624219820Sjeff				 [IB_QPT_RC]  = (IB_QP_ALT_PATH			|
625219820Sjeff						 IB_QP_ACCESS_FLAGS		|
626219820Sjeff						 IB_QP_PKEY_INDEX),
627278886Shselasky				 [IB_QPT_DC_INI]  = (IB_QP_ALT_PATH		|
628278886Shselasky						     IB_QP_ACCESS_FLAGS		|
629278886Shselasky						     IB_QP_PKEY_INDEX),
630278886Shselasky				 [IB_QPT_XRC_INI] = (IB_QP_ALT_PATH		|
631278886Shselasky						 IB_QP_ACCESS_FLAGS		|
632278886Shselasky						 IB_QP_PKEY_INDEX),
633278886Shselasky				 [IB_QPT_XRC_TGT] = (IB_QP_ALT_PATH		|
634219820Sjeff						IB_QP_ACCESS_FLAGS		|
635219820Sjeff						IB_QP_PKEY_INDEX),
636219820Sjeff				 [IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
637219820Sjeff						 IB_QP_QKEY),
638219820Sjeff				 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
639219820Sjeff						 IB_QP_QKEY),
640278886Shselasky				[IB_QPT_RAW_PACKET] = IB_QP_AV,
641278886Shselasky			 },
642278886Shselasky			.opt_param_add_eth = {
643278886Shselasky				[IB_QPT_RC]  = (IB_QP_ALT_SMAC			|
644278886Shselasky						IB_QP_VID			|
645278886Shselasky						IB_QP_ALT_VID),
646278886Shselasky				[IB_QPT_UC]  = (IB_QP_ALT_SMAC			|
647278886Shselasky						IB_QP_VID			|
648278886Shselasky						IB_QP_ALT_VID),
649278886Shselasky				[IB_QPT_XRC_INI] = (IB_QP_ALT_SMAC		|
650278886Shselasky						    IB_QP_VID			|
651278886Shselasky						    IB_QP_ALT_VID),
652278886Shselasky				[IB_QPT_XRC_TGT] = (IB_QP_ALT_SMAC		|
653278886Shselasky						    IB_QP_VID			|
654278886Shselasky						    IB_QP_ALT_VID)
655219820Sjeff			 }
656219820Sjeff		}
657219820Sjeff	},
658219820Sjeff	[IB_QPS_RTR]   = {
659219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
660219820Sjeff		[IB_QPS_ERR] =   { .valid = 1 },
661219820Sjeff		[IB_QPS_RTS]   = {
662219820Sjeff			.valid = 1,
663219820Sjeff			.req_param = {
664219820Sjeff				[IB_QPT_UD]  = IB_QP_SQ_PSN,
665219820Sjeff				[IB_QPT_UC]  = IB_QP_SQ_PSN,
666219820Sjeff				[IB_QPT_RC]  = (IB_QP_TIMEOUT			|
667219820Sjeff						IB_QP_RETRY_CNT			|
668219820Sjeff						IB_QP_RNR_RETRY			|
669219820Sjeff						IB_QP_SQ_PSN			|
670219820Sjeff						IB_QP_MAX_QP_RD_ATOMIC),
671278886Shselasky				[IB_QPT_DC_INI]  = (IB_QP_TIMEOUT		|
672278886Shselasky						    IB_QP_RETRY_CNT		|
673278886Shselasky						    IB_QP_RNR_RETRY		|
674278886Shselasky						    IB_QP_MAX_QP_RD_ATOMIC),
675278886Shselasky				[IB_QPT_XRC_INI] = (IB_QP_TIMEOUT		|
676219820Sjeff						IB_QP_RETRY_CNT			|
677219820Sjeff						IB_QP_RNR_RETRY			|
678219820Sjeff						IB_QP_SQ_PSN			|
679219820Sjeff						IB_QP_MAX_QP_RD_ATOMIC),
680278886Shselasky				[IB_QPT_XRC_TGT] = (IB_QP_TIMEOUT		|
681278886Shselasky						IB_QP_SQ_PSN),
682219820Sjeff				[IB_QPT_SMI] = IB_QP_SQ_PSN,
683219820Sjeff				[IB_QPT_GSI] = IB_QP_SQ_PSN,
684219820Sjeff			},
685219820Sjeff			.opt_param = {
686219820Sjeff				 [IB_QPT_UD]  = (IB_QP_CUR_STATE		|
687219820Sjeff						 IB_QP_QKEY),
688219820Sjeff				 [IB_QPT_UC]  = (IB_QP_CUR_STATE		|
689219820Sjeff						 IB_QP_ALT_PATH			|
690219820Sjeff						 IB_QP_ACCESS_FLAGS		|
691219820Sjeff						 IB_QP_PATH_MIG_STATE),
692219820Sjeff				 [IB_QPT_RC]  = (IB_QP_CUR_STATE		|
693219820Sjeff						 IB_QP_ALT_PATH			|
694219820Sjeff						 IB_QP_ACCESS_FLAGS		|
695219820Sjeff						 IB_QP_MIN_RNR_TIMER		|
696219820Sjeff						 IB_QP_PATH_MIG_STATE),
697278886Shselasky				 [IB_QPT_DC_INI] = (IB_QP_CUR_STATE		|
698278886Shselasky						    IB_QP_ALT_PATH		|
699278886Shselasky						    IB_QP_ACCESS_FLAGS		|
700278886Shselasky						    IB_QP_MIN_RNR_TIMER		|
701278886Shselasky						    IB_QP_PATH_MIG_STATE),
702278886Shselasky				 [IB_QPT_XRC_INI] = (IB_QP_CUR_STATE		|
703278886Shselasky						 IB_QP_ALT_PATH			|
704278886Shselasky						 IB_QP_ACCESS_FLAGS		|
705278886Shselasky						 IB_QP_PATH_MIG_STATE),
706278886Shselasky				 [IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE		|
707219820Sjeff						IB_QP_ALT_PATH			|
708219820Sjeff						IB_QP_ACCESS_FLAGS		|
709219820Sjeff						IB_QP_MIN_RNR_TIMER		|
710219820Sjeff						IB_QP_PATH_MIG_STATE),
711219820Sjeff				 [IB_QPT_SMI] = (IB_QP_CUR_STATE		|
712219820Sjeff						 IB_QP_QKEY),
713219820Sjeff				 [IB_QPT_GSI] = (IB_QP_CUR_STATE		|
714219820Sjeff						 IB_QP_QKEY),
715219820Sjeff			 }
716219820Sjeff		}
717219820Sjeff	},
718219820Sjeff	[IB_QPS_RTS]   = {
719219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
720219820Sjeff		[IB_QPS_ERR] =   { .valid = 1 },
721219820Sjeff		[IB_QPS_RTS]   = {
722219820Sjeff			.valid = 1,
723219820Sjeff			.opt_param = {
724219820Sjeff				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
725219820Sjeff						IB_QP_QKEY),
726219820Sjeff				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
727219820Sjeff						IB_QP_ACCESS_FLAGS		|
728219820Sjeff						IB_QP_ALT_PATH			|
729219820Sjeff						IB_QP_PATH_MIG_STATE),
730219820Sjeff				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
731219820Sjeff						IB_QP_ACCESS_FLAGS		|
732219820Sjeff						IB_QP_ALT_PATH			|
733219820Sjeff						IB_QP_PATH_MIG_STATE		|
734219820Sjeff						IB_QP_MIN_RNR_TIMER),
735278886Shselasky				[IB_QPT_DC_INI]  = (IB_QP_CUR_STATE		|
736278886Shselasky						    IB_QP_ACCESS_FLAGS		|
737278886Shselasky						    IB_QP_ALT_PATH		|
738278886Shselasky						    IB_QP_PATH_MIG_STATE	|
739278886Shselasky						    IB_QP_MIN_RNR_TIMER),
740278886Shselasky				[IB_QPT_XRC_INI] = (IB_QP_CUR_STATE		|
741219820Sjeff						IB_QP_ACCESS_FLAGS		|
742219820Sjeff						IB_QP_ALT_PATH			|
743278886Shselasky						IB_QP_PATH_MIG_STATE),
744278886Shselasky				[IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE		|
745278886Shselasky						IB_QP_ACCESS_FLAGS		|
746278886Shselasky						IB_QP_ALT_PATH			|
747219820Sjeff						IB_QP_PATH_MIG_STATE		|
748219820Sjeff						IB_QP_MIN_RNR_TIMER),
749219820Sjeff				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
750219820Sjeff						IB_QP_QKEY),
751219820Sjeff				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
752219820Sjeff						IB_QP_QKEY),
753219820Sjeff			}
754219820Sjeff		},
755219820Sjeff		[IB_QPS_SQD]   = {
756219820Sjeff			.valid = 1,
757219820Sjeff			.opt_param = {
758219820Sjeff				[IB_QPT_UD]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
759219820Sjeff				[IB_QPT_UC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
760219820Sjeff				[IB_QPT_RC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
761278886Shselasky				[IB_QPT_XRC_INI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
762278886Shselasky				[IB_QPT_XRC_TGT] = IB_QP_EN_SQD_ASYNC_NOTIFY, /* ??? */
763219820Sjeff				[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
764219820Sjeff				[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
765219820Sjeff			}
766219820Sjeff		},
767219820Sjeff	},
768219820Sjeff	[IB_QPS_SQD]   = {
769219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
770219820Sjeff		[IB_QPS_ERR] =   { .valid = 1 },
771219820Sjeff		[IB_QPS_RTS]   = {
772219820Sjeff			.valid = 1,
773219820Sjeff			.opt_param = {
774219820Sjeff				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
775219820Sjeff						IB_QP_QKEY),
776219820Sjeff				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
777219820Sjeff						IB_QP_ALT_PATH			|
778219820Sjeff						IB_QP_ACCESS_FLAGS		|
779219820Sjeff						IB_QP_PATH_MIG_STATE),
780219820Sjeff				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
781219820Sjeff						IB_QP_ALT_PATH			|
782219820Sjeff						IB_QP_ACCESS_FLAGS		|
783219820Sjeff						IB_QP_MIN_RNR_TIMER		|
784219820Sjeff						IB_QP_PATH_MIG_STATE),
785278886Shselasky				[IB_QPT_XRC_INI] = (IB_QP_CUR_STATE		|
786219820Sjeff						IB_QP_ALT_PATH			|
787219820Sjeff						IB_QP_ACCESS_FLAGS		|
788278886Shselasky						IB_QP_PATH_MIG_STATE),
789278886Shselasky				[IB_QPT_XRC_TGT] = (IB_QP_CUR_STATE		|
790278886Shselasky						IB_QP_ALT_PATH			|
791278886Shselasky						IB_QP_ACCESS_FLAGS		|
792219820Sjeff						IB_QP_MIN_RNR_TIMER		|
793219820Sjeff						IB_QP_PATH_MIG_STATE),
794219820Sjeff				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
795219820Sjeff						IB_QP_QKEY),
796219820Sjeff				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
797219820Sjeff						IB_QP_QKEY),
798219820Sjeff			}
799219820Sjeff		},
800219820Sjeff		[IB_QPS_SQD]   = {
801219820Sjeff			.valid = 1,
802219820Sjeff			.opt_param = {
803219820Sjeff				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
804219820Sjeff						IB_QP_QKEY),
805219820Sjeff				[IB_QPT_UC]  = (IB_QP_AV			|
806219820Sjeff						IB_QP_ALT_PATH			|
807219820Sjeff						IB_QP_ACCESS_FLAGS		|
808219820Sjeff						IB_QP_PKEY_INDEX		|
809219820Sjeff						IB_QP_PATH_MIG_STATE),
810219820Sjeff				[IB_QPT_RC]  = (IB_QP_PORT			|
811219820Sjeff						IB_QP_AV			|
812219820Sjeff						IB_QP_TIMEOUT			|
813219820Sjeff						IB_QP_RETRY_CNT			|
814219820Sjeff						IB_QP_RNR_RETRY			|
815219820Sjeff						IB_QP_MAX_QP_RD_ATOMIC		|
816219820Sjeff						IB_QP_MAX_DEST_RD_ATOMIC	|
817219820Sjeff						IB_QP_ALT_PATH			|
818219820Sjeff						IB_QP_ACCESS_FLAGS		|
819219820Sjeff						IB_QP_PKEY_INDEX		|
820219820Sjeff						IB_QP_MIN_RNR_TIMER		|
821219820Sjeff						IB_QP_PATH_MIG_STATE),
822278886Shselasky				[IB_QPT_XRC_INI] = (IB_QP_PORT			|
823219820Sjeff						IB_QP_AV			|
824219820Sjeff						IB_QP_TIMEOUT			|
825219820Sjeff						IB_QP_RETRY_CNT			|
826219820Sjeff						IB_QP_RNR_RETRY			|
827219820Sjeff						IB_QP_MAX_QP_RD_ATOMIC		|
828278886Shselasky						IB_QP_ALT_PATH			|
829278886Shselasky						IB_QP_ACCESS_FLAGS		|
830278886Shselasky						IB_QP_PKEY_INDEX		|
831278886Shselasky						IB_QP_PATH_MIG_STATE),
832278886Shselasky				[IB_QPT_XRC_TGT] = (IB_QP_PORT			|
833278886Shselasky						IB_QP_AV			|
834278886Shselasky						IB_QP_TIMEOUT			|
835219820Sjeff						IB_QP_MAX_DEST_RD_ATOMIC	|
836219820Sjeff						IB_QP_ALT_PATH			|
837219820Sjeff						IB_QP_ACCESS_FLAGS		|
838219820Sjeff						IB_QP_PKEY_INDEX		|
839219820Sjeff						IB_QP_MIN_RNR_TIMER		|
840219820Sjeff						IB_QP_PATH_MIG_STATE),
841219820Sjeff				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
842219820Sjeff						IB_QP_QKEY),
843219820Sjeff				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
844219820Sjeff						IB_QP_QKEY),
845219820Sjeff			}
846219820Sjeff		}
847219820Sjeff	},
848219820Sjeff	[IB_QPS_SQE]   = {
849219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
850219820Sjeff		[IB_QPS_ERR] =   { .valid = 1 },
851219820Sjeff		[IB_QPS_RTS]   = {
852219820Sjeff			.valid = 1,
853219820Sjeff			.opt_param = {
854219820Sjeff				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
855219820Sjeff						IB_QP_QKEY),
856219820Sjeff				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
857219820Sjeff						IB_QP_ACCESS_FLAGS),
858219820Sjeff				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
859219820Sjeff						IB_QP_QKEY),
860219820Sjeff				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
861219820Sjeff						IB_QP_QKEY),
862219820Sjeff			}
863219820Sjeff		}
864219820Sjeff	},
865219820Sjeff	[IB_QPS_ERR] = {
866219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
867219820Sjeff		[IB_QPS_ERR] =   { .valid = 1 }
868219820Sjeff	}
869219820Sjeff};
870219820Sjeff
871219820Sjeffint ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
872278886Shselasky		       enum ib_qp_type type, enum ib_qp_attr_mask mask,
873278886Shselasky		       enum rdma_link_layer ll)
874219820Sjeff{
875219820Sjeff	enum ib_qp_attr_mask req_param, opt_param;
876219820Sjeff
877219820Sjeff	if (cur_state  < 0 || cur_state  > IB_QPS_ERR ||
878219820Sjeff	    next_state < 0 || next_state > IB_QPS_ERR)
879219820Sjeff		return 0;
880219820Sjeff
881219820Sjeff	if (mask & IB_QP_CUR_STATE  &&
882219820Sjeff	    cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
883219820Sjeff	    cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE)
884219820Sjeff		return 0;
885219820Sjeff
886219820Sjeff	if (!qp_state_table[cur_state][next_state].valid)
887219820Sjeff		return 0;
888219820Sjeff
889219820Sjeff	req_param = qp_state_table[cur_state][next_state].req_param[type];
890219820Sjeff	opt_param = qp_state_table[cur_state][next_state].opt_param[type];
891219820Sjeff
892278886Shselasky	if (ll == IB_LINK_LAYER_ETHERNET) {
893278886Shselasky		req_param |= qp_state_table[cur_state][next_state].
894278886Shselasky			req_param_add_eth[type];
895278886Shselasky		opt_param |= qp_state_table[cur_state][next_state].
896278886Shselasky			opt_param_add_eth[type];
897278886Shselasky	}
898278886Shselasky
899219820Sjeff	if ((mask & req_param) != req_param)
900219820Sjeff		return 0;
901219820Sjeff
902219820Sjeff	if (mask & ~(req_param | opt_param | IB_QP_STATE))
903219820Sjeff		return 0;
904219820Sjeff
905219820Sjeff	return 1;
906219820Sjeff}
907219820SjeffEXPORT_SYMBOL(ib_modify_qp_is_ok);
908219820Sjeff
909219820Sjeffint ib_modify_qp(struct ib_qp *qp,
910219820Sjeff		 struct ib_qp_attr *qp_attr,
911219820Sjeff		 int qp_attr_mask)
912219820Sjeff{
913278886Shselasky	int ret;
914278886Shselasky
915278886Shselasky	ret = qp->device->modify_qp(qp->real_qp, qp_attr, qp_attr_mask, NULL);
916278886Shselasky	if (!ret && (qp_attr_mask & IB_QP_PORT))
917278886Shselasky		qp->port_num = qp_attr->port_num;
918278886Shselasky
919278886Shselasky	return ret;
920219820Sjeff}
921219820SjeffEXPORT_SYMBOL(ib_modify_qp);
922219820Sjeff
923219820Sjeffint ib_query_qp(struct ib_qp *qp,
924219820Sjeff		struct ib_qp_attr *qp_attr,
925219820Sjeff		int qp_attr_mask,
926219820Sjeff		struct ib_qp_init_attr *qp_init_attr)
927219820Sjeff{
928219820Sjeff	return qp->device->query_qp ?
929278886Shselasky		qp->device->query_qp(qp->real_qp, qp_attr, qp_attr_mask, qp_init_attr) :
930219820Sjeff		-ENOSYS;
931219820Sjeff}
932219820SjeffEXPORT_SYMBOL(ib_query_qp);
933219820Sjeff
934278886Shselaskyint ib_close_qp(struct ib_qp *qp)
935278886Shselasky{
936278886Shselasky	struct ib_qp *real_qp;
937278886Shselasky	unsigned long flags;
938278886Shselasky
939278886Shselasky	real_qp = qp->real_qp;
940278886Shselasky	if (real_qp == qp)
941278886Shselasky		return -EINVAL;
942278886Shselasky
943278886Shselasky	spin_lock_irqsave(&real_qp->device->event_handler_lock, flags);
944278886Shselasky	list_del(&qp->open_list);
945278886Shselasky	spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags);
946278886Shselasky
947278886Shselasky	atomic_dec(&real_qp->usecnt);
948278886Shselasky	kfree(qp);
949278886Shselasky
950278886Shselasky	return 0;
951278886Shselasky}
952278886ShselaskyEXPORT_SYMBOL(ib_close_qp);
953278886Shselasky
954278886Shselaskystatic int __ib_destroy_shared_qp(struct ib_qp *qp)
955278886Shselasky{
956278886Shselasky	struct ib_xrcd *xrcd;
957278886Shselasky	struct ib_qp *real_qp;
958278886Shselasky	int ret;
959278886Shselasky
960278886Shselasky	real_qp = qp->real_qp;
961278886Shselasky	xrcd = real_qp->xrcd;
962278886Shselasky
963278886Shselasky	mutex_lock(&xrcd->tgt_qp_mutex);
964278886Shselasky	ib_close_qp(qp);
965278886Shselasky	if (atomic_read(&real_qp->usecnt) == 0)
966278886Shselasky		list_del(&real_qp->xrcd_list);
967278886Shselasky	else
968278886Shselasky		real_qp = NULL;
969278886Shselasky	mutex_unlock(&xrcd->tgt_qp_mutex);
970278886Shselasky
971278886Shselasky	if (real_qp) {
972278886Shselasky		ret = ib_destroy_qp(real_qp);
973278886Shselasky		if (!ret)
974278886Shselasky			atomic_dec(&xrcd->usecnt);
975278886Shselasky		else
976278886Shselasky			__ib_insert_xrcd_qp(xrcd, real_qp);
977278886Shselasky	}
978278886Shselasky
979278886Shselasky	return 0;
980278886Shselasky}
981278886Shselasky
982219820Sjeffint ib_destroy_qp(struct ib_qp *qp)
983219820Sjeff{
984219820Sjeff	struct ib_pd *pd;
985219820Sjeff	struct ib_cq *scq, *rcq;
986219820Sjeff	struct ib_srq *srq;
987219820Sjeff	int ret;
988219820Sjeff
989278886Shselasky	if (atomic_read(&qp->usecnt))
990278886Shselasky		return -EBUSY;
991278886Shselasky
992278886Shselasky	if (qp->real_qp != qp)
993278886Shselasky		return __ib_destroy_shared_qp(qp);
994278886Shselasky
995219820Sjeff	pd  = qp->pd;
996219820Sjeff	scq = qp->send_cq;
997219820Sjeff	rcq = qp->recv_cq;
998219820Sjeff	srq = qp->srq;
999219820Sjeff
1000219820Sjeff	ret = qp->device->destroy_qp(qp);
1001219820Sjeff	if (!ret) {
1002278886Shselasky		if (pd)
1003219820Sjeff		atomic_dec(&pd->usecnt);
1004278886Shselasky		if (scq)
1005219820Sjeff		atomic_dec(&scq->usecnt);
1006278886Shselasky		if (rcq)
1007219820Sjeff		atomic_dec(&rcq->usecnt);
1008219820Sjeff		if (srq)
1009219820Sjeff			atomic_dec(&srq->usecnt);
1010219820Sjeff	}
1011219820Sjeff
1012219820Sjeff	return ret;
1013219820Sjeff}
1014219820SjeffEXPORT_SYMBOL(ib_destroy_qp);
1015219820Sjeff
1016219820Sjeff/* Completion queues */
1017219820Sjeff
1018219820Sjeffstruct ib_cq *ib_create_cq(struct ib_device *device,
1019219820Sjeff			   ib_comp_handler comp_handler,
1020219820Sjeff			   void (*event_handler)(struct ib_event *, void *),
1021219820Sjeff			   void *cq_context, int cqe, int comp_vector)
1022219820Sjeff{
1023219820Sjeff	struct ib_cq *cq;
1024278886Shselasky	struct ib_cq_init_attr attr = {
1025278886Shselasky		.cqe		= cqe,
1026278886Shselasky		.comp_vector	= comp_vector,
1027278886Shselasky		.flags		= 0,
1028278886Shselasky	};
1029219820Sjeff
1030278886Shselasky	cq = device->create_cq(device, &attr, NULL, NULL);
1031219820Sjeff
1032219820Sjeff	if (!IS_ERR(cq)) {
1033219820Sjeff		cq->device        = device;
1034219820Sjeff		cq->uobject       = NULL;
1035219820Sjeff		cq->comp_handler  = comp_handler;
1036219820Sjeff		cq->event_handler = event_handler;
1037219820Sjeff		cq->cq_context    = cq_context;
1038219820Sjeff		atomic_set(&cq->usecnt, 0);
1039219820Sjeff	}
1040219820Sjeff
1041219820Sjeff	return cq;
1042219820Sjeff}
1043219820SjeffEXPORT_SYMBOL(ib_create_cq);
1044219820Sjeff
1045278886Shselaskyint ib_modify_cq(struct ib_cq *cq,
1046278886Shselasky		 struct ib_cq_attr *cq_attr,
1047278886Shselasky		 int cq_attr_mask)
1048219820Sjeff{
1049219820Sjeff	return cq->device->modify_cq ?
1050278886Shselasky		cq->device->modify_cq(cq, cq_attr, cq_attr_mask) : -ENOSYS;
1051219820Sjeff}
1052219820SjeffEXPORT_SYMBOL(ib_modify_cq);
1053219820Sjeff
1054219820Sjeffint ib_destroy_cq(struct ib_cq *cq)
1055219820Sjeff{
1056219820Sjeff	if (atomic_read(&cq->usecnt))
1057219820Sjeff		return -EBUSY;
1058219820Sjeff
1059219820Sjeff	return cq->device->destroy_cq(cq);
1060219820Sjeff}
1061219820SjeffEXPORT_SYMBOL(ib_destroy_cq);
1062219820Sjeff
1063219820Sjeffint ib_resize_cq(struct ib_cq *cq, int cqe)
1064219820Sjeff{
1065219820Sjeff	return cq->device->resize_cq ?
1066219820Sjeff		cq->device->resize_cq(cq, cqe, NULL) : -ENOSYS;
1067219820Sjeff}
1068219820SjeffEXPORT_SYMBOL(ib_resize_cq);
1069219820Sjeff
1070219820Sjeff/* Memory regions */
1071219820Sjeff
1072219820Sjeffstruct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
1073219820Sjeff{
1074219820Sjeff	struct ib_mr *mr;
1075278886Shselasky	int err;
1076219820Sjeff
1077278886Shselasky	err = ib_check_mr_access(mr_access_flags);
1078278886Shselasky	if (err)
1079278886Shselasky		return ERR_PTR(err);
1080278886Shselasky
1081219820Sjeff	mr = pd->device->get_dma_mr(pd, mr_access_flags);
1082219820Sjeff
1083219820Sjeff	if (!IS_ERR(mr)) {
1084219820Sjeff		mr->device  = pd->device;
1085219820Sjeff		mr->pd      = pd;
1086219820Sjeff		mr->uobject = NULL;
1087219820Sjeff		atomic_inc(&pd->usecnt);
1088219820Sjeff		atomic_set(&mr->usecnt, 0);
1089219820Sjeff	}
1090219820Sjeff
1091219820Sjeff	return mr;
1092219820Sjeff}
1093219820SjeffEXPORT_SYMBOL(ib_get_dma_mr);
1094219820Sjeff
1095219820Sjeffstruct ib_mr *ib_reg_phys_mr(struct ib_pd *pd,
1096219820Sjeff			     struct ib_phys_buf *phys_buf_array,
1097219820Sjeff			     int num_phys_buf,
1098219820Sjeff			     int mr_access_flags,
1099219820Sjeff			     u64 *iova_start)
1100219820Sjeff{
1101219820Sjeff	struct ib_mr *mr;
1102278886Shselasky	int err;
1103219820Sjeff
1104278886Shselasky	err = ib_check_mr_access(mr_access_flags);
1105278886Shselasky	if (err)
1106278886Shselasky		return ERR_PTR(err);
1107278886Shselasky
1108219820Sjeff	if (!pd->device->reg_phys_mr)
1109219820Sjeff		return ERR_PTR(-ENOSYS);
1110219820Sjeff
1111219820Sjeff	mr = pd->device->reg_phys_mr(pd, phys_buf_array, num_phys_buf,
1112219820Sjeff				     mr_access_flags, iova_start);
1113219820Sjeff
1114219820Sjeff	if (!IS_ERR(mr)) {
1115219820Sjeff		mr->device  = pd->device;
1116219820Sjeff		mr->pd      = pd;
1117219820Sjeff		mr->uobject = NULL;
1118219820Sjeff		atomic_inc(&pd->usecnt);
1119219820Sjeff		atomic_set(&mr->usecnt, 0);
1120219820Sjeff	}
1121219820Sjeff
1122219820Sjeff	return mr;
1123219820Sjeff}
1124219820SjeffEXPORT_SYMBOL(ib_reg_phys_mr);
1125219820Sjeff
1126219820Sjeffint ib_rereg_phys_mr(struct ib_mr *mr,
1127219820Sjeff		     int mr_rereg_mask,
1128219820Sjeff		     struct ib_pd *pd,
1129219820Sjeff		     struct ib_phys_buf *phys_buf_array,
1130219820Sjeff		     int num_phys_buf,
1131219820Sjeff		     int mr_access_flags,
1132219820Sjeff		     u64 *iova_start)
1133219820Sjeff{
1134219820Sjeff	struct ib_pd *old_pd;
1135219820Sjeff	int ret;
1136219820Sjeff
1137278886Shselasky	ret = ib_check_mr_access(mr_access_flags);
1138278886Shselasky	if (ret)
1139278886Shselasky		return ret;
1140278886Shselasky
1141219820Sjeff	if (!mr->device->rereg_phys_mr)
1142219820Sjeff		return -ENOSYS;
1143219820Sjeff
1144219820Sjeff	if (atomic_read(&mr->usecnt))
1145219820Sjeff		return -EBUSY;
1146219820Sjeff
1147219820Sjeff	old_pd = mr->pd;
1148219820Sjeff
1149219820Sjeff	ret = mr->device->rereg_phys_mr(mr, mr_rereg_mask, pd,
1150219820Sjeff					phys_buf_array, num_phys_buf,
1151219820Sjeff					mr_access_flags, iova_start);
1152219820Sjeff
1153219820Sjeff	if (!ret && (mr_rereg_mask & IB_MR_REREG_PD)) {
1154219820Sjeff		atomic_dec(&old_pd->usecnt);
1155219820Sjeff		atomic_inc(&pd->usecnt);
1156219820Sjeff	}
1157219820Sjeff
1158219820Sjeff	return ret;
1159219820Sjeff}
1160219820SjeffEXPORT_SYMBOL(ib_rereg_phys_mr);
1161219820Sjeff
1162219820Sjeffint ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
1163219820Sjeff{
1164219820Sjeff	return mr->device->query_mr ?
1165219820Sjeff		mr->device->query_mr(mr, mr_attr) : -ENOSYS;
1166219820Sjeff}
1167219820SjeffEXPORT_SYMBOL(ib_query_mr);
1168219820Sjeff
1169219820Sjeffint ib_dereg_mr(struct ib_mr *mr)
1170219820Sjeff{
1171219820Sjeff	struct ib_pd *pd;
1172219820Sjeff	int ret;
1173219820Sjeff
1174219820Sjeff	if (atomic_read(&mr->usecnt))
1175219820Sjeff		return -EBUSY;
1176219820Sjeff
1177219820Sjeff	pd = mr->pd;
1178219820Sjeff	ret = mr->device->dereg_mr(mr);
1179219820Sjeff	if (!ret)
1180219820Sjeff		atomic_dec(&pd->usecnt);
1181219820Sjeff
1182219820Sjeff	return ret;
1183219820Sjeff}
1184219820SjeffEXPORT_SYMBOL(ib_dereg_mr);
1185219820Sjeff
1186278886Shselaskystruct ib_mr *ib_create_mr(struct ib_pd *pd,
1187278886Shselasky			   struct ib_mr_init_attr *mr_init_attr)
1188278886Shselasky{
1189278886Shselasky	struct ib_mr *mr;
1190278886Shselasky
1191278886Shselasky	if (!pd->device->create_mr)
1192278886Shselasky		return ERR_PTR(-ENOSYS);
1193278886Shselasky
1194278886Shselasky	mr = pd->device->create_mr(pd, mr_init_attr);
1195278886Shselasky
1196278886Shselasky	if (!IS_ERR(mr)) {
1197278886Shselasky		mr->device  = pd->device;
1198278886Shselasky		mr->pd      = pd;
1199278886Shselasky		mr->uobject = NULL;
1200278886Shselasky		atomic_inc(&pd->usecnt);
1201278886Shselasky		atomic_set(&mr->usecnt, 0);
1202278886Shselasky	}
1203278886Shselasky
1204278886Shselasky	return mr;
1205278886Shselasky}
1206278886ShselaskyEXPORT_SYMBOL(ib_create_mr);
1207278886Shselasky
1208278886Shselaskyint ib_destroy_mr(struct ib_mr *mr)
1209278886Shselasky{
1210278886Shselasky	struct ib_pd *pd;
1211278886Shselasky	int ret;
1212278886Shselasky
1213278886Shselasky	if (atomic_read(&mr->usecnt))
1214278886Shselasky		return -EBUSY;
1215278886Shselasky
1216278886Shselasky	pd = mr->pd;
1217278886Shselasky	ret = mr->device->destroy_mr(mr);
1218278886Shselasky	if (!ret)
1219278886Shselasky		atomic_dec(&pd->usecnt);
1220278886Shselasky
1221278886Shselasky	return ret;
1222278886Shselasky}
1223278886ShselaskyEXPORT_SYMBOL(ib_destroy_mr);
1224278886Shselasky
1225219820Sjeffstruct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len)
1226219820Sjeff{
1227219820Sjeff	struct ib_mr *mr;
1228219820Sjeff
1229219820Sjeff	if (!pd->device->alloc_fast_reg_mr)
1230219820Sjeff		return ERR_PTR(-ENOSYS);
1231219820Sjeff
1232219820Sjeff	mr = pd->device->alloc_fast_reg_mr(pd, max_page_list_len);
1233219820Sjeff
1234219820Sjeff	if (!IS_ERR(mr)) {
1235219820Sjeff		mr->device  = pd->device;
1236219820Sjeff		mr->pd      = pd;
1237219820Sjeff		mr->uobject = NULL;
1238219820Sjeff		atomic_inc(&pd->usecnt);
1239219820Sjeff		atomic_set(&mr->usecnt, 0);
1240219820Sjeff	}
1241219820Sjeff
1242219820Sjeff	return mr;
1243219820Sjeff}
1244219820SjeffEXPORT_SYMBOL(ib_alloc_fast_reg_mr);
1245219820Sjeff
1246219820Sjeffstruct ib_fast_reg_page_list *ib_alloc_fast_reg_page_list(struct ib_device *device,
1247219820Sjeff							  int max_page_list_len)
1248219820Sjeff{
1249219820Sjeff	struct ib_fast_reg_page_list *page_list;
1250219820Sjeff
1251219820Sjeff	if (!device->alloc_fast_reg_page_list)
1252219820Sjeff		return ERR_PTR(-ENOSYS);
1253219820Sjeff
1254219820Sjeff	page_list = device->alloc_fast_reg_page_list(device, max_page_list_len);
1255219820Sjeff
1256219820Sjeff	if (!IS_ERR(page_list)) {
1257219820Sjeff		page_list->device = device;
1258219820Sjeff		page_list->max_page_list_len = max_page_list_len;
1259219820Sjeff	}
1260219820Sjeff
1261219820Sjeff	return page_list;
1262219820Sjeff}
1263219820SjeffEXPORT_SYMBOL(ib_alloc_fast_reg_page_list);
1264219820Sjeff
1265219820Sjeffvoid ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list)
1266219820Sjeff{
1267219820Sjeff	page_list->device->free_fast_reg_page_list(page_list);
1268219820Sjeff}
1269219820SjeffEXPORT_SYMBOL(ib_free_fast_reg_page_list);
1270219820Sjeff
1271219820Sjeff/* Memory windows */
1272219820Sjeff
1273278886Shselaskystruct ib_mw *ib_alloc_mw(struct ib_pd *pd, enum ib_mw_type type)
1274219820Sjeff{
1275219820Sjeff	struct ib_mw *mw;
1276219820Sjeff
1277219820Sjeff	if (!pd->device->alloc_mw)
1278219820Sjeff		return ERR_PTR(-ENOSYS);
1279219820Sjeff
1280278886Shselasky	mw = pd->device->alloc_mw(pd, type);
1281219820Sjeff	if (!IS_ERR(mw)) {
1282219820Sjeff		mw->device  = pd->device;
1283219820Sjeff		mw->pd      = pd;
1284219820Sjeff		mw->uobject = NULL;
1285278886Shselasky		mw->type    = type;
1286219820Sjeff		atomic_inc(&pd->usecnt);
1287219820Sjeff	}
1288219820Sjeff
1289219820Sjeff	return mw;
1290219820Sjeff}
1291219820SjeffEXPORT_SYMBOL(ib_alloc_mw);
1292219820Sjeff
1293219820Sjeffint ib_dealloc_mw(struct ib_mw *mw)
1294219820Sjeff{
1295219820Sjeff	struct ib_pd *pd;
1296219820Sjeff	int ret;
1297219820Sjeff
1298219820Sjeff	pd = mw->pd;
1299219820Sjeff	ret = mw->device->dealloc_mw(mw);
1300219820Sjeff	if (!ret)
1301219820Sjeff		atomic_dec(&pd->usecnt);
1302219820Sjeff
1303219820Sjeff	return ret;
1304219820Sjeff}
1305219820SjeffEXPORT_SYMBOL(ib_dealloc_mw);
1306219820Sjeff
1307219820Sjeff/* "Fast" memory regions */
1308219820Sjeff
1309219820Sjeffstruct ib_fmr *ib_alloc_fmr(struct ib_pd *pd,
1310219820Sjeff			    int mr_access_flags,
1311219820Sjeff			    struct ib_fmr_attr *fmr_attr)
1312219820Sjeff{
1313219820Sjeff	struct ib_fmr *fmr;
1314219820Sjeff
1315219820Sjeff	if (!pd->device->alloc_fmr)
1316219820Sjeff		return ERR_PTR(-ENOSYS);
1317219820Sjeff
1318219820Sjeff	fmr = pd->device->alloc_fmr(pd, mr_access_flags, fmr_attr);
1319219820Sjeff	if (!IS_ERR(fmr)) {
1320219820Sjeff		fmr->device = pd->device;
1321219820Sjeff		fmr->pd     = pd;
1322219820Sjeff		atomic_inc(&pd->usecnt);
1323219820Sjeff	}
1324219820Sjeff
1325219820Sjeff	return fmr;
1326219820Sjeff}
1327219820SjeffEXPORT_SYMBOL(ib_alloc_fmr);
1328219820Sjeff
1329219820Sjeffint ib_unmap_fmr(struct list_head *fmr_list)
1330219820Sjeff{
1331219820Sjeff	struct ib_fmr *fmr;
1332219820Sjeff
1333219820Sjeff	if (list_empty(fmr_list))
1334219820Sjeff		return 0;
1335219820Sjeff
1336219820Sjeff	fmr = list_entry(fmr_list->next, struct ib_fmr, list);
1337219820Sjeff	return fmr->device->unmap_fmr(fmr_list);
1338219820Sjeff}
1339219820SjeffEXPORT_SYMBOL(ib_unmap_fmr);
1340219820Sjeff
1341219820Sjeffint ib_dealloc_fmr(struct ib_fmr *fmr)
1342219820Sjeff{
1343219820Sjeff	struct ib_pd *pd;
1344219820Sjeff	int ret;
1345219820Sjeff
1346219820Sjeff	pd = fmr->pd;
1347219820Sjeff	ret = fmr->device->dealloc_fmr(fmr);
1348219820Sjeff	if (!ret)
1349219820Sjeff		atomic_dec(&pd->usecnt);
1350219820Sjeff
1351219820Sjeff	return ret;
1352219820Sjeff}
1353219820SjeffEXPORT_SYMBOL(ib_dealloc_fmr);
1354219820Sjeff
1355219820Sjeff/* Multicast groups */
1356219820Sjeff
1357219820Sjeffint ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
1358219820Sjeff{
1359278886Shselasky	int ret;
1360278886Shselasky
1361219820Sjeff	if (!qp->device->attach_mcast)
1362219820Sjeff		return -ENOSYS;
1363219820Sjeff
1364219820Sjeff	switch (rdma_node_get_transport(qp->device->node_type)) {
1365219820Sjeff	case RDMA_TRANSPORT_IB:
1366278886Shselasky		if ((gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD) &&
1367278886Shselasky		    qp->qp_type != IB_QPT_RAW_PACKET)
1368219820Sjeff			return -EINVAL;
1369219820Sjeff		break;
1370219820Sjeff	case RDMA_TRANSPORT_IWARP:
1371278886Shselasky	case RDMA_TRANSPORT_SCIF:
1372255932Salfred		if (qp->qp_type != IB_QPT_RAW_PACKET)
1373219820Sjeff			return -EINVAL;
1374219820Sjeff		break;
1375219820Sjeff	}
1376278886Shselasky
1377278886Shselasky	ret = qp->device->attach_mcast(qp, gid, lid);
1378278886Shselasky	if (!ret)
1379278886Shselasky		atomic_inc(&qp->usecnt);
1380278886Shselasky	return ret;
1381219820Sjeff}
1382219820SjeffEXPORT_SYMBOL(ib_attach_mcast);
1383219820Sjeff
1384219820Sjeffint ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
1385219820Sjeff{
1386278886Shselasky	int ret;
1387278886Shselasky
1388219820Sjeff	if (!qp->device->detach_mcast)
1389219820Sjeff		return -ENOSYS;
1390219820Sjeff
1391219820Sjeff	switch (rdma_node_get_transport(qp->device->node_type)) {
1392219820Sjeff	case RDMA_TRANSPORT_IB:
1393278886Shselasky		if ((gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD) &&
1394278886Shselasky		    qp->qp_type != IB_QPT_RAW_PACKET)
1395219820Sjeff			return -EINVAL;
1396219820Sjeff		break;
1397219820Sjeff	case RDMA_TRANSPORT_IWARP:
1398278886Shselasky	case RDMA_TRANSPORT_SCIF:
1399278886Shselasky
1400255932Salfred		if (qp->qp_type != IB_QPT_RAW_PACKET)
1401219820Sjeff			return -EINVAL;
1402219820Sjeff		break;
1403219820Sjeff	}
1404278886Shselasky
1405278886Shselasky	ret = qp->device->detach_mcast(qp, gid, lid);
1406278886Shselasky	if (!ret)
1407278886Shselasky		atomic_dec(&qp->usecnt);
1408278886Shselasky	return ret;
1409219820Sjeff}
1410219820SjeffEXPORT_SYMBOL(ib_detach_mcast);
1411219820Sjeff
1412219820Sjeffstruct ib_xrcd *ib_alloc_xrcd(struct ib_device *device)
1413219820Sjeff{
1414219820Sjeff	struct ib_xrcd *xrcd;
1415219820Sjeff
1416219820Sjeff	if (!device->alloc_xrcd)
1417219820Sjeff		return ERR_PTR(-ENOSYS);
1418219820Sjeff
1419219820Sjeff	xrcd = device->alloc_xrcd(device, NULL, NULL);
1420219820Sjeff	if (!IS_ERR(xrcd)) {
1421219820Sjeff		xrcd->device = device;
1422219820Sjeff		xrcd->inode = NULL;
1423219820Sjeff		atomic_set(&xrcd->usecnt, 0);
1424278886Shselasky		mutex_init(&xrcd->tgt_qp_mutex);
1425278886Shselasky		INIT_LIST_HEAD(&xrcd->tgt_qp_list);
1426219820Sjeff	}
1427278886Shselasky
1428219820Sjeff	return xrcd;
1429219820Sjeff}
1430219820SjeffEXPORT_SYMBOL(ib_alloc_xrcd);
1431219820Sjeff
1432278886Shselaskyint ib_dealloc_xrcd(struct ib_xrcd *xrcd)
1433278886Shselasky{
1434278886Shselasky	struct ib_qp *qp;
1435278886Shselasky	int ret;
1436278886Shselasky
1437278886Shselasky	if (atomic_read(&xrcd->usecnt))
1438278886Shselasky		return -EBUSY;
1439278886Shselasky
1440278886Shselasky	while (!list_empty(&xrcd->tgt_qp_list)) {
1441278886Shselasky		qp = list_entry(xrcd->tgt_qp_list.next, struct ib_qp, xrcd_list);
1442278886Shselasky		ret = ib_destroy_qp(qp);
1443278886Shselasky		if (ret)
1444278886Shselasky			return ret;
1445278886Shselasky	}
1446278886Shselasky
1447278886Shselasky	return xrcd->device->dealloc_xrcd(xrcd);
1448278886Shselasky}
1449278886ShselaskyEXPORT_SYMBOL(ib_dealloc_xrcd);
1450278886Shselasky
1451278886Shselaskystruct ib_flow *ib_create_flow(struct ib_qp *qp,
1452278886Shselasky			       struct ib_flow_attr *flow_attr,
1453278886Shselasky			       int domain)
1454278886Shselasky{
1455278886Shselasky	struct ib_flow *flow_id;
1456278886Shselasky	if (!qp->device->create_flow)
1457278886Shselasky		return ERR_PTR(-ENOSYS);
1458278886Shselasky
1459278886Shselasky	flow_id = qp->device->create_flow(qp, flow_attr, domain);
1460278886Shselasky	if (!IS_ERR(flow_id))
1461278886Shselasky		atomic_inc(&qp->usecnt);
1462278886Shselasky	return flow_id;
1463278886Shselasky}
1464278886ShselaskyEXPORT_SYMBOL(ib_create_flow);
1465278886Shselasky
1466278886Shselaskyint ib_destroy_flow(struct ib_flow *flow_id)
1467278886Shselasky{
1468278886Shselasky	int err;
1469278886Shselasky	struct ib_qp *qp;
1470278886Shselasky
1471278886Shselasky	if (!flow_id)
1472278886Shselasky		return -EINVAL;
1473278886Shselasky	qp = flow_id->qp;
1474278886Shselasky	if (!qp->device->destroy_flow)
1475278886Shselasky		return -ENOSYS;
1476278886Shselasky	err = qp->device->destroy_flow(flow_id);
1477278886Shselasky	if (!err)
1478278886Shselasky		atomic_dec(&qp->usecnt);
1479278886Shselasky	return err;
1480278886Shselasky}
1481278886ShselaskyEXPORT_SYMBOL(ib_destroy_flow);
1482278886Shselasky
1483278886Shselaskystruct ib_dct *ib_create_dct(struct ib_pd *pd, struct ib_dct_init_attr *attr,
1484278886Shselasky			     struct ib_udata *udata)
1485278886Shselasky{
1486278886Shselasky	struct ib_dct *dct;
1487278886Shselasky
1488278886Shselasky	if (!pd->device->exp_create_dct)
1489278886Shselasky		return ERR_PTR(-ENOSYS);
1490278886Shselasky
1491278886Shselasky	dct = pd->device->exp_create_dct(pd, attr, udata);
1492278886Shselasky	if (!IS_ERR(dct)) {
1493278886Shselasky		dct->pd = pd;
1494278886Shselasky		dct->srq = attr->srq;
1495278886Shselasky		dct->cq = attr->cq;
1496278886Shselasky		atomic_inc(&dct->srq->usecnt);
1497278886Shselasky		atomic_inc(&dct->cq->usecnt);
1498278886Shselasky		atomic_inc(&dct->pd->usecnt);
1499278886Shselasky	}
1500278886Shselasky
1501278886Shselasky	return dct;
1502278886Shselasky}
1503278886ShselaskyEXPORT_SYMBOL(ib_create_dct);
1504278886Shselasky
1505278886Shselaskyint ib_destroy_dct(struct ib_dct *dct)
1506278886Shselasky{
1507278886Shselasky	int err;
1508278886Shselasky
1509278886Shselasky	if (!dct->device->exp_destroy_dct)
1510278886Shselasky		return -ENOSYS;
1511278886Shselasky
1512278886Shselasky	err = dct->device->exp_destroy_dct(dct);
1513278886Shselasky	if (!err) {
1514278886Shselasky		atomic_dec(&dct->srq->usecnt);
1515278886Shselasky		atomic_dec(&dct->cq->usecnt);
1516278886Shselasky		atomic_dec(&dct->pd->usecnt);
1517278886Shselasky	}
1518278886Shselasky
1519278886Shselasky	return err;
1520278886Shselasky}
1521278886ShselaskyEXPORT_SYMBOL(ib_destroy_dct);
1522278886Shselasky
1523278886Shselaskyint ib_query_dct(struct ib_dct *dct, struct ib_dct_attr *attr)
1524278886Shselasky{
1525278886Shselasky	if (!dct->device->exp_query_dct)
1526278886Shselasky		return -ENOSYS;
1527278886Shselasky
1528278886Shselasky	return dct->device->exp_query_dct(dct, attr);
1529278886Shselasky}
1530278886ShselaskyEXPORT_SYMBOL(ib_query_dct);
1531278886Shselasky
1532278886Shselaskyint ib_check_mr_status(struct ib_mr *mr, u32 check_mask,
1533278886Shselasky		       struct ib_mr_status *mr_status)
1534278886Shselasky{
1535278886Shselasky	return mr->device->check_mr_status ?
1536278886Shselasky		mr->device->check_mr_status(mr, check_mask, mr_status) : -ENOSYS;
1537278886Shselasky}
1538278886ShselaskyEXPORT_SYMBOL(ib_check_mr_status);
1539