[VD/NPUMGR] Implement buffer-related APIs
authorDongju Chae <dongju.chae@samsung.com>
Tue, 25 May 2021 04:06:23 +0000 (13:06 +0900)
committer채동주/On-Device Lab(SR)/Staff Engineer/삼성전자 <dongju.chae@samsung.com>
Tue, 25 May 2021 09:43:47 +0000 (18:43 +0900)
This patch implement buffer-related APIs and its backend modules.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
src/core/ne-mem.cc
tests/apptests/npumgr/npumgr.cc
tests/apptests/npumgr/npumgr_api.cc
tests/apptests/npumgr/npumgr_api.h
tests/apptests/npumgr/npumgr_common.h [new file with mode: 0644]
tests/apptests/npumgr/npumgr_triv2.cc

index 8a6f679..d8a106a 100644 (file)
@@ -28,11 +28,11 @@ class MemDefault : public MemAllocator {
 
   /** For library users. its backing storage is always a device driver */
   int allocMemory (size_t size, void **addr) {
-    int dmabuf = api_->alloc (size);
+    int dmabuf = api_->alloc (ALIGNED_SIZE (size));
     if (dmabuf < 0)
       return dmabuf;
 
-    *addr = api_->mmap (dmabuf, size);
+    *addr = api_->mmap (dmabuf, ALIGNED_SIZE (size));
     if (*addr == nullptr) {
       api_->dealloc (dmabuf);
       return -EINVAL;
@@ -42,7 +42,7 @@ class MemDefault : public MemAllocator {
   }
 
   int deallocMemory (int dmabuf_fd, size_t size, void *addr) {
-    int status = api_->munmap (addr, size);
+    int status = api_->munmap (addr, ALIGNED_SIZE (size));
     if (status != 0)
       return status;
 
index 8f9f540..34c8d27 100644 (file)
@@ -84,10 +84,40 @@ static const gchar introspection_xml[] =
     "       <arg type='v' name='out_tensor_names' direction='in'/>"
     "       <arg type='t' name='nw_handle' direction='out'/>"
     "     </method>"
+    "     <method name='NetworkSetInput'>"
+    "       <arg type='t' name='ctx_handle' direction='in'/>"
+    "       <arg type='t' name='nw_handle' direction='in'/>"
+    "       <arg type='i' name='index' direction='in'/>"
+    "       <arg type='v' name='buffer' direction='in'/>"
+    "     </method>"
+    "     <method name='NetworkSetOutput'>"
+    "       <arg type='t' name='ctx_handle' direction='in'/>"
+    "       <arg type='t' name='nw_handle' direction='in'/>"
+    "       <arg type='i' name='index' direction='in'/>"
+    "       <arg type='v' name='buffer' direction='in'/>"
+    "     </method>"
+    "     <method name='NetworkPrepare'>"
+    "       <arg type='t' name='ctx_handle' direction='in'/>"
+    "       <arg type='t' name='nw_handle' direction='in'/>"
+    "     </method>"
     "     <method name='NetworkDestroy'>"
     "       <arg type='t' name='ctx_handle' direction='in'/>"
     "       <arg type='t' name='nw_handle' direction='in'/>"
     "     </method>"
+    "     <method name='BufferCreate'>"
+    "       <arg type='t' name='ctx_handle' direction='in'/>"
+    "       <arg type='v' name='param' direction='in'/>"
+    "       <arg type='v' name='buffer' direction='out'/>"
+    "     </method>"
+    "     <method name='BufferMap'>"
+    "       <arg type='t' name='ctx_handle' direction='in'/>"
+    "       <arg type='v' name='buffer' direction='in'/>"
+    "       <arg type='v' name='buffer' direction='out'/>"
+    "     </method>"
+    "     <method name='BufferDestroy'>"
+    "       <arg type='t' name='ctx_handle' direction='in'/>"
+    "       <arg type='v' name='buffer' direction='in'/>"
+    "     </method>"
     "     <method name='QueryNetwork'>"
     "       <arg type='t' name='ctx_handle' direction='in'/>"
     "       <arg type='t' name='nw_handle' direction='in'/>"
@@ -350,6 +380,128 @@ handle_method_call (GDBusConnection *connection, const gchar *sender,
                                              G_DBUS_ERROR_INVALID_ARGS,
                                              "Invalid arguments detected");
     }
+  } else if (g_strcmp0 (method_name, "NetworkSetInput") == 0) {
+    npumgr_context ctx_handle = 0;
+    npumgr_network nw_handle = 0;
+    GVariant *variant = NULL;
+    int index = -1;
+
+    g_variant_get (parameters, "(ttiv)", (guint64 *) &ctx_handle,
+                   (guint64 *) &nw_handle, &index, &variant);
+    if (ctx_handle > 0 && nw_handle > 0 && index >= 0 && variant != NULL) {
+      NpumgrContext *context = find_context (ctx_handle);
+      if (context != NULL) {
+        NpumgrDevice *device = context->device;
+        npumgr_status_e status;
+        npumgr_buffer buffer;
+        GBytes *bytes;
+
+        bytes = g_variant_get_data_as_bytes (variant);
+        if (g_bytes_get_size (bytes) != sizeof (buffer)) {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_INVALID_ARGS,
+                                                 "Invalid arguments detected");
+          g_bytes_unref (bytes);
+          return;
+        }
+
+        memcpy (&buffer, g_bytes_get_data (bytes, NULL), sizeof (buffer));
+        g_bytes_unref (bytes);
+
+        status = NPUMGR_DEVICE_GET_CLASS (device)->network_set_input (
+            device, ctx_handle, nw_handle, index, &buffer);
+        if (status == NPUMGR_STATUS_SUCCESS)
+          g_dbus_method_invocation_return_value (invocation, NULL);
+        else
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_UNKNOWN_OBJECT,
+                                                 "Unable to set the input");
+      } else {
+        g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                               G_DBUS_ERROR_UNKNOWN_OBJECT,
+                                               "Unable to find the context");
+      }
+    } else {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid arguments detected");
+    }
+  } else if (g_strcmp0 (method_name, "NetworkSetOutput") == 0) {
+    npumgr_context ctx_handle = 0;
+    npumgr_network nw_handle = 0;
+    GVariant *variant = NULL;
+    int index = -1;
+
+    g_variant_get (parameters, "(ttiv)", (guint64 *) &ctx_handle,
+                   (guint64 *) &nw_handle, &index, &variant);
+    if (ctx_handle > 0 && nw_handle > 0 && index >= 0 && variant != NULL) {
+      NpumgrContext *context = find_context (ctx_handle);
+      if (context != NULL) {
+        NpumgrDevice *device = context->device;
+        npumgr_status_e status;
+        npumgr_buffer buffer;
+        GBytes *bytes;
+
+        bytes = g_variant_get_data_as_bytes (variant);
+        if (g_bytes_get_size (bytes) != sizeof (buffer)) {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_INVALID_ARGS,
+                                                 "Invalid arguments detected");
+          g_bytes_unref (bytes);
+          return;
+        }
+
+        memcpy (&buffer, g_bytes_get_data (bytes, NULL), sizeof (buffer));
+        g_bytes_unref (bytes);
+
+        status = NPUMGR_DEVICE_GET_CLASS (device)->network_set_output (
+            device, ctx_handle, nw_handle, index, &buffer);
+        if (status == NPUMGR_STATUS_SUCCESS)
+          g_dbus_method_invocation_return_value (invocation, NULL);
+        else
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_UNKNOWN_OBJECT,
+                                                 "Unable to set the output");
+      } else {
+        g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                               G_DBUS_ERROR_UNKNOWN_OBJECT,
+                                               "Unable to find the context");
+      }
+    } else {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid arguments detected");
+    }
+  } else if (g_strcmp0 (method_name, "NetworkPrepare") == 0) {
+    npumgr_context ctx_handle = 0;
+    npumgr_network nw_handle = 0;
+
+    g_variant_get (parameters, "(tt)", (guint64 *) &ctx_handle,
+                   (guint64 *) &nw_handle);
+    if (ctx_handle > 0 && nw_handle > 0) {
+      NpumgrContext *context = find_context (ctx_handle);
+      if (context != NULL) {
+        NpumgrDevice *device = context->device;
+        npumgr_status_e status;
+
+        status = NPUMGR_DEVICE_GET_CLASS (device)->network_prepare (
+            device, ctx_handle, nw_handle);
+        if (status == NPUMGR_STATUS_SUCCESS)
+          g_dbus_method_invocation_return_value (invocation, NULL);
+        else
+          g_dbus_method_invocation_return_error (
+              invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_OBJECT,
+              "Unable to prepare network execution");
+      } else {
+        g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                               G_DBUS_ERROR_UNKNOWN_OBJECT,
+                                               "Unable to find the context");
+      }
+    } else {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid arguments detected");
+    }
   } else if (g_strcmp0 (method_name, "NetworkDestroy") == 0) {
     npumgr_context ctx_handle = 0;
     npumgr_network nw_handle = 0;
@@ -489,6 +641,151 @@ handle_method_call (GDBusConnection *connection, const gchar *sender,
                                              G_DBUS_ERROR_INVALID_ARGS,
                                              "Invalid arguments detected");
     }
