blob: 3abc1ebca7fc1f0e1714281e3ca753f9a053c06c [file] [log] [blame]
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
* Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <alloca.h>
#include <infiniband/arch.h>
#include "ibverbs.h"
static pthread_mutex_t device_list_lock = PTHREAD_MUTEX_INITIALIZER;
static int num_devices;
static struct ibv_device **device_list;
struct ibv_device **__ibv_get_device_list(int *num)
{
struct ibv_device **l;
int i;
pthread_mutex_lock(&device_list_lock);
if (!num_devices)
num_devices = ibverbs_init(&device_list);
l = calloc(num_devices + 1, sizeof (struct ibv_device *));
if (!l)
goto out;
for (i = 0; i < num_devices; ++i)
l[i] = device_list[i];
out:
pthread_mutex_unlock(&device_list_lock);
if (num)
*num = l ? num_devices : 0;
return l;
}
default_symver(__ibv_get_device_list, ibv_get_device_list);
void __ibv_free_device_list(struct ibv_device **list)
{
free(list);
}
default_symver(__ibv_free_device_list, ibv_free_device_list);
const char *__ibv_get_device_name(struct ibv_device *device)
{
return device->name;
}
default_symver(__ibv_get_device_name, ibv_get_device_name);
uint64_t __ibv_get_device_guid(struct ibv_device *device)
{
char attr[24];
uint64_t guid = 0;
uint16_t parts[4];
int i;
if (ibv_read_sysfs_file(device->ibdev_path, "node_guid",
attr, sizeof attr) < 0)
return 0;
if (sscanf(attr, "%hx:%hx:%hx:%hx",
parts, parts + 1, parts + 2, parts + 3) != 4)
return 0;
for (i = 0; i < 4; ++i)
guid = (guid << 16) | parts[i];
return htonll(guid);
}
default_symver(__ibv_get_device_guid, ibv_get_device_guid);
struct ibv_context *__ibv_open_device(struct ibv_device *device)
{
char *devpath;
int cmd_fd;
struct ibv_context *context;
if (asprintf(&devpath, "/dev/infiniband/%s", device->dev_name) < 0)
return NULL;
/*
* We'll only be doing writes, but we need O_RDWR in case the
* provider needs to mmap() the file.
*/
cmd_fd = open(devpath, O_RDWR);
free(devpath);
if (cmd_fd < 0)
return NULL;
context = device->ops.alloc_context(device, cmd_fd);
if (!context)
goto err;
context->device = device;
context->cmd_fd = cmd_fd;
pthread_mutex_init(&context->mutex, NULL);
return context;
err:
close(cmd_fd);
return NULL;
}
default_symver(__ibv_open_device, ibv_open_device);
int __ibv_close_device(struct ibv_context *context)
{
int async_fd = context->async_fd;
int cmd_fd = context->cmd_fd;
int cq_fd = -1;
if (abi_ver <= 2) {
struct ibv_abi_compat_v2 *t = context->abi_compat;
cq_fd = t->channel.fd;
free(context->abi_compat);
}
context->device->ops.free_context(context);
close(async_fd);
close(cmd_fd);
if (abi_ver <= 2)
close(cq_fd);
return 0;
}
default_symver(__ibv_close_device, ibv_close_device);
int __ibv_get_async_event(struct ibv_context *context,
struct ibv_async_event *event)
{
struct ibv_kern_async_event ev;
if (read(context->async_fd, &ev, sizeof ev) != sizeof ev)
return -1;
event->event_type = ev.event_type;
switch (event->event_type) {
case IBV_EVENT_CQ_ERR:
event->element.cq = (void *) (uintptr_t) ev.element;
break;
case IBV_EVENT_QP_FATAL:
case IBV_EVENT_QP_REQ_ERR:
case IBV_EVENT_QP_ACCESS_ERR:
case IBV_EVENT_COMM_EST:
case IBV_EVENT_SQ_DRAINED:
case IBV_EVENT_PATH_MIG:
case IBV_EVENT_PATH_MIG_ERR:
case IBV_EVENT_QP_LAST_WQE_REACHED:
event->element.qp = (void *) (uintptr_t) ev.element;
break;
case IBV_EVENT_SRQ_ERR:
case IBV_EVENT_SRQ_LIMIT_REACHED:
event->element.srq = (void *) (uintptr_t) ev.element;
break;
default:
event->element.port_num = ev.element;
break;
}
if (context->ops.async_event)
context->ops.async_event(event);
return 0;
}
default_symver(__ibv_get_async_event, ibv_get_async_event);
void __ibv_ack_async_event(struct ibv_async_event *event)
{
switch (event->event_type) {
case IBV_EVENT_CQ_ERR:
{
struct ibv_cq *cq = event->element.cq;
pthread_mutex_lock(&cq->mutex);
++cq->async_events_completed;
pthread_cond_signal(&cq->cond);
pthread_mutex_unlock(&cq->mutex);
return;
}
case IBV_EVENT_QP_FATAL:
case IBV_EVENT_QP_REQ_ERR:
case IBV_EVENT_QP_ACCESS_ERR:
case IBV_EVENT_COMM_EST:
case IBV_EVENT_SQ_DRAINED:
case IBV_EVENT_PATH_MIG:
case IBV_EVENT_PATH_MIG_ERR:
case IBV_EVENT_QP_LAST_WQE_REACHED:
{
struct ibv_qp *qp = event->element.qp;
pthread_mutex_lock(&qp->mutex);
++qp->events_completed;
pthread_cond_signal(&qp->cond);
pthread_mutex_unlock(&qp->mutex);
return;
}
case IBV_EVENT_SRQ_ERR:
case IBV_EVENT_SRQ_LIMIT_REACHED:
{
struct ibv_srq *srq = event->element.srq;
pthread_mutex_lock(&srq->mutex);
++srq->events_completed;
pthread_cond_signal(&srq->cond);
pthread_mutex_unlock(&srq->mutex);
return;
}
default:
return;
}
}
default_symver(__ibv_ack_async_event, ibv_ack_async_event);