summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk@arm.linux.org.uk>2013-12-08 22:10:39 +0000
committerRussell King <rmk@arm.linux.org.uk>2013-12-08 22:15:21 +0000
commitc46faad66a8d44b67b9b270649c0b9812bf9eff7 (patch)
tree57eb54f705e1059ce32be27d910edc2b91e35ece
parent6fcf08e81615ac4a571220b9ebfbbb91eeeae8d0 (diff)
Update vmeta to BMMv2HEADv2.0master
Update vmeta to use the dma_buf handling now provided by libbmm v2. This permits more flexible buffer management, as the buffers can now be passed via a standardized mechanism to other subsystems (such as DRM), and image data to be encoded can be accepted directly from other subsystems without needing to be copied. Signed-off-by: Russell King <rmk@arm.linux.org.uk>
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac2
-rw-r--r--debian/changelog6
-rw-r--r--rb.c549
-rw-r--r--rb.h128
-rw-r--r--uio_vmeta.h9
-rw-r--r--vmeta_lib.c354
-rw-r--r--vmeta_lib.h3
8 files changed, 1019 insertions, 34 deletions
diff --git a/Makefile.am b/Makefile.am
index 371482e..a714788 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,6 +7,8 @@ libvmeta_la_LDFLAGS = -avoid-version -no-undefined -export-symbols-regex "vdec_o
libvmeta_la_LIBADD = @LIBBMM_LIBS@
libvmeta_la_SOURCES = \
+ rb.c \
+ rb.h \
vmeta_lib.c \
uio_vmeta.h
diff --git a/configure.ac b/configure.ac
index 5b8ab19..ffe5450 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,7 +18,7 @@ AC_USE_SYSTEM_EXTENSIONS
LT_PREREQ([2.2])
LT_INIT
-PKG_CHECK_MODULES(LIBBMM, libbmm >= 1.1.0)
+PKG_CHECK_MODULES(LIBBMM, libbmm >= 2.0.0)
AC_SUBST(LIBBMM_CFLAGS)
AC_SUBST(LIBBMM_LIBS)
diff --git a/debian/changelog b/debian/changelog
index 93f3ae5..e20dcb6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+libvmeta (2.0) precise; urgency=low
+
+ * Convert to use new BMM dma_buf APIs
+
+ -- Russell King <rmk@arm.linux.org.uk> Sat, 7 Dec 2013 16:10:02 +0000
+
libvmeta (1.0ubuntu2.rmk4) precise; urgency=low
* Convert to use bmm_malloc_aligned_phys() API
diff --git a/rb.c b/rb.c
new file mode 100644
index 0000000..34a270e
--- /dev/null
+++ b/rb.c
@@ -0,0 +1,549 @@
+/*
+Generic C code for red-black trees.
+Copyright (C) 2000 James S. Plank
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* Revision 1.2. Jim Plank */
+
+/* Original code by Jim Plank (plank@cs.utk.edu) */
+/* modified for THINK C 6.0 for Macintosh by Chris Bartley */
+
+/* Modified by Russell King to support embedded keys only */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "rb.h"
+
+static void mk_new_int(Rb_node l, Rb_node r, Rb_node p, int il);
+static Rb_node lprev(Rb_node n);
+static Rb_node rprev(Rb_node n);
+static void recolor(Rb_node n);
+static void single_rotate(Rb_node y, int l);
+#ifdef DEBUG
+static void rb_print_tree(Rb_node t, int level);
+static void rb_iprint_tree(Rb_node t, int level);
+#endif
+
+
+#define isred(n) (n->s.red)
+#define isblack(n) (!isred(n))
+#define isleft(n) (n->s.left)
+#define isright(n) (!isleft(n))
+#define isint(n) (n->s.internal)
+#define isext(n) (!isint(n))
+#define ishead(n) (n->s.head)
+#define isroot(n) (n->s.root)
+#define setred(n) n->s.red = 1
+#define setblack(n) n->s.red = 0
+#define setleft(n) n->s.left = 1
+#define setright(n) n->s.left = 0
+#define sethead(n) n->s.head = 1
+#define setroot(n) n->s.root = 1
+#define setint(n) n->s.internal = 1
+#define setext(n) n->s.internal = 0
+#define setnormal(n) { n->s.root = 0; n ->s.head = 0; }
+#define sibling(n) ((isleft(n)) ? n->p.parent->c.child.right \
+ : n->p.parent->c.child.left)
+
+static void insert(Rb_node item, Rb_node list) /* Inserts to the end of a list */
+{
+ Rb_node last_node;
+
+ last_node = list->c.list.blink;
+
+ list->c.list.blink = item;
+ last_node->c.list.flink = item;
+ item->c.list.blink = last_node;
+ item->c.list.flink = list;
+}
+
+static void delete_item(Rb_node item) /* Deletes an arbitrary iterm */
+{
+ item->c.list.flink->c.list.blink = item->c.list.blink;
+ item->c.list.blink->c.list.flink = item->c.list.flink;
+}
+
+#define mk_new_ext(new, vvval) {\
+ new = (Rb_node) malloc(sizeof(struct rb_node));\
+ new->v.val = vvval;\
+ setext(new);\
+ setblack(new);\
+ setnormal(new);\
+}
+
+static void mk_new_int(Rb_node l, Rb_node r, Rb_node p, int il)
+{
+ Rb_node newnode;
+
+ newnode = (Rb_node) malloc(sizeof(struct rb_node));
+ setint(newnode);
+ setred(newnode);
+ setnormal(newnode);
+ newnode->c.child.left = l;
+ newnode->c.child.right = r;
+ newnode->p.parent = p;
+ newnode->k.lext = l;
+ newnode->v.rext = r;
+ l->p.parent = newnode;
+ r->p.parent = newnode;
+ setleft(l);
+ setright(r);
+ if (ishead(p)) {
+ p->p.root = newnode;
+ setroot(newnode);
+ } else if (il) {
+ setleft(newnode);
+ p->c.child.left = newnode;
+ } else {
+ setright(newnode);
+ p->c.child.right = newnode;
+ }
+ recolor(newnode);
+}
+
+
+Rb_node lprev(Rb_node n)
+{
+ if (ishead(n)) return n;
+ while (!isroot(n)) {
+ if (isright(n)) return n->p.parent;
+ n = n->p.parent;
+ }
+ return n->p.parent;
+}
+
+Rb_node rprev(Rb_node n)
+{
+ if (ishead(n)) return n;
+ while (!isroot(n)) {
+ if (isleft(n)) return n->p.parent;
+ n = n->p.parent;
+ }
+ return n->p.parent;
+}
+
+Rb_node make_rb(void)
+{
+ Rb_node head;
+
+ head = (Rb_node) malloc (sizeof(struct rb_node));
+ head->c.list.flink = head;
+ head->c.list.blink = head;
+ head->p.root = head;
+ sethead(head);
+ return head;
+}
+
+Rb_node rb_find_key_n(Rb_node n, const void *key, rb_key_cmp_fn cmp, int *fnd)
+{
+ int rc;
+ *fnd = 0;
+#ifdef DEBUG
+ if (!ishead(n)) {
+ fprintf(stderr, "%s called on non-head %p\n", __FUNCTION__, n);
+ exit(1);
+ }
+#else
+ assert(ishead(n));
+#endif
+ if (n->p.root == n) return n;
+ rc = cmp(key, n->c.list.blink->v.val);
+ if (rc == 0) {
+ *fnd = 1;
+ return n->c.list.blink;
+ }
+ if (rc > 0) return n;
+ else n = n->p.root;
+ while (1) {
+ if (isext(n)) return n;
+ rc = cmp(key, n->k.lext->v.val);
+ if (rc == 0) {
+ *fnd = 1;
+ return n->k.lext;
+ }
+ n = rc < 0 ? n->c.child.left : n->c.child.right;
+ }
+}
+
+Rb_node rb_find_key(Rb_node n, const void *key, rb_key_cmp_fn cmp)
+{
+ int fnd;
+ return rb_find_key_n(n, key, cmp, &fnd);
+}
+
+Rb_node rb_insert_b(Rb_node n, void *val)
+{
+ Rb_node newleft, newright, newnode, p;
+
+ if (ishead(n)) {
+ if (n->p.root == n) { /* Tree is empty */
+ mk_new_ext(newnode, val);
+ insert(newnode, n);
+ n->p.root = newnode;
+ newnode->p.parent = n;
+ setroot(newnode);
+ return newnode;
+ } else {
+ mk_new_ext(newright, val);
+ insert(newright, n);
+ newleft = newright->c.list.blink;
+ setnormal(newleft);
+ mk_new_int(newleft, newright, newleft->p.parent, isleft(newleft));
+ p = rprev(newright);
+ if (!ishead(p)) p->k.lext = newright;
+ return newright;
+ }
+ } else {
+ mk_new_ext(newleft, val);
+ insert(newleft, n);
+ setnormal(n);
+ mk_new_int(newleft, n, n->p.parent, isleft(n));
+ p = lprev(newleft);
+ if (!ishead(p)) p->v.rext = newleft;
+ return newleft;
+ }
+}
+
+static void recolor(Rb_node n)
+{
+ Rb_node p, gp, s;
+ int done = 0;
+
+ while(!done) {
+ if (isroot(n)) {
+ setblack(n);
+ return;
+ }
+
+ p = n->p.parent;
+
+ if (isblack(p)) return;
+
+ if (isroot(p)) {
+ setblack(p);
+ return;
+ }
+
+ gp = p->p.parent;
+ s = sibling(p);
+ if (isred(s)) {
+ setblack(p);
+ setred(gp);
+ setblack(s);
+ n = gp;
+ } else {
+ done = 1;
+ }
+ }
+ /* p's sibling is black, p is red, gp is black */
+
+ if ((isleft(n) == 0) == (isleft(p) == 0)) {
+ single_rotate(gp, isleft(n));
+ setblack(p);
+ setred(gp);
+ } else {
+ single_rotate(p, isleft(n));
+ single_rotate(gp, isleft(n));
+ setblack(n);
+ setred(gp);
+ }
+}
+
+static void single_rotate(Rb_node y, int l)
+{
+ int rl, ir;
+ Rb_node x, yp;
+
+ ir = isroot(y);
+ yp = y->p.parent;
+ if (!ir) {
+ rl = isleft(y);
+ }
+
+ if (l) {
+ x = y->c.child.left;
+ y->c.child.left = x->c.child.right;
+ setleft(y->c.child.left);
+ y->c.child.left->p.parent = y;
+ x->c.child.right = y;
+ setright(y);
+ } else {
+ x = y->c.child.right;
+ y->c.child.right = x->c.child.left;
+ setright(y->c.child.right);
+ y->c.child.right->p.parent = y;
+ x->c.child.left = y;
+ setleft(y);
+ }
+
+ x->p.parent = yp;
+ y->p.parent = x;
+ if (ir) {
+ yp->p.root = x;
+ setnormal(y);
+ setroot(x);
+ } else {
+ if (rl) {
+ yp->c.child.left = x;
+ setleft(x);
+ } else {
+ yp->c.child.right = x;
+ setright(x);
+ }
+ }
+}
+
+void rb_delete_node(Rb_node n)
+{
+ Rb_node s, p, gp;
+ char ir;
+
+#ifdef DEBUG
+ if (isint(n)) {
+ fprintf(stderr, "Cannot delete an internal node: %p\n", n);
+ exit(1);
+ }
+ if (ishead(n)) {
+ fprintf(stderr, "Cannot delete the head of an rb_tree: %p\n", n);
+ exit(1);
+ }
+#else
+ assert(!isint(n));
+ assert(!ishead(n));
+#endif
+ delete_item(n); /* Delete it from the list */
+ p = n->p.parent; /* The only node */
+ if (isroot(n)) {
+ p->p.root = p;
+ free(n);
+ return;
+ }
+ s = sibling(n); /* The only node after deletion */
+ if (isroot(p)) {
+ s->p.parent = p->p.parent;
+ s->p.parent->p.root = s;
+ setroot(s);
+ free(p);
+ free(n);
+ return;
+ }
+ gp = p->p.parent; /* Set parent to sibling */
+ s->p.parent = gp;
+ if (isleft(p)) {
+ gp->c.child.left = s;
+ setleft(s);
+ } else {
+ gp->c.child.right = s;
+ setright(s);
+ }
+ ir = isred(p);
+ free(p);
+ free(n);
+
+ if (isext(s)) { /* Update proper rext and lext values */
+ p = lprev(s);
+ if (!ishead(p)) p->v.rext = s;
+ p = rprev(s);
+ if (!ishead(p)) p->k.lext = s;
+ } else if (isblack(s)) {
+#ifdef DEBUG
+ fprintf(stderr, "DELETION PROB -- sib is black, internal\n");
+ exit(1);
+#else
+ assert(1);
+#endif
+ } else {
+ p = lprev(s);
+ if (!ishead(p)) p->v.rext = s->c.child.left;
+ p = rprev(s);
+ if (!ishead(p)) p->k.lext = s->c.child.right;
+ setblack(s);
+ return;
+ }
+
+ if (ir) return;
+
+ /* Recolor */
+
+ n = s;
+ p = n->p.parent;
+ s = sibling(n);
+ while(isblack(p) && isblack(s) && isint(s) &&
+ isblack(s->c.child.left) && isblack(s->c.child.right)) {
+ setred(s);
+ n = p;
+ if (isroot(n)) return;
+ p = n->p.parent;
+ s = sibling(n);
+ }
+
+ if (isblack(p) && isred(s)) { /* Rotation 2.3b */
+ single_rotate(p, isright(n));
+ setred(p);
+ setblack(s);
+ s = sibling(n);
+ }
+
+ { Rb_node x, z; char il;
+#ifdef DEBUG
+ if (isext(s)) {
+ fprintf(stderr, "DELETION ERROR: sibling not internal\n");
+ exit(1);
+ }
+#else
+ assert(!isext(s));
+#endif
+
+ il = isleft(n);
+ x = il ? s->c.child.left : s->c.child.right;
+ z = sibling(x);
+
+ if (isred(z)) { /* Rotation 2.3f */
+ single_rotate(p, !il);
+ setblack(z);
+ if (isred(p)) setred(s); else setblack(s);
+ setblack(p);
+ } else if (isblack(x)) { /* Recoloring only (2.3c) */
+#ifdef DEBUG
+ if (isred(s) || isblack(p)) {
+ fprintf(stderr, "DELETION ERROR: 2.3c not quite right\n");
+ exit(1);
+ }
+#else
+ assert(!isred(s) && !isblack(p));
+#endif
+ setblack(p);
+ setred(s);
+ return;
+ } else if (isred(p)) { /* 2.3d */
+ single_rotate(s, il);
+ single_rotate(p, !il);
+ setblack(x);
+ setred(s);
+ return;
+ } else { /* 2.3e */
+ single_rotate(s, il);
+ single_rotate(p, !il);
+ setblack(x);
+ return;
+ }
+ }
+}
+
+
+#ifdef DEBUG
+void rb_print_tree(Rb_node t, int level)
+{
+ int i;
+ if (ishead(t) && t->p.parent == t) {
+ printf("tree %p is empty\n", t);
+ } else if (ishead(t)) {
+ printf("Head: %p. Root = %p\n", t, t->p.root);
+ rb_print_tree(t->p.root, 0);
+ } else {
+ if (isext(t)) {
+ for (i = 0; i < level; i++) putchar(' ');
+ printf("Ext node %p: %c,%c: p=0x%x, k=%s\n",
+ t, isred(t)?'R':'B', isleft(t)?'l':'r', t->p.parent, t->k.key);
+ } else {
+ rb_print_tree(t->c.child.left, level+2);
+ rb_print_tree(t->c.child.right, level+2);
+ for (i = 0; i < level; i++) putchar(' ');
+ printf("Int node %p: %c,%c: l=0x%x, r=0x%x, p=0x%x, lr=(%s,%s)\n",
+ t, isred(t)?'R':'B', isleft(t)?'l':'r', t->c.child.left,
+ t->c.child.right,
+ t->p.parent, t->k.lext->k.key, t->v.rext->k.key);
+ }
+ }
+}
+#endif
+
+int rb_nblack(Rb_node n)
+{
+ int nb;
+#ifdef DEBUG
+ if (ishead(n) || isint(n)) {
+ fprintf(stderr, "ERROR: rb_nblack called on a non-external node %p\n",
+ n);
+ exit(1);
+ }
+#else
+ assert(!ishead(n));
+ assert(!isint(n));
+#endif
+ nb = 0;
+ while(!ishead(n)) {
+ if (isblack(n)) nb++;
+ n = n->p.parent;
+ }
+ return nb;
+}
+
+int rb_plength(Rb_node n)
+{
+ int pl;
+#ifdef DEBUG
+ if (ishead(n) || isint(n)) {
+ fprintf(stderr, "ERROR: rb_plength called on a non-external node %p\n",
+ n);
+ exit(1);
+ }
+#else
+ assert(!ishead(n));
+ assert(!isint(n));
+#endif
+ pl = 0;
+ while(!ishead(n)) {
+ pl++;
+ n = n->p.parent;
+ }
+ return pl;
+}
+
+void rb_free_tree(Rb_node n)
+{
+#ifdef DEBUG
+ if (!ishead(n)) {
+ fprintf(stderr, "ERROR: Rb_free_tree called on a non-head node\n");
+ exit(1);
+ }
+#else
+ assert(ishead(n));
+#endif
+
+ while(rb_first(n) != rb_nil(n)) {
+ rb_delete_node(rb_first(n));
+ }
+ free(n);
+}
+
+void *rb_val(Rb_node n)
+{
+ return n->v.val;
+}
+
+Rb_node rb_insert_a(Rb_node nd, void *val)
+{
+ return rb_insert_b(nd->c.list.flink, val);
+}
+
+Rb_node rb_insert(Rb_node tree, const void *key, rb_key_cmp_fn cmp, void *val)
+{
+ return rb_insert_b(rb_find_key(tree, key, cmp), val);
+}
diff --git a/rb.h b/rb.h
new file mode 100644
index 0000000..80f433c
--- /dev/null
+++ b/rb.h
@@ -0,0 +1,128 @@
+/*
+Generic C code for red-black trees.
+Copyright (C) 2000 James S. Plank
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* Revision 1.2. Jim Plank */
+
+/* Original code by Jim Plank (plank@cs.utk.edu) */
+/* modified for THINK C 6.0 for Macintosh by Chris Bartley */
+
+/* Modified by Russell King to support embedded keys only */
+
+typedef struct {
+ unsigned red : 1 ;
+ unsigned internal : 1 ;
+ unsigned left : 1 ;
+ unsigned root : 1 ;
+ unsigned head : 1 ;
+} status;
+
+/* Main rb_node. You only ever use the fields
+
+ c.list.flink
+ c.list.blink
+
+ k.key or k.ikey
+ v.val
+*/
+
+typedef int (*rb_key_cmp_fn)(const void *, const void *);
+
+typedef struct rb_node {
+ union {
+ struct {
+ struct rb_node *flink;
+ struct rb_node *blink;
+ } list;
+ struct {
+ struct rb_node *left;
+ struct rb_node *right;
+ } child;
+ } c;
+ union {
+ struct rb_node *parent;
+ struct rb_node *root;
+ } p;
+ status s;
+ union {
+ struct rb_node *lext;
+ } k;
+ union {
+ void *val;
+ struct rb_node *rext;
+ } v;
+} *Rb_node;
+
+
+extern Rb_node make_rb(void); /* Creates a new rb-tree */
+
+
+
+/* Creates a node with key key and val val and inserts it into the tree.
+ rb_insert uses strcmp() as comparison funcion. rb_inserti uses <>=,
+ rb_insertg uses func() */
+
+extern Rb_node rb_insert(Rb_node tree, const void *key,
+ rb_key_cmp_fn fn, void *data);
+
+
+/* returns an external node in t whose value is equal
+ k or whose value is the smallest value greater than k. */
+
+extern Rb_node rb_find_key(Rb_node root, const void *key,
+ rb_key_cmp_fn fn);
+
+
+/* Works just like the find_key versions only it returns whether or not
+ it found the key in the integer variable found */
+
+extern Rb_node rb_find_key_n(Rb_node root, const void *key,
+ rb_key_cmp_fn fn, int *found);
+
+
+/* Creates a node with key key and val val and inserts it into the
+ tree before/after node nd. Does not check to ensure that you are
+ keeping the correct order */
+
+extern Rb_node rb_insert_b(Rb_node nd, void *val);
+extern Rb_node rb_insert_a(Rb_node nd, void *val);
+
+
+extern void rb_delete_node(Rb_node node); /* Deletes and frees a node (but
+ not the key or val) */
+extern void rb_free_tree(Rb_node root); /* Deletes and frees an entire tree */
+
+extern void *rb_val(Rb_node node); /* Returns node->v.val -- this is to shut
+ lint up */
+
+extern int rb_nblack(Rb_node n); /* returns # of black nodes in path from
+ n to the root */
+int rb_plength(Rb_node n); /* returns the # of nodes in path from
+ n to the root */
+
+#define rb_first(n) (n->c.list.flink)
+#define rb_last(n) (n->c.list.blink)
+#define rb_next(n) (n->c.list.flink)
+#define rb_prev(n) (n->c.list.blink)
+#define rb_empty(t) (t->c.list.flink == t)
+#ifndef rb_nil
+#define rb_nil(t) (t)
+#endif
+
+#define rb_traverse(ptr, lst) \
+ for(ptr = rb_first(lst); ptr != rb_nil(lst); ptr = rb_next(ptr))
diff --git a/uio_vmeta.h b/uio_vmeta.h
index 08ebaa1..d9e55a5 100644
--- a/uio_vmeta.h
+++ b/uio_vmeta.h
@@ -63,6 +63,13 @@ struct vmeta_mmap {
uint32_t size;
};
+struct vmeta_dmabuf_import {
+ uint64_t phys;
+ uint32_t size;
+ int32_t fd;
+ int32_t id;
+};
+
#define VMETA_STATUS_BIT_USED 0
#define VMETA_STATUS_BIT_REGISTED 1
#define VMETA_STATUS_USED BIT(0)
@@ -93,5 +100,7 @@ struct vmeta_mmap {
#define VMETA_CMD_GET_USER_NUM _IOR(IOP_MAGIC, 20, unsigned)
#define VMETA_CMD_GET_INFO _IOR(IOP_MAGIC, 21, struct vmeta_info)
#define VMETA_CMD_MAP_SW_CONTEXT _IOWR(IOP_MAGIC, 22, struct vmeta_mmap)
+#define VMETA_CMD_DMABUF_IMPORT _IOWR(IOP_MAGIC, 23, struct vmeta_dmabuf_import)
+#define VMETA_CMD_DMABUF_RELEASE _IO(IOP_MAGIC, 24)
#endif /* __UIO_VMETA_H */
diff --git a/vmeta_lib.c b/vmeta_lib.c
index 6959a1f..735e8ce 100644
--- a/vmeta_lib.c
+++ b/vmeta_lib.c
@@ -23,6 +23,7 @@
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
+#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
@@ -36,6 +37,7 @@
#include "vmeta_lib.h"
#include "bmm_lib.h"
+#include "rb.h"
#include "uio_vmeta.h"
#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
@@ -76,9 +78,68 @@ typedef struct vdec_os_driver_cb_s {
// global variable
static vdec_os_driver_cb_t *vdec_iface = NULL;
+static int vmeta_fd = -1;
static UNSG32 globalDbgLevel = VDEC_DEBUG_NONE;
static UNSG32 syncTimeout = 500;
static pthread_mutex_t pmt = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t rb_mutex = PTHREAD_MUTEX_INITIALIZER;
+static Rb_node phys_rb, virt_rb;
+
+typedef unsigned long phys_t;
+
+struct v2p {
+ void *vaddr;
+ size_t size;
+ phys_t paddr;
+ int32_t fd;
+ int32_t id;
+};
+
+static int cmp_phys(const void *key, const void *val)
+{
+ const struct v2p *v2p = val;
+ phys_t k = *(const phys_t *)key;
+
+ return (k < v2p->paddr) ? -1 : (k - v2p->paddr < v2p->size) ? 0 : 1;
+}
+
+static struct v2p *find_phys(phys_t paddr)
+{
+ int found = 0;
+ Rb_node node = rb_find_key_n(phys_rb, &paddr, cmp_phys, &found);
+
+ return found ? rb_val(node) : NULL;
+}
+
+static struct v2p *find_remove_phys(phys_t paddr)
+{
+ struct v2p *v2p = NULL;
+ int found = 0;
+ Rb_node node = rb_find_key_n(phys_rb, &paddr, cmp_phys, &found);
+
+ if (found) {
+ v2p = rb_val(node);
+ rb_delete_node(node);
+ }
+
+ return v2p;
+}
+
+static int cmp_virt(const void *key, const void *val)
+{
+ const struct v2p *v2p = val;
+ void *k = (void *)key;
+
+ return (k < v2p->vaddr) ? -1 : (k - v2p->vaddr < v2p->size) ? 0 : 1;
+}
+
+static struct v2p *find_virt(void *vaddr)
+{
+ int found = 0;
+ Rb_node node = rb_find_key_n(virt_rb, vaddr, cmp_virt, &found);
+
+ return found ? rb_val(node) : NULL;
+}
UNSG8 vdec_os_api_rd8(UNSG32 addr)
{
@@ -116,15 +177,191 @@ UNSG32 vdec_os_api_get_regbase_addr(void)
return (UNSG32) vdec->regs;
}
+static void __attribute__((destructor)) vdec_os_api_exit(void)
+{
+ if (phys_rb) {
+ Rb_node node;
+
+ /*
+ * Release all resources on the virtual rb tree, but leave
+ * the v2p structs in place, as these will also be on the
+ * phys rb tree.
+ */
+ rb_traverse(node, virt_rb) {
+ struct v2p *v2p = rb_val(node);
+
+ ioctl(vmeta_fd, VMETA_CMD_DMABUF_RELEASE, v2p->id);
+ bmm_dmabuf_unmap(v2p->vaddr);
+ bmm_dmabuf_free(v2p->fd);
+ v2p->id = -1;
+ }
+ rb_free_tree(virt_rb);
+
+ rb_traverse(node, phys_rb) {
+ struct v2p *v2p = rb_val(node);
+
+ if (v2p->id != -1) {
+ ioctl(vmeta_fd, VMETA_CMD_DMABUF_RELEASE, v2p->id);
+ v2p->id = -1;
+ }
+ free(v2p);
+ }
+ rb_free_tree(phys_rb);
+ }
+
+ if (vmeta_fd >= 0)
+ close(vmeta_fd);
+ bmm_exit();
+}
+
+static int vdec_os_api_init(void)
+{
+ int fd;
+
+ if (!virt_rb) {
+ virt_rb = make_rb();
+ phys_rb = make_rb();
+ if (!virt_rb || !phys_rb)
+ goto rb;
+
+ fd = open("/dev/vmeta", O_RDWR | O_CLOEXEC);
+ if (fd == -1)
+ goto rb;
+
+ if (bmm_init() < 0)
+ goto vmeta;
+
+ vmeta_fd = fd;
+ }
+ return 0;
+
+vmeta:
+ close(fd);
+rb:
+ if (virt_rb)
+ rb_free_tree(virt_rb);
+ if (phys_rb)
+ rb_free_tree(phys_rb);
+ phys_rb = virt_rb = NULL;
+
+ return 1;
+}
+
+static int vdec_os_api_add_mapping(void *ptr, size_t size, phys_t paddr,
+ int fd, int id)
+{
+ struct v2p *v2p;
+ Rb_node node;
+ int found = 0;
+
+ v2p = malloc(sizeof(*v2p));
+ if (!v2p)
+ return -1;
+
+ v2p->vaddr = ptr;
+ v2p->size = size;
+ v2p->paddr = paddr;
+ v2p->fd = fd;
+ v2p->id = id;
+
+ pthread_mutex_lock(&rb_mutex);
+ node = rb_find_key_n(phys_rb, &paddr, cmp_phys, &found);
+ assert(found == 0);
+ rb_insert_b(node, v2p);
+
+ if (ptr) {
+ node = rb_find_key_n(virt_rb, ptr, cmp_virt, &found);
+ assert(found == 0);
+ rb_insert_b(node, v2p);
+ }
+ pthread_mutex_unlock(&rb_mutex);
+
+ return 0;
+}
+
+/**
+ * vdec_os_api_dmabuf_import - import a DMA buffer into vmeta
+ * @fd: dmabuf file descriptor
+ * @phys: pointer to unsigned long for physical address of buffer
+ * @size: pointer ti size_t for size of buffer
+ *
+ * Returns: ID of buffer, physical address in *phys and size in *size,
+ * or -1 on error.
+ */
+int vdec_os_api_dmabuf_import(int fd, unsigned long *phys, size_t *size)
+{
+ struct vmeta_dmabuf_import arg;
+ int ret;
+
+ if (vdec_os_api_init())
+ return -1;
+
+ arg.fd = fd;
+ ret = ioctl(vmeta_fd, VMETA_CMD_DMABUF_IMPORT, &arg);
+ if (ret == -1)
+ return ret;
+
+ if ((phys_t)arg.phys != arg.phys) {
+ ret = -1;
+ goto release;
+ }
+
+ ret = vdec_os_api_add_mapping(NULL, arg.size, arg.phys, arg.fd, arg.id);
+ if (ret)
+ goto release;
+
+ return arg.id;
+
+ release:
+ ioctl(vmeta_fd, VMETA_CMD_DMABUF_RELEASE, arg.id);
+ return ret;
+}
+
+void vdec_os_api_dmabuf_release(unsigned long phys)
+{
+ struct v2p *v2p;
+
+ pthread_mutex_lock(&rb_mutex);
+ v2p = find_remove_phys(phys);
+ pthread_mutex_unlock(&rb_mutex);
+
+ ioctl(vmeta_fd, VMETA_CMD_DMABUF_RELEASE, v2p->id);
+ free(v2p);
+}
+
//Mem map to bmm_lib
-UNSG32 vdec_os_api_get_pa(UNSG32 vaddr)
+UNSG32 vdec_os_api_get_pa(UNSG32 virt)
{
- return bmm_get_paddr((void *)vaddr);
+ unsigned long paddr;
+ struct v2p *v2p;
+ void *vaddr = (void *)virt;
+
+ pthread_mutex_lock(&rb_mutex);
+ v2p = find_virt(vaddr);
+ pthread_mutex_unlock(&rb_mutex);
+
+ assert(v2p);
+ paddr = v2p->paddr + vaddr - v2p->vaddr;
+
+ return paddr;
}
UNSG32 vdec_os_api_get_va(UNSG32 paddr)
-{
- return ((UNSG32)bmm_get_vaddr(paddr));
+{
+ struct v2p *v2p;
+ void *vaddr;
+
+ pthread_mutex_lock(&rb_mutex);
+ v2p = find_phys(paddr);
+ pthread_mutex_unlock(&rb_mutex);
+
+ assert(v2p);
+ if (v2p->vaddr)
+ vaddr = v2p->vaddr + paddr - v2p->paddr;
+ else
+ vaddr = NULL;
+
+ return (UNSG32)vaddr;
}
void vdec_os_api_vfree(void *ptr)
@@ -162,33 +399,83 @@ void *vdec_os_api_vmalloc(UNSG32 size, UNSG32 align)
void vdec_os_api_dma_free(void *ptr)
{
- bmm_free(ptr);
+ struct v2p *v2p;
+ Rb_node node;
+ int found = 0;
+
+ dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_free: 0x%p\n", ptr);
+
+ pthread_mutex_lock(&rb_mutex);
+ node = rb_find_key_n(virt_rb, ptr, cmp_virt, &found);
+ if (!found) {
+ pthread_mutex_unlock(&rb_mutex);
+ dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_free: not found\n");
+ assert(0);
+ return;
+ }
+ rb_delete_node(node);
+
+ v2p = rb_val(node);
+ assert(find_remove_phys(v2p->paddr) == v2p);
+ pthread_mutex_unlock(&rb_mutex);
+
+ bmm_dmabuf_unmap(v2p->vaddr);
+ if (v2p->id != -1)
+ ioctl(vmeta_fd, VMETA_CMD_DMABUF_RELEASE, v2p->id);
+ bmm_dmabuf_free(v2p->fd);
+ free(v2p);
}
static void *vmeta_bmm_malloc_aligned(UNSG32 size, UNSG32 align, UNSG32 *phys, int attr)
{
+ struct vmeta_dmabuf_import arg;
unsigned long paddr;
void *ptr;
+ int fd;
+
+ dbg_printf(VDEC_DEBUG_MEM, "%s: size 0x%x attr %u align %u\n",
+ __FUNCTION__, size, attr, align);
if (size == 0)
return NULL;
- dbg_printf(VDEC_DEBUG_MEM, "%s: size 0x%x attr %u align %u\n",
- __FUNCTION__, size, attr, align);
+ if (vdec_os_api_init())
+ return NULL;
- ptr = bmm_malloc_aligned_phys(size, attr, align, &paddr);
- if (!ptr) {
- dbg_printf(VDEC_DEBUG_MEM, "%s: not enough memory\n",
- __FUNCTION__);
+ fd = bmm_dmabuf_alloc(size, attr, align);
+ if (fd < 0) {
+ dbg_printf(VDEC_DEBUG_MEM, "%s: %s\n",
+ __FUNCTION__, strerror(errno));
return NULL;
- }
+ }
- *phys = paddr;
+ ptr = bmm_dmabuf_map(fd, 0, size);
+ if (ptr == NULL)
+ goto free;
+
+ arg.fd = fd;
+ if (ioctl(vmeta_fd, VMETA_CMD_DMABUF_IMPORT, &arg) == -1)
+ goto unmap;
+
+ paddr = arg.phys;
+
+ dbg_printf(VDEC_DEBUG_MEM, "%s: virt=%p phys=0x%08lx fd %d id %d\n",
+ __FUNCTION__, ptr, paddr, fd, arg.id);
+
+ if (vdec_os_api_add_mapping(ptr, size, paddr, fd, arg.id))
+ goto release;
- dbg_printf(VDEC_DEBUG_MEM, "%s: virt=%p phys=0x%08lx\n",
- __FUNCTION__, ptr, paddr);
+ *phys = paddr;
return ptr;
+
+release:
+ ioctl(vmeta_fd, VMETA_CMD_DMABUF_RELEASE, arg.id);
+unmap:
+ bmm_dmabuf_unmap(ptr);
+free:
+ bmm_dmabuf_free(fd);
+ return NULL;
}
void *vdec_os_api_dma_alloc(UNSG32 size, UNSG32 align, UNSG32 *phys)
@@ -208,11 +495,11 @@ void *vdec_os_api_dma_alloc_writecombine(UNSG32 size, UNSG32 align, UNSG32 *phys
UNSG32 vdec_os_api_flush_cache(UNSG32 vaddr, UNSG32 size, enum dma_data_direction direction)
{
- int bmm_direction;
+ struct v2p *v2p;
+ unsigned bmm_direction, offset;
switch (direction) {
case DMA_NONE:
- default:
bmm_direction = BMM_DMA_NONE;
break;
case DMA_FROM_DEVICE:
@@ -224,16 +511,22 @@ UNSG32 vdec_os_api_flush_cache(UNSG32 vaddr, UNSG32 size, enum dma_data_directio
case DMA_BIDIRECTIONAL:
bmm_direction = BMM_DMA_BIDIRECTIONAL;
break;
+ default:
+ assert(0);
}
if (bmm_direction == BMM_DMA_NONE)
return 0;
- if (0 < size) {
- bmm_flush_cache_range((void *)vaddr, size, bmm_direction);
- } else {
- bmm_flush_cache((void *)vaddr, bmm_direction);
- }
+ pthread_mutex_lock(&rb_mutex);
+ v2p = find_virt((void *)vaddr);
+ pthread_mutex_unlock(&rb_mutex);
+
+ assert(v2p);
+ offset = (void *)vaddr - v2p->vaddr;
+
+ bmm_dmabuf_flush(v2p->fd, v2p->vaddr, offset, size - offset, direction);
+
return 0;
}
@@ -346,6 +639,11 @@ SIGN32 vdec_os_driver_init(void)
return VDEC_OS_DRIVER_OK;
}
+ if (vdec_os_api_init()) {
+ pthread_mutex_unlock(&pmt);
+ return -VDEC_OS_DRIVER_INIT_FAIL;
+ }
+
#if (VMETA_LOG_ON && 0)
fp_log = fopen(VMETA_LOG_FILE,"w");
if(fp_log == NULL) {
@@ -366,12 +664,7 @@ SIGN32 vdec_os_driver_init(void)
// initialize reference count
vdec->refcount++;
- // Try to open the (new) vmeta device
- vdec->fd = open("/dev/vmeta", O_RDWR | O_CLOEXEC);
- if (vdec->fd == -1) {
- ret = -VDEC_OS_DRIVER_OPEN_FAIL;
- goto err_open_fail;
- }
+ vdec->fd = vmeta_fd;
ret = ioctl(vdec->fd, VMETA_CMD_GET_INFO, &info);
if (ret == -1) {
@@ -412,7 +705,6 @@ SIGN32 vdec_os_driver_init(void)
return VDEC_OS_DRIVER_OK;
err_mmap_fail:
- close(vdec->fd);
err_open_fail:
free(vdec);
@@ -461,10 +753,6 @@ SIGN32 vdec_os_driver_clean(void)
munmap(vdec->vdec_obj_va, vdec->vdec_obj_size);
}
- // close fd
- close(vdec->fd);
- dbg_printf(VDEC_DEBUG_ALL, "kernel close\n");
-
// free vdec_iface
free(vdec);
dbg_printf(VDEC_DEBUG_ALL, "free vdec_iface\n");
diff --git a/vmeta_lib.h b/vmeta_lib.h
index fe7ac40..8609dc5 100644
--- a/vmeta_lib.h
+++ b/vmeta_lib.h
@@ -69,6 +69,9 @@ UNSG32 vdec_os_api_flush_cache(UNSG32 vaddr, UNSG32 size, enum dma_data_directio
SIGN32 vdec_os_api_get_hw_obj_addr(UNSG32* vaddr, UNSG32 size);
SIGN32 vdec_os_api_get_hw_context_addr(UNSG32* paddr, UNSG32* vaddr, UNSG32 size, SIGN32 flag);
+int vdec_os_api_dmabuf_import(int fd, unsigned long *phys, size_t *size);
+void vdec_os_api_dmabuf_release(unsigned long phys);
+
//---------------------------------------------------------------------------
// Mem/IO R/W API
//---------------------------------------------------------------------------