+  } else if (g_strcmp0 (method_name, "BufferCreate") == 0) {
+    npumgr_context ctx_handle = 0;
+    GVariant *variant = NULL;
+
+    g_variant_get (parameters, "(tv)", (guint64 *) &ctx_handle, &variant);
+    if (ctx_handle > 0 && variant != NULL) {
+      NpumgrContext *context = find_context (ctx_handle);
+      if (context != NULL) {
+        NpumgrDevice *device = context->device;
+        npumgr_query_tensor_attr param;
+        npumgr_buffer buf;
+        npumgr_status_e status;
+
+        GBytes *bytes = g_variant_get_data_as_bytes (variant);
+        if (g_bytes_get_size (bytes) != sizeof (param)) {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_INVALID_ARGS,
+                                                 "Invalid arguments detected");
+          g_bytes_unref (bytes);
+          return;
+        }
+
+        memcpy (&param, g_bytes_get_data (bytes, NULL), sizeof (param));
+        g_bytes_unref (bytes);
+
+        status = NPUMGR_DEVICE_GET_CLASS (device)->buffer_create (
+            device, ctx_handle, &param, &buf);
+        if (status == NPUMGR_STATUS_SUCCESS) {
+          bytes = g_bytes_new (&buf, sizeof (buf));
+          variant =
+              g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"), bytes, TRUE);
+          g_dbus_method_invocation_return_value (
+              invocation, g_variant_new ("(v)", variant));
+          g_bytes_unref (bytes);
+        } else {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_FAILED,
+                                                 "Unable to create buffer");
+        }
+      } else {
+        g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                               G_DBUS_ERROR_UNKNOWN_OBJECT,
+                                               "Unable to find the context");
+      }
+    } else {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid arguments detected");
+    }
+  } else if (g_strcmp0 (method_name, "BufferMap") == 0) {
+    npumgr_context ctx_handle = 0;
+    GVariant *variant = NULL;
+
+    g_variant_get (parameters, "(tv)", (guint64 *) &ctx_handle, &variant);
+    if (ctx_handle > 0 && variant != NULL) {
+      NpumgrContext *context = find_context (ctx_handle);
+      if (context != NULL) {
+        NpumgrDevice *device = context->device;
+        npumgr_buffer buf;
+        uint8_t *addr;
+        npumgr_status_e status;
+
+        GBytes *bytes = g_variant_get_data_as_bytes (variant);
+        if (g_bytes_get_size (bytes) != sizeof (buf)) {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_INVALID_ARGS,
+                                                 "Invalid arguments detected");
+          g_bytes_unref (bytes);
+          return;
+        }
+
+        memcpy (&buf, g_bytes_get_data (bytes, NULL), sizeof (buf));
+        g_bytes_unref (bytes);
+
+        /* TODO: how to deliver this addr to client? */
+        status = NPUMGR_DEVICE_GET_CLASS (device)->buffer_map (
+            device, ctx_handle, &buf, &addr);
+        if (status == NPUMGR_STATUS_SUCCESS) {
+          GUnixFDList *fd_list = g_unix_fd_list_new ();
+          g_unix_fd_list_append (fd_list, buf.buf_fd, NULL);
+
+          bytes = g_bytes_new (&buf, sizeof (buf));
+          variant =
+              g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"), bytes, TRUE);
+          g_dbus_method_invocation_return_value_with_unix_fd_list (
+              invocation, g_variant_new ("(v)", variant), fd_list);
+          g_bytes_unref (bytes);
+        } else {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_FAILED,
+                                                 "Unable to map buffer");
+        }
+      } else {
+        g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                               G_DBUS_ERROR_UNKNOWN_OBJECT,
+                                               "Unable to find the context");
+      }
+    } else {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid arguments detected");
+    }
+  } else if (g_strcmp0 (method_name, "BufferDestroy") == 0) {
+    npumgr_context ctx_handle = 0;
+    GVariant *variant = NULL;
+
+    g_variant_get (parameters, "(tv)", (guint64 *) &ctx_handle, &variant);
+    if (ctx_handle > 0 && variant != NULL) {
+      NpumgrContext *context = find_context (ctx_handle);
+      if (context != NULL) {
+        NpumgrDevice *device = context->device;
+        npumgr_buffer buf;
+        npumgr_status_e status;
+
+        GBytes *bytes = g_variant_get_data_as_bytes (variant);
+        if (g_bytes_get_size (bytes) != sizeof (buf)) {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_INVALID_ARGS,
+                                                 "Invalid arguments detected");
+          g_bytes_unref (bytes);
+          return;
+        }
+
+        memcpy (&buf, g_bytes_get_data (bytes, NULL), sizeof (buf));
+        g_bytes_unref (bytes);
+
+        status = NPUMGR_DEVICE_GET_CLASS (device)->buffer_destroy (
+            device, ctx_handle, &buf);
+        if (status == NPUMGR_STATUS_SUCCESS) {
+          g_dbus_method_invocation_return_value (invocation, NULL);
+        } else {
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                                 G_DBUS_ERROR_FAILED,
+                                                 "Unable to destroy buffer");
+        }
+      } else {
+        g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                               G_DBUS_ERROR_UNKNOWN_OBJECT,
+                                               "Unable to find the context");
+      }
+    } else {
+      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
+                                             G_DBUS_ERROR_INVALID_ARGS,
+                                             "Invalid arguments detected");
+    }
   }
 }
 
