1219820Sjeff/*
2219820Sjeff * Copyright (c) 2005 Topspin Communications.  All rights reserved.
3219820Sjeff * Copyright (c) 2006, 2007 Cisco Systems, Inc.  All rights reserved.
4219820Sjeff *
5219820Sjeff * This software is available to you under a choice of one of two
6219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
7219820Sjeff * General Public License (GPL) Version 2, available from the file
8219820Sjeff * COPYING in the main directory of this source tree, or the
9219820Sjeff * OpenIB.org BSD license below:
10219820Sjeff *
11219820Sjeff *     Redistribution and use in source and binary forms, with or
12219820Sjeff *     without modification, are permitted provided that the following
13219820Sjeff *     conditions are met:
14219820Sjeff *
15219820Sjeff *      - Redistributions of source code must retain the above
16219820Sjeff *        copyright notice, this list of conditions and the following
17219820Sjeff *        disclaimer.
18219820Sjeff *
19219820Sjeff *      - Redistributions in binary form must reproduce the above
20219820Sjeff *        copyright notice, this list of conditions and the following
21219820Sjeff *        disclaimer in the documentation and/or other materials
22219820Sjeff *        provided with the distribution.
23219820Sjeff *
24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31219820Sjeff * SOFTWARE.
32219820Sjeff */
33219820Sjeff
34219820Sjeff#if HAVE_CONFIG_H
35219820Sjeff#  include <config.h>
36219820Sjeff#endif /* HAVE_CONFIG_H */
37219820Sjeff
38219820Sjeff#include <stdio.h>
39219820Sjeff#include <netinet/in.h>
40219820Sjeff#include <unistd.h>
41219820Sjeff#include <stdlib.h>
42219820Sjeff#include <errno.h>
43219820Sjeff#include <string.h>
44219820Sjeff
45219820Sjeff#include "ibverbs.h"
46219820Sjeff
47219820Sjeffint ibv_rate_to_mult(enum ibv_rate rate)
48219820Sjeff{
49219820Sjeff	switch (rate) {
50219820Sjeff	case IBV_RATE_2_5_GBPS: return  1;
51219820Sjeff	case IBV_RATE_5_GBPS:   return  2;
52219820Sjeff	case IBV_RATE_10_GBPS:  return  4;
53219820Sjeff	case IBV_RATE_20_GBPS:  return  8;
54219820Sjeff	case IBV_RATE_30_GBPS:  return 12;
55219820Sjeff	case IBV_RATE_40_GBPS:  return 16;
56219820Sjeff	case IBV_RATE_60_GBPS:  return 24;
57219820Sjeff	case IBV_RATE_80_GBPS:  return 32;
58219820Sjeff	case IBV_RATE_120_GBPS: return 48;
59219820Sjeff	default:           return -1;
60219820Sjeff	}
61219820Sjeff}
62219820Sjeff
63219820Sjeffenum ibv_rate mult_to_ibv_rate(int mult)
64219820Sjeff{
65219820Sjeff	switch (mult) {
66219820Sjeff	case 1:  return IBV_RATE_2_5_GBPS;
67219820Sjeff	case 2:  return IBV_RATE_5_GBPS;
68219820Sjeff	case 4:  return IBV_RATE_10_GBPS;
69219820Sjeff	case 8:  return IBV_RATE_20_GBPS;
70219820Sjeff	case 12: return IBV_RATE_30_GBPS;
71219820Sjeff	case 16: return IBV_RATE_40_GBPS;
72219820Sjeff	case 24: return IBV_RATE_60_GBPS;
73219820Sjeff	case 32: return IBV_RATE_80_GBPS;
74219820Sjeff	case 48: return IBV_RATE_120_GBPS;
75219820Sjeff	default: return IBV_RATE_MAX;
76219820Sjeff	}
77219820Sjeff}
78219820Sjeff
79219820Sjeffint __ibv_query_device(struct ibv_context *context,
80219820Sjeff		       struct ibv_device_attr *device_attr)
81219820Sjeff{
82219820Sjeff	return context->ops.query_device(context, device_attr);
83219820Sjeff}
84219820Sjeffdefault_symver(__ibv_query_device, ibv_query_device);
85219820Sjeff
86219820Sjeffint __ibv_query_port(struct ibv_context *context, uint8_t port_num,
87219820Sjeff		     struct ibv_port_attr *port_attr)
88219820Sjeff{
89219820Sjeff	return context->ops.query_port(context, port_num, port_attr);
90219820Sjeff}
91219820Sjeffdefault_symver(__ibv_query_port, ibv_query_port);
92219820Sjeff
93219820Sjeffint __ibv_query_gid(struct ibv_context *context, uint8_t port_num,
94219820Sjeff		    int index, union ibv_gid *gid)
95219820Sjeff{
96219820Sjeff	char name[24];
97219820Sjeff	char attr[41];
98219820Sjeff	uint16_t val;
99219820Sjeff	int i;
100219820Sjeff
101219820Sjeff	snprintf(name, sizeof name, "ports/%d/gids/%d", port_num, index);
102219820Sjeff
103219820Sjeff	if (ibv_read_sysfs_file(context->device->ibdev_path, name,
104219820Sjeff				attr, sizeof attr) < 0)
105219820Sjeff		return -1;
106219820Sjeff
107219820Sjeff	for (i = 0; i < 8; ++i) {
108219820Sjeff		if (sscanf(attr + i * 5, "%hx", &val) != 1)
109219820Sjeff			return -1;
110219820Sjeff		gid->raw[i * 2    ] = val >> 8;
111219820Sjeff		gid->raw[i * 2 + 1] = val & 0xff;
112219820Sjeff	}
113219820Sjeff
114219820Sjeff	return 0;
115219820Sjeff}
116219820Sjeffdefault_symver(__ibv_query_gid, ibv_query_gid);
117219820Sjeff
118219820Sjeffint __ibv_query_pkey(struct ibv_context *context, uint8_t port_num,
119219820Sjeff		     int index, uint16_t *pkey)
120219820Sjeff{
121219820Sjeff	char name[24];
122219820Sjeff	char attr[8];
123219820Sjeff	uint16_t val;
124219820Sjeff
125219820Sjeff	snprintf(name, sizeof name, "ports/%d/pkeys/%d", port_num, index);
126219820Sjeff
127219820Sjeff	if (ibv_read_sysfs_file(context->device->ibdev_path, name,
128219820Sjeff				attr, sizeof attr) < 0)
129219820Sjeff		return -1;
130219820Sjeff
131219820Sjeff	if (sscanf(attr, "%hx", &val) != 1)
132219820Sjeff		return -1;
133219820Sjeff
134219820Sjeff	*pkey = htons(val);
135219820Sjeff	return 0;
136219820Sjeff}
137219820Sjeffdefault_symver(__ibv_query_pkey, ibv_query_pkey);
138219820Sjeff
139219820Sjeffstruct ibv_pd *__ibv_alloc_pd(struct ibv_context *context)
140219820Sjeff{
141219820Sjeff	struct ibv_pd *pd;
142219820Sjeff
143219820Sjeff	pd = context->ops.alloc_pd(context);
144219820Sjeff	if (pd)
145219820Sjeff		pd->context = context;
146219820Sjeff
147219820Sjeff	return pd;
148219820Sjeff}
149219820Sjeffdefault_symver(__ibv_alloc_pd, ibv_alloc_pd);
150219820Sjeff
151219820Sjeffint __ibv_dealloc_pd(struct ibv_pd *pd)
152219820Sjeff{
153219820Sjeff	return pd->context->ops.dealloc_pd(pd);
154219820Sjeff}
155219820Sjeffdefault_symver(__ibv_dealloc_pd, ibv_dealloc_pd);
156219820Sjeff
157219820Sjeffstruct ibv_mr *__ibv_reg_mr(struct ibv_pd *pd, void *addr,
158219820Sjeff			    size_t length, int access)
159219820Sjeff{
160219820Sjeff	struct ibv_mr *mr;
161219820Sjeff
162219820Sjeff	if (ibv_dontfork_range(addr, length))
163219820Sjeff		return NULL;
164219820Sjeff
165219820Sjeff	mr = pd->context->ops.reg_mr(pd, addr, length, access);
166219820Sjeff	if (mr) {
167219820Sjeff		mr->context = pd->context;
168219820Sjeff		mr->pd      = pd;
169219820Sjeff		mr->addr    = addr;
170219820Sjeff		mr->length  = length;
171219820Sjeff	} else
172219820Sjeff		ibv_dofork_range(addr, length);
173219820Sjeff
174219820Sjeff	return mr;
175219820Sjeff}
176219820Sjeffdefault_symver(__ibv_reg_mr, ibv_reg_mr);
177219820Sjeff
178219820Sjeffint __ibv_dereg_mr(struct ibv_mr *mr)
179219820Sjeff{
180219820Sjeff	int ret;
181219820Sjeff	void *addr	= mr->addr;
182219820Sjeff	size_t length	= mr->length;
183219820Sjeff
184219820Sjeff	ret = mr->context->ops.dereg_mr(mr);
185219820Sjeff	if (!ret)
186219820Sjeff		ibv_dofork_range(addr, length);
187219820Sjeff
188219820Sjeff	return ret;
189219820Sjeff}
190219820Sjeffdefault_symver(__ibv_dereg_mr, ibv_dereg_mr);
191219820Sjeff
192219820Sjeffstatic struct ibv_comp_channel *ibv_create_comp_channel_v2(struct ibv_context *context)
193219820Sjeff{
194219820Sjeff	struct ibv_abi_compat_v2 *t = context->abi_compat;
195219820Sjeff	static int warned;
196219820Sjeff
197219820Sjeff	if (!pthread_mutex_trylock(&t->in_use))
198219820Sjeff		return &t->channel;
199219820Sjeff
200219820Sjeff	if (!warned) {
201219820Sjeff		fprintf(stderr, PFX "Warning: kernel's ABI version %d limits capacity.\n"
202219820Sjeff			"    Only one completion channel can be created per context.\n",
203219820Sjeff			abi_ver);
204219820Sjeff		++warned;
205219820Sjeff	}
206219820Sjeff
207219820Sjeff	return NULL;
208219820Sjeff}
209219820Sjeff
210219820Sjeffstruct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context)
211219820Sjeff{
212219820Sjeff	struct ibv_comp_channel            *channel;
213219820Sjeff	struct ibv_create_comp_channel      cmd;
214219820Sjeff	struct ibv_create_comp_channel_resp resp;
215219820Sjeff
216219820Sjeff	if (abi_ver <= 2)
217219820Sjeff		return ibv_create_comp_channel_v2(context);
218219820Sjeff
219219820Sjeff	channel = malloc(sizeof *channel);
220219820Sjeff	if (!channel)
221219820Sjeff		return NULL;
222219820Sjeff
223219820Sjeff	IBV_INIT_CMD_RESP(&cmd, sizeof cmd, CREATE_COMP_CHANNEL, &resp, sizeof resp);
224219820Sjeff	if (write(context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) {
225219820Sjeff		free(channel);
226219820Sjeff		return NULL;
227219820Sjeff	}
228219820Sjeff
229219820Sjeff	VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp);
230219820Sjeff
231219820Sjeff	channel->context = context;
232219820Sjeff	channel->fd      = resp.fd;
233219820Sjeff	channel->refcnt  = 0;
234219820Sjeff
235219820Sjeff	return channel;
236219820Sjeff}
237219820Sjeff
238219820Sjeffstatic int ibv_destroy_comp_channel_v2(struct ibv_comp_channel *channel)
239219820Sjeff{
240219820Sjeff	struct ibv_abi_compat_v2 *t = (struct ibv_abi_compat_v2 *) channel;
241219820Sjeff	pthread_mutex_unlock(&t->in_use);
242219820Sjeff	return 0;
243219820Sjeff}
244219820Sjeff
245219820Sjeffint ibv_destroy_comp_channel(struct ibv_comp_channel *channel)
246219820Sjeff{
247219820Sjeff	struct ibv_context *context;
248219820Sjeff	int ret;
249219820Sjeff
250219820Sjeff	context = channel->context;
251219820Sjeff	pthread_mutex_lock(&context->mutex);
252219820Sjeff
253219820Sjeff	if (channel->refcnt) {
254219820Sjeff		ret = EBUSY;
255219820Sjeff		goto out;
256219820Sjeff	}
257219820Sjeff
258219820Sjeff	if (abi_ver <= 2) {
259219820Sjeff		ret = ibv_destroy_comp_channel_v2(channel);
260219820Sjeff		goto out;
261219820Sjeff	}
262219820Sjeff
263219820Sjeff	close(channel->fd);
264219820Sjeff	free(channel);
265219820Sjeff	ret = 0;
266219820Sjeff
267219820Sjeffout:
268219820Sjeff	pthread_mutex_unlock(&context->mutex);
269219820Sjeff
270219820Sjeff	return ret;
271219820Sjeff}
272219820Sjeff
273219820Sjeffstruct ibv_cq *__ibv_create_cq(struct ibv_context *context, int cqe, void *cq_context,
274219820Sjeff			       struct ibv_comp_channel *channel, int comp_vector)
275219820Sjeff{
276219820Sjeff	struct ibv_cq *cq;
277219820Sjeff
278219820Sjeff	pthread_mutex_lock(&context->mutex);
279219820Sjeff
280219820Sjeff	cq = context->ops.create_cq(context, cqe, channel, comp_vector);
281219820Sjeff
282219820Sjeff	if (cq) {
283219820Sjeff		cq->context    	     	   = context;
284219820Sjeff		cq->channel		   = channel;
285219820Sjeff		if (channel)
286219820Sjeff			++channel->refcnt;
287219820Sjeff		cq->cq_context 	     	   = cq_context;
288219820Sjeff		cq->comp_events_completed  = 0;
289219820Sjeff		cq->async_events_completed = 0;
290219820Sjeff		pthread_mutex_init(&cq->mutex, NULL);
291219820Sjeff		pthread_cond_init(&cq->cond, NULL);
292219820Sjeff	}
293219820Sjeff
294219820Sjeff	pthread_mutex_unlock(&context->mutex);
295219820Sjeff
296219820Sjeff	return cq;
297219820Sjeff}
298219820Sjeffdefault_symver(__ibv_create_cq, ibv_create_cq);
299219820Sjeff
300219820Sjeffint __ibv_resize_cq(struct ibv_cq *cq, int cqe)
301219820Sjeff{
302219820Sjeff	if (!cq->context->ops.resize_cq)
303219820Sjeff		return ENOSYS;
304219820Sjeff
305219820Sjeff	return cq->context->ops.resize_cq(cq, cqe);
306219820Sjeff}
307219820Sjeffdefault_symver(__ibv_resize_cq, ibv_resize_cq);
308219820Sjeff
309219820Sjeffint __ibv_destroy_cq(struct ibv_cq *cq)
310219820Sjeff{
311219820Sjeff	struct ibv_comp_channel *channel = cq->channel;
312219820Sjeff	int ret;
313219820Sjeff
314219820Sjeff	if (channel)
315219820Sjeff		pthread_mutex_lock(&channel->context->mutex);
316219820Sjeff
317219820Sjeff	ret = cq->context->ops.destroy_cq(cq);
318219820Sjeff
319219820Sjeff	if (channel) {
320219820Sjeff		if (!ret)
321219820Sjeff			--channel->refcnt;
322219820Sjeff		pthread_mutex_unlock(&channel->context->mutex);
323219820Sjeff	}
324219820Sjeff
325219820Sjeff	return ret;
326219820Sjeff}
327219820Sjeffdefault_symver(__ibv_destroy_cq, ibv_destroy_cq);
328219820Sjeff
329219820Sjeffint __ibv_get_cq_event(struct ibv_comp_channel *channel,
330219820Sjeff		       struct ibv_cq **cq, void **cq_context)
331219820Sjeff{
332219820Sjeff	struct ibv_comp_event ev;
333219820Sjeff
334219820Sjeff	if (read(channel->fd, &ev, sizeof ev) != sizeof ev)
335219820Sjeff		return -1;
336219820Sjeff
337219820Sjeff	*cq         = (struct ibv_cq *) (uintptr_t) ev.cq_handle;
338219820Sjeff	*cq_context = (*cq)->cq_context;
339219820Sjeff
340219820Sjeff	if ((*cq)->context->ops.cq_event)
341219820Sjeff		(*cq)->context->ops.cq_event(*cq);
342219820Sjeff
343219820Sjeff	return 0;
344219820Sjeff}
345219820Sjeffdefault_symver(__ibv_get_cq_event, ibv_get_cq_event);
346219820Sjeff
347219820Sjeffvoid __ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
348219820Sjeff{
349219820Sjeff	pthread_mutex_lock(&cq->mutex);
350219820Sjeff	cq->comp_events_completed += nevents;
351219820Sjeff	pthread_cond_signal(&cq->cond);
352219820Sjeff	pthread_mutex_unlock(&cq->mutex);
353219820Sjeff}
354219820Sjeffdefault_symver(__ibv_ack_cq_events, ibv_ack_cq_events);
355219820Sjeff
356219820Sjeffstruct ibv_srq *__ibv_create_srq(struct ibv_pd *pd,
357219820Sjeff				 struct ibv_srq_init_attr *srq_init_attr)
358219820Sjeff{
359219820Sjeff	struct ibv_srq *srq;
360219820Sjeff
361219820Sjeff	if (!pd->context->ops.create_srq)
362219820Sjeff		return NULL;
363219820Sjeff
364219820Sjeff	srq = pd->context->ops.create_srq(pd, srq_init_attr);
365219820Sjeff	if (srq) {
366219820Sjeff		srq->context          = pd->context;
367219820Sjeff		srq->srq_context      = srq_init_attr->srq_context;
368219820Sjeff		srq->pd               = pd;
369219820Sjeff		srq->xrc_domain       = NULL;
370219820Sjeff		srq->xrc_cq           = NULL;
371219820Sjeff		srq->xrc_srq_num      = 0;
372219820Sjeff		srq->events_completed = 0;
373219820Sjeff		pthread_mutex_init(&srq->mutex, NULL);
374219820Sjeff		pthread_cond_init(&srq->cond, NULL);
375219820Sjeff	}
376219820Sjeff
377219820Sjeff	return srq;
378219820Sjeff}
379219820Sjeffdefault_symver(__ibv_create_srq, ibv_create_srq);
380219820Sjeff
381219820Sjeffstruct ibv_srq *ibv_create_xrc_srq(struct ibv_pd *pd,
382219820Sjeff				   struct ibv_xrc_domain *xrc_domain,
383219820Sjeff				   struct ibv_cq *xrc_cq,
384219820Sjeff				   struct ibv_srq_init_attr *srq_init_attr)
385219820Sjeff{
386219820Sjeff	struct ibv_srq *srq;
387219820Sjeff
388219820Sjeff	if (!pd->context->more_ops)
389219820Sjeff		return NULL;
390219820Sjeff
391219820Sjeff	srq = pd->context->more_ops->create_xrc_srq(pd, xrc_domain,
392219820Sjeff						    xrc_cq, srq_init_attr);
393219820Sjeff	if (srq) {
394219820Sjeff		srq->context          = pd->context;
395219820Sjeff		srq->srq_context      = srq_init_attr->srq_context;
396219820Sjeff		srq->pd               = pd;
397219820Sjeff		srq->xrc_domain       = xrc_domain;
398219820Sjeff		srq->xrc_cq           = xrc_cq;
399219820Sjeff		srq->events_completed = 0;
400219820Sjeff		pthread_mutex_init(&srq->mutex, NULL);
401219820Sjeff		pthread_cond_init(&srq->cond, NULL);
402219820Sjeff	}
403219820Sjeff
404219820Sjeff	return srq;
405219820Sjeff}
406219820Sjeff
407219820Sjeffint __ibv_modify_srq(struct ibv_srq *srq,
408219820Sjeff		     struct ibv_srq_attr *srq_attr,
409219820Sjeff		     int srq_attr_mask)
410219820Sjeff{
411219820Sjeff	return srq->context->ops.modify_srq(srq, srq_attr, srq_attr_mask);
412219820Sjeff}
413219820Sjeffdefault_symver(__ibv_modify_srq, ibv_modify_srq);
414219820Sjeff
415219820Sjeffint __ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr)
416219820Sjeff{
417219820Sjeff	return srq->context->ops.query_srq(srq, srq_attr);
418219820Sjeff}
419219820Sjeffdefault_symver(__ibv_query_srq, ibv_query_srq);
420219820Sjeff
421219820Sjeffint __ibv_destroy_srq(struct ibv_srq *srq)
422219820Sjeff{
423219820Sjeff	return srq->context->ops.destroy_srq(srq);
424219820Sjeff}
425219820Sjeffdefault_symver(__ibv_destroy_srq, ibv_destroy_srq);
426219820Sjeff
427219820Sjeffstruct ibv_qp *__ibv_create_qp(struct ibv_pd *pd,
428219820Sjeff			       struct ibv_qp_init_attr *qp_init_attr)
429219820Sjeff{
430219820Sjeff	struct ibv_qp *qp = pd->context->ops.create_qp(pd, qp_init_attr);
431219820Sjeff
432219820Sjeff	if (qp) {
433219820Sjeff		qp->context    	     = pd->context;
434219820Sjeff		qp->qp_context 	     = qp_init_attr->qp_context;
435219820Sjeff		qp->pd         	     = pd;
436219820Sjeff		qp->send_cq    	     = qp_init_attr->send_cq;
437219820Sjeff		qp->recv_cq    	     = qp_init_attr->recv_cq;
438219820Sjeff		qp->srq        	     = qp_init_attr->srq;
439219820Sjeff		qp->qp_type          = qp_init_attr->qp_type;
440219820Sjeff		qp->state	     = IBV_QPS_RESET;
441219820Sjeff		qp->events_completed = 0;
442219820Sjeff		qp->xrc_domain       = qp_init_attr->qp_type == IBV_QPT_XRC ?
443219820Sjeff			qp_init_attr->xrc_domain : NULL;
444219820Sjeff		pthread_mutex_init(&qp->mutex, NULL);
445219820Sjeff		pthread_cond_init(&qp->cond, NULL);
446219820Sjeff	}
447219820Sjeff
448219820Sjeff	return qp;
449219820Sjeff}
450219820Sjeffdefault_symver(__ibv_create_qp, ibv_create_qp);
451219820Sjeff
452219820Sjeffint __ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
453219820Sjeff		   int attr_mask,
454219820Sjeff		   struct ibv_qp_init_attr *init_attr)
455219820Sjeff{
456219820Sjeff	int ret;
457219820Sjeff
458219820Sjeff	ret = qp->context->ops.query_qp(qp, attr, attr_mask, init_attr);
459219820Sjeff	if (ret)
460219820Sjeff		return ret;
461219820Sjeff
462219820Sjeff	if (attr_mask & IBV_QP_STATE)
463219820Sjeff		qp->state = attr->qp_state;
464219820Sjeff
465219820Sjeff	return 0;
466219820Sjeff}
467219820Sjeffdefault_symver(__ibv_query_qp, ibv_query_qp);
468219820Sjeff
469219820Sjeffint __ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr,
470219820Sjeff		    int attr_mask)
471219820Sjeff{
472219820Sjeff	int ret;
473219820Sjeff
474219820Sjeff	ret = qp->context->ops.modify_qp(qp, attr, attr_mask);
475219820Sjeff	if (ret)
476219820Sjeff		return ret;
477219820Sjeff
478219820Sjeff	if (attr_mask & IBV_QP_STATE)
479219820Sjeff		qp->state = attr->qp_state;
480219820Sjeff
481219820Sjeff	return 0;
482219820Sjeff}
483219820Sjeffdefault_symver(__ibv_modify_qp, ibv_modify_qp);
484219820Sjeff
485219820Sjeffint __ibv_destroy_qp(struct ibv_qp *qp)
486219820Sjeff{
487219820Sjeff	return qp->context->ops.destroy_qp(qp);
488219820Sjeff}
489219820Sjeffdefault_symver(__ibv_destroy_qp, ibv_destroy_qp);
490219820Sjeff
491219820Sjeffstruct ibv_ah *__ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr)
492219820Sjeff{
493219820Sjeff	struct ibv_ah *ah = pd->context->ops.create_ah(pd, attr);
494219820Sjeff
495219820Sjeff	if (ah) {
496219820Sjeff		ah->context = pd->context;
497219820Sjeff		ah->pd      = pd;
498219820Sjeff	}
499219820Sjeff
500219820Sjeff	return ah;
501219820Sjeff}
502219820Sjeffdefault_symver(__ibv_create_ah, ibv_create_ah);
503219820Sjeff
504219820Sjeffstatic int ibv_find_gid_index(struct ibv_context *context, uint8_t port_num,
505219820Sjeff			      union ibv_gid *gid)
506219820Sjeff{
507219820Sjeff	union ibv_gid sgid;
508219820Sjeff	int i = 0, ret;
509219820Sjeff
510219820Sjeff	do {
511219820Sjeff		ret = ibv_query_gid(context, port_num, i++, &sgid);
512219820Sjeff	} while (!ret && memcmp(&sgid, gid, sizeof *gid));
513219820Sjeff
514219820Sjeff	return ret ? ret : i - 1;
515219820Sjeff}
516219820Sjeff
517219820Sjeffint ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num,
518219820Sjeff			struct ibv_wc *wc, struct ibv_grh *grh,
519219820Sjeff			struct ibv_ah_attr *ah_attr)
520219820Sjeff{
521219820Sjeff	uint32_t flow_class;
522219820Sjeff	int ret;
523219820Sjeff
524219820Sjeff	memset(ah_attr, 0, sizeof *ah_attr);
525219820Sjeff	ah_attr->dlid = wc->slid;
526219820Sjeff	ah_attr->sl = wc->sl;
527219820Sjeff	ah_attr->src_path_bits = wc->dlid_path_bits;
528219820Sjeff	ah_attr->port_num = port_num;
529219820Sjeff
530219820Sjeff	if (wc->wc_flags & IBV_WC_GRH) {
531219820Sjeff		ah_attr->is_global = 1;
532219820Sjeff		ah_attr->grh.dgid = grh->sgid;
533219820Sjeff
534219820Sjeff		ret = ibv_find_gid_index(context, port_num, &grh->dgid);
535219820Sjeff		if (ret < 0)
536219820Sjeff			return ret;
537219820Sjeff
538219820Sjeff		ah_attr->grh.sgid_index = (uint8_t) ret;
539219820Sjeff		flow_class = ntohl(grh->version_tclass_flow);
540219820Sjeff		ah_attr->grh.flow_label = flow_class & 0xFFFFF;
541219820Sjeff		ah_attr->grh.hop_limit = grh->hop_limit;
542219820Sjeff		ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
543219820Sjeff	}
544219820Sjeff	return 0;
545219820Sjeff}
546219820Sjeff
547219820Sjeffstruct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc,
548219820Sjeff				     struct ibv_grh *grh, uint8_t port_num)
549219820Sjeff{
550219820Sjeff	struct ibv_ah_attr ah_attr;
551219820Sjeff	int ret;
552219820Sjeff
553219820Sjeff	ret = ibv_init_ah_from_wc(pd->context, port_num, wc, grh, &ah_attr);
554219820Sjeff	if (ret)
555219820Sjeff		return NULL;
556219820Sjeff
557219820Sjeff	return ibv_create_ah(pd, &ah_attr);
558219820Sjeff}
559219820Sjeff
560219820Sjeffint __ibv_destroy_ah(struct ibv_ah *ah)
561219820Sjeff{
562219820Sjeff	return ah->context->ops.destroy_ah(ah);
563219820Sjeff}
564219820Sjeffdefault_symver(__ibv_destroy_ah, ibv_destroy_ah);
565219820Sjeff
566219820Sjeffint __ibv_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid)
567219820Sjeff{
568219820Sjeff	return qp->context->ops.attach_mcast(qp, gid, lid);
569219820Sjeff}
570219820Sjeffdefault_symver(__ibv_attach_mcast, ibv_attach_mcast);
571219820Sjeff
572219820Sjeffint __ibv_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid)
573219820Sjeff{
574219820Sjeff	return qp->context->ops.detach_mcast(qp, gid, lid);
575219820Sjeff}
576219820Sjeffdefault_symver(__ibv_detach_mcast, ibv_detach_mcast);
577219820Sjeff
578219820Sjeffstruct ibv_xrc_domain *ibv_open_xrc_domain(struct ibv_context *context,
579219820Sjeff					   int fd, int oflag)
580219820Sjeff{
581219820Sjeff	struct ibv_xrc_domain *d;
582219820Sjeff
583219820Sjeff	if (!context->more_ops)
584219820Sjeff		return NULL;
585219820Sjeff
586219820Sjeff	d = context->more_ops->open_xrc_domain(context, fd, oflag);
587219820Sjeff	if (d)
588219820Sjeff		d->context = context;
589219820Sjeff
590219820Sjeff	return d;
591219820Sjeff}
592219820Sjeff
593219820Sjeffint ibv_close_xrc_domain(struct ibv_xrc_domain *d)
594219820Sjeff{
595219820Sjeff	if (!d->context->more_ops)
596219820Sjeff		return 0;
597219820Sjeff
598219820Sjeff	return d->context->more_ops->close_xrc_domain(d);
599219820Sjeff}
600219820Sjeff
601219820Sjeffint ibv_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr,
602219820Sjeff			  uint32_t *xrc_rcv_qpn)
603219820Sjeff{
604219820Sjeff	struct ibv_context *c;
605219820Sjeff	if (!init_attr || !(init_attr->xrc_domain))
606219820Sjeff		return EINVAL;
607219820Sjeff
608219820Sjeff	c = init_attr->xrc_domain->context;
609219820Sjeff	if (!c->more_ops)
610219820Sjeff		return ENOSYS;
611219820Sjeff
612219820Sjeff	return c->more_ops->create_xrc_rcv_qp(init_attr,
613219820Sjeff					      xrc_rcv_qpn);
614219820Sjeff}
615219820Sjeff
616219820Sjeffint ibv_modify_xrc_rcv_qp(struct ibv_xrc_domain *d,
617219820Sjeff			  uint32_t xrc_rcv_qpn,
618219820Sjeff			  struct ibv_qp_attr *attr,
619219820Sjeff			  int attr_mask)
620219820Sjeff{
621219820Sjeff	if (!d || !attr)
622219820Sjeff		return EINVAL;
623219820Sjeff
624219820Sjeff	if (!d->context->more_ops)
625219820Sjeff		return ENOSYS;
626219820Sjeff
627219820Sjeff	return d->context->more_ops->modify_xrc_rcv_qp(d, xrc_rcv_qpn, attr,
628219820Sjeff						       attr_mask);
629219820Sjeff}
630219820Sjeff
631219820Sjeffint ibv_query_xrc_rcv_qp(struct ibv_xrc_domain *d,
632219820Sjeff			 uint32_t xrc_rcv_qpn,
633219820Sjeff			 struct ibv_qp_attr *attr,
634219820Sjeff			 int attr_mask,
635219820Sjeff			 struct ibv_qp_init_attr *init_attr)
636219820Sjeff{
637219820Sjeff	if (!d)
638219820Sjeff		return EINVAL;
639219820Sjeff
640219820Sjeff	if (!d->context->more_ops)
641219820Sjeff		return ENOSYS;
642219820Sjeff
643219820Sjeff	return d->context->more_ops->query_xrc_rcv_qp(d, xrc_rcv_qpn, attr,
644219820Sjeff						      attr_mask, init_attr);
645219820Sjeff}
646219820Sjeff
647219820Sjeffint ibv_reg_xrc_rcv_qp(struct ibv_xrc_domain *d,
648219820Sjeff		       uint32_t xrc_rcv_qpn)
649219820Sjeff{
650219820Sjeff	return d->context->more_ops->reg_xrc_rcv_qp(d, xrc_rcv_qpn);
651219820Sjeff}
652219820Sjeff
653219820Sjeffint ibv_unreg_xrc_rcv_qp(struct ibv_xrc_domain *d,
654219820Sjeff			 uint32_t xrc_rcv_qpn)
655219820Sjeff{
656219820Sjeff	return d->context->more_ops->unreg_xrc_rcv_qp(d, xrc_rcv_qpn);
657219820Sjeff}
658219820Sjeff
659219820Sjeff
660219820Sjeffstatic uint16_t get_vlan_id(const union ibv_gid *dgid)
661219820Sjeff{
662219820Sjeff	return dgid->raw[11] << 8 | dgid->raw[12];
663219820Sjeff}
664219820Sjeff
665219820Sjeffstatic void get_ll_mac(const union ibv_gid *gid, uint8_t *mac)
666219820Sjeff{
667219820Sjeff	memcpy(mac, &gid->raw[8], 3);
668219820Sjeff	memcpy(mac + 3, &gid->raw[13], 3);
669219820Sjeff	mac[0] ^= 2;
670219820Sjeff}
671219820Sjeff
672219820Sjeffstatic int is_multicast_gid(const union ibv_gid *gid)
673219820Sjeff{
674219820Sjeff	return gid->raw[0] == 0xff;
675219820Sjeff}
676219820Sjeff
677219820Sjeffstatic void get_mcast_mac(const union ibv_gid *gid, uint8_t *mac)
678219820Sjeff{
679219820Sjeff	int i;
680219820Sjeff
681219820Sjeff	mac[0] = 0x33;
682219820Sjeff	mac[1] = 0x33;
683219820Sjeff	for (i = 2; i < 6; ++i)
684219820Sjeff		mac[i] = gid->raw[i + 10];
685219820Sjeff}
686219820Sjeff
687219820Sjeffstatic int is_link_local_gid(const union ibv_gid *gid)
688219820Sjeff{
689219820Sjeff	uint32_t hi = *(uint32_t *)(gid->raw);
690219820Sjeff	uint32_t lo = *(uint32_t *)(gid->raw + 4);
691219820Sjeff	if (hi == htonl(0xfe800000) && lo == 0)
692219820Sjeff		return 1;
693219820Sjeff
694219820Sjeff	return 0;
695219820Sjeff}
696219820Sjeff
697219820Sjeffstatic int resolve_gid(const union ibv_gid *dgid, uint8_t *mac, uint8_t *is_mcast)
698219820Sjeff{
699219820Sjeff	if (is_link_local_gid(dgid)) {
700219820Sjeff		get_ll_mac(dgid, mac);
701219820Sjeff		*is_mcast = 0;
702219820Sjeff	} else if (is_multicast_gid(dgid)) {
703219820Sjeff		get_mcast_mac(dgid, mac);
704219820Sjeff		*is_mcast = 1;
705219820Sjeff	} else
706219820Sjeff		return -EINVAL;
707219820Sjeff
708219820Sjeff	return 0;
709219820Sjeff}
710219820Sjeff
711219820Sjeffstatic int is_tagged_vlan(const union ibv_gid *gid)
712219820Sjeff{
713219820Sjeff	uint16_t tag;
714219820Sjeff
715219820Sjeff	tag = gid->raw[11] << 8 |  gid->raw[12];
716219820Sjeff
717219820Sjeff	return tag < 0x1000;
718219820Sjeff}
719219820Sjeff
720219820Sjeffint __ibv_resolve_eth_gid(const struct ibv_pd *pd, uint8_t port_num,
721219820Sjeff			  union ibv_gid *dgid, uint8_t sgid_index,
722219820Sjeff			  uint8_t mac[], uint16_t *vlan, uint8_t *tagged,
723219820Sjeff			  uint8_t *is_mcast)
724219820Sjeff{
725219820Sjeff	int err;
726219820Sjeff	union ibv_gid sgid;
727219820Sjeff	int stagged, svlan;
728219820Sjeff
729219820Sjeff	err = resolve_gid(dgid, mac, is_mcast);
730219820Sjeff	if (err)
731219820Sjeff		return err;
732219820Sjeff
733219820Sjeff	err = ibv_query_gid(pd->context, port_num, sgid_index, &sgid);
734219820Sjeff	if (err)
735219820Sjeff		return err;
736219820Sjeff
737219820Sjeff	stagged = is_tagged_vlan(&sgid);
738219820Sjeff	if (stagged) {
739219820Sjeff		if (!is_tagged_vlan(dgid) && !is_mcast)
740219820Sjeff			return -1;
741219820Sjeff
742219820Sjeff		svlan = get_vlan_id(&sgid);
743219820Sjeff		if (svlan != get_vlan_id(dgid) && !is_mcast)
744219820Sjeff			return -1;
745219820Sjeff
746219820Sjeff		*tagged = 1;
747219820Sjeff		*vlan = svlan;
748219820Sjeff	} else
749219820Sjeff		*tagged = 0;
750219820Sjeff
751219820Sjeff	return 0;
752219820Sjeff}
753219820Sjeffdefault_symver(__ibv_resolve_eth_gid, ibv_resolve_eth_gid);
754219820Sjeff
755