[TLBdrvAPI] sr TLB API driver implementation
authorParichay Kapoor <pk.kapoor@samsung.com>
Mon, 14 Oct 2019 07:13:29 +0000 (16:13 +0900)
committer채동주/On-Device Lab(SR)/Staff Engineer/삼성전자 <dongju.chae@samsung.com>
Mon, 28 Oct 2019 08:33:53 +0000 (17:33 +0900)
Added sr TLB driver implementation
Added unittests for TLB api driver
Bug fix for hash table hashing generating constant

Signed-off-by: Parichay Kapoor <pk.kapoor@samsung.com>
src/core/ne-utils.c
src/core/ne-utils.h
src/core/tlb/TLBdrvAPI.c
src/core/tlb/meson.build
src/test/unittests/meson.build
src/test/unittests/ne_core_tlb_test.cpp [new file with mode: 0644]

index 6e90834..28034b6 100644 (file)
@@ -279,6 +279,7 @@ static const char *modulestr[] = {
   [_N71] = "N71/CMA ",
   [_N72] = "N72/IOMM",
   [_N9] =  "N9/GEM  ",
+  [_N95] = "N95/TLB ",
 };
 
 static FILE *fp = NULL;
index f6c1100..fe4fe12 100644 (file)
@@ -124,7 +124,7 @@ void list_add_next (list *list, list_node *node, list_node *next);
 void list_del (list *list, list_node *node);
 
 /* hash table */
-#define GOLDEN_RATIO_32 0x61C88647          /* 32-bits hash */
+#define GOLDEN_RATIO_32 0x61C88647u          /* 32-bits hash */
 #define HASH_BITS(size) LOG2(size)
 #define HASH_INDEX(ht, key) ((key * GOLDEN_RATIO_32) >> (32 - HASH_BITS ((ht)->size)))
 
@@ -223,7 +223,8 @@ typedef enum {
   _N7,
   _N71,
   _N72,
-  _N9
+  _N9,
+  _N95
 } module;
 
 /**
index 3d01607..2c6da62 100644 (file)
  *
  */
 
-#include "TLBdrvAPI.h"
+#include <stdio.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
 
 /* npu-engine */
 #include <ne-conf.h>
 #include <ne-utils.h>
+#include <misc/srtlb.h>
+
+#include "TLBdrvAPI.h"
+
+#define HASH_TABLE_SIZE 1024
+#define TLB_BASE_PATH  "/dev"
+#define DUMMY_FD  100000000
+#define TAG  _N95
+
+/**
+ * @brief fd id mapping element
+ */
+typedef struct _map_elem {
+  int fd;
+  int id;
+  hash_node hash;
+} map_elem;
 
+/**
+ * @brief private data struct for tlb API driver
+ */
+typedef struct _tlb_dev_priv {
+  int fd;
+  int ref_count;
+  hash_table dmabuf_map;
+} tlb_dev_priv;
+
+/**
+ * @brief private data struct for tlb API driver
+ */
+static tlb_dev_priv tlb_priv;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/**
+ * @brief verify tlb entry detail with fd
+ * @param[in] priv tlb priv object
+ * @param[in] fd fd of the object opened
+ * @note lock is acquired if successful
+ */
+#define VERIFY_VALID_TLB_LOCKED(priv, fd) \
+  pthread_mutex_lock (&mutex); \
+  if (priv.fd != fd) {  \
+    pthread_mutex_unlock (&mutex); \
+    logerr (TAG, "Invalid fd for the device\n"); \
+    return -EINVAL;  \
+  } \
+  if (priv.ref_count == 0) { \
+    pthread_mutex_unlock (&mutex); \
+    logerr (TAG, "Device for fd is alread closed\n"); \
+    return -EPERM;  \
+  }
+
+
+/**
+ * @brief find map element in hash table
+ * @param[in] dmabuf_fd key for the element to find
+ * @return element on success, NULL on error
+ */
+static map_elem *
+find_map_elem (int dmabuf_fd)
+{
+  map_elem *elem = NULL;
+
+  hash_for_each_possible (elem, tlb_priv.dmabuf_map, hash, dmabuf_fd)
+    if (elem->fd == dmabuf_fd)
+      return elem;
+
+  return elem;
+}
 
 /* API wrapper functions */
 
  * @brief open tlb driver
  * @param[in] name the name of tlb driver
  * @return file descriptor if not error. otherwise negative
