diff --git a/drivers/dma/skeleton/meson.build b/drivers/dma/skeleton/meson.build
index 27509b1..5d47339 100644
--- a/drivers/dma/skeleton/meson.build
+++ b/drivers/dma/skeleton/meson.build
@@ -4,4 +4,5 @@
 deps += ['dmadev', 'kvargs', 'ring', 'bus_vdev']
 sources = files(
         'skeleton_dmadev.c',
+        'skeleton_dmadev_test.c',
 )
diff --git a/drivers/dma/skeleton/skeleton_dmadev.c b/drivers/dma/skeleton/skeleton_dmadev.c
index b3ab4a0..1707e88 100644
--- a/drivers/dma/skeleton/skeleton_dmadev.c
+++ b/drivers/dma/skeleton/skeleton_dmadev.c
@@ -430,6 +430,7 @@ static const struct rte_dmadev_ops skeldma_ops = {
 	.stats_reset = skeldma_stats_reset,
 
 	.dev_dump = skeldma_dump,
+	.dev_selftest = test_dma_skeleton,
 };
 
 static int
@@ -503,11 +504,24 @@ skeldma_parse_lcore(const char *key __rte_unused,
 	return 0;
 }
 
+static int
+skeldma_parse_selftest(const char *key __rte_unused,
+		       const char *value,
+		       void *opaque)
+{
+	int flag = atoi(value);
+	if (flag == 0 || flag == 1)
+		*(int *)opaque = flag;
+	return 0;
+}
+
 static void
-skeldma_parse_vdev_args(struct rte_vdev_device *vdev, int *lcore_id)
+skeldma_parse_vdev_args(struct rte_vdev_device *vdev,
+			int *lcore_id, int *selftest)
 {
 	static const char *const args[] = {
 		SKELDMA_ARG_LCORE,
+		SKELDMA_ARG_SELFTEST,
 		NULL
 	};
 
@@ -524,8 +538,11 @@ skeldma_parse_vdev_args(struct rte_vdev_device *vdev, int *lcore_id)
 
 	(void)rte_kvargs_process(kvlist, SKELDMA_ARG_LCORE,
 				 skeldma_parse_lcore, lcore_id);
+	(void)rte_kvargs_process(kvlist, SKELDMA_ARG_SELFTEST,
+				 skeldma_parse_selftest, selftest);
 
-	SKELDMA_INFO("Parse lcore_id = %d\n", *lcore_id);
+	SKELDMA_INFO("Parse lcore_id = %d selftest = %d\n",
+		     *lcore_id, *selftest);
 
 	rte_kvargs_free(kvlist);
 }
@@ -535,6 +552,7 @@ skeldma_probe(struct rte_vdev_device *vdev)
 {
 	const char *name;
 	int lcore_id = -1;
+	int selftest = 0;
 	int ret;
 
 	name = rte_vdev_device_name(vdev);
@@ -552,10 +570,17 @@ skeldma_probe(struct rte_vdev_device *vdev)
 		return -EINVAL;
 	}
 
