DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH] test/dma: add test skip status
@ 2023-08-10 11:59 Gowrishankar Muthukrishnan
  2023-08-10 12:36 ` [PATCH v2 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-10-08  1:51 ` [PATCH] test/dma: add test skip status fengchengwen
  0 siblings, 2 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-08-10 11:59 UTC (permalink / raw)
  To: dev; +Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Gowrishankar Muthukrishnan

Add status on skipped tests.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
---
 app/test/test_dmadev_api.c | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 4a181af90a..a1646472b0 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -9,6 +9,8 @@
 #include <rte_test.h>
 #include <rte_dmadev.h>
 
+#include "test.h"
+
 extern int test_dma_api(uint16_t dev_id);
 
 #define DMA_TEST_API_RUN(test) \
@@ -17,9 +19,6 @@ extern int test_dma_api(uint16_t dev_id);
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
 
-#define TEST_SUCCESS 0
-#define TEST_FAILED  -1
-
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
@@ -29,6 +28,7 @@ static char *dst;
 static int total;
 static int passed;
 static int failed;
+static int skipped;
 
 static int
 testsuite_setup(int16_t dev_id)
@@ -49,6 +49,7 @@ testsuite_setup(int16_t dev_id)
 	total = 0;
 	passed = 0;
 	failed = 0;
+	skipped = 0;
 
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
@@ -78,12 +79,22 @@ testsuite_run_test(int (*test)(void), const char *name)
 
 	if (test) {
 		ret = test();
-		if (ret < 0) {
-			failed++;
-			printf("%s Failed\n", name);
-		} else {
+		switch (ret) {
+		case TEST_SUCCESS:
 			passed++;
 			printf("%s Passed\n", name);
+			break;
+		case TEST_FAILED:
+			failed++;
+			printf("%s Failed\n", name);
+			break;
+		case TEST_SKIPPED:
+			skipped++;
+			printf("%s Skipped\n", name);
+			break;
+		default:
+			printf("Invalid test status\n");
+			break;
 		}
 	}
 
@@ -566,6 +577,7 @@ test_dma_api(uint16_t dev_id)
 	printf("Total tests   : %d\n", total);
 	printf("Passed        : %d\n", passed);
 	printf("Failed        : %d\n", failed);
+	printf("Skipped       : %d\n", skipped);
 
 	if (failed)
 		return -1;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v2 0/3] test/dma: add vchan reconfig and SG tests
  2023-08-10 11:59 [PATCH] test/dma: add test skip status Gowrishankar Muthukrishnan
@ 2023-08-10 12:36 ` Gowrishankar Muthukrishnan
  2023-08-10 12:36   ` [PATCH v2 1/3] test/dma: add test skip status Gowrishankar Muthukrishnan
                     ` (3 more replies)
  2023-10-08  1:51 ` [PATCH] test/dma: add test skip status fengchengwen
  1 sibling, 4 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-08-10 12:36 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Vidya Sagar Velumuri,
	Gowrishankar Muthukrishnan

This patch series adds vchan reconfiguration and SG tests.

v2:
 - combined individual test patches with 1/3 as tests can be
   skipped unless supported by PMD.

