This patch implements hwmem alloc/dealloc via Cuse driver.
Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
* @note this input service does not use a thread pool.
*/
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#include "ne-inputservice.h"
#include <memory>
#include <thread>
-#include <sys/user.h> /* PAGE_SIZE */
-/** the size of each allocation is aligned to PAGE_SIZE */
-#ifndef PAGE_SHIFT
-#define PAGE_SHIFT (12)
-#endif
-#ifndef PAGE_SIZE
-#define PAGE_SIZE (1UL << PAGE_SHIFT)
-#endif
-#ifndef PFN_UP
-#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
-#endif
-#define ALIGNED_SIZE(x) (PFN_UP(x) * PAGE_SIZE)
-
-typedef struct trinity_model model_config_t;
-typedef struct trinity_input input_config_t;
+typedef struct trinity_ioctl_model model_config_t;
+typedef struct trinity_ioctl_input input_config_t;
typedef enum trinity_state device_state_t;
typedef enum trinity_dev_type device_dev_t;
static uint32_t api_level_; /**< Trinity API level */
};
+class CuseElement;
+
/** @brief Driver APIs for TRIV2 */
class TrinityVision2API : public DriverAPI {
public:
static const std::string dev_node_base;
static std::bitset<CHAR_BIT> dev_bitset;
+ static ThreadSafeMap<int, CuseElement> cuse_map;
+
int sched_dev_fd_;
+ bool is_cuse_;
std::fstream dev_ios_;
};
const std::string TrinityVision2API::dev_node_base = "triv2";
std::bitset<CHAR_BIT> TrinityVision2API::dev_bitset = 0;
+/** @brief Cuse-hwmem element */
+class CuseElement {
+ public:
+ CuseElement (int dbuf_fd, int shm_fd, const std::string & shm_name) :
+ dbuf_fd_ (dbuf_fd), shm_fd_ (shm_fd), shm_name_ (shm_name) {}
+
+ ~CuseElement () {
+ close (shm_fd_);
+ shm_unlink (shm_name_.c_str ());
+ }
+
+ int getDbufFD () { return dbuf_fd_; }
+ int getShmFD () { return shm_fd_; }
+ const std::string & getShmName () { return shm_name_; }
+
+ private:
+ int dbuf_fd_;
+ int shm_fd_;
+ const std::string shm_name_;
+};
+
+ThreadSafeMap<int, CuseElement> TrinityVision2API::cuse_map;
+
/**
* @brief constructor of the API instance for Trinity Vision driver
* @param[in] dev_id device id
*/
TrinityVision2API::TrinityVision2API (int dev_id) :
- DriverAPI (dev_id), sched_dev_fd_ (-1)
+ DriverAPI (dev_id), sched_dev_fd_ (-1), is_cuse_ (false)
{
int num_devs;
int
TrinityVision2API::checkSanity ()
{
- unsigned int lib_ver = trinity_gen_ver (TRINITY_DEV_VISION_2, VER_NE_MAJOR,
- VER_NE_MINOR, VER_NE_EXTRA);
- unsigned int min_ver = this->getDrvVersion();
+ int lib_ver = trinity_gen_ver (0, VER_NE_MAJOR, VER_NE_MINOR, VER_NE_EXTRA);
+ int min_ver = this->getDrvVersion();
+ enum trinity_dev_type type =
+ static_cast<enum trinity_dev_type> ((min_ver & TRINITY_MASK_DEV) >> TRINITY_SHIFT_DEV);
- // Check if this device is for TRIV1
- if ((lib_ver & TRINITY_MASK_DEV) != (min_ver & TRINITY_MASK_DEV))
+ /* Check if this device is a TRIV2-compatible one */
+ if (type != TRINITY_DEV_VISION2 && type != TRINITY_DEV_VISION2_CUSE)
return -ENODEV;
- // Check if the major version numbers are same
+ /* Check if this device is using a cuse-based driver */
+ if (type == TRINITY_DEV_VISION2_CUSE)
+ this->is_cuse_ = true;
+
+ min_ver &= ~TRINITY_MASK_DEV;
+ /* Check if the major version numbers are same */
if ((lib_ver & TRINITY_MASK_MAJOR_VER) != (min_ver & TRINITY_MASK_MAJOR_VER))
return -ENOTSUP;
+ /* Check if the library version is lower than the driver one */
if (lib_ver < min_ver)
return -ENOTSUP;
if (!this->initialized())
return -EPERM;
+ if (size == 0 || size > UINT32_MAX)
+ return -EINVAL;
+
hwmem.type = contiguous ? HWMEM_DMA_CONT : HWMEM_DMA_IOMMU;
hwmem.size = size;
if (ret < 0)
return -errno;
+ if (!is_cuse_)
+ return ret;
+
+ CuseElement *elem;
+ std::string shm_name;
+ int dbuf_fd = ret;
+ struct stat statbuf;
+
+ /* Let's use shared memory for emulated dmabuf */
+ shm_name = "/triv2_" + std::to_string (getpid ()) + "_" + std::to_string (dbuf_fd);
+ ret = shm_open (shm_name.c_str (), O_RDWR, 0666);
+ if (ret < 0)
+ return ret;
+
+ elem = new CuseElement (dbuf_fd, ret, shm_name);
+ if (fstat (ret, &statbuf) < 0) {
+ delete elem;
+ return -errno;
+ }
+
+ if (size != statbuf.st_size) {
+ delete elem;
+ return -EINVAL;
+ }
+
+ if (cuse_map.insert (ret, elem) < 0) {
+ delete elem;
+ return -EINVAL;
+ }
+
return ret;
}
return -EPERM;
hwmem.type = contiguous ? HWMEM_DMA_CONT : HWMEM_DMA_IOMMU;
- hwmem.dbuf_fd = dmabuf;
+
+ if (is_cuse_) {
+ CuseElement *elem = cuse_map.find (dmabuf);
+ if (elem == nullptr)
+ return -ENOENT;
+
+ hwmem.dbuf_fd = elem->getDbufFD ();
+
+ cuse_map.remove (dmabuf);
+ } else {
+ hwmem.dbuf_fd = dmabuf;
+ }
ret = ioctl (this->getDeviceFD (), TRINITY_IOCTL_HWMEM_DEALLOC, &hwmem);
if (ret < 0)
{
void *ret;
- if (!this->initialized())
+ if (!this->initialized ())
+ return nullptr;
+
+ if (size != ALIGNED_SIZE (size))
return nullptr;
- ret = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, dmabuf, 0);
+ ret = ::mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, dmabuf, 0);
if (ret == MAP_FAILED)
return nullptr;
int
TrinityVision2API::getProfile (int req_id, npu_profile *profile) const
{
- struct trinity_profile t_profile;
+ struct trinity_ioctl_profile t_profile;
int ret = 0;
if (profile == nullptr)
ne_core_npu_dep = declare_dependency(
sources : ne_core_npu_src,
dependencies : [ne_core_utils_dep],
+ link_args : '-lrt',
include_directories : [ne_common_inc, ne_core_npu_inc])
endif
#include <condition_variable>
#include <functional>
+#include <sys/user.h> /* PAGE_SIZE */
+
+#ifndef PAGE_SHIFT
+#define PAGE_SHIFT (12)
+#endif
+#ifndef PAGE_SIZE
+#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#endif
+#ifndef PFN_UP
+#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
+#endif
+#define ALIGNED_SIZE(x) (PFN_UP(x) * PAGE_SIZE)
+
/********************************************************************
* Logging utilities *
********************************************************************/
#include <triv2profile.h>
#include <ne-conf.h>
+#include <ne-utils.h>
+#include <atomic>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/types.h>
#include "trinity-cuse.h"
/**
+ * @brief Emulated Dmabuf Impl.
+ */
+class EmulDmabuf {
+ public:
+ EmulDmabuf (int app_id) : fd_ (-1), shm_fd_ (-1), size_ (0) {
+ std::string name;
+
+ fd_ = global_fd_.fetch_add (1);
+
+ /* create a shared memory */
+ mode_t old_umask = umask (0);
+ shm_name_ = "/triv2_" + std::to_string (app_id) + "_" + std::to_string (fd_);
+ shm_fd_ = shm_open (shm_name_.c_str (), O_RDWR | O_CREAT, 0666);
+ umask (old_umask);
+ }
+
+ ~EmulDmabuf () {
+ if (shm_fd_ < 0)
+ return;
+
+ shm_unlink (shm_name_.c_str ());
+ close (shm_fd_);
+ }
+
+ int setSize (size_t size) {
+ int err;
+
+ if (shm_fd_ < 0)
+ return -EINVAL;
+
+ /* change file size */
+ err = ftruncate (shm_fd_, size);
+ if (err != 0)
+ return err;
+
+ size_ = size;
+ return 0;
+ }
+
+ size_t getSize () const { return size_; }
+ int getFD () const { return fd_; }
+
+ private:
+ static std::atomic<int> global_fd_;
+
+ int fd_;
+ int shm_fd_;
+ std::string shm_name_;
+ size_t size_;
+};
+
+/** @brief Global mapping of dmabuf */
+ThreadSafeMap<int, EmulDmabuf> global_dmabuf_map;
+/** @brief Global file descriptor */
+std::atomic<int> EmulDmabuf::global_fd_ (0);
+
+/**
* @brief TRIV2 impl. of get_version ioctl()
*/
static int
-triv2_get_version (uint32_t *version)
+triv2_get_version (trinity_cuse_context *ctx, uint32_t *version)
{
- *version = trinity_gen_ver (2, 2, 0, 0);
- fprintf (stderr, "version: %x\n", *version);
+ *version = trinity_gen_ver (TRINITY_DEV_VISION2_CUSE, 2, 0, 0);
return 0;
}
* @brief TRIV2 impl. of get_api_level ioctl()
*/
static int
-triv2_get_api_level (uint32_t *api_level)
+triv2_get_api_level (trinity_cuse_context *ctx, 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)
+triv2_get_state (trinity_cuse_context *ctx, uint32_t *state)
{
*state = STATE_READY;
return 0;
* @brief TRIV2 impl. of get_tops ioctl()
*/
static int
-triv2_get_tops (uint32_t *tops)
+triv2_get_tops (trinity_cuse_context *ctx, uint32_t *tops)
{
*tops = 2;
return 0;
* @brief TRIV2 impl. of get_dspm ioctl()
*/
static int
-triv2_get_dspm (uint32_t *dspm)
+triv2_get_dspm (trinity_cuse_context *ctx, uint32_t *dspm)
{
*dspm = UINT32_MAX;
return 0;
}
+/**
+ * @brief TRIV2 impl. of hwmem_alloc ioctl()
+ */
+static int
+triv2_hwmem_alloc (trinity_cuse_context *ctx, const struct trinity_ioctl_hwmem * hwmem)
+{
+ EmulDmabuf *dmabuf;
+ size_t size;
+
+ size = ALIGNED_SIZE (hwmem->size);
+ if (size == 0)
+ return -EINVAL;
+
+ switch (hwmem->type) {
+ case HWMEM_DMA_CONT:
+ case HWMEM_DMA_IOMMU:
+ dmabuf = new EmulDmabuf (ctx->app_id);
+ if (dmabuf->setSize (size) != 0)
+ return -EINVAL;
+
+ if (global_dmabuf_map.insert (dmabuf->getFD (), dmabuf) != 0) {
+ delete dmabuf;
+ return -EINVAL;
+ }
+
+ return dmabuf->getFD ();
+ default:
+ return -ENOTTY;
+ }
+}
+
+/**
+ * @brief TRIV2 impl. of hwmem_dealloc ioctl()
+ */
+static int
+triv2_hwmem_dealloc (trinity_cuse_context *ctx, const struct trinity_ioctl_hwmem * hwmem)
+{
+ return global_dmabuf_map.remove (hwmem->dbuf_fd);
+}
+
/** @brief The ioctl vtable for TRIV2 devices */
static trinity_cuse_ioctl_vtable triv2_vtable {
+ /* Device Info. */
.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 */
+ /* Device Control */
+ .hwmem_alloc = triv2_hwmem_alloc,
+ .hwmem_dealloc = triv2_hwmem_dealloc,
};
/** @brief Setting the ioctl vtable */
return;
}
- std::cerr << "open!!\n";
+ ctx->app_id = fuse_req_ctx (req)->pid;
fi->fh = (uint64_t) ctx;
fuse_reply_open(req, fi);
struct fuse_file_info *fi, unsigned int flags,
const void *in_buf, size_t in_size, size_t out_size)
{
- (void) fi;
+ trinity_cuse_context *ctx = (trinity_cuse_context *) fi->fh;
if (flags & FUSE_IOCTL_COMPAT) {
fuse_reply_err (req, ENOSYS);
fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
} else {
uint32_t val;
- vtable->get_version (&val);
+ vtable->get_version (ctx, &val);
fuse_reply_ioctl (req, 0, &val, sizeof (val));
}
break;
fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
} else {
uint32_t val;
- vtable->get_api_level (&val);
+ vtable->get_api_level (ctx, &val);
fuse_reply_ioctl (req, 0, &val, sizeof (val));
}
break;
fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
} else {
uint32_t val;
- vtable->get_state (&val);
+ vtable->get_state (ctx, &val);
fuse_reply_ioctl (req, 0, &val, sizeof (val));
}
break;
fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
} else {
uint32_t val;
- vtable->get_tops (&val);
+ vtable->get_tops (ctx, &val);
fuse_reply_ioctl (req, 0, &val, sizeof (val));
}
break;
fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
} else {
uint32_t val;
- vtable->get_dspm (&val);
+ vtable->get_dspm (ctx, &val);
fuse_reply_ioctl (req, 0, &val, sizeof (val));
}
break;
+ case TRINITY_IOCTL_HWMEM_ALLOC:
+ if (!in_size) {
+ struct iovec iov = { arg, sizeof (struct trinity_ioctl_hwmem) };
+ fuse_reply_ioctl_retry (req, &iov, 1, NULL, 0);
+ } else {
+ const struct trinity_ioctl_hwmem *val =
+ static_cast<const struct trinity_ioctl_hwmem *> (in_buf);
+ fuse_reply_ioctl (req, vtable->hwmem_alloc (ctx, val), NULL, 0);
+ }
+ break;
+ case TRINITY_IOCTL_HWMEM_DEALLOC:
+ if (!in_size) {
+ struct iovec iov = { arg, sizeof (struct trinity_ioctl_hwmem) };
+ fuse_reply_ioctl_retry (req, &iov, 1, NULL, 0);
+ } else {
+ const struct trinity_ioctl_hwmem *val =
+ static_cast<const struct trinity_ioctl_hwmem *> (in_buf);
+ fuse_reply_ioctl (req, vtable->hwmem_dealloc (ctx, val), NULL, 0);
+ }
+ break;
/* NYI */
default:
fuse_reply_err (req, ENOTTY);
- break;
}
-
- fuse_reply_err (req, 0);
}
/** @brief Structure to describe parameters */
* @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 */
+ /* Device Info. */
+ int (*get_version) (trinity_cuse_context *, uint32_t *);
+ int (*get_api_level) (trinity_cuse_context *, uint32_t *);
+ int (*get_state) (trinity_cuse_context *, uint32_t *);
+ int (*get_tops) (trinity_cuse_context *, uint32_t *);
+ int (*get_dspm) (trinity_cuse_context *, uint32_t *);
+ /* Device Control */
+ int (*hwmem_alloc) (trinity_cuse_context *, const struct trinity_ioctl_hwmem *);
+ int (*hwmem_dealloc) (trinity_cuse_context *, const struct trinity_ioctl_hwmem *);
} trinity_cuse_ioctl_vtable;
#endif