-	skeldma_parse_vdev_args(vdev, &lcore_id);
+	skeldma_parse_vdev_args(vdev, &lcore_id, &selftest);
 
 	ret = skeldma_create(name, vdev, lcore_id);
 	if (ret >= 0) {
+		/* In case command line argument for 'selftest' was passed;
+		 * if invalid arguments were passed, execution continues but
+		 * without selftest.
+		 */
+		if (selftest)
+			(void)test_dma_skeleton(ret);
+
 		SKELDMA_INFO("Create %s dmadev lcore-id %d\n", name, lcore_id);
 		/* Device instance created; Second instance not possible */
 		skeldma_init_once = 1;
@@ -592,4 +617,5 @@ static struct rte_vdev_driver skeldma_pmd_drv = {
 RTE_LOG_REGISTER_DEFAULT(skeldma_logtype, INFO);
 RTE_PMD_REGISTER_VDEV(dma_skeleton, skeldma_pmd_drv);
 RTE_PMD_REGISTER_PARAM_STRING(dma_skeleton,
-		SKELDMA_ARG_LCORE "=<uint16> ");
+		SKELDMA_ARG_LCORE "=<uint16> "
+		SKELDMA_ARG_SELFTEST "=<0|1> ");
diff --git a/drivers/dma/skeleton/skeleton_dmadev.h b/drivers/dma/skeleton/skeleton_dmadev.h
index 6495653..e8a310d 100644
--- a/drivers/dma/skeleton/skeleton_dmadev.h
+++ b/drivers/dma/skeleton/skeleton_dmadev.h
@@ -22,6 +22,7 @@ extern int skeldma_logtype;
 	SKELDMA_LOG(ERR, fmt, ## args)
 
 #define SKELDMA_ARG_LCORE	"lcore"
+#define SKELDMA_ARG_SELFTEST	"selftest"
 
 struct skeldma_desc {
 	void *src;
diff --git a/drivers/dma/skeleton/skeleton_dmadev_test.c b/drivers/dma/skeleton/skeleton_dmadev_test.c
new file mode 100644
index 0000000..be56f07
--- /dev/null
+++ b/drivers/dma/skeleton/skeleton_dmadev_test.c
@@ -0,0 +1,521 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 HiSilicon Limited.
+ */
+
+#include <string.h>
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_malloc.h>
+#include <rte_test.h>
+
+/* Using relative path as skeleton_dmadev is not part of exported headers */
+#include "skeleton_dmadev.h"
+
+#define SKELDMA_TEST_DEBUG(fmt, args...) \
+	SKELDMA_LOG(DEBUG, fmt, ## args)
+#define SKELDMA_TEST_INFO(fmt, args...) \
+	SKELDMA_LOG(INFO, fmt, ## args)
+
+#define SKELDMA_TEST_RUN(test) \
+	testsuite_run_test(test, #test)
+
+#define TEST_MEMCPY_SIZE	1024
+#define TEST_WAIT_US_VAL	50000
+
+#define TEST_SUCCESS 0
+#define TEST_FAILED  -1
+
+static uint16_t test_dev_id;
+static uint16_t invalid_dev_id;
+
+static int total;
+static int passed;
+static int failed;
+static char *src;
+static char *dst;
+
+static int
+testsuite_setup(uint16_t dev_id)
+{
+	test_dev_id = dev_id;
+	invalid_dev_id = RTE_DMADEV_MAX_DEVS;
+
+	src = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
+	if (src == NULL)
+		return -ENOMEM;
+	dst = rte_malloc("dmadev_test_dst", TEST_MEMCPY_SIZE, 0);
+	if (dst == NULL)
+		return -ENOMEM;
+
+	total = 0;
+	passed = 0;
+	failed = 0;
+
+	return 0;
+}
+
+static void
+testsuite_teardown(void)
+{
+	rte_free(src);
+	rte_free(dst);
+	/* Ensure the dmadev is stopped. */
+	rte_dmadev_stop(test_dev_id);
+}
+
+static void
+testsuite_run_test(int (*test)(void), const char *name)
+{
+	int ret = 0;
+
+	if (test) {
+		ret = test();
+		if (ret < 0) {
+			failed++;
+			SKELDMA_TEST_INFO("%s Failed", name);
+		} else {
+			passed++;
+			SKELDMA_TEST_DEBUG("%s Passed", name);
+		}
+	}
+
+	total++;
+}
+
+static int
+test_dmadev_get_dev_id(void)
+{
+	int ret = rte_dmadev_get_dev_id("invalid_dmadev_device");
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_is_valid_dev(void)
+{
+	int ret;
+	ret = rte_dmadev_is_valid_dev(invalid_dev_id);
+	RTE_TEST_ASSERT(ret == false, "Expected false for invalid dev id");
+	ret = rte_dmadev_is_valid_dev(test_dev_id);
+	RTE_TEST_ASSERT(ret == true, "Expected true for valid dev id");
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_count(void)
+{
+	uint16_t count = rte_dmadev_count();
+	RTE_TEST_ASSERT(count > 0, "Invalid dmadev count %u", count);
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_info_get(void)
+{
+	struct rte_dmadev_info info =  { 0 };
+	int ret;
+
+	ret = rte_dmadev_info_get(invalid_dev_id, &info);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	ret = rte_dmadev_info_get(test_dev_id, NULL);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	ret = rte_dmadev_info_get(test_dev_id, &info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_configure(void)
+{
+	struct rte_dmadev_conf conf = { 0 };
+	struct rte_dmadev_info info = { 0 };
+	int ret;
+
+	/* Check for invalid parameters */
+	ret = rte_dmadev_configure(invalid_dev_id, &conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	ret = rte_dmadev_configure(test_dev_id, NULL);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Check for nb_vchans == 0 */
+	memset(&conf, 0, sizeof(conf));
+	ret = rte_dmadev_configure(test_dev_id, &conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Check for conf.nb_vchans > info.max_vchans */
+	ret = rte_dmadev_info_get(test_dev_id, &info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info");
+	memset(&conf, 0, sizeof(conf));
+	conf.nb_vchans = info.max_vchans + 1;
+	ret = rte_dmadev_configure(test_dev_id, &conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Check enable silent mode */
+	memset(&conf, 0, sizeof(conf));
+	conf.nb_vchans = info.max_vchans;
+	conf.enable_silent = true;
+	ret = rte_dmadev_configure(test_dev_id, &conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Configure success */
+	memset(&conf, 0, sizeof(conf));
+	conf.nb_vchans = info.max_vchans;
+	ret = rte_dmadev_configure(test_dev_id, &conf);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure dmadev, %d", ret);
+
+	/* Check configure success */
+	ret = rte_dmadev_info_get(test_dev_id, &info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info");
+	RTE_TEST_ASSERT_EQUAL(conf.nb_vchans, info.nb_vchans,
+			      "Configure nb_vchans not match");
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_vchan_setup(void)
+{
+	struct rte_dmadev_vchan_conf vchan_conf = { 0 };
+	struct rte_dmadev_conf dev_conf = { 0 };
+	struct rte_dmadev_info dev_info = { 0 };
+	int ret;
+
+	/* Check for invalid parameters */
+	ret = rte_dmadev_vchan_setup(invalid_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, NULL);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Make sure configure success */
+	ret = rte_dmadev_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info");
+	dev_conf.nb_vchans = dev_info.max_vchans;
+	ret = rte_dmadev_configure(test_dev_id, &dev_conf);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure dmadev, %d", ret);
+
+	/* Check for invalid vchan */
+	ret = rte_dmadev_vchan_setup(test_dev_id, dev_conf.nb_vchans,
+				     &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Check for direction */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_DEV_TO_DEV + 1;
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM - 1;
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Check for direction and dev_capa combination */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_DEV;
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	vchan_conf.direction = RTE_DMA_DIR_DEV_TO_MEM;
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	vchan_conf.direction = RTE_DMA_DIR_DEV_TO_DEV;
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Check for nb_desc validation */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info.min_desc - 1;
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	vchan_conf.nb_desc = dev_info.max_desc + 1;
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Check src port type validation */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info.min_desc;
+	vchan_conf.src_port.port_type = RTE_DMADEV_PORT_PCIE;
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Check dst port type validation */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info.min_desc;
+	vchan_conf.dst_port.port_type = RTE_DMADEV_PORT_PCIE;
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Check vchan setup success */
+	memset(&vchan_conf, 0, sizeof(vchan_conf));
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info.min_desc;
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
+static int
+setup_one_vchan(void)
+{
+	struct rte_dmadev_vchan_conf vchan_conf = { 0 };
+	struct rte_dmadev_info dev_info = { 0 };
+	struct rte_dmadev_conf dev_conf = { 0 };
+	int ret;
+
+	ret = rte_dmadev_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+	dev_conf.nb_vchans = dev_info.max_vchans;
+	ret = rte_dmadev_configure(test_dev_id, &dev_conf);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to configure, %d", ret);
+	vchan_conf.direction = RTE_DMA_DIR_MEM_TO_MEM;
+	vchan_conf.nb_desc = dev_info.min_desc;
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_start_stop(void)
+{
+	struct rte_dmadev_vchan_conf vchan_conf = { 0 };
+	struct rte_dmadev_conf dev_conf = { 0 };
+	int ret;
+
+	/* Check for invalid parameters */
+	ret = rte_dmadev_start(invalid_dev_id);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	ret = rte_dmadev_stop(invalid_dev_id);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Setup one vchan for later test */
+	ret = setup_one_vchan();
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dmadev_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	/* Check reconfigure and vchan setup when device started */
+	ret = rte_dmadev_configure(test_dev_id, &dev_conf);
+	RTE_TEST_ASSERT(ret == -EBUSY, "Failed to configure, %d", ret);
+	ret = rte_dmadev_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT(ret == -EBUSY, "Failed to setup vchan, %d", ret);
+
+	ret = rte_dmadev_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_stats(void)
+{
+	struct rte_dmadev_info dev_info = { 0 };
+	struct rte_dmadev_stats stats = { 0 };
+	int ret;
+
+	/* Check for invalid parameters */
+	ret = rte_dmadev_stats_get(invalid_dev_id, 0, &stats);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	ret = rte_dmadev_stats_get(invalid_dev_id, 0, NULL);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	ret = rte_dmadev_stats_reset(invalid_dev_id, 0);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Setup one vchan for later test */
+	ret = setup_one_vchan();
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	/* Check for invalid vchan */
+	ret = rte_dmadev_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+	ret = rte_dmadev_stats_get(test_dev_id, dev_info.max_vchans, &stats);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+	ret = rte_dmadev_stats_reset(test_dev_id, dev_info.max_vchans);
+	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
+
+	/* Check for valid vchan */
+	ret = rte_dmadev_stats_get(test_dev_id, 0, &stats);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get stats, %d", ret);
+	ret = rte_dmadev_stats_get(test_dev_id, RTE_DMADEV_ALL_VCHAN, &stats);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to get all stats, %d", ret);
+	ret = rte_dmadev_stats_reset(test_dev_id, 0);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to reset stats, %d", ret);
+	ret = rte_dmadev_stats_reset(test_dev_id, RTE_DMADEV_ALL_VCHAN);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to reset all stats, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_completed(void)
+{
+	uint16_t last_idx = 1;
+	bool has_error = true;
+	uint16_t cpl_ret;
+	int ret, i;
+
+	/* Setup one vchan for later test */
+	ret = setup_one_vchan();
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dmadev_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	/* Setup test memory */
+	for (i = 0; i < TEST_MEMCPY_SIZE; i++)
+		src[i] = (char)i;
+	memset(dst, 0, TEST_MEMCPY_SIZE);
+
+	/* Check enqueue without submit */
+	ret = rte_dmadev_copy(test_dev_id, 0, (rte_iova_t)src, (rte_iova_t)dst,
+				TEST_MEMCPY_SIZE, 0);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to enqueue copy, %d", ret);
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+	cpl_ret = rte_dmadev_completed(test_dev_id, 0, 1, &last_idx,
+				       &has_error);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 0, "Failed to get completed");
+
+	/* Check add submit */
+	ret = rte_dmadev_submit(test_dev_id, 0);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to submit, %d", ret);
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+	cpl_ret = rte_dmadev_completed(test_dev_id, 0, 1, &last_idx,
+				       &has_error);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 1, "Failed to get completed");
+	RTE_TEST_ASSERT_EQUAL(last_idx, 0, "Last idx should be zero, %u",
+				last_idx);
+	RTE_TEST_ASSERT_EQUAL(has_error, false, "Should have no error");
+	for (i = 0; i < TEST_MEMCPY_SIZE; i++) {
+		if (src[i] != dst[i]) {
+			RTE_TEST_ASSERT_EQUAL(src[i], dst[i],
+				"Failed to copy memory, %d %d", src[i], dst[i]);
+			break;
+		}
+	}
+
+	/* Setup test memory */
+	for (i = 0; i < TEST_MEMCPY_SIZE; i++)
+		src[i] = (char)i;
+	memset(dst, 0, TEST_MEMCPY_SIZE);
+
+	/* Check for enqueue with submit */
+	ret = rte_dmadev_copy(test_dev_id, 0, (rte_iova_t)src, (rte_iova_t)dst,
+				TEST_MEMCPY_SIZE, RTE_DMA_OP_FLAG_SUBMIT);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to enqueue copy, %d", ret);
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+	cpl_ret = rte_dmadev_completed(test_dev_id, 0, 1, &last_idx,
+				       &has_error);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 1, "Failed to get completed");
+	RTE_TEST_ASSERT_EQUAL(last_idx, 1, "Last idx should be 1, %u",
+				last_idx);
+	RTE_TEST_ASSERT_EQUAL(has_error, false, "Should have no error");
+	for (i = 0; i < TEST_MEMCPY_SIZE; i++) {
+		if (src[i] != dst[i]) {
+			RTE_TEST_ASSERT_EQUAL(src[i], dst[i],
+				"Failed to copy memory, %d %d", src[i], dst[i]);
+			break;
+		}
+	}
+
+	/* Stop dmadev to make sure dmadev to a known state */
+	ret = rte_dmadev_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_completed_status(void)
+{
+	enum rte_dma_status_code status[1] = { 1 };
+	uint16_t last_idx = 1;
+	uint16_t cpl_ret, i;
+	int ret;
+
+	/* Setup one vchan for later test */
+	ret = setup_one_vchan();
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dmadev_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	/* Check for enqueue with submit */
+	ret = rte_dmadev_copy(test_dev_id, 0, (rte_iova_t)src, (rte_iova_t)dst,
+				TEST_MEMCPY_SIZE, RTE_DMA_OP_FLAG_SUBMIT);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to enqueue copy, %d", ret);
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+	cpl_ret = rte_dmadev_completed_status(test_dev_id, 0, 1, &last_idx,
+					      status);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 1, "Failed to completed status");
+	RTE_TEST_ASSERT_EQUAL(last_idx, 0, "Last idx should be zero, %u",
+				last_idx);
+	for (i = 0; i < RTE_DIM(status); i++)
+		RTE_TEST_ASSERT_EQUAL(status[i], 0,
+				"Failed to completed status, %d", status[i]);
+
+	/* Check do completed status again */
+	cpl_ret = rte_dmadev_completed_status(test_dev_id, 0, 1, &last_idx,
+					      status);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 0, "Failed to completed status");
+
+	/* Check for enqueue with submit again */
+	ret = rte_dmadev_copy(test_dev_id, 0, (rte_iova_t)src, (rte_iova_t)dst,
+				TEST_MEMCPY_SIZE, RTE_DMA_OP_FLAG_SUBMIT);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to enqueue copy, %d", ret);
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+	cpl_ret = rte_dmadev_completed_status(test_dev_id, 0, 1, &last_idx,
+					      status);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 1, "Failed to completed status");
+	RTE_TEST_ASSERT_EQUAL(last_idx, 1, "Last idx should be 1, %u",
+				last_idx);
+	for (i = 0; i < RTE_DIM(status); i++)
+		RTE_TEST_ASSERT_EQUAL(status[i], 0,
+				"Failed to completed status, %d", status[i]);
+
+	/* Stop dmadev to make sure dmadev to a known state */
+	ret = rte_dmadev_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
+int
+test_dma_skeleton(uint16_t dev_id)
+{
+	int ret = testsuite_setup(dev_id);
+	if (ret) {
+		SKELDMA_TEST_INFO("testsuite setup fail!");
+		return -1;
+	}
+
+	/* If the testcase exit successfully, ensure that the test dmadev exist
+	 * and the dmadev is in the stopped state.
+	 */
+	SKELDMA_TEST_RUN(test_dmadev_get_dev_id);
+	SKELDMA_TEST_RUN(test_dmadev_is_valid_dev);
+	SKELDMA_TEST_RUN(test_dmadev_count);
+	SKELDMA_TEST_RUN(test_dmadev_info_get);
+	SKELDMA_TEST_RUN(test_dmadev_configure);
+	SKELDMA_TEST_RUN(test_dmadev_vchan_setup);
+	SKELDMA_TEST_RUN(test_dmadev_start_stop);
+	SKELDMA_TEST_RUN(test_dmadev_stats);
+	SKELDMA_TEST_RUN(test_dmadev_completed);
+	SKELDMA_TEST_RUN(test_dmadev_completed_status);
+
+	testsuite_teardown();
+
+	SKELDMA_TEST_INFO("Total tests   : %d\n", total);
+	SKELDMA_TEST_INFO("Passed        : %d\n", passed);
+	SKELDMA_TEST_INFO("Failed        : %d\n", failed);
+
+	if (failed)
+		return -1;
+
+	return 0;
+};