Gowrishankar Muthukrishnan (3):
  test/dma: add test skip status
  test/dma: test vchan reconfiguration
  test/dma: add SG copy tests

 app/test/test_dmadev.c     | 124 ++++++++++++++++++-
 app/test/test_dmadev_api.c | 238 ++++++++++++++++++++++++++++++++++---
 app/test/test_dmadev_api.h |   2 +
 3 files changed, 343 insertions(+), 21 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v2 1/3] test/dma: add test skip status
  2023-08-10 12:36 ` [PATCH v2 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
@ 2023-08-10 12:36   ` Gowrishankar Muthukrishnan
  2023-08-10 12:36   ` [PATCH v2 2/3] test/dma: test vchan reconfiguration Gowrishankar Muthukrishnan
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-08-10 12:36 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Vidya Sagar Velumuri,
	Gowrishankar Muthukrishnan

Add status on skipped tests.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
---
 app/test/test_dmadev_api.c | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 4a181af90a..a1646472b0 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -9,6 +9,8 @@
 #include <rte_test.h>
 #include <rte_dmadev.h>
 
+#include "test.h"
+
 extern int test_dma_api(uint16_t dev_id);
 
 #define DMA_TEST_API_RUN(test) \
@@ -17,9 +19,6 @@ extern int test_dma_api(uint16_t dev_id);
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
 
-#define TEST_SUCCESS 0
-#define TEST_FAILED  -1
-
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
@@ -29,6 +28,7 @@ static char *dst;
 static int total;
 static int passed;
 static int failed;
+static int skipped;
 
 static int
 testsuite_setup(int16_t dev_id)
@@ -49,6 +49,7 @@ testsuite_setup(int16_t dev_id)
 	total = 0;
 	passed = 0;
 	failed = 0;
+	skipped = 0;
 
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
@@ -78,12 +79,22 @@ testsuite_run_test(int (*test)(void), const char *name)
 
 	if (test) {
 		ret = test();
-		if (ret < 0) {
-			failed++;
-			printf("%s Failed\n", name);
-		} else {
+		switch (ret) {
+		case TEST_SUCCESS:
 			passed++;
 			printf("%s Passed\n", name);
+			break;
+		case TEST_FAILED:
+			failed++;
+			printf("%s Failed\n", name);
+			break;
+		case TEST_SKIPPED:
+			skipped++;
+			printf("%s Skipped\n", name);
+			break;
+		default:
+			printf("Invalid test status\n");
+			break;
 		}
 	}
 
@@ -566,6 +577,7 @@ test_dma_api(uint16_t dev_id)
 	printf("Total tests   : %d\n", total);
 	printf("Passed        : %d\n", passed);
 	printf("Failed        : %d\n", failed);
+	printf("Skipped       : %d\n", skipped);
 
 	if (failed)
 		return -1;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v2 2/3] test/dma: test vchan reconfiguration
  2023-08-10 12:36 ` [PATCH v2 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-08-10 12:36   ` [PATCH v2 1/3] test/dma: add test skip status Gowrishankar Muthukrishnan
@ 2023-08-10 12:36   ` Gowrishankar Muthukrishnan
  2023-08-10 12:36   ` [PATCH v2 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
  2023-11-03 15:38   ` [PATCH v3 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  3 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-08-10 12:36 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Vidya Sagar Velumuri,
	Gowrishankar Muthukrishnan

Reconfigure vchan count and validate if new count is effective.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
---
 app/test/test_dmadev_api.c | 51 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index a1646472b0..5cdd87e162 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -355,6 +355,56 @@ test_dma_start_stop(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_reconfigure(void)
+{
+	struct rte_dma_vchan_conf vchan_conf = { 0 };
+	struct rte_dma_conf dev_conf = { 0 };
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t cfg_vchans;
+	int ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	/* At least two vchans required for the test */
+	if (dev_info.max_vchans < 2)
+		return TEST_SKIPPED;
+
+	/* Setup one vchan for later test */
+	ret = setup_one_vchan();
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	/* Check reconfigure and vchan setup after device stopped */
+	cfg_vchans = dev_conf.nb_vchans = (dev_info.max_vchans - 1);
+
+	ret = rte_dma_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_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+	RTE_TEST_ASSERT_EQUAL(dev_info.nb_vchans, cfg_vchans, "incorrect reconfiguration");
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static int
 test_dma_stats(void)
 {
@@ -567,6 +617,7 @@ test_dma_api(uint16_t dev_id)
 	DMA_TEST_API_RUN(test_dma_configure);
 	DMA_TEST_API_RUN(test_dma_vchan_setup);
 	DMA_TEST_API_RUN(test_dma_start_stop);
+	DMA_TEST_API_RUN(test_dma_reconfigure);
 	DMA_TEST_API_RUN(test_dma_stats);
 	DMA_TEST_API_RUN(test_dma_dump);
 	DMA_TEST_API_RUN(test_dma_completed);
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v2 3/3] test/dma: add SG copy tests
  2023-08-10 12:36 ` [PATCH v2 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-08-10 12:36   ` [PATCH v2 1/3] test/dma: add test skip status Gowrishankar Muthukrishnan
  2023-08-10 12:36   ` [PATCH v2 2/3] test/dma: test vchan reconfiguration Gowrishankar Muthukrishnan
@ 2023-08-10 12:36   ` Gowrishankar Muthukrishnan
  2023-11-03 15:38   ` [PATCH v3 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  3 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-08-10 12:36 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Vidya Sagar Velumuri,
	Gowrishankar Muthukrishnan

Add scatter-gather copy tests.

Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
---
 app/test/test_dmadev.c     | 124 +++++++++++++++++++++++++++-
 app/test/test_dmadev_api.c | 163 ++++++++++++++++++++++++++++++++++---
 app/test/test_dmadev_api.h |   2 +
 3 files changed, 274 insertions(+), 15 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 0736ff2a18..abe970baaf 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -18,7 +18,7 @@
 
 #define ERR_RETURN(...) do { print_err(__func__, __LINE__, __VA_ARGS__); return -1; } while (0)
 
-#define COPY_LEN 1024
+#define COPY_LEN 1032
 
 static struct rte_mempool *pool;
 static uint16_t id_count;
@@ -346,6 +346,120 @@ test_stop_start(int16_t dev_id, uint16_t vchan)
 	return 0;
 }
 
+static int
+test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
+{
+	unsigned int src_len, dst_len, n_sge, len, i, j, k;
+	char orig_src[COPY_LEN], orig_dst[COPY_LEN];
+	struct rte_dma_info info = { 0 };
+	enum rte_dma_status_code status;
+	uint16_t id, n_src, n_dst;
+
+	if (rte_dma_info_get(dev_id, &info) < 0)
+		ERR_RETURN("Failed to get dev info");
+
+	n_sge = RTE_MIN(info.max_sges, TEST_SG_MAX);
+	len = COPY_LEN;
+
+	for (n_src = 1; n_src <= n_sge; n_src++) {
+		src_len = len / n_src;
+		for (n_dst = 1; n_dst <= n_sge; n_dst++) {
+			dst_len = len / n_dst;
+
+			struct rte_dma_sge sg_src[n_sge], sg_dst[n_sge];
+			struct rte_mbuf *src[n_sge], *dst[n_sge];
+			char *src_data[n_sge], *dst_data[n_sge];
+
+			for (i = 0 ; i < COPY_LEN; i++)
+				orig_src[i] = rte_rand() & 0xFF;
+
+			memset(orig_dst, 0, COPY_LEN);
+
+			for (i = 0; i < n_src; i++) {
+				src[i] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(src[i] != NULL);
+				sg_src[i].addr = rte_pktmbuf_iova(src[i]);
+				sg_src[i].length = src_len;
+				src_data[i] = rte_pktmbuf_mtod(src[i], char *);
+			}
+
+			for (k = 0; k < n_dst; k++) {
+				dst[k] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(dst[k] != NULL);
+				sg_dst[k].addr = rte_pktmbuf_iova(dst[k]);
+				sg_dst[k].length = dst_len;
+				dst_data[k] = rte_pktmbuf_mtod(dst[k], char *);
+			}
+
+			for (i = 0; i < n_src; i++) {
+				for (j = 0; j < src_len; j++)
+					src_data[i][j] = orig_src[i * src_len + j];
+			}
+
+			for (k = 0; k < n_dst; k++)
+				memset(dst_data[k], 0, dst_len);
+
+			printf("\tsrc segs: %2d [seg len: %4d] - dst segs: %2d [seg len : %4d]\n",
+				n_src, src_len, n_dst, dst_len);
+
+			id = rte_dma_copy_sg(dev_id, vchan, sg_src, sg_dst, n_src, n_dst,
+					     RTE_DMA_OP_FLAG_SUBMIT);
+
+			if (id != id_count)
+				ERR_RETURN("Error with rte_dma_copy_sg, got %u, expected %u\n",
+					id, id_count);
+
+			/* Give time for copy to finish, then check it was done */
+			await_hw(dev_id, vchan);
+
+			for (k = 0; k < n_dst; k++)
+				memcpy((&orig_dst[0] + k * dst_len), dst_data[k], dst_len);
+
+			if (memcmp(orig_src, orig_dst, COPY_LEN))
+				ERR_RETURN("Data mismatch");
+
+			/* Verify completion */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 1)
+				ERR_RETURN("Error with rte_dma_completed\n");
+
+			/* Verify expected index(id_count) */
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received, %u [expected %u]\n",
+						id, id_count);
+
+			/* Check for completed and id when no job done */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed when no job done\n");
+
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+					   id, id_count);
+
+			/* Check for completed_status and id when no job done */
+			id = ~id;
+			if (rte_dma_completed_status(dev_id, vchan, 1, &id, &status) != 0)
+				ERR_RETURN("Error with rte_dma_completed_status when no job done\n");
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+						id, 0);
+
+			for (i = 0; i < n_src; i++)
+				rte_pktmbuf_free(src[i]);
+			for (i = 0; i < n_dst; i++)
+				rte_pktmbuf_free(dst[i]);
+
+			/* Verify that completion returns nothing more */
+			if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed in empty check\n");
+
+			id_count++;
+		}
+	}
+	return 0;
+}
+
 /* Failure handling test cases - global macros and variables for those tests*/
 #define COMP_BURST_SZ	16
 #define OPT_FENCE(idx) ((fence && idx == 8) ? RTE_DMA_OP_FLAG_FENCE : 0)
@@ -852,7 +966,7 @@ test_dmadev_instance(int16_t dev_id)
 			TEST_RINGSIZE * 2, /* n == num elements */
 			32,  /* cache size */
 			0,   /* priv size */
-			2048, /* data room size */
+			COPY_LEN + RTE_PKTMBUF_HEADROOM, /* data room size */
 			info.numa_node);
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
@@ -865,6 +979,12 @@ test_dmadev_instance(int16_t dev_id)
 	if (runtest("stop-start", test_stop_start, 1, dev_id, vchan, CHECK_ERRS) < 0)
 		goto err;
 
+	/* run SG test cases */
+	if ((info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		printf("DMA Dev %u: No SG support, skipping SG copy tests\n", dev_id);
+	else if (runtest("sg_copy", test_enqueue_sg_copies, 1, dev_id, vchan, CHECK_ERRS) < 0)
+		goto err;
+
 	/* run some burst capacity tests */
 	if (rte_dma_burst_capacity(dev_id, vchan) < 64)
 		printf("DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 5cdd87e162..0934cc81cc 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -10,8 +10,7 @@
 #include <rte_dmadev.h>
 
 #include "test.h"
-
-extern int test_dma_api(uint16_t dev_id);
+#include "test_dmadev_api.h"
 
 #define DMA_TEST_API_RUN(test) \
 	testsuite_run_test(test, #test)
@@ -24,6 +23,8 @@ static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
+static char *src_sg[TEST_SG_MAX];
+static char *dst_sg[TEST_SG_MAX];
 
 static int total;
 static int passed;
@@ -35,17 +36,27 @@ testsuite_setup(int16_t dev_id)
 {
 	test_dev_id = dev_id;
 	invalid_dev_id = -1;
+	int i, rc = 0;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		src_sg[i] = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
+		if (src_sg[i] == NULL) {
+			rc = -ENOMEM;
+			goto exit;
+		}
 
-	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) {
-		rte_free(src);
-		src = NULL;
-		return -ENOMEM;
+		dst_sg[i] = rte_malloc("dmadev_test_dst", TEST_MEMCPY_SIZE, 0);
+		if (dst_sg[i] == NULL) {
+			rte_free(src_sg[i]);
+			src_sg[i] = NULL;
+			rc = -ENOMEM;
+			goto exit;
+		}
 	}
 
+	src = src_sg[0];
+	dst = dst_sg[0];
+
 	total = 0;
 	passed = 0;
 	failed = 0;
@@ -56,15 +67,29 @@ testsuite_setup(int16_t dev_id)
 	 */
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_CRIT);
 
-	return 0;
+	return rc;
+exit:
+	while (--i >= 0) {
+		rte_free(src_sg[i]);
+		rte_free(dst_sg[i]);
+	}
+
+	return rc;
 }
 
 static void
 testsuite_teardown(void)
 {
-	rte_free(src);
+	int i;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		rte_free(src_sg[i]);
+		src_sg[i] = NULL;
+		rte_free(dst_sg[i]);
+		dst_sg[i] = NULL;
+	}
+
 	src = NULL;
-	rte_free(dst);
 	dst = NULL;
 	/* Ensure the dmadev is stopped. */
 	rte_dma_stop(test_dev_id);
@@ -484,6 +509,37 @@ verify_memory(void)
 	return 0;
 }
 
+static void
+sg_memory_setup(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++)
+			src_sg[i][j] = (char)j;
+
+		memset(dst_sg[i], 0, TEST_MEMCPY_SIZE);
+	}
+}
+
+static int
+sg_memory_verify(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++) {
+			if (src_sg[i][j] == dst_sg[i][j])
+				continue;
+
+			RTE_TEST_ASSERT_EQUAL(src_sg[i][j], dst_sg[i][j], "Failed to copy memory, %d %d",
+				src_sg[i][j], dst_sg[i][j]);
+		}
+	}
+
+	return 0;
+}
+
 static int
 test_dma_completed(void)
 {
@@ -598,6 +654,86 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_sg(void)
+{
+	struct rte_dma_sge src_sge[TEST_SG_MAX], dst_sge[TEST_SG_MAX];
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t last_idx = -1;
+	bool has_error = true;
+	int n_sge, i, ret;
+	uint16_t cpl_ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		return TEST_SKIPPED;
+
+	n_sge = RTE_MIN(dev_info.max_sges, TEST_SG_MAX);
+
+	ret = setup_one_vchan();
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	for (i = 0; i < n_sge; i++) {
+		src_sge[i].addr = rte_malloc_virt2iova(src_sg[i]);
+		src_sge[i].length = TEST_MEMCPY_SIZE;
+		dst_sge[i].addr = rte_malloc_virt2iova(dst_sg[i]);
+		dst_sge[i].length = TEST_MEMCPY_SIZE;
+	}
+
+	sg_memory_setup(n_sge);
+
+	/* Check enqueue without submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge, 0);
+	RTE_TEST_ASSERT_EQUAL(ret, 0, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_completed(test_dev_id, 0, 1, &last_idx, &has_error);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 0, "Failed to get completed");
+
+	/* Check DMA submit */
+	ret = rte_dma_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_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	sg_memory_setup(n_sge);
+
+	/* Check for enqueue with submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge,
+			      RTE_DMA_OP_FLAG_SUBMIT);
+	RTE_TEST_ASSERT_EQUAL(ret, 1, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	/* Stop dmadev to make sure dmadev to a known state */
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 int
 test_dma_api(uint16_t dev_id)
 {
@@ -622,6 +758,7 @@ test_dma_api(uint16_t dev_id)
 	DMA_TEST_API_RUN(test_dma_dump);
 	DMA_TEST_API_RUN(test_dma_completed);
 	DMA_TEST_API_RUN(test_dma_completed_status);
+	DMA_TEST_API_RUN(test_dma_sg);
 
 	testsuite_teardown();
 
diff --git a/app/test/test_dmadev_api.h b/app/test/test_dmadev_api.h
index 33fbc5bd41..10ab925f80 100644
--- a/app/test/test_dmadev_api.h
+++ b/app/test/test_dmadev_api.h
@@ -2,4 +2,6 @@
  * Copyright(c) 2021 HiSilicon Limited
  */
 
+#define TEST_SG_MAX 4
+
 int test_dma_api(uint16_t dev_id);
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] test/dma: add test skip status
  2023-08-10 11:59 [PATCH] test/dma: add test skip status Gowrishankar Muthukrishnan
  2023-08-10 12:36 ` [PATCH v2 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
@ 2023-10-08  1:51 ` fengchengwen
  1 sibling, 0 replies; 39+ messages in thread
From: fengchengwen @ 2023-10-08  1:51 UTC (permalink / raw)
  To: Gowrishankar Muthukrishnan, dev; +Cc: anoobj, Vamsi Attunuru

Hi Gowrishankar,

It was already support in test framework (unit_test_suite), I suggest not invent.
Could you help refactoring the test_dmadev (use the test framework) ?

PS: could refer test_fbarray.c

Thanks.

On 2023/8/10 19:59, Gowrishankar Muthukrishnan wrote:
> Add status on skipped tests.
> 
> Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
> ---
>  app/test/test_dmadev_api.c | 26 +++++++++++++++++++-------
>  1 file changed, 19 insertions(+), 7 deletions(-)
> 
> diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
> index 4a181af90a..a1646472b0 100644
> --- a/app/test/test_dmadev_api.c
> +++ b/app/test/test_dmadev_api.c
> @@ -9,6 +9,8 @@
>  #include <rte_test.h>
>  #include <rte_dmadev.h>
>  
> +#include "test.h"
> +
>  extern int test_dma_api(uint16_t dev_id);
>  
>  #define DMA_TEST_API_RUN(test) \
> @@ -17,9 +19,6 @@ extern int test_dma_api(uint16_t dev_id);
>  #define TEST_MEMCPY_SIZE	1024
>  #define TEST_WAIT_US_VAL	50000
>  
> -#define TEST_SUCCESS 0
> -#define TEST_FAILED  -1
> -
>  static int16_t test_dev_id;
>  static int16_t invalid_dev_id;
>  
> @@ -29,6 +28,7 @@ static char *dst;
>  static int total;
>  static int passed;
>  static int failed;
> +static int skipped;
>  
>  static int
>  testsuite_setup(int16_t dev_id)
> @@ -49,6 +49,7 @@ testsuite_setup(int16_t dev_id)
>  	total = 0;
>  	passed = 0;
>  	failed = 0;
> +	skipped = 0;
>  
>  	/* Set dmadev log level to critical to suppress unnecessary output
>  	 * during API tests.
> @@ -78,12 +79,22 @@ testsuite_run_test(int (*test)(void), const char *name)
>  
>  	if (test) {
>  		ret = test();
> -		if (ret < 0) {
> -			failed++;
> -			printf("%s Failed\n", name);
> -		} else {
> +		switch (ret) {
> +		case TEST_SUCCESS:
>  			passed++;
>  			printf("%s Passed\n", name);
> +			break;
> +		case TEST_FAILED:
> +			failed++;
> +			printf("%s Failed\n", name);
> +			break;
> +		case TEST_SKIPPED:
> +			skipped++;
> +			printf("%s Skipped\n", name);
> +			break;
> +		default:
> +			printf("Invalid test status\n");
> +			break;
>  		}
>  	}
>  
> @@ -566,6 +577,7 @@ test_dma_api(uint16_t dev_id)
>  	printf("Total tests   : %d\n", total);
>  	printf("Passed        : %d\n", passed);
>  	printf("Failed        : %d\n", failed);
> +	printf("Skipped       : %d\n", skipped);
>  
>  	if (failed)
>  		return -1;
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v3 0/3] test/dma: add vchan reconfig and SG tests
  2023-08-10 12:36 ` [PATCH v2 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
                     ` (2 preceding siblings ...)
  2023-08-10 12:36   ` [PATCH v2 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
@ 2023-11-03 15:38   ` Gowrishankar Muthukrishnan
  2023-11-03 15:38     ` [PATCH v3 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
                       ` (3 more replies)
  3 siblings, 4 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-03 15:38 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

This patch series reworks DMA tests to follow unit test framework
followed by new vchan reconfig and SG tests.

v3:
 - followed unit test framework.

Gowrishankar Muthukrishnan (3):
  test/dma: use unit test framework
  test/dma: test vchan reconfiguration
  test/dma: add SG copy tests

 app/test/test_dmadev.c     | 372 +++++++++++++++++++++++++++++++------
 app/test/test_dmadev_api.c | 309 ++++++++++++++++++++++--------
 app/test/test_dmadev_api.h |   2 +
 3 files changed, 547 insertions(+), 136 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v3 1/3] test/dma: use unit test framework
  2023-11-03 15:38   ` [PATCH v3 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
@ 2023-11-03 15:38     ` Gowrishankar Muthukrishnan
  2023-11-06  3:47       ` fengchengwen
  2023-11-03 15:38     ` [PATCH v3 2/3] test/dma: test vchan reconfiguration Gowrishankar Muthukrishnan
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-03 15:38 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Use unit test framework to execute DMA tests.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Suggested-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_dmadev.c     | 240 ++++++++++++++++++++++++++++---------
 app/test/test_dmadev_api.c |  89 ++++----------
 2 files changed, 212 insertions(+), 117 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 216f84b6bb..780941fc1e 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -22,7 +22,9 @@
 #define COPY_LEN 1024
 
 static struct rte_mempool *pool;
+static int16_t test_dev_id;
 static uint16_t id_count;
+static int vchan;
 
 enum {
 	TEST_PARAM_REMOTE_ADDR = 0,
@@ -61,13 +63,35 @@ print_err(const char *func, int lineno, const char *format, ...)
 	va_end(ap);
 }
 
+struct runtest_param {
+	const char *printable;
+	int (*test_fn)(int16_t dev_id, uint16_t vchan);
+	int iterations;
+	int16_t dev_id;
+	uint16_t vchan;
+	bool check_err_stats;
+};
+
 static int
-runtest(const char *printable, int (*test_fn)(int16_t dev_id, uint16_t vchan), int iterations,
-		int16_t dev_id, uint16_t vchan, bool check_err_stats)
+runtest(const void *args)
 {
+	int (*test_fn)(int16_t dev_id, uint16_t vchan);
+	const struct runtest_param *param = args;
 	struct rte_dma_stats stats;
+	const char *printable;
+	bool check_err_stats;
+	int iterations;
+	int16_t dev_id;
+	uint16_t vchan;
 	int i;
 
+	printable = param->printable;
+	iterations = param->iterations;
+	dev_id = param->dev_id;
+	vchan = param->vchan;
+	check_err_stats = param->check_err_stats;
+	test_fn = param->test_fn;
+
 	rte_dma_stats_reset(dev_id, vchan);
 	printf("DMA Dev %d: Running %s Tests %s\n", dev_id, printable,
 			check_err_stats ? " " : "(errors expected)");
@@ -918,9 +942,21 @@ test_m2d_auto_free(int16_t dev_id, uint16_t vchan)
 }
 
 static int
-test_dmadev_instance(int16_t dev_id)
+test_dmadev_burst_setup(void)
 {
-#define CHECK_ERRS    true
+	if (rte_dma_burst_capacity(test_dev_id, vchan) < 64) {
+		printf("DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
+				test_dev_id);
+		return TEST_SKIPPED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_setup(void)
+{
+	int16_t dev_id = test_dev_id;
 	struct rte_dma_stats stats;
 	struct rte_dma_info info;
 	const struct rte_dma_conf conf = { .nb_vchans = 1};
@@ -928,16 +964,12 @@ test_dmadev_instance(int16_t dev_id)
 			.direction = RTE_DMA_DIR_MEM_TO_MEM,
 			.nb_desc = TEST_RINGSIZE,
 	};
-	const int vchan = 0;
 	int ret;
 
 	ret = rte_dma_info_get(dev_id, &info);
 	if (ret != 0)
 		ERR_RETURN("Error with rte_dma_info_get()\n");
 
-	printf("\n### Test dmadev instance %u [%s]\n",
-			dev_id, info.dev_name);
-
 	if (info.max_vchans < 1)
 		ERR_RETURN("Error, no channels available on device id %u\n", dev_id);
 
@@ -976,20 +1008,123 @@ test_dmadev_instance(int16_t dev_id)
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
 
+	return 0;
+}
+
+static void
+test_dmadev_teardown(void)
+{
+	rte_mempool_free(pool);
+	rte_dma_stop(test_dev_id);
+	rte_dma_stats_reset(test_dev_id, vchan);
+	test_dev_id = -EINVAL;
+}
+
+static int
+test_dmadev_instance(int16_t dev_id)
+{
+#define CHECK_ERRS    true
+	enum {
+		  TEST_COPY = 0,
+		  TEST_START,
+		  TEST_BURST,
+		  TEST_ERR,
+		  TEST_FILL,
+		  TEST_M2D,
+		  TEST_END
+	};
+
+	struct runtest_param param[TEST_END];
+	struct rte_dma_info dev_info;
+	struct unit_test_suite *ts;
+	struct unit_test_case *tc;
+	int ret;
+
+	if (rte_dma_info_get(dev_id, &dev_info) < 0)
+		return TEST_SKIPPED;
+
+	test_dev_id = dev_id;
+	vchan = 0;
+
+	ts = calloc(1, sizeof(struct unit_test_suite)
+				+ sizeof(struct unit_test_case) * (TEST_END + 1));
+
+	ts->suite_name = "DMA dev instance testsuite";
+	ts->setup = test_dmadev_setup;
+	ts->teardown = test_dmadev_teardown;
+
+	param[TEST_COPY].printable = "copy";
+	param[TEST_COPY].test_fn = test_enqueue_copies;
+	param[TEST_COPY].iterations = 640;
+	param[TEST_COPY].dev_id = dev_id;
+	param[TEST_COPY].vchan = vchan;
+	param[TEST_COPY].check_err_stats = CHECK_ERRS;
+
+	param[TEST_START].printable = "stop-start";
+	param[TEST_START].test_fn = test_stop_start;
+	param[TEST_START].iterations = 1;
+	param[TEST_START].dev_id = dev_id;
+	param[TEST_START].vchan = vchan;
+	param[TEST_START].check_err_stats = CHECK_ERRS;
+
+	param[TEST_BURST].printable = "burst capacity";
+	param[TEST_BURST].test_fn = test_burst_capacity;
+	param[TEST_BURST].iterations = 1;
+	param[TEST_BURST].dev_id = dev_id;
+	param[TEST_BURST].vchan = vchan;
+	param[TEST_BURST].check_err_stats = CHECK_ERRS;
+
+	param[TEST_ERR].printable = "error handling";
+	param[TEST_ERR].test_fn = test_completion_handling;
+	param[TEST_ERR].iterations = 1;
+	param[TEST_ERR].dev_id = dev_id;
+	param[TEST_ERR].vchan = vchan;
+	param[TEST_ERR].check_err_stats = CHECK_ERRS;
+
+	param[TEST_FILL].printable = "fill";
+	param[TEST_FILL].test_fn = test_enqueue_fill;
+	param[TEST_FILL].iterations = 1;
+	param[TEST_FILL].dev_id = dev_id;
+	param[TEST_FILL].vchan = vchan;
+	param[TEST_FILL].check_err_stats = CHECK_ERRS;
+
+	param[TEST_M2D].printable = "m2d_auto_free";
+	param[TEST_M2D].test_fn = test_m2d_auto_free;
+	param[TEST_M2D].iterations = 128;
+	param[TEST_M2D].dev_id = dev_id;
+	param[TEST_M2D].vchan = vchan;
+	param[TEST_M2D].check_err_stats = CHECK_ERRS;
+
+	for (int i = 0; i < TEST_END; i++) {
+		tc = &ts->unit_test_cases[i];
+		tc->setup = NULL;
+		tc->teardown = NULL;
+		tc->testcase = NULL;
+		tc->testcase_with_data = runtest;
+		tc->data = &param[i];
+		tc->enabled = 0;
+	}
+
+	tc = &ts->unit_test_cases[TEST_END];
+	tc->setup = NULL;
+	tc->teardown = NULL;
+	tc->testcase = NULL;
+	tc->testcase_with_data = NULL;
+	tc->data = NULL;
+	tc->enabled = 0;
+
+	printf("\n### Test dmadev instance %u [%s]\n",
+		   dev_id, dev_info.dev_name);
+
 	/* run the test cases, use many iterations to ensure UINT16_MAX id wraparound */
-	if (runtest("copy", test_enqueue_copies, 640, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
+	ts->unit_test_cases[TEST_COPY].enabled = 1;
 
 	/* run tests stopping/starting devices and check jobs still work after restart */
-	if (runtest("stop-start", test_stop_start, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
+	ts->unit_test_cases[TEST_START].enabled = 1;
 
 	/* run some burst capacity tests */
-	if (rte_dma_burst_capacity(dev_id, vchan) < 64)
-		printf("DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
-				dev_id);
-	else if (runtest("burst capacity", test_burst_capacity, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
+	ts->unit_test_cases[TEST_BURST].setup = test_dmadev_burst_setup;
+	ts->unit_test_cases[TEST_BURST].enabled = 1;
 
 	/* to test error handling we can provide null pointers for source or dest in copies. This
 	 * requires VA mode in DPDK, since NULL(0) is a valid physical address.
@@ -997,55 +1132,40 @@ test_dmadev_instance(int16_t dev_id)
 	 */
 	if (rte_eal_iova_mode() != RTE_IOVA_VA)
 		printf("DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n", dev_id);
-	else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
+	else if ((dev_info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
 		printf("DMA Dev %u: device does not report errors, skipping error handling tests\n",
 				dev_id);
-	else if (runtest("error handling", test_completion_handling, 1,
-			dev_id, vchan, !CHECK_ERRS) < 0)
-		goto err;
+	else
+		ts->unit_test_cases[TEST_ERR].enabled = 1;
 
-	if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0)
+	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0)
 		printf("DMA Dev %u: No device fill support, skipping fill tests\n", dev_id);
-	else if (runtest("fill", test_enqueue_fill, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
+	else
+		ts->unit_test_cases[TEST_FILL].enabled = 1;
 
-	if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
+	if ((dev_info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
 	    dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
-		if (runtest("m2d_auto_free", test_m2d_auto_free, 128, dev_id, vchan,
-			    CHECK_ERRS) < 0)
-			goto err;
+		ts->unit_test_cases[TEST_M2D].enabled = 1;
 	}
 
-	rte_mempool_free(pool);
-
-	if (rte_dma_stop(dev_id) < 0)
-		ERR_RETURN("Error stopping device %u\n", dev_id);
-
-	rte_dma_stats_reset(dev_id, vchan);
-	return 0;
+	ret = unit_test_suite_runner(ts);
+	test_dev_id = -EINVAL;
+	free(ts);
 
-err:
-	rte_mempool_free(pool);
-	rte_dma_stop(dev_id);
-	return -1;
+	return ret;
 }
 
 static int
-test_apis(void)
+test_apis(const void *args)
 {
-	const char *pmd = "dma_skeleton";
-	int id;
-	int ret;
+	const int16_t dev_id = *(const int16_t *)args;
+	struct rte_dma_info dev_info;
 
-	/* attempt to create skeleton instance - ignore errors due to one being already present */
-	rte_vdev_init(pmd, NULL);
-	id = rte_dma_get_dev_id_by_name(pmd);
-	if (id < 0)
+	if (rte_dma_info_get(dev_id, &dev_info) < 0)
 		return TEST_SKIPPED;
-	printf("\n### Test dmadev infrastructure using skeleton driver\n");
-	ret = test_dma_api(id);
 
-	return ret;
+	printf("\n### Test dmadev infrastructure using %s\n", dev_info.dev_name);
+	return test_dma_api(dev_id);
 }
 
 static void
@@ -1088,16 +1208,28 @@ parse_dma_env_var(void)
 static int
 test_dma(void)
 {
-	int i;
+	const char *pmd = "dma_skeleton";
+	int i,  avail;
 
 	parse_dma_env_var();
 
+	/* attempt to create skeleton instance - ignore errors due to one being already present*/
+	rte_vdev_init(pmd, NULL);
+	i = rte_dma_get_dev_id_by_name(pmd);
+	if (i < 0)
+		return TEST_SKIPPED;
+
 	/* basic sanity on dmadev infrastructure */
-	if (test_apis() < 0)
+	if (test_apis(&i) < 0)
 		ERR_RETURN("Error performing API tests\n");
 
-	if (rte_dma_count_avail() == 0)
-		return TEST_SKIPPED;
+	avail = rte_dma_count_avail();
+	if (avail == 0)
+		return 0;
+
+	i = rte_dma_next_dev(0);
+	if (avail > 1 && test_apis(&i) < 0)
+		ERR_RETURN("Error performing API tests\n");
 
 	RTE_DMA_FOREACH_DEV(i)
 		if (test_dmadev_instance(i) < 0)
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 4a181af90a..da8fddb3ca 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -9,31 +9,22 @@
 #include <rte_test.h>
 #include <rte_dmadev.h>
 
-extern int test_dma_api(uint16_t dev_id);
+#include "test.h"
 
-#define DMA_TEST_API_RUN(test) \
-	testsuite_run_test(test, #test)
+extern int test_dma_api(uint16_t dev_id);
 
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
 
-#define TEST_SUCCESS 0
-#define TEST_FAILED  -1
-
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
 
-static int total;
-static int passed;
-static int failed;
-
 static int
-testsuite_setup(int16_t dev_id)
+testsuite_setup(void)
 {
-	test_dev_id = dev_id;
 	invalid_dev_id = -1;
 
 	src = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
@@ -46,10 +37,6 @@ testsuite_setup(int16_t dev_id)
 		return -ENOMEM;
 	}
 
-	total = 0;
-	passed = 0;
-	failed = 0;
-
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
 	 */
@@ -71,25 +58,6 @@ testsuite_teardown(void)
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_INFO);
 }
 
-static void
-testsuite_run_test(int (*test)(void), const char *name)
-{
-	int ret = 0;
-
-	if (test) {
-		ret = test();
-		if (ret < 0) {
-			failed++;
-			printf("%s Failed\n", name);
-		} else {
-			passed++;
-			printf("%s Passed\n", name);
-		}
-	}
-
-	total++;
-}
-
 static int
 test_dma_get_dev_id_by_name(void)
 {
@@ -301,7 +269,7 @@ setup_one_vchan(void)
 
 	ret = rte_dma_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;
+	dev_conf.nb_vchans = 1;
 	ret = rte_dma_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;
@@ -537,38 +505,33 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static struct unit_test_suite dma_api_testsuite = {
+	.suite_name = "DMA API Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE(test_dma_get_dev_id_by_name),
+		TEST_CASE(test_dma_is_valid_dev),
+		TEST_CASE(test_dma_count),
+		TEST_CASE(test_dma_info_get),
+		TEST_CASE(test_dma_configure),
+		TEST_CASE(test_dma_vchan_setup),
+		TEST_CASE(test_dma_start_stop),
+		TEST_CASE(test_dma_stats),
+		TEST_CASE(test_dma_dump),
+		TEST_CASE(test_dma_completed),
+		TEST_CASE(test_dma_completed_status),
+		TEST_CASES_END()
+	}
+};
+
 int
 test_dma_api(uint16_t dev_id)
 {
-	int ret = testsuite_setup(dev_id);
-	if (ret) {
-		printf("testsuite setup fail!\n");
-		return -1;
-	}
+	test_dev_id = dev_id;
 
 	/* If the testcase exit successfully, ensure that the test dmadev exist
 	 * and the dmadev is in the stopped state.
 	 */
-	DMA_TEST_API_RUN(test_dma_get_dev_id_by_name);
-	DMA_TEST_API_RUN(test_dma_is_valid_dev);
-	DMA_TEST_API_RUN(test_dma_count);
-	DMA_TEST_API_RUN(test_dma_info_get);
-	DMA_TEST_API_RUN(test_dma_configure);
-	DMA_TEST_API_RUN(test_dma_vchan_setup);
-	DMA_TEST_API_RUN(test_dma_start_stop);
-	DMA_TEST_API_RUN(test_dma_stats);
-	DMA_TEST_API_RUN(test_dma_dump);
-	DMA_TEST_API_RUN(test_dma_completed);
-	DMA_TEST_API_RUN(test_dma_completed_status);
-
-	testsuite_teardown();
-
-	printf("Total tests   : %d\n", total);
-	printf("Passed        : %d\n", passed);
-	printf("Failed        : %d\n", failed);
-
-	if (failed)
-		return -1;
-
-	return 0;
+	return unit_test_suite_runner(&dma_api_testsuite);
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v3 2/3] test/dma: test vchan reconfiguration
  2023-11-03 15:38   ` [PATCH v3 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-11-03 15:38     ` [PATCH v3 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
@ 2023-11-03 15:38     ` Gowrishankar Muthukrishnan
  2023-11-06  4:06       ` fengchengwen
  2023-11-03 15:38     ` [PATCH v3 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
  2023-11-13 12:53     ` [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  3 siblings, 1 reply; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-03 15:38 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Reconfigure vchan count and validate if new count is effective.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
---
 app/test/test_dmadev_api.c | 63 +++++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 8 deletions(-)

diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index da8fddb3ca..aa07d2b359 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -260,7 +260,7 @@ test_dma_vchan_setup(void)
 }
 
 static int
-setup_one_vchan(void)
+setup_vchan(int nb_vchans)
 {
 	struct rte_dma_vchan_conf vchan_conf = { 0 };
 	struct rte_dma_info dev_info = { 0 };
@@ -269,13 +269,15 @@ setup_one_vchan(void)
 
 	ret = rte_dma_info_get(test_dev_id, &dev_info);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
-	dev_conf.nb_vchans = 1;
+	dev_conf.nb_vchans = nb_vchans;
 	ret = rte_dma_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_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
-	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan, %d", ret);
+	for (int i = 0; i < nb_vchans; i++) {
+		ret = rte_dma_vchan_setup(test_dev_id, i, &vchan_conf);
+		RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan %d, %d", i, ret);
+	}
 
 	return TEST_SUCCESS;
 }
@@ -294,7 +296,7 @@ test_dma_start_stop(void)
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -312,6 +314,50 @@ test_dma_start_stop(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_reconfigure(void)
+{
+	struct rte_dma_conf dev_conf = { 0 };
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t cfg_vchans;
+	int ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	/* At least two vchans required for the test */
+	if (dev_info.max_vchans < 2)
+		return TEST_SKIPPED;
+
+	/* Setup one vchan for later test */
+	ret = setup_vchan(1);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	/* Check reconfigure and vchan setup after device stopped */
+	cfg_vchans = dev_conf.nb_vchans = (dev_info.max_vchans - 1);
+
+	ret = setup_vchan(cfg_vchans);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+	RTE_TEST_ASSERT_EQUAL(dev_info.nb_vchans, cfg_vchans, "incorrect reconfiguration");
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static int
 test_dma_stats(void)
 {
@@ -328,7 +374,7 @@ test_dma_stats(void)
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	/* Check for invalid vchan */
@@ -400,7 +446,7 @@ test_dma_completed(void)
 	int ret;
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -459,7 +505,7 @@ test_dma_completed_status(void)
 	int ret;
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -517,6 +563,7 @@ static struct unit_test_suite dma_api_testsuite = {
 		TEST_CASE(test_dma_configure),
 		TEST_CASE(test_dma_vchan_setup),
 		TEST_CASE(test_dma_start_stop),
+		TEST_CASE(test_dma_reconfigure),
 		TEST_CASE(test_dma_stats),
 		TEST_CASE(test_dma_dump),
 		TEST_CASE(test_dma_completed),
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v3 3/3] test/dma: add SG copy tests
  2023-11-03 15:38   ` [PATCH v3 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-11-03 15:38     ` [PATCH v3 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
  2023-11-03 15:38     ` [PATCH v3 2/3] test/dma: test vchan reconfiguration Gowrishankar Muthukrishnan
@ 2023-11-03 15:38     ` Gowrishankar Muthukrishnan
  2023-11-06  6:43       ` fengchengwen
  2023-11-13 12:53     ` [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  3 siblings, 1 reply; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-03 15:38 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Add scatter-gather copy tests.

Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
---
 app/test/test_dmadev.c     | 132 +++++++++++++++++++++++++++++-
 app/test/test_dmadev_api.c | 163 ++++++++++++++++++++++++++++++++++---
 app/test/test_dmadev_api.h |   2 +
 3 files changed, 283 insertions(+), 14 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 780941fc1e..a2f3a7f999 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -19,7 +19,7 @@
 #define ERR_RETURN(...) do { print_err(__func__, __LINE__, __VA_ARGS__); return -1; } while (0)
 
 #define TEST_RINGSIZE 512
-#define COPY_LEN 1024
+#define COPY_LEN 1032
 
 static struct rte_mempool *pool;
 static int16_t test_dev_id;
@@ -396,6 +396,120 @@ test_stop_start(int16_t dev_id, uint16_t vchan)
 	return 0;
 }
 
+static int
+test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
+{
+	unsigned int src_len, dst_len, n_sge, len, i, j, k;
+	char orig_src[COPY_LEN], orig_dst[COPY_LEN];
+	struct rte_dma_info info = { 0 };
+	enum rte_dma_status_code status;
+	uint16_t id, n_src, n_dst;
+
+	if (rte_dma_info_get(dev_id, &info) < 0)
+		ERR_RETURN("Failed to get dev info");
+
+	n_sge = RTE_MIN(info.max_sges, TEST_SG_MAX);
+	len = COPY_LEN;
+
+	for (n_src = 1; n_src <= n_sge; n_src++) {
+		src_len = len / n_src;
+		for (n_dst = 1; n_dst <= n_sge; n_dst++) {
+			dst_len = len / n_dst;
+
+			struct rte_dma_sge sg_src[n_sge], sg_dst[n_sge];
+			struct rte_mbuf *src[n_sge], *dst[n_sge];
+			char *src_data[n_sge], *dst_data[n_sge];
+
+			for (i = 0 ; i < COPY_LEN; i++)
+				orig_src[i] = rte_rand() & 0xFF;
+
+			memset(orig_dst, 0, COPY_LEN);
+
+			for (i = 0; i < n_src; i++) {
+				src[i] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(src[i] != NULL);
+				sg_src[i].addr = rte_pktmbuf_iova(src[i]);
+				sg_src[i].length = src_len;
+				src_data[i] = rte_pktmbuf_mtod(src[i], char *);
+			}
+
+			for (k = 0; k < n_dst; k++) {
+				dst[k] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(dst[k] != NULL);
+				sg_dst[k].addr = rte_pktmbuf_iova(dst[k]);
+				sg_dst[k].length = dst_len;
+				dst_data[k] = rte_pktmbuf_mtod(dst[k], char *);
+			}
+
+			for (i = 0; i < n_src; i++) {
+				for (j = 0; j < src_len; j++)
+					src_data[i][j] = orig_src[i * src_len + j];
+			}
+
+			for (k = 0; k < n_dst; k++)
+				memset(dst_data[k], 0, dst_len);
+
+			printf("\tsrc segs: %2d [seg len: %4d] - dst segs: %2d [seg len : %4d]\n",
+				n_src, src_len, n_dst, dst_len);
+
+			id = rte_dma_copy_sg(dev_id, vchan, sg_src, sg_dst, n_src, n_dst,
+					     RTE_DMA_OP_FLAG_SUBMIT);
+
+			if (id != id_count)
+				ERR_RETURN("Error with rte_dma_copy_sg, got %u, expected %u\n",
+					id, id_count);
+
+			/* Give time for copy to finish, then check it was done */
+			await_hw(dev_id, vchan);
+
+			for (k = 0; k < n_dst; k++)
+				memcpy((&orig_dst[0] + k * dst_len), dst_data[k], dst_len);
+
+			if (memcmp(orig_src, orig_dst, COPY_LEN))
+				ERR_RETURN("Data mismatch");
+
+			/* Verify completion */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 1)
+				ERR_RETURN("Error with rte_dma_completed\n");
+
+			/* Verify expected index(id_count) */
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received, %u [expected %u]\n",
+						id, id_count);
+
+			/* Check for completed and id when no job done */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed when no job done\n");
+
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+					   id, id_count);
+
+			/* Check for completed_status and id when no job done */
+			id = ~id;
+			if (rte_dma_completed_status(dev_id, vchan, 1, &id, &status) != 0)
+				ERR_RETURN("Error with rte_dma_completed_status when no job done\n");
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+						id, 0);
+
+			for (i = 0; i < n_src; i++)
+				rte_pktmbuf_free(src[i]);
+			for (i = 0; i < n_dst; i++)
+				rte_pktmbuf_free(dst[i]);
+
+			/* Verify that completion returns nothing more */
+			if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed in empty check\n");
+
+			id_count++;
+		}
+	}
+	return 0;
+}
+
 /* Failure handling test cases - global macros and variables for those tests*/
 #define COMP_BURST_SZ	16
 #define OPT_FENCE(idx) ((fence && idx == 8) ? RTE_DMA_OP_FLAG_FENCE : 0)
@@ -1003,7 +1117,7 @@ test_dmadev_setup(void)
 			TEST_RINGSIZE * 2, /* n == num elements */
 			32,  /* cache size */
 			0,   /* priv size */
-			2048, /* data room size */
+			COPY_LEN + RTE_PKTMBUF_HEADROOM, /* data room size */
 			info.numa_node);
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
@@ -1026,6 +1140,7 @@ test_dmadev_instance(int16_t dev_id)
 #define CHECK_ERRS    true
 	enum {
 		  TEST_COPY = 0,
+		  TEST_COPY_SG,
 		  TEST_START,
 		  TEST_BURST,
 		  TEST_ERR,
@@ -1060,6 +1175,13 @@ test_dmadev_instance(int16_t dev_id)
 	param[TEST_COPY].vchan = vchan;
 	param[TEST_COPY].check_err_stats = CHECK_ERRS;
 
+	param[TEST_COPY_SG].printable = "copy";
+	param[TEST_COPY_SG].test_fn = test_enqueue_sg_copies;
+	param[TEST_COPY_SG].iterations = 1;
+	param[TEST_COPY_SG].dev_id = dev_id;
+	param[TEST_COPY_SG].vchan = vchan;
+	param[TEST_COPY_SG].check_err_stats = CHECK_ERRS;
+
 	param[TEST_START].printable = "stop-start";
 	param[TEST_START].test_fn = test_stop_start;
 	param[TEST_START].iterations = 1;
@@ -1122,6 +1244,12 @@ test_dmadev_instance(int16_t dev_id)
 	/* run tests stopping/starting devices and check jobs still work after restart */
 	ts->unit_test_cases[TEST_START].enabled = 1;
 
+	/* run SG test cases */
+	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		printf("DMA Dev %u: No SG support, skipping SG copy tests\n", dev_id);
+	else
+		ts->unit_test_cases[TEST_COPY_SG].enabled = 1;
+
 	/* run some burst capacity tests */
 	ts->unit_test_cases[TEST_BURST].setup = test_dmadev_burst_setup;
 	ts->unit_test_cases[TEST_BURST].enabled = 1;
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index aa07d2b359..37e43c9336 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -10,6 +10,7 @@
 #include <rte_dmadev.h>
 
 #include "test.h"
+#include "test_dmadev_api.h"
 
 extern int test_dma_api(uint16_t dev_id);
 
@@ -21,36 +22,62 @@ static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
+static char *src_sg[TEST_SG_MAX];
+static char *dst_sg[TEST_SG_MAX];
 
 static int
 testsuite_setup(void)
 {
 	invalid_dev_id = -1;
-
-	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) {
-		rte_free(src);
-		src = NULL;
-		return -ENOMEM;
+	int i, rc = 0;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		src_sg[i] = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
+		if (src_sg[i] == NULL) {
+			rc = -ENOMEM;
+			goto exit;
+		}
+
+		dst_sg[i] = rte_malloc("dmadev_test_dst", TEST_MEMCPY_SIZE, 0);
+		if (dst_sg[i] == NULL) {
+			rte_free(src_sg[i]);
+			src_sg[i] = NULL;
+			rc = -ENOMEM;
+			goto exit;
+		}
 	}
 
+	src = src_sg[0];
+	dst = dst_sg[0];
+
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
 	 */
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_CRIT);
 
-	return 0;
+	return rc;
+exit:
+	while (--i >= 0) {
+		rte_free(src_sg[i]);
+		rte_free(dst_sg[i]);
+	}
+
+	return rc;
 }
 
 static void
 testsuite_teardown(void)
 {
-	rte_free(src);
+	int i;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		rte_free(src_sg[i]);
+		src_sg[i] = NULL;
+		rte_free(dst_sg[i]);
+		dst_sg[i] = NULL;
+	}
+
 	src = NULL;
-	rte_free(dst);
 	dst = NULL;
 	/* Ensure the dmadev is stopped. */
 	rte_dma_stop(test_dev_id);
@@ -437,6 +464,37 @@ verify_memory(void)
 	return 0;
 }
 
+static void
+sg_memory_setup(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++)
+			src_sg[i][j] = (char)j;
+
+		memset(dst_sg[i], 0, TEST_MEMCPY_SIZE);
+	}
+}
+
+static int
+sg_memory_verify(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++) {
+			if (src_sg[i][j] == dst_sg[i][j])
+				continue;
+
+			RTE_TEST_ASSERT_EQUAL(src_sg[i][j], dst_sg[i][j], "Failed to copy memory, %d %d",
+				src_sg[i][j], dst_sg[i][j]);
+		}
+	}
+
+	return 0;
+}
+
 static int
 test_dma_completed(void)
 {
@@ -551,6 +609,86 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_sg(void)
+{
+	struct rte_dma_sge src_sge[TEST_SG_MAX], dst_sge[TEST_SG_MAX];
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t last_idx = -1;
+	bool has_error = true;
+	int n_sge, i, ret;
+	uint16_t cpl_ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		return TEST_SKIPPED;
+
+	n_sge = RTE_MIN(dev_info.max_sges, TEST_SG_MAX);
+
+	ret = setup_vchan(1);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	for (i = 0; i < n_sge; i++) {
+		src_sge[i].addr = rte_malloc_virt2iova(src_sg[i]);
+		src_sge[i].length = TEST_MEMCPY_SIZE;
+		dst_sge[i].addr = rte_malloc_virt2iova(dst_sg[i]);
+		dst_sge[i].length = TEST_MEMCPY_SIZE;
+	}
+
+	sg_memory_setup(n_sge);
+
+	/* Check enqueue without submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge, 0);
+	RTE_TEST_ASSERT_EQUAL(ret, 0, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_completed(test_dev_id, 0, 1, &last_idx, &has_error);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 0, "Failed to get completed");
+
+	/* Check DMA submit */
+	ret = rte_dma_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_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	sg_memory_setup(n_sge);
+
+	/* Check for enqueue with submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge,
+			      RTE_DMA_OP_FLAG_SUBMIT);
+	RTE_TEST_ASSERT_EQUAL(ret, 1, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	/* Stop dmadev to make sure dmadev to a known state */
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static struct unit_test_suite dma_api_testsuite = {
 	.suite_name = "DMA API Test Suite",
 	.setup = testsuite_setup,
@@ -568,6 +706,7 @@ static struct unit_test_suite dma_api_testsuite = {
 		TEST_CASE(test_dma_dump),
 		TEST_CASE(test_dma_completed),
 		TEST_CASE(test_dma_completed_status),
+		TEST_CASE(test_dma_sg),
 		TEST_CASES_END()
 	}
 };
diff --git a/app/test/test_dmadev_api.h b/app/test/test_dmadev_api.h
index 33fbc5bd41..10ab925f80 100644
--- a/app/test/test_dmadev_api.h
+++ b/app/test/test_dmadev_api.h
@@ -2,4 +2,6 @@
  * Copyright(c) 2021 HiSilicon Limited
  */
 
+#define TEST_SG_MAX 4
+
 int test_dma_api(uint16_t dev_id);
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 1/3] test/dma: use unit test framework
  2023-11-03 15:38     ` [PATCH v3 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
@ 2023-11-06  3:47       ` fengchengwen
  2023-11-13  9:28         ` [EXT] " Gowrishankar Muthukrishnan
  0 siblings, 1 reply; 39+ messages in thread
From: fengchengwen @ 2023-11-06  3:47 UTC (permalink / raw)
  To: Gowrishankar Muthukrishnan, dev
  Cc: anoobj, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson

Hi Gowrishankar,

  Thanks for your works.

On 2023/11/3 23:38, Gowrishankar Muthukrishnan wrote:
> Use unit test framework to execute DMA tests.
> 
> Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
> Suggested-by: Chengwen Feng <fengchengwen@huawei.com>
> ---
>  app/test/test_dmadev.c     | 240 ++++++++++++++++++++++++++++---------
>  app/test/test_dmadev_api.c |  89 ++++----------
>  2 files changed, 212 insertions(+), 117 deletions(-)
> 
> diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
> index 216f84b6bb..780941fc1e 100644
> --- a/app/test/test_dmadev.c
> +++ b/app/test/test_dmadev.c
> @@ -22,7 +22,9 @@
>  #define COPY_LEN 1024
>  
>  static struct rte_mempool *pool;
> +static int16_t test_dev_id;
>  static uint16_t id_count;
> +static int vchan;
>  
>  enum {
>  	TEST_PARAM_REMOTE_ADDR = 0,
> @@ -61,13 +63,35 @@ print_err(const char *func, int lineno, const char *format, ...)
>  	va_end(ap);
>  }
>  
> +struct runtest_param {
> +	const char *printable;
> +	int (*test_fn)(int16_t dev_id, uint16_t vchan);
> +	int iterations;
> +	int16_t dev_id;
> +	uint16_t vchan;
> +	bool check_err_stats;
> +};
> +
>  static int
> -runtest(const char *printable, int (*test_fn)(int16_t dev_id, uint16_t vchan), int iterations,
> -		int16_t dev_id, uint16_t vchan, bool check_err_stats)
> +runtest(const void *args)
>  {
> +	int (*test_fn)(int16_t dev_id, uint16_t vchan);
> +	const struct runtest_param *param = args;
>  	struct rte_dma_stats stats;
> +	const char *printable;
> +	bool check_err_stats;
> +	int iterations;
> +	int16_t dev_id;
> +	uint16_t vchan;
>  	int i;
>  
> +	printable = param->printable;
> +	iterations = param->iterations;
> +	dev_id = param->dev_id;
> +	vchan = param->vchan;
> +	check_err_stats = param->check_err_stats;
> +	test_fn = param->test_fn;
> +
>  	rte_dma_stats_reset(dev_id, vchan);
>  	printf("DMA Dev %d: Running %s Tests %s\n", dev_id, printable,
>  			check_err_stats ? " " : "(errors expected)");
> @@ -918,9 +942,21 @@ test_m2d_auto_free(int16_t dev_id, uint16_t vchan)
>  }
>  
>  static int
> -test_dmadev_instance(int16_t dev_id)
> +test_dmadev_burst_setup(void)
>  {
> -#define CHECK_ERRS    true
> +	if (rte_dma_burst_capacity(test_dev_id, vchan) < 64) {
> +		printf("DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
> +				test_dev_id);
> +		return TEST_SKIPPED;
> +	}
> +
> +	return TEST_SUCCESS;
> +}
> +
> +static int
> +test_dmadev_setup(void)
> +{
> +	int16_t dev_id = test_dev_id;
>  	struct rte_dma_stats stats;
>  	struct rte_dma_info info;
>  	const struct rte_dma_conf conf = { .nb_vchans = 1};
> @@ -928,16 +964,12 @@ test_dmadev_instance(int16_t dev_id)
>  			.direction = RTE_DMA_DIR_MEM_TO_MEM,
>  			.nb_desc = TEST_RINGSIZE,
>  	};
> -	const int vchan = 0;
>  	int ret;
>  
>  	ret = rte_dma_info_get(dev_id, &info);
>  	if (ret != 0)
>  		ERR_RETURN("Error with rte_dma_info_get()\n");
>  
> -	printf("\n### Test dmadev instance %u [%s]\n",
> -			dev_id, info.dev_name);
> -
>  	if (info.max_vchans < 1)
>  		ERR_RETURN("Error, no channels available on device id %u\n", dev_id);
>  
> @@ -976,20 +1008,123 @@ test_dmadev_instance(int16_t dev_id)
>  	if (pool == NULL)
>  		ERR_RETURN("Error with mempool creation\n");
>  
> +	return 0;
> +}
> +
> +static void
> +test_dmadev_teardown(void)
> +{
> +	rte_mempool_free(pool);
> +	rte_dma_stop(test_dev_id);
> +	rte_dma_stats_reset(test_dev_id, vchan);
> +	test_dev_id = -EINVAL;
> +}
> +
> +static int
> +test_dmadev_instance(int16_t dev_id)
> +{
> +#define CHECK_ERRS    true

suggest rm this define

> +	enum {
> +		  TEST_COPY = 0,
> +		  TEST_START,
> +		  TEST_BURST,
> +		  TEST_ERR,
> +		  TEST_FILL,
> +		  TEST_M2D,
> +		  TEST_END
> +	};
> +
> +	struct runtest_param param[TEST_END];
> +	struct rte_dma_info dev_info;
> +	struct unit_test_suite *ts;
> +	struct unit_test_case *tc;
> +	int ret;
> +
> +	if (rte_dma_info_get(dev_id, &dev_info) < 0)
> +		return TEST_SKIPPED;
> +
> +	test_dev_id = dev_id;
> +	vchan = 0;
> +
> +	ts = calloc(1, sizeof(struct unit_test_suite)
> +				+ sizeof(struct unit_test_case) * (TEST_END + 1));
> +
> +	ts->suite_name = "DMA dev instance testsuite";
> +	ts->setup = test_dmadev_setup;
> +	ts->teardown = test_dmadev_teardown;
> +
> +	param[TEST_COPY].printable = "copy";
> +	param[TEST_COPY].test_fn = test_enqueue_copies;
> +	param[TEST_COPY].iterations = 640;
> +	param[TEST_COPY].dev_id = dev_id;
> +	param[TEST_COPY].vchan = vchan;
> +	param[TEST_COPY].check_err_stats = CHECK_ERRS;
> +
> +	param[TEST_START].printable = "stop-start";
> +	param[TEST_START].test_fn = test_stop_start;
> +	param[TEST_START].iterations = 1;
> +	param[TEST_START].dev_id = dev_id;
> +	param[TEST_START].vchan = vchan;
> +	param[TEST_START].check_err_stats = CHECK_ERRS;
> +
> +	param[TEST_BURST].printable = "burst capacity";
> +	param[TEST_BURST].test_fn = test_burst_capacity;
> +	param[TEST_BURST].iterations = 1;
> +	param[TEST_BURST].dev_id = dev_id;
> +	param[TEST_BURST].vchan = vchan;
> +	param[TEST_BURST].check_err_stats = CHECK_ERRS;
> +
> +	param[TEST_ERR].printable = "error handling";
> +	param[TEST_ERR].test_fn = test_completion_handling;
> +	param[TEST_ERR].iterations = 1;
> +	param[TEST_ERR].dev_id = dev_id;
> +	param[TEST_ERR].vchan = vchan;
> +	param[TEST_ERR].check_err_stats = CHECK_ERRS;
> +
> +	param[TEST_FILL].printable = "fill";
> +	param[TEST_FILL].test_fn = test_enqueue_fill;
> +	param[TEST_FILL].iterations = 1;
> +	param[TEST_FILL].dev_id = dev_id;
> +	param[TEST_FILL].vchan = vchan;
> +	param[TEST_FILL].check_err_stats = CHECK_ERRS;
> +
> +	param[TEST_M2D].printable = "m2d_auto_free";
> +	param[TEST_M2D].test_fn = test_m2d_auto_free;
> +	param[TEST_M2D].iterations = 128;
> +	param[TEST_M2D].dev_id = dev_id;
> +	param[TEST_M2D].vchan = vchan;
> +	param[TEST_M2D].check_err_stats = CHECK_ERRS;

The above param was constant for all dmadev, suggest make them as global variable.

> +
> +	for (int i = 0; i < TEST_END; i++) {
> +		tc = &ts->unit_test_cases[i];
> +		tc->setup = NULL;
> +		tc->teardown = NULL;
> +		tc->testcase = NULL;
> +		tc->testcase_with_data = runtest;
> +		tc->data = &param[i];

suggest set name, it could be param[i].printable

> +		tc->enabled = 0;
> +	}
> +
> +	tc = &ts->unit_test_cases[TEST_END];
> +	tc->setup = NULL;
> +	tc->teardown = NULL;
> +	tc->testcase = NULL;
> +	tc->testcase_with_data = NULL;
> +	tc->data = NULL;
> +	tc->enabled = 0;

With above global variable, could use TEST_CASE_WITH_DATA here which pass TEST_XXX as data.

> +
> +	printf("\n### Test dmadev instance %u [%s]\n",
> +		   dev_id, dev_info.dev_name);
> +
>  	/* run the test cases, use many iterations to ensure UINT16_MAX id wraparound */

The comment could consider del or place it to proper context. the same with other comments

> -	if (runtest("copy", test_enqueue_copies, 640, dev_id, vchan, CHECK_ERRS) < 0)
> -		goto err;
> +	ts->unit_test_cases[TEST_COPY].enabled = 1;
>  
>  	/* run tests stopping/starting devices and check jobs still work after restart */
> -	if (runtest("stop-start", test_stop_start, 1, dev_id, vchan, CHECK_ERRS) < 0)
> -		goto err;
> +	ts->unit_test_cases[TEST_START].enabled = 1;
>  
>  	/* run some burst capacity tests */
> -	if (rte_dma_burst_capacity(dev_id, vchan) < 64)
> -		printf("DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
> -				dev_id);
> -	else if (runtest("burst capacity", test_burst_capacity, 1, dev_id, vchan, CHECK_ERRS) < 0)
> -		goto err;
> +	ts->unit_test_cases[TEST_BURST].setup = test_dmadev_burst_setup;
> +	ts->unit_test_cases[TEST_BURST].enabled = 1;
>  
>  	/* to test error handling we can provide null pointers for source or dest in copies. This
>  	 * requires VA mode in DPDK, since NULL(0) is a valid physical address.
> @@ -997,55 +1132,40 @@ test_dmadev_instance(int16_t dev_id)
>  	 */
>  	if (rte_eal_iova_mode() != RTE_IOVA_VA)
>  		printf("DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n", dev_id);
> -	else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
> +	else if ((dev_info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
>  		printf("DMA Dev %u: device does not report errors, skipping error handling tests\n",
>  				dev_id);
> -	else if (runtest("error handling", test_completion_handling, 1,
> -			dev_id, vchan, !CHECK_ERRS) < 0)
> -		goto err;
> +	else
> +		ts->unit_test_cases[TEST_ERR].enabled = 1;
>  
> -	if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0)
> +	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0)
>  		printf("DMA Dev %u: No device fill support, skipping fill tests\n", dev_id);
> -	else if (runtest("fill", test_enqueue_fill, 1, dev_id, vchan, CHECK_ERRS) < 0)
> -		goto err;
> +	else
> +		ts->unit_test_cases[TEST_FILL].enabled = 1;
>  
> -	if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
> +	if ((dev_info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
>  	    dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
> -		if (runtest("m2d_auto_free", test_m2d_auto_free, 128, dev_id, vchan,
> -			    CHECK_ERRS) < 0)
> -			goto err;
> +		ts->unit_test_cases[TEST_M2D].enabled = 1;
>  	}
>  
> -	rte_mempool_free(pool);
> -
> -	if (rte_dma_stop(dev_id) < 0)
> -		ERR_RETURN("Error stopping device %u\n", dev_id);
> -
> -	rte_dma_stats_reset(dev_id, vchan);
> -	return 0;
> +	ret = unit_test_suite_runner(ts);
> +	test_dev_id = -EINVAL;
> +	free(ts);
>  
> -err:
> -	rte_mempool_free(pool);
> -	rte_dma_stop(dev_id);
> -	return -1;
> +	return ret;
>  }
>  
>  static int
> -test_apis(void)
> +test_apis(const void *args)
>  {
> -	const char *pmd = "dma_skeleton";
> -	int id;
> -	int ret;
> +	const int16_t dev_id = *(const int16_t *)args;
> +	struct rte_dma_info dev_info;
>  
> -	/* attempt to create skeleton instance - ignore errors due to one being already present */
> -	rte_vdev_init(pmd, NULL);
> -	id = rte_dma_get_dev_id_by_name(pmd);
> -	if (id < 0)
> +	if (rte_dma_info_get(dev_id, &dev_info) < 0)
>  		return TEST_SKIPPED;
> -	printf("\n### Test dmadev infrastructure using skeleton driver\n");
> -	ret = test_dma_api(id);
>  
> -	return ret;
> +	printf("\n### Test dmadev infrastructure using %s\n", dev_info.dev_name);

suggest place above printf in the beginning of test_dma_api()

> +	return test_dma_api(dev_id);
>  }
>  
>  static void
> @@ -1088,16 +1208,28 @@ parse_dma_env_var(void)
>  static int
>  test_dma(void)
>  {
> -	int i;
> +	const char *pmd = "dma_skeleton";
> +	int i,  avail;
>  
>  	parse_dma_env_var();
>  
> +	/* attempt to create skeleton instance - ignore errors due to one being already present*/
> +	rte_vdev_init(pmd, NULL);
> +	i = rte_dma_get_dev_id_by_name(pmd);
> +	if (i < 0)
> +		return TEST_SKIPPED;

+1 for place create skeleton invoking here.

> +
>  	/* basic sanity on dmadev infrastructure */
> -	if (test_apis() < 0)
> +	if (test_apis(&i) < 0)
>  		ERR_RETURN("Error performing API tests\n");
>  
> -	if (rte_dma_count_avail() == 0)
> -		return TEST_SKIPPED;
> +	avail = rte_dma_count_avail();
> +	if (avail == 0)
> +		return 0;
> +
> +	i = rte_dma_next_dev(0);
> +	if (avail > 1 && test_apis(&i) < 0)
> +		ERR_RETURN("Error performing API tests\n");

Why only test later dmadev? Maybe it's ok for one of the channels, but should consider multi-vendor DMA devices exist.
So suggest test all or just test skeleton for the API test.

Also, suggest move API related code to test_dmadev_api.c, e.g.:
void
test_api(void)   ---place this function in test_dmadev_api.c
{
	RTE_DMA_FOREACH_DEV(i) {
		// get device info
		// check whether support memory-to-memory, because API test will setup memory-to-memory vchan
		// if not should skip it
		if (test_dma_api(i) < 0)
			ERR_RETURN("Error, test failure for device %d\n", i);
	}
}

>  
>  	RTE_DMA_FOREACH_DEV(i)
>  		if (test_dmadev_instance(i) < 0)
> diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
> index 4a181af90a..da8fddb3ca 100644
> --- a/app/test/test_dmadev_api.c
> +++ b/app/test/test_dmadev_api.c
> @@ -9,31 +9,22 @@
>  #include <rte_test.h>
>  #include <rte_dmadev.h>
>  
> -extern int test_dma_api(uint16_t dev_id);
> +#include "test.h"
>  
> -#define DMA_TEST_API_RUN(test) \
> -	testsuite_run_test(test, #test)
> +extern int test_dma_api(uint16_t dev_id);
>  
>  #define TEST_MEMCPY_SIZE	1024
>  #define TEST_WAIT_US_VAL	50000
>  
> -#define TEST_SUCCESS 0
> -#define TEST_FAILED  -1
> -
>  static int16_t test_dev_id;
>  static int16_t invalid_dev_id;
>  
>  static char *src;
>  static char *dst;
>  
> -static int total;
> -static int passed;
> -static int failed;
> -
>  static int
> -testsuite_setup(int16_t dev_id)
> +testsuite_setup(void)
>  {
> -	test_dev_id = dev_id;
>  	invalid_dev_id = -1;
>  
>  	src = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
> @@ -46,10 +37,6 @@ testsuite_setup(int16_t dev_id)
>  		return -ENOMEM;
>  	}
>  
> -	total = 0;
> -	passed = 0;
> -	failed = 0;
> -
>  	/* Set dmadev log level to critical to suppress unnecessary output
>  	 * during API tests.
>  	 */
> @@ -71,25 +58,6 @@ testsuite_teardown(void)
>  	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_INFO);
>  }
>  
> -static void
> -testsuite_run_test(int (*test)(void), const char *name)
> -{
> -	int ret = 0;
> -
> -	if (test) {
> -		ret = test();
> -		if (ret < 0) {
> -			failed++;
> -			printf("%s Failed\n", name);
> -		} else {
> -			passed++;
> -			printf("%s Passed\n", name);
> -		}
> -	}
> -
> -	total++;
> -}
> -
>  static int
>  test_dma_get_dev_id_by_name(void)
>  {
> @@ -301,7 +269,7 @@ setup_one_vchan(void)
>  
>  	ret = rte_dma_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;
> +	dev_conf.nb_vchans = 1;
>  	ret = rte_dma_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;
> @@ -537,38 +505,33 @@ test_dma_completed_status(void)
>  	return TEST_SUCCESS;
>  }
>  
> +static struct unit_test_suite dma_api_testsuite = {
> +	.suite_name = "DMA API Test Suite",
> +	.setup = testsuite_setup,
> +	.teardown = testsuite_teardown,
> +	.unit_test_cases = {
> +		TEST_CASE(test_dma_get_dev_id_by_name),
> +		TEST_CASE(test_dma_is_valid_dev),
> +		TEST_CASE(test_dma_count),
> +		TEST_CASE(test_dma_info_get),
> +		TEST_CASE(test_dma_configure),
> +		TEST_CASE(test_dma_vchan_setup),
> +		TEST_CASE(test_dma_start_stop),
> +		TEST_CASE(test_dma_stats),
> +		TEST_CASE(test_dma_dump),
> +		TEST_CASE(test_dma_completed),
> +		TEST_CASE(test_dma_completed_status),
> +		TEST_CASES_END()
> +	}
> +};
> +
>  int
>  test_dma_api(uint16_t dev_id)
>  {
> -	int ret = testsuite_setup(dev_id);
> -	if (ret) {
> -		printf("testsuite setup fail!\n");
> -		return -1;
> -	}
> +	test_dev_id = dev_id;
>  
>  	/* If the testcase exit successfully, ensure that the test dmadev exist
>  	 * and the dmadev is in the stopped state.
>  	 */

I think the above comments could delete or place just before 'static struct unit_test_suite dma_api_testsuite = {'

> -	DMA_TEST_API_RUN(test_dma_get_dev_id_by_name);
> -	DMA_TEST_API_RUN(test_dma_is_valid_dev);
> -	DMA_TEST_API_RUN(test_dma_count);
> -	DMA_TEST_API_RUN(test_dma_info_get);
> -	DMA_TEST_API_RUN(test_dma_configure);
> -	DMA_TEST_API_RUN(test_dma_vchan_setup);
> -	DMA_TEST_API_RUN(test_dma_start_stop);
> -	DMA_TEST_API_RUN(test_dma_stats);
> -	DMA_TEST_API_RUN(test_dma_dump);
> -	DMA_TEST_API_RUN(test_dma_completed);
> -	DMA_TEST_API_RUN(test_dma_completed_status);
> -
> -	testsuite_teardown();
> -
> -	printf("Total tests   : %d\n", total);
> -	printf("Passed        : %d\n", passed);
> -	printf("Failed        : %d\n", failed);
> -
> -	if (failed)
> -		return -1;
> -
> -	return 0;
> +	return unit_test_suite_runner(&dma_api_testsuite);
>  };
> 

For the dmadev, which have API test, memory-to-memory test, memory-to-device test, currently packed into two test-suites,
But I think its better use sub testsuite (could refer test_pdcp.c). Anyway, this is further more, we could do it later.

As the first stage, I think current impl is OK with above comments addressed.

Thanks
Chengwen

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 2/3] test/dma: test vchan reconfiguration
  2023-11-03 15:38     ` [PATCH v3 2/3] test/dma: test vchan reconfiguration Gowrishankar Muthukrishnan
@ 2023-11-06  4:06       ` fengchengwen
  0 siblings, 0 replies; 39+ messages in thread
From: fengchengwen @ 2023-11-06  4:06 UTC (permalink / raw)
  To: Gowrishankar Muthukrishnan, dev
  Cc: anoobj, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson

Hi Gowrishankar,

On 2023/11/3 23:38, Gowrishankar Muthukrishnan wrote:
> Reconfigure vchan count and validate if new count is effective.

I think it mainly due to multi-vchan, should point it out, suggest be: support API with multiple vchan test

Thanks
Chengwen

> 
> Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
> ---
>  app/test/test_dmadev_api.c | 63 +++++++++++++++++++++++++++++++++-----
>  1 file changed, 55 insertions(+), 8 deletions(-)
> 
> diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
> index da8fddb3ca..aa07d2b359 100644
> --- a/app/test/test_dmadev_api.c
> +++ b/app/test/test_dmadev_api.c
> @@ -260,7 +260,7 @@ test_dma_vchan_setup(void)
>  }
>  
>  static int
> -setup_one_vchan(void)
> +setup_vchan(int nb_vchans)
>  {
>  	struct rte_dma_vchan_conf vchan_conf = { 0 };
>  	struct rte_dma_info dev_info = { 0 };
> @@ -269,13 +269,15 @@ setup_one_vchan(void)
>  
>  	ret = rte_dma_info_get(test_dev_id, &dev_info);
>  	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
> -	dev_conf.nb_vchans = 1;
> +	dev_conf.nb_vchans = nb_vchans;
>  	ret = rte_dma_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_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
> -	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan, %d", ret);
> +	for (int i = 0; i < nb_vchans; i++) {
> +		ret = rte_dma_vchan_setup(test_dev_id, i, &vchan_conf);
> +		RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan %d, %d", i, ret);
> +	}
>  
>  	return TEST_SUCCESS;
>  }
> @@ -294,7 +296,7 @@ test_dma_start_stop(void)
>  	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
>  
>  	/* Setup one vchan for later test */
> -	ret = setup_one_vchan();
> +	ret = setup_vchan(1);
>  	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
>  
>  	ret = rte_dma_start(test_dev_id);
> @@ -312,6 +314,50 @@ test_dma_start_stop(void)
>  	return TEST_SUCCESS;
>  }
>  
> +static int
> +test_dma_reconfigure(void)
> +{
> +	struct rte_dma_conf dev_conf = { 0 };
> +	struct rte_dma_info dev_info = { 0 };
> +	uint16_t cfg_vchans;
> +	int ret;
> +
> +	ret = rte_dma_info_get(test_dev_id, &dev_info);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
> +
> +	/* At least two vchans required for the test */
> +	if (dev_info.max_vchans < 2)
> +		return TEST_SKIPPED;
> +
> +	/* Setup one vchan for later test */
> +	ret = setup_vchan(1);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
> +
> +	ret = rte_dma_start(test_dev_id);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
> +
> +	ret = rte_dma_stop(test_dev_id);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
> +
> +	/* Check reconfigure and vchan setup after device stopped */
> +	cfg_vchans = dev_conf.nb_vchans = (dev_info.max_vchans - 1);
> +
> +	ret = setup_vchan(cfg_vchans);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
> +
> +	ret = rte_dma_start(test_dev_id);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
> +
> +	ret = rte_dma_info_get(test_dev_id, &dev_info);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
> +	RTE_TEST_ASSERT_EQUAL(dev_info.nb_vchans, cfg_vchans, "incorrect reconfiguration");
> +
> +	ret = rte_dma_stop(test_dev_id);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
> +
> +	return TEST_SUCCESS;
> +}
> +
>  static int
>  test_dma_stats(void)
>  {
> @@ -328,7 +374,7 @@ test_dma_stats(void)
>  	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
>  
>  	/* Setup one vchan for later test */
> -	ret = setup_one_vchan();
> +	ret = setup_vchan(1);
>  	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
>  
>  	/* Check for invalid vchan */
> @@ -400,7 +446,7 @@ test_dma_completed(void)
>  	int ret;
>  
>  	/* Setup one vchan for later test */
> -	ret = setup_one_vchan();
> +	ret = setup_vchan(1);
>  	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
>  
>  	ret = rte_dma_start(test_dev_id);
> @@ -459,7 +505,7 @@ test_dma_completed_status(void)
>  	int ret;
>  
>  	/* Setup one vchan for later test */
> -	ret = setup_one_vchan();
> +	ret = setup_vchan(1);
>  	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
>  
>  	ret = rte_dma_start(test_dev_id);
> @@ -517,6 +563,7 @@ static struct unit_test_suite dma_api_testsuite = {
>  		TEST_CASE(test_dma_configure),
>  		TEST_CASE(test_dma_vchan_setup),
>  		TEST_CASE(test_dma_start_stop),
> +		TEST_CASE(test_dma_reconfigure),
>  		TEST_CASE(test_dma_stats),
>  		TEST_CASE(test_dma_dump),
>  		TEST_CASE(test_dma_completed),
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v3 3/3] test/dma: add SG copy tests
  2023-11-03 15:38     ` [PATCH v3 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
@ 2023-11-06  6:43       ` fengchengwen
  2023-11-13  9:27         ` [EXT] " Gowrishankar Muthukrishnan
  0 siblings, 1 reply; 39+ messages in thread
From: fengchengwen @ 2023-11-06  6:43 UTC (permalink / raw)
  To: Gowrishankar Muthukrishnan, dev
  Cc: anoobj, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson

Hi Gowrishankar,

On 2023/11/3 23:38, Gowrishankar Muthukrishnan wrote:
> Add scatter-gather copy tests.
> 
> Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
> Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
> ---
>  app/test/test_dmadev.c     | 132 +++++++++++++++++++++++++++++-
>  app/test/test_dmadev_api.c | 163 ++++++++++++++++++++++++++++++++++---
>  app/test/test_dmadev_api.h |   2 +
>  3 files changed, 283 insertions(+), 14 deletions(-)
> 
> diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
> index 780941fc1e..a2f3a7f999 100644
> --- a/app/test/test_dmadev.c
> +++ b/app/test/test_dmadev.c
> @@ -19,7 +19,7 @@
>  #define ERR_RETURN(...) do { print_err(__func__, __LINE__, __VA_ARGS__); return -1; } while (0)
>  
>  #define TEST_RINGSIZE 512
> -#define COPY_LEN 1024
> +#define COPY_LEN 1032

The test MAX_SG_NUM is limit 4, so it could be 1/2/3/4 segment, and 1032 can both div 1/2/3/4, but 1024 couldn't

I think this is why change 1024->1032.
Suggest add some comment about it.

>  
>  static struct rte_mempool *pool;
>  static int16_t test_dev_id;
> @@ -396,6 +396,120 @@ test_stop_start(int16_t dev_id, uint16_t vchan)
>  	return 0;
>  }
>  
> +static int
> +test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
> +{
> +	unsigned int src_len, dst_len, n_sge, len, i, j, k;
> +	char orig_src[COPY_LEN], orig_dst[COPY_LEN];
> +	struct rte_dma_info info = { 0 };
> +	enum rte_dma_status_code status;
> +	uint16_t id, n_src, n_dst;
> +
> +	if (rte_dma_info_get(dev_id, &info) < 0)
> +		ERR_RETURN("Failed to get dev info");
> +
> +	n_sge = RTE_MIN(info.max_sges, TEST_SG_MAX);
> +	len = COPY_LEN;
> +
> +	for (n_src = 1; n_src <= n_sge; n_src++) {
> +		src_len = len / n_src;
> +		for (n_dst = 1; n_dst <= n_sge; n_dst++) {
> +			dst_len = len / n_dst;

If the len % [1~n_dst] not zero, how to process it ?

I see, it was ensured by adjust copy_len value. Suggest add comments for it.

Also suggest extra above to one function.

> +
> +			struct rte_dma_sge sg_src[n_sge], sg_dst[n_sge];
> +			struct rte_mbuf *src[n_sge], *dst[n_sge];
> +			char *src_data[n_sge], *dst_data[n_sge];
> +
> +			for (i = 0 ; i < COPY_LEN; i++)
> +				orig_src[i] = rte_rand() & 0xFF;
> +
> +			memset(orig_dst, 0, COPY_LEN);
> +
> +			for (i = 0; i < n_src; i++) {
> +				src[i] = rte_pktmbuf_alloc(pool);
> +				RTE_ASSERT(src[i] != NULL);
> +				sg_src[i].addr = rte_pktmbuf_iova(src[i]);
> +				sg_src[i].length = src_len;
> +				src_data[i] = rte_pktmbuf_mtod(src[i], char *);
> +			}
> +
> +			for (k = 0; k < n_dst; k++) {
> +				dst[k] = rte_pktmbuf_alloc(pool);
> +				RTE_ASSERT(dst[k] != NULL);
> +				sg_dst[k].addr = rte_pktmbuf_iova(dst[k]);
> +				sg_dst[k].length = dst_len;
> +				dst_data[k] = rte_pktmbuf_mtod(dst[k], char *);
> +			}
> +
> +			for (i = 0; i < n_src; i++) {
> +				for (j = 0; j < src_len; j++)
> +					src_data[i][j] = orig_src[i * src_len + j];
> +			}
> +
> +			for (k = 0; k < n_dst; k++)
> +				memset(dst_data[k], 0, dst_len);
> +
> +			printf("\tsrc segs: %2d [seg len: %4d] - dst segs: %2d [seg len : %4d]\n",
> +				n_src, src_len, n_dst, dst_len);
> +
> +			id = rte_dma_copy_sg(dev_id, vchan, sg_src, sg_dst, n_src, n_dst,
> +					     RTE_DMA_OP_FLAG_SUBMIT);
> +
> +			if (id != id_count)
> +				ERR_RETURN("Error with rte_dma_copy_sg, got %u, expected %u\n",
> +					id, id_count);
> +
> +			/* Give time for copy to finish, then check it was done */
> +			await_hw(dev_id, vchan);
> +
> +			for (k = 0; k < n_dst; k++)
> +				memcpy((&orig_dst[0] + k * dst_len), dst_data[k], dst_len);
> +
> +			if (memcmp(orig_src, orig_dst, COPY_LEN))
> +				ERR_RETURN("Data mismatch");
> +
> +			/* Verify completion */
> +			id = ~id;
> +			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 1)
> +				ERR_RETURN("Error with rte_dma_completed\n");
> +
> +			/* Verify expected index(id_count) */
> +			if (id != id_count)
> +				ERR_RETURN("Error:incorrect job id received, %u [expected %u]\n",
> +						id, id_count);
> +
> +			/* Check for completed and id when no job done */
> +			id = ~id;
> +			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 0)
> +				ERR_RETURN("Error with rte_dma_completed when no job done\n");
> +
> +			if (id != id_count)
> +				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
> +					   id, id_count);
> +
> +			/* Check for completed_status and id when no job done */
> +			id = ~id;
> +			if (rte_dma_completed_status(dev_id, vchan, 1, &id, &status) != 0)
> +				ERR_RETURN("Error with rte_dma_completed_status when no job done\n");
> +			if (id != id_count)
> +				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
> +						id, 0);
> +
> +			for (i = 0; i < n_src; i++)
> +				rte_pktmbuf_free(src[i]);
> +			for (i = 0; i < n_dst; i++)
> +				rte_pktmbuf_free(dst[i]);
> +
> +			/* Verify that completion returns nothing more */
> +			if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
> +				ERR_RETURN("Error with rte_dma_completed in empty check\n");

already verify this, no need do more

> +
> +			id_count++;
> +		}
> +	}
> +	return 0;
> +}
> +
>  /* Failure handling test cases - global macros and variables for those tests*/
>  #define COMP_BURST_SZ	16
>  #define OPT_FENCE(idx) ((fence && idx == 8) ? RTE_DMA_OP_FLAG_FENCE : 0)
> @@ -1003,7 +1117,7 @@ test_dmadev_setup(void)
>  			TEST_RINGSIZE * 2, /* n == num elements */
>  			32,  /* cache size */
>  			0,   /* priv size */
> -			2048, /* data room size */
> +			COPY_LEN + RTE_PKTMBUF_HEADROOM, /* data room size */
>  			info.numa_node);
>  	if (pool == NULL)
>  		ERR_RETURN("Error with mempool creation\n");
> @@ -1026,6 +1140,7 @@ test_dmadev_instance(int16_t dev_id)
>  #define CHECK_ERRS    true
>  	enum {
>  		  TEST_COPY = 0,
> +		  TEST_COPY_SG,
>  		  TEST_START,
>  		  TEST_BURST,
>  		  TEST_ERR,
> @@ -1060,6 +1175,13 @@ test_dmadev_instance(int16_t dev_id)
>  	param[TEST_COPY].vchan = vchan;
>  	param[TEST_COPY].check_err_stats = CHECK_ERRS;
>  
> +	param[TEST_COPY_SG].printable = "copy";

should be SG copy.

> +	param[TEST_COPY_SG].test_fn = test_enqueue_sg_copies;
> +	param[TEST_COPY_SG].iterations = 1;
> +	param[TEST_COPY_SG].dev_id = dev_id;
> +	param[TEST_COPY_SG].vchan = vchan;
> +	param[TEST_COPY_SG].check_err_stats = CHECK_ERRS;
> +
>  	param[TEST_START].printable = "stop-start";
>  	param[TEST_START].test_fn = test_stop_start;
>  	param[TEST_START].iterations = 1;
> @@ -1122,6 +1244,12 @@ test_dmadev_instance(int16_t dev_id)
>  	/* run tests stopping/starting devices and check jobs still work after restart */
>  	ts->unit_test_cases[TEST_START].enabled = 1;
>  
> +	/* run SG test cases */
> +	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
> +		printf("DMA Dev %u: No SG support, skipping SG copy tests\n", dev_id);
> +	else
> +		ts->unit_test_cases[TEST_COPY_SG].enabled = 1;

suggest wrap it as test_dmadev_sg_copy_setup, just like test_dmadev_burst_setup

> +
>  	/* run some burst capacity tests */
>  	ts->unit_test_cases[TEST_BURST].setup = test_dmadev_burst_setup;
>  	ts->unit_test_cases[TEST_BURST].enabled = 1;
> diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
> index aa07d2b359..37e43c9336 100644
> --- a/app/test/test_dmadev_api.c
> +++ b/app/test/test_dmadev_api.c
> @@ -10,6 +10,7 @@
>  #include <rte_dmadev.h>
>  
>  #include "test.h"
> +#include "test_dmadev_api.h"
>  
>  extern int test_dma_api(uint16_t dev_id);
>  
> @@ -21,36 +22,62 @@ static int16_t invalid_dev_id;
>  
>  static char *src;
>  static char *dst;
> +static char *src_sg[TEST_SG_MAX];
> +static char *dst_sg[TEST_SG_MAX];
>  
>  static int
>  testsuite_setup(void)
>  {
>  	invalid_dev_id = -1;
> -
> -	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) {
> -		rte_free(src);
> -		src = NULL;
> -		return -ENOMEM;
> +	int i, rc = 0;
> +
> +	for (i = 0; i < TEST_SG_MAX; i++) {
> +		src_sg[i] = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
> +		if (src_sg[i] == NULL) {
> +			rc = -ENOMEM;
> +			goto exit;
> +		}
> +
> +		dst_sg[i] = rte_malloc("dmadev_test_dst", TEST_MEMCPY_SIZE, 0);
> +		if (dst_sg[i] == NULL) {
> +			rte_free(src_sg[i]);
> +			src_sg[i] = NULL;
> +			rc = -ENOMEM;
> +			goto exit;
> +		}
>  	}
>  
> +	src = src_sg[0];
> +	dst = dst_sg[0];
> +
>  	/* Set dmadev log level to critical to suppress unnecessary output
>  	 * during API tests.
>  	 */
>  	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_CRIT);
>  
> -	return 0;
> +	return rc;
> +exit:
> +	while (--i >= 0) {
> +		rte_free(src_sg[i]);
> +		rte_free(dst_sg[i]);
> +	}
> +
> +	return rc;
>  }
>  
>  static void
>  testsuite_teardown(void)
>  {
> -	rte_free(src);
> +	int i;
> +
> +	for (i = 0; i < TEST_SG_MAX; i++) {
> +		rte_free(src_sg[i]);
> +		src_sg[i] = NULL;
> +		rte_free(dst_sg[i]);
> +		dst_sg[i] = NULL;
> +	}
> +
>  	src = NULL;
> -	rte_free(dst);
>  	dst = NULL;
>  	/* Ensure the dmadev is stopped. */
>  	rte_dma_stop(test_dev_id);
> @@ -437,6 +464,37 @@ verify_memory(void)
>  	return 0;
>  }
>  
> +static void
> +sg_memory_setup(int n)
> +{
> +	int i, j;
> +
> +	for (i = 0; i < n; i++) {
> +		for (j = 0; j < TEST_MEMCPY_SIZE; j++)
> +			src_sg[i][j] = (char)j;
> +
> +		memset(dst_sg[i], 0, TEST_MEMCPY_SIZE);
> +	}
> +}
> +
> +static int
> +sg_memory_verify(int n)
> +{
> +	int i, j;
> +
> +	for (i = 0; i < n; i++) {
> +		for (j = 0; j < TEST_MEMCPY_SIZE; j++) {
> +			if (src_sg[i][j] == dst_sg[i][j])
> +				continue;
> +
> +			RTE_TEST_ASSERT_EQUAL(src_sg[i][j], dst_sg[i][j], "Failed to copy memory, %d %d",
> +				src_sg[i][j], dst_sg[i][j]);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  static int
>  test_dma_completed(void)
>  {
> @@ -551,6 +609,86 @@ test_dma_completed_status(void)
>  	return TEST_SUCCESS;
>  }
>  
> +static int
> +test_dma_sg(void)
> +{
> +	struct rte_dma_sge src_sge[TEST_SG_MAX], dst_sge[TEST_SG_MAX];
> +	struct rte_dma_info dev_info = { 0 };
> +	uint16_t last_idx = -1;
> +	bool has_error = true;
> +	int n_sge, i, ret;
> +	uint16_t cpl_ret;
> +
> +	ret = rte_dma_info_get(test_dev_id, &dev_info);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
> +
> +	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
> +		return TEST_SKIPPED;
> +
> +	n_sge = RTE_MIN(dev_info.max_sges, TEST_SG_MAX);
> +
> +	ret = setup_vchan(1);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
> +
> +	ret = rte_dma_start(test_dev_id);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
> +
> +	for (i = 0; i < n_sge; i++) {
> +		src_sge[i].addr = rte_malloc_virt2iova(src_sg[i]);
> +		src_sge[i].length = TEST_MEMCPY_SIZE;
> +		dst_sge[i].addr = rte_malloc_virt2iova(dst_sg[i]);
> +		dst_sge[i].length = TEST_MEMCPY_SIZE;
> +	}
> +
> +	sg_memory_setup(n_sge);
> +
> +	/* Check enqueue without submit */
> +	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge, 0);
> +	RTE_TEST_ASSERT_EQUAL(ret, 0, "Failed to enqueue copy, %d", ret);
> +
> +	rte_delay_us_sleep(TEST_WAIT_US_VAL);
> +
> +	cpl_ret = rte_dma_completed(test_dev_id, 0, 1, &last_idx, &has_error);
> +	RTE_TEST_ASSERT_EQUAL(cpl_ret, 0, "Failed to get completed");
> +
> +	/* Check DMA submit */
> +	ret = rte_dma_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_dma_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");
> +
> +	ret = sg_memory_verify(n_sge);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
> +
> +	sg_memory_setup(n_sge);
> +
> +	/* Check for enqueue with submit */
> +	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge,
> +			      RTE_DMA_OP_FLAG_SUBMIT);
> +	RTE_TEST_ASSERT_EQUAL(ret, 1, "Failed to enqueue copy, %d", ret);
> +
> +	rte_delay_us_sleep(TEST_WAIT_US_VAL);
> +
> +	cpl_ret = rte_dma_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");
> +
> +	ret = sg_memory_verify(n_sge);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
> +
> +	/* Stop dmadev to make sure dmadev to a known state */
> +	ret = rte_dma_stop(test_dev_id);
> +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
> +
> +	return TEST_SUCCESS;
> +}
> +
>  static struct unit_test_suite dma_api_testsuite = {
>  	.suite_name = "DMA API Test Suite",
>  	.setup = testsuite_setup,
> @@ -568,6 +706,7 @@ static struct unit_test_suite dma_api_testsuite = {
>  		TEST_CASE(test_dma_dump),
>  		TEST_CASE(test_dma_completed),
>  		TEST_CASE(test_dma_completed_status),
> +		TEST_CASE(test_dma_sg),
>  		TEST_CASES_END()
>  	}
>  };
> diff --git a/app/test/test_dmadev_api.h b/app/test/test_dmadev_api.h
> index 33fbc5bd41..10ab925f80 100644
> --- a/app/test/test_dmadev_api.h
> +++ b/app/test/test_dmadev_api.h
> @@ -2,4 +2,6 @@
>   * Copyright(c) 2021 HiSilicon Limited
>   */
>  
> +#define TEST_SG_MAX 4

suggest TEST_MAX_SGES which corresponding dev_info.max_sges

Thanks
Chengwen

> +
>  int test_dma_api(uint16_t dev_id);
>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* RE: [EXT] Re: [PATCH v3 3/3] test/dma: add SG copy tests
  2023-11-06  6:43       ` fengchengwen
@ 2023-11-13  9:27         ` Gowrishankar Muthukrishnan
  0 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-13  9:27 UTC (permalink / raw)
  To: fengchengwen, dev
  Cc: Anoob Joseph, Vamsi Krishna Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson

Hi Fengchengwen,

> 
> On 2023/11/3 23:38, Gowrishankar Muthukrishnan wrote:
> > Add scatter-gather copy tests.
> >
> > Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
> > Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
> > ---
> >  app/test/test_dmadev.c     | 132 +++++++++++++++++++++++++++++-
> >  app/test/test_dmadev_api.c | 163 ++++++++++++++++++++++++++++++++++-
> --
> >  app/test/test_dmadev_api.h |   2 +
> >  3 files changed, 283 insertions(+), 14 deletions(-)
> >
> > diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c index
> > 780941fc1e..a2f3a7f999 100644
> > --- a/app/test/test_dmadev.c
> > +++ b/app/test/test_dmadev.c
> > @@ -19,7 +19,7 @@
> >  #define ERR_RETURN(...) do { print_err(__func__, __LINE__,
> > __VA_ARGS__); return -1; } while (0)
> >
> >  #define TEST_RINGSIZE 512
> > -#define COPY_LEN 1024
> > +#define COPY_LEN 1032
> 
> The test MAX_SG_NUM is limit 4, so it could be 1/2/3/4 segment, and 1032 can
> both div 1/2/3/4, but 1024 couldn't
> 
> I think this is why change 1024->1032.
> Suggest add some comment about it.
>

This change is not required after normalization as done in next patch.
 
> >
> >  static struct rte_mempool *pool;
> >  static int16_t test_dev_id;
> > @@ -396,6 +396,120 @@ test_stop_start(int16_t dev_id, uint16_t vchan)
> >  	return 0;
> >  }
> >
> > +static int
> > +test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan) {
> > +	unsigned int src_len, dst_len, n_sge, len, i, j, k;
> > +	char orig_src[COPY_LEN], orig_dst[COPY_LEN];
> > +	struct rte_dma_info info = { 0 };
> > +	enum rte_dma_status_code status;
> > +	uint16_t id, n_src, n_dst;
> > +
> > +	if (rte_dma_info_get(dev_id, &info) < 0)
> > +		ERR_RETURN("Failed to get dev info");
> > +
> > +	n_sge = RTE_MIN(info.max_sges, TEST_SG_MAX);
> > +	len = COPY_LEN;
> > +
> > +	for (n_src = 1; n_src <= n_sge; n_src++) {
> > +		src_len = len / n_src;
> > +		for (n_dst = 1; n_dst <= n_sge; n_dst++) {
> > +			dst_len = len / n_dst;
> 
> If the len % [1~n_dst] not zero, how to process it ?
> 
> I see, it was ensured by adjust copy_len value. Suggest add comments for it.
> 
> Also suggest extra above to one function.

I have added minor fix here to normalize buffer lengths. Please check in next patch version.
> 
> > +
> > +			struct rte_dma_sge sg_src[n_sge], sg_dst[n_sge];
> > +			struct rte_mbuf *src[n_sge], *dst[n_sge];
> > +			char *src_data[n_sge], *dst_data[n_sge];
> > +
> > +			for (i = 0 ; i < COPY_LEN; i++)
> > +				orig_src[i] = rte_rand() & 0xFF;
> > +
> > +			memset(orig_dst, 0, COPY_LEN);
> > +
> > +			for (i = 0; i < n_src; i++) {
> > +				src[i] = rte_pktmbuf_alloc(pool);
> > +				RTE_ASSERT(src[i] != NULL);
> > +				sg_src[i].addr = rte_pktmbuf_iova(src[i]);
> > +				sg_src[i].length = src_len;
> > +				src_data[i] = rte_pktmbuf_mtod(src[i], char *);
> > +			}
> > +
> > +			for (k = 0; k < n_dst; k++) {
> > +				dst[k] = rte_pktmbuf_alloc(pool);
> > +				RTE_ASSERT(dst[k] != NULL);
> > +				sg_dst[k].addr = rte_pktmbuf_iova(dst[k]);
> > +				sg_dst[k].length = dst_len;
> > +				dst_data[k] = rte_pktmbuf_mtod(dst[k], char
> *);
> > +			}
> > +
> > +			for (i = 0; i < n_src; i++) {
> > +				for (j = 0; j < src_len; j++)
> > +					src_data[i][j] = orig_src[i * src_len + j];
> > +			}
> > +
> > +			for (k = 0; k < n_dst; k++)
> > +				memset(dst_data[k], 0, dst_len);
> > +
> > +			printf("\tsrc segs: %2d [seg len: %4d] - dst segs: %2d
> [seg len : %4d]\n",
> > +				n_src, src_len, n_dst, dst_len);
> > +
> > +			id = rte_dma_copy_sg(dev_id, vchan, sg_src, sg_dst,
> n_src, n_dst,
> > +					     RTE_DMA_OP_FLAG_SUBMIT);
> > +
> > +			if (id != id_count)
> > +				ERR_RETURN("Error with rte_dma_copy_sg,
> got %u, expected %u\n",
> > +					id, id_count);
> > +
> > +			/* Give time for copy to finish, then check it was done
> */
> > +			await_hw(dev_id, vchan);
> > +
> > +			for (k = 0; k < n_dst; k++)
> > +				memcpy((&orig_dst[0] + k * dst_len),
> dst_data[k], dst_len);
> > +
> > +			if (memcmp(orig_src, orig_dst, COPY_LEN))
> > +				ERR_RETURN("Data mismatch");
> > +
> > +			/* Verify completion */
> > +			id = ~id;
> > +			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) !=
> 1)
> > +				ERR_RETURN("Error with
> rte_dma_completed\n");
> > +
> > +			/* Verify expected index(id_count) */
> > +			if (id != id_count)
> > +				ERR_RETURN("Error:incorrect job id received,
> %u [expected %u]\n",
> > +						id, id_count);
> > +
> > +			/* Check for completed and id when no job done */
> > +			id = ~id;
> > +			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) !=
> 0)
> > +				ERR_RETURN("Error with rte_dma_completed
> when no job done\n");
> > +
> > +			if (id != id_count)
> > +				ERR_RETURN("Error:incorrect job id received
> when no job done, %u [expected %u]\n",
> > +					   id, id_count);
> > +
> > +			/* Check for completed_status and id when no job done
> */
> > +			id = ~id;
> > +			if (rte_dma_completed_status(dev_id, vchan, 1, &id,
> &status) != 0)
> > +				ERR_RETURN("Error with
> rte_dma_completed_status when no job done\n");
> > +			if (id != id_count)
> > +				ERR_RETURN("Error:incorrect job id received
> when no job done, %u [expected %u]\n",
> > +						id, 0);
> > +
> > +			for (i = 0; i < n_src; i++)
> > +				rte_pktmbuf_free(src[i]);
> > +			for (i = 0; i < n_dst; i++)
> > +				rte_pktmbuf_free(dst[i]);
> > +
> > +			/* Verify that completion returns nothing more */
> > +			if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
> > +				ERR_RETURN("Error with rte_dma_completed
> in empty check\n");
> 
> already verify this, no need do more

But this is against empty param check (as it is also done in plain copy test).

> 
> > +
> > +			id_count++;
> > +		}
> > +	}
> > +	return 0;
> > +}
> > +
> >  /* Failure handling test cases - global macros and variables for those tests*/
> >  #define COMP_BURST_SZ	16
> >  #define OPT_FENCE(idx) ((fence && idx == 8) ? RTE_DMA_OP_FLAG_FENCE :
> > 0) @@ -1003,7 +1117,7 @@ test_dmadev_setup(void)
> >  			TEST_RINGSIZE * 2, /* n == num elements */
> >  			32,  /* cache size */
> >  			0,   /* priv size */
> > -			2048, /* data room size */
> > +			COPY_LEN + RTE_PKTMBUF_HEADROOM, /* data
> room size */
> >  			info.numa_node);
> >  	if (pool == NULL)
> >  		ERR_RETURN("Error with mempool creation\n"); @@ -1026,6
> +1140,7 @@
> > test_dmadev_instance(int16_t dev_id)
> >  #define CHECK_ERRS    true
> >  	enum {
> >  		  TEST_COPY = 0,
> > +		  TEST_COPY_SG,
> >  		  TEST_START,
> >  		  TEST_BURST,
> >  		  TEST_ERR,
> > @@ -1060,6 +1175,13 @@ test_dmadev_instance(int16_t dev_id)
> >  	param[TEST_COPY].vchan = vchan;
> >  	param[TEST_COPY].check_err_stats = CHECK_ERRS;
> >
> > +	param[TEST_COPY_SG].printable = "copy";
> 
> should be SG copy.

Ack.
> 
> > +	param[TEST_COPY_SG].test_fn = test_enqueue_sg_copies;
> > +	param[TEST_COPY_SG].iterations = 1;
> > +	param[TEST_COPY_SG].dev_id = dev_id;
> > +	param[TEST_COPY_SG].vchan = vchan;
> > +	param[TEST_COPY_SG].check_err_stats = CHECK_ERRS;
> > +
> >  	param[TEST_START].printable = "stop-start";
> >  	param[TEST_START].test_fn = test_stop_start;
> >  	param[TEST_START].iterations = 1;
> > @@ -1122,6 +1244,12 @@ test_dmadev_instance(int16_t dev_id)
> >  	/* run tests stopping/starting devices and check jobs still work after
> restart */
> >  	ts->unit_test_cases[TEST_START].enabled = 1;
> >
> > +	/* run SG test cases */
> > +	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
> > +		printf("DMA Dev %u: No SG support, skipping SG copy tests\n",
> dev_id);
> > +	else
> > +		ts->unit_test_cases[TEST_COPY_SG].enabled = 1;
> 
> suggest wrap it as test_dmadev_sg_copy_setup, just like
> test_dmadev_burst_setup
> 
> > +
> >  	/* run some burst capacity tests */
> >  	ts->unit_test_cases[TEST_BURST].setup = test_dmadev_burst_setup;
> >  	ts->unit_test_cases[TEST_BURST].enabled = 1; diff --git
> > a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c index
> > aa07d2b359..37e43c9336 100644
> > --- a/app/test/test_dmadev_api.c
> > +++ b/app/test/test_dmadev_api.c
> > @@ -10,6 +10,7 @@
> >  #include <rte_dmadev.h>
> >
> >  #include "test.h"
> > +#include "test_dmadev_api.h"
> >
> >  extern int test_dma_api(uint16_t dev_id);
> >
> > @@ -21,36 +22,62 @@ static int16_t invalid_dev_id;
> >
> >  static char *src;
> >  static char *dst;
> > +static char *src_sg[TEST_SG_MAX];
> > +static char *dst_sg[TEST_SG_MAX];
> >
> >  static int
> >  testsuite_setup(void)
> >  {
> >  	invalid_dev_id = -1;
> > -
> > -	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) {
> > -		rte_free(src);
> > -		src = NULL;
> > -		return -ENOMEM;
> > +	int i, rc = 0;
> > +
> > +	for (i = 0; i < TEST_SG_MAX; i++) {
> > +		src_sg[i] = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE,
> 0);
> > +		if (src_sg[i] == NULL) {
> > +			rc = -ENOMEM;
> > +			goto exit;
> > +		}
> > +
> > +		dst_sg[i] = rte_malloc("dmadev_test_dst", TEST_MEMCPY_SIZE,
> 0);
> > +		if (dst_sg[i] == NULL) {
> > +			rte_free(src_sg[i]);
> > +			src_sg[i] = NULL;
> > +			rc = -ENOMEM;
> > +			goto exit;
> > +		}
> >  	}
> >
> > +	src = src_sg[0];
> > +	dst = dst_sg[0];
> > +
> >  	/* Set dmadev log level to critical to suppress unnecessary output
> >  	 * during API tests.
> >  	 */
> >  	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_CRIT);
> >
> > -	return 0;
> > +	return rc;
> > +exit:
> > +	while (--i >= 0) {
> > +		rte_free(src_sg[i]);
> > +		rte_free(dst_sg[i]);
> > +	}
> > +
> > +	return rc;
> >  }
> >
> >  static void
> >  testsuite_teardown(void)
> >  {
> > -	rte_free(src);
> > +	int i;
> > +
> > +	for (i = 0; i < TEST_SG_MAX; i++) {
> > +		rte_free(src_sg[i]);
> > +		src_sg[i] = NULL;
> > +		rte_free(dst_sg[i]);
> > +		dst_sg[i] = NULL;
> > +	}
> > +
> >  	src = NULL;
> > -	rte_free(dst);
> >  	dst = NULL;
> >  	/* Ensure the dmadev is stopped. */
> >  	rte_dma_stop(test_dev_id);
> > @@ -437,6 +464,37 @@ verify_memory(void)
> >  	return 0;
> >  }
> >
> > +static void
> > +sg_memory_setup(int n)
> > +{
> > +	int i, j;
> > +
> > +	for (i = 0; i < n; i++) {
> > +		for (j = 0; j < TEST_MEMCPY_SIZE; j++)
> > +			src_sg[i][j] = (char)j;
> > +
> > +		memset(dst_sg[i], 0, TEST_MEMCPY_SIZE);
> > +	}
> > +}
> > +
> > +static int
> > +sg_memory_verify(int n)
> > +{
> > +	int i, j;
> > +
> > +	for (i = 0; i < n; i++) {
> > +		for (j = 0; j < TEST_MEMCPY_SIZE; j++) {
> > +			if (src_sg[i][j] == dst_sg[i][j])
> > +				continue;
> > +
> > +			RTE_TEST_ASSERT_EQUAL(src_sg[i][j], dst_sg[i][j],
> "Failed to copy memory, %d %d",
> > +				src_sg[i][j], dst_sg[i][j]);
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >  static int
> >  test_dma_completed(void)
> >  {
> > @@ -551,6 +609,86 @@ test_dma_completed_status(void)
> >  	return TEST_SUCCESS;
> >  }
> >
> > +static int
> > +test_dma_sg(void)
> > +{
> > +	struct rte_dma_sge src_sge[TEST_SG_MAX], dst_sge[TEST_SG_MAX];
> > +	struct rte_dma_info dev_info = { 0 };
> > +	uint16_t last_idx = -1;
> > +	bool has_error = true;
> > +	int n_sge, i, ret;
> > +	uint16_t cpl_ret;
> > +
> > +	ret = rte_dma_info_get(test_dev_id, &dev_info);
> > +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d",
> > +ret);
> > +
> > +	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
> > +		return TEST_SKIPPED;
> > +
> > +	n_sge = RTE_MIN(dev_info.max_sges, TEST_SG_MAX);
> > +
> > +	ret = setup_vchan(1);
> > +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
> > +
> > +	ret = rte_dma_start(test_dev_id);
> > +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
> > +
> > +	for (i = 0; i < n_sge; i++) {
> > +		src_sge[i].addr = rte_malloc_virt2iova(src_sg[i]);
> > +		src_sge[i].length = TEST_MEMCPY_SIZE;
> > +		dst_sge[i].addr = rte_malloc_virt2iova(dst_sg[i]);
> > +		dst_sge[i].length = TEST_MEMCPY_SIZE;
> > +	}
> > +
> > +	sg_memory_setup(n_sge);
> > +
> > +	/* Check enqueue without submit */
> > +	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge,
> 0);
> > +	RTE_TEST_ASSERT_EQUAL(ret, 0, "Failed to enqueue copy, %d", ret);
> > +
> > +	rte_delay_us_sleep(TEST_WAIT_US_VAL);
> > +
> > +	cpl_ret = rte_dma_completed(test_dev_id, 0, 1, &last_idx, &has_error);
> > +	RTE_TEST_ASSERT_EQUAL(cpl_ret, 0, "Failed to get completed");
> > +
> > +	/* Check DMA submit */
> > +	ret = rte_dma_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_dma_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");
> > +
> > +	ret = sg_memory_verify(n_sge);
> > +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
> > +
> > +	sg_memory_setup(n_sge);
> > +
> > +	/* Check for enqueue with submit */
> > +	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge,
> > +			      RTE_DMA_OP_FLAG_SUBMIT);
> > +	RTE_TEST_ASSERT_EQUAL(ret, 1, "Failed to enqueue copy, %d", ret);
> > +
> > +	rte_delay_us_sleep(TEST_WAIT_US_VAL);
> > +
> > +	cpl_ret = rte_dma_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");
> > +
> > +	ret = sg_memory_verify(n_sge);
> > +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
> > +
> > +	/* Stop dmadev to make sure dmadev to a known state */
> > +	ret = rte_dma_stop(test_dev_id);
> > +	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
> > +
> > +	return TEST_SUCCESS;
> > +}
> > +
> >  static struct unit_test_suite dma_api_testsuite = {
> >  	.suite_name = "DMA API Test Suite",
> >  	.setup = testsuite_setup,
> > @@ -568,6 +706,7 @@ static struct unit_test_suite dma_api_testsuite = {
> >  		TEST_CASE(test_dma_dump),
> >  		TEST_CASE(test_dma_completed),
> >  		TEST_CASE(test_dma_completed_status),
> > +		TEST_CASE(test_dma_sg),
> >  		TEST_CASES_END()
> >  	}
> >  };
> > diff --git a/app/test/test_dmadev_api.h b/app/test/test_dmadev_api.h
> > index 33fbc5bd41..10ab925f80 100644
> > --- a/app/test/test_dmadev_api.h
> > +++ b/app/test/test_dmadev_api.h
> > @@ -2,4 +2,6 @@
> >   * Copyright(c) 2021 HiSilicon Limited
> >   */
> >
> > +#define TEST_SG_MAX 4
> 
> suggest TEST_MAX_SGES which corresponding dev_info.max_sges

Ok, I have fixed API test to validate against max_ages.

Thanks,
Gowrishankar
> 
> Thanks
> Chengwen
> 
> > +
> >  int test_dma_api(uint16_t dev_id);
> >

^ permalink raw reply	[flat|nested] 39+ messages in thread

* RE: [EXT] Re: [PATCH v3 1/3] test/dma: use unit test framework
  2023-11-06  3:47       ` fengchengwen
@ 2023-11-13  9:28         ` Gowrishankar Muthukrishnan
  0 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-13  9:28 UTC (permalink / raw)
  To: fengchengwen, dev
  Cc: Anoob Joseph, Vamsi Krishna Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson

Hi Fengchengwen,
Thanks for your valuable comments, I have addressed all of them in v4 (sending shortly).
Please review the same.

> >
> 
> For the dmadev, which have API test, memory-to-memory test, memory-to-
> device test, currently packed into two test-suites, But I think its better use
> sub testsuite (could refer test_pdcp.c). Anyway, this is further more, we
> could do it later.
> 
> As the first stage, I think current impl is OK with above comments addressed.
> 

Ack.
Regards,
Gowrishankar

> Thanks
> Chengwen

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests
  2023-11-03 15:38   ` [PATCH v3 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
                       ` (2 preceding siblings ...)
  2023-11-03 15:38     ` [PATCH v3 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
@ 2023-11-13 12:53     ` Gowrishankar Muthukrishnan
  2023-11-13 12:53       ` [PATCH v4 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
                         ` (4 more replies)
  3 siblings, 5 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-13 12:53 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

This patch series reworks DMA tests to follow unit test framework
followed by new vchan reconfig and SG tests.

v4:
 - Suggestions from Fengchenwen addressed.

Gowrishankar Muthukrishnan (3):
  test/dma: use unit test framework
  test/dma: test multiple vchan
  test/dma: add SG copy tests

 app/test/test_dmadev.c     | 374 +++++++++++++++++++++++++++++--------
 app/test/test_dmadev_api.c | 316 +++++++++++++++++++++++--------
 2 files changed, 534 insertions(+), 156 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v4 1/3] test/dma: use unit test framework
  2023-11-13 12:53     ` [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
@ 2023-11-13 12:53       ` Gowrishankar Muthukrishnan
  2023-11-13 12:53       ` [PATCH v4 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
                         ` (3 subsequent siblings)
  4 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-13 12:53 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Use unit test framework to execute DMA tests.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
---
 app/test/test_dmadev.c     | 235 +++++++++++++++++++++++++------------
 app/test/test_dmadev_api.c |  95 +++++----------
 2 files changed, 193 insertions(+), 137 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 216f84b6bb..9f7e7aa866 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -21,8 +21,12 @@
 #define TEST_RINGSIZE 512
 #define COPY_LEN 1024
 
+static struct rte_dma_info info;
 static struct rte_mempool *pool;
+static bool check_err_stats;
+static int16_t test_dev_id;
 static uint16_t id_count;
+static uint16_t vchan;
 
 enum {
 	TEST_PARAM_REMOTE_ADDR = 0,
@@ -49,6 +53,8 @@ struct dma_add_test dma_add_test[] = {
 	[TEST_M2D_AUTO_FREE] = {.name = "m2d_auto_free", .enabled = false},
 };
 
+static bool dev_init;
+
 static void
 __rte_format_printf(3, 4)
 print_err(const char *func, int lineno, const char *format, ...)
@@ -61,13 +67,28 @@ print_err(const char *func, int lineno, const char *format, ...)
 	va_end(ap);
 }
 
+struct runtest_param {
+	const char name[NAME_MAX];
+	int (*test_fn)(int16_t dev_id, uint16_t vchan);
+	int iterations;
+};
+
 static int
-runtest(const char *printable, int (*test_fn)(int16_t dev_id, uint16_t vchan), int iterations,
-		int16_t dev_id, uint16_t vchan, bool check_err_stats)
+runtest(const void *args)
 {
+	int (*test_fn)(int16_t dev_id, uint16_t vchan);
+	const struct runtest_param *param = args;
 	struct rte_dma_stats stats;
+	const char *printable;
+	int iterations;
+	int16_t dev_id;
 	int i;
 
+	printable = param->name;
+	iterations = param->iterations;
+	test_fn = param->test_fn;
+	dev_id = test_dev_id;
+
 	rte_dma_stats_reset(dev_id, vchan);
 	printf("DMA Dev %d: Running %s Tests %s\n", dev_id, printable,
 			check_err_stats ? " " : "(errors expected)");
@@ -837,7 +858,6 @@ test_m2d_auto_free(int16_t dev_id, uint16_t vchan)
 	};
 	uint32_t buf_cnt1, buf_cnt2;
 	struct rte_mempool_ops *ops;
-	static bool dev_init;
 	uint16_t nb_done = 0;
 	bool dma_err = false;
 	int retry = 100;
@@ -918,26 +938,85 @@ test_m2d_auto_free(int16_t dev_id, uint16_t vchan)
 }
 
 static int
-test_dmadev_instance(int16_t dev_id)
+test_dmadev_burst_setup(void)
+{
+	if (rte_dma_burst_capacity(test_dev_id, vchan) < 64) {
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
+			test_dev_id);
+		return TEST_SKIPPED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_err_handling_setup(void)
+{
+	int ret = TEST_SKIPPED;
+
+	/* to test error handling we can provide null pointers for source or dest in copies. This
+	 * requires VA mode in DPDK, since NULL(0) is a valid physical address.
+	 * We also need hardware that can report errors back.
+	 */
+	if (rte_eal_iova_mode() != RTE_IOVA_VA)
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n",
+			test_dev_id);
+	else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: device does not report errors, skipping error handling tests\n",
+			test_dev_id);
+	else
+		ret = TEST_SUCCESS;
+
+	return ret;
+}
+
+static int
+test_dmadev_fill_setup(void)
+{
+	int ret = TEST_SUCCESS;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0) {
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: No device fill support, skipping fill tests\n", test_dev_id);
+		ret = TEST_SKIPPED;
+	}
+
+	return ret;
+}
+
+static int
+test_dmadev_autofree_setup(void)
+{
+	int ret = TEST_SKIPPED;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
+	    dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
+		dev_init = false;
+		ret = TEST_SUCCESS;
+	}
+
+	return ret;
+}
+
+static int
+test_dmadev_setup(void)
 {
-#define CHECK_ERRS    true
+	int16_t dev_id = test_dev_id;
 	struct rte_dma_stats stats;
-	struct rte_dma_info info;
 	const struct rte_dma_conf conf = { .nb_vchans = 1};
 	const struct rte_dma_vchan_conf qconf = {
 			.direction = RTE_DMA_DIR_MEM_TO_MEM,
 			.nb_desc = TEST_RINGSIZE,
 	};
-	const int vchan = 0;
 	int ret;
 
 	ret = rte_dma_info_get(dev_id, &info);
 	if (ret != 0)
 		ERR_RETURN("Error with rte_dma_info_get()\n");
 
-	printf("\n### Test dmadev instance %u [%s]\n",
-			dev_id, info.dev_name);
-
 	if (info.max_vchans < 1)
 		ERR_RETURN("Error, no channels available on device id %u\n", dev_id);
 
@@ -976,74 +1055,82 @@ test_dmadev_instance(int16_t dev_id)
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
 
-	/* run the test cases, use many iterations to ensure UINT16_MAX id wraparound */
-	if (runtest("copy", test_enqueue_copies, 640, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* run tests stopping/starting devices and check jobs still work after restart */
-	if (runtest("stop-start", test_stop_start, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* run some burst capacity tests */
-	if (rte_dma_burst_capacity(dev_id, vchan) < 64)
-		printf("DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
-				dev_id);
-	else if (runtest("burst capacity", test_burst_capacity, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* to test error handling we can provide null pointers for source or dest in copies. This
-	 * requires VA mode in DPDK, since NULL(0) is a valid physical address.
-	 * We also need hardware that can report errors back.
-	 */
-	if (rte_eal_iova_mode() != RTE_IOVA_VA)
-		printf("DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n", dev_id);
-	else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
-		printf("DMA Dev %u: device does not report errors, skipping error handling tests\n",
-				dev_id);
-	else if (runtest("error handling", test_completion_handling, 1,
-			dev_id, vchan, !CHECK_ERRS) < 0)
-		goto err;
-
-	if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0)
-		printf("DMA Dev %u: No device fill support, skipping fill tests\n", dev_id);
-	else if (runtest("fill", test_enqueue_fill, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
-	    dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
-		if (runtest("m2d_auto_free", test_m2d_auto_free, 128, dev_id, vchan,
-			    CHECK_ERRS) < 0)
-			goto err;
-	}
-
-	rte_mempool_free(pool);
-
-	if (rte_dma_stop(dev_id) < 0)
-		ERR_RETURN("Error stopping device %u\n", dev_id);
+	check_err_stats = false;
+	vchan = 0;
 
-	rte_dma_stats_reset(dev_id, vchan);
 	return 0;
+}
 
-err:
+static void
+test_dmadev_teardown(void)
+{
 	rte_mempool_free(pool);
-	rte_dma_stop(dev_id);
-	return -1;
+	rte_dma_stop(test_dev_id);
+	rte_dma_stats_reset(test_dev_id, vchan);
+	test_dev_id = -EINVAL;
 }
 
 static int
-test_apis(void)
+test_dmadev_instance(int16_t dev_id)
 {
-	const char *pmd = "dma_skeleton";
-	int id;
+	struct rte_dma_info dev_info;
+	enum {
+		  TEST_COPY = 0,
+		  TEST_START,
+		  TEST_BURST,
+		  TEST_ERR,
+		  TEST_FILL,
+		  TEST_M2D,
+		  TEST_END
+	};
+
+	static struct runtest_param param[] = {
+		{"copy", test_enqueue_copies, 640},
+		{"stop_start", test_stop_start, 1},
+		{"burst_capacity", test_burst_capacity, 1},
+		{"error_handling", test_completion_handling, 1},
+		{"fill", test_enqueue_fill, 1},
+		{"m2d_auto_free", test_m2d_auto_free, 128},
+	};
+
+	static struct unit_test_suite ts = {
+		.suite_name = "DMA dev instance testsuite",
+		.setup = test_dmadev_setup,
+		.teardown = test_dmadev_teardown,
+		.unit_test_cases = {
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_COPY].name,
+				NULL, NULL,
+				runtest, &param[TEST_COPY]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_START].name,
+				NULL, NULL,
+				runtest, &param[TEST_START]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_BURST].name,
+				test_dmadev_burst_setup, NULL,
+				runtest, &param[TEST_BURST]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_ERR].name,
+				test_dmadev_err_handling_setup, NULL,
+				runtest, &param[TEST_ERR]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_FILL].name,
+				test_dmadev_fill_setup, NULL,
+				runtest, &param[TEST_FILL]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_M2D].name,
+				test_dmadev_autofree_setup, NULL,
+				runtest, &param[TEST_M2D]),
+			TEST_CASES_END()
+		}
+	};
+
 	int ret;
 
-	/* attempt to create skeleton instance - ignore errors due to one being already present */
-	rte_vdev_init(pmd, NULL);
-	id = rte_dma_get_dev_id_by_name(pmd);
-	if (id < 0)
+	if (rte_dma_info_get(dev_id, &dev_info) < 0)
 		return TEST_SKIPPED;
-	printf("\n### Test dmadev infrastructure using skeleton driver\n");
-	ret = test_dma_api(id);
+
+	test_dev_id = dev_id;
+	printf("\n### Test dmadev instance %u [%s]\n",
+		   test_dev_id, dev_info.dev_name);
+
+	ret = unit_test_suite_runner(&ts);
+	test_dev_id = -EINVAL;
 
 	return ret;
 }
@@ -1088,22 +1175,26 @@ parse_dma_env_var(void)
 static int
 test_dma(void)
 {
+	const char *pmd = "dma_skeleton";
 	int i;
 
 	parse_dma_env_var();
 
-	/* basic sanity on dmadev infrastructure */
-	if (test_apis() < 0)
-		ERR_RETURN("Error performing API tests\n");
+	/* attempt to create skeleton instance - ignore errors due to one being already present*/
+	rte_vdev_init(pmd, NULL);
 
 	if (rte_dma_count_avail() == 0)
 		return TEST_SKIPPED;
 
-	RTE_DMA_FOREACH_DEV(i)
+	RTE_DMA_FOREACH_DEV(i) {
+		if (test_dma_api(i) < 0)
+			ERR_RETURN("Error performing API tests\n");
+
 		if (test_dmadev_instance(i) < 0)
 			ERR_RETURN("Error, test failure for device %d\n", i);
+	}
 
 	return 0;
 }
 
-REGISTER_DRIVER_TEST(dmadev_autotest, test_dma);
+REGISTER_TEST_COMMAND(dmadev_autotest, test_dma);
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 4a181af90a..73d4db825a 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -9,31 +9,22 @@
 #include <rte_test.h>
 #include <rte_dmadev.h>
 
-extern int test_dma_api(uint16_t dev_id);
+#include "test.h"
 
-#define DMA_TEST_API_RUN(test) \
-	testsuite_run_test(test, #test)
+extern int test_dma_api(uint16_t dev_id);
 
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
 
-#define TEST_SUCCESS 0
-#define TEST_FAILED  -1
-
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
 
-static int total;
-static int passed;
-static int failed;
-
 static int
-testsuite_setup(int16_t dev_id)
+testsuite_setup(void)
 {
-	test_dev_id = dev_id;
 	invalid_dev_id = -1;
 
 	src = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
@@ -46,10 +37,6 @@ testsuite_setup(int16_t dev_id)
 		return -ENOMEM;
 	}
 
-	total = 0;
-	passed = 0;
-	failed = 0;
-
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
 	 */
@@ -71,25 +58,6 @@ testsuite_teardown(void)
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_INFO);
 }
 
-static void
-testsuite_run_test(int (*test)(void), const char *name)
-{
-	int ret = 0;
-
-	if (test) {
-		ret = test();
-		if (ret < 0) {
-			failed++;
-			printf("%s Failed\n", name);
-		} else {
-			passed++;
-			printf("%s Passed\n", name);
-		}
-	}
-
-	total++;
-}
-
 static int
 test_dma_get_dev_id_by_name(void)
 {
@@ -301,7 +269,7 @@ setup_one_vchan(void)
 
 	ret = rte_dma_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;
+	dev_conf.nb_vchans = 1;
 	ret = rte_dma_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;
@@ -537,38 +505,35 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static struct unit_test_suite dma_api_testsuite = {
+	.suite_name = "DMA API Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE(test_dma_get_dev_id_by_name),
+		TEST_CASE(test_dma_is_valid_dev),
+		TEST_CASE(test_dma_count),
+		TEST_CASE(test_dma_info_get),
+		TEST_CASE(test_dma_configure),
+		TEST_CASE(test_dma_vchan_setup),
+		TEST_CASE(test_dma_start_stop),
+		TEST_CASE(test_dma_stats),
+		TEST_CASE(test_dma_dump),
+		TEST_CASE(test_dma_completed),
+		TEST_CASE(test_dma_completed_status),
+		TEST_CASES_END()
+	}
+};
+
 int
 test_dma_api(uint16_t dev_id)
 {
-	int ret = testsuite_setup(dev_id);
-	if (ret) {
-		printf("testsuite setup fail!\n");
-		return -1;
-	}
+	struct rte_dma_info dev_info;
 
-	/* If the testcase exit successfully, ensure that the test dmadev exist
-	 * and the dmadev is in the stopped state.
-	 */
-	DMA_TEST_API_RUN(test_dma_get_dev_id_by_name);
-	DMA_TEST_API_RUN(test_dma_is_valid_dev);
-	DMA_TEST_API_RUN(test_dma_count);
-	DMA_TEST_API_RUN(test_dma_info_get);
-	DMA_TEST_API_RUN(test_dma_configure);
-	DMA_TEST_API_RUN(test_dma_vchan_setup);
-	DMA_TEST_API_RUN(test_dma_start_stop);
-	DMA_TEST_API_RUN(test_dma_stats);
-	DMA_TEST_API_RUN(test_dma_dump);
-	DMA_TEST_API_RUN(test_dma_completed);
-	DMA_TEST_API_RUN(test_dma_completed_status);
-
-	testsuite_teardown();
-
-	printf("Total tests   : %d\n", total);
-	printf("Passed        : %d\n", passed);
-	printf("Failed        : %d\n", failed);
-
-	if (failed)
-		return -1;
+	if (rte_dma_info_get(dev_id, &dev_info) < 0)
+		return TEST_SKIPPED;
 
-	return 0;
+	printf("\n### Test dmadev infrastructure using %u [%s]\n", dev_id, dev_info.dev_name);
+	test_dev_id = dev_id;
+	return unit_test_suite_runner(&dma_api_testsuite);
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v4 2/3] test/dma: test multiple vchan
  2023-11-13 12:53     ` [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-11-13 12:53       ` [PATCH v4 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
@ 2023-11-13 12:53       ` Gowrishankar Muthukrishnan
  2023-11-13 12:53       ` [PATCH v4 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
                         ` (2 subsequent siblings)
  4 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-13 12:53 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Support API with multiple vchan test.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
---
 app/test/test_dmadev_api.c | 63 +++++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 8 deletions(-)

diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 73d4db825a..2b8a4eda62 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -260,7 +260,7 @@ test_dma_vchan_setup(void)
 }
 
 static int
-setup_one_vchan(void)
+setup_vchan(int nb_vchans)
 {
 	struct rte_dma_vchan_conf vchan_conf = { 0 };
 	struct rte_dma_info dev_info = { 0 };
@@ -269,13 +269,15 @@ setup_one_vchan(void)
 
 	ret = rte_dma_info_get(test_dev_id, &dev_info);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
-	dev_conf.nb_vchans = 1;
+	dev_conf.nb_vchans = nb_vchans;
 	ret = rte_dma_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_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
-	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan, %d", ret);
+	for (int i = 0; i < nb_vchans; i++) {
+		ret = rte_dma_vchan_setup(test_dev_id, i, &vchan_conf);
+		RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan %d, %d", i, ret);
+	}
 
 	return TEST_SUCCESS;
 }
@@ -294,7 +296,7 @@ test_dma_start_stop(void)
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -312,6 +314,50 @@ test_dma_start_stop(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_reconfigure(void)
+{
+	struct rte_dma_conf dev_conf = { 0 };
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t cfg_vchans;
+	int ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	/* At least two vchans required for the test */
+	if (dev_info.max_vchans < 2)
+		return TEST_SKIPPED;
+
+	/* Setup one vchan for later test */
+	ret = setup_vchan(1);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	/* Check reconfigure and vchan setup after device stopped */
+	cfg_vchans = dev_conf.nb_vchans = (dev_info.max_vchans - 1);
+
+	ret = setup_vchan(cfg_vchans);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+	RTE_TEST_ASSERT_EQUAL(dev_info.nb_vchans, cfg_vchans, "incorrect reconfiguration");
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static int
 test_dma_stats(void)
 {
@@ -328,7 +374,7 @@ test_dma_stats(void)
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	/* Check for invalid vchan */
@@ -400,7 +446,7 @@ test_dma_completed(void)
 	int ret;
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -459,7 +505,7 @@ test_dma_completed_status(void)
 	int ret;
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -517,6 +563,7 @@ static struct unit_test_suite dma_api_testsuite = {
 		TEST_CASE(test_dma_configure),
 		TEST_CASE(test_dma_vchan_setup),
 		TEST_CASE(test_dma_start_stop),
+		TEST_CASE(test_dma_reconfigure),
 		TEST_CASE(test_dma_stats),
 		TEST_CASE(test_dma_dump),
 		TEST_CASE(test_dma_completed),
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v4 3/3] test/dma: add SG copy tests
  2023-11-13 12:53     ` [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-11-13 12:53       ` [PATCH v4 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
  2023-11-13 12:53       ` [PATCH v4 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
@ 2023-11-13 12:53       ` Gowrishankar Muthukrishnan
  2023-11-16  7:16       ` [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests fengchengwen
  2023-11-16 10:40       ` [PATCH v5 " Gowrishankar Muthukrishnan
  4 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-13 12:53 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Add scatter-gather copy tests.

Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
---
 app/test/test_dmadev.c     | 139 ++++++++++++++++++++++++++++++-
 app/test/test_dmadev_api.c | 164 ++++++++++++++++++++++++++++++++++---
 2 files changed, 289 insertions(+), 14 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 9f7e7aa866..cc9e71156d 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -19,7 +19,7 @@
 #define ERR_RETURN(...) do { print_err(__func__, __LINE__, __VA_ARGS__); return -1; } while (0)
 
 #define TEST_RINGSIZE 512
-#define COPY_LEN 1024
+#define COPY_LEN 2048
 
 static struct rte_dma_info info;
 static struct rte_mempool *pool;
@@ -393,6 +393,125 @@ test_stop_start(int16_t dev_id, uint16_t vchan)
 	return 0;
 }
 
+static int
+test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
+{
+	unsigned int src_len, dst_len, n_sge, len, i, j, k;
+	char orig_src[COPY_LEN], orig_dst[COPY_LEN];
+	struct rte_dma_info info = { 0 };
+	enum rte_dma_status_code status;
+	uint16_t id, n_src, n_dst;
+
+	if (rte_dma_info_get(dev_id, &info) < 0)
+		ERR_RETURN("Failed to get dev info");
+
+	if (info.max_sges < 2)
+		ERR_RETURN("Test needs minimum 2 SG pointers");
+
+	n_sge = info.max_sges;
+
+	for (n_src = 1; n_src <= n_sge; n_src++) {
+		for (n_dst = 1; n_dst <= n_sge; n_dst++) {
+			/* Normalize SG buffer lengths */
+			len = COPY_LEN;
+			len -= (len % (n_src * n_dst));
+			dst_len = len / n_dst;
+			src_len = len / n_src;
+
+			struct rte_dma_sge sg_src[n_sge], sg_dst[n_sge];
+			struct rte_mbuf *src[n_sge], *dst[n_sge];
+			char *src_data[n_sge], *dst_data[n_sge];
+
+			for (i = 0 ; i < len; i++)
+				orig_src[i] = rte_rand() & 0xFF;
+
+			memset(orig_dst, 0, len);
+
+			for (i = 0; i < n_src; i++) {
+				src[i] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(src[i] != NULL);
+				sg_src[i].addr = rte_pktmbuf_iova(src[i]);
+				sg_src[i].length = src_len;
+				src_data[i] = rte_pktmbuf_mtod(src[i], char *);
+			}
+
+			for (k = 0; k < n_dst; k++) {
+				dst[k] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(dst[k] != NULL);
+				sg_dst[k].addr = rte_pktmbuf_iova(dst[k]);
+				sg_dst[k].length = dst_len;
+				dst_data[k] = rte_pktmbuf_mtod(dst[k], char *);
+			}
+
+			for (i = 0; i < n_src; i++) {
+				for (j = 0; j < src_len; j++)
+					src_data[i][j] = orig_src[i * src_len + j];
+			}
+
+			for (k = 0; k < n_dst; k++)
+				memset(dst_data[k], 0, dst_len);
+
+			printf("\tsrc segs: %2d [seg len: %4d] - dst segs: %2d [seg len : %4d]\n",
+				n_src, src_len, n_dst, dst_len);
+
+			id = rte_dma_copy_sg(dev_id, vchan, sg_src, sg_dst, n_src, n_dst,
+					     RTE_DMA_OP_FLAG_SUBMIT);
+
+			if (id != id_count)
+				ERR_RETURN("Error with rte_dma_copy_sg, got %u, expected %u\n",
+					id, id_count);
+
+			/* Give time for copy to finish, then check it was done */
+			await_hw(dev_id, vchan);
+
+			for (k = 0; k < n_dst; k++)
+				memcpy((&orig_dst[0] + k * dst_len), dst_data[k], dst_len);
+
+			if (memcmp(orig_src, orig_dst, COPY_LEN))
+				ERR_RETURN("Data mismatch");
+
+			/* Verify completion */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 1)
+				ERR_RETURN("Error with rte_dma_completed\n");
+
+			/* Verify expected index(id_count) */
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received, %u [expected %u]\n",
+						id, id_count);
+
+			/* Check for completed and id when no job done */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed when no job done\n");
+
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+					   id, id_count);
+
+			/* Check for completed_status and id when no job done */
+			id = ~id;
+			if (rte_dma_completed_status(dev_id, vchan, 1, &id, &status) != 0)
+				ERR_RETURN("Error with rte_dma_completed_status when no job done\n");
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+						id, 0);
+
+			for (i = 0; i < n_src; i++)
+				rte_pktmbuf_free(src[i]);
+			for (i = 0; i < n_dst; i++)
+				rte_pktmbuf_free(dst[i]);
+
+			/* Verify that completion returns nothing more */
+			if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed in empty check\n");
+
+			id_count++;
+		}
+	}
+	return 0;
+}
+
 /* Failure handling test cases - global macros and variables for those tests*/
 #define COMP_BURST_SZ	16
 #define OPT_FENCE(idx) ((fence && idx == 8) ? RTE_DMA_OP_FLAG_FENCE : 0)
@@ -937,6 +1056,17 @@ test_m2d_auto_free(int16_t dev_id, uint16_t vchan)
 	return ret;
 }
 
+static int
+test_dmadev_sg_copy_setup(void)
+{
+	int ret = TEST_SUCCESS;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		return TEST_SKIPPED;
+
+	return ret;
+}
+
 static int
 test_dmadev_burst_setup(void)
 {
@@ -1050,7 +1180,7 @@ test_dmadev_setup(void)
 			TEST_RINGSIZE * 2, /* n == num elements */
 			32,  /* cache size */
 			0,   /* priv size */
-			2048, /* data room size */
+			COPY_LEN + RTE_PKTMBUF_HEADROOM, /* data room size */
 			info.numa_node);
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
@@ -1076,6 +1206,7 @@ test_dmadev_instance(int16_t dev_id)
 	struct rte_dma_info dev_info;
 	enum {
 		  TEST_COPY = 0,
+		  TEST_COPY_SG,
 		  TEST_START,
 		  TEST_BURST,
 		  TEST_ERR,
@@ -1086,6 +1217,7 @@ test_dmadev_instance(int16_t dev_id)
 
 	static struct runtest_param param[] = {
 		{"copy", test_enqueue_copies, 640},
+		{"sg_copy", test_enqueue_sg_copies, 1},
 		{"stop_start", test_stop_start, 1},
 		{"burst_capacity", test_burst_capacity, 1},
 		{"error_handling", test_completion_handling, 1},
@@ -1101,6 +1233,9 @@ test_dmadev_instance(int16_t dev_id)
 			TEST_CASE_NAMED_WITH_DATA(param[TEST_COPY].name,
 				NULL, NULL,
 				runtest, &param[TEST_COPY]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_COPY_SG].name,
+				test_dmadev_sg_copy_setup, NULL,
+				runtest, &param[TEST_COPY_SG]),
 			TEST_CASE_NAMED_WITH_DATA(param[TEST_START].name,
 				NULL, NULL,
 				runtest, &param[TEST_START]),
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 2b8a4eda62..a130e74b51 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -10,47 +10,75 @@
 #include <rte_dmadev.h>
 
 #include "test.h"
+#include "test_dmadev_api.h"
 
 extern int test_dma_api(uint16_t dev_id);
 
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
+#define TEST_SG_MAX		64
 
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
+static char *src_sg[TEST_SG_MAX];
+static char *dst_sg[TEST_SG_MAX];
 
 static int
 testsuite_setup(void)
 {
 	invalid_dev_id = -1;
-
-	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) {
-		rte_free(src);
-		src = NULL;
-		return -ENOMEM;
+	int i, rc = 0;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		src_sg[i] = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
+		if (src_sg[i] == NULL) {
+			rc = -ENOMEM;
+			goto exit;
+		}
+
+		dst_sg[i] = rte_malloc("dmadev_test_dst", TEST_MEMCPY_SIZE, 0);
+		if (dst_sg[i] == NULL) {
+			rte_free(src_sg[i]);
+			src_sg[i] = NULL;
+			rc = -ENOMEM;
+			goto exit;
+		}
 	}
 
+	src = src_sg[0];
+	dst = dst_sg[0];
+
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
 	 */
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_CRIT);
 
-	return 0;
+	return rc;
+exit:
+	while (--i >= 0) {
+		rte_free(src_sg[i]);
+		rte_free(dst_sg[i]);
+	}
+
+	return rc;
 }
 
 static void
 testsuite_teardown(void)
 {
-	rte_free(src);
+	int i;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		rte_free(src_sg[i]);
+		src_sg[i] = NULL;
+		rte_free(dst_sg[i]);
+		dst_sg[i] = NULL;
+	}
+
 	src = NULL;
-	rte_free(dst);
 	dst = NULL;
 	/* Ensure the dmadev is stopped. */
 	rte_dma_stop(test_dev_id);
@@ -437,6 +465,37 @@ verify_memory(void)
 	return 0;
 }
 
+static void
+sg_memory_setup(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++)
+			src_sg[i][j] = (char)j;
+
+		memset(dst_sg[i], 0, TEST_MEMCPY_SIZE);
+	}
+}
+
+static int
+sg_memory_verify(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++) {
+			if (src_sg[i][j] == dst_sg[i][j])
+				continue;
+
+			RTE_TEST_ASSERT_EQUAL(src_sg[i][j], dst_sg[i][j], "Failed to copy memory, %d %d",
+				src_sg[i][j], dst_sg[i][j]);
+		}
+	}
+
+	return 0;
+}
+
 static int
 test_dma_completed(void)
 {
@@ -551,6 +610,86 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_sg(void)
+{
+	struct rte_dma_sge src_sge[TEST_SG_MAX], dst_sge[TEST_SG_MAX];
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t last_idx = -1;
+	bool has_error = true;
+	int n_sge, i, ret;
+	uint16_t cpl_ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		return TEST_SKIPPED;
+
+	n_sge = RTE_MIN(dev_info.max_sges, TEST_SG_MAX);
+
+	ret = setup_vchan(1);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	for (i = 0; i < n_sge; i++) {
+		src_sge[i].addr = rte_malloc_virt2iova(src_sg[i]);
+		src_sge[i].length = TEST_MEMCPY_SIZE;
+		dst_sge[i].addr = rte_malloc_virt2iova(dst_sg[i]);
+		dst_sge[i].length = TEST_MEMCPY_SIZE;
+	}
+
+	sg_memory_setup(n_sge);
+
+	/* Check enqueue without submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge, 0);
+	RTE_TEST_ASSERT_EQUAL(ret, 0, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_completed(test_dev_id, 0, 1, &last_idx, &has_error);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 0, "Failed to get completed");
+
+	/* Check DMA submit */
+	ret = rte_dma_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_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	sg_memory_setup(n_sge);
+
+	/* Check for enqueue with submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge,
+			      RTE_DMA_OP_FLAG_SUBMIT);
+	RTE_TEST_ASSERT_EQUAL(ret, 1, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	/* Stop dmadev to make sure dmadev to a known state */
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static struct unit_test_suite dma_api_testsuite = {
 	.suite_name = "DMA API Test Suite",
 	.setup = testsuite_setup,
@@ -568,6 +707,7 @@ static struct unit_test_suite dma_api_testsuite = {
 		TEST_CASE(test_dma_dump),
 		TEST_CASE(test_dma_completed),
 		TEST_CASE(test_dma_completed_status),
+		TEST_CASE(test_dma_sg),
 		TEST_CASES_END()
 	}
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests
  2023-11-13 12:53     ` [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
                         ` (2 preceding siblings ...)
  2023-11-13 12:53       ` [PATCH v4 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
@ 2023-11-16  7:16       ` fengchengwen
  2023-11-16 10:40       ` [PATCH v5 " Gowrishankar Muthukrishnan
  4 siblings, 0 replies; 39+ messages in thread
From: fengchengwen @ 2023-11-16  7:16 UTC (permalink / raw)
  To: Gowrishankar Muthukrishnan, dev
  Cc: anoobj, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson

LGTM
Series-acked-by: Chengwen Feng <fengchengwen@huawei.com>

PS: since 'test/dma: fix for buffer auto free' already merged, I think you should resend v5 to fix the apply error.

On 2023/11/13 20:53, Gowrishankar Muthukrishnan wrote:
> This patch series reworks DMA tests to follow unit test framework
> followed by new vchan reconfig and SG tests.
> 
> v4:
>  - Suggestions from Fengchenwen addressed.
> 
> Gowrishankar Muthukrishnan (3):
>   test/dma: use unit test framework
>   test/dma: test multiple vchan
>   test/dma: add SG copy tests
> 
>  app/test/test_dmadev.c     | 374 +++++++++++++++++++++++++++++--------
>  app/test/test_dmadev_api.c | 316 +++++++++++++++++++++++--------
>  2 files changed, 534 insertions(+), 156 deletions(-)
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v5 0/3] test/dma: add vchan reconfig and SG tests
  2023-11-13 12:53     ` [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
                         ` (3 preceding siblings ...)
  2023-11-16  7:16       ` [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests fengchengwen
@ 2023-11-16 10:40       ` Gowrishankar Muthukrishnan
  2023-11-16 10:40         ` [PATCH v5 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
                           ` (3 more replies)
  4 siblings, 4 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 10:40 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

This patch series reworks DMA tests to follow unit test framework
followed by new vchan reconfig and SG tests.

v5:
 - patch rebased.

Gowrishankar Muthukrishnan (3):
  test/dma: use unit test framework
  test/dma: test multiple vchan
  test/dma: add SG copy tests

 app/test/test_dmadev.c     | 375 +++++++++++++++++++++++++++++--------
 app/test/test_dmadev_api.c | 316 +++++++++++++++++++++++--------
 2 files changed, 534 insertions(+), 157 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v5 1/3] test/dma: use unit test framework
  2023-11-16 10:40       ` [PATCH v5 " Gowrishankar Muthukrishnan
@ 2023-11-16 10:40         ` Gowrishankar Muthukrishnan
  2023-11-16 10:40         ` [PATCH v5 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 10:40 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Use unit test framework to execute DMA tests.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_dmadev.c     | 236 +++++++++++++++++++++++++------------
 app/test/test_dmadev_api.c |  95 +++++----------
 2 files changed, 193 insertions(+), 138 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 7581fc2b4c..a1505716d1 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -21,8 +21,12 @@
 #define TEST_RINGSIZE 512
 #define COPY_LEN 1024
 
+static struct rte_dma_info info;
 static struct rte_mempool *pool;
+static bool check_err_stats;
+static int16_t test_dev_id;
 static uint16_t id_count;
+static uint16_t vchan;
 
 enum {
 	TEST_PARAM_REMOTE_ADDR = 0,
@@ -61,13 +65,28 @@ print_err(const char *func, int lineno, const char *format, ...)
 	va_end(ap);
 }
 
+struct runtest_param {
+	const char name[NAME_MAX];
+	int (*test_fn)(int16_t dev_id, uint16_t vchan);
+	int iterations;
+};
+
 static int
-runtest(const char *printable, int (*test_fn)(int16_t dev_id, uint16_t vchan), int iterations,
-		int16_t dev_id, uint16_t vchan, bool check_err_stats)
+runtest(const void *args)
 {
+	int (*test_fn)(int16_t dev_id, uint16_t vchan);
+	const struct runtest_param *param = args;
 	struct rte_dma_stats stats;
+	const char *printable;
+	int iterations;
+	int16_t dev_id;
 	int i;
 
+	printable = param->name;
+	iterations = param->iterations;
+	test_fn = param->test_fn;
+	dev_id = test_dev_id;
+
 	rte_dma_stats_reset(dev_id, vchan);
 	printf("DMA Dev %d: Running %s Tests %s\n", dev_id, printable,
 			check_err_stats ? " " : "(errors expected)");
@@ -911,26 +930,87 @@ prepare_m2d_auto_free(int16_t dev_id, uint16_t vchan)
 }
 
 static int
-test_dmadev_instance(int16_t dev_id)
+test_dmadev_burst_setup(void)
+{
+	if (rte_dma_burst_capacity(test_dev_id, vchan) < 64) {
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
+			test_dev_id);
+		return TEST_SKIPPED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_err_handling_setup(void)
+{
+	int ret = TEST_SKIPPED;
+
+	/* to test error handling we can provide null pointers for source or dest in copies. This
+	 * requires VA mode in DPDK, since NULL(0) is a valid physical address.
+	 * We also need hardware that can report errors back.
+	 */
+	if (rte_eal_iova_mode() != RTE_IOVA_VA)
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n",
+			test_dev_id);
+	else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: device does not report errors, skipping error handling tests\n",
+			test_dev_id);
+	else
+		ret = TEST_SUCCESS;
+
+	return ret;
+}
+
+static int
+test_dmadev_fill_setup(void)
+{
+	int ret = TEST_SUCCESS;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0) {
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: No device fill support, skipping fill tests\n", test_dev_id);
+		ret = TEST_SKIPPED;
+	}
+
+	return ret;
+}
+
+static int
+test_dmadev_autofree_setup(void)
+{
+	int ret = TEST_SKIPPED;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
+	    dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
+		if (prepare_m2d_auto_free(test_dev_id, vchan) != 0)
+			return ret;
+
+		ret = TEST_SUCCESS;
+	}
+
+	return ret;
+}
+
+static int
+test_dmadev_setup(void)
 {
-#define CHECK_ERRS    true
+	int16_t dev_id = test_dev_id;
 	struct rte_dma_stats stats;
-	struct rte_dma_info info;
 	const struct rte_dma_conf conf = { .nb_vchans = 1};
 	const struct rte_dma_vchan_conf qconf = {
 			.direction = RTE_DMA_DIR_MEM_TO_MEM,
 			.nb_desc = TEST_RINGSIZE,
 	};
-	const int vchan = 0;
 	int ret;
 
 	ret = rte_dma_info_get(dev_id, &info);
 	if (ret != 0)
 		ERR_RETURN("Error with rte_dma_info_get()\n");
 
-	printf("\n### Test dmadev instance %u [%s]\n",
-			dev_id, info.dev_name);
-
 	if (info.max_vchans < 1)
 		ERR_RETURN("Error, no channels available on device id %u\n", dev_id);
 
@@ -969,76 +1049,82 @@ test_dmadev_instance(int16_t dev_id)
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
 
-	/* run the test cases, use many iterations to ensure UINT16_MAX id wraparound */
-	if (runtest("copy", test_enqueue_copies, 640, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* run tests stopping/starting devices and check jobs still work after restart */
-	if (runtest("stop-start", test_stop_start, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* run some burst capacity tests */
-	if (rte_dma_burst_capacity(dev_id, vchan) < 64)
-		printf("DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
-				dev_id);
-	else if (runtest("burst capacity", test_burst_capacity, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* to test error handling we can provide null pointers for source or dest in copies. This
-	 * requires VA mode in DPDK, since NULL(0) is a valid physical address.
-	 * We also need hardware that can report errors back.
-	 */
-	if (rte_eal_iova_mode() != RTE_IOVA_VA)
-		printf("DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n", dev_id);
-	else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
-		printf("DMA Dev %u: device does not report errors, skipping error handling tests\n",
-				dev_id);
-	else if (runtest("error handling", test_completion_handling, 1,
-			dev_id, vchan, !CHECK_ERRS) < 0)
-		goto err;
-
-	if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0)
-		printf("DMA Dev %u: No device fill support, skipping fill tests\n", dev_id);
-	else if (runtest("fill", test_enqueue_fill, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
-	    dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
-		if (prepare_m2d_auto_free(dev_id, vchan) != 0)
-			goto err;
-		if (runtest("m2d_auto_free", test_m2d_auto_free, 128, dev_id, vchan,
-			    CHECK_ERRS) < 0)
-			goto err;
-	}
-
-	rte_mempool_free(pool);
-
-	if (rte_dma_stop(dev_id) < 0)
-		ERR_RETURN("Error stopping device %u\n", dev_id);
+	check_err_stats = false;
+	vchan = 0;
 
-	rte_dma_stats_reset(dev_id, vchan);
 	return 0;
+}
 
-err:
+static void
+test_dmadev_teardown(void)
+{
 	rte_mempool_free(pool);
-	rte_dma_stop(dev_id);
-	return -1;
+	rte_dma_stop(test_dev_id);
+	rte_dma_stats_reset(test_dev_id, vchan);
+	test_dev_id = -EINVAL;
 }
 
 static int
-test_apis(void)
+test_dmadev_instance(int16_t dev_id)
 {
-	const char *pmd = "dma_skeleton";
-	int id;
+	struct rte_dma_info dev_info;
+	enum {
+		  TEST_COPY = 0,
+		  TEST_START,
+		  TEST_BURST,
+		  TEST_ERR,
+		  TEST_FILL,
+		  TEST_M2D,
+		  TEST_END
+	};
+
+	static struct runtest_param param[] = {
+		{"copy", test_enqueue_copies, 640},
+		{"stop_start", test_stop_start, 1},
+		{"burst_capacity", test_burst_capacity, 1},
+		{"error_handling", test_completion_handling, 1},
+		{"fill", test_enqueue_fill, 1},
+		{"m2d_auto_free", test_m2d_auto_free, 128},
+	};
+
+	static struct unit_test_suite ts = {
+		.suite_name = "DMA dev instance testsuite",
+		.setup = test_dmadev_setup,
+		.teardown = test_dmadev_teardown,
+		.unit_test_cases = {
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_COPY].name,
+				NULL, NULL,
+				runtest, &param[TEST_COPY]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_START].name,
+				NULL, NULL,
+				runtest, &param[TEST_START]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_BURST].name,
+				test_dmadev_burst_setup, NULL,
+				runtest, &param[TEST_BURST]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_ERR].name,
+				test_dmadev_err_handling_setup, NULL,
+				runtest, &param[TEST_ERR]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_FILL].name,
+				test_dmadev_fill_setup, NULL,
+				runtest, &param[TEST_FILL]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_M2D].name,
+				test_dmadev_autofree_setup, NULL,
+				runtest, &param[TEST_M2D]),
+			TEST_CASES_END()
+		}
+	};
+
 	int ret;
 
-	/* attempt to create skeleton instance - ignore errors due to one being already present */
-	rte_vdev_init(pmd, NULL);
-	id = rte_dma_get_dev_id_by_name(pmd);
-	if (id < 0)
+	if (rte_dma_info_get(dev_id, &dev_info) < 0)
 		return TEST_SKIPPED;
-	printf("\n### Test dmadev infrastructure using skeleton driver\n");
-	ret = test_dma_api(id);
+
+	test_dev_id = dev_id;
+	printf("\n### Test dmadev instance %u [%s]\n",
+		   test_dev_id, dev_info.dev_name);
+
+	ret = unit_test_suite_runner(&ts);
+	test_dev_id = -EINVAL;
 
 	return ret;
 }
@@ -1083,22 +1169,26 @@ parse_dma_env_var(void)
 static int
 test_dma(void)
 {
+	const char *pmd = "dma_skeleton";
 	int i;
 
 	parse_dma_env_var();
 
-	/* basic sanity on dmadev infrastructure */
-	if (test_apis() < 0)
-		ERR_RETURN("Error performing API tests\n");
+	/* attempt to create skeleton instance - ignore errors due to one being already present*/
+	rte_vdev_init(pmd, NULL);
 
 	if (rte_dma_count_avail() == 0)
 		return TEST_SKIPPED;
 
-	RTE_DMA_FOREACH_DEV(i)
+	RTE_DMA_FOREACH_DEV(i) {
+		if (test_dma_api(i) < 0)
+			ERR_RETURN("Error performing API tests\n");
+
 		if (test_dmadev_instance(i) < 0)
 			ERR_RETURN("Error, test failure for device %d\n", i);
+	}
 
 	return 0;
 }
 
-REGISTER_DRIVER_TEST(dmadev_autotest, test_dma);
+REGISTER_TEST_COMMAND(dmadev_autotest, test_dma);
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 4a181af90a..73d4db825a 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -9,31 +9,22 @@
 #include <rte_test.h>
 #include <rte_dmadev.h>
 
-extern int test_dma_api(uint16_t dev_id);
+#include "test.h"
 
-#define DMA_TEST_API_RUN(test) \
-	testsuite_run_test(test, #test)
+extern int test_dma_api(uint16_t dev_id);
 
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
 
-#define TEST_SUCCESS 0
-#define TEST_FAILED  -1
-
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
 
-static int total;
-static int passed;
-static int failed;
-
 static int
-testsuite_setup(int16_t dev_id)
+testsuite_setup(void)
 {
-	test_dev_id = dev_id;
 	invalid_dev_id = -1;
 
 	src = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
@@ -46,10 +37,6 @@ testsuite_setup(int16_t dev_id)
 		return -ENOMEM;
 	}
 
-	total = 0;
-	passed = 0;
-	failed = 0;
-
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
 	 */
@@ -71,25 +58,6 @@ testsuite_teardown(void)
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_INFO);
 }
 
-static void
-testsuite_run_test(int (*test)(void), const char *name)
-{
-	int ret = 0;
-
-	if (test) {
-		ret = test();
-		if (ret < 0) {
-			failed++;
-			printf("%s Failed\n", name);
-		} else {
-			passed++;
-			printf("%s Passed\n", name);
-		}
-	}
-
-	total++;
-}
-
 static int
 test_dma_get_dev_id_by_name(void)
 {
@@ -301,7 +269,7 @@ setup_one_vchan(void)
 
 	ret = rte_dma_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;
+	dev_conf.nb_vchans = 1;
 	ret = rte_dma_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;
@@ -537,38 +505,35 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static struct unit_test_suite dma_api_testsuite = {
+	.suite_name = "DMA API Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE(test_dma_get_dev_id_by_name),
+		TEST_CASE(test_dma_is_valid_dev),
+		TEST_CASE(test_dma_count),
+		TEST_CASE(test_dma_info_get),
+		TEST_CASE(test_dma_configure),
+		TEST_CASE(test_dma_vchan_setup),
+		TEST_CASE(test_dma_start_stop),
+		TEST_CASE(test_dma_stats),
+		TEST_CASE(test_dma_dump),
+		TEST_CASE(test_dma_completed),
+		TEST_CASE(test_dma_completed_status),
+		TEST_CASES_END()
+	}
+};
+
 int
 test_dma_api(uint16_t dev_id)
 {
-	int ret = testsuite_setup(dev_id);
-	if (ret) {
-		printf("testsuite setup fail!\n");
-		return -1;
-	}
+	struct rte_dma_info dev_info;
 
-	/* If the testcase exit successfully, ensure that the test dmadev exist
-	 * and the dmadev is in the stopped state.
-	 */
-	DMA_TEST_API_RUN(test_dma_get_dev_id_by_name);
-	DMA_TEST_API_RUN(test_dma_is_valid_dev);
-	DMA_TEST_API_RUN(test_dma_count);
-	DMA_TEST_API_RUN(test_dma_info_get);
-	DMA_TEST_API_RUN(test_dma_configure);
-	DMA_TEST_API_RUN(test_dma_vchan_setup);
-	DMA_TEST_API_RUN(test_dma_start_stop);
-	DMA_TEST_API_RUN(test_dma_stats);
-	DMA_TEST_API_RUN(test_dma_dump);
-	DMA_TEST_API_RUN(test_dma_completed);
-	DMA_TEST_API_RUN(test_dma_completed_status);
-
-	testsuite_teardown();
-
-	printf("Total tests   : %d\n", total);
-	printf("Passed        : %d\n", passed);
-	printf("Failed        : %d\n", failed);
-
-	if (failed)
-		return -1;
+	if (rte_dma_info_get(dev_id, &dev_info) < 0)
+		return TEST_SKIPPED;
 
-	return 0;
+	printf("\n### Test dmadev infrastructure using %u [%s]\n", dev_id, dev_info.dev_name);
+	test_dev_id = dev_id;
+	return unit_test_suite_runner(&dma_api_testsuite);
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v5 2/3] test/dma: test multiple vchan
  2023-11-16 10:40       ` [PATCH v5 " Gowrishankar Muthukrishnan
  2023-11-16 10:40         ` [PATCH v5 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
@ 2023-11-16 10:40         ` Gowrishankar Muthukrishnan
  2023-11-16 10:40         ` [PATCH v5 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
  2023-11-16 10:59         ` [PATCH v6 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  3 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 10:40 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Support API with multiple vchan test.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_dmadev_api.c | 63 +++++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 8 deletions(-)

diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 73d4db825a..2b8a4eda62 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -260,7 +260,7 @@ test_dma_vchan_setup(void)
 }
 
 static int
-setup_one_vchan(void)
+setup_vchan(int nb_vchans)
 {
 	struct rte_dma_vchan_conf vchan_conf = { 0 };
 	struct rte_dma_info dev_info = { 0 };
@@ -269,13 +269,15 @@ setup_one_vchan(void)
 
 	ret = rte_dma_info_get(test_dev_id, &dev_info);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
-	dev_conf.nb_vchans = 1;
+	dev_conf.nb_vchans = nb_vchans;
 	ret = rte_dma_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_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
-	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan, %d", ret);
+	for (int i = 0; i < nb_vchans; i++) {
+		ret = rte_dma_vchan_setup(test_dev_id, i, &vchan_conf);
+		RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan %d, %d", i, ret);
+	}
 
 	return TEST_SUCCESS;
 }
@@ -294,7 +296,7 @@ test_dma_start_stop(void)
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -312,6 +314,50 @@ test_dma_start_stop(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_reconfigure(void)
+{
+	struct rte_dma_conf dev_conf = { 0 };
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t cfg_vchans;
+	int ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	/* At least two vchans required for the test */
+	if (dev_info.max_vchans < 2)
+		return TEST_SKIPPED;
+
+	/* Setup one vchan for later test */
+	ret = setup_vchan(1);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	/* Check reconfigure and vchan setup after device stopped */
+	cfg_vchans = dev_conf.nb_vchans = (dev_info.max_vchans - 1);
+
+	ret = setup_vchan(cfg_vchans);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+	RTE_TEST_ASSERT_EQUAL(dev_info.nb_vchans, cfg_vchans, "incorrect reconfiguration");
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static int
 test_dma_stats(void)
 {
@@ -328,7 +374,7 @@ test_dma_stats(void)
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	/* Check for invalid vchan */
@@ -400,7 +446,7 @@ test_dma_completed(void)
 	int ret;
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -459,7 +505,7 @@ test_dma_completed_status(void)
 	int ret;
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -517,6 +563,7 @@ static struct unit_test_suite dma_api_testsuite = {
 		TEST_CASE(test_dma_configure),
 		TEST_CASE(test_dma_vchan_setup),
 		TEST_CASE(test_dma_start_stop),
+		TEST_CASE(test_dma_reconfigure),
 		TEST_CASE(test_dma_stats),
 		TEST_CASE(test_dma_dump),
 		TEST_CASE(test_dma_completed),
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v5 3/3] test/dma: add SG copy tests
  2023-11-16 10:40       ` [PATCH v5 " Gowrishankar Muthukrishnan
  2023-11-16 10:40         ` [PATCH v5 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
  2023-11-16 10:40         ` [PATCH v5 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
@ 2023-11-16 10:40         ` Gowrishankar Muthukrishnan
  2023-11-16 10:59         ` [PATCH v6 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  3 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 10:40 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Add scatter-gather copy tests.

Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_dmadev.c     | 139 ++++++++++++++++++++++++++++++-
 app/test/test_dmadev_api.c | 164 ++++++++++++++++++++++++++++++++++---
 2 files changed, 289 insertions(+), 14 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index a1505716d1..2a7eea698f 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -19,7 +19,7 @@
 #define ERR_RETURN(...) do { print_err(__func__, __LINE__, __VA_ARGS__); return -1; } while (0)
 
 #define TEST_RINGSIZE 512
-#define COPY_LEN 1024
+#define COPY_LEN 2048
 
 static struct rte_dma_info info;
 static struct rte_mempool *pool;
@@ -391,6 +391,125 @@ test_stop_start(int16_t dev_id, uint16_t vchan)
 	return 0;
 }
 
+static int
+test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
+{
+	unsigned int src_len, dst_len, n_sge, len, i, j, k;
+	char orig_src[COPY_LEN], orig_dst[COPY_LEN];
+	struct rte_dma_info info = { 0 };
+	enum rte_dma_status_code status;
+	uint16_t id, n_src, n_dst;
+
+	if (rte_dma_info_get(dev_id, &info) < 0)
+		ERR_RETURN("Failed to get dev info");
+
+	if (info.max_sges < 2)
+		ERR_RETURN("Test needs minimum 2 SG pointers");
+
+	n_sge = info.max_sges;
+
+	for (n_src = 1; n_src <= n_sge; n_src++) {
+		for (n_dst = 1; n_dst <= n_sge; n_dst++) {
+			/* Normalize SG buffer lengths */
+			len = COPY_LEN;
+			len -= (len % (n_src * n_dst));
+			dst_len = len / n_dst;
+			src_len = len / n_src;
+
+			struct rte_dma_sge sg_src[n_sge], sg_dst[n_sge];
+			struct rte_mbuf *src[n_sge], *dst[n_sge];
+			char *src_data[n_sge], *dst_data[n_sge];
+
+			for (i = 0 ; i < len; i++)
+				orig_src[i] = rte_rand() & 0xFF;
+
+			memset(orig_dst, 0, len);
+
+			for (i = 0; i < n_src; i++) {
+				src[i] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(src[i] != NULL);
+				sg_src[i].addr = rte_pktmbuf_iova(src[i]);
+				sg_src[i].length = src_len;
+				src_data[i] = rte_pktmbuf_mtod(src[i], char *);
+			}
+
+			for (k = 0; k < n_dst; k++) {
+				dst[k] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(dst[k] != NULL);
+				sg_dst[k].addr = rte_pktmbuf_iova(dst[k]);
+				sg_dst[k].length = dst_len;
+				dst_data[k] = rte_pktmbuf_mtod(dst[k], char *);
+			}
+
+			for (i = 0; i < n_src; i++) {
+				for (j = 0; j < src_len; j++)
+					src_data[i][j] = orig_src[i * src_len + j];
+			}
+
+			for (k = 0; k < n_dst; k++)
+				memset(dst_data[k], 0, dst_len);
+
+			printf("\tsrc segs: %2d [seg len: %4d] - dst segs: %2d [seg len : %4d]\n",
+				n_src, src_len, n_dst, dst_len);
+
+			id = rte_dma_copy_sg(dev_id, vchan, sg_src, sg_dst, n_src, n_dst,
+					     RTE_DMA_OP_FLAG_SUBMIT);
+
+			if (id != id_count)
+				ERR_RETURN("Error with rte_dma_copy_sg, got %u, expected %u\n",
+					id, id_count);
+
+			/* Give time for copy to finish, then check it was done */
+			await_hw(dev_id, vchan);
+
+			for (k = 0; k < n_dst; k++)
+				memcpy((&orig_dst[0] + k * dst_len), dst_data[k], dst_len);
+
+			if (memcmp(orig_src, orig_dst, COPY_LEN))
+				ERR_RETURN("Data mismatch");
+
+			/* Verify completion */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 1)
+				ERR_RETURN("Error with rte_dma_completed\n");
+
+			/* Verify expected index(id_count) */
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received, %u [expected %u]\n",
+						id, id_count);
+
+			/* Check for completed and id when no job done */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed when no job done\n");
+
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+					   id, id_count);
+
+			/* Check for completed_status and id when no job done */
+			id = ~id;
+			if (rte_dma_completed_status(dev_id, vchan, 1, &id, &status) != 0)
+				ERR_RETURN("Error with rte_dma_completed_status when no job done\n");
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+						id, 0);
+
+			for (i = 0; i < n_src; i++)
+				rte_pktmbuf_free(src[i]);
+			for (i = 0; i < n_dst; i++)
+				rte_pktmbuf_free(dst[i]);
+
+			/* Verify that completion returns nothing more */
+			if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed in empty check\n");
+
+			id_count++;
+		}
+	}
+	return 0;
+}
+
 /* Failure handling test cases - global macros and variables for those tests*/
 #define COMP_BURST_SZ	16
 #define OPT_FENCE(idx) ((fence && idx == 8) ? RTE_DMA_OP_FLAG_FENCE : 0)
@@ -929,6 +1048,17 @@ prepare_m2d_auto_free(int16_t dev_id, uint16_t vchan)
 	return 0;
 }
 
+static int
+test_dmadev_sg_copy_setup(void)
+{
+	int ret = TEST_SUCCESS;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		return TEST_SKIPPED;
+
+	return ret;
+}
+
 static int
 test_dmadev_burst_setup(void)
 {
@@ -1044,7 +1174,7 @@ test_dmadev_setup(void)
 			TEST_RINGSIZE * 2, /* n == num elements */
 			32,  /* cache size */
 			0,   /* priv size */
-			2048, /* data room size */
+			COPY_LEN + RTE_PKTMBUF_HEADROOM, /* data room size */
 			info.numa_node);
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
@@ -1070,6 +1200,7 @@ test_dmadev_instance(int16_t dev_id)
 	struct rte_dma_info dev_info;
 	enum {
 		  TEST_COPY = 0,
+		  TEST_COPY_SG,
 		  TEST_START,
 		  TEST_BURST,
 		  TEST_ERR,
@@ -1080,6 +1211,7 @@ test_dmadev_instance(int16_t dev_id)
 
 	static struct runtest_param param[] = {
 		{"copy", test_enqueue_copies, 640},
+		{"sg_copy", test_enqueue_sg_copies, 1},
 		{"stop_start", test_stop_start, 1},
 		{"burst_capacity", test_burst_capacity, 1},
 		{"error_handling", test_completion_handling, 1},
@@ -1095,6 +1227,9 @@ test_dmadev_instance(int16_t dev_id)
 			TEST_CASE_NAMED_WITH_DATA(param[TEST_COPY].name,
 				NULL, NULL,
 				runtest, &param[TEST_COPY]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_COPY_SG].name,
+				test_dmadev_sg_copy_setup, NULL,
+				runtest, &param[TEST_COPY_SG]),
 			TEST_CASE_NAMED_WITH_DATA(param[TEST_START].name,
 				NULL, NULL,
 				runtest, &param[TEST_START]),
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 2b8a4eda62..a130e74b51 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -10,47 +10,75 @@
 #include <rte_dmadev.h>
 
 #include "test.h"
+#include "test_dmadev_api.h"
 
 extern int test_dma_api(uint16_t dev_id);
 
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
+#define TEST_SG_MAX		64
 
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
+static char *src_sg[TEST_SG_MAX];
+static char *dst_sg[TEST_SG_MAX];
 
 static int
 testsuite_setup(void)
 {
 	invalid_dev_id = -1;
-
-	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) {
-		rte_free(src);
-		src = NULL;
-		return -ENOMEM;
+	int i, rc = 0;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		src_sg[i] = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
+		if (src_sg[i] == NULL) {
+			rc = -ENOMEM;
+			goto exit;
+		}
+
+		dst_sg[i] = rte_malloc("dmadev_test_dst", TEST_MEMCPY_SIZE, 0);
+		if (dst_sg[i] == NULL) {
+			rte_free(src_sg[i]);
+			src_sg[i] = NULL;
+			rc = -ENOMEM;
+			goto exit;
+		}
 	}
 
+	src = src_sg[0];
+	dst = dst_sg[0];
+
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
 	 */
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_CRIT);
 
-	return 0;
+	return rc;
+exit:
+	while (--i >= 0) {
+		rte_free(src_sg[i]);
+		rte_free(dst_sg[i]);
+	}
+
+	return rc;
 }
 
 static void
 testsuite_teardown(void)
 {
-	rte_free(src);
+	int i;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		rte_free(src_sg[i]);
+		src_sg[i] = NULL;
+		rte_free(dst_sg[i]);
+		dst_sg[i] = NULL;
+	}
+
 	src = NULL;
-	rte_free(dst);
 	dst = NULL;
 	/* Ensure the dmadev is stopped. */
 	rte_dma_stop(test_dev_id);
@@ -437,6 +465,37 @@ verify_memory(void)
 	return 0;
 }
 
+static void
+sg_memory_setup(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++)
+			src_sg[i][j] = (char)j;
+
+		memset(dst_sg[i], 0, TEST_MEMCPY_SIZE);
+	}
+}
+
+static int
+sg_memory_verify(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++) {
+			if (src_sg[i][j] == dst_sg[i][j])
+				continue;
+
+			RTE_TEST_ASSERT_EQUAL(src_sg[i][j], dst_sg[i][j], "Failed to copy memory, %d %d",
+				src_sg[i][j], dst_sg[i][j]);
+		}
+	}
+
+	return 0;
+}
+
 static int
 test_dma_completed(void)
 {
@@ -551,6 +610,86 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_sg(void)
+{
+	struct rte_dma_sge src_sge[TEST_SG_MAX], dst_sge[TEST_SG_MAX];
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t last_idx = -1;
+	bool has_error = true;
+	int n_sge, i, ret;
+	uint16_t cpl_ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		return TEST_SKIPPED;
+
+	n_sge = RTE_MIN(dev_info.max_sges, TEST_SG_MAX);
+
+	ret = setup_vchan(1);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	for (i = 0; i < n_sge; i++) {
+		src_sge[i].addr = rte_malloc_virt2iova(src_sg[i]);
+		src_sge[i].length = TEST_MEMCPY_SIZE;
+		dst_sge[i].addr = rte_malloc_virt2iova(dst_sg[i]);
+		dst_sge[i].length = TEST_MEMCPY_SIZE;
+	}
+
+	sg_memory_setup(n_sge);
+
+	/* Check enqueue without submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge, 0);
+	RTE_TEST_ASSERT_EQUAL(ret, 0, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_completed(test_dev_id, 0, 1, &last_idx, &has_error);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 0, "Failed to get completed");
+
+	/* Check DMA submit */
+	ret = rte_dma_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_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	sg_memory_setup(n_sge);
+
+	/* Check for enqueue with submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge,
+			      RTE_DMA_OP_FLAG_SUBMIT);
+	RTE_TEST_ASSERT_EQUAL(ret, 1, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	/* Stop dmadev to make sure dmadev to a known state */
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static struct unit_test_suite dma_api_testsuite = {
 	.suite_name = "DMA API Test Suite",
 	.setup = testsuite_setup,
@@ -568,6 +707,7 @@ static struct unit_test_suite dma_api_testsuite = {
 		TEST_CASE(test_dma_dump),
 		TEST_CASE(test_dma_completed),
 		TEST_CASE(test_dma_completed_status),
+		TEST_CASE(test_dma_sg),
 		TEST_CASES_END()
 	}
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v6 0/3] test/dma: add vchan reconfig and SG tests
  2023-11-16 10:40       ` [PATCH v5 " Gowrishankar Muthukrishnan
                           ` (2 preceding siblings ...)
  2023-11-16 10:40         ` [PATCH v5 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
@ 2023-11-16 10:59         ` Gowrishankar Muthukrishnan
  2023-11-16 10:59           ` [PATCH v6 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
                             ` (3 more replies)
  3 siblings, 4 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 10:59 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

This patch series reworks DMA tests to follow unit test framework
followed by new vchan reconfig and SG tests.

v6:
 - fixed coding style warning (to use REGISTER_DRIVER_TEST).

Gowrishankar Muthukrishnan (3):
  test/dma: use unit test framework
  test/dma: test multiple vchan
  test/dma: add SG copy tests

 app/test/test_dmadev.c     | 373 +++++++++++++++++++++++++++++--------
 app/test/test_dmadev_api.c | 316 +++++++++++++++++++++++--------
 2 files changed, 533 insertions(+), 156 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v6 1/3] test/dma: use unit test framework
  2023-11-16 10:59         ` [PATCH v6 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
@ 2023-11-16 10:59           ` Gowrishankar Muthukrishnan
  2023-11-16 10:59           ` [PATCH v6 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
                             ` (2 subsequent siblings)
  3 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 10:59 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Use unit test framework to execute DMA tests.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_dmadev.c     | 234 +++++++++++++++++++++++++------------
 app/test/test_dmadev_api.c |  95 +++++----------
 2 files changed, 192 insertions(+), 137 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 7581fc2b4c..f4a40190e5 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -21,8 +21,12 @@
 #define TEST_RINGSIZE 512
 #define COPY_LEN 1024
 
+static struct rte_dma_info info;
 static struct rte_mempool *pool;
+static bool check_err_stats;
+static int16_t test_dev_id;
 static uint16_t id_count;
+static uint16_t vchan;
 
 enum {
 	TEST_PARAM_REMOTE_ADDR = 0,
@@ -61,13 +65,28 @@ print_err(const char *func, int lineno, const char *format, ...)
 	va_end(ap);
 }
 
+struct runtest_param {
+	const char name[NAME_MAX];
+	int (*test_fn)(int16_t dev_id, uint16_t vchan);
+	int iterations;
+};
+
 static int
-runtest(const char *printable, int (*test_fn)(int16_t dev_id, uint16_t vchan), int iterations,
-		int16_t dev_id, uint16_t vchan, bool check_err_stats)
+runtest(const void *args)
 {
+	int (*test_fn)(int16_t dev_id, uint16_t vchan);
+	const struct runtest_param *param = args;
 	struct rte_dma_stats stats;
+	const char *printable;
+	int iterations;
+	int16_t dev_id;
 	int i;
 
+	printable = param->name;
+	iterations = param->iterations;
+	test_fn = param->test_fn;
+	dev_id = test_dev_id;
+
 	rte_dma_stats_reset(dev_id, vchan);
 	printf("DMA Dev %d: Running %s Tests %s\n", dev_id, printable,
 			check_err_stats ? " " : "(errors expected)");
@@ -911,26 +930,87 @@ prepare_m2d_auto_free(int16_t dev_id, uint16_t vchan)
 }
 
 static int
-test_dmadev_instance(int16_t dev_id)
+test_dmadev_burst_setup(void)
+{
+	if (rte_dma_burst_capacity(test_dev_id, vchan) < 64) {
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
+			test_dev_id);
+		return TEST_SKIPPED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_err_handling_setup(void)
+{
+	int ret = TEST_SKIPPED;
+
+	/* to test error handling we can provide null pointers for source or dest in copies. This
+	 * requires VA mode in DPDK, since NULL(0) is a valid physical address.
+	 * We also need hardware that can report errors back.
+	 */
+	if (rte_eal_iova_mode() != RTE_IOVA_VA)
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n",
+			test_dev_id);
+	else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: device does not report errors, skipping error handling tests\n",
+			test_dev_id);
+	else
+		ret = TEST_SUCCESS;
+
+	return ret;
+}
+
+static int
+test_dmadev_fill_setup(void)
+{
+	int ret = TEST_SUCCESS;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0) {
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: No device fill support, skipping fill tests\n", test_dev_id);
+		ret = TEST_SKIPPED;
+	}
+
+	return ret;
+}
+
+static int
+test_dmadev_autofree_setup(void)
+{
+	int ret = TEST_SKIPPED;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
+	    dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
+		if (prepare_m2d_auto_free(test_dev_id, vchan) != 0)
+			return ret;
+
+		ret = TEST_SUCCESS;
+	}
+
+	return ret;
+}
+
+static int
+test_dmadev_setup(void)
 {
-#define CHECK_ERRS    true
+	int16_t dev_id = test_dev_id;
 	struct rte_dma_stats stats;
-	struct rte_dma_info info;
 	const struct rte_dma_conf conf = { .nb_vchans = 1};
 	const struct rte_dma_vchan_conf qconf = {
 			.direction = RTE_DMA_DIR_MEM_TO_MEM,
 			.nb_desc = TEST_RINGSIZE,
 	};
-	const int vchan = 0;
 	int ret;
 
 	ret = rte_dma_info_get(dev_id, &info);
 	if (ret != 0)
 		ERR_RETURN("Error with rte_dma_info_get()\n");
 
-	printf("\n### Test dmadev instance %u [%s]\n",
-			dev_id, info.dev_name);
-
 	if (info.max_vchans < 1)
 		ERR_RETURN("Error, no channels available on device id %u\n", dev_id);
 
@@ -969,76 +1049,82 @@ test_dmadev_instance(int16_t dev_id)
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
 
-	/* run the test cases, use many iterations to ensure UINT16_MAX id wraparound */
-	if (runtest("copy", test_enqueue_copies, 640, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* run tests stopping/starting devices and check jobs still work after restart */
-	if (runtest("stop-start", test_stop_start, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* run some burst capacity tests */
-	if (rte_dma_burst_capacity(dev_id, vchan) < 64)
-		printf("DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
-				dev_id);
-	else if (runtest("burst capacity", test_burst_capacity, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* to test error handling we can provide null pointers for source or dest in copies. This
-	 * requires VA mode in DPDK, since NULL(0) is a valid physical address.
-	 * We also need hardware that can report errors back.
-	 */
-	if (rte_eal_iova_mode() != RTE_IOVA_VA)
-		printf("DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n", dev_id);
-	else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
-		printf("DMA Dev %u: device does not report errors, skipping error handling tests\n",
-				dev_id);
-	else if (runtest("error handling", test_completion_handling, 1,
-			dev_id, vchan, !CHECK_ERRS) < 0)
-		goto err;
-
-	if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0)
-		printf("DMA Dev %u: No device fill support, skipping fill tests\n", dev_id);
-	else if (runtest("fill", test_enqueue_fill, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
-	    dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
-		if (prepare_m2d_auto_free(dev_id, vchan) != 0)
-			goto err;
-		if (runtest("m2d_auto_free", test_m2d_auto_free, 128, dev_id, vchan,
-			    CHECK_ERRS) < 0)
-			goto err;
-	}
-
-	rte_mempool_free(pool);
-
-	if (rte_dma_stop(dev_id) < 0)
-		ERR_RETURN("Error stopping device %u\n", dev_id);
+	check_err_stats = false;
+	vchan = 0;
 
-	rte_dma_stats_reset(dev_id, vchan);
 	return 0;
+}
 
-err:
+static void
+test_dmadev_teardown(void)
+{
 	rte_mempool_free(pool);
-	rte_dma_stop(dev_id);
-	return -1;
+	rte_dma_stop(test_dev_id);
+	rte_dma_stats_reset(test_dev_id, vchan);
+	test_dev_id = -EINVAL;
 }
 
 static int
-test_apis(void)
+test_dmadev_instance(int16_t dev_id)
 {
-	const char *pmd = "dma_skeleton";
-	int id;
+	struct rte_dma_info dev_info;
+	enum {
+		  TEST_COPY = 0,
+		  TEST_START,
+		  TEST_BURST,
+		  TEST_ERR,
+		  TEST_FILL,
+		  TEST_M2D,
+		  TEST_END
+	};
+
+	static struct runtest_param param[] = {
+		{"copy", test_enqueue_copies, 640},
+		{"stop_start", test_stop_start, 1},
+		{"burst_capacity", test_burst_capacity, 1},
+		{"error_handling", test_completion_handling, 1},
+		{"fill", test_enqueue_fill, 1},
+		{"m2d_auto_free", test_m2d_auto_free, 128},
+	};
+
+	static struct unit_test_suite ts = {
+		.suite_name = "DMA dev instance testsuite",
+		.setup = test_dmadev_setup,
+		.teardown = test_dmadev_teardown,
+		.unit_test_cases = {
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_COPY].name,
+				NULL, NULL,
+				runtest, &param[TEST_COPY]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_START].name,
+				NULL, NULL,
+				runtest, &param[TEST_START]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_BURST].name,
+				test_dmadev_burst_setup, NULL,
+				runtest, &param[TEST_BURST]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_ERR].name,
+				test_dmadev_err_handling_setup, NULL,
+				runtest, &param[TEST_ERR]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_FILL].name,
+				test_dmadev_fill_setup, NULL,
+				runtest, &param[TEST_FILL]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_M2D].name,
+				test_dmadev_autofree_setup, NULL,
+				runtest, &param[TEST_M2D]),
+			TEST_CASES_END()
+		}
+	};
+
 	int ret;
 
-	/* attempt to create skeleton instance - ignore errors due to one being already present */
-	rte_vdev_init(pmd, NULL);
-	id = rte_dma_get_dev_id_by_name(pmd);
-	if (id < 0)
+	if (rte_dma_info_get(dev_id, &dev_info) < 0)
 		return TEST_SKIPPED;
-	printf("\n### Test dmadev infrastructure using skeleton driver\n");
-	ret = test_dma_api(id);
+
+	test_dev_id = dev_id;
+	printf("\n### Test dmadev instance %u [%s]\n",
+		   test_dev_id, dev_info.dev_name);
+
+	ret = unit_test_suite_runner(&ts);
+	test_dev_id = -EINVAL;
 
 	return ret;
 }
@@ -1083,20 +1169,24 @@ parse_dma_env_var(void)
 static int
 test_dma(void)
 {
+	const char *pmd = "dma_skeleton";
 	int i;
 
 	parse_dma_env_var();
 
-	/* basic sanity on dmadev infrastructure */
-	if (test_apis() < 0)
-		ERR_RETURN("Error performing API tests\n");
+	/* attempt to create skeleton instance - ignore errors due to one being already present*/
+	rte_vdev_init(pmd, NULL);
 
 	if (rte_dma_count_avail() == 0)
 		return TEST_SKIPPED;
 
-	RTE_DMA_FOREACH_DEV(i)
+	RTE_DMA_FOREACH_DEV(i) {
+		if (test_dma_api(i) < 0)
+			ERR_RETURN("Error performing API tests\n");
+
 		if (test_dmadev_instance(i) < 0)
 			ERR_RETURN("Error, test failure for device %d\n", i);
+	}
 
 	return 0;
 }
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 4a181af90a..73d4db825a 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -9,31 +9,22 @@
 #include <rte_test.h>
 #include <rte_dmadev.h>
 
-extern int test_dma_api(uint16_t dev_id);
+#include "test.h"
 
-#define DMA_TEST_API_RUN(test) \
-	testsuite_run_test(test, #test)
+extern int test_dma_api(uint16_t dev_id);
 
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
 
-#define TEST_SUCCESS 0
-#define TEST_FAILED  -1
-
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
 
-static int total;
-static int passed;
-static int failed;
-
 static int
-testsuite_setup(int16_t dev_id)
+testsuite_setup(void)
 {
-	test_dev_id = dev_id;
 	invalid_dev_id = -1;
 
 	src = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
@@ -46,10 +37,6 @@ testsuite_setup(int16_t dev_id)
 		return -ENOMEM;
 	}
 
-	total = 0;
-	passed = 0;
-	failed = 0;
-
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
 	 */
@@ -71,25 +58,6 @@ testsuite_teardown(void)
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_INFO);
 }
 
-static void
-testsuite_run_test(int (*test)(void), const char *name)
-{
-	int ret = 0;
-
-	if (test) {
-		ret = test();
-		if (ret < 0) {
-			failed++;
-			printf("%s Failed\n", name);
-		} else {
-			passed++;
-			printf("%s Passed\n", name);
-		}
-	}
-
-	total++;
-}
-
 static int
 test_dma_get_dev_id_by_name(void)
 {
@@ -301,7 +269,7 @@ setup_one_vchan(void)
 
 	ret = rte_dma_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;
+	dev_conf.nb_vchans = 1;
 	ret = rte_dma_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;
@@ -537,38 +505,35 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static struct unit_test_suite dma_api_testsuite = {
+	.suite_name = "DMA API Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE(test_dma_get_dev_id_by_name),
+		TEST_CASE(test_dma_is_valid_dev),
+		TEST_CASE(test_dma_count),
+		TEST_CASE(test_dma_info_get),
+		TEST_CASE(test_dma_configure),
+		TEST_CASE(test_dma_vchan_setup),
+		TEST_CASE(test_dma_start_stop),
+		TEST_CASE(test_dma_stats),
+		TEST_CASE(test_dma_dump),
+		TEST_CASE(test_dma_completed),
+		TEST_CASE(test_dma_completed_status),
+		TEST_CASES_END()
+	}
+};
+
 int
 test_dma_api(uint16_t dev_id)
 {
-	int ret = testsuite_setup(dev_id);
-	if (ret) {
-		printf("testsuite setup fail!\n");
-		return -1;
-	}
+	struct rte_dma_info dev_info;
 
-	/* If the testcase exit successfully, ensure that the test dmadev exist
-	 * and the dmadev is in the stopped state.
-	 */
-	DMA_TEST_API_RUN(test_dma_get_dev_id_by_name);
-	DMA_TEST_API_RUN(test_dma_is_valid_dev);
-	DMA_TEST_API_RUN(test_dma_count);
-	DMA_TEST_API_RUN(test_dma_info_get);
-	DMA_TEST_API_RUN(test_dma_configure);
-	DMA_TEST_API_RUN(test_dma_vchan_setup);
-	DMA_TEST_API_RUN(test_dma_start_stop);
-	DMA_TEST_API_RUN(test_dma_stats);
-	DMA_TEST_API_RUN(test_dma_dump);
-	DMA_TEST_API_RUN(test_dma_completed);
-	DMA_TEST_API_RUN(test_dma_completed_status);
-
-	testsuite_teardown();
-
-	printf("Total tests   : %d\n", total);
-	printf("Passed        : %d\n", passed);
-	printf("Failed        : %d\n", failed);
-
-	if (failed)
-		return -1;
+	if (rte_dma_info_get(dev_id, &dev_info) < 0)
+		return TEST_SKIPPED;
 
-	return 0;
+	printf("\n### Test dmadev infrastructure using %u [%s]\n", dev_id, dev_info.dev_name);
+	test_dev_id = dev_id;
+	return unit_test_suite_runner(&dma_api_testsuite);
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v6 2/3] test/dma: test multiple vchan
  2023-11-16 10:59         ` [PATCH v6 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-11-16 10:59           ` [PATCH v6 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
@ 2023-11-16 10:59           ` Gowrishankar Muthukrishnan
  2023-11-16 10:59           ` [PATCH v6 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
  2023-11-16 13:27           ` [PATCH v7 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  3 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 10:59 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Support API with multiple vchan test.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_dmadev_api.c | 63 +++++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 8 deletions(-)

diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 73d4db825a..2b8a4eda62 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -260,7 +260,7 @@ test_dma_vchan_setup(void)
 }
 
 static int
-setup_one_vchan(void)
+setup_vchan(int nb_vchans)
 {
 	struct rte_dma_vchan_conf vchan_conf = { 0 };
 	struct rte_dma_info dev_info = { 0 };
@@ -269,13 +269,15 @@ setup_one_vchan(void)
 
 	ret = rte_dma_info_get(test_dev_id, &dev_info);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
-	dev_conf.nb_vchans = 1;
+	dev_conf.nb_vchans = nb_vchans;
 	ret = rte_dma_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_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
-	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan, %d", ret);
+	for (int i = 0; i < nb_vchans; i++) {
+		ret = rte_dma_vchan_setup(test_dev_id, i, &vchan_conf);
+		RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan %d, %d", i, ret);
+	}
 
 	return TEST_SUCCESS;
 }
@@ -294,7 +296,7 @@ test_dma_start_stop(void)
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -312,6 +314,50 @@ test_dma_start_stop(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_reconfigure(void)
+{
+	struct rte_dma_conf dev_conf = { 0 };
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t cfg_vchans;
+	int ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	/* At least two vchans required for the test */
+	if (dev_info.max_vchans < 2)
+		return TEST_SKIPPED;
+
+	/* Setup one vchan for later test */
+	ret = setup_vchan(1);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	/* Check reconfigure and vchan setup after device stopped */
+	cfg_vchans = dev_conf.nb_vchans = (dev_info.max_vchans - 1);
+
+	ret = setup_vchan(cfg_vchans);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+	RTE_TEST_ASSERT_EQUAL(dev_info.nb_vchans, cfg_vchans, "incorrect reconfiguration");
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static int
 test_dma_stats(void)
 {
@@ -328,7 +374,7 @@ test_dma_stats(void)
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	/* Check for invalid vchan */
@@ -400,7 +446,7 @@ test_dma_completed(void)
 	int ret;
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -459,7 +505,7 @@ test_dma_completed_status(void)
 	int ret;
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -517,6 +563,7 @@ static struct unit_test_suite dma_api_testsuite = {
 		TEST_CASE(test_dma_configure),
 		TEST_CASE(test_dma_vchan_setup),
 		TEST_CASE(test_dma_start_stop),
+		TEST_CASE(test_dma_reconfigure),
 		TEST_CASE(test_dma_stats),
 		TEST_CASE(test_dma_dump),
 		TEST_CASE(test_dma_completed),
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v6 3/3] test/dma: add SG copy tests
  2023-11-16 10:59         ` [PATCH v6 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-11-16 10:59           ` [PATCH v6 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
  2023-11-16 10:59           ` [PATCH v6 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
@ 2023-11-16 10:59           ` Gowrishankar Muthukrishnan
  2023-11-16 13:27           ` [PATCH v7 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  3 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 10:59 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Add scatter-gather copy tests.

Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_dmadev.c     | 139 ++++++++++++++++++++++++++++++-
 app/test/test_dmadev_api.c | 164 ++++++++++++++++++++++++++++++++++---
 2 files changed, 289 insertions(+), 14 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index f4a40190e5..d426ea0a85 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -19,7 +19,7 @@
 #define ERR_RETURN(...) do { print_err(__func__, __LINE__, __VA_ARGS__); return -1; } while (0)
 
 #define TEST_RINGSIZE 512
-#define COPY_LEN 1024
+#define COPY_LEN 2048
 
 static struct rte_dma_info info;
 static struct rte_mempool *pool;
@@ -391,6 +391,125 @@ test_stop_start(int16_t dev_id, uint16_t vchan)
 	return 0;
 }
 
+static int
+test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
+{
+	unsigned int src_len, dst_len, n_sge, len, i, j, k;
+	char orig_src[COPY_LEN], orig_dst[COPY_LEN];
+	struct rte_dma_info info = { 0 };
+	enum rte_dma_status_code status;
+	uint16_t id, n_src, n_dst;
+
+	if (rte_dma_info_get(dev_id, &info) < 0)
+		ERR_RETURN("Failed to get dev info");
+
+	if (info.max_sges < 2)
+		ERR_RETURN("Test needs minimum 2 SG pointers");
+
+	n_sge = info.max_sges;
+
+	for (n_src = 1; n_src <= n_sge; n_src++) {
+		for (n_dst = 1; n_dst <= n_sge; n_dst++) {
+			/* Normalize SG buffer lengths */
+			len = COPY_LEN;
+			len -= (len % (n_src * n_dst));
+			dst_len = len / n_dst;
+			src_len = len / n_src;
+
+			struct rte_dma_sge sg_src[n_sge], sg_dst[n_sge];
+			struct rte_mbuf *src[n_sge], *dst[n_sge];
+			char *src_data[n_sge], *dst_data[n_sge];
+
+			for (i = 0 ; i < len; i++)
+				orig_src[i] = rte_rand() & 0xFF;
+
+			memset(orig_dst, 0, len);
+
+			for (i = 0; i < n_src; i++) {
+				src[i] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(src[i] != NULL);
+				sg_src[i].addr = rte_pktmbuf_iova(src[i]);
+				sg_src[i].length = src_len;
+				src_data[i] = rte_pktmbuf_mtod(src[i], char *);
+			}
+
+			for (k = 0; k < n_dst; k++) {
+				dst[k] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(dst[k] != NULL);
+				sg_dst[k].addr = rte_pktmbuf_iova(dst[k]);
+				sg_dst[k].length = dst_len;
+				dst_data[k] = rte_pktmbuf_mtod(dst[k], char *);
+			}
+
+			for (i = 0; i < n_src; i++) {
+				for (j = 0; j < src_len; j++)
+					src_data[i][j] = orig_src[i * src_len + j];
+			}
+
+			for (k = 0; k < n_dst; k++)
+				memset(dst_data[k], 0, dst_len);
+
+			printf("\tsrc segs: %2d [seg len: %4d] - dst segs: %2d [seg len : %4d]\n",
+				n_src, src_len, n_dst, dst_len);
+
+			id = rte_dma_copy_sg(dev_id, vchan, sg_src, sg_dst, n_src, n_dst,
+					     RTE_DMA_OP_FLAG_SUBMIT);
+
+			if (id != id_count)
+				ERR_RETURN("Error with rte_dma_copy_sg, got %u, expected %u\n",
+					id, id_count);
+
+			/* Give time for copy to finish, then check it was done */
+			await_hw(dev_id, vchan);
+
+			for (k = 0; k < n_dst; k++)
+				memcpy((&orig_dst[0] + k * dst_len), dst_data[k], dst_len);
+
+			if (memcmp(orig_src, orig_dst, COPY_LEN))
+				ERR_RETURN("Data mismatch");
+
+			/* Verify completion */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 1)
+				ERR_RETURN("Error with rte_dma_completed\n");
+
+			/* Verify expected index(id_count) */
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received, %u [expected %u]\n",
+						id, id_count);
+
+			/* Check for completed and id when no job done */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed when no job done\n");
+
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+					   id, id_count);
+
+			/* Check for completed_status and id when no job done */
+			id = ~id;
+			if (rte_dma_completed_status(dev_id, vchan, 1, &id, &status) != 0)
+				ERR_RETURN("Error with rte_dma_completed_status when no job done\n");
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+						id, 0);
+
+			for (i = 0; i < n_src; i++)
+				rte_pktmbuf_free(src[i]);
+			for (i = 0; i < n_dst; i++)
+				rte_pktmbuf_free(dst[i]);
+
+			/* Verify that completion returns nothing more */
+			if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed in empty check\n");
+
+			id_count++;
+		}
+	}
+	return 0;
+}
+
 /* Failure handling test cases - global macros and variables for those tests*/
 #define COMP_BURST_SZ	16
 #define OPT_FENCE(idx) ((fence && idx == 8) ? RTE_DMA_OP_FLAG_FENCE : 0)
@@ -929,6 +1048,17 @@ prepare_m2d_auto_free(int16_t dev_id, uint16_t vchan)
 	return 0;
 }
 
