[MEM/IP] Support dma-buf sharing for I/O buffers
authorDongju Chae <dongju.chae@samsung.com>
Mon, 16 Sep 2019 09:42:09 +0000 (18:42 +0900)
committer함명주/On-Device Lab(SR)/Principal Engineer/삼성전자 <myungjoo.ham@samsung.com>
Tue, 17 Sep 2019 07:28:50 +0000 (16:28 +0900)
This commit enables dma-buf shring for I/O buffers.
New APIs, buffer_get_dmabuf and bufferget_dmabuf, are added.
It also changes some codes in IP plugin to use these APIs.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
include/host/libnpuhost.h
src/core/ip/plugin-comm-ip.c
src/core/ne-mem.c
src/core/ne-mem.h

index 41e2d1d..d632013 100644 (file)
@@ -156,17 +156,6 @@ int unregisterNPUmodel(npudev_h dev, uint32_t modelid);
 int unregisterNPUmodel_all(npudev_h dev);
 
 /**
- * @brief Set the buffer type for input and output buffers
- * @param[in] dev The NPU device handle
- * @param[in] buffer_type Type of the generic_buffer
- * @return @c 0 if no error. otherwise a negative error value
- *
- * @note for output, async will result in output of type BUFFER_CONT.
- */
-int setInoutBufferType(npudev_h dev, buffer_types buffer_type)
-  __attribute__ ((deprecated));
-
-/**
  * @brief Execute inference. Wait (block) until the output is available.
  * @param[in] dev The NPU device handle
  * @param[in] modelid The model to be inferred.
index 32e69d8..d8d3f35 100644 (file)
@@ -262,28 +262,6 @@ int getNPUdeviceByCondition(npudev_h *dev, const npucondition *cond)
 }
 
 /**
- * @brief wrap the mmap function
- * @param[in] prot protection of the mapping
- * @param[in] buf generic buf to be mapped
- * @param[out] mapped_ptr ptr of the mapped memory
- * @return @c 0 if no error. otherwise a negative error value
- */
-static int mmap_wrapper (int prot, const generic_buffer *buf, void **mapped_ptr)
-{
-  if (buf->type != BUFFER_DMABUF)
-    return -EINVAL;
-
-  *mapped_ptr = mmap (NULL, buf->size + buf->offset, prot, MAP_SHARED, buf->fd, 0);
-  if (*mapped_ptr == MAP_FAILED) {
-    logerr (TAG, "Mmap failed\n");
-    return -errno;
-  }
-  *mapped_ptr = (void *)((char *)*mapped_ptr + buf->offset);
-
-  return 0;
-}
-
-/**
  * @brief setup input buffer based on its type
  * @param[in] npu_dev npu device private data struct
  * @param[in] model The generic buffer for model/input
@@ -312,15 +290,6 @@ static int setup_hwmem (npu_device *npu_dev, const generic_buffer *in_buf, hwmem
       goto out;
     }
     memcpy (data_ptr, in_buf->buf, in_buf->size);
-  } else if (in_buf->type == BUFFER_DMABUF) {
-    void *mapped_ptr;
-
-    if ((err = mmap_wrapper (PROT_READ, in_buf, &mapped_ptr)) < 0)
-      goto out;
-
-    memcpy (data_ptr, mapped_ptr, in_buf->size);
-
-    err = munmap(mapped_ptr - in_buf->offset, in_buf->size + in_buf->offset);
   } else if (in_buf->type == BUFFER_FILE) {
     FILE *fp;
     size_t read_size;
@@ -347,8 +316,11 @@ static int setup_hwmem (npu_device *npu_dev, const generic_buffer *in_buf, hwmem
     }
 
     fclose (fp);
+  } else if (in_buf->type == BUFFER_DMABUF) {
+    logerr (TAG, "BUFFER_DMABUF should be not handled here\n");
+    err = -EINVAL;
   } else {
-    logerr (TAG, "Unknown output buffer type: %d\n", in_buf->type);
+    logerr (TAG, "Unknown input buffer type: %d\n", in_buf->type);
     err = -EINVAL;
   }
 
@@ -596,17 +568,9 @@ static int setup_output_buffer (const void *data_ptr, uint64_t size,
     }
     memcpy (out_buf->buf, data_ptr, size);
   } else if (out_buf->type == BUFFER_DMABUF) {
-    void *mapped_ptr = NULL;
-
-    if ((err = mmap_wrapper (PROT_WRITE, out_buf, &mapped_ptr)) < 0)
-      return err;
-
-    memcpy (mapped_ptr, data_ptr, size);
-
-    if (munmap (mapped_ptr - out_buf->offset, size + out_buf->offset) == -1) {
-      logerr (TAG, "Munmap failed\n");
-      return -errno;
-    }
+    /** nothing to do because buffers were already stored in user-provided memory */
+    logerr (TAG, "Invalid request for setting output buffer\n");
+    return -EINVAL;
   } else if (out_buf->type == BUFFER_FILE) {
     FILE *fp;
     size_t write_size;
@@ -698,9 +662,13 @@ static void npu_callback (buffer *buffer_ptr, uint64_t offset, uint64_t size,
     }
 
     output_buf->size = size;
-    output_buf->type = BUFFER_MAPPED;
     output_buf->buf = (void *)((char *) data_ptr + offset);
 
+    if (buffer_get_dmabuf (buffer_ptr) > 0)
+      output_buf->type = BUFFER_DMABUF;
+    else
+      output_buf->type = BUFFER_MAPPED;
+
     /**
      * When this callback finishes, output_buf will be freed along with the data
      * buffer inside it. The caller must create a copy of the buffer if needed.
@@ -814,11 +782,6 @@ static int runNPU_async_util(npudev_h dev, uint32_t modelid, const input_buffers
     goto out;
   }
 
-  if ((err = buffer_get_hwmem (buffer_ptr, &hwmem_ptr)) < 0) {
-    logerr (TAG, "Error getting hwmem from buffer, errno: %d\n", err);
-    goto out;
-  }
-
   DEVICE_LOCK();
 
   if ((err = activateNPUmodel (dev, modelid, cb, data)) < 0) {
@@ -828,8 +791,26 @@ static int runNPU_async_util(npudev_h dev, uint32_t modelid, const input_buffers
   /** TODO: handle more than 1 input buffer at once */
   in_buf = &input->bufs[0];
 
-  if ((err = setup_hwmem (npu_dev, in_buf, hwmem_ptr)) < 0) {
-    goto out_unlock;
+  if (in_buf->type != BUFFER_DMABUF) {
+    if ((err = buffer_set_dmabuf (buffer_ptr, 0)) < 0) {
+      logerr (TAG, "Error disabling dmabuf sharing\n");
+      goto out_unlock;
+    }
+
+    if ((err = buffer_get_hwmem (buffer_ptr, &hwmem_ptr)) < 0) {
+      logerr (TAG, "Error getting hwmem from buffer, errno: %d\n", err);
+      goto out_unlock;
+    }
+
+    if ((err = setup_hwmem (npu_dev, in_buf, hwmem_ptr)) < 0) {
+      logerr (TAG, "Fail to setup hwmem for input buffer\n");
+      goto out_unlock;
+    }
+  } else {
+    if ((err = buffer_set_dmabuf (buffer_ptr, in_buf->fd)) < 0) {
+      logerr (TAG, "Error setting dmabuf sharing\n");
+      goto out_unlock;
+    }
   }
 
   buffer_ptr->sequence = npu_dev->sequence_in + 1;
@@ -970,26 +951,3 @@ int runNPU_async(npudev_h dev, uint32_t modelid, const input_buffers *input,
 
   return 0;
 }
-
-/** DEPRECATED */
-
-/**
- * @brief Set the buffer type for input and output buffers
- * @param[in] dev The NPU device handle
- * @param[in] buffer_type Type of the generic_buffer
- * @return @c 0 if no error. otherwise a negative error value
- */
-int setInoutBufferType(npudev_h dev, buffer_types buffer_type)
-{
-  npu_device *npu_dev = dev;
-
-  if (npu_dev == NULL || buffer_type >= BUFFER_UNDEFINED) {
-    return -EINVAL;
-  }
-
-  if (npu_dev != libnpupriv.npu_dev) {
-    return -EINVAL;
-  }
-
-  return 0;
-}
index 08fb4ce..2c36ce0 100644 (file)
@@ -1788,6 +1788,112 @@ hwmem_deactivate (hwmem *hwmem)
 }
 
 /**
+ * @brief enable the dma-buf sharing for this buffer
+ * @param[in] buffer the buffer instance
+ * @param[in] dmabuf_fd dmabuf file descriptor
+ * @return 0 if no error, otherwise a negative error value
+ * @note This should be called after its hwmem is activated (i.e., getNextBuffer())
+ *       Also, if dmabuf_fd is zero, it disables the dma-buf sharing.
+ */
+int
+buffer_set_dmabuf (buffer *buffer, int dmabuf_fd)
+{
+  buffer_priv *bpriv;
+
+  hwmem *old_hwmem, *new_hwmem;
+  hwmem_priv *old_hpriv, *new_hpriv;
+
+  mem_size_t size;
+
+  if (!buffer || dmabuf_fd < 0) {
+    logerr (MEM_TAG, "invalid arguments\n");
+    return -EINVAL;
+  }
+
+  bpriv = TO_BUFFER_PRIVATE (buffer);
+  assert (bpriv);
+
+  old_hwmem = bpriv->hwmem;
+  assert (old_hwmem);
+
+  old_hpriv = TO_HWMEM_PRIVATE (old_hwmem);
+  assert (old_hpriv);
+
+  size = old_hwmem->size;
+
+  /* switch hwmem type */
+  if (dmabuf_fd > 0) {
+    /* its type is already HWMEM_TYPE_USER. let's replace dmabuf */
+    if (old_hpriv->type == HWMEM_TYPE_USER) {
+      hwmem_deactivate (old_hwmem);
+
+      old_hpriv->user.fd = dmabuf_fd;
+      old_hpriv->user.addr = NULL;
+
+      hwmem_activate (old_hwmem);
+      return 0;
+    }
+
+    new_hwmem = hwmem_alloc (size, HWMEM_TYPE_USER);
+    if (!new_hwmem)
+      return -ENOMEM;
+
+    new_hpriv = TO_HWMEM_PRIVATE (new_hwmem);
+    new_hpriv->user.fd = dmabuf_fd;
+    new_hpriv->user.addr = NULL;
+  } else { /* dmabuf_fd == 0 */
+    /* its type is not HWMEM_TYPE_USER. nothing to do */
+    if (old_hpriv->type != HWMEM_TYPE_USER)
+      return 0;
+
+    new_hwmem = hwmem_alloc (size, HWMEM_TYPE_BUFFER);
+    if (!new_hwmem)
+      return -ENOMEM;
+  }
+
+  /* replace hwmem */
+  hwmem_deactivate (old_hwmem);
+  hwmem_free (old_hwmem);
+
+  hwmem_activate (new_hwmem);
+  bpriv->hwmem = new_hwmem;
+
+  return 0;
+}
+
+/**
+ * @brief get the dmabuf fd for this buffer
+ * @param[in] buffer the buffer instance
+ * @return dmabuf fd if it's used for user mem. otherwise, zero is returned
+ */
+int
+buffer_get_dmabuf (buffer *buffer)
+{
+  buffer_priv *bpriv;
+  hwmem_priv *hpriv;
+  hwmem *hwmem;
+
+  if (!buffer) {
+    logerr (MEM_TAG, "invalid arguments\n");
+    return -EINVAL;
+  }
+
+  bpriv = TO_BUFFER_PRIVATE (buffer);
+  assert (bpriv);
+
+  hwmem = bpriv->hwmem;
+  assert (hwmem);
+
+  hpriv = TO_HWMEM_PRIVATE (hwmem);
+  assert (hpriv);
+
+  if (hpriv->type == HWMEM_TYPE_USER)
+    return hpriv->user.fd;
+  else
+    return 0;
+}
+
+/**
  * @brief get the hwmem associated with this buffer
  * @param[in] buffer the buffer instance
  * @param[out] hwmem the hwmem instance
index e1383d9..62d1965 100644 (file)
@@ -115,6 +115,23 @@ typedef struct {
 } buffer;
 
 /**
+ * @brief enable the dma-buf sharing for this buffer
+ * @param[in] buffer the buffer instance
+ * @param[in] dmabuf_fd dmabuf file descriptor
+ * @return 0 if no error, otherwise a negative error value
+ * @note This should be called after its hwmem is activated (i.e., getNextBuffer())
+ *       Also, if dmabuf_fd is zero, it disables the dma-buf sharing.
+ */
+int buffer_set_dmabuf (buffer *buffer, int dmabuf_fd);
+
+/**
+ * @brief get the dmabuf fd for this buffer
+ * @param[in] buffer the buffer instance
+ * @return dmabuf fd if it's used for user mem. otherwise, zero is returned
+ */
+int buffer_get_dmabuf (buffer *buffer);
+
+/**
  * @brief get the hwmem associated with this buffer
  * @param[in] buffer the buffer instance
  * @param[out] hwmem the hwmem instance