+ * @details is only opened once to share hash table of fd to id
  */
 int
 tlb_open (const char *name)
 {
-  /** TODO: fill this function */
-  return 0;
+  char dev_name[64];
+  int fd;
+
+  pthread_mutex_lock (&mutex);
+  snprintf (dev_name, sizeof(dev_name), "%s/%s", TLB_BASE_PATH, name);
+
+  if (conf->test_mode == 0) {
+    if (tlb_priv.ref_count == 0) {
+      fd = open (dev_name, O_RDWR);
+      if (fd >= 0) {
+        tlb_priv.fd = fd;
+      }
+    } else {
+      fd = tlb_priv.fd;
+    }
+  } else {
+    fd = DUMMY_FD;
+    tlb_priv.fd = fd;
+  }
+
+  if (fd >= 0) {
+    if (tlb_priv.ref_count == 0)
+      hash_table_init (&tlb_priv.dmabuf_map, HASH_TABLE_SIZE);
+    tlb_priv.ref_count += 1;
+  }
+
+  pthread_mutex_unlock (&mutex);
+
+  return fd;
 }
 
 /**
@@ -51,7 +155,45 @@ tlb_open (const char *name)
 void
 tlb_close (int fd)
 {
-  /** TODO: fill this function */
+  int err = 0;
+  map_elem *elem, *tmp;
+  int bkt;
+
+  pthread_mutex_lock (&mutex);
+  if (tlb_priv.fd != fd) {
+    logerr (TAG, "Invalid fd for the device\n");
+    goto exit;
+  }
+
+  if (tlb_priv.ref_count == 0) {
+    logerr (TAG, "Device for fd is alread closed\n");
+    goto exit;
+  }
+
+  tlb_priv.ref_count -= 1;
+  if (tlb_priv.ref_count == 0) {
+
+    /** remove all elements from hash table */
+    hash_for_each_safe (elem, tmp, tlb_priv.dmabuf_map, bkt, hash) {
+      if (conf->test_mode == 0) {
+        err = ioctl (tlb_priv.fd, SRTLB_IOCTL_UNMAP_DMABUF, &elem->id);
+        if (err < 0)
+          logerr (TAG, "ioctl() error in unmap %d: %s\n", errno,
+              strerror (errno));
+      }
+      hash_table_del (&tlb_priv.dmabuf_map, &elem->hash);
+      free (elem);
+    }
+
+    if (conf->test_mode == 0)
+      close(fd);
+
+    if (hash_table_destroy (&tlb_priv.dmabuf_map) < 0)
+      logerr (TAG, "Error destroying the hash table\n");
+  }
+
+exit:
+  pthread_mutex_unlock (&mutex);
 }
 
 /**
@@ -63,8 +205,41 @@ tlb_close (int fd)
 int
 tlb_map_dmabuf (int fd, int dmabuf_fd)
 {
-  /** TODO: fill this function */
-  return 0;
+  int err = 0;
+  int id;
+  map_elem *elem;
+
+  VERIFY_VALID_TLB_LOCKED (tlb_priv, fd);
+
+  elem = (map_elem *) malloc (sizeof(map_elem));
+  if (elem == NULL) {
+    err = -ENOMEM;
+    goto exit;
+  }
+
+  if (conf->test_mode == 1) {
+    id = dmabuf_fd;
+  } else {
+    id = dmabuf_fd;
+    err = ioctl (tlb_priv.fd, SRTLB_IOCTL_MAP_DMABUF, &dmabuf_fd);
+    if (err < 0) {
+      logerr (TAG, "ioctl() error in map %d: %s\n", errno, strerror (errno));
+      goto exit_free;
+    }
+  }
+
+  elem->fd = dmabuf_fd;
+  elem->id = id;
+  hash_table_add (&tlb_priv.dmabuf_map, &elem->hash, dmabuf_fd);
+
+  goto exit;
+
+exit_free:
+  free (elem);
+exit:
+  pthread_mutex_unlock (&mutex);
+
+  return err;
 }
 
 /**
@@ -76,8 +251,34 @@ tlb_map_dmabuf (int fd, int dmabuf_fd)
 int
 tlb_unmap_dmabuf (int fd, int dmabuf_fd)
 {
-  /** TODO: fill this function */
-  return 0;
+  int err = 0;
+  map_elem *elem = NULL;
+
+  VERIFY_VALID_TLB_LOCKED (tlb_priv, fd);
+
+  /** find the elem */
+  elem = find_map_elem (dmabuf_fd);
+  if (elem == NULL) {
+    err = -EPERM;
+    logerr (TAG, "Entry not found\n");
+    goto exit;
+  }
+
+  if (conf->test_mode == 0) {
+    err = ioctl (tlb_priv.fd, SRTLB_IOCTL_UNMAP_DMABUF, &elem->id);
+    if (err < 0) {
+      logerr (TAG, "ioctl() error in unmap %d: %s\n", errno, strerror (errno));
+      goto exit;
+    }
+  }
+
+  hash_table_del (&tlb_priv.dmabuf_map, &elem->hash);
+  free (elem);
+
+exit:
+  pthread_mutex_unlock (&mutex);
+
+  return err;
 }
 
 /**
@@ -89,6 +290,23 @@ tlb_unmap_dmabuf (int fd, int dmabuf_fd)
 int
 tlb_get_dmabuf_id (int fd, int dmabuf_fd)
 {
-  /** TODO: fill this function */
-  return 0;
+  int err = 0;
+  map_elem *elem = NULL;
+
+  VERIFY_VALID_TLB_LOCKED (tlb_priv, fd);
+
+  /** find the elem */
+  elem = find_map_elem (dmabuf_fd);
+  if (elem == NULL) {
+    logerr (TAG, "Entry not found\n");
+    err = -EINVAL;
+    goto exit;
+  }
+
+  err = elem->id;
+
+exit:
+  pthread_mutex_unlock (&mutex);
+
+  return err;
 }