+static int
+test_dmadev_sg_copy_setup(void)
+{
+	int ret = TEST_SUCCESS;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		return TEST_SKIPPED;
+
+	return ret;
+}
+
 static int
 test_dmadev_burst_setup(void)
 {
@@ -1044,7 +1174,7 @@ test_dmadev_setup(void)
 			TEST_RINGSIZE * 2, /* n == num elements */
 			32,  /* cache size */
 			0,   /* priv size */
-			2048, /* data room size */
+			COPY_LEN + RTE_PKTMBUF_HEADROOM, /* data room size */
 			info.numa_node);
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
@@ -1070,6 +1200,7 @@ test_dmadev_instance(int16_t dev_id)
 	struct rte_dma_info dev_info;
 	enum {
 		  TEST_COPY = 0,
+		  TEST_COPY_SG,
 		  TEST_START,
 		  TEST_BURST,
 		  TEST_ERR,
@@ -1080,6 +1211,7 @@ test_dmadev_instance(int16_t dev_id)
 
 	static struct runtest_param param[] = {
 		{"copy", test_enqueue_copies, 640},
+		{"sg_copy", test_enqueue_sg_copies, 1},
 		{"stop_start", test_stop_start, 1},
 		{"burst_capacity", test_burst_capacity, 1},
 		{"error_handling", test_completion_handling, 1},
@@ -1095,6 +1227,9 @@ test_dmadev_instance(int16_t dev_id)
 			TEST_CASE_NAMED_WITH_DATA(param[TEST_COPY].name,
 				NULL, NULL,
 				runtest, &param[TEST_COPY]),
+			TEST_CASE_NAMED_WITH_DATA(param[TEST_COPY_SG].name,
+				test_dmadev_sg_copy_setup, NULL,
+				runtest, &param[TEST_COPY_SG]),
 			TEST_CASE_NAMED_WITH_DATA(param[TEST_START].name,
 				NULL, NULL,
 				runtest, &param[TEST_START]),
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 2b8a4eda62..a130e74b51 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -10,47 +10,75 @@
 #include <rte_dmadev.h>
 
 #include "test.h"
+#include "test_dmadev_api.h"
 
 extern int test_dma_api(uint16_t dev_id);
 
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
+#define TEST_SG_MAX		64
 
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
+static char *src_sg[TEST_SG_MAX];
+static char *dst_sg[TEST_SG_MAX];
 
 static int
 testsuite_setup(void)
 {
 	invalid_dev_id = -1;
-
-	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) {
-		rte_free(src);
-		src = NULL;
-		return -ENOMEM;
+	int i, rc = 0;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		src_sg[i] = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
+		if (src_sg[i] == NULL) {
+			rc = -ENOMEM;
+			goto exit;
+		}
+
+		dst_sg[i] = rte_malloc("dmadev_test_dst", TEST_MEMCPY_SIZE, 0);
+		if (dst_sg[i] == NULL) {
+			rte_free(src_sg[i]);
+			src_sg[i] = NULL;
+			rc = -ENOMEM;
+			goto exit;
+		}
 	}
 
+	src = src_sg[0];
+	dst = dst_sg[0];
+
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
 	 */
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_CRIT);
 
-	return 0;
+	return rc;
+exit:
+	while (--i >= 0) {
+		rte_free(src_sg[i]);
+		rte_free(dst_sg[i]);
+	}
+
+	return rc;
 }
 
 static void
 testsuite_teardown(void)
 {
-	rte_free(src);
+	int i;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		rte_free(src_sg[i]);
+		src_sg[i] = NULL;
+		rte_free(dst_sg[i]);
+		dst_sg[i] = NULL;
+	}
+
 	src = NULL;
