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