diff options
Diffstat (limited to 'bmm_lib.c')
-rw-r--r-- | bmm_lib.c | 264 |
1 files changed, 210 insertions, 54 deletions
@@ -15,11 +15,15 @@ #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> +#include <assert.h> #include <fcntl.h> +#include <pthread.h> +#include <stdlib.h> #include <unistd.h> #include "bmm_lib_priv.h" #include "bmm_lib.h" +#include "rb.h" #undef DEBUG @@ -38,6 +42,108 @@ static unsigned bmm_api; static int bmm_fd = -1; +static pthread_mutex_t bmm_mutex = PTHREAD_MUTEX_INITIALIZER; +static Rb_node virt_rb; +static Rb_node phys_rb; + +struct bmm_buffer { + void *vaddr; + unsigned long paddr; + size_t size; + int attr; +}; + +static int cmp_virt(const void *key, const void *val) +{ + const struct bmm_buffer *buf = val; + void *k = (void *)key; + + return (k < buf->vaddr) ? -1 : + (k - buf->vaddr < buf->size) ? 0 : 1; +} + +static int cmp_phys(const void *key, const void *val) +{ + const struct bmm_buffer *buf = val; + unsigned long k = (unsigned long)key; + + return (k < buf->paddr) ? -1 : + (k - buf->paddr < buf->size) ? 0 : 1; +} + +static struct bmm_buffer *bmm_buf_find_virt(void *virt) +{ + struct bmm_buffer *buf = NULL; + Rb_node node; + int found = 0; + + node = rb_find_key_n(virt_rb, virt, cmp_virt, &found); + if (found) { + buf = rb_val(node); + + pr_debug("rb: %s(%p) phys=0x%08lx virt=%p size=0x%08lx\n", + "find_virt", virt, buf->paddr, buf->vaddr, buf->size); + } else { + pr_debug("rb: %s(%p): not found\n", + "find_virt", virt); + } + + return buf; +} + +static struct bmm_buffer *bmm_buf_find_phys(unsigned long phys) +{ + struct bmm_buffer *buf = NULL; + Rb_node node; + int found = 0; + + node = rb_find_key_n(phys_rb, (void *)phys, cmp_phys, &found); + if (found) { + buf = rb_val(node); + + pr_debug("rb: %s(0x%08lx) phys=0x%08lx virt=%p size=0x%08lx\n", + "find_phys", (unsigned long)phys, buf->paddr, buf->vaddr, buf->size); + } else { + pr_debug("rb: %s(0x%08lx): not found\n", + "find_phys", (unsigned long)phys); + } + + return buf; +} + +static void bmm_buf_remove(struct bmm_buffer *buf) +{ + Rb_node node; + int found = 0; + + pr_debug("rb: %s phys=0x%08lx virt=%p size=0x%08lx\n", + "remove", buf->paddr, buf->vaddr, buf->size); + + node = rb_find_key_n(virt_rb, buf->vaddr, cmp_virt, &found); + assert(found); + rb_delete_node(node); + + node = rb_find_key_n(phys_rb, (void *)buf->paddr, cmp_phys, &found); + assert(found); + rb_delete_node(node); +} + +static void bmm_buf_insert(struct bmm_buffer *buf) +{ + Rb_node node; + int found = 0; + + pr_debug("rb: %s phys=0x%08lx virt=%p size=0x%08lx\n", + "insert", buf->paddr, buf->vaddr, buf->size); + + node = rb_find_key_n(virt_rb, buf->vaddr, cmp_virt, &found); + assert(found == 0); + rb_insert_b(node, buf); + + node = rb_find_key_n(phys_rb, (void *)buf->paddr, cmp_phys, &found); + assert(found == 0); + rb_insert_b(node, buf); +} static int bmm_get_api_version(void) { @@ -64,10 +170,14 @@ static int bmm_get_api_version(void) int bmm_init() { - /* attempt to open the BMM driver */ - if(bmm_fd < 0) { - bmm_fd = open(BMM_DEVICE_FILE, O_RDWR | O_CLOEXEC); + if (bmm_fd < 0) { + virt_rb = make_rb(); + phys_rb = make_rb(); + if (!virt_rb || !phys_rb) + goto err_rb; + /* attempt to open the BMM driver */ + bmm_fd = open(BMM_DEVICE_FILE, O_RDWR | O_CLOEXEC); pr_debug("BMM device fd: %d\n", bmm_fd); if (bmm_fd < 0) goto err_open; @@ -82,18 +192,29 @@ int bmm_init() close(bmm_fd); bmm_fd = -1; err_open: + err_rb: + if (phys_rb) + rb_free_tree(phys_rb); + if (virt_rb) + rb_free_tree(virt_rb); + phys_rb = virt_rb = NULL; return bmm_fd; } void bmm_exit() { - if(bmm_fd >= 0) + if (bmm_fd >= 0) { close(bmm_fd); + rb_free_tree(phys_rb); + rb_free_tree(virt_rb); + phys_rb = virt_rb = NULL; + } bmm_fd = -1; } void *bmm_malloc_aligned(unsigned long size, int attr, unsigned align) { + struct bmm_buffer *buf; int ret; void *vaddr; ioctl_arg_t io; @@ -104,6 +225,10 @@ void *bmm_malloc_aligned(unsigned long size, int attr, unsigned align) if(bmm_init() < 0) return NULL; + buf = malloc(sizeof(*buf)); + if (!buf) + return NULL; + pr_debug("%s(size=%lu,attr=%x,align=%u)\n", __FUNCTION__, size, attr, align); /* obsolete, only for back-compatible */ @@ -118,13 +243,31 @@ void *bmm_malloc_aligned(unsigned long size, int attr, unsigned align) io.output = 0; io.arg = attr; ret = ioctl(bmm_fd, BMM_MALLOC_ALIGNED, &io); - if(ret < 0 || io.output == 0) - return NULL; + if (ret < 0 || io.output == 0) + goto err_free_buf; pr_debug("bmm_malloc return paddr = 0x%08lx\n", io.output); vaddr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, bmm_fd, io.output); - return ((int)vaddr == -1) ? NULL : vaddr; + if ((int)vaddr == -1) { + /* FIXME: we can't free the bmm buffer without a vaddr! */ + goto err_free_buf; + } + + buf->vaddr = vaddr; + buf->paddr = io.output; + buf->size = size; + buf->attr = attr; + + pthread_mutex_lock(&bmm_mutex); + bmm_buf_insert(buf); + pthread_mutex_unlock(&bmm_mutex); + + return vaddr; + + err_free_buf: + free(buf); + return NULL; } void *bmm_malloc(unsigned long size, int attr) @@ -134,19 +277,27 @@ void *bmm_malloc(unsigned long size, int attr) void bmm_free(void *vaddr) { - unsigned long size; + struct bmm_buffer *buf; ioctl_arg_t io; - if(bmm_init() < 0) + if (bmm_init() < 0) return; - size = bmm_get_mem_size(vaddr); - munmap(vaddr, size); + pthread_mutex_lock(&bmm_mutex); + buf = bmm_buf_find_virt(vaddr); + if (buf) + bmm_buf_remove(buf); + pthread_mutex_unlock(&bmm_mutex); - io.input = (unsigned long)vaddr; + assert(buf); + + munmap(buf->vaddr, buf->size); + + io.input = (unsigned long)buf->vaddr; io.output = 0; io.arg = 0; ioctl(bmm_fd, BMM_FREE, &io); + free(buf); } void *bmm_attach(unsigned long paddr, unsigned long len) @@ -174,38 +325,36 @@ void bmm_detach(void *vaddr, unsigned long len) void *bmm_get_vaddr(unsigned long paddr) { - int ret; - ioctl_arg_t io; + struct bmm_buffer *buf; + void *va = NULL; - if(bmm_init() < 0) - return NULL; + if (bmm_init() < 0) + return 0; - io.input = paddr; - io.output = 0; - io.arg = 0; - ret = ioctl(bmm_fd, BMM_GET_VIRT_ADDR, &io); - if(ret < 0) - return NULL; + pthread_mutex_lock(&bmm_mutex); + buf = bmm_buf_find_phys(paddr); + if (buf) + va = buf->vaddr + (paddr - buf->paddr); + pthread_mutex_unlock(&bmm_mutex); - return (void *)io.output; + return va; } unsigned long bmm_get_paddr(void *vaddr) { - int ret; - ioctl_arg_t io; + struct bmm_buffer *buf; + unsigned long pa = 0; - if(bmm_init() < 0) + if (bmm_init() < 0) return 0; - io.input = (unsigned long)vaddr; - io.output = 0; - io.arg = 0; - ret = ioctl(bmm_fd,BMM_GET_PHYS_ADDR, &io); - if(ret < 0) - return 0; + pthread_mutex_lock(&bmm_mutex); + buf = bmm_buf_find_virt(vaddr); + if (buf) + pa = buf->paddr + (vaddr - buf->vaddr); + pthread_mutex_unlock(&bmm_mutex); - return io.output; + return pa; } int bmm_get_dmabuf_fd(void *vaddr) @@ -227,42 +376,41 @@ int bmm_get_dmabuf_fd(void *vaddr) unsigned long bmm_get_mem_size(void *vaddr) { - int ret; - ioctl_arg_t io; + struct bmm_buffer *buf; + unsigned long size = 0; - if(bmm_init() < 0) + if (bmm_init() < 0) return 0; - io.input = (unsigned long)vaddr; - io.output = 0; - io.arg = 0; - ret = ioctl(bmm_fd,BMM_GET_MEM_SIZE, &io); - if(ret < 0) - return 0; + pthread_mutex_lock(&bmm_mutex); + buf = bmm_buf_find_virt(vaddr); + if (buf) + size = buf->size; + pthread_mutex_unlock(&bmm_mutex); - return io.output; + return size; } int bmm_get_mem_attr(void *vaddr) { - int ret; - ioctl_arg_t io; + struct bmm_buffer *buf; + int attr = 0; - if(bmm_init() < 0) + if (bmm_init() < 0) return 0; - io.input = (unsigned long)vaddr; - io.output = 0; - io.arg = 0; - ret = ioctl(bmm_fd, BMM_GET_MEM_ATTR, &io); - if(ret < 0) - return 0; + pthread_mutex_lock(&bmm_mutex); + buf = bmm_buf_find_virt(vaddr); + if (buf) + attr = buf->attr; + pthread_mutex_unlock(&bmm_mutex); - return (int)io.output; + return attr; } int bmm_set_mem_attr(void *vaddr, int attr) { + struct bmm_buffer *buf; int ret; ioctl_arg_t io; @@ -276,7 +424,15 @@ int bmm_set_mem_attr(void *vaddr, int attr) if(ret < 0) return 0; - return (int)io.output; + attr = io.output; + + pthread_mutex_lock(&bmm_mutex); + buf = bmm_buf_find_virt(vaddr); + if (buf) + buf->attr = attr; + pthread_mutex_unlock(&bmm_mutex); + + return attr; } unsigned long bmm_get_total_space() |