[Utils/Cuse] Add the prototype of trinity-cuse
authorDongju Chae <dongju.chae@samsung.com>
Mon, 12 Apr 2021 07:55:58 +0000 (16:55 +0900)
committer채동주/On-Device Lab(SR)/Staff Engineer/삼성전자 <dongju.chae@samsung.com>
Mon, 19 Apr 2021 04:02:08 +0000 (13:02 +0900)
This patch adds the prototype of trinity-cuse, which is a
CUSE-based user-level device driver, and thus can be utilized
in the tizen emulator to provide a virtual device node.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
debian/control
packaging/npu-engine.spec
utils/meson.build
utils/trinity_cuse/meson.build [new file with mode: 0644]
utils/trinity_cuse/trinity-cuse-triv2.cc [new file with mode: 0644]
utils/trinity_cuse/trinity-cuse.cc [new file with mode: 0644]
utils/trinity_cuse/trinity-cuse.h [new file with mode: 0644]
utils/trinity_smi/meson.build

index 0fde882..e774e50 100644 (file)
@@ -4,7 +4,7 @@ Priority: optional
 Maintainer: MyungJoo Ham <myungjoo.ham@samsung.com>
 Build-Depends: ninja-build, meson (>=0.50), debhelper (>=9),
  gcc-9 | gcc-8 | gcc-7 | gcc-6 | gcc-5, libgtest-dev, python,
- libiniparser-dev, pkg-config, cmake, libdrm-dev,
+ libiniparser-dev, pkg-config, cmake, libdrm-dev, libfuse-dev,
  linux-fvp-headers, libmrpsim-dev (>=2.3.4), libtinyxml2-dev, libncurses-dev
 Standards-Version: 3.8.2
 Homepage: https://research.samsung.com
index bb9fad3..f0c7d25 100644 (file)
@@ -21,6 +21,7 @@ BuildRequires:        pkgconfig(iniparser)
 
 # utils
 BuildRequires: ncurses-devel
+BuildRequires: fuse-devel
 
 # test
 BuildRequires: gtest-devel
index 510bd58..286acb4 100644 (file)
@@ -1,2 +1,3 @@
 subdir('model_inspect')
 subdir('trinity_smi')
