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>
41219820Sjeff#include <linux/string.h>
42219820Sjeff
43219820Sjeff#include <rdma/ib_verbs.h>
44219820Sjeff#include <rdma/ib_cache.h>
45219820Sjeff
46219820Sjeffint ib_rate_to_mult(enum ib_rate rate)
47219820Sjeff{
48219820Sjeff	switch (rate) {
49219820Sjeff	case IB_RATE_2_5_GBPS: return  1;
50219820Sjeff	case IB_RATE_5_GBPS:   return  2;
51219820Sjeff	case IB_RATE_10_GBPS:  return  4;
52219820Sjeff	case IB_RATE_20_GBPS:  return  8;
53219820Sjeff	case IB_RATE_30_GBPS:  return 12;
54219820Sjeff	case IB_RATE_40_GBPS:  return 16;
55219820Sjeff	case IB_RATE_60_GBPS:  return 24;
56219820Sjeff	case IB_RATE_80_GBPS:  return 32;
57219820Sjeff	case IB_RATE_120_GBPS: return 48;
58219820Sjeff	default:	       return -1;
59219820Sjeff	}
60219820Sjeff}
61219820SjeffEXPORT_SYMBOL(ib_rate_to_mult);
62219820Sjeff
63219820Sjeffenum ib_rate mult_to_ib_rate(int mult)
64219820Sjeff{
65219820Sjeff	switch (mult) {
66219820Sjeff	case 1:  return IB_RATE_2_5_GBPS;
67219820Sjeff	case 2:  return IB_RATE_5_GBPS;
68219820Sjeff	case 4:  return IB_RATE_10_GBPS;
69219820Sjeff	case 8:  return IB_RATE_20_GBPS;
70219820Sjeff	case 12: return IB_RATE_30_GBPS;
71219820Sjeff	case 16: return IB_RATE_40_GBPS;
72219820Sjeff	case 24: return IB_RATE_60_GBPS;
73219820Sjeff	case 32: return IB_RATE_80_GBPS;
74219820Sjeff	case 48: return IB_RATE_120_GBPS;
75219820Sjeff	default: return IB_RATE_PORT_CURRENT;
76219820Sjeff	}
77219820Sjeff}
78219820SjeffEXPORT_SYMBOL(mult_to_ib_rate);
79219820Sjeff
80219820Sjeffenum rdma_transport_type
81219820Sjeffrdma_node_get_transport(enum rdma_node_type node_type)
82219820Sjeff{
83219820Sjeff	switch (node_type) {
84219820Sjeff	case RDMA_NODE_IB_CA:
85219820Sjeff	case RDMA_NODE_IB_SWITCH:
86219820Sjeff	case RDMA_NODE_IB_ROUTER:
87219820Sjeff		return RDMA_TRANSPORT_IB;
88219820Sjeff	case RDMA_NODE_RNIC:
89219820Sjeff		return RDMA_TRANSPORT_IWARP;
90219820Sjeff	default:
91219820Sjeff		BUG();
92219820Sjeff		return 0;
93219820Sjeff	}
94219820Sjeff}
95219820SjeffEXPORT_SYMBOL(rdma_node_get_transport);
96219820Sjeff
97219820Sjeffenum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device, u8 port_num)
98219820Sjeff{
99219820Sjeff	if (device->get_link_layer)
100219820Sjeff		return device->get_link_layer(device, port_num);
101219820Sjeff
102219820Sjeff	switch (rdma_node_get_transport(device->node_type)) {
103219820Sjeff	case RDMA_TRANSPORT_IB:
104219820Sjeff		return IB_LINK_LAYER_INFINIBAND;
105219820Sjeff	case RDMA_TRANSPORT_IWARP:
106219820Sjeff		return IB_LINK_LAYER_ETHERNET;
107219820Sjeff	default:
108219820Sjeff		return IB_LINK_LAYER_UNSPECIFIED;
109219820Sjeff	}
110219820Sjeff}
111219820SjeffEXPORT_SYMBOL(rdma_port_get_link_layer);
112219820Sjeff
113219820Sjeff/* Protection domains */
114219820Sjeff
115219820Sjeffstruct ib_pd *ib_alloc_pd(struct ib_device *device)
116219820Sjeff{
117219820Sjeff	struct ib_pd *pd;
118219820Sjeff
119219820Sjeff	pd = device->alloc_pd(device, NULL, NULL);
120219820Sjeff
121219820Sjeff	if (!IS_ERR(pd)) {
122219820Sjeff		pd->device  = device;
123219820Sjeff		pd->uobject = NULL;
124219820Sjeff		atomic_set(&pd->usecnt, 0);
125219820Sjeff	}
126219820Sjeff
127219820Sjeff	return pd;
128219820Sjeff}
129219820SjeffEXPORT_SYMBOL(ib_alloc_pd);
130219820Sjeff
131219820Sjeffint ib_dealloc_pd(struct ib_pd *pd)
132219820Sjeff{
133219820Sjeff	if (atomic_read(&pd->usecnt))
134219820Sjeff		return -EBUSY;
135219820Sjeff
136219820Sjeff	return pd->device->dealloc_pd(pd);
137219820Sjeff}
138219820SjeffEXPORT_SYMBOL(ib_dealloc_pd);
139219820Sjeff
140219820Sjeff/* Address handles */
141219820Sjeff
142219820Sjeffstruct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
143219820Sjeff{
144219820Sjeff	struct ib_ah *ah;
145219820Sjeff
146219820Sjeff	ah = pd->device->create_ah(pd, ah_attr);
147219820Sjeff
148219820Sjeff	if (!IS_ERR(ah)) {
149219820Sjeff		ah->device  = pd->device;
150219820Sjeff		ah->pd      = pd;
151219820Sjeff		ah->uobject = NULL;
152219820Sjeff		atomic_inc(&pd->usecnt);
153219820Sjeff	}
154219820Sjeff
155219820Sjeff	return ah;
156219820Sjeff}
157219820SjeffEXPORT_SYMBOL(ib_create_ah);
158219820Sjeff
159219820Sjeffint ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc,
160219820Sjeff		       struct ib_grh *grh, struct ib_ah_attr *ah_attr)
161219820Sjeff{
162219820Sjeff	u32 flow_class;
163219820Sjeff	u16 gid_index;
164219820Sjeff	int ret;
165219820Sjeff
166219820Sjeff	memset(ah_attr, 0, sizeof *ah_attr);
167219820Sjeff	ah_attr->dlid = wc->slid;
168219820Sjeff	ah_attr->sl = wc->sl;
169219820Sjeff	ah_attr->src_path_bits = wc->dlid_path_bits;
170219820Sjeff	ah_attr->port_num = port_num;
171219820Sjeff
172219820Sjeff	if (wc->wc_flags & IB_WC_GRH) {
173219820Sjeff		ah_attr->ah_flags = IB_AH_GRH;
174219820Sjeff		ah_attr->grh.dgid = grh->sgid;
175219820Sjeff
176219820Sjeff		ret = ib_find_cached_gid(device, &grh->dgid, &port_num,
177219820Sjeff					 &gid_index);
178219820Sjeff		if (ret)
179219820Sjeff			return ret;
180219820Sjeff
181219820Sjeff		ah_attr->grh.sgid_index = (u8) gid_index;
182219820Sjeff		flow_class = be32_to_cpu(grh->version_tclass_flow);
183219820Sjeff		ah_attr->grh.flow_label = flow_class & 0xFFFFF;
184219820Sjeff		ah_attr->grh.hop_limit = 0xFF;
185219820Sjeff		ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
186219820Sjeff	}
187219820Sjeff	return 0;
188219820Sjeff}
189219820SjeffEXPORT_SYMBOL(ib_init_ah_from_wc);
190219820Sjeff
191219820Sjeffstruct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc,
192219820Sjeff				   struct ib_grh *grh, u8 port_num)
193219820Sjeff{
194219820Sjeff	struct ib_ah_attr ah_attr;
195219820Sjeff	int ret;
196219820Sjeff
197219820Sjeff	ret = ib_init_ah_from_wc(pd->device, port_num, wc, grh, &ah_attr);
198219820Sjeff	if (ret)
199219820Sjeff		return ERR_PTR(ret);
200219820Sjeff
201219820Sjeff	return ib_create_ah(pd, &ah_attr);
202219820Sjeff}
203219820SjeffEXPORT_SYMBOL(ib_create_ah_from_wc);
204219820Sjeff
205219820Sjeffint ib_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
206219820Sjeff{
207219820Sjeff	return ah->device->modify_ah ?
208219820Sjeff		ah->device->modify_ah(ah, ah_attr) :
209219820Sjeff		-ENOSYS;
210219820Sjeff}
211219820SjeffEXPORT_SYMBOL(ib_modify_ah);
212219820Sjeff
213219820Sjeffint ib_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
214219820Sjeff{
215219820Sjeff	return ah->device->query_ah ?
216219820Sjeff		ah->device->query_ah(ah, ah_attr) :
217219820Sjeff		-ENOSYS;
218219820Sjeff}
219219820SjeffEXPORT_SYMBOL(ib_query_ah);
220219820Sjeff
221219820Sjeffint ib_destroy_ah(struct ib_ah *ah)
222219820Sjeff{
223219820Sjeff	struct ib_pd *pd;
224219820Sjeff	int ret;
225219820Sjeff
226219820Sjeff	pd = ah->pd;
227219820Sjeff	ret = ah->device->destroy_ah(ah);
228219820Sjeff	if (!ret)
229219820Sjeff		atomic_dec(&pd->usecnt);
230219820Sjeff
231219820Sjeff	return ret;
232219820Sjeff}
233219820SjeffEXPORT_SYMBOL(ib_destroy_ah);
234219820Sjeff
235219820Sjeff/* Shared receive queues */
236219820Sjeff
237219820Sjeffstruct ib_srq *ib_create_srq(struct ib_pd *pd,
238219820Sjeff			     struct ib_srq_init_attr *srq_init_attr)
239219820Sjeff{
240219820Sjeff	struct ib_srq *srq;
241219820Sjeff
242219820Sjeff	if (!pd->device->create_srq)
243219820Sjeff		return ERR_PTR(-ENOSYS);
244219820Sjeff
245219820Sjeff	srq = pd->device->create_srq(pd, srq_init_attr, NULL);
246219820Sjeff
247219820Sjeff	if (!IS_ERR(srq)) {
248219820Sjeff		srq->device    	   = pd->device;
249219820Sjeff		srq->pd        	   = pd;
250219820Sjeff		srq->uobject       = NULL;
251219820Sjeff		srq->event_handler = srq_init_attr->event_handler;
252219820Sjeff		srq->srq_context   = srq_init_attr->srq_context;
253219820Sjeff		srq->xrc_cq = NULL;
254219820Sjeff		srq->xrcd = NULL;
255219820Sjeff		atomic_inc(&pd->usecnt);
256219820Sjeff		atomic_set(&srq->usecnt, 0);
257219820Sjeff	}
258219820Sjeff
259219820Sjeff	return srq;
260219820Sjeff}
261219820SjeffEXPORT_SYMBOL(ib_create_srq);
262219820Sjeff
263219820Sjeffstruct ib_srq *ib_create_xrc_srq(struct ib_pd *pd,
264219820Sjeff				 struct ib_cq *xrc_cq,
265219820Sjeff				 struct ib_xrcd *xrcd,
266219820Sjeff				 struct ib_srq_init_attr *srq_init_attr)
267219820Sjeff{
268219820Sjeff	struct ib_srq *srq;
269219820Sjeff
270219820Sjeff	if (!pd->device->create_xrc_srq)
271219820Sjeff		return ERR_PTR(-ENOSYS);
272219820Sjeff
273219820Sjeff	srq = pd->device->create_xrc_srq(pd, xrc_cq, xrcd, srq_init_attr, NULL);
274219820Sjeff
275219820Sjeff	if (!IS_ERR(srq)) {
276219820Sjeff		srq->device	   = pd->device;
277219820Sjeff		srq->pd		   = pd;
278219820Sjeff		srq->uobject	   = NULL;
279219820Sjeff		srq->event_handler = srq_init_attr->event_handler;
280219820Sjeff		srq->srq_context   = srq_init_attr->srq_context;
281219820Sjeff		srq->xrc_cq	   = xrc_cq;
282219820Sjeff		srq->xrcd	   = xrcd;
283219820Sjeff		atomic_inc(&pd->usecnt);
284219820Sjeff		atomic_inc(&xrcd->usecnt);
285219820Sjeff		atomic_inc(&xrc_cq->usecnt);
286219820Sjeff		atomic_set(&srq->usecnt, 0);
287219820Sjeff	}
288219820Sjeff
289219820Sjeff	return srq;
290219820Sjeff}
291219820SjeffEXPORT_SYMBOL(ib_create_xrc_srq);
292219820Sjeff
293219820Sjeffint ib_modify_srq(struct ib_srq *srq,
294219820Sjeff		  struct ib_srq_attr *srq_attr,
295219820Sjeff		  enum ib_srq_attr_mask srq_attr_mask)
296219820Sjeff{
297219820Sjeff	return srq->device->modify_srq ?
298219820Sjeff		srq->device->modify_srq(srq, srq_attr, srq_attr_mask, NULL) :
299219820Sjeff		-ENOSYS;
300219820Sjeff}
301219820SjeffEXPORT_SYMBOL(ib_modify_srq);
302219820Sjeff
303219820Sjeffint ib_query_srq(struct ib_srq *srq,
304219820Sjeff		 struct ib_srq_attr *srq_attr)
305219820Sjeff{
306219820Sjeff	return srq->device->query_srq ?
307219820Sjeff		srq->device->query_srq(srq, srq_attr) : -ENOSYS;
308219820Sjeff}
309219820SjeffEXPORT_SYMBOL(ib_query_srq);
310219820Sjeff
311219820Sjeffint ib_destroy_srq(struct ib_srq *srq)
312219820Sjeff{
313219820Sjeff	struct ib_pd *pd;
314219820Sjeff	struct ib_cq *xrc_cq;
315219820Sjeff	struct ib_xrcd *xrcd;
316219820Sjeff	int ret;
317219820Sjeff
318219820Sjeff	if (atomic_read(&srq->usecnt))
319219820Sjeff		return -EBUSY;
320219820Sjeff
321219820Sjeff	pd = srq->pd;
322219820Sjeff	xrc_cq = srq->xrc_cq;
323219820Sjeff	xrcd = srq->xrcd;
324219820Sjeff
325219820Sjeff	ret = srq->device->destroy_srq(srq);
326219820Sjeff	if (!ret) {
327219820Sjeff		atomic_dec(&pd->usecnt);
328219820Sjeff		if (xrc_cq)
329219820Sjeff			atomic_dec(&xrc_cq->usecnt);
330219820Sjeff		if (xrcd)
331219820Sjeff			atomic_dec(&xrcd->usecnt);
332219820Sjeff	}
333219820Sjeff
334219820Sjeff	return ret;
335219820Sjeff}
336219820SjeffEXPORT_SYMBOL(ib_destroy_srq);
337219820Sjeff
338219820Sjeff/* Queue pairs */
339219820Sjeff
340219820Sjeffstruct ib_qp *ib_create_qp(struct ib_pd *pd,
341219820Sjeff			   struct ib_qp_init_attr *qp_init_attr)
342219820Sjeff{
343219820Sjeff	struct ib_qp *qp;
344219820Sjeff
345219820Sjeff	qp = pd->device->create_qp(pd, qp_init_attr, NULL);
346219820Sjeff
347219820Sjeff	if (!IS_ERR(qp)) {
348219820Sjeff		qp->device     	  = pd->device;
349219820Sjeff		qp->pd         	  = pd;
350219820Sjeff		qp->send_cq    	  = qp_init_attr->send_cq;
351219820Sjeff		qp->recv_cq    	  = qp_init_attr->recv_cq;
352219820Sjeff		qp->srq	       	  = qp_init_attr->srq;
353219820Sjeff		qp->uobject       = NULL;
354219820Sjeff		qp->event_handler = qp_init_attr->event_handler;
355219820Sjeff		qp->qp_context    = qp_init_attr->qp_context;
356219820Sjeff		qp->qp_type	  = qp_init_attr->qp_type;
357219820Sjeff		qp->xrcd	  = qp->qp_type == IB_QPT_XRC ?
358219820Sjeff			qp_init_attr->xrc_domain : NULL;
359219820Sjeff		atomic_inc(&pd->usecnt);
360219820Sjeff		atomic_inc(&qp_init_attr->send_cq->usecnt);
361219820Sjeff		atomic_inc(&qp_init_attr->recv_cq->usecnt);
362219820Sjeff		if (qp_init_attr->srq)
363219820Sjeff			atomic_inc(&qp_init_attr->srq->usecnt);
364219820Sjeff		if (qp->qp_type == IB_QPT_XRC)
365219820Sjeff			atomic_inc(&qp->xrcd->usecnt);
366219820Sjeff	}
367219820Sjeff
368219820Sjeff	return qp;
369219820Sjeff}
370219820SjeffEXPORT_SYMBOL(ib_create_qp);
371219820Sjeff
372219820Sjeffstatic const struct {
373219820Sjeff	int			valid;
374219820Sjeff	enum ib_qp_attr_mask	req_param[IB_QPT_RAW_ETH + 1];
375219820Sjeff	enum ib_qp_attr_mask	opt_param[IB_QPT_RAW_ETH + 1];
376219820Sjeff} qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
377219820Sjeff	[IB_QPS_RESET] = {
378219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
379219820Sjeff		[IB_QPS_INIT]  = {
380219820Sjeff			.valid = 1,
381219820Sjeff			.req_param = {
382219820Sjeff				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
383219820Sjeff						IB_QP_PORT			|
384219820Sjeff						IB_QP_QKEY),
385219820Sjeff				[IB_QPT_RAW_ETH] = IB_QP_PORT,
386219820Sjeff				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
387219820Sjeff						IB_QP_PORT			|
388219820Sjeff						IB_QP_ACCESS_FLAGS),
389219820Sjeff				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
390219820Sjeff						IB_QP_PORT			|
391219820Sjeff						IB_QP_ACCESS_FLAGS),
392219820Sjeff				[IB_QPT_XRC] = (IB_QP_PKEY_INDEX		|
393219820Sjeff						IB_QP_PORT			|
394219820Sjeff						IB_QP_ACCESS_FLAGS),
395219820Sjeff				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
396219820Sjeff						IB_QP_QKEY),
397219820Sjeff				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
398219820Sjeff						IB_QP_QKEY),
399219820Sjeff			}
400219820Sjeff		},
401219820Sjeff	},
402219820Sjeff	[IB_QPS_INIT]  = {
403219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
404219820Sjeff		[IB_QPS_ERR] =   { .valid = 1 },
405219820Sjeff		[IB_QPS_INIT]  = {
406219820Sjeff			.valid = 1,
407219820Sjeff			.opt_param = {
408219820Sjeff				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
409219820Sjeff						IB_QP_PORT			|
410219820Sjeff						IB_QP_QKEY),
411219820Sjeff				[IB_QPT_UC]  = (IB_QP_PKEY_INDEX		|
412219820Sjeff						IB_QP_PORT			|
413219820Sjeff						IB_QP_ACCESS_FLAGS),
414219820Sjeff				[IB_QPT_RC]  = (IB_QP_PKEY_INDEX		|
415219820Sjeff						IB_QP_PORT			|
416219820Sjeff						IB_QP_ACCESS_FLAGS),
417219820Sjeff				[IB_QPT_XRC] = (IB_QP_PKEY_INDEX		|
418219820Sjeff						IB_QP_PORT			|
419219820Sjeff						IB_QP_ACCESS_FLAGS),
420219820Sjeff				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
421219820Sjeff						IB_QP_QKEY),
422219820Sjeff				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
423219820Sjeff						IB_QP_QKEY),
424219820Sjeff			}
425219820Sjeff		},
426219820Sjeff		[IB_QPS_RTR]   = {
427219820Sjeff			.valid = 1,
428219820Sjeff			.req_param = {
429219820Sjeff				[IB_QPT_UC]  = (IB_QP_AV			|
430219820Sjeff						IB_QP_PATH_MTU			|
431219820Sjeff						IB_QP_DEST_QPN			|
432219820Sjeff						IB_QP_RQ_PSN),
433219820Sjeff				[IB_QPT_RC]  = (IB_QP_AV			|
434219820Sjeff						IB_QP_PATH_MTU			|
435219820Sjeff						IB_QP_DEST_QPN			|
436219820Sjeff						IB_QP_RQ_PSN			|
437219820Sjeff						IB_QP_MAX_DEST_RD_ATOMIC	|
438219820Sjeff						IB_QP_MIN_RNR_TIMER),
439219820Sjeff				[IB_QPT_XRC] = (IB_QP_AV			|
440219820Sjeff						IB_QP_PATH_MTU			|
441219820Sjeff						IB_QP_DEST_QPN			|
442219820Sjeff						IB_QP_RQ_PSN			|
443219820Sjeff						IB_QP_MAX_DEST_RD_ATOMIC	|
444219820Sjeff						IB_QP_MIN_RNR_TIMER),
445219820Sjeff			},
446219820Sjeff			.opt_param = {
447219820Sjeff				 [IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
448219820Sjeff						 IB_QP_QKEY),
449219820Sjeff				 [IB_QPT_UC]  = (IB_QP_ALT_PATH			|
450219820Sjeff						 IB_QP_ACCESS_FLAGS		|
451219820Sjeff						 IB_QP_PKEY_INDEX),
452219820Sjeff				 [IB_QPT_RC]  = (IB_QP_ALT_PATH			|
453219820Sjeff						 IB_QP_ACCESS_FLAGS		|
454219820Sjeff						 IB_QP_PKEY_INDEX),
455219820Sjeff				 [IB_QPT_XRC] = (IB_QP_ALT_PATH			|
456219820Sjeff						IB_QP_ACCESS_FLAGS		|
457219820Sjeff						IB_QP_PKEY_INDEX),
458219820Sjeff				 [IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
459219820Sjeff						 IB_QP_QKEY),
460219820Sjeff				 [IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
461219820Sjeff						 IB_QP_QKEY),
462219820Sjeff			 }
463219820Sjeff		}
464219820Sjeff	},
465219820Sjeff	[IB_QPS_RTR]   = {
466219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
467219820Sjeff		[IB_QPS_ERR] =   { .valid = 1 },
468219820Sjeff		[IB_QPS_RTS]   = {
469219820Sjeff			.valid = 1,
470219820Sjeff			.req_param = {
471219820Sjeff				[IB_QPT_UD]  = IB_QP_SQ_PSN,
472219820Sjeff				[IB_QPT_UC]  = IB_QP_SQ_PSN,
473219820Sjeff				[IB_QPT_RC]  = (IB_QP_TIMEOUT			|
474219820Sjeff						IB_QP_RETRY_CNT			|
475219820Sjeff						IB_QP_RNR_RETRY			|
476219820Sjeff						IB_QP_SQ_PSN			|
477219820Sjeff						IB_QP_MAX_QP_RD_ATOMIC),
478219820Sjeff				[IB_QPT_XRC] = (IB_QP_TIMEOUT			|
479219820Sjeff						IB_QP_RETRY_CNT			|
480219820Sjeff						IB_QP_RNR_RETRY			|
481219820Sjeff						IB_QP_SQ_PSN			|
482219820Sjeff						IB_QP_MAX_QP_RD_ATOMIC),
483219820Sjeff				[IB_QPT_SMI] = IB_QP_SQ_PSN,
484219820Sjeff				[IB_QPT_GSI] = IB_QP_SQ_PSN,
485219820Sjeff			},
486219820Sjeff			.opt_param = {
487219820Sjeff				 [IB_QPT_UD]  = (IB_QP_CUR_STATE		|
488219820Sjeff						 IB_QP_QKEY),
489219820Sjeff				 [IB_QPT_UC]  = (IB_QP_CUR_STATE		|
490219820Sjeff						 IB_QP_ALT_PATH			|
491219820Sjeff						 IB_QP_ACCESS_FLAGS		|
492219820Sjeff						 IB_QP_PATH_MIG_STATE),
493219820Sjeff				 [IB_QPT_RC]  = (IB_QP_CUR_STATE		|
494219820Sjeff						 IB_QP_ALT_PATH			|
495219820Sjeff						 IB_QP_ACCESS_FLAGS		|
496219820Sjeff						 IB_QP_MIN_RNR_TIMER		|
497219820Sjeff						 IB_QP_PATH_MIG_STATE),
498219820Sjeff				 [IB_QPT_XRC] = (IB_QP_CUR_STATE		|
499219820Sjeff						IB_QP_ALT_PATH			|
500219820Sjeff						IB_QP_ACCESS_FLAGS		|
501219820Sjeff						IB_QP_MIN_RNR_TIMER		|
502219820Sjeff						IB_QP_PATH_MIG_STATE),
503219820Sjeff				 [IB_QPT_SMI] = (IB_QP_CUR_STATE		|
504219820Sjeff						 IB_QP_QKEY),
505219820Sjeff				 [IB_QPT_GSI] = (IB_QP_CUR_STATE		|
506219820Sjeff						 IB_QP_QKEY),
507219820Sjeff			 }
508219820Sjeff		}
509219820Sjeff	},
510219820Sjeff	[IB_QPS_RTS]   = {
511219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
512219820Sjeff		[IB_QPS_ERR] =   { .valid = 1 },
513219820Sjeff		[IB_QPS_RTS]   = {
514219820Sjeff			.valid = 1,
515219820Sjeff			.opt_param = {
516219820Sjeff				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
517219820Sjeff						IB_QP_QKEY),
518219820Sjeff				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
519219820Sjeff						IB_QP_ACCESS_FLAGS		|
520219820Sjeff						IB_QP_ALT_PATH			|
521219820Sjeff						IB_QP_PATH_MIG_STATE),
522219820Sjeff				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
523219820Sjeff						IB_QP_ACCESS_FLAGS		|
524219820Sjeff						IB_QP_ALT_PATH			|
525219820Sjeff						IB_QP_PATH_MIG_STATE		|
526219820Sjeff						IB_QP_MIN_RNR_TIMER),
527219820Sjeff				[IB_QPT_XRC] = (IB_QP_CUR_STATE			|
528219820Sjeff						IB_QP_ACCESS_FLAGS		|
529219820Sjeff						IB_QP_ALT_PATH			|
530219820Sjeff						IB_QP_PATH_MIG_STATE		|
531219820Sjeff						IB_QP_MIN_RNR_TIMER),
532219820Sjeff				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
533219820Sjeff						IB_QP_QKEY),
534219820Sjeff				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
535219820Sjeff						IB_QP_QKEY),
536219820Sjeff			}
537219820Sjeff		},
538219820Sjeff		[IB_QPS_SQD]   = {
539219820Sjeff			.valid = 1,
540219820Sjeff			.opt_param = {
541219820Sjeff				[IB_QPT_UD]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
542219820Sjeff				[IB_QPT_UC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
543219820Sjeff				[IB_QPT_RC]  = IB_QP_EN_SQD_ASYNC_NOTIFY,
544219820Sjeff				[IB_QPT_XRC] = IB_QP_EN_SQD_ASYNC_NOTIFY,
545219820Sjeff				[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
546219820Sjeff				[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
547219820Sjeff			}
548219820Sjeff		},
549219820Sjeff	},
550219820Sjeff	[IB_QPS_SQD]   = {
551219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
552219820Sjeff		[IB_QPS_ERR] =   { .valid = 1 },
553219820Sjeff		[IB_QPS_RTS]   = {
554219820Sjeff			.valid = 1,
555219820Sjeff			.opt_param = {
556219820Sjeff				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
557219820Sjeff						IB_QP_QKEY),
558219820Sjeff				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
559219820Sjeff						IB_QP_ALT_PATH			|
560219820Sjeff						IB_QP_ACCESS_FLAGS		|
561219820Sjeff						IB_QP_PATH_MIG_STATE),
562219820Sjeff				[IB_QPT_RC]  = (IB_QP_CUR_STATE			|
563219820Sjeff						IB_QP_ALT_PATH			|
564219820Sjeff						IB_QP_ACCESS_FLAGS		|
565219820Sjeff						IB_QP_MIN_RNR_TIMER		|
566219820Sjeff						IB_QP_PATH_MIG_STATE),
567219820Sjeff				[IB_QPT_XRC] = (IB_QP_CUR_STATE			|
568219820Sjeff						IB_QP_ALT_PATH			|
569219820Sjeff						IB_QP_ACCESS_FLAGS		|
570219820Sjeff						IB_QP_MIN_RNR_TIMER		|
571219820Sjeff						IB_QP_PATH_MIG_STATE),
572219820Sjeff				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
573219820Sjeff						IB_QP_QKEY),
574219820Sjeff				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
575219820Sjeff						IB_QP_QKEY),
576219820Sjeff			}
577219820Sjeff		},
578219820Sjeff		[IB_QPS_SQD]   = {
579219820Sjeff			.valid = 1,
580219820Sjeff			.opt_param = {
581219820Sjeff				[IB_QPT_UD]  = (IB_QP_PKEY_INDEX		|
582219820Sjeff						IB_QP_QKEY),
583219820Sjeff				[IB_QPT_UC]  = (IB_QP_AV			|
584219820Sjeff						IB_QP_ALT_PATH			|
585219820Sjeff						IB_QP_ACCESS_FLAGS		|
586219820Sjeff						IB_QP_PKEY_INDEX		|
587219820Sjeff						IB_QP_PATH_MIG_STATE),
588219820Sjeff				[IB_QPT_RC]  = (IB_QP_PORT			|
589219820Sjeff						IB_QP_AV			|
590219820Sjeff						IB_QP_TIMEOUT			|
591219820Sjeff						IB_QP_RETRY_CNT			|
592219820Sjeff						IB_QP_RNR_RETRY			|
593219820Sjeff						IB_QP_MAX_QP_RD_ATOMIC		|
594219820Sjeff						IB_QP_MAX_DEST_RD_ATOMIC	|
595219820Sjeff						IB_QP_ALT_PATH			|
596219820Sjeff						IB_QP_ACCESS_FLAGS		|
597219820Sjeff						IB_QP_PKEY_INDEX		|
598219820Sjeff						IB_QP_MIN_RNR_TIMER		|
599219820Sjeff						IB_QP_PATH_MIG_STATE),
600219820Sjeff				[IB_QPT_XRC] = (IB_QP_PORT			|
601219820Sjeff						IB_QP_AV			|
602219820Sjeff						IB_QP_TIMEOUT			|
603219820Sjeff						IB_QP_RETRY_CNT			|
604219820Sjeff						IB_QP_RNR_RETRY			|
605219820Sjeff						IB_QP_MAX_QP_RD_ATOMIC		|
606219820Sjeff						IB_QP_MAX_DEST_RD_ATOMIC	|
607219820Sjeff						IB_QP_ALT_PATH			|
608219820Sjeff						IB_QP_ACCESS_FLAGS		|
609219820Sjeff						IB_QP_PKEY_INDEX		|
610219820Sjeff						IB_QP_MIN_RNR_TIMER		|
611219820Sjeff						IB_QP_PATH_MIG_STATE),
612219820Sjeff				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX		|
613219820Sjeff						IB_QP_QKEY),
614219820Sjeff				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX		|
615219820Sjeff						IB_QP_QKEY),
616219820Sjeff			}
617219820Sjeff		}
618219820Sjeff	},
619219820Sjeff	[IB_QPS_SQE]   = {
620219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
621219820Sjeff		[IB_QPS_ERR] =   { .valid = 1 },
622219820Sjeff		[IB_QPS_RTS]   = {
623219820Sjeff			.valid = 1,
624219820Sjeff			.opt_param = {
625219820Sjeff				[IB_QPT_UD]  = (IB_QP_CUR_STATE			|
626219820Sjeff						IB_QP_QKEY),
627219820Sjeff				[IB_QPT_UC]  = (IB_QP_CUR_STATE			|
628219820Sjeff						IB_QP_ACCESS_FLAGS),
629219820Sjeff				[IB_QPT_SMI] = (IB_QP_CUR_STATE			|
630219820Sjeff						IB_QP_QKEY),
631219820Sjeff				[IB_QPT_GSI] = (IB_QP_CUR_STATE			|
632219820Sjeff						IB_QP_QKEY),
633219820Sjeff			}
634219820Sjeff		}
635219820Sjeff	},
636219820Sjeff	[IB_QPS_ERR] = {
637219820Sjeff		[IB_QPS_RESET] = { .valid = 1 },
638219820Sjeff		[IB_QPS_ERR] =   { .valid = 1 }
639219820Sjeff	}
640219820Sjeff};
641219820Sjeff
642219820Sjeffint ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
643219820Sjeff		       enum ib_qp_type type, enum ib_qp_attr_mask mask)
644219820Sjeff{
645219820Sjeff	enum ib_qp_attr_mask req_param, opt_param;
646219820Sjeff
647219820Sjeff	if (cur_state  < 0 || cur_state  > IB_QPS_ERR ||
648219820Sjeff	    next_state < 0 || next_state > IB_QPS_ERR)
649219820Sjeff		return 0;
650219820Sjeff
651219820Sjeff	if (mask & IB_QP_CUR_STATE  &&
652219820Sjeff	    cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
653219820Sjeff	    cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE)
654219820Sjeff		return 0;
655219820Sjeff
656219820Sjeff	if (!qp_state_table[cur_state][next_state].valid)
657219820Sjeff		return 0;
658219820Sjeff
659219820Sjeff	req_param = qp_state_table[cur_state][next_state].req_param[type];
660219820Sjeff	opt_param = qp_state_table[cur_state][next_state].opt_param[type];
661219820Sjeff
662219820Sjeff	if ((mask & req_param) != req_param)
663219820Sjeff		return 0;
664219820Sjeff
665219820Sjeff	if (mask & ~(req_param | opt_param | IB_QP_STATE))
666219820Sjeff		return 0;
667219820Sjeff
668219820Sjeff	return 1;
669219820Sjeff}
670219820SjeffEXPORT_SYMBOL(ib_modify_qp_is_ok);
671219820Sjeff
672219820Sjeffint ib_modify_qp(struct ib_qp *qp,
673219820Sjeff		 struct ib_qp_attr *qp_attr,
674219820Sjeff		 int qp_attr_mask)
675219820Sjeff{
676219820Sjeff	return qp->device->modify_qp(qp, qp_attr, qp_attr_mask, NULL);
677219820Sjeff}
678219820SjeffEXPORT_SYMBOL(ib_modify_qp);
679219820Sjeff
680219820Sjeffint ib_query_qp(struct ib_qp *qp,
681219820Sjeff		struct ib_qp_attr *qp_attr,
682219820Sjeff		int qp_attr_mask,
683219820Sjeff		struct ib_qp_init_attr *qp_init_attr)
684219820Sjeff{
685219820Sjeff	return qp->device->query_qp ?
686219820Sjeff		qp->device->query_qp(qp, qp_attr, qp_attr_mask, qp_init_attr) :
687219820Sjeff		-ENOSYS;
688219820Sjeff}
689219820SjeffEXPORT_SYMBOL(ib_query_qp);
690219820Sjeff
691219820Sjeffint ib_destroy_qp(struct ib_qp *qp)
692219820Sjeff{
693219820Sjeff	struct ib_pd *pd;
694219820Sjeff	struct ib_cq *scq, *rcq;
695219820Sjeff	struct ib_srq *srq;
696219820Sjeff	struct ib_xrcd *xrcd;
697219820Sjeff	enum ib_qp_type	qp_type = qp->qp_type;
698219820Sjeff	int ret;
699219820Sjeff
700219820Sjeff	pd  = qp->pd;
701219820Sjeff	scq = qp->send_cq;
702219820Sjeff	rcq = qp->recv_cq;
703219820Sjeff	srq = qp->srq;
704219820Sjeff	xrcd = qp->xrcd;
705219820Sjeff
706219820Sjeff	ret = qp->device->destroy_qp(qp);
707219820Sjeff	if (!ret) {
708219820Sjeff		atomic_dec(&pd->usecnt);
709219820Sjeff		atomic_dec(&scq->usecnt);
710219820Sjeff		atomic_dec(&rcq->usecnt);
711219820Sjeff		if (srq)
712219820Sjeff			atomic_dec(&srq->usecnt);
713219820Sjeff		if (qp_type == IB_QPT_XRC)
714219820Sjeff			atomic_dec(&xrcd->usecnt);
715219820Sjeff	}
716219820Sjeff
717219820Sjeff	return ret;
718219820Sjeff}
719219820SjeffEXPORT_SYMBOL(ib_destroy_qp);
720219820Sjeff
721219820Sjeff/* Completion queues */
722219820Sjeff
723219820Sjeffstruct ib_cq *ib_create_cq(struct ib_device *device,
724219820Sjeff			   ib_comp_handler comp_handler,
725219820Sjeff			   void (*event_handler)(struct ib_event *, void *),
726219820Sjeff			   void *cq_context, int cqe, int comp_vector)
727219820Sjeff{
728219820Sjeff	struct ib_cq *cq;
729219820Sjeff
730219820Sjeff	cq = device->create_cq(device, cqe, comp_vector, NULL, NULL);
731219820Sjeff
732219820Sjeff	if (!IS_ERR(cq)) {
733219820Sjeff		cq->device        = device;
734219820Sjeff		cq->uobject       = NULL;
735219820Sjeff		cq->comp_handler  = comp_handler;
736219820Sjeff		cq->event_handler = event_handler;
737219820Sjeff		cq->cq_context    = cq_context;
738219820Sjeff		atomic_set(&cq->usecnt, 0);
739219820Sjeff	}
740219820Sjeff
741219820Sjeff	return cq;
742219820Sjeff}
743219820SjeffEXPORT_SYMBOL(ib_create_cq);
744219820Sjeff
745219820Sjeffint ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
746219820Sjeff{
747219820Sjeff	return cq->device->modify_cq ?
748219820Sjeff		cq->device->modify_cq(cq, cq_count, cq_period) : -ENOSYS;
749219820Sjeff}
750219820SjeffEXPORT_SYMBOL(ib_modify_cq);
751219820Sjeff
752219820Sjeffint ib_destroy_cq(struct ib_cq *cq)
753219820Sjeff{
754219820Sjeff	if (atomic_read(&cq->usecnt))
755219820Sjeff		return -EBUSY;
756219820Sjeff
757219820Sjeff	return cq->device->destroy_cq(cq);
758219820Sjeff}
759219820SjeffEXPORT_SYMBOL(ib_destroy_cq);
760219820Sjeff
761219820Sjeffint ib_resize_cq(struct ib_cq *cq, int cqe)
762219820Sjeff{
763219820Sjeff	return cq->device->resize_cq ?
764219820Sjeff		cq->device->resize_cq(cq, cqe, NULL) : -ENOSYS;
765219820Sjeff}
766219820SjeffEXPORT_SYMBOL(ib_resize_cq);
767219820Sjeff
768219820Sjeff/* Memory regions */
769219820Sjeff
770219820Sjeffstruct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
771219820Sjeff{
772219820Sjeff	struct ib_mr *mr;
773219820Sjeff
774219820Sjeff	mr = pd->device->get_dma_mr(pd, mr_access_flags);
775219820Sjeff
776219820Sjeff	if (!IS_ERR(mr)) {
777219820Sjeff		mr->device  = pd->device;
778219820Sjeff		mr->pd      = pd;
779219820Sjeff		mr->uobject = NULL;
780219820Sjeff		atomic_inc(&pd->usecnt);
781219820Sjeff		atomic_set(&mr->usecnt, 0);
782219820Sjeff	}
783219820Sjeff
784219820Sjeff	return mr;
785219820Sjeff}
786219820SjeffEXPORT_SYMBOL(ib_get_dma_mr);
787219820Sjeff
788219820Sjeffstruct ib_mr *ib_reg_phys_mr(struct ib_pd *pd,
789219820Sjeff			     struct ib_phys_buf *phys_buf_array,
790219820Sjeff			     int num_phys_buf,
791219820Sjeff			     int mr_access_flags,
792219820Sjeff			     u64 *iova_start)
793219820Sjeff{
794219820Sjeff	struct ib_mr *mr;
795219820Sjeff
796219820Sjeff	if (!pd->device->reg_phys_mr)
797219820Sjeff		return ERR_PTR(-ENOSYS);
798219820Sjeff
799219820Sjeff	mr = pd->device->reg_phys_mr(pd, phys_buf_array, num_phys_buf,
800219820Sjeff				     mr_access_flags, iova_start);
801219820Sjeff
802219820Sjeff	if (!IS_ERR(mr)) {
803219820Sjeff		mr->device  = pd->device;
804219820Sjeff		mr->pd      = pd;
805219820Sjeff		mr->uobject = NULL;
806219820Sjeff		atomic_inc(&pd->usecnt);
807219820Sjeff		atomic_set(&mr->usecnt, 0);
808219820Sjeff	}
809219820Sjeff
810219820Sjeff	return mr;
811219820Sjeff}
812219820SjeffEXPORT_SYMBOL(ib_reg_phys_mr);
813219820Sjeff
814219820Sjeffint ib_rereg_phys_mr(struct ib_mr *mr,
815219820Sjeff		     int mr_rereg_mask,
816219820Sjeff		     struct ib_pd *pd,
817219820Sjeff		     struct ib_phys_buf *phys_buf_array,
818219820Sjeff		     int num_phys_buf,
819219820Sjeff		     int mr_access_flags,
820219820Sjeff		     u64 *iova_start)
821219820Sjeff{
822219820Sjeff	struct ib_pd *old_pd;
823219820Sjeff	int ret;
824219820Sjeff
825219820Sjeff	if (!mr->device->rereg_phys_mr)
826219820Sjeff		return -ENOSYS;
827219820Sjeff
828219820Sjeff	if (atomic_read(&mr->usecnt))
829219820Sjeff		return -EBUSY;
830219820Sjeff
831219820Sjeff	old_pd = mr->pd;
832219820Sjeff
833219820Sjeff	ret = mr->device->rereg_phys_mr(mr, mr_rereg_mask, pd,
834219820Sjeff					phys_buf_array, num_phys_buf,
835219820Sjeff					mr_access_flags, iova_start);
836219820Sjeff
837219820Sjeff	if (!ret && (mr_rereg_mask & IB_MR_REREG_PD)) {
838219820Sjeff		atomic_dec(&old_pd->usecnt);
839219820Sjeff		atomic_inc(&pd->usecnt);
840219820Sjeff	}
841219820Sjeff
842219820Sjeff	return ret;
843219820Sjeff}
844219820SjeffEXPORT_SYMBOL(ib_rereg_phys_mr);
845219820Sjeff
846219820Sjeffint ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
847219820Sjeff{
848219820Sjeff	return mr->device->query_mr ?
849219820Sjeff		mr->device->query_mr(mr, mr_attr) : -ENOSYS;
850219820Sjeff}
851219820SjeffEXPORT_SYMBOL(ib_query_mr);
852219820Sjeff
853219820Sjeffint ib_dereg_mr(struct ib_mr *mr)
854219820Sjeff{
855219820Sjeff	struct ib_pd *pd;
856219820Sjeff	int ret;
857219820Sjeff
858219820Sjeff	if (atomic_read(&mr->usecnt))
859219820Sjeff		return -EBUSY;
860219820Sjeff
861219820Sjeff	pd = mr->pd;
862219820Sjeff	ret = mr->device->dereg_mr(mr);
863219820Sjeff	if (!ret)
864219820Sjeff		atomic_dec(&pd->usecnt);
865219820Sjeff
866219820Sjeff	return ret;
867219820Sjeff}
868219820SjeffEXPORT_SYMBOL(ib_dereg_mr);
869219820Sjeff
870219820Sjeffstruct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len)
871219820Sjeff{
872219820Sjeff	struct ib_mr *mr;
873219820Sjeff
874219820Sjeff	if (!pd->device->alloc_fast_reg_mr)
875219820Sjeff		return ERR_PTR(-ENOSYS);
876219820Sjeff
877219820Sjeff	mr = pd->device->alloc_fast_reg_mr(pd, max_page_list_len);
878219820Sjeff
879219820Sjeff	if (!IS_ERR(mr)) {
880219820Sjeff		mr->device  = pd->device;
881219820Sjeff		mr->pd      = pd;
882219820Sjeff		mr->uobject = NULL;
883219820Sjeff		atomic_inc(&pd->usecnt);
884219820Sjeff		atomic_set(&mr->usecnt, 0);
885219820Sjeff	}
886219820Sjeff
887219820Sjeff	return mr;
888219820Sjeff}
889219820SjeffEXPORT_SYMBOL(ib_alloc_fast_reg_mr);
890219820Sjeff
891219820Sjeffstruct ib_fast_reg_page_list *ib_alloc_fast_reg_page_list(struct ib_device *device,
892219820Sjeff							  int max_page_list_len)
893219820Sjeff{
894219820Sjeff	struct ib_fast_reg_page_list *page_list;
895219820Sjeff
896219820Sjeff	if (!device->alloc_fast_reg_page_list)
897219820Sjeff		return ERR_PTR(-ENOSYS);
898219820Sjeff
899219820Sjeff	page_list = device->alloc_fast_reg_page_list(device, max_page_list_len);
900219820Sjeff
901219820Sjeff	if (!IS_ERR(page_list)) {
902219820Sjeff		page_list->device = device;
903219820Sjeff		page_list->max_page_list_len = max_page_list_len;
904219820Sjeff	}
905219820Sjeff
906219820Sjeff	return page_list;
907219820Sjeff}
908219820SjeffEXPORT_SYMBOL(ib_alloc_fast_reg_page_list);
909219820Sjeff
910219820Sjeffvoid ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list)
911219820Sjeff{
912219820Sjeff	page_list->device->free_fast_reg_page_list(page_list);
913219820Sjeff}
914219820SjeffEXPORT_SYMBOL(ib_free_fast_reg_page_list);
915219820Sjeff
916219820Sjeff/* Memory windows */
917219820Sjeff
918219820Sjeffstruct ib_mw *ib_alloc_mw(struct ib_pd *pd)
919219820Sjeff{
920219820Sjeff	struct ib_mw *mw;
921219820Sjeff
922219820Sjeff	if (!pd->device->alloc_mw)
923219820Sjeff		return ERR_PTR(-ENOSYS);
924219820Sjeff
925219820Sjeff	mw = pd->device->alloc_mw(pd);
926219820Sjeff	if (!IS_ERR(mw)) {
927219820Sjeff		mw->device  = pd->device;
928219820Sjeff		mw->pd      = pd;
929219820Sjeff		mw->uobject = NULL;
930219820Sjeff		atomic_inc(&pd->usecnt);
931219820Sjeff	}
932219820Sjeff
933219820Sjeff	return mw;
934219820Sjeff}
935219820SjeffEXPORT_SYMBOL(ib_alloc_mw);
936219820Sjeff
937219820Sjeffint ib_dealloc_mw(struct ib_mw *mw)
938219820Sjeff{
939219820Sjeff	struct ib_pd *pd;
940219820Sjeff	int ret;
941219820Sjeff
942219820Sjeff	pd = mw->pd;
943219820Sjeff	ret = mw->device->dealloc_mw(mw);
944219820Sjeff	if (!ret)
945219820Sjeff		atomic_dec(&pd->usecnt);
946219820Sjeff
947219820Sjeff	return ret;
948219820Sjeff}
949219820SjeffEXPORT_SYMBOL(ib_dealloc_mw);
950219820Sjeff
951219820Sjeff/* "Fast" memory regions */
952219820Sjeff
953219820Sjeffstruct ib_fmr *ib_alloc_fmr(struct ib_pd *pd,
954219820Sjeff			    int mr_access_flags,
955219820Sjeff			    struct ib_fmr_attr *fmr_attr)
956219820Sjeff{
957219820Sjeff	struct ib_fmr *fmr;
958219820Sjeff
959219820Sjeff	if (!pd->device->alloc_fmr)
960219820Sjeff		return ERR_PTR(-ENOSYS);
961219820Sjeff
962219820Sjeff	fmr = pd->device->alloc_fmr(pd, mr_access_flags, fmr_attr);
963219820Sjeff	if (!IS_ERR(fmr)) {
964219820Sjeff		fmr->device = pd->device;
965219820Sjeff		fmr->pd     = pd;
966219820Sjeff		atomic_inc(&pd->usecnt);
967219820Sjeff	}
968219820Sjeff
969219820Sjeff	return fmr;
970219820Sjeff}
971219820SjeffEXPORT_SYMBOL(ib_alloc_fmr);
972219820Sjeff
973219820Sjeffint ib_unmap_fmr(struct list_head *fmr_list)
974219820Sjeff{
975219820Sjeff	struct ib_fmr *fmr;
976219820Sjeff
977219820Sjeff	if (list_empty(fmr_list))
978219820Sjeff		return 0;
979219820Sjeff
980219820Sjeff	fmr = list_entry(fmr_list->next, struct ib_fmr, list);
981219820Sjeff	return fmr->device->unmap_fmr(fmr_list);
982219820Sjeff}
983219820SjeffEXPORT_SYMBOL(ib_unmap_fmr);
984219820Sjeff
985219820Sjeffint ib_dealloc_fmr(struct ib_fmr *fmr)
986219820Sjeff{
987219820Sjeff	struct ib_pd *pd;
988219820Sjeff	int ret;
989219820Sjeff
990219820Sjeff	pd = fmr->pd;
991219820Sjeff	ret = fmr->device->dealloc_fmr(fmr);
992219820Sjeff	if (!ret)
993219820Sjeff		atomic_dec(&pd->usecnt);
994219820Sjeff
995219820Sjeff	return ret;
996219820Sjeff}
997219820SjeffEXPORT_SYMBOL(ib_dealloc_fmr);
998219820Sjeff
999219820Sjeff/* Multicast groups */
1000219820Sjeff
1001219820Sjeffint ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
1002219820Sjeff{
1003219820Sjeff	if (!qp->device->attach_mcast)
1004219820Sjeff		return -ENOSYS;
1005219820Sjeff
1006219820Sjeff	switch (rdma_node_get_transport(qp->device->node_type)) {
1007219820Sjeff	case RDMA_TRANSPORT_IB:
1008219820Sjeff		if (qp->qp_type == IB_QPT_RAW_ETH) {
1009219820Sjeff			/* In raw Etherent mgids the 63 msb's should be 0 */
1010219820Sjeff			if (gid->global.subnet_prefix & cpu_to_be64(~1ULL))
1011219820Sjeff				return -EINVAL;
1012219820Sjeff		} else if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
1013219820Sjeff			return -EINVAL;
1014219820Sjeff		break;
1015219820Sjeff	case RDMA_TRANSPORT_IWARP:
1016219820Sjeff		if (qp->qp_type != IB_QPT_RAW_ETH)
1017219820Sjeff			return -EINVAL;
1018219820Sjeff		break;
1019219820Sjeff	}
1020219820Sjeff	return qp->device->attach_mcast(qp, gid, lid);
1021219820Sjeff}
1022219820SjeffEXPORT_SYMBOL(ib_attach_mcast);
1023219820Sjeff
1024219820Sjeffint ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
1025219820Sjeff{
1026219820Sjeff	if (!qp->device->detach_mcast)
1027219820Sjeff		return -ENOSYS;
1028219820Sjeff
1029219820Sjeff	switch (rdma_node_get_transport(qp->device->node_type)) {
1030219820Sjeff	case RDMA_TRANSPORT_IB:
1031219820Sjeff		if (qp->qp_type == IB_QPT_RAW_ETH) {
1032219820Sjeff			/* In raw Etherent mgids the 63 msb's should be 0 */
1033219820Sjeff			if (gid->global.subnet_prefix & cpu_to_be64(~1ULL))
1034219820Sjeff				return -EINVAL;
1035219820Sjeff		} else if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD)
1036219820Sjeff			return -EINVAL;
1037219820Sjeff		break;
1038219820Sjeff	case RDMA_TRANSPORT_IWARP:
1039219820Sjeff		if (qp->qp_type != IB_QPT_RAW_ETH)
1040219820Sjeff			return -EINVAL;
1041219820Sjeff		break;
1042219820Sjeff	}
1043219820Sjeff	return qp->device->detach_mcast(qp, gid, lid);
1044219820Sjeff}
1045219820SjeffEXPORT_SYMBOL(ib_detach_mcast);
1046219820Sjeff
1047219820Sjeffint ib_dealloc_xrcd(struct ib_xrcd *xrcd)
1048219820Sjeff{
1049219820Sjeff	if (atomic_read(&xrcd->usecnt))
1050219820Sjeff		return -EBUSY;
1051219820Sjeff
1052219820Sjeff	return xrcd->device->dealloc_xrcd(xrcd);
1053219820Sjeff}
1054219820SjeffEXPORT_SYMBOL(ib_dealloc_xrcd);
1055219820Sjeff
1056219820Sjeffstruct ib_xrcd *ib_alloc_xrcd(struct ib_device *device)
1057219820Sjeff{
1058219820Sjeff	struct ib_xrcd *xrcd;
1059219820Sjeff
1060219820Sjeff	if (!device->alloc_xrcd)
1061219820Sjeff		return ERR_PTR(-ENOSYS);
1062219820Sjeff
1063219820Sjeff	xrcd = device->alloc_xrcd(device, NULL, NULL);
1064219820Sjeff	if (!IS_ERR(xrcd)) {
1065219820Sjeff		xrcd->device = device;
1066219820Sjeff		xrcd->inode = NULL;
1067219820Sjeff		xrcd->uobject = NULL;
1068219820Sjeff		atomic_set(&xrcd->usecnt, 0);
1069219820Sjeff	}
1070219820Sjeff	return xrcd;
1071219820Sjeff}
1072219820SjeffEXPORT_SYMBOL(ib_alloc_xrcd);
1073219820Sjeff
1074