-	rte_free(dst);
 	dst = NULL;
 	/* Ensure the dmadev is stopped. */
 	rte_dma_stop(test_dev_id);
@@ -437,6 +465,37 @@ verify_memory(void)
 	return 0;
 }
 
+static void
+sg_memory_setup(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++)
+			src_sg[i][j] = (char)j;
+
+		memset(dst_sg[i], 0, TEST_MEMCPY_SIZE);
+	}
+}
+
+static int
+sg_memory_verify(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++) {
+			if (src_sg[i][j] == dst_sg[i][j])
+				continue;
+
+			RTE_TEST_ASSERT_EQUAL(src_sg[i][j], dst_sg[i][j], "Failed to copy memory, %d %d",
+				src_sg[i][j], dst_sg[i][j]);
+		}
+	}
+
+	return 0;
+}
+
 static int
 test_dma_completed(void)
 {
@@ -551,6 +610,86 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_sg(void)
+{
+	struct rte_dma_sge src_sge[TEST_SG_MAX], dst_sge[TEST_SG_MAX];
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t last_idx = -1;
+	bool has_error = true;
+	int n_sge, i, ret;
+	uint16_t cpl_ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		return TEST_SKIPPED;
+
+	n_sge = RTE_MIN(dev_info.max_sges, TEST_SG_MAX);
+
+	ret = setup_vchan(1);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	for (i = 0; i < n_sge; i++) {
+		src_sge[i].addr = rte_malloc_virt2iova(src_sg[i]);
+		src_sge[i].length = TEST_MEMCPY_SIZE;
+		dst_sge[i].addr = rte_malloc_virt2iova(dst_sg[i]);
+		dst_sge[i].length = TEST_MEMCPY_SIZE;
+	}
+
+	sg_memory_setup(n_sge);
+
+	/* Check enqueue without submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge, 0);
+	RTE_TEST_ASSERT_EQUAL(ret, 0, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_completed(test_dev_id, 0, 1, &last_idx, &has_error);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 0, "Failed to get completed");
+
+	/* Check DMA submit */
+	ret = rte_dma_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_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	sg_memory_setup(n_sge);
+
+	/* Check for enqueue with submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge,
+			      RTE_DMA_OP_FLAG_SUBMIT);
+	RTE_TEST_ASSERT_EQUAL(ret, 1, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	/* Stop dmadev to make sure dmadev to a known state */
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static struct unit_test_suite dma_api_testsuite = {
 	.suite_name = "DMA API Test Suite",
 	.setup = testsuite_setup,
@@ -568,6 +707,7 @@ static struct unit_test_suite dma_api_testsuite = {
 		TEST_CASE(test_dma_dump),
 		TEST_CASE(test_dma_completed),
 		TEST_CASE(test_dma_completed_status),
+		TEST_CASE(test_dma_sg),
 		TEST_CASES_END()
 	}
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 0/3] test/dma: add vchan reconfig and SG tests
  2023-11-16 10:59         ` [PATCH v6 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
                             ` (2 preceding siblings ...)
  2023-11-16 10:59           ` [PATCH v6 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
@ 2023-11-16 13:27           ` Gowrishankar Muthukrishnan
  2023-11-16 13:27             ` [PATCH v7 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
                               ` (3 more replies)
  3 siblings, 4 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 13:27 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

This patch series reworks DMA tests to follow unit test framework
followed by new vchan reconfig and SG tests.

v7:
 - Addressed compilation issue in Windows platform.

Gowrishankar Muthukrishnan (3):
  test/dma: use unit test framework
  test/dma: test multiple vchan
  test/dma: add SG copy tests

 app/test/test_dmadev.c     | 373 +++++++++++++++++++++++++++++--------
 app/test/test_dmadev_api.c | 316 +++++++++++++++++++++++--------
 2 files changed, 533 insertions(+), 156 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 1/3] test/dma: use unit test framework
  2023-11-16 13:27           ` [PATCH v7 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
@ 2023-11-16 13:27             ` Gowrishankar Muthukrishnan
  2023-11-16 13:27             ` [PATCH v7 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
                               ` (2 subsequent siblings)
  3 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 13:27 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Use unit test framework to execute DMA tests.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
v7:
 - Used string const in unit_test_cases name member to avoid
   compilation failure in Windows platform.
---
 app/test/test_dmadev.c     | 234 +++++++++++++++++++++++++------------
 app/test/test_dmadev_api.c |  95 +++++----------
 2 files changed, 192 insertions(+), 137 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 7581fc2b4c..2d20e716d2 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -21,8 +21,12 @@
 #define TEST_RINGSIZE 512
 #define COPY_LEN 1024
 
+static struct rte_dma_info info;
 static struct rte_mempool *pool;
+static bool check_err_stats;
+static int16_t test_dev_id;
 static uint16_t id_count;
+static uint16_t vchan;
 
 enum {
 	TEST_PARAM_REMOTE_ADDR = 0,
@@ -61,13 +65,28 @@ print_err(const char *func, int lineno, const char *format, ...)
 	va_end(ap);
 }
 
+struct runtest_param {
+	const char name[NAME_MAX];
+	int (*test_fn)(int16_t dev_id, uint16_t vchan);
+	int iterations;
+};
+
 static int
-runtest(const char *printable, int (*test_fn)(int16_t dev_id, uint16_t vchan), int iterations,
-		int16_t dev_id, uint16_t vchan, bool check_err_stats)
+runtest(const void *args)
 {
+	int (*test_fn)(int16_t dev_id, uint16_t vchan);
+	const struct runtest_param *param = args;
 	struct rte_dma_stats stats;
+	const char *printable;
+	int iterations;
+	int16_t dev_id;
 	int i;
 
+	printable = param->name;
+	iterations = param->iterations;
+	test_fn = param->test_fn;
+	dev_id = test_dev_id;
+
 	rte_dma_stats_reset(dev_id, vchan);
 	printf("DMA Dev %d: Running %s Tests %s\n", dev_id, printable,
 			check_err_stats ? " " : "(errors expected)");
@@ -911,26 +930,87 @@ prepare_m2d_auto_free(int16_t dev_id, uint16_t vchan)
 }
 
 static int
-test_dmadev_instance(int16_t dev_id)
+test_dmadev_burst_setup(void)
+{
+	if (rte_dma_burst_capacity(test_dev_id, vchan) < 64) {
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
+			test_dev_id);
+		return TEST_SKIPPED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_err_handling_setup(void)
+{
+	int ret = TEST_SKIPPED;
+
+	/* to test error handling we can provide null pointers for source or dest in copies. This
+	 * requires VA mode in DPDK, since NULL(0) is a valid physical address.
+	 * We also need hardware that can report errors back.
+	 */
+	if (rte_eal_iova_mode() != RTE_IOVA_VA)
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n",
+			test_dev_id);
+	else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: device does not report errors, skipping error handling tests\n",
+			test_dev_id);
+	else
+		ret = TEST_SUCCESS;
+
+	return ret;
+}
+
+static int
+test_dmadev_fill_setup(void)
+{
+	int ret = TEST_SUCCESS;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0) {
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: No device fill support, skipping fill tests\n", test_dev_id);
+		ret = TEST_SKIPPED;
+	}
+
+	return ret;
+}
+
+static int
+test_dmadev_autofree_setup(void)
+{
+	int ret = TEST_SKIPPED;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
+	    dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
+		if (prepare_m2d_auto_free(test_dev_id, vchan) != 0)
+			return ret;
+
+		ret = TEST_SUCCESS;
+	}
+
+	return ret;
+}
+
+static int
+test_dmadev_setup(void)
 {
-#define CHECK_ERRS    true
+	int16_t dev_id = test_dev_id;
 	struct rte_dma_stats stats;
-	struct rte_dma_info info;
 	const struct rte_dma_conf conf = { .nb_vchans = 1};
 	const struct rte_dma_vchan_conf qconf = {
 			.direction = RTE_DMA_DIR_MEM_TO_MEM,
 			.nb_desc = TEST_RINGSIZE,
 	};
-	const int vchan = 0;
 	int ret;
 
 	ret = rte_dma_info_get(dev_id, &info);
 	if (ret != 0)
 		ERR_RETURN("Error with rte_dma_info_get()\n");
 
-	printf("\n### Test dmadev instance %u [%s]\n",
-			dev_id, info.dev_name);
-
 	if (info.max_vchans < 1)
 		ERR_RETURN("Error, no channels available on device id %u\n", dev_id);
 
@@ -969,76 +1049,82 @@ test_dmadev_instance(int16_t dev_id)
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
 
-	/* run the test cases, use many iterations to ensure UINT16_MAX id wraparound */
-	if (runtest("copy", test_enqueue_copies, 640, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* run tests stopping/starting devices and check jobs still work after restart */
-	if (runtest("stop-start", test_stop_start, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* run some burst capacity tests */
-	if (rte_dma_burst_capacity(dev_id, vchan) < 64)
-		printf("DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
-				dev_id);
-	else if (runtest("burst capacity", test_burst_capacity, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* to test error handling we can provide null pointers for source or dest in copies. This
-	 * requires VA mode in DPDK, since NULL(0) is a valid physical address.
-	 * We also need hardware that can report errors back.
-	 */
-	if (rte_eal_iova_mode() != RTE_IOVA_VA)
-		printf("DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n", dev_id);
-	else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
-		printf("DMA Dev %u: device does not report errors, skipping error handling tests\n",
-				dev_id);
-	else if (runtest("error handling", test_completion_handling, 1,
-			dev_id, vchan, !CHECK_ERRS) < 0)
-		goto err;
-
-	if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0)
-		printf("DMA Dev %u: No device fill support, skipping fill tests\n", dev_id);
-	else if (runtest("fill", test_enqueue_fill, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
-	    dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
-		if (prepare_m2d_auto_free(dev_id, vchan) != 0)
-			goto err;
-		if (runtest("m2d_auto_free", test_m2d_auto_free, 128, dev_id, vchan,
-			    CHECK_ERRS) < 0)
-			goto err;
-	}
-
-	rte_mempool_free(pool);
-
-	if (rte_dma_stop(dev_id) < 0)
-		ERR_RETURN("Error stopping device %u\n", dev_id);
+	check_err_stats = false;
+	vchan = 0;
 
-	rte_dma_stats_reset(dev_id, vchan);
 	return 0;
+}
 
-err:
+static void
+test_dmadev_teardown(void)
+{
 	rte_mempool_free(pool);
-	rte_dma_stop(dev_id);
-	return -1;
+	rte_dma_stop(test_dev_id);
+	rte_dma_stats_reset(test_dev_id, vchan);
+	test_dev_id = -EINVAL;
 }
 
 static int
-test_apis(void)
+test_dmadev_instance(int16_t dev_id)
 {
-	const char *pmd = "dma_skeleton";
-	int id;
+	struct rte_dma_info dev_info;
+	enum {
+		  TEST_COPY = 0,
+		  TEST_START,
+		  TEST_BURST,
+		  TEST_ERR,
+		  TEST_FILL,
+		  TEST_M2D,
+		  TEST_END
+	};
+
+	static struct runtest_param param[] = {
+		{"copy", test_enqueue_copies, 640},
+		{"stop_start", test_stop_start, 1},
+		{"burst_capacity", test_burst_capacity, 1},
+		{"error_handling", test_completion_handling, 1},
+		{"fill", test_enqueue_fill, 1},
+		{"m2d_auto_free", test_m2d_auto_free, 128},
+	};
+
+	static struct unit_test_suite ts = {
+		.suite_name = "DMA dev instance testsuite",
+		.setup = test_dmadev_setup,
+		.teardown = test_dmadev_teardown,
+		.unit_test_cases = {
+			TEST_CASE_NAMED_WITH_DATA("copy",
+				NULL, NULL,
+				runtest, &param[TEST_COPY]),
+			TEST_CASE_NAMED_WITH_DATA("stop_start",
+				NULL, NULL,
+				runtest, &param[TEST_START]),
+			TEST_CASE_NAMED_WITH_DATA("burst_capacity",
+				test_dmadev_burst_setup, NULL,
+				runtest, &param[TEST_BURST]),
+			TEST_CASE_NAMED_WITH_DATA("error_handling",
+				test_dmadev_err_handling_setup, NULL,
+				runtest, &param[TEST_ERR]),
+			TEST_CASE_NAMED_WITH_DATA("fill",
+				test_dmadev_fill_setup, NULL,
+				runtest, &param[TEST_FILL]),
+			TEST_CASE_NAMED_WITH_DATA("m2d_autofree",
+				test_dmadev_autofree_setup, NULL,
+				runtest, &param[TEST_M2D]),
+			TEST_CASES_END()
+		}
+	};
+
 	int ret;
 
-	/* attempt to create skeleton instance - ignore errors due to one being already present */
-	rte_vdev_init(pmd, NULL);
-	id = rte_dma_get_dev_id_by_name(pmd);
-	if (id < 0)
+	if (rte_dma_info_get(dev_id, &dev_info) < 0)
 		return TEST_SKIPPED;
-	printf("\n### Test dmadev infrastructure using skeleton driver\n");
-	ret = test_dma_api(id);
+
+	test_dev_id = dev_id;
+	printf("\n### Test dmadev instance %u [%s]\n",
+		   test_dev_id, dev_info.dev_name);
+
+	ret = unit_test_suite_runner(&ts);
+	test_dev_id = -EINVAL;
 
 	return ret;
 }
@@ -1083,20 +1169,24 @@ parse_dma_env_var(void)
 static int
 test_dma(void)
 {
+	const char *pmd = "dma_skeleton";
 	int i;
 
 	parse_dma_env_var();
 
-	/* basic sanity on dmadev infrastructure */
-	if (test_apis() < 0)
-		ERR_RETURN("Error performing API tests\n");
+	/* attempt to create skeleton instance - ignore errors due to one being already present*/
+	rte_vdev_init(pmd, NULL);
 
 	if (rte_dma_count_avail() == 0)
 		return TEST_SKIPPED;
 
-	RTE_DMA_FOREACH_DEV(i)
+	RTE_DMA_FOREACH_DEV(i) {
+		if (test_dma_api(i) < 0)
+			ERR_RETURN("Error performing API tests\n");
+
 		if (test_dmadev_instance(i) < 0)
 			ERR_RETURN("Error, test failure for device %d\n", i);
+	}
 
 	return 0;
 }
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 4a181af90a..73d4db825a 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -9,31 +9,22 @@
 #include <rte_test.h>
 #include <rte_dmadev.h>
 
-extern int test_dma_api(uint16_t dev_id);
+#include "test.h"
 
-#define DMA_TEST_API_RUN(test) \
-	testsuite_run_test(test, #test)
+extern int test_dma_api(uint16_t dev_id);
 
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
 
-#define TEST_SUCCESS 0
-#define TEST_FAILED  -1
-
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
 
-static int total;
-static int passed;
-static int failed;
-
 static int
-testsuite_setup(int16_t dev_id)
+testsuite_setup(void)
 {
-	test_dev_id = dev_id;
 	invalid_dev_id = -1;
 
 	src = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
@@ -46,10 +37,6 @@ testsuite_setup(int16_t dev_id)
 		return -ENOMEM;
 	}
 
-	total = 0;
-	passed = 0;
-	failed = 0;
-
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
 	 */
@@ -71,25 +58,6 @@ testsuite_teardown(void)
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_INFO);
 }
 
-static void
-testsuite_run_test(int (*test)(void), const char *name)
-{
-	int ret = 0;
-
-	if (test) {
-		ret = test();
-		if (ret < 0) {
-			failed++;
-			printf("%s Failed\n", name);
-		} else {
-			passed++;
-			printf("%s Passed\n", name);
-		}
-	}
-
-	total++;
-}
-
 static int
 test_dma_get_dev_id_by_name(void)
 {
@@ -301,7 +269,7 @@ setup_one_vchan(void)
 
 	ret = rte_dma_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;
+	dev_conf.nb_vchans = 1;
 	ret = rte_dma_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;
@@ -537,38 +505,35 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static struct unit_test_suite dma_api_testsuite = {
+	.suite_name = "DMA API Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE(test_dma_get_dev_id_by_name),
+		TEST_CASE(test_dma_is_valid_dev),
+		TEST_CASE(test_dma_count),
+		TEST_CASE(test_dma_info_get),
+		TEST_CASE(test_dma_configure),
+		TEST_CASE(test_dma_vchan_setup),
+		TEST_CASE(test_dma_start_stop),
+		TEST_CASE(test_dma_stats),
+		TEST_CASE(test_dma_dump),
+		TEST_CASE(test_dma_completed),
+		TEST_CASE(test_dma_completed_status),
+		TEST_CASES_END()
+	}
+};
+
 int
 test_dma_api(uint16_t dev_id)
 {
-	int ret = testsuite_setup(dev_id);
-	if (ret) {
-		printf("testsuite setup fail!\n");
-		return -1;
-	}
+	struct rte_dma_info dev_info;
 
-	/* If the testcase exit successfully, ensure that the test dmadev exist
-	 * and the dmadev is in the stopped state.
-	 */
-	DMA_TEST_API_RUN(test_dma_get_dev_id_by_name);
-	DMA_TEST_API_RUN(test_dma_is_valid_dev);
-	DMA_TEST_API_RUN(test_dma_count);
-	DMA_TEST_API_RUN(test_dma_info_get);
-	DMA_TEST_API_RUN(test_dma_configure);
-	DMA_TEST_API_RUN(test_dma_vchan_setup);
-	DMA_TEST_API_RUN(test_dma_start_stop);
-	DMA_TEST_API_RUN(test_dma_stats);
-	DMA_TEST_API_RUN(test_dma_dump);
-	DMA_TEST_API_RUN(test_dma_completed);
-	DMA_TEST_API_RUN(test_dma_completed_status);
-
-	testsuite_teardown();
-
-	printf("Total tests   : %d\n", total);
-	printf("Passed        : %d\n", passed);
-	printf("Failed        : %d\n", failed);
-
-	if (failed)
-		return -1;
+	if (rte_dma_info_get(dev_id, &dev_info) < 0)
+		return TEST_SKIPPED;
 
-	return 0;
+	printf("\n### Test dmadev infrastructure using %u [%s]\n", dev_id, dev_info.dev_name);
+	test_dev_id = dev_id;
+	return unit_test_suite_runner(&dma_api_testsuite);
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 2/3] test/dma: test multiple vchan
  2023-11-16 13:27           ` [PATCH v7 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-11-16 13:27             ` [PATCH v7 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
@ 2023-11-16 13:27             ` Gowrishankar Muthukrishnan
  2023-11-16 13:27             ` [PATCH v7 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
  2023-11-16 17:45             ` [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  3 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 13:27 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Support API with multiple vchan test.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_dmadev_api.c | 63 +++++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 8 deletions(-)

diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 73d4db825a..2b8a4eda62 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -260,7 +260,7 @@ test_dma_vchan_setup(void)
 }
 
 static int
-setup_one_vchan(void)
+setup_vchan(int nb_vchans)
 {
 	struct rte_dma_vchan_conf vchan_conf = { 0 };
 	struct rte_dma_info dev_info = { 0 };
@@ -269,13 +269,15 @@ setup_one_vchan(void)
 
 	ret = rte_dma_info_get(test_dev_id, &dev_info);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
-	dev_conf.nb_vchans = 1;
+	dev_conf.nb_vchans = nb_vchans;
 	ret = rte_dma_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_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
-	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan, %d", ret);
+	for (int i = 0; i < nb_vchans; i++) {
+		ret = rte_dma_vchan_setup(test_dev_id, i, &vchan_conf);
+		RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan %d, %d", i, ret);
+	}
 
 	return TEST_SUCCESS;
 }
@@ -294,7 +296,7 @@ test_dma_start_stop(void)
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -312,6 +314,50 @@ test_dma_start_stop(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_reconfigure(void)
+{
+	struct rte_dma_conf dev_conf = { 0 };
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t cfg_vchans;
+	int ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	/* At least two vchans required for the test */
+	if (dev_info.max_vchans < 2)
+		return TEST_SKIPPED;
+
+	/* Setup one vchan for later test */
+	ret = setup_vchan(1);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	/* Check reconfigure and vchan setup after device stopped */
+	cfg_vchans = dev_conf.nb_vchans = (dev_info.max_vchans - 1);
+
+	ret = setup_vchan(cfg_vchans);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+	RTE_TEST_ASSERT_EQUAL(dev_info.nb_vchans, cfg_vchans, "incorrect reconfiguration");
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static int
 test_dma_stats(void)
 {
@@ -328,7 +374,7 @@ test_dma_stats(void)
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	/* Check for invalid vchan */
@@ -400,7 +446,7 @@ test_dma_completed(void)
 	int ret;
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -459,7 +505,7 @@ test_dma_completed_status(void)
 	int ret;
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -517,6 +563,7 @@ static struct unit_test_suite dma_api_testsuite = {
 		TEST_CASE(test_dma_configure),
 		TEST_CASE(test_dma_vchan_setup),
 		TEST_CASE(test_dma_start_stop),
+		TEST_CASE(test_dma_reconfigure),
 		TEST_CASE(test_dma_stats),
 		TEST_CASE(test_dma_dump),
 		TEST_CASE(test_dma_completed),
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v7 3/3] test/dma: add SG copy tests
  2023-11-16 13:27           ` [PATCH v7 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-11-16 13:27             ` [PATCH v7 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
  2023-11-16 13:27             ` [PATCH v7 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
@ 2023-11-16 13:27             ` Gowrishankar Muthukrishnan
  2023-11-16 17:45             ` [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  3 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 13:27 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Add scatter-gather copy tests.

Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_dmadev.c     | 139 ++++++++++++++++++++++++++++++-
 app/test/test_dmadev_api.c | 164 ++++++++++++++++++++++++++++++++++---
 2 files changed, 289 insertions(+), 14 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 2d20e716d2..d7cbb9a861 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -19,7 +19,7 @@
 #define ERR_RETURN(...) do { print_err(__func__, __LINE__, __VA_ARGS__); return -1; } while (0)
 
 #define TEST_RINGSIZE 512
-#define COPY_LEN 1024
+#define COPY_LEN 2048
 
 static struct rte_dma_info info;
 static struct rte_mempool *pool;
@@ -391,6 +391,125 @@ test_stop_start(int16_t dev_id, uint16_t vchan)
 	return 0;
 }
 
+static int
+test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
+{
+	unsigned int src_len, dst_len, n_sge, len, i, j, k;
+	char orig_src[COPY_LEN], orig_dst[COPY_LEN];
+	struct rte_dma_info info = { 0 };
+	enum rte_dma_status_code status;
+	uint16_t id, n_src, n_dst;
+
+	if (rte_dma_info_get(dev_id, &info) < 0)
+		ERR_RETURN("Failed to get dev info");
+
+	if (info.max_sges < 2)
+		ERR_RETURN("Test needs minimum 2 SG pointers");
+
+	n_sge = info.max_sges;
+
+	for (n_src = 1; n_src <= n_sge; n_src++) {
+		for (n_dst = 1; n_dst <= n_sge; n_dst++) {
+			/* Normalize SG buffer lengths */
+			len = COPY_LEN;
+			len -= (len % (n_src * n_dst));
+			dst_len = len / n_dst;
+			src_len = len / n_src;
+
+			struct rte_dma_sge sg_src[n_sge], sg_dst[n_sge];
+			struct rte_mbuf *src[n_sge], *dst[n_sge];
+			char *src_data[n_sge], *dst_data[n_sge];
+
+			for (i = 0 ; i < len; i++)
+				orig_src[i] = rte_rand() & 0xFF;
+
+			memset(orig_dst, 0, len);
+
+			for (i = 0; i < n_src; i++) {
+				src[i] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(src[i] != NULL);
+				sg_src[i].addr = rte_pktmbuf_iova(src[i]);
+				sg_src[i].length = src_len;
+				src_data[i] = rte_pktmbuf_mtod(src[i], char *);
+			}
+
+			for (k = 0; k < n_dst; k++) {
+				dst[k] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(dst[k] != NULL);
+				sg_dst[k].addr = rte_pktmbuf_iova(dst[k]);
+				sg_dst[k].length = dst_len;
+				dst_data[k] = rte_pktmbuf_mtod(dst[k], char *);
+			}
+
+			for (i = 0; i < n_src; i++) {
+				for (j = 0; j < src_len; j++)
+					src_data[i][j] = orig_src[i * src_len + j];
+			}
+
+			for (k = 0; k < n_dst; k++)
+				memset(dst_data[k], 0, dst_len);
+
+			printf("\tsrc segs: %2d [seg len: %4d] - dst segs: %2d [seg len : %4d]\n",
+				n_src, src_len, n_dst, dst_len);
+
+			id = rte_dma_copy_sg(dev_id, vchan, sg_src, sg_dst, n_src, n_dst,
+					     RTE_DMA_OP_FLAG_SUBMIT);
+
+			if (id != id_count)
+				ERR_RETURN("Error with rte_dma_copy_sg, got %u, expected %u\n",
+					id, id_count);
+
+			/* Give time for copy to finish, then check it was done */
+			await_hw(dev_id, vchan);
+
+			for (k = 0; k < n_dst; k++)
+				memcpy((&orig_dst[0] + k * dst_len), dst_data[k], dst_len);
+
+			if (memcmp(orig_src, orig_dst, COPY_LEN))
+				ERR_RETURN("Data mismatch");
+
+			/* Verify completion */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 1)
+				ERR_RETURN("Error with rte_dma_completed\n");
+
+			/* Verify expected index(id_count) */
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received, %u [expected %u]\n",
+						id, id_count);
+
+			/* Check for completed and id when no job done */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed when no job done\n");
+
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+					   id, id_count);
+
+			/* Check for completed_status and id when no job done */
+			id = ~id;
+			if (rte_dma_completed_status(dev_id, vchan, 1, &id, &status) != 0)
+				ERR_RETURN("Error with rte_dma_completed_status when no job done\n");
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+						id, 0);
+
+			for (i = 0; i < n_src; i++)
+				rte_pktmbuf_free(src[i]);
+			for (i = 0; i < n_dst; i++)
+				rte_pktmbuf_free(dst[i]);
+
+			/* Verify that completion returns nothing more */
+			if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed in empty check\n");
+
+			id_count++;
+		}
+	}
+	return 0;
+}
+
 /* Failure handling test cases - global macros and variables for those tests*/
 #define COMP_BURST_SZ	16
 #define OPT_FENCE(idx) ((fence && idx == 8) ? RTE_DMA_OP_FLAG_FENCE : 0)
@@ -929,6 +1048,17 @@ prepare_m2d_auto_free(int16_t dev_id, uint16_t vchan)
 	return 0;
 }
 
+static int
+test_dmadev_sg_copy_setup(void)
+{
+	int ret = TEST_SUCCESS;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		return TEST_SKIPPED;
+
+	return ret;
+}
+
 static int
 test_dmadev_burst_setup(void)
 {
@@ -1044,7 +1174,7 @@ test_dmadev_setup(void)
 			TEST_RINGSIZE * 2, /* n == num elements */
 			32,  /* cache size */
 			0,   /* priv size */
-			2048, /* data room size */
+			COPY_LEN + RTE_PKTMBUF_HEADROOM, /* data room size */
 			info.numa_node);
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
@@ -1070,6 +1200,7 @@ test_dmadev_instance(int16_t dev_id)
 	struct rte_dma_info dev_info;
 	enum {
 		  TEST_COPY = 0,
+		  TEST_COPY_SG,
 		  TEST_START,
 		  TEST_BURST,
 		  TEST_ERR,
@@ -1080,6 +1211,7 @@ test_dmadev_instance(int16_t dev_id)
 
 	static struct runtest_param param[] = {
 		{"copy", test_enqueue_copies, 640},
+		{"sg_copy", test_enqueue_sg_copies, 1},
 		{"stop_start", test_stop_start, 1},
 		{"burst_capacity", test_burst_capacity, 1},
 		{"error_handling", test_completion_handling, 1},
@@ -1095,6 +1227,9 @@ test_dmadev_instance(int16_t dev_id)
 			TEST_CASE_NAMED_WITH_DATA("copy",
 				NULL, NULL,
 				runtest, &param[TEST_COPY]),
+			TEST_CASE_NAMED_WITH_DATA("sg_copy",
+				test_dmadev_sg_copy_setup, NULL,
+				runtest, &param[TEST_COPY_SG]),
 			TEST_CASE_NAMED_WITH_DATA("stop_start",
 				NULL, NULL,
 				runtest, &param[TEST_START]),
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 2b8a4eda62..a130e74b51 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -10,47 +10,75 @@
 #include <rte_dmadev.h>
 
 #include "test.h"
+#include "test_dmadev_api.h"
 
 extern int test_dma_api(uint16_t dev_id);
 
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
+#define TEST_SG_MAX		64
 
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
+static char *src_sg[TEST_SG_MAX];
+static char *dst_sg[TEST_SG_MAX];
 
 static int
 testsuite_setup(void)
 {
 	invalid_dev_id = -1;
-
-	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) {
-		rte_free(src);
-		src = NULL;
-		return -ENOMEM;
+	int i, rc = 0;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		src_sg[i] = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
+		if (src_sg[i] == NULL) {
+			rc = -ENOMEM;
+			goto exit;
+		}
+
+		dst_sg[i] = rte_malloc("dmadev_test_dst", TEST_MEMCPY_SIZE, 0);
+		if (dst_sg[i] == NULL) {
+			rte_free(src_sg[i]);
+			src_sg[i] = NULL;
+			rc = -ENOMEM;
+			goto exit;
+		}
 	}
 
+	src = src_sg[0];
+	dst = dst_sg[0];
+
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
 	 */
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_CRIT);
 
-	return 0;
+	return rc;
+exit:
+	while (--i >= 0) {
+		rte_free(src_sg[i]);
+		rte_free(dst_sg[i]);
+	}
+
+	return rc;
 }
 
 static void
 testsuite_teardown(void)
 {
-	rte_free(src);
+	int i;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		rte_free(src_sg[i]);
+		src_sg[i] = NULL;
+		rte_free(dst_sg[i]);
+		dst_sg[i] = NULL;
+	}
+
 	src = NULL;
-	rte_free(dst);
 	dst = NULL;
 	/* Ensure the dmadev is stopped. */
 	rte_dma_stop(test_dev_id);
@@ -437,6 +465,37 @@ verify_memory(void)
 	return 0;
 }
 
+static void
+sg_memory_setup(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++)
+			src_sg[i][j] = (char)j;
+
+		memset(dst_sg[i], 0, TEST_MEMCPY_SIZE);
+	}
+}
+
+static int
+sg_memory_verify(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++) {
+			if (src_sg[i][j] == dst_sg[i][j])
+				continue;
+
+			RTE_TEST_ASSERT_EQUAL(src_sg[i][j], dst_sg[i][j], "Failed to copy memory, %d %d",
+				src_sg[i][j], dst_sg[i][j]);
+		}
+	}
+
+	return 0;
+}
+
 static int
 test_dma_completed(void)
 {
@@ -551,6 +610,86 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_sg(void)
+{
+	struct rte_dma_sge src_sge[TEST_SG_MAX], dst_sge[TEST_SG_MAX];
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t last_idx = -1;
+	bool has_error = true;
+	int n_sge, i, ret;
+	uint16_t cpl_ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		return TEST_SKIPPED;
+
+	n_sge = RTE_MIN(dev_info.max_sges, TEST_SG_MAX);
+
+	ret = setup_vchan(1);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	for (i = 0; i < n_sge; i++) {
+		src_sge[i].addr = rte_malloc_virt2iova(src_sg[i]);
+		src_sge[i].length = TEST_MEMCPY_SIZE;
+		dst_sge[i].addr = rte_malloc_virt2iova(dst_sg[i]);
+		dst_sge[i].length = TEST_MEMCPY_SIZE;
+	}
+
+	sg_memory_setup(n_sge);
+
+	/* Check enqueue without submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge, 0);
+	RTE_TEST_ASSERT_EQUAL(ret, 0, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_completed(test_dev_id, 0, 1, &last_idx, &has_error);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 0, "Failed to get completed");
+
+	/* Check DMA submit */
+	ret = rte_dma_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_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	sg_memory_setup(n_sge);
+
+	/* Check for enqueue with submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge,
+			      RTE_DMA_OP_FLAG_SUBMIT);
+	RTE_TEST_ASSERT_EQUAL(ret, 1, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	/* Stop dmadev to make sure dmadev to a known state */
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static struct unit_test_suite dma_api_testsuite = {
 	.suite_name = "DMA API Test Suite",
 	.setup = testsuite_setup,
@@ -568,6 +707,7 @@ static struct unit_test_suite dma_api_testsuite = {
 		TEST_CASE(test_dma_dump),
 		TEST_CASE(test_dma_completed),
 		TEST_CASE(test_dma_completed_status),
+		TEST_CASE(test_dma_sg),
 		TEST_CASES_END()
 	}
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests
  2023-11-16 13:27           ` [PATCH v7 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
                               ` (2 preceding siblings ...)
  2023-11-16 13:27             ` [PATCH v7 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
@ 2023-11-16 17:45             ` Gowrishankar Muthukrishnan
  2023-11-16 17:45               ` [PATCH v8 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
                                 ` (4 more replies)
  3 siblings, 5 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 17:45 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

This patch series reworks DMA tests to follow unit test framework
followed by new vchan reconfig and SG tests.

v8:
 - Addressed compilation issue in Windows platform.

Gowrishankar Muthukrishnan (3):
  test/dma: use unit test framework
  test/dma: test multiple vchan
  test/dma: add SG copy tests

 app/test/test_dmadev.c     | 374 +++++++++++++++++++++++++++++--------
 app/test/test_dmadev_api.c | 316 +++++++++++++++++++++++--------
 2 files changed, 534 insertions(+), 156 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v8 1/3] test/dma: use unit test framework
  2023-11-16 17:45             ` [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
@ 2023-11-16 17:45               ` Gowrishankar Muthukrishnan
  2023-11-16 17:45               ` [PATCH v8 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
                                 ` (3 subsequent siblings)
  4 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 17:45 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Use unit test framework to execute DMA tests.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
v8:
 - Used local macro instead of NAME_MAX, due to compilation
   issue in Windows.
---
 app/test/test_dmadev.c     | 235 +++++++++++++++++++++++++------------
 app/test/test_dmadev_api.c |  95 +++++----------
 2 files changed, 193 insertions(+), 137 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 7581fc2b4c..94673720c4 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -18,11 +18,16 @@
 
 #define ERR_RETURN(...) do { print_err(__func__, __LINE__, __VA_ARGS__); return -1; } while (0)
 
+#define TEST_NAME_MAX_LEN 80
 #define TEST_RINGSIZE 512
 #define COPY_LEN 1024
 
+static struct rte_dma_info info;
 static struct rte_mempool *pool;
+static bool check_err_stats;
+static int16_t test_dev_id;
 static uint16_t id_count;
+static uint16_t vchan;
 
 enum {
 	TEST_PARAM_REMOTE_ADDR = 0,
@@ -61,13 +66,28 @@ print_err(const char *func, int lineno, const char *format, ...)
 	va_end(ap);
 }
 
+struct runtest_param {
+	const char name[TEST_NAME_MAX_LEN];
+	int (*test_fn)(int16_t dev_id, uint16_t vchan);
+	int iterations;
+};
+
 static int
-runtest(const char *printable, int (*test_fn)(int16_t dev_id, uint16_t vchan), int iterations,
-		int16_t dev_id, uint16_t vchan, bool check_err_stats)
+runtest(const void *args)
 {
+	int (*test_fn)(int16_t dev_id, uint16_t vchan);
+	const struct runtest_param *param = args;
 	struct rte_dma_stats stats;
+	const char *printable;
+	int iterations;
+	int16_t dev_id;
 	int i;
 
+	printable = param->name;
+	iterations = param->iterations;
+	test_fn = param->test_fn;
+	dev_id = test_dev_id;
+
 	rte_dma_stats_reset(dev_id, vchan);
 	printf("DMA Dev %d: Running %s Tests %s\n", dev_id, printable,
 			check_err_stats ? " " : "(errors expected)");
@@ -911,26 +931,87 @@ prepare_m2d_auto_free(int16_t dev_id, uint16_t vchan)
 }
 
 static int
-test_dmadev_instance(int16_t dev_id)
+test_dmadev_burst_setup(void)
+{
+	if (rte_dma_burst_capacity(test_dev_id, vchan) < 64) {
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
+			test_dev_id);
+		return TEST_SKIPPED;
+	}
+
+	return TEST_SUCCESS;
+}
+
+static int
+test_dmadev_err_handling_setup(void)
+{
+	int ret = TEST_SKIPPED;
+
+	/* to test error handling we can provide null pointers for source or dest in copies. This
+	 * requires VA mode in DPDK, since NULL(0) is a valid physical address.
+	 * We also need hardware that can report errors back.
+	 */
+	if (rte_eal_iova_mode() != RTE_IOVA_VA)
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n",
+			test_dev_id);
+	else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: device does not report errors, skipping error handling tests\n",
+			test_dev_id);
+	else
+		ret = TEST_SUCCESS;
+
+	return ret;
+}
+
+static int
+test_dmadev_fill_setup(void)
+{
+	int ret = TEST_SUCCESS;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0) {
+		RTE_LOG(ERR, USER1,
+			"DMA Dev %u: No device fill support, skipping fill tests\n", test_dev_id);
+		ret = TEST_SKIPPED;
+	}
+
+	return ret;
+}
+
+static int
+test_dmadev_autofree_setup(void)
+{
+	int ret = TEST_SKIPPED;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
+	    dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
+		if (prepare_m2d_auto_free(test_dev_id, vchan) != 0)
+			return ret;
+
+		ret = TEST_SUCCESS;
+	}
+
+	return ret;
+}
+
+static int
+test_dmadev_setup(void)
 {
-#define CHECK_ERRS    true
+	int16_t dev_id = test_dev_id;
 	struct rte_dma_stats stats;
-	struct rte_dma_info info;
 	const struct rte_dma_conf conf = { .nb_vchans = 1};
 	const struct rte_dma_vchan_conf qconf = {
 			.direction = RTE_DMA_DIR_MEM_TO_MEM,
 			.nb_desc = TEST_RINGSIZE,
 	};
-	const int vchan = 0;
 	int ret;
 
 	ret = rte_dma_info_get(dev_id, &info);
 	if (ret != 0)
 		ERR_RETURN("Error with rte_dma_info_get()\n");
 
-	printf("\n### Test dmadev instance %u [%s]\n",
-			dev_id, info.dev_name);
-
 	if (info.max_vchans < 1)
 		ERR_RETURN("Error, no channels available on device id %u\n", dev_id);
 
@@ -969,76 +1050,82 @@ test_dmadev_instance(int16_t dev_id)
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
 
-	/* run the test cases, use many iterations to ensure UINT16_MAX id wraparound */
-	if (runtest("copy", test_enqueue_copies, 640, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* run tests stopping/starting devices and check jobs still work after restart */
-	if (runtest("stop-start", test_stop_start, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* run some burst capacity tests */
-	if (rte_dma_burst_capacity(dev_id, vchan) < 64)
-		printf("DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
-				dev_id);
-	else if (runtest("burst capacity", test_burst_capacity, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	/* to test error handling we can provide null pointers for source or dest in copies. This
-	 * requires VA mode in DPDK, since NULL(0) is a valid physical address.
-	 * We also need hardware that can report errors back.
-	 */
-	if (rte_eal_iova_mode() != RTE_IOVA_VA)
-		printf("DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n", dev_id);
-	else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
-		printf("DMA Dev %u: device does not report errors, skipping error handling tests\n",
-				dev_id);
-	else if (runtest("error handling", test_completion_handling, 1,
-			dev_id, vchan, !CHECK_ERRS) < 0)
-		goto err;
-
-	if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0)
-		printf("DMA Dev %u: No device fill support, skipping fill tests\n", dev_id);
-	else if (runtest("fill", test_enqueue_fill, 1, dev_id, vchan, CHECK_ERRS) < 0)
-		goto err;
-
-	if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
-	    dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
-		if (prepare_m2d_auto_free(dev_id, vchan) != 0)
-			goto err;
-		if (runtest("m2d_auto_free", test_m2d_auto_free, 128, dev_id, vchan,
-			    CHECK_ERRS) < 0)
-			goto err;
-	}
-
-	rte_mempool_free(pool);
-
-	if (rte_dma_stop(dev_id) < 0)
-		ERR_RETURN("Error stopping device %u\n", dev_id);
+	check_err_stats = false;
+	vchan = 0;
 
-	rte_dma_stats_reset(dev_id, vchan);
 	return 0;
+}
 
-err:
+static void
+test_dmadev_teardown(void)
+{
 	rte_mempool_free(pool);
-	rte_dma_stop(dev_id);
-	return -1;
+	rte_dma_stop(test_dev_id);
+	rte_dma_stats_reset(test_dev_id, vchan);
+	test_dev_id = -EINVAL;
 }
 
 static int
-test_apis(void)
+test_dmadev_instance(int16_t dev_id)
 {
-	const char *pmd = "dma_skeleton";
-	int id;
+	struct rte_dma_info dev_info;
+	enum {
+		  TEST_COPY = 0,
+		  TEST_START,
+		  TEST_BURST,
+		  TEST_ERR,
+		  TEST_FILL,
+		  TEST_M2D,
+		  TEST_END
+	};
+
+	static struct runtest_param param[] = {
+		{"copy", test_enqueue_copies, 640},
+		{"stop_start", test_stop_start, 1},
+		{"burst_capacity", test_burst_capacity, 1},
+		{"error_handling", test_completion_handling, 1},
+		{"fill", test_enqueue_fill, 1},
+		{"m2d_auto_free", test_m2d_auto_free, 128},
+	};
+
+	static struct unit_test_suite ts = {
+		.suite_name = "DMA dev instance testsuite",
+		.setup = test_dmadev_setup,
+		.teardown = test_dmadev_teardown,
+		.unit_test_cases = {
+			TEST_CASE_NAMED_WITH_DATA("copy",
+				NULL, NULL,
+				runtest, &param[TEST_COPY]),
+			TEST_CASE_NAMED_WITH_DATA("stop_start",
+				NULL, NULL,
+				runtest, &param[TEST_START]),
+			TEST_CASE_NAMED_WITH_DATA("burst_capacity",
+				test_dmadev_burst_setup, NULL,
+				runtest, &param[TEST_BURST]),
+			TEST_CASE_NAMED_WITH_DATA("error_handling",
+				test_dmadev_err_handling_setup, NULL,
+				runtest, &param[TEST_ERR]),
+			TEST_CASE_NAMED_WITH_DATA("fill",
+				test_dmadev_fill_setup, NULL,
+				runtest, &param[TEST_FILL]),
+			TEST_CASE_NAMED_WITH_DATA("m2d_autofree",
+				test_dmadev_autofree_setup, NULL,
+				runtest, &param[TEST_M2D]),
+			TEST_CASES_END()
+		}
+	};
+
 	int ret;
 
-	/* attempt to create skeleton instance - ignore errors due to one being already present */
-	rte_vdev_init(pmd, NULL);
-	id = rte_dma_get_dev_id_by_name(pmd);
-	if (id < 0)
+	if (rte_dma_info_get(dev_id, &dev_info) < 0)
 		return TEST_SKIPPED;
-	printf("\n### Test dmadev infrastructure using skeleton driver\n");
-	ret = test_dma_api(id);
+
+	test_dev_id = dev_id;
+	printf("\n### Test dmadev instance %u [%s]\n",
+		   test_dev_id, dev_info.dev_name);
+
+	ret = unit_test_suite_runner(&ts);
+	test_dev_id = -EINVAL;
 
 	return ret;
 }
@@ -1083,20 +1170,24 @@ parse_dma_env_var(void)
 static int
 test_dma(void)
 {
+	const char *pmd = "dma_skeleton";
 	int i;
 
 	parse_dma_env_var();
 
-	/* basic sanity on dmadev infrastructure */
-	if (test_apis() < 0)
-		ERR_RETURN("Error performing API tests\n");
+	/* attempt to create skeleton instance - ignore errors due to one being already present*/
+	rte_vdev_init(pmd, NULL);
 
 	if (rte_dma_count_avail() == 0)
 		return TEST_SKIPPED;
 
-	RTE_DMA_FOREACH_DEV(i)
+	RTE_DMA_FOREACH_DEV(i) {
+		if (test_dma_api(i) < 0)
+			ERR_RETURN("Error performing API tests\n");
+
 		if (test_dmadev_instance(i) < 0)
 			ERR_RETURN("Error, test failure for device %d\n", i);
+	}
 
 	return 0;
 }
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 4a181af90a..73d4db825a 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -9,31 +9,22 @@
 #include <rte_test.h>
 #include <rte_dmadev.h>
 
-extern int test_dma_api(uint16_t dev_id);
+#include "test.h"
 
-#define DMA_TEST_API_RUN(test) \
-	testsuite_run_test(test, #test)
+extern int test_dma_api(uint16_t dev_id);
 
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
 
-#define TEST_SUCCESS 0
-#define TEST_FAILED  -1
-
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
 
-static int total;
-static int passed;
-static int failed;
-
 static int
-testsuite_setup(int16_t dev_id)
+testsuite_setup(void)
 {
-	test_dev_id = dev_id;
 	invalid_dev_id = -1;
 
 	src = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
@@ -46,10 +37,6 @@ testsuite_setup(int16_t dev_id)
 		return -ENOMEM;
 	}
 
-	total = 0;
-	passed = 0;
-	failed = 0;
-
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
 	 */
@@ -71,25 +58,6 @@ testsuite_teardown(void)
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_INFO);
 }
 
-static void
-testsuite_run_test(int (*test)(void), const char *name)
-{
-	int ret = 0;
-
-	if (test) {
-		ret = test();
-		if (ret < 0) {
-			failed++;
-			printf("%s Failed\n", name);
-		} else {
-			passed++;
-			printf("%s Passed\n", name);
-		}
-	}
-
-	total++;
-}
-
 static int
 test_dma_get_dev_id_by_name(void)
 {
@@ -301,7 +269,7 @@ setup_one_vchan(void)
 
 	ret = rte_dma_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;
+	dev_conf.nb_vchans = 1;
 	ret = rte_dma_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;
@@ -537,38 +505,35 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static struct unit_test_suite dma_api_testsuite = {
+	.suite_name = "DMA API Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE(test_dma_get_dev_id_by_name),
+		TEST_CASE(test_dma_is_valid_dev),
+		TEST_CASE(test_dma_count),
+		TEST_CASE(test_dma_info_get),
+		TEST_CASE(test_dma_configure),
+		TEST_CASE(test_dma_vchan_setup),
+		TEST_CASE(test_dma_start_stop),
+		TEST_CASE(test_dma_stats),
+		TEST_CASE(test_dma_dump),
+		TEST_CASE(test_dma_completed),
+		TEST_CASE(test_dma_completed_status),
+		TEST_CASES_END()
+	}
+};
+
 int
 test_dma_api(uint16_t dev_id)
 {
-	int ret = testsuite_setup(dev_id);
-	if (ret) {
-		printf("testsuite setup fail!\n");
-		return -1;
-	}
+	struct rte_dma_info dev_info;
 
-	/* If the testcase exit successfully, ensure that the test dmadev exist
-	 * and the dmadev is in the stopped state.
-	 */
-	DMA_TEST_API_RUN(test_dma_get_dev_id_by_name);
-	DMA_TEST_API_RUN(test_dma_is_valid_dev);
-	DMA_TEST_API_RUN(test_dma_count);
-	DMA_TEST_API_RUN(test_dma_info_get);
-	DMA_TEST_API_RUN(test_dma_configure);
-	DMA_TEST_API_RUN(test_dma_vchan_setup);
-	DMA_TEST_API_RUN(test_dma_start_stop);
-	DMA_TEST_API_RUN(test_dma_stats);
-	DMA_TEST_API_RUN(test_dma_dump);
-	DMA_TEST_API_RUN(test_dma_completed);
-	DMA_TEST_API_RUN(test_dma_completed_status);
-
-	testsuite_teardown();
-
-	printf("Total tests   : %d\n", total);
-	printf("Passed        : %d\n", passed);
-	printf("Failed        : %d\n", failed);
-
-	if (failed)
-		return -1;
+	if (rte_dma_info_get(dev_id, &dev_info) < 0)
+		return TEST_SKIPPED;
 
-	return 0;
+	printf("\n### Test dmadev infrastructure using %u [%s]\n", dev_id, dev_info.dev_name);
+	test_dev_id = dev_id;
+	return unit_test_suite_runner(&dma_api_testsuite);
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v8 2/3] test/dma: test multiple vchan
  2023-11-16 17:45             ` [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-11-16 17:45               ` [PATCH v8 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
@ 2023-11-16 17:45               ` Gowrishankar Muthukrishnan
  2023-11-16 17:45               ` [PATCH v8 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
                                 ` (2 subsequent siblings)
  4 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 17:45 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Support API with multiple vchan test.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_dmadev_api.c | 63 +++++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 8 deletions(-)

diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 73d4db825a..2b8a4eda62 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -260,7 +260,7 @@ test_dma_vchan_setup(void)
 }
 
 static int
-setup_one_vchan(void)
+setup_vchan(int nb_vchans)
 {
 	struct rte_dma_vchan_conf vchan_conf = { 0 };
 	struct rte_dma_info dev_info = { 0 };
@@ -269,13 +269,15 @@ setup_one_vchan(void)
 
 	ret = rte_dma_info_get(test_dev_id, &dev_info);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
-	dev_conf.nb_vchans = 1;
+	dev_conf.nb_vchans = nb_vchans;
 	ret = rte_dma_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_dma_vchan_setup(test_dev_id, 0, &vchan_conf);
-	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan, %d", ret);
+	for (int i = 0; i < nb_vchans; i++) {
+		ret = rte_dma_vchan_setup(test_dev_id, i, &vchan_conf);
+		RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup vchan %d, %d", i, ret);
+	}
 
 	return TEST_SUCCESS;
 }
@@ -294,7 +296,7 @@ test_dma_start_stop(void)
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -312,6 +314,50 @@ test_dma_start_stop(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_reconfigure(void)
+{
+	struct rte_dma_conf dev_conf = { 0 };
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t cfg_vchans;
+	int ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	/* At least two vchans required for the test */
+	if (dev_info.max_vchans < 2)
+		return TEST_SKIPPED;
+
+	/* Setup one vchan for later test */
+	ret = setup_vchan(1);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	/* Check reconfigure and vchan setup after device stopped */
+	cfg_vchans = dev_conf.nb_vchans = (dev_info.max_vchans - 1);
+
+	ret = setup_vchan(cfg_vchans);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+	RTE_TEST_ASSERT_EQUAL(dev_info.nb_vchans, cfg_vchans, "incorrect reconfiguration");
+
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static int
 test_dma_stats(void)
 {
@@ -328,7 +374,7 @@ test_dma_stats(void)
 	RTE_TEST_ASSERT(ret == -EINVAL, "Expected -EINVAL, %d", ret);
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	/* Check for invalid vchan */
@@ -400,7 +446,7 @@ test_dma_completed(void)
 	int ret;
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -459,7 +505,7 @@ test_dma_completed_status(void)
 	int ret;
 
 	/* Setup one vchan for later test */
-	ret = setup_one_vchan();
+	ret = setup_vchan(1);
 	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
 
 	ret = rte_dma_start(test_dev_id);
@@ -517,6 +563,7 @@ static struct unit_test_suite dma_api_testsuite = {
 		TEST_CASE(test_dma_configure),
 		TEST_CASE(test_dma_vchan_setup),
 		TEST_CASE(test_dma_start_stop),
+		TEST_CASE(test_dma_reconfigure),
 		TEST_CASE(test_dma_stats),
 		TEST_CASE(test_dma_dump),
 		TEST_CASE(test_dma_completed),
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v8 3/3] test/dma: add SG copy tests
  2023-11-16 17:45             ` [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2023-11-16 17:45               ` [PATCH v8 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
  2023-11-16 17:45               ` [PATCH v8 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
@ 2023-11-16 17:45               ` Gowrishankar Muthukrishnan
  2023-12-07 10:10               ` [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
  2024-03-06 19:45               ` Thomas Monjalon
  4 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-11-16 17:45 UTC (permalink / raw)
  To: dev
  Cc: anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson,
	Gowrishankar Muthukrishnan

Add scatter-gather copy tests.

Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_dmadev.c     | 139 ++++++++++++++++++++++++++++++-
 app/test/test_dmadev_api.c | 164 ++++++++++++++++++++++++++++++++++---
 2 files changed, 289 insertions(+), 14 deletions(-)

diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
index 94673720c4..143e1bcd68 100644
--- a/app/test/test_dmadev.c
+++ b/app/test/test_dmadev.c
@@ -20,7 +20,7 @@
 
 #define TEST_NAME_MAX_LEN 80
 #define TEST_RINGSIZE 512
-#define COPY_LEN 1024
+#define COPY_LEN 2048
 
 static struct rte_dma_info info;
 static struct rte_mempool *pool;
@@ -392,6 +392,125 @@ test_stop_start(int16_t dev_id, uint16_t vchan)
 	return 0;
 }
 
+static int
+test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
+{
+	unsigned int src_len, dst_len, n_sge, len, i, j, k;
+	char orig_src[COPY_LEN], orig_dst[COPY_LEN];
+	struct rte_dma_info info = { 0 };
+	enum rte_dma_status_code status;
+	uint16_t id, n_src, n_dst;
+
+	if (rte_dma_info_get(dev_id, &info) < 0)
+		ERR_RETURN("Failed to get dev info");
+
+	if (info.max_sges < 2)
+		ERR_RETURN("Test needs minimum 2 SG pointers");
+
+	n_sge = info.max_sges;
+
+	for (n_src = 1; n_src <= n_sge; n_src++) {
+		for (n_dst = 1; n_dst <= n_sge; n_dst++) {
+			/* Normalize SG buffer lengths */
+			len = COPY_LEN;
+			len -= (len % (n_src * n_dst));
+			dst_len = len / n_dst;
+			src_len = len / n_src;
+
+			struct rte_dma_sge sg_src[n_sge], sg_dst[n_sge];
+			struct rte_mbuf *src[n_sge], *dst[n_sge];
+			char *src_data[n_sge], *dst_data[n_sge];
+
+			for (i = 0 ; i < len; i++)
+				orig_src[i] = rte_rand() & 0xFF;
+
+			memset(orig_dst, 0, len);
+
+			for (i = 0; i < n_src; i++) {
+				src[i] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(src[i] != NULL);
+				sg_src[i].addr = rte_pktmbuf_iova(src[i]);
+				sg_src[i].length = src_len;
+				src_data[i] = rte_pktmbuf_mtod(src[i], char *);
+			}
+
+			for (k = 0; k < n_dst; k++) {
+				dst[k] = rte_pktmbuf_alloc(pool);
+				RTE_ASSERT(dst[k] != NULL);
+				sg_dst[k].addr = rte_pktmbuf_iova(dst[k]);
+				sg_dst[k].length = dst_len;
+				dst_data[k] = rte_pktmbuf_mtod(dst[k], char *);
+			}
+
+			for (i = 0; i < n_src; i++) {
+				for (j = 0; j < src_len; j++)
+					src_data[i][j] = orig_src[i * src_len + j];
+			}
+
+			for (k = 0; k < n_dst; k++)
+				memset(dst_data[k], 0, dst_len);
+
+			printf("\tsrc segs: %2d [seg len: %4d] - dst segs: %2d [seg len : %4d]\n",
+				n_src, src_len, n_dst, dst_len);
+
+			id = rte_dma_copy_sg(dev_id, vchan, sg_src, sg_dst, n_src, n_dst,
+					     RTE_DMA_OP_FLAG_SUBMIT);
+
+			if (id != id_count)
+				ERR_RETURN("Error with rte_dma_copy_sg, got %u, expected %u\n",
+					id, id_count);
+
+			/* Give time for copy to finish, then check it was done */
+			await_hw(dev_id, vchan);
+
+			for (k = 0; k < n_dst; k++)
+				memcpy((&orig_dst[0] + k * dst_len), dst_data[k], dst_len);
+
+			if (memcmp(orig_src, orig_dst, COPY_LEN))
+				ERR_RETURN("Data mismatch");
+
+			/* Verify completion */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 1)
+				ERR_RETURN("Error with rte_dma_completed\n");
+
+			/* Verify expected index(id_count) */
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received, %u [expected %u]\n",
+						id, id_count);
+
+			/* Check for completed and id when no job done */
+			id = ~id;
+			if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed when no job done\n");
+
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+					   id, id_count);
+
+			/* Check for completed_status and id when no job done */
+			id = ~id;
+			if (rte_dma_completed_status(dev_id, vchan, 1, &id, &status) != 0)
+				ERR_RETURN("Error with rte_dma_completed_status when no job done\n");
+			if (id != id_count)
+				ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
+						id, 0);
+
+			for (i = 0; i < n_src; i++)
+				rte_pktmbuf_free(src[i]);
+			for (i = 0; i < n_dst; i++)
+				rte_pktmbuf_free(dst[i]);
+
+			/* Verify that completion returns nothing more */
+			if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
+				ERR_RETURN("Error with rte_dma_completed in empty check\n");
+
+			id_count++;
+		}
+	}
+	return 0;
+}
+
 /* Failure handling test cases - global macros and variables for those tests*/
 #define COMP_BURST_SZ	16
 #define OPT_FENCE(idx) ((fence && idx == 8) ? RTE_DMA_OP_FLAG_FENCE : 0)
@@ -930,6 +1049,17 @@ prepare_m2d_auto_free(int16_t dev_id, uint16_t vchan)
 	return 0;
 }
 
+static int
+test_dmadev_sg_copy_setup(void)
+{
+	int ret = TEST_SUCCESS;
+
+	if ((info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		return TEST_SKIPPED;
+
+	return ret;
+}
+
 static int
 test_dmadev_burst_setup(void)
 {
@@ -1045,7 +1175,7 @@ test_dmadev_setup(void)
 			TEST_RINGSIZE * 2, /* n == num elements */
 			32,  /* cache size */
 			0,   /* priv size */
-			2048, /* data room size */
+			COPY_LEN + RTE_PKTMBUF_HEADROOM, /* data room size */
 			info.numa_node);
 	if (pool == NULL)
 		ERR_RETURN("Error with mempool creation\n");
@@ -1071,6 +1201,7 @@ test_dmadev_instance(int16_t dev_id)
 	struct rte_dma_info dev_info;
 	enum {
 		  TEST_COPY = 0,
+		  TEST_COPY_SG,
 		  TEST_START,
 		  TEST_BURST,
 		  TEST_ERR,
@@ -1081,6 +1212,7 @@ test_dmadev_instance(int16_t dev_id)
 
 	static struct runtest_param param[] = {
 		{"copy", test_enqueue_copies, 640},
+		{"sg_copy", test_enqueue_sg_copies, 1},
 		{"stop_start", test_stop_start, 1},
 		{"burst_capacity", test_burst_capacity, 1},
 		{"error_handling", test_completion_handling, 1},
@@ -1096,6 +1228,9 @@ test_dmadev_instance(int16_t dev_id)
 			TEST_CASE_NAMED_WITH_DATA("copy",
 				NULL, NULL,
 				runtest, &param[TEST_COPY]),
+			TEST_CASE_NAMED_WITH_DATA("sg_copy",
+				test_dmadev_sg_copy_setup, NULL,
+				runtest, &param[TEST_COPY_SG]),
 			TEST_CASE_NAMED_WITH_DATA("stop_start",
 				NULL, NULL,
 				runtest, &param[TEST_START]),
diff --git a/app/test/test_dmadev_api.c b/app/test/test_dmadev_api.c
index 2b8a4eda62..a130e74b51 100644
--- a/app/test/test_dmadev_api.c
+++ b/app/test/test_dmadev_api.c
@@ -10,47 +10,75 @@
 #include <rte_dmadev.h>
 
 #include "test.h"
+#include "test_dmadev_api.h"
 
 extern int test_dma_api(uint16_t dev_id);
 
 #define TEST_MEMCPY_SIZE	1024
 #define TEST_WAIT_US_VAL	50000
+#define TEST_SG_MAX		64
 
 static int16_t test_dev_id;
 static int16_t invalid_dev_id;
 
 static char *src;
 static char *dst;
+static char *src_sg[TEST_SG_MAX];
+static char *dst_sg[TEST_SG_MAX];
 
 static int
 testsuite_setup(void)
 {
 	invalid_dev_id = -1;
-
-	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) {
-		rte_free(src);
-		src = NULL;
-		return -ENOMEM;
+	int i, rc = 0;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		src_sg[i] = rte_malloc("dmadev_test_src", TEST_MEMCPY_SIZE, 0);
+		if (src_sg[i] == NULL) {
+			rc = -ENOMEM;
+			goto exit;
+		}
+
+		dst_sg[i] = rte_malloc("dmadev_test_dst", TEST_MEMCPY_SIZE, 0);
+		if (dst_sg[i] == NULL) {
+			rte_free(src_sg[i]);
+			src_sg[i] = NULL;
+			rc = -ENOMEM;
+			goto exit;
+		}
 	}
 
+	src = src_sg[0];
+	dst = dst_sg[0];
+
 	/* Set dmadev log level to critical to suppress unnecessary output
 	 * during API tests.
 	 */
 	rte_log_set_level_pattern("lib.dmadev", RTE_LOG_CRIT);
 
-	return 0;
+	return rc;
+exit:
+	while (--i >= 0) {
+		rte_free(src_sg[i]);
+		rte_free(dst_sg[i]);
+	}
+
+	return rc;
 }
 
 static void
 testsuite_teardown(void)
 {
-	rte_free(src);
+	int i;
+
+	for (i = 0; i < TEST_SG_MAX; i++) {
+		rte_free(src_sg[i]);
+		src_sg[i] = NULL;
+		rte_free(dst_sg[i]);
+		dst_sg[i] = NULL;
+	}
+
 	src = NULL;
-	rte_free(dst);
 	dst = NULL;
 	/* Ensure the dmadev is stopped. */
 	rte_dma_stop(test_dev_id);
@@ -437,6 +465,37 @@ verify_memory(void)
 	return 0;
 }
 
+static void
+sg_memory_setup(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++)
+			src_sg[i][j] = (char)j;
+
+		memset(dst_sg[i], 0, TEST_MEMCPY_SIZE);
+	}
+}
+
+static int
+sg_memory_verify(int n)
+{
+	int i, j;
+
+	for (i = 0; i < n; i++) {
+		for (j = 0; j < TEST_MEMCPY_SIZE; j++) {
+			if (src_sg[i][j] == dst_sg[i][j])
+				continue;
+
+			RTE_TEST_ASSERT_EQUAL(src_sg[i][j], dst_sg[i][j], "Failed to copy memory, %d %d",
+				src_sg[i][j], dst_sg[i][j]);
+		}
+	}
+
+	return 0;
+}
+
 static int
 test_dma_completed(void)
 {
@@ -551,6 +610,86 @@ test_dma_completed_status(void)
 	return TEST_SUCCESS;
 }
 
+static int
+test_dma_sg(void)
+{
+	struct rte_dma_sge src_sge[TEST_SG_MAX], dst_sge[TEST_SG_MAX];
+	struct rte_dma_info dev_info = { 0 };
+	uint16_t last_idx = -1;
+	bool has_error = true;
+	int n_sge, i, ret;
+	uint16_t cpl_ret;
+
+	ret = rte_dma_info_get(test_dev_id, &dev_info);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to obtain device info, %d", ret);
+
+	if ((dev_info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
+		return TEST_SKIPPED;
+
+	n_sge = RTE_MIN(dev_info.max_sges, TEST_SG_MAX);
+
+	ret = setup_vchan(1);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to setup one vchan, %d", ret);
+
+	ret = rte_dma_start(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to start, %d", ret);
+
+	for (i = 0; i < n_sge; i++) {
+		src_sge[i].addr = rte_malloc_virt2iova(src_sg[i]);
+		src_sge[i].length = TEST_MEMCPY_SIZE;
+		dst_sge[i].addr = rte_malloc_virt2iova(dst_sg[i]);
+		dst_sge[i].length = TEST_MEMCPY_SIZE;
+	}
+
+	sg_memory_setup(n_sge);
+
+	/* Check enqueue without submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge, 0);
+	RTE_TEST_ASSERT_EQUAL(ret, 0, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_completed(test_dev_id, 0, 1, &last_idx, &has_error);
+	RTE_TEST_ASSERT_EQUAL(cpl_ret, 0, "Failed to get completed");
+
+	/* Check DMA submit */
+	ret = rte_dma_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_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	sg_memory_setup(n_sge);
+
+	/* Check for enqueue with submit */
+	ret = rte_dma_copy_sg(test_dev_id, 0, src_sge, dst_sge, n_sge, n_sge,
+			      RTE_DMA_OP_FLAG_SUBMIT);
+	RTE_TEST_ASSERT_EQUAL(ret, 1, "Failed to enqueue copy, %d", ret);
+
+	rte_delay_us_sleep(TEST_WAIT_US_VAL);
+
+	cpl_ret = rte_dma_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");
+
+	ret = sg_memory_verify(n_sge);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to verify memory");
+
+	/* Stop dmadev to make sure dmadev to a known state */
+	ret = rte_dma_stop(test_dev_id);
+	RTE_TEST_ASSERT_SUCCESS(ret, "Failed to stop, %d", ret);
+
+	return TEST_SUCCESS;
+}
+
 static struct unit_test_suite dma_api_testsuite = {
 	.suite_name = "DMA API Test Suite",
 	.setup = testsuite_setup,
@@ -568,6 +707,7 @@ static struct unit_test_suite dma_api_testsuite = {
 		TEST_CASE(test_dma_dump),
 		TEST_CASE(test_dma_completed),
 		TEST_CASE(test_dma_completed_status),
+		TEST_CASE(test_dma_sg),
 		TEST_CASES_END()
 	}
 };
-- 
2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* RE: [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests
  2023-11-16 17:45             ` [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
                                 ` (2 preceding siblings ...)
  2023-11-16 17:45               ` [PATCH v8 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
@ 2023-12-07 10:10               ` Gowrishankar Muthukrishnan
  2024-02-05 10:34                 ` Gowrishankar Muthukrishnan
  2024-03-06 19:45               ` Thomas Monjalon
  4 siblings, 1 reply; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2023-12-07 10:10 UTC (permalink / raw)
  To: dev
  Cc: Anoob Joseph, Chengwen Feng, Vamsi Krishna Attunuru,
	Amit Prakash Shukla, Vidya Sagar Velumuri, Kevin Laatz,
	Bruce Richardson

Hi,
Could this patch series be reviewed ? As of now, patches are rebased without any conflicts.

Thanks,
Gowrishankar

> -----Original Message-----
> From: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
> Sent: Thursday, November 16, 2023 11:15 PM
> To: dev@dpdk.org
> Cc: Anoob Joseph <anoobj@marvell.com>; Chengwen Feng
> <fengchengwen@huawei.com>; Vamsi Krishna Attunuru
> <vattunuru@marvell.com>; Amit Prakash Shukla
> <amitprakashs@marvell.com>; Vidya Sagar Velumuri
> <vvelumuri@marvell.com>; Kevin Laatz <kevin.laatz@intel.com>; Bruce
> Richardson <bruce.richardson@intel.com>; Gowrishankar Muthukrishnan
> <gmuthukrishn@marvell.com>
> Subject: [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests
> 
> This patch series reworks DMA tests to follow unit test framework followed
> by new vchan reconfig and SG tests.
> 
> v8:
>  - Addressed compilation issue in Windows platform.
> 
> Gowrishankar Muthukrishnan (3):
>   test/dma: use unit test framework
>   test/dma: test multiple vchan
>   test/dma: add SG copy tests
> 
>  app/test/test_dmadev.c     | 374 +++++++++++++++++++++++++++++-------
> -
>  app/test/test_dmadev_api.c | 316 +++++++++++++++++++++++--------
>  2 files changed, 534 insertions(+), 156 deletions(-)
> 
> --
> 2.25.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* RE: [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests
  2023-12-07 10:10               ` [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
@ 2024-02-05 10:34                 ` Gowrishankar Muthukrishnan
  0 siblings, 0 replies; 39+ messages in thread
From: Gowrishankar Muthukrishnan @ 2024-02-05 10:34 UTC (permalink / raw)
  To: dev
  Cc: Anoob Joseph, Chengwen Feng, Vamsi Krishna Attunuru,
	Amit Prakash Shukla, Vidya Sagar Velumuri, Kevin Laatz,
	Bruce Richardson, Jerin Jacob, Thomas Monjalon

Hi,
Could this series be merged as the patches are acked.

Thanks,
Gowrishankar

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests
  2023-11-16 17:45             ` [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
                                 ` (3 preceding siblings ...)
  2023-12-07 10:10               ` [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
@ 2024-03-06 19:45               ` Thomas Monjalon
  4 siblings, 0 replies; 39+ messages in thread
From: Thomas Monjalon @ 2024-03-06 19:45 UTC (permalink / raw)
  To: Gowrishankar Muthukrishnan
  Cc: dev, anoobj, Chengwen Feng, Vamsi Attunuru, Amit Prakash Shukla,
	Vidya Sagar Velumuri, Kevin Laatz, Bruce Richardson

16/11/2023 18:45, Gowrishankar Muthukrishnan:
> Gowrishankar Muthukrishnan (3):
>   test/dma: use unit test framework
>   test/dma: test multiple vchan
>   test/dma: add SG copy tests

Applied, thanks.




^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2024-03-06 19:45 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-10 11:59 [PATCH] test/dma: add test skip status Gowrishankar Muthukrishnan
2023-08-10 12:36 ` [PATCH v2 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
2023-08-10 12:36   ` [PATCH v2 1/3] test/dma: add test skip status Gowrishankar Muthukrishnan
2023-08-10 12:36   ` [PATCH v2 2/3] test/dma: test vchan reconfiguration Gowrishankar Muthukrishnan
2023-08-10 12:36   ` [PATCH v2 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
2023-11-03 15:38   ` [PATCH v3 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
2023-11-03 15:38     ` [PATCH v3 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
2023-11-06  3:47       ` fengchengwen
2023-11-13  9:28         ` [EXT] " Gowrishankar Muthukrishnan
2023-11-03 15:38     ` [PATCH v3 2/3] test/dma: test vchan reconfiguration Gowrishankar Muthukrishnan
2023-11-06  4:06       ` fengchengwen
2023-11-03 15:38     ` [PATCH v3 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
2023-11-06  6:43       ` fengchengwen
2023-11-13  9:27         ` [EXT] " Gowrishankar Muthukrishnan
2023-11-13 12:53     ` [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
2023-11-13 12:53       ` [PATCH v4 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
2023-11-13 12:53       ` [PATCH v4 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
2023-11-13 12:53       ` [PATCH v4 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
2023-11-16  7:16       ` [PATCH v4 0/3] test/dma: add vchan reconfig and SG tests fengchengwen
2023-11-16 10:40       ` [PATCH v5 " Gowrishankar Muthukrishnan
2023-11-16 10:40         ` [PATCH v5 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
2023-11-16 10:40         ` [PATCH v5 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
2023-11-16 10:40         ` [PATCH v5 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
2023-11-16 10:59         ` [PATCH v6 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
2023-11-16 10:59           ` [PATCH v6 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
2023-11-16 10:59           ` [PATCH v6 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
2023-11-16 10:59           ` [PATCH v6 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
2023-11-16 13:27           ` [PATCH v7 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
2023-11-16 13:27             ` [PATCH v7 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
2023-11-16 13:27             ` [PATCH v7 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
2023-11-16 13:27             ` [PATCH v7 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
2023-11-16 17:45             ` [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
2023-11-16 17:45               ` [PATCH v8 1/3] test/dma: use unit test framework Gowrishankar Muthukrishnan
2023-11-16 17:45               ` [PATCH v8 2/3] test/dma: test multiple vchan Gowrishankar Muthukrishnan
2023-11-16 17:45               ` [PATCH v8 3/3] test/dma: add SG copy tests Gowrishankar Muthukrishnan
2023-12-07 10:10               ` [PATCH v8 0/3] test/dma: add vchan reconfig and SG tests Gowrishankar Muthukrishnan
2024-02-05 10:34                 ` Gowrishankar Muthukrishnan
2024-03-06 19:45               ` Thomas Monjalon
2023-10-08  1:51 ` [PATCH] test/dma: add test skip status fengchengwen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).