index 686916f..55d36dc 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include "npumgr_api.h"
+#include "npumgr_common.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -306,8 +307,47 @@ npumgr_network_set_attribute (npumgr_context ctx, npumgr_network nw_handle,
 npumgr_status_e
 npumgr_network_set_input (npumgr_context ctx, npumgr_network nw_handle,
                           int index, npumgr_buffer *input_buffer) {
-  /* NYI */
-  return NPUMGR_STATUS_SUCCESS;
+  GDBusMessage *method_call;
+  GDBusMessage *method_reply;
+  npumgr_status_e status = NPUMGR_STATUS_SUCCESS;
+  GBytes *bytes;
+  GVariant *variant;
+  GError *error = NULL;
+
+  g_return_val_if_fail (wait_until_connected (), NPUMGR_STATUS_ERR_TIMEOUT);
+
+  method_call = g_dbus_message_new_method_call (
+      _name_owner, "/sr/odl/NPUManager/APIObject", "sr.odl.NPUManager.API",
+      "NetworkSetInput");
+
+  bytes = g_bytes_new (input_buffer, sizeof (*input_buffer));
+  variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"), bytes, TRUE);
+  g_dbus_message_set_body (
+      method_call, g_variant_new ("(ttiv)", ctx, nw_handle, index, variant));
+
+  method_reply = g_dbus_connection_send_message_with_reply_sync (
+      _connection, method_call, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL,
+      &error);
+
+  if (method_reply == NULL) {
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+  if (g_dbus_message_get_message_type (method_reply) ==
+      G_DBUS_MESSAGE_TYPE_ERROR) {
+    g_dbus_message_to_gerror (method_reply, &error);
+    g_critical ("error: %s\n", error->message);
+    g_error_free (error);
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+out:
+  g_object_unref (method_call);
+  g_object_unref (method_reply);
+
+  return status;
 }
 
 /**
@@ -316,8 +356,47 @@ npumgr_network_set_input (npumgr_context ctx, npumgr_network nw_handle,
 npumgr_status_e
 npumgr_network_set_output (npumgr_context ctx, npumgr_network nw_handle,
                            int index, npumgr_buffer *output_buffer) {
-  /* NYI */
-  return NPUMGR_STATUS_SUCCESS;
+  GDBusMessage *method_call;
+  GDBusMessage *method_reply;
+  npumgr_status_e status = NPUMGR_STATUS_SUCCESS;
+  GBytes *bytes;
+  GVariant *variant;
+  GError *error = NULL;
+
+  g_return_val_if_fail (wait_until_connected (), NPUMGR_STATUS_ERR_TIMEOUT);
+
+  method_call = g_dbus_message_new_method_call (
+      _name_owner, "/sr/odl/NPUManager/APIObject", "sr.odl.NPUManager.API",
+      "NetworkSetOutput");
+
+  bytes = g_bytes_new (output_buffer, sizeof (*output_buffer));
+  variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"), bytes, TRUE);
+  g_dbus_message_set_body (
+      method_call, g_variant_new ("(ttiv)", ctx, nw_handle, index, variant));
+
+  method_reply = g_dbus_connection_send_message_with_reply_sync (
+      _connection, method_call, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL,
+      &error);
+
+  if (method_reply == NULL) {
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+  if (g_dbus_message_get_message_type (method_reply) ==
+      G_DBUS_MESSAGE_TYPE_ERROR) {
+    g_dbus_message_to_gerror (method_reply, &error);
+    g_critical ("error: %s\n", error->message);
+    g_error_free (error);
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+out:
+  g_object_unref (method_call);
+  g_object_unref (method_reply);
+
+  return status;
 }
 
 /**
@@ -325,8 +404,41 @@ npumgr_network_set_output (npumgr_context ctx, npumgr_network nw_handle,
  */
 npumgr_status_e
 npumgr_network_prepare (npumgr_context ctx, npumgr_network nw_handle) {
-  /* NYI */
-  return NPUMGR_STATUS_SUCCESS;
+  GDBusMessage *method_call;
+  GDBusMessage *method_reply;
+  npumgr_status_e status = NPUMGR_STATUS_SUCCESS;
+  GError *error = NULL;
+
+  g_return_val_if_fail (wait_until_connected (), NPUMGR_STATUS_ERR_TIMEOUT);
+
+  method_call = g_dbus_message_new_method_call (
+      _name_owner, "/sr/odl/NPUManager/APIObject", "sr.odl.NPUManager.API",
+      "NetworkPrepare");
+  g_dbus_message_set_body (method_call, g_variant_new ("(tt)", ctx, nw_handle));
+
+  method_reply = g_dbus_connection_send_message_with_reply_sync (
+      _connection, method_call, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL,
+      &error);
+
+  if (method_reply == NULL) {
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+  if (g_dbus_message_get_message_type (method_reply) ==
+      G_DBUS_MESSAGE_TYPE_ERROR) {
+    g_dbus_message_to_gerror (method_reply, &error);
+    g_critical ("error: %s\n", error->message);
+    g_error_free (error);
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+out:
+  g_object_unref (method_call);
+  g_object_unref (method_reply);
+
+  return status;
 }
 
 /**
@@ -378,8 +490,61 @@ npumgr_status_e
 npumgr_buffer_create (npumgr_context ctx,
                       npumgr_query_tensor_attr *create_param,
                       npumgr_buffer *buf) {
-  /* NYI */
-  return NPUMGR_STATUS_SUCCESS;
+  GDBusMessage *method_call;
+  GDBusMessage *method_reply;
+  npumgr_status_e status = NPUMGR_STATUS_SUCCESS;
+  GError *error = NULL;
+  GVariant *variant;
+  GBytes *bytes;
+
+  g_return_val_if_fail (wait_until_connected (), NPUMGR_STATUS_ERR_TIMEOUT);
+
+  method_call = g_dbus_message_new_method_call (
+      _name_owner, "/sr/odl/NPUManager/APIObject", "sr.odl.NPUManager.API",
+      "BufferCreate");
+
+  bytes = g_bytes_new (create_param, sizeof (*create_param));
+  variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"), bytes, TRUE);
+  g_dbus_message_set_body (method_call, g_variant_new ("(tv)", ctx, variant));
+
+  method_reply = g_dbus_connection_send_message_with_reply_sync (
+      _connection, method_call, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL,
+      &error);
+
+  g_bytes_unref (bytes);
+
+  if (method_reply == NULL) {
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+  if (g_dbus_message_get_message_type (method_reply) ==
+      G_DBUS_MESSAGE_TYPE_ERROR) {
+    g_dbus_message_to_gerror (method_reply, &error);
+    g_critical ("error: %s\n", error->message);
+    g_error_free (error);
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+  g_variant_get (g_dbus_message_get_body (method_reply), "(v)", &variant);
+  bytes = g_variant_get_data_as_bytes (variant);
+
+  if (g_bytes_get_size (bytes) != sizeof (*buf)) {
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out_unref;
+  }
+
+  memcpy (buf, g_bytes_get_data (bytes, NULL), sizeof (*buf));
+
+out_unref:
+  g_bytes_unref (bytes);
+
+out:
+  g_object_unref (method_call);
+  g_object_unref (method_reply);
+
+  return status;
 }
 
 /**
@@ -387,8 +552,48 @@ npumgr_buffer_create (npumgr_context ctx,
  */
 npumgr_status_e
 npumgr_buffer_destroy (npumgr_context ctx, npumgr_buffer *buf) {
-  /* NYI */
-  return NPUMGR_STATUS_SUCCESS;
+  GDBusMessage *method_call;
+  GDBusMessage *method_reply;
+  npumgr_status_e status = NPUMGR_STATUS_SUCCESS;
+  GError *error = NULL;
+  GVariant *variant;
+  GBytes *bytes;
+
+  g_return_val_if_fail (wait_until_connected (), NPUMGR_STATUS_ERR_TIMEOUT);
+
+  method_call = g_dbus_message_new_method_call (
+      _name_owner, "/sr/odl/NPUManager/APIObject", "sr.odl.NPUManager.API",
+      "BufferDestroy");
+
+  bytes = g_bytes_new (buf, sizeof (*buf));
+  variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"), bytes, TRUE);
+  g_dbus_message_set_body (method_call, g_variant_new ("(tv)", ctx, variant));
+
+  method_reply = g_dbus_connection_send_message_with_reply_sync (
+      _connection, method_call, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL,
+      &error);
+
+  g_bytes_unref (bytes);
+
+  if (method_reply == NULL) {
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+  if (g_dbus_message_get_message_type (method_reply) ==
+      G_DBUS_MESSAGE_TYPE_ERROR) {
+    g_dbus_message_to_gerror (method_reply, &error);
+    g_critical ("error: %s\n", error->message);
+    g_error_free (error);
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+out:
+  g_object_unref (method_call);
+  g_object_unref (method_reply);
+
+  return status;
 }
 
 /**
@@ -397,8 +602,71 @@ npumgr_buffer_destroy (npumgr_context ctx, npumgr_buffer *buf) {
 npumgr_status_e
 npumgr_buffer_map (npumgr_context ctx, npumgr_buffer *buf,
                    uint8_t **mapped_addr) {
-  /* NYI */
-  return NPUMGR_STATUS_SUCCESS;
+  GDBusMessage *method_call;
+  GDBusMessage *method_reply;
+  npumgr_status_e status = NPUMGR_STATUS_SUCCESS;
+  GError *error = NULL;
+  GVariant *variant;
+  GBytes *bytes;
+  GUnixFDList *fd_list;
+
+  g_return_val_if_fail (wait_until_connected (), NPUMGR_STATUS_ERR_TIMEOUT);
+
+  method_call = g_dbus_message_new_method_call (
+      _name_owner, "/sr/odl/NPUManager/APIObject", "sr.odl.NPUManager.API",
+      "BufferMap");
+
+  bytes = g_bytes_new (buf, sizeof (*buf));
+  variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"), bytes, TRUE);
+  g_dbus_message_set_body (method_call, g_variant_new ("(tv)", ctx, variant));
+
+  method_reply = g_dbus_connection_send_message_with_reply_sync (
+      _connection, method_call, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL,
+      &error);
+
+  g_bytes_unref (bytes);
+
+  if (method_reply == NULL) {
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+  if (g_dbus_message_get_message_type (method_reply) ==
+      G_DBUS_MESSAGE_TYPE_ERROR) {
+    g_dbus_message_to_gerror (method_reply, &error);
+    g_critical ("error: %s\n", error->message);
+    g_error_free (error);
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out;
+  }
+
+  g_variant_get (g_dbus_message_get_body (method_reply), "(v)", &variant);
+  bytes = g_variant_get_data_as_bytes (variant);
+
+  if (g_bytes_get_size (bytes) != sizeof (*buf)) {
+    status = NPUMGR_STATUS_ERR_FAIL;
+    goto out_unref;
+  }
+
+  memcpy (buf, g_bytes_get_data (bytes, NULL), sizeof (*buf));
+
+  fd_list = g_dbus_message_get_unix_fd_list (method_reply);
+  buf->buf_fd = g_unix_fd_list_get (fd_list, 0, NULL);
+
+  *mapped_addr =
+      (uint8_t *) mmap (NULL, ALIGNED_SIZE (buf->buf_size),
+                        PROT_READ | PROT_WRITE, MAP_SHARED, buf->buf_fd, 0);
+  if (*mapped_addr == MAP_FAILED)
+    status = NPUMGR_STATUS_ERR_FAIL;
+
+out_unref:
+  g_bytes_unref (bytes);
+
+out:
+  g_object_unref (method_call);
+  g_object_unref (method_reply);
+
+  return status;
 }
 
 /**
index c17dcf8..6fae8e7 100644 (file)
@@ -165,6 +165,7 @@ typedef enum _npumgr_tensor_qnt_type {
 typedef enum _npumgr_tensor_fmt {
        NPUMGR_TENSOR_FMT_NCHW = 0,
        NPUMGR_TENSOR_FMT_NHWC,
+       NPUMGR_TENSOR_FMT_TRIV2,
 
        NPUMGR_TENSOR_FMT_MAX
 }npumgr_tensor_fmt_t;
diff --git a/tests/apptests/npumgr/npumgr_common.h b/tests/apptests/npumgr/npumgr_common.h
new file mode 100644 (file)
index 0000000..aa7708a
--- /dev/null
@@ -0,0 +1,33 @@
+/**
+ * Proprietary
+ * Copyright (C) 2021 Samsung Electronics
+ * Copyright (C) 2021 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file npumgr_common.h
+ * @date 10 May 2021
+ * @brief npumgr common header
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#ifndef __NPUMGR_COMMON_H__
+#define __NPUMGR_COMMON_H__
+
+#include <sys/mman.h>
+#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)
+
+#endif
index 62a18bd..d9a3ba3 100644 (file)
@@ -25,12 +25,106 @@ NpumgrDevice *npumgr_device_triv2_new (void);
 }
 
 /**
+ * @brief Class for triv2 npumgr buffer
+ */
+class NpumgrBufferTriv2 {
+ public:
+  NpumgrBufferTriv2 (const generic_buffer &gbuf) {
+    handle_ = g_atomic_int_add (&g_buf_handle, 1);
+    memcpy (&gbuf_, &gbuf, sizeof (gbuf));
+    quant_type_ = NPUMGR_TENSOR_QNT_MAX;
+  }
+
+  int getDbufFD () const { return gbuf_.dmabuf; }
+  size_t getSize () const { return gbuf_.size; }
+  void *getData () const { return gbuf_.addr; }
+  npumgr_buffer_h getHandle () const { return handle_; }
+  generic_buffer *getGenericBuffer () { return &gbuf_; }
+
+  void setDataFmt (const npumgr_tensor_fmt_t &fmt) { data_fmt_ = fmt; }
+  void setDataType (const npumgr_tensor_data_t &type) { data_type_ = type; }
+  void setQuantType (const npumgr_tensor_qnt_t &type) { quant_type_ = type; }
+
+  const npumgr_tensor_fmt_t &getDataFmt () const { return data_fmt_; }
+  const npumgr_tensor_data_t &getDataType () const { return data_type_; }
+  const npumgr_tensor_qnt_t &getQuantType () const { return quant_type_; }
+
+ private:
+  static volatile guint g_buf_handle;
+
+  npumgr_buffer_h handle_;
+  generic_buffer gbuf_;
+
+  npumgr_tensor_fmt_t data_fmt_;
+  npumgr_tensor_data_t data_type_;
+  npumgr_tensor_qnt_t quant_type_;
+};
+
+static data_layout
+convert_layout (const npumgr_tensor_fmt_t &fmt) {
+  data_layout layout;
+
+  /* unknown, relying on the model */
+  layout = DATA_LAYOUT_MODEL;
+  switch (fmt) {
+    case NPUMGR_TENSOR_FMT_NCHW:
+      layout = DATA_LAYOUT_NCHW;
+      break;
+    case NPUMGR_TENSOR_FMT_NHWC:
+      layout = DATA_LAYOUT_NHWC;
+      break;
+    case NPUMGR_TENSOR_FMT_TRIV2:
+      layout = DATA_LAYOUT_TRIV2;
+      break;
+    default:
+      break;
+  }
+
+  return layout;
+}
+
+static data_type
+convert_type (const npumgr_tensor_data_t &data,
+              const npumgr_tensor_qnt_t &qnt) {
+  data_type type;
+
+  /* unknown, relying on the model */
+  type = DATA_TYPE_MODEL;
+  switch (data) {
+    case NPUMGR_TENSOR_DATA_FLOAT32:
+      type = DATA_TYPE_FLOAT32;
+      break;
+    case NPUMGR_TENSOR_DATA_INT8:
+      type = DATA_TYPE_INT8;
+      break;
+    case NPUMGR_TENSOR_DATA_UINT8:
+      type = DATA_TYPE_UINT8;
+      break;
+    case NPUMGR_TENSOR_DATA_INT16:
+      type = DATA_TYPE_INT16;
+      break;
+    case NPUMGR_TENSOR_DATA_UINT16:
+      type = DATA_TYPE_UINT16;
+      break;
+    default:
+      break;
+  }
+
+  if (qnt == NPUMGR_TENSOR_QNT_AFFINE_ASYMM)
+    type = DATA_TYPE_QASYMM8;
+
+  return type;
+}
+
+/**
  * @brief Class for triv2 npumgr network
  */
 class NpumgrNetworkTriv2 {
  public:
-  NpumgrNetworkTriv2 (const npumgr_network_defn &model_file)
-      : model_file_ (model_file),
+  NpumgrNetworkTriv2 (npudev_h dev, const npumgr_network_defn &model_file)
+      : dev_ (dev),
+        model_id_ (0),
+        model_file_ (model_file),
         in_buffer_type_ (NPUMGR_BUF_TYPE_MAX),
         out_buffer_type_ (NPUMGR_BUF_TYPE_MAX),
         in_tensor_names_ (NULL),
@@ -38,8 +132,16 @@ class NpumgrNetworkTriv2 {
     handle_ = g_atomic_int_add (&g_nw_handle, 1);
     meta_ = (npubin_meta *) g_new0 (npubin_meta, 1);
     model_file_ = model_file;
+    in_buffers_.num_buffers = 0;
+    out_buffers_.num_buffers = 0;
+
+    memset (&in_info_, '\x00', sizeof (in_info_));
+    memset (&out_info_, '\x00', sizeof (out_info_));
   }
   ~NpumgrNetworkTriv2 () {
+    if (model_id_ > 0)
+      unregisterNPUmodel (dev_, model_id_);
+
     close (model_file_.fd);
     g_strfreev (in_tensor_names_);
     g_strfreev (out_tensor_names_);
@@ -53,8 +155,31 @@ class NpumgrNetworkTriv2 {
     in_tensor_names_ = g_strdupv (in_tensor_names);
   }
   gboolean loadModel () {
-    return read (model_file_.fd, (void *) meta_, NPUBIN_META_SIZE) ==
-           NPUBIN_META_SIZE;
+    generic_buffer model = {0};
+
+    lseek (model_file_.fd, 0, SEEK_SET);
+    if (read (model_file_.fd, (void *) meta_, NPUBIN_META_SIZE) !=
+        NPUBIN_META_SIZE)
+      return FALSE;
+
+    if (meta_->size <= NPUBIN_META_SIZE)
+      return FALSE;
+
+    model.type = BUFFER_FILE;
+    model.fd = model_file_.fd;
+    model.size = meta_->size;
+
+    if (registerNPUmodel (dev_, &model, &model_id_) != 0) {
+      return FALSE;
+    }
+
+    in_buffers_.num_buffers = getInTensorCnt ();
+    out_buffers_.num_buffers = getOutTensorCnt ();
+
+    in_info_.num_info = getInTensorCnt ();
+    out_info_.num_info = getOutTensorCnt ();
+
+    return TRUE;
   }
 
   /** @brief set output buffer type */
@@ -79,8 +204,13 @@ class NpumgrNetworkTriv2 {
     return meta_->input_seg_dims[i][j];
   }
   guint getInTensorSize (guint i) {
-    guint size = 1;
-    for (guint j = 0; j < MAX_RANK; j++) size *= getInTensorDim (i, j);
+    guint size;
+    int status;
+
+    status = getNPUmodel_tensorSize (dev_, model_id_, true, i, &size);
+    if (status != 0)
+      return 0;
+
     return size;
   }
   int32_t getInTensorQuantZero (guint i) { return meta_->input_seg_quant_z[i]; }
@@ -90,8 +220,13 @@ class NpumgrNetworkTriv2 {
     return meta_->output_seg_dims[i][j];
   }
   guint getOutTensorSize (guint i) {
-    guint size = 1;
-    for (guint j = 0; j < MAX_RANK; j++) size *= getOutTensorDim (i, j);
+    guint size;
+    int status;
+
+    status = getNPUmodel_tensorSize (dev_, model_id_, false, i, &size);
+    if (status != 0)
+      return 0;
+
     return size;
   }
   int32_t getOutTensorQuantZero (gint i) {
@@ -99,10 +234,45 @@ class NpumgrNetworkTriv2 {
   }
   float getOutTensorQuantScale (gint i) { return meta_->output_seg_quant_s[i]; }
 
+  gboolean setInput (gint index, NpumgrBufferTriv2 *buffer) {
+    if (index >= in_buffers_.num_buffers)
+      return FALSE;
+
+    in_info_.info[index].layout = convert_layout (buffer->getDataFmt ());
+    in_info_.info[index].type =
+        convert_type (buffer->getDataType (), buffer->getQuantType ());
+
+    memcpy (&in_buffers_.bufs[index], buffer->getGenericBuffer (),
+            sizeof (generic_buffer));
+    in_buffers_.bufs[index].type = BUFFER_DMABUF;
+    return TRUE;
+  }
+
+  gboolean setOutput (gint index, NpumgrBufferTriv2 *buffer) {
+    if (index >= out_buffers_.num_buffers)
+      return FALSE;
+
+    out_info_.info[index].layout = convert_layout (buffer->getDataFmt ());
+    out_info_.info[index].type =
+        convert_type (buffer->getDataType (), buffer->getQuantType ());
+
+    memcpy (&out_buffers_.bufs[index], buffer->getGenericBuffer (),
+            sizeof (generic_buffer));
+    out_buffers_.bufs[index].type = BUFFER_DMABUF;
+    return TRUE;
+  }
+
+  gboolean prepare () {
+    return (setNPU_dataInfo (dev_, model_id_, &in_info_, &out_info_) == 0);
+  }
+
  private:
   static volatile guint g_nw_handle;
 
+  npudev_h dev_;
+
   npumgr_network handle_;
+  uint32_t model_id_;
 
   npumgr_network_defn model_file_;
   npubin_meta *meta_;
@@ -112,6 +282,12 @@ class NpumgrNetworkTriv2 {
 
   gchar **in_tensor_names_;
   gchar **out_tensor_names_;
+
+  input_buffers in_buffers_;
+  output_buffers out_buffers_;
+
+  tensors_data_info in_info_;
+  tensors_data_info out_info_;
 };
 
 static void
@@ -121,6 +297,13 @@ nw_destroy (gpointer data) {
   delete nw;
 }
 
+static void
+buf_destroy (gpointer data) {
+  NpumgrBufferTriv2 *buf = static_cast<NpumgrBufferTriv2 *> (data);
+
+  delete buf;
+}
+
 /**
  * @brief Class for triv2 npumgr context
  */
@@ -131,9 +314,16 @@ class NpumgrContextTriv2 {
     handle_ = g_atomic_int_add (&g_ctx_handle, 1);
     nw_table_ =
         g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, nw_destroy);
+    buf_table_ = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
+                                        buf_destroy);
   }
 
-  ~NpumgrContextTriv2 () { g_hash_table_destroy (nw_table_); }
+  ~NpumgrContextTriv2 () {
+    g_hash_table_destroy (nw_table_);
+    g_hash_table_destroy (buf_table_);
+  }
+
+  npudev_h getDevice () const { return dev_; }
 
   gboolean appendNetwork (npumgr_network handle, NpumgrNetworkTriv2 *nw) {
     return g_hash_table_insert (nw_table_, GSIZE_TO_POINTER (handle), nw);
@@ -146,6 +336,58 @@ class NpumgrContextTriv2 {
         nw_table_, GSIZE_TO_POINTER (handle));
   }
 
+  NpumgrBufferTriv2 *findBuffer (npumgr_buffer_h handle) {
+    return (NpumgrBufferTriv2 *) g_hash_table_lookup (
+        buf_table_, GSIZE_TO_POINTER (handle));
+  }
+
+  gboolean allocBuffer (npumgr_query_tensor_attr *param, npumgr_buffer *buf) {
+    generic_buffer gbuf = {0};
+
+    gbuf.type = BUFFER_MAPPED;
+    gbuf.size = param->size;
+
+    if (allocNPU_genericBuffer (dev_, &gbuf) != 0)
+      return FALSE;
+
+    NpumgrBufferTriv2 *nbuf = new NpumgrBufferTriv2 (gbuf);
+    nbuf->setDataFmt (param->fmt);
+    nbuf->setDataType (param->type);
+    nbuf->setQuantType (param->quant_type);
+
+    if (!g_hash_table_insert (buf_table_, GSIZE_TO_POINTER (nbuf->getHandle ()),
+                              nbuf)) {
+      cleanNPU_genericBuffer (dev_, &gbuf);
+      delete nbuf;
+      return FALSE;
+    }
+
+    buf->buf_handle = nbuf->getHandle ();
+    buf->buf_fd = nbuf->getDbufFD ();
+    buf->buf_size = nbuf->getSize ();
+    buf->buf_offset = 0;
+
+    return TRUE;
+  }
+
+  gboolean destroyBuffer (npumgr_buffer *buf) {
+    NpumgrBufferTriv2 *nbuf = findBuffer (buf->buf_handle);
+    g_return_val_if_fail (nbuf != NULL, FALSE);
+
+    generic_buffer *gbuf = nbuf->getGenericBuffer ();
+    g_return_val_if_fail (gbuf != NULL, FALSE);
+
+    if (cleanNPU_genericBuffer (dev_, gbuf) != 0)
+      return FALSE;
+
+    return g_hash_table_remove (buf_table_, GSIZE_TO_POINTER (buf->buf_handle));
+  }
+
+  gboolean mapBuffer (npumgr_buffer *buf, uint8_t **mapped_addr) {
+    /* NYI */
+    return TRUE;
+  }
+
   npumgr_context getHandle () { return handle_; }
 
  private:
@@ -156,6 +398,7 @@ class NpumgrContextTriv2 {
   int priority_;
 
   GHashTable *nw_table_;
+  GHashTable *buf_table_;
 };
 
 static void
@@ -167,6 +410,7 @@ ctx_destroy (gpointer data) {
 
 volatile guint NpumgrContextTriv2::g_ctx_handle = 1;
 volatile guint NpumgrNetworkTriv2::g_nw_handle = 1;
+volatile guint NpumgrBufferTriv2::g_buf_handle = 1;
 
 /**
  * @brief Private members in NpumgrDeviceTriv2
@@ -201,9 +445,34 @@ static npumgr_status_e triv2_network_create (
     int in_tensor_cnt, char **input_tensor_names,
     npumgr_buffer_t out_buffer_type, int out_tensor_cnt,
     char **output_tensor_names, npumgr_network *out_nw_handle);
+static npumgr_status_e triv2_network_set_input (NpumgrDevice *device,
+                                                npumgr_context ctx,
+                                                npumgr_network nw_handle,
+                                                int index,
+                                                npumgr_buffer *input_buffer);
+static npumgr_status_e triv2_network_set_output (NpumgrDevice *device,
+                                                 npumgr_context ctx,
+                                                 npumgr_network nw_handle,
+                                                 int index,
+                                                 npumgr_buffer *output_buffer);
+static npumgr_status_e triv2_network_prepare (NpumgrDevice *device,
+                                              npumgr_context ctx,
+                                              npumgr_network nw_handle);
 static npumgr_status_e triv2_network_destroy (NpumgrDevice *device,
                                               npumgr_context ctx,
                                               npumgr_network nw_handle);
+static npumgr_status_e triv2_buffer_create (
+    NpumgrDevice *device, npumgr_context ctx,
+    npumgr_query_tensor_attr *create_param, npumgr_buffer *buf);
+static npumgr_status_e triv2_buffer_destroy (NpumgrDevice *device,
+                                             npumgr_context ctx,
+                                             npumgr_buffer *buf);
+static npumgr_status_e triv2_buffer_map (NpumgrDevice *device,
+                                         npumgr_context ctx, npumgr_buffer *buf,
+                                         uint8_t **mapped_addr);
+static npumgr_status_e triv2_buffer_unmap (NpumgrDevice *device,
+                                           npumgr_context ctx,
+                                           npumgr_buffer *buf);
 static npumgr_status_e triv2_query_network (NpumgrDevice *device,
                                             npumgr_context ctx,
                                             npumgr_network nw_handle,
@@ -236,7 +505,14 @@ npumgr_device_triv2_class_init (NpumgrDeviceTriv2Class *klass) {
   npumgr_device_class->context_create = triv2_context_create;
   npumgr_device_class->context_destroy = triv2_context_destroy;
   npumgr_device_class->network_create = triv2_network_create;
+  npumgr_device_class->network_set_input = triv2_network_set_input;
+  npumgr_device_class->network_set_output = triv2_network_set_output;
+  npumgr_device_class->network_prepare = triv2_network_prepare;
   npumgr_device_class->network_destroy = triv2_network_destroy;
+  npumgr_device_class->buffer_create = triv2_buffer_create;
+  npumgr_device_class->buffer_destroy = triv2_buffer_destroy;
+  npumgr_device_class->buffer_map = triv2_buffer_map;
+  npumgr_device_class->buffer_unmap = triv2_buffer_unmap;
   npumgr_device_class->query_network = triv2_query_network;
   npumgr_device_class->query_input = triv2_query_input;
   npumgr_device_class->query_output = triv2_query_output;
@@ -394,7 +670,8 @@ triv2_network_create (NpumgrDevice *device, npumgr_context ctx, int num_files,
 
   g_return_val_if_fail (context != NULL, NPUMGR_STATUS_ERR_CTX_INVALID);
 
-  NpumgrNetworkTriv2 *network = new NpumgrNetworkTriv2 (input_files[0]);
+  NpumgrNetworkTriv2 *network =
+      new NpumgrNetworkTriv2 (context->getDevice (), input_files[0]);
   if (!network->loadModel ())
     goto err;
   if (network->getInTensorCnt () != in_tensor_cnt)
@@ -418,6 +695,86 @@ err:
 }
 
 static npumgr_status_e
+triv2_network_set_input (NpumgrDevice *device, npumgr_context ctx_handle,
+                         npumgr_network nw_handle, int index,
+                         npumgr_buffer *buf) {
+  g_return_val_if_fail (device != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (ctx_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (nw_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (buf != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+
+  NpumgrDeviceTriv2 *self = NPUMGR_DEVICE_TRIV2 (device);
+  NpumgrDeviceTriv2Private *priv = NPUMGR_DEVICE_TRIV2_GET_PRIVATE (self);
+
+  NpumgrContextTriv2 *context = find_context (priv, ctx_handle);
+  g_return_val_if_fail (context != NULL, NPUMGR_STATUS_ERR_CTX_INVALID);
+
+  NpumgrNetworkTriv2 *network = context->findNetwork (nw_handle);
+  g_return_val_if_fail (network != NULL, NPUMGR_STATUS_ERR_MODEL_INVALID);
+  g_return_val_if_fail (network->getInTensorCnt () > index,
+                        NPUMGR_STATUS_ERR_PARAM_INVALID);
+
+  NpumgrBufferTriv2 *buffer = context->findBuffer (buf->buf_handle);
+  g_return_val_if_fail (buffer != NULL, NPUMGR_STATUS_ERR_FAIL);
+
+  if (!network->setInput (index, buffer))
+    return NPUMGR_STATUS_ERR_FAIL;
+
+  return NPUMGR_STATUS_SUCCESS;
+}
+
+static npumgr_status_e
+triv2_network_set_output (NpumgrDevice *device, npumgr_context ctx_handle,
+                          npumgr_network nw_handle, int index,
+                          npumgr_buffer *buf) {
+  g_return_val_if_fail (device != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (ctx_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (nw_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (buf != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+
+  NpumgrDeviceTriv2 *self = NPUMGR_DEVICE_TRIV2 (device);
+  NpumgrDeviceTriv2Private *priv = NPUMGR_DEVICE_TRIV2_GET_PRIVATE (self);
+
+  NpumgrContextTriv2 *context = find_context (priv, ctx_handle);
+  g_return_val_if_fail (context != NULL, NPUMGR_STATUS_ERR_CTX_INVALID);
+
+  NpumgrNetworkTriv2 *network = context->findNetwork (nw_handle);
+  g_return_val_if_fail (network != NULL, NPUMGR_STATUS_ERR_MODEL_INVALID);
+  g_return_val_if_fail (network->getOutTensorCnt () > index,
+                        NPUMGR_STATUS_ERR_PARAM_INVALID);
+
+  NpumgrBufferTriv2 *buffer = context->findBuffer (buf->buf_handle);
+  g_return_val_if_fail (buffer != NULL, NPUMGR_STATUS_ERR_FAIL);
+
+  if (!network->setOutput (index, buffer))
+    return NPUMGR_STATUS_ERR_FAIL;
+
+  return NPUMGR_STATUS_SUCCESS;
+}
+
+static npumgr_status_e
+triv2_network_prepare (NpumgrDevice *device, npumgr_context ctx_handle,
+                       npumgr_network nw_handle) {
+  g_return_val_if_fail (device != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (ctx_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (nw_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+
+  NpumgrDeviceTriv2 *self = NPUMGR_DEVICE_TRIV2 (device);
+  NpumgrDeviceTriv2Private *priv = NPUMGR_DEVICE_TRIV2_GET_PRIVATE (self);
+
+  NpumgrContextTriv2 *context = find_context (priv, ctx_handle);
+  g_return_val_if_fail (context != NULL, NPUMGR_STATUS_ERR_CTX_INVALID);
+
+  NpumgrNetworkTriv2 *network = context->findNetwork (nw_handle);
+  g_return_val_if_fail (network != NULL, NPUMGR_STATUS_ERR_MODEL_INVALID);
+
+  if (!network->prepare ())
+    return NPUMGR_STATUS_ERR_FAIL;
+
+  return NPUMGR_STATUS_SUCCESS;
+}
+
+static npumgr_status_e
 triv2_network_destroy (NpumgrDevice *device, npumgr_context ctx_handle,
                        npumgr_network nw_handle) {
   g_return_val_if_fail (device != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
@@ -438,6 +795,73 @@ triv2_network_destroy (NpumgrDevice *device, npumgr_context ctx_handle,
 }
 
 static npumgr_status_e
+triv2_buffer_create (NpumgrDevice *device, npumgr_context ctx_handle,
+                     npumgr_query_tensor_attr *create_param,
+                     npumgr_buffer *buf) {
+  g_return_val_if_fail (device != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (ctx_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (create_param != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (buf != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+
+  NpumgrDeviceTriv2 *self = NPUMGR_DEVICE_TRIV2 (device);
+  NpumgrDeviceTriv2Private *priv = NPUMGR_DEVICE_TRIV2_GET_PRIVATE (self);
+
+  NpumgrContextTriv2 *context = find_context (priv, ctx_handle);
+  g_return_val_if_fail (context != NULL, NPUMGR_STATUS_ERR_CTX_INVALID);
+
+  if (!context->allocBuffer (create_param, buf))
+    return NPUMGR_STATUS_ERR_FAIL;
+
+  return NPUMGR_STATUS_SUCCESS;
+}
+
+static npumgr_status_e
+triv2_buffer_destroy (NpumgrDevice *device, npumgr_context ctx_handle,
+                      npumgr_buffer *buf) {
+  g_return_val_if_fail (device != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (ctx_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (buf != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+
+  NpumgrDeviceTriv2 *self = NPUMGR_DEVICE_TRIV2 (device);
+  NpumgrDeviceTriv2Private *priv = NPUMGR_DEVICE_TRIV2_GET_PRIVATE (self);
+
+  NpumgrContextTriv2 *context = find_context (priv, ctx_handle);
+  g_return_val_if_fail (context != NULL, NPUMGR_STATUS_ERR_CTX_INVALID);
+
+  if (!context->destroyBuffer (buf))
+    return NPUMGR_STATUS_ERR_FAIL;
+
+  return NPUMGR_STATUS_SUCCESS;
+}
+
+static npumgr_status_e
+triv2_buffer_map (NpumgrDevice *device, npumgr_context ctx_handle,
+                  npumgr_buffer *buf, uint8_t **mapped_addr) {
+  g_return_val_if_fail (device != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (ctx_handle != 0, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (buf != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+  g_return_val_if_fail (mapped_addr != NULL, NPUMGR_STATUS_ERR_PARAM_INVALID);
+
+  NpumgrDeviceTriv2 *self = NPUMGR_DEVICE_TRIV2 (device);
+  NpumgrDeviceTriv2Private *priv = NPUMGR_DEVICE_TRIV2_GET_PRIVATE (self);
+
+  NpumgrContextTriv2 *context = find_context (priv, ctx_handle);
+  g_return_val_if_fail (context != NULL, NPUMGR_STATUS_ERR_CTX_INVALID);
+
+  if (!context->mapBuffer (buf, mapped_addr))
+    return NPUMGR_STATUS_ERR_FAIL;
+
+  return NPUMGR_STATUS_SUCCESS;
+}
+
+static npumgr_status_e
+triv2_buffer_unmap (NpumgrDevice *device, npumgr_context ctx,
+                    npumgr_buffer *buf) {
+  /* NYI */
+  return NPUMGR_STATUS_SUCCESS;
+}
+
+static npumgr_status_e
 triv2_query_network (NpumgrDevice *device, npumgr_context ctx_handle,
                      npumgr_network nw_handle,
                      npumgr_query_inout_num *inout_num) {