aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Dreier <roland@topspin.com>2005-01-10 23:47:29 +0000
committerRoland Dreier <rolandd@cisco.com>2006-11-09 11:35:56 -0800
commit1ac479a3286fef634d2a6f6b10a33b1452ef1d1d (patch)
treea2a6d91ac8c6e6b96476e68817c7e944b4a3f659
parentf43b7ec6dda58c5f62cd2541edb2e4479580cc9e (diff)
downloadlibibverbs-1ac479a3286fef634d2a6f6b10a33b1452ef1d1d.tar.gz
Fill in more verbs API
Start filling in more of the verbs API. Implement tracking for possibly overlapping locked memory ranges.
-rw-r--r--Makefile.am2
-rw-r--r--configure.in8
-rw-r--r--include/infiniband/verbs.h59
-rw-r--r--src/device.c20
-rw-r--r--src/ibverbs.h6
-rw-r--r--src/init.c3
-rw-r--r--src/libibverbs.map6
-rw-r--r--src/memory.c257
8 files changed, 358 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am
index 9591ae7..7bafe38 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,7 +12,7 @@ else
libibverbs_version_script =
endif
-src_libibverbs_la_SOURCES = src/init.c src/device.c
+src_libibverbs_la_SOURCES = src/init.c src/device.c src/memory.c
src_libibverbs_la_LDFLAGS = -version-info 1 -export-dynamic \
$(libibverbs_version_script)
src_libibverbs_la_DEPENDENCIES = $(srcdir)/src/libibverbs.map
diff --git a/configure.in b/configure.in
index 94d03ff..b3806e0 100644
--- a/configure.in
+++ b/configure.in
@@ -13,8 +13,12 @@ dnl Checks for programs
AC_PROG_CC
dnl Checks for libraries
-AC_CHECK_LIB(dl, dlsym)
-AC_CHECK_LIB(sysfs, sysfs_open_class)
+AC_CHECK_LIB(dl, dlsym, [],
+ AC_MSG_ERROR([dlsym() not found. libibverbs requires libdl.]))
+AC_CHECK_LIB(pthread, pthread_mutex_init, [],
+ AC_MSG_ERROR([pthread_mutex_init() not found. libibverbs requires libpthread.]))
+AC_CHECK_LIB(sysfs, sysfs_open_class, [],
+ AC_MSG_ERROR([sysfs_open_class() not found. libibverbs requires libsysfs.]))
dnl Checks for header files.
AC_CHECK_HEADER(sysfs/libsysfs.h, [],
diff --git a/include/infiniband/verbs.h b/include/infiniband/verbs.h
index aa65232..d0ac245 100644
--- a/include/infiniband/verbs.h
+++ b/include/infiniband/verbs.h
@@ -49,6 +49,30 @@
BEGIN_C_DECLS
+enum ibv_access_flags {
+ IBV_ACCESS_LOCAL_WRITE = 1,
+ IBV_ACCESS_REMOTE_WRITE = (1<<1),
+ IBV_ACCESS_REMOTE_READ = (1<<2),
+ IBV_ACCESS_REMOTE_ATOMIC = (1<<3),
+ IBV_ACCESS_MW_BIND = (1<<4)
+};
+
+struct ibv_pd {
+
+};
+
+struct ibv_mr {
+
+};
+
+struct ibv_qp {
+
+};
+
+struct ibv_cq {
+
+};
+
struct ibv_device_ops {
};
@@ -59,6 +83,10 @@ struct ibv_device {
struct ibv_device_ops ops;
};
+struct ibv_context {
+ struct ibv_device *device;
+};
+
/**
* ibv_get_devices - Return list of IB devices
*/
@@ -74,6 +102,37 @@ extern const char *ibv_get_device_name(struct ibv_device *device);
*/
extern uint64_t ibv_get_device_guid(struct ibv_device *device);
+/**
+ * ibv_open_device - Initialize device for use
+ */
+extern struct ibv_context *ibv_open_device(struct ibv_device *device);
+
+/**
+ * ibv_close_device - Release device
+ */
+extern int ibv_close_device(struct ibv_context *context);
+
+/**
+ * ibv_alloc_pd - Allocate a protection domain
+ */
+extern struct ibv_pd *ibv_alloc_pd(struct ibv_context *context);
+
+/**
+ * ibv_dealloc_pd - Free a protection domain
+ */
+extern int ibv_dealloc_pd(struct ibv_pd *pd);
+
+/**
+ * ibv_reg_mr - Register a memory region
+ */
+extern struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr,
+ size_t length, enum ibv_access_flags access);
+
+/**
+ * ibv_dereg_mr - Deregister a memory region
+ */
+extern int ibv_dereg_mr(struct ibv_mr *mr);
+
END_C_DECLS
#endif /* INFINIBAND_VERBS_H */
diff --git a/src/device.c b/src/device.c
index 96d13ff..f3a3073 100644
--- a/src/device.c
+++ b/src/device.c
@@ -70,3 +70,23 @@ uint64_t ibv_get_device_guid(struct ibv_device *device)
return *(uint64_t *) guid;
}
+
+struct ibv_context *ibv_open_device(struct ibv_device *device)
+{
+ struct ibv_context *context;
+
+ context = malloc(sizeof *context);
+ if (!context)
+ return NULL;
+
+ context->device = device;
+
+ return context;
+}
+
+int ibv_close_device(struct ibv_context *context)
+{
+ free(context);
+
+ return 0;
+}
diff --git a/src/ibverbs.h b/src/ibverbs.h
index 2dc5646..f97e93e 100644
--- a/src/ibverbs.h
+++ b/src/ibverbs.h
@@ -35,6 +35,8 @@
#ifndef IB_VERBS_H
#define IB_VERBS_H
+#include <pthread.h>
+
#include <infiniband/verbs.h>
#include <infiniband/driver.h>
@@ -51,4 +53,8 @@ struct ibv_driver {
extern Dlist *device_list;
+extern int ibv_init_mem_map(void);
+extern int ibv_lock_range(void *base, size_t size);
+extern int ibv_unlock_range(void *base, size_t size);
+
#endif /* IB_VERBS_H */
diff --git a/src/init.c b/src/init.c
index 2620065..1f19d36 100644
--- a/src/init.c
+++ b/src/init.c
@@ -136,6 +136,9 @@ static void INIT ibverbs_init(void)
Dlist *ib_dev_list;
struct sysfs_class_device *ib_dev;
+ if (ibv_init_mem_map())
+ abort();
+
driver_list = dlist_new(sizeof (struct ibv_driver));
device_list = dlist_new(sizeof (struct ibv_device));
if (!driver_list || !device_list)
diff --git a/src/libibverbs.map b/src/libibverbs.map
index 61742fa..81c2d1e 100644
--- a/src/libibverbs.map
+++ b/src/libibverbs.map
@@ -3,5 +3,11 @@ IBVERBS_1.0 {
ibv_get_devices;
ibv_get_device_name;
ibv_get_device_guid;
+ ibv_open_device;
+ ibv_close_device;
+ ibv_alloc_pd;
+ ibv_dealloc_pd;
+ ibv_reg_mr;
+ ibv_dereg_mr;
local: *;
};
diff --git a/src/memory.c b/src/memory.c
new file mode 100644
index 0000000..fb11b3f
--- /dev/null
+++ b/src/memory.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2004, 2005 Topspin Communications. 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.
+ *
+ * $Id$
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "ibverbs.h"
+
+/*
+ * We keep a linked list of page ranges that have been locked along with a
+ * reference count to manage overlapping registrations, etc.
+ *
+ * Eventually we should turn this into an RB-tree or something similar
+ * to avoid the O(n) cost of registering/unregistering memory.
+ */
+
+struct ibv_mem_node {
+ struct ibv_mem_node *prev, *next;
+ uintptr_t start, end;
+ int refcnt;
+};
+
+static struct {
+ struct ibv_mem_node *first;
+ pthread_mutex_t mutex;
+ uintptr_t page_size;
+} mem_map;
+
+int ibv_init_mem_map(void)
+{
+ struct ibv_mem_node *node = NULL;
+
+ node = malloc(sizeof *node);
+ if (!node)
+ goto fail;
+
+ node->prev = node->next = NULL;
+ node->start = 0;
+ node->end = UINTPTR_MAX;
+ node->refcnt = 0;
+
+ mem_map.first = node;
+
+ mem_map.page_size = sysconf(_SC_PAGESIZE);
+ if (mem_map.page_size < 0)
+ goto fail;
+
+ if (pthread_mutex_init(&mem_map.mutex, NULL))
+ goto fail;
+
+ return 0;
+
+fail:
+ if (node)
+ free(node);
+
+ return -1;
+}
+
+static struct ibv_mem_node *__mm_find_first(uintptr_t start, uintptr_t end)
+{
+ struct ibv_mem_node *node = mem_map.first;
+
+ while (node) {
+ if ((node->start <= start && node->end >= start) ||
+ (node->start <= end && node->end >= end))
+ break;
+ node = node->next;
+ }
+
+ return node;
+}
+
+static struct ibv_mem_node *__mm_prev(struct ibv_mem_node *node)
+{
+ return node->prev;
+}
+
+static struct ibv_mem_node *__mm_next(struct ibv_mem_node *node)
+{
+ return node->next;
+}
+
+static void __mm_add(struct ibv_mem_node *node,
+ struct ibv_mem_node *new)
+{
+ new->prev = node;
+ new->next = node->next;
+ node->next = new;
+ if (new->next)
+ new->next->prev = new;
+}
+
+static void __mm_remove(struct ibv_mem_node *node)
+{
+ /* Never have to remove the first node, so we can use prev */
+ node->prev->next = node->next;
+ if (node->next)
+ node->next->prev = node->prev;
+}
+
+int ibv_lock_range(void *base, size_t size)
+{
+ uintptr_t start, end;
+ struct ibv_mem_node *node, *tmp;
+ int ret = 0;
+
+ if (!size)
+ return 0;
+
+ start = (uintptr_t) base & ~(mem_map.page_size - 1);
+ end = ((uintptr_t) (base + size + mem_map.page_size - 1) &
+ ~(mem_map.page_size - 1)) - 1;
+
+ pthread_mutex_lock(&mem_map.mutex);
+
+ node = __mm_find_first(start, end);
+
+ if (node->start < start) {
+ tmp = malloc(sizeof *tmp);
+ if (!tmp) {
+ ret = -1;
+ goto out;
+ }
+
+ tmp->start = start;
+ tmp->end = node->end;
+ tmp->refcnt = node->refcnt;
+ node->end = start - 1;
+
+ __mm_add(node, tmp);
+ node = tmp;
+ }
+
+ while (node->start <= end) {
+ if (node->end > end) {
+ tmp = malloc(sizeof *tmp);
+ if (!tmp) {
+ ret = -1;
+ goto out;
+ }
+
+ tmp->start = end + 1;
+ tmp->end = node->end;
+ tmp->refcnt = node->refcnt;
+ node->end = end;
+
+ __mm_add(node, tmp);
+ }
+
+
+ if (node->refcnt++ == 0) {
+ ret = mlock((void *) node->start,
+ node->end - node->start + 1);
+ if (ret)
+ goto out;
+ }
+
+ node = __mm_next(node);
+ }
+
+out:
+ pthread_mutex_unlock(&mem_map.mutex);
+
+ return ret;
+}
+
+int ibv_unlock_range(void *base, size_t size)
+{
+ uintptr_t start, end;
+ struct ibv_mem_node *node, *tmp;
+ int ret = 0;
+
+ if (!size)
+ return 0;
+
+ start = (uintptr_t) base & ~(mem_map.page_size - 1);
+ end = ((uintptr_t) (base + size + mem_map.page_size - 1) &
+ ~(mem_map.page_size - 1)) - 1;
+
+ pthread_mutex_lock(&mem_map.mutex);
+
+ node = __mm_find_first(start, end);
+
+ if (node->start != start) {
+ ret = -1;
+ goto out;
+ }
+
+ while (node && node->end <= end) {
+ if (--node->refcnt == 0) {
+ ret = munlock((void *) node->start,
+ node->end - node->start + 1);
+ }
+
+ if (__mm_prev(node) && node->refcnt == __mm_prev(node)->refcnt) {
+ __mm_prev(node)->end = node->end;
+ tmp = __mm_prev(node);
+ __mm_remove(node);
+ node = tmp;
+ }
+
+ node = __mm_next(node);
+ }
+
+ if (node && node->refcnt == __mm_prev(node)->refcnt) {
+ __mm_prev(node)->end = node->end;
+ tmp = __mm_prev(node);
+ __mm_remove(node);
+ }
+
+ if (node->end != end) {
+ ret = -1;
+ goto out;
+ }
+
+out:
+ pthread_mutex_unlock(&mem_map.mutex);
+
+ return ret;
+}