From: Dongju Chae Date: Tue, 20 Apr 2021 02:58:41 +0000 (+0900) Subject: [Utils/Cuse] Implement hwmem alloc/dealloc via Cuse driver X-Git-Tag: accepted/tizen/unified/20220103.130045~184 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1394c11953857bda4b3550a16169df2ff3f8bcc5;p=platform%2Fadaptation%2Fnpu%2Ftrix-engine.git [Utils/Cuse] Implement hwmem alloc/dealloc via Cuse driver This patch implements hwmem alloc/dealloc via Cuse driver. Signed-off-by: Dongju Chae --- diff --git a/src/core/ne-hw-input-service.cc b/src/core/ne-hw-input-service.cc index a5fe299..131e975 100644 --- a/src/core/ne-hw-input-service.cc +++ b/src/core/ne-hw-input-service.cc @@ -12,6 +12,8 @@ * @note this input service does not use a thread pool. */ +#include +#include #include #include "ne-inputservice.h" diff --git a/src/core/npu/NPUdrvAPI.h b/src/core/npu/NPUdrvAPI.h index 1707df0..9b3fec4 100644 --- a/src/core/npu/NPUdrvAPI.h +++ b/src/core/npu/NPUdrvAPI.h @@ -33,21 +33,8 @@ #include #include -#include /* 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; @@ -126,6 +113,8 @@ class DriverAPI { static uint32_t api_level_; /**< Trinity API level */ }; +class CuseElement; + /** @brief Driver APIs for TRIV2 */ class TrinityVision2API : public DriverAPI { public: @@ -171,7 +160,10 @@ class TrinityVision2API : public DriverAPI { static const std::string dev_node_base; static std::bitset dev_bitset; + static ThreadSafeMap cuse_map; + int sched_dev_fd_; + bool is_cuse_; std::fstream dev_ios_; }; diff --git a/src/core/npu/NPUdrvAPI_triv2.cc b/src/core/npu/NPUdrvAPI_triv2.cc index ce20b96..ea58f93 100644 --- a/src/core/npu/NPUdrvAPI_triv2.cc +++ b/src/core/npu/NPUdrvAPI_triv2.cc @@ -20,12 +20,35 @@ constexpr size_t default_buf_size = (256 * PAGE_SIZE); const std::string TrinityVision2API::dev_node_base = "triv2"; std::bitset 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 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; @@ -80,18 +103,25 @@ TrinityVision2API::open () 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 ((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; @@ -184,6 +214,9 @@ TrinityVision2API::alloc (size_t size, bool contiguous) const 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; @@ -191,6 +224,36 @@ TrinityVision2API::alloc (size_t size, bool contiguous) const 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; } @@ -210,7 +273,18 @@ TrinityVision2API::dealloc (int dmabuf, bool contiguous) const 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) @@ -259,10 +333,13 @@ TrinityVision2API::mmap (int dmabuf, size_t size) const { 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; @@ -472,7 +549,7 @@ TrinityVision2API::fpga_memcpy (int dmabuf, uint32_t offset, void *addr, size_t 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) diff --git a/src/core/npu/meson.build b/src/core/npu/meson.build index 336052e..52ca000 100644 --- a/src/core/npu/meson.build +++ b/src/core/npu/meson.build @@ -22,6 +22,7 @@ else 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 diff --git a/src/core/utils/ne-utils.h b/src/core/utils/ne-utils.h index 2a0edff..253aa6e 100644 --- a/src/core/utils/ne-utils.h +++ b/src/core/utils/ne-utils.h @@ -21,6 +21,19 @@ #include #include +#include /* 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 * ********************************************************************/ diff --git a/utils/trinity_cuse/trinity-cuse-triv2.cc b/utils/trinity_cuse/trinity-cuse-triv2.cc index da34450..459b6b6 100644 --- a/utils/trinity_cuse/trinity-cuse-triv2.cc +++ b/utils/trinity_cuse/trinity-cuse-triv2.cc @@ -13,17 +13,82 @@ #include #include +#include +#include + +#include +#include + +#include +#include +#include #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 global_fd_; + + int fd_; + int shm_fd_; + std::string shm_name_; + size_t size_; +}; + +/** @brief Global mapping of dmabuf */ +ThreadSafeMap global_dmabuf_map; +/** @brief Global file descriptor */ +std::atomic 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; } @@ -31,7 +96,7 @@ triv2_get_version (uint32_t *version) * @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; @@ -41,7 +106,7 @@ triv2_get_api_level (uint32_t *api_level) * @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; @@ -51,7 +116,7 @@ triv2_get_state (uint32_t *state) * @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; @@ -61,20 +126,63 @@ triv2_get_tops (uint32_t *tops) * @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 */ diff --git a/utils/trinity_cuse/trinity-cuse.cc b/utils/trinity_cuse/trinity-cuse.cc index 033cd21..84b3ee5 100644 --- a/utils/trinity_cuse/trinity-cuse.cc +++ b/utils/trinity_cuse/trinity-cuse.cc @@ -57,7 +57,7 @@ trinity_cuse_open (fuse_req_t req, struct fuse_file_info *fi) return; } - std::cerr << "open!!\n"; + ctx->app_id = fuse_req_ctx (req)->pid; fi->fh = (uint64_t) ctx; fuse_reply_open(req, fi); @@ -86,7 +86,7 @@ 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; + trinity_cuse_context *ctx = (trinity_cuse_context *) fi->fh; if (flags & FUSE_IOCTL_COMPAT) { fuse_reply_err (req, ENOSYS); @@ -105,7 +105,7 @@ trinity_cuse_ioctl (fuse_req_t req, int cmd, void *arg, 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; @@ -115,7 +115,7 @@ trinity_cuse_ioctl (fuse_req_t req, int cmd, void *arg, 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; @@ -125,7 +125,7 @@ trinity_cuse_ioctl (fuse_req_t req, int cmd, void *arg, 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; @@ -135,7 +135,7 @@ trinity_cuse_ioctl (fuse_req_t req, int cmd, void *arg, 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; @@ -145,17 +145,34 @@ trinity_cuse_ioctl (fuse_req_t req, int cmd, void *arg, 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 (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 (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 */ diff --git a/utils/trinity_cuse/trinity-cuse.h b/utils/trinity_cuse/trinity-cuse.h index 4272b04..51569a1 100644 --- a/utils/trinity_cuse/trinity-cuse.h +++ b/utils/trinity_cuse/trinity-cuse.h @@ -28,12 +28,15 @@ typedef struct { * @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