diff options
author | Roland Dreier <roland@topspin.com> | 2005-01-10 23:47:29 +0000 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-11-09 11:35:56 -0800 |
commit | 1ac479a3286fef634d2a6f6b10a33b1452ef1d1d (patch) | |
tree | a2a6d91ac8c6e6b96476e68817c7e944b4a3f659 | |
parent | f43b7ec6dda58c5f62cd2541edb2e4479580cc9e (diff) | |
download | libibverbs-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.am | 2 | ||||
-rw-r--r-- | configure.in | 8 | ||||
-rw-r--r-- | include/infiniband/verbs.h | 59 | ||||
-rw-r--r-- | src/device.c | 20 | ||||
-rw-r--r-- | src/ibverbs.h | 6 | ||||
-rw-r--r-- | src/init.c | 3 | ||||
-rw-r--r-- | src/libibverbs.map | 6 | ||||
-rw-r--r-- | src/memory.c | 257 |
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 */ @@ -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; +} |