From: Parichay Kapoor Date: Fri, 28 Jun 2019 05:55:05 +0000 (+0900) Subject: [Wait4#9][N91/NPUdrvApi_c] Implementation for NPU API interface X-Git-Tag: accepted/tizen/unified/20220103.130045~805 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a4443a80e63df792d377fa191b4798d2f0e7931d;p=platform%2Fadaptation%2Fnpu%2Ftrix-engine.git [Wait4#9][N91/NPUdrvApi_c] Implementation for NPU API interface Added implementation for NPU API interface Updated meson build TODO: implement NYI items v1: Added locking along with minor fixes v2: Updated as per blocking I/O Signed-off-by: Parichay Kapoor --- diff --git a/core/libnpu-core/meson.build b/core/libnpu-core/meson.build index 6607342..d1b205d 100644 --- a/core/libnpu-core/meson.build +++ b/core/libnpu-core/meson.build @@ -1 +1,12 @@ -# DO NOTHING, YET +inc = [ + 'include', +] + +lib_sources = [ + 'src/NPUdrvAPI.c', +] + +libnpu_build = static_library('npu-core', + lib_sources, + include_directories : inc, + install : false) diff --git a/core/libnpu-core/src/NPUdrvAPI.c b/core/libnpu-core/src/NPUdrvAPI.c new file mode 100644 index 0000000..d52cd81 --- /dev/null +++ b/core/libnpu-core/src/NPUdrvAPI.c @@ -0,0 +1,393 @@ +/** + * Proprietary + * Copyright (C) 2019 Samsung Electronics + * Copyright (C) 2019 Parichay Kapoor + * Copyright (C) 2019 MyungJoo Ham + */ +/** + * @file NPUdrvAPI.c + * @date 26 June 2019 + * @brief Implementation of API to access NPU + * @see http://suprem.sec.samsung.net/confluence/display/ODLC/Software+Stack + * @author Parichay Kapoor + * @bug No known bugs except for NYI items + * + * To packagers: this is used by NPU Engine (NE). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DEV_BASE_PATH "/dev" +#define DEV_NAME "srnpu" +#define MAX_NUM_DEVICE 1 + + +/** private object corresponding to each npu opened */ +typedef struct _npu_dev_priv +{ + int internal_fd; /** the actual fd for the opened device */ + npu_input_opmode mode; /** operating for the npu */ + + /** npu copnfigration variables */ + uint64_t program_offset_addr; + uint64_t program_size; + uint64_t weight_offset_addr; + uint64_t activation_offset_addr0; + uint64_t activation_offset_addr1; + + /** Base physical address for the memory */ + int dmabuf_fd; + int offset0; + int offset1; +} npu_dev_priv; + + +/** npu api private struct */ +typedef struct +{ + npu_dev_priv * npu_fd_table[MAX_NUM_DEVICE]; /** struct of opened devices */ + pthread_mutex_t mutex; /** mutex for multiple devices */ +} npu_api_priv; + + +/** + * global values maintain all the opened npus + * currently only 1 NPU is supported + * extened npu_fd_table to a table to support multiple devices + */ +static npu_api_priv napi_priv; + +/** constructor/destructor for npu api */ +void init_npu_api(void) __attribute__ ((constructor)); +void fini_npu_api(void) __attribute__ ((destructor)); + +/** + * @brief find the object for the given fd + * @param[in] fd file descriptor for the device + * @return npu_dev_priv object on success, NULL on error + */ +static npu_dev_priv* fd_to_obj (int fd) +{ + return napi_priv.npu_fd_table[fd]; +} + + +/** + * @brief add an entry to the fd table + * @param[in] fd abstracted file descriptor for the device + * @param[in] internal_fd actual non-abstracted file descriptor for the device + * + * @note actual file descriptor is referred as internal_fd, and abstracted + * fd is referred directly as fd + */ +static int fd_table_add_new_entry (int fd, int internal_fd) +{ + if (fd >= MAX_NUM_DEVICE) { + return -ENOMEM; + } + + pthread_mutex_lock(&napi_priv.mutex); + /** cannot open the same device twice */ + if (napi_priv.npu_fd_table[fd] != NULL) { + pthread_mutex_unlock(&napi_priv.mutex); + return -EBUSY; + } + + napi_priv.npu_fd_table[fd] = (npu_dev_priv *) malloc (sizeof (npu_dev_priv)); + napi_priv.npu_fd_table[fd]->internal_fd = internal_fd; + + pthread_mutex_unlock(&napi_priv.mutex); + return 0; +} + +/** + * @brief delete an entry from the fd table + * @param[in] fd file descriptor for the device + * return 0 on success, errno on failure + */ +static int fd_table_delete_entry (int fd) +{ + if (fd >= MAX_NUM_DEVICE) { + return -EMFILE; + } + + pthread_mutex_lock(&napi_priv.mutex); + if (napi_priv.npu_fd_table[fd] == NULL) { + pthread_mutex_unlock(&napi_priv.mutex); + return -EBADF; + } + + free (napi_priv.npu_fd_table[fd]); + napi_priv.npu_fd_table[fd] = NULL; + + pthread_mutex_unlock(&napi_priv.mutex); + + return 0; +} + +/** + * @brief verify that addresses are 32bits + * @param[in] value address/offset value provided + * @return 0 on success, errno on failure + */ +static int verify_size32 (uint64_t value) +{ + if (value >> 32 == 0x0) { + return 0; + } else { + return -ERANGE; + } +} + +/** + * @brief open the npu device + * @param[in] dev_id index of the device to be opened + * @return file descriptor is not error. otherwise errno + */ +int npu_open (unsigned int dev_id) +{ + int fd; + char name[64]; + int status; + errno = 0; + + snprintf(name, sizeof(name), "%s/%s%u", DEV_BASE_PATH, DEV_NAME, dev_id); + + fd = open(name, O_RDWR); + if (fd < 0) { + return -errno; + } + + status = fd_table_add_new_entry (dev_id, fd); + if (status < 0) { + close (fd); + return status; + } + + return dev_id; +} + + +/** + * @brief close the npu device + * @param[in] fd file descriptor of the device + * @returns 0 on success, errno on error + */ +int npu_close (int fd) +{ + npu_dev_priv * npu_dev_priv_t; + int status; + + npu_dev_priv_t = fd_to_obj (fd); + if (npu_dev_priv_t == NULL) + return -ENXIO; + + close (npu_dev_priv_t->internal_fd); + status = fd_table_delete_entry (fd); + if (status < 0) { + return status; + } + + return 0; +} + + +/** + * @brief set mode for the NPU to operate in + * @param[in] fd file descriptor of the device + * @param[in] mode mode of operation for the NPU + */ +void npu_set_mode (int fd, npu_input_opmode mode) +{ + npu_dev_priv * npu_dev_priv_t; + + npu_dev_priv_t = fd_to_obj (fd); + npu_dev_priv_t->mode = mode; +} + + +/** + * @brief run the npu based on the set configuration + * @param[in] fd file descriptor of the device + * @return 0 on success, errno on error + * @note this function will block the calling thread till output is complete + */ +int npu_setup_device (int fd) +{ + return 0; +} + + +/** + * @brief get the status of the device + * @param[in] fd file descriptor of the device + * @return NULL to error, else register values filled in struct + */ +struct srnpu_status_arg * npu_get_status (int fd) +{ + return NULL; +} + + +/** + * @brief set the program instruction offset dram address and size + * @param[in] fd file descriptor of the device + * @param[in] program_offset_addr offset address for the instructions (NPU_PROG_BASE) + * @param[in] program_size size of the program instructions (NPU_PROG_SIZE) + * @return 0 on success, errno on error + */ +int npu_set_program (int fd, uint64_t program_offset_addr, + uint64_t program_size) +{ + npu_dev_priv * npu_dev_priv_t; + + npu_dev_priv_t = fd_to_obj (fd); + if (npu_dev_priv_t == NULL) + return -ENXIO; + + if (verify_size32(program_offset_addr) != 0 || + verify_size32(program_size) != 0) { + return -ERANGE; + } + + npu_dev_priv_t->program_offset_addr = program_offset_addr; + npu_dev_priv_t->program_size = program_size; + return 0; +} + + +/** + * @brief set the offset dram address for the model parameters + * @param[in] fd file descriptor of the device + * @param[in] weight_offset_addr offset address for storing weights (NPU_WGT_BASE) + * @return 0 on success, errno on error + */ +int npu_set_weight (int fd, uint64_t weight_offset_addr) +{ + npu_dev_priv * npu_dev_priv_t; + + npu_dev_priv_t = fd_to_obj (fd); + if (npu_dev_priv_t == NULL) + return -ENXIO; + + if (verify_size32(weight_offset_addr) != 0) { + return -ERANGE; + } + + npu_dev_priv_t->weight_offset_addr = weight_offset_addr; + return 0; +} + + +/** + * @brief set the offset dram address for the activation/input + * @param[in] fd file descriptor of the device + * @param[in] activation_offset_addr0 offset address for storing weights (NPU_ACT_BASE0) + * @param[in] activation_offset_addr1 offset address for storing weights (NPU_ACT_BASE1) + * @return 0 on success, -1 on error + * + * @note The addr value act as offset from the base physical address + */ +int npu_set_activation (int fd, uint64_t activation_offset_addr0, + uint64_t activation_offset_addr1) +{ + npu_dev_priv * npu_dev_priv_t; + + npu_dev_priv_t = fd_to_obj (fd); + if (npu_dev_priv_t == NULL) + return -ENXIO; + + if (verify_size32(activation_offset_addr0) != 0 || + verify_size32(activation_offset_addr1) != 0) { + return -ERANGE; + } + + npu_dev_priv_t->activation_offset_addr0 = activation_offset_addr0; + npu_dev_priv_t->activation_offset_addr1 = activation_offset_addr1; + return 0; +} + + +/** + * @brief set the base dram address + * @param[in] fd file descriptor of the device + * @param[in] dmabuf_fd to extract the base physical address + * @param[in] offset1 to get start of first memory region + * @param[in] offset2 to get start of second memory region + * @return 0 on success, errno on error + */ +int npu_set_buffer (int fd, int dmabuf_fd, uint64_t offset0, uint64_t offset1) +{ + npu_dev_priv * npu_dev_priv_t; + struct srnpu_buffer_arg npu_buffer_t; + int ret; + + npu_dev_priv_t = fd_to_obj (fd); + if (npu_dev_priv_t == NULL) + return -ENXIO; + + if (verify_size32(offset0) != 0 || verify_size32(offset1) != 0) { + return -ERANGE; + } + + /** for now, these two will be same */ + npu_dev_priv_t->dmabuf_fd = dmabuf_fd; + npu_dev_priv_t->offset0 = offset0; + npu_dev_priv_t->offset1 = offset1; + + /** TODO: send the dmabuf fd */ + + return 0; +} + + +/** + * @brief check if the device to get ready for the next computation + * @param[in] fd file descriptor of the device + * @return 0 if ready, errno if not ready or error + */ +int npu_check_compute_ready (int fd) +{ + return 0; +} + + +/** + * @brief check if the device to get ready for the next computation + * @param[in] fd file descriptor of the device + * @return 0 if ready, errno on error + * @note this function will block till npu is ready + */ +int npu_wait_compute_ready (int fd) +{ + return 0; +} + +void init_npu_api(void) +{ + int i; + + pthread_mutex_init(&napi_priv.mutex, NULL); + for (i=0; i