+subdir('trinity_cuse')
diff --git a/utils/trinity_cuse/meson.build b/utils/trinity_cuse/meson.build
new file mode 100644 (file)
index 0000000..b8f2d7b
--- /dev/null
@@ -0,0 +1,27 @@
+fuse_dep = dependency('fuse', required: false)
+libmrpsim_dep = dependency('libmrpsim', required: false)
+
+##
+# Trinity-CUSE: Utility to provide a character device in userspace (CUSE).
+# Note that CUSE is a fuse-based optimization for character devices.
+#
+if fuse_dep.found() and libmrpsim_dep.found()
+  utils_cuse_srcs = [
+    'trinity-cuse.cc',
+    'trinity-cuse-triv2.cc'
+  ]
+  utils_cuse_deps = [
+    ne_core_utils_dep,
+    fuse_dep,
+    libmrpsim_dep
+  ]
+
+  utils_trinity_cuse = executable('trinity-cuse',
+    utils_cuse_srcs,
+    include_directories: [ne_common_inc],
+    dependencies : utils_cuse_deps,
+    install : true,
+    install_rpath : ne_libdir,
+    install_dir : join_paths(ne_bindir, 'utils')
+  )
+endif
diff --git a/utils/trinity_cuse/trinity-cuse-triv2.cc b/utils/trinity_cuse/trinity-cuse-triv2.cc
new file mode 100644 (file)
index 0000000..da34450
--- /dev/null
@@ -0,0 +1,88 @@
+/**
+ * Proprietary
+ * Copyright (C) 2021 Samsung Electronics
+ * Copyright (C) 2021 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file trinity-cuse-triv2.cc
+ * @date 12 Apr 2021
+ * @brief Implementation of triv2 ioctl() in the cuse driver
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <triv2profile.h>
+#include <ne-conf.h>
+
+#include "trinity-cuse.h"
+
+/**
+ * @brief TRIV2 impl. of get_version ioctl()
+ */
+static int
+triv2_get_version (uint32_t *version)
+{
+  *version = trinity_gen_ver (2, 2, 0, 0);
+  fprintf (stderr, "version: %x\n", *version);
+  return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of get_api_level ioctl()
+ */
+static int
+triv2_get_api_level (uint32_t *api_level)
+{
+  *api_level = TRINITY_API_LEVEL;
+  return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of get_state ioctl()
+ */
+static int
+triv2_get_state (uint32_t *state)
+{
+  *state = STATE_READY;
+  return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of get_tops ioctl()
+ */
+static int
+triv2_get_tops (uint32_t *tops)
+{
+  *tops = 2;
+  return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of get_dspm ioctl()
+ */
+static int
+triv2_get_dspm (uint32_t *dspm)
+{
+  *dspm = UINT32_MAX;
+  return 0;
+}
+
+/** @brief The ioctl vtable for TRIV2 devices */
+static trinity_cuse_ioctl_vtable triv2_vtable {
+  .get_version = triv2_get_version,
+  .get_api_level = triv2_get_api_level,
+  .get_state = triv2_get_state,
+  .get_tops = triv2_get_tops,
+  .get_dspm = triv2_get_dspm,
+  /* NYI */
+};
+
+/** @brief Setting the ioctl vtable */
+bool
+set_ioctl_vtable_triv2 (trinity_cuse_ioctl_vtable ** vtable) {
+  if (vtable == nullptr)
+    return false;
+
+  *vtable = &triv2_vtable;
+  return true;
+}
diff --git a/utils/trinity_cuse/trinity-cuse.cc b/utils/trinity_cuse/trinity-cuse.cc
new file mode 100644 (file)
index 0000000..033cd21
--- /dev/null
@@ -0,0 +1,280 @@
+/**
+ * Proprietary
+ * Copyright (C) 2021 Samsung Electronics
+ * Copyright (C) 2021 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file trinity-cuse.cc
+ * @date 12 Apr 2021
+ * @brief Utility to provide virtual device nodes of trinity devices
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#define FUSE_USE_VERSION 29
+
+#include <iostream>
+
+#include <cuse_lowlevel.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/ioctl.h>
+
+#include "trinity-cuse.h"
+
+static trinity_cuse_ioctl_vtable *vtable;
+
+extern bool set_ioctl_vtable_triv2 (trinity_cuse_ioctl_vtable **);
+
+/**
+ * @brief Find the ioctl vtable for the given device type
+ */
+bool
+find_ioctl_vtable (const std::string &dev_name)
+{
+  if (dev_name == "triv2")
+    return set_ioctl_vtable_triv2 (&vtable);
+
+  return false;
+}
+
+/**
+ * @brief impl. of .open ()
+ */
+static void
+trinity_cuse_open (fuse_req_t req, struct fuse_file_info *fi)
+{
+  trinity_cuse_context *ctx;
+
+  ctx = (trinity_cuse_context *) malloc (sizeof (*ctx));
+  if (ctx == NULL) {
+    fuse_reply_err (req, ENOMEM);
+    return;
+  }
+
+  std::cerr << "open!!\n";
+
+  fi->fh = (uint64_t) ctx;
+  fuse_reply_open(req, fi);
+}
+
+/**
+ * @brief impl. of .release ()
+ */
+static void
+trinity_cuse_release (fuse_req_t req, struct fuse_file_info *fi)
+{
+  trinity_cuse_context *ctx = (trinity_cuse_context *) fi->fh;
+
+  if (ctx)
+    free (ctx);
+
+  fi->fh = 0;
+  fuse_reply_err (req, 0);
+}
+
+/**
+ * @brief impl. of .ioctl ()
+ */
+static void
+trinity_cuse_ioctl (fuse_req_t req, int cmd, void *arg,
+    struct fuse_file_info *fi, unsigned int flags,
+    const void *in_buf, size_t in_size, size_t out_size)
+{
+  (void) fi;
+
+  if (flags & FUSE_IOCTL_COMPAT) {
+    fuse_reply_err (req, ENOSYS);
+    return;
+  }
+
+  if (vtable == nullptr) {
+    fuse_reply_err (req, EINVAL);
+    return;
+  }
+
+  switch (cmd) {
+    case TRINITY_IOCTL_GET_VERSION:
+      if (!out_size) {
+        struct iovec iov = { arg, sizeof (uint32_t) };
+        fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+      } else {
+        uint32_t val;
+        vtable->get_version (&val);
+        fuse_reply_ioctl (req, 0, &val, sizeof (val));
+      }
+      break;
+    case TRINITY_IOCTL_GET_API_LEVEL:
+      if (!out_size) {
+        struct iovec iov = { arg, sizeof (uint32_t) };
+        fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+      } else {
+        uint32_t val;
+        vtable->get_api_level (&val);
+        fuse_reply_ioctl (req, 0, &val, sizeof (val));
+      }
+      break;
+    case TRINITY_IOCTL_GET_STATE:
+      if (!out_size) {
+        struct iovec iov = { arg, sizeof (uint32_t) };
+        fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+      } else {
+        uint32_t val;
+        vtable->get_state (&val);
+        fuse_reply_ioctl (req, 0, &val, sizeof (val));
+      }
+      break;
+    case TRINITY_IOCTL_GET_TOPS:
+      if (!out_size) {
+        struct iovec iov = { arg, sizeof (uint32_t) };
+        fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+      } else {
+        uint32_t val;
+        vtable->get_tops (&val);
+        fuse_reply_ioctl (req, 0, &val, sizeof (val));
+      }
+      break;
+    case TRINITY_IOCTL_GET_DSPM:
+      if (!out_size) {
+        struct iovec iov = { arg, sizeof (uint32_t) };
+        fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+      } else {
+        uint32_t val;
+        vtable->get_dspm (&val);
+        fuse_reply_ioctl (req, 0, &val, sizeof (val));
+      }
+      break;
+    /* NYI */
+    default:
+      fuse_reply_err (req, ENOTTY);
+      break;
+  }
+
+  fuse_reply_err (req, 0);
+}
+
+/** @brief Structure to describe parameters */
+struct trinity_cuse_param {
+  unsigned int major;
+  unsigned int minor;
+  std::string  dev_name;
+  bool         is_help;
+};
+
+#define TRINITY_OPT(t, p) { t, offsetof (struct trinity_cuse_param, p), 1 }
+
+enum {
+  KEY_HELP
+};
+
+/** @brief The definitions of available options */
+static const struct fuse_opt trinity_cuse_opts[] = {
+  TRINITY_OPT("-M %u",      major),
+  TRINITY_OPT("--maj=%u",   major),
+  TRINITY_OPT("-m %u",      minor),
+  TRINITY_OPT("--min=%u",   minor),
+  FUSE_OPT_KEY("-h",        KEY_HELP),
+  FUSE_OPT_KEY("--help",    KEY_HELP),
+  FUSE_OPT_END
+};
+
+/** @brief Print the help message */
+static void
+print_help_message ()
+{
+  static const char *usage =
+    "\nUsage: trinity-cuse [options] [device name]\n"
+    "options:\n"
+    "   --maj=MAJ|-M MAJ    device major number\n"
+    "   --min=MIN|-m MIN    device minor number\n"
+    "   --help|-h           print this help message\n";
+
+  std::cerr << usage;
+}
+
+/** @brief Parse the given arguments */
+static int
+trinity_cuse_parse_args(void *data, const char *arg, int key,
+                              struct fuse_args *outargs)
+{
+  struct trinity_cuse_param *param = (struct trinity_cuse_param *) data;
+
+  (void)outargs;
+  (void)arg;
+
+  switch (key) {
+  case FUSE_OPT_KEY_NONOPT:
+    param->dev_name = std::string (arg);
+    return 0;
+  case KEY_HELP:
+    param->is_help = true;
+    print_help_message ();
+    return fuse_opt_add_arg (outargs, "-ho");
+  default:
+    return 1;
+  }
+}
+
+/** @brief trinity cuse driver's lowlevel ops */
+static const struct cuse_lowlevel_ops trinity_cuse_clop = {
+  .init = nullptr,
+  .init_done = nullptr,
+  .destroy = nullptr,
+  .open = trinity_cuse_open,
+  .read = nullptr,
+  .write = nullptr,
+  .flush = nullptr,
+  .release = trinity_cuse_release,
+  .fsync = nullptr,
+  .ioctl = trinity_cuse_ioctl,
+  .poll = nullptr
+};
+
+/**
+ * @brief main routine of trinity-cuse
+ */
+int
+main (int argc, char **argv)
+{
+  struct fuse_args args = FUSE_ARGS_INIT (argc, argv);
+  struct trinity_cuse_param param = { 0 };
+  struct cuse_info ci = { 0 };
+  std::string dev_name ("DEVNAME=");
+
+  if (fuse_opt_parse (&args, &param, trinity_cuse_opts, trinity_cuse_parse_args)) {
+    std::cerr << "[Error] Failed to parse options\n";
+    return -EINVAL;
+  }
+
+  if (param.is_help == 1)
+    return 0;
+
+  if (param.dev_name.empty ()) {
+    std::cerr << "[Error] Missing device name (e.g., --name=triv2)\n";
+    print_help_message ();
+    return -EINVAL;
+  }
+
+  if (!find_ioctl_vtable (param.dev_name)) {
+    std::cerr << "[Error] Unsupported device: " << param.dev_name << "\n";
+    print_help_message ();
+    return -ENOENT;
+  }
+
+  dev_name += param.dev_name;
+  dev_name += "-0";
+  const char *dev_info_argv[] = { dev_name.c_str() };
+
+  ci.dev_major = param.major;
+  ci.dev_minor = param.minor;
+  ci.dev_info_argc = 1;
+  ci.dev_info_argv = dev_info_argv;
+  ci.flags = CUSE_UNRESTRICTED_IOCTL;
+
+  return cuse_lowlevel_main (args.argc, args.argv, &ci, &trinity_cuse_clop, NULL);
+}
diff --git a/utils/trinity_cuse/trinity-cuse.h b/utils/trinity_cuse/trinity-cuse.h
new file mode 100644 (file)
index 0000000..4272b04
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * Proprietary
+ * Copyright (C) 2021 Samsung Electronics
+ * Copyright (C) 2021 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file trinity-fuse.h
+ * @date 12 Apr 2021
+ * @brief Utility to provide virtual device nodes of trinity devices
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#ifndef __TRINITY_FUSE_H__
+#define __TRINITY_FUSE_H__
+
+#include <misc/trinity.h>
+
+/**
+ * @brief The trinity context
+ */
+typedef struct {
+  int app_id;
+  /* NYI */
+} trinity_cuse_context;
+
+/**
+ * @brief The ioctl vtable of each device ioctl
+ */
+typedef struct {
+  int (*get_version) (uint32_t *);
+  int (*get_api_level) (uint32_t *);
+  int (*get_state) (uint32_t *);
+  int (*get_tops) (uint32_t *);
+  int (*get_dspm) (uint32_t *);
+  /* NYI */
+} trinity_cuse_ioctl_vtable;
+
+#endif
index e4baf71..dcad19e 100644 (file)
@@ -1,11 +1,13 @@
-ncurses_dep = dependency('ncurses')
+ncurses_dep = dependency('ncurses', required: false)
 
-utils_model_inspect = executable('trinity-smi',
-  ['trinity-smi.cc'],
-  include_directories: [ne_host_inc, ne_common_inc],
-  dependencies : ncurses_dep,
-  link_with : ne_library_shared,
-  install : true,
-  install_rpath : ne_libdir,
-  install_dir : join_paths(ne_bindir, 'utils')
-)
+if ncurses_dep.found()
+  utils_trinity_smi = executable('trinity-smi',
+    ['trinity-smi.cc'],
+    include_directories: [ne_host_inc, ne_common_inc],
+    dependencies : ncurses_dep,
+    link_with : ne_library_shared,
+    install : true,
+    install_rpath : ne_libdir,
+    install_dir : join_paths(ne_bindir, 'utils')
+  )
+endif