index 1f3cf31..4b34255 100644 (file)
@@ -2,5 +2,6 @@ ne_core_tlb_inc = include_directories('.')
 ne_core_tlb_src = ['TLBdrvAPI.c']
 ne_core_tlb_dep = declare_dependency(
   sources : ne_core_tlb_src,
+  dependencies : ne_core_utils_dep,
   include_directories : ne_core_tlb_inc)
 
index 6862880..9aa14f5 100644 (file)
@@ -35,6 +35,21 @@ if gtest_dep.found()
 
   test('unittest_ne_core_npu', unittest_ne_core_npu)
 
+  ne_core_tlb_unittest_deps = [
+    ne_core_tlb_dep,
+    gtest_dep
+  ]
+
+  unittest_ne_core_tlb = executable('unittest_ne_core_tlb',
+    ['ne_core_tlb_test.cpp'],
+    dependencies: [ne_core_tlb_unittest_deps],
+    cpp_args : '-std=c++11',
+    install : true,
+    install_dir : join_paths(ne_bindir, 'unittests')
+  )
+
+  test('unittest_ne_core_tlb', unittest_ne_core_tlb)
+
   ne_core_utils_unittest_deps = [
     ne_core_utils_dep,
     gtest_dep
diff --git a/src/test/unittests/ne_core_tlb_test.cpp b/src/test/unittests/ne_core_tlb_test.cpp
new file mode 100644 (file)
index 0000000..47bff39
--- /dev/null
@@ -0,0 +1,190 @@
+/**
+ * Proprietary
+ * Copyright (C) 2019 Samsung Electronics
+ * Copyright (C) 2019 Parichay Kapoor <pk.kapoor@samsung.com>
+ */
+/**
+ * @file ne_core_tlb_test.cpp
+ * @date 14 Oct 2019
+ * @brief Test tlb driver api
+ * @author Parichay Kapoor <pk.kapoor@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <gtest/gtest.h>
+
+extern "C"
+{
+  #include <ne-conf.h>
+  #include <TLBdrvAPI.h>
+}
+
+/** Define 0 for success return */
+#define RET_SUCCESS 0
+#define TLB_NAME "srtlb"
+
+/**
+ * @brief base open and close a device
+ */
+TEST (ne_core_tlb_test, dev_open_close)
+{
+  int base_fd, fd;
+
+  /** basic open and close */
+  fd = tlb_open (TLB_NAME);
+  EXPECT_TRUE (fd >= 0);
+  base_fd = fd;
+
+  fd = tlb_open (TLB_NAME);
+  EXPECT_EQ (fd, base_fd);
+
+  fd = tlb_open (TLB_NAME);
+  EXPECT_EQ (fd, base_fd);
+
+  tlb_close (fd);
+  tlb_close (fd);
+  tlb_close (fd);
+}
+
+/**
+ * @brief error cases for map/unmap of dmabuf
+ */
+TEST (ne_core_tlb_test, dev_operate_00_n)
+{
+  int fd = 0;
+  int dmabuf_fd = 1;
+  int ret;
+
+  /** perform operations without device opened */
+  ret = tlb_unmap_dmabuf(fd, dmabuf_fd);
+  EXPECT_NE (ret, RET_SUCCESS);
+  ret = tlb_map_dmabuf(fd, dmabuf_fd);
+  EXPECT_NE (ret, RET_SUCCESS);
+  ret = tlb_unmap_dmabuf(fd, dmabuf_fd);
+  EXPECT_NE (ret, RET_SUCCESS);
+  ret = tlb_get_dmabuf_id(fd, dmabuf_fd);
+  EXPECT_NE (ret, RET_SUCCESS);
+
+  /** basic open and close */
+  fd = tlb_open (TLB_NAME);
+  EXPECT_TRUE (fd >= 0);
+
+  tlb_close (fd);
+
+  /** perform operations after device closed */
+  ret = tlb_unmap_dmabuf(fd, dmabuf_fd);
+  EXPECT_NE (ret, RET_SUCCESS);
+  ret = tlb_map_dmabuf(fd, dmabuf_fd);
+  EXPECT_NE (ret, RET_SUCCESS);
+  ret = tlb_unmap_dmabuf(fd, dmabuf_fd);
+  EXPECT_NE (ret, RET_SUCCESS);
+  ret = tlb_get_dmabuf_id(fd, dmabuf_fd);
+  EXPECT_NE (ret, RET_SUCCESS);
+}
+
+/**
+ * @brief map/unmap dmabuf testing 01
+ */
+TEST (ne_core_tlb_test, dev_operate_01_n)
+{
+  int fd;
+  int dmabuf_fd = 1;
+  int ret;
+
+  /** basic open and close */
+  fd = tlb_open (TLB_NAME);
+  EXPECT_TRUE (fd >= 0);
+
+  /** access entry without creating entry */
+  ret = tlb_unmap_dmabuf(fd, dmabuf_fd);
+  EXPECT_NE (ret, RET_SUCCESS);
+  ret = tlb_get_dmabuf_id(fd, dmabuf_fd);
+  EXPECT_NE (ret, RET_SUCCESS);
+
+  /** create successful entry and access */
+  ret = tlb_map_dmabuf(fd, dmabuf_fd);
+  EXPECT_EQ (ret, RET_SUCCESS);
+  ret = tlb_get_dmabuf_id(fd, dmabuf_fd);
+  EXPECT_GE (ret, RET_SUCCESS);
+  ret = tlb_unmap_dmabuf(fd, dmabuf_fd);
+  EXPECT_EQ (ret, RET_SUCCESS);
+
+  /** access entry after removing entry */
+  ret = tlb_unmap_dmabuf(fd, dmabuf_fd);
+  EXPECT_NE (ret, RET_SUCCESS);
+  ret = tlb_get_dmabuf_id(fd, dmabuf_fd);
+  EXPECT_NE (ret, RET_SUCCESS);
+
+  tlb_close (fd);
+}
+
+/**
+ * @brief map/unmap dmabuf testing 02
+ */
+TEST (ne_core_tlb_test, dev_operate_02_n)
+{
+  int fd;
+  int dmabuf_fd = 1;
+  int ret;
+
+  /** basic open and close */
+  fd = tlb_open (TLB_NAME);
+  EXPECT_TRUE (fd >= 0);
+
+  /** create successful entry and access */
+  ret = tlb_map_dmabuf(fd, dmabuf_fd);
+  EXPECT_EQ (ret, RET_SUCCESS);
+  ret = tlb_map_dmabuf(fd, dmabuf_fd);
+  EXPECT_EQ (ret, RET_SUCCESS);
+  ret = tlb_map_dmabuf(fd, dmabuf_fd+3);
+  EXPECT_EQ (ret, RET_SUCCESS);
+  ret = tlb_map_dmabuf(fd, dmabuf_fd+2);
+  EXPECT_EQ (ret, RET_SUCCESS);
+
+  ret = tlb_get_dmabuf_id(fd, dmabuf_fd);
+  EXPECT_GE (ret, RET_SUCCESS);
+  ret = tlb_get_dmabuf_id(fd, dmabuf_fd+3);
+  EXPECT_GE (ret, RET_SUCCESS);
+  ret = tlb_get_dmabuf_id(fd, dmabuf_fd+2);
+  EXPECT_GE (ret, RET_SUCCESS);
+  ret = tlb_get_dmabuf_id(fd, dmabuf_fd+4);
+  EXPECT_NE (ret, RET_SUCCESS);
+
+  ret = tlb_unmap_dmabuf(fd, dmabuf_fd);
+  EXPECT_EQ (ret, RET_SUCCESS);
+
+  ret = tlb_get_dmabuf_id(fd, dmabuf_fd);
+  EXPECT_GE (ret, RET_SUCCESS);
+  ret = tlb_get_dmabuf_id(fd, dmabuf_fd+3);
+  EXPECT_GE (ret, RET_SUCCESS);
+  ret = tlb_get_dmabuf_id(fd, dmabuf_fd+2);
+  EXPECT_GE (ret, RET_SUCCESS);
+
+  /** access entry after removing entry */
+  ret = tlb_unmap_dmabuf(fd, dmabuf_fd);
+  EXPECT_EQ (ret, RET_SUCCESS);
+  ret = tlb_unmap_dmabuf(fd, dmabuf_fd+3);
+  EXPECT_EQ (ret, RET_SUCCESS);
+  ret = tlb_unmap_dmabuf(fd, dmabuf_fd+2);
+  EXPECT_EQ (ret, RET_SUCCESS);
+  ret = tlb_unmap_dmabuf(fd, dmabuf_fd+4);
+  EXPECT_NE (ret, RET_SUCCESS);
+
+  tlb_close (fd);
+}
+
+/**
+ * @brief main function for unit test
+ */
+int
+main (int argc, char **argv)
+{
+  load_conf (argv[1]);
+
+  testing::InitGoogleTest (&argc, argv);
+
+  return RUN_ALL_TESTS();
+}
+