This commit adds test cases for GSDMA.
Imitate the behavior of the driver, set LLT and sdma registers.
After the data transmission is completed, check the destination address data.

Run this qtest:
    $ mkdir build && cd build && ../configure --target-list="riscv64-softmmu"
    $ QTEST_QEMU_BINARY=./qemu-system-riscv64   tests/qtest/k230-gsdma-test

Signed-off-by: Tao Ding <[email protected]>
---
 tests/qtest/k230-gsdma-test.c | 201 ++++++++++++++++++++++++++++++++++
 tests/qtest/meson.build       |   2 +-
 2 files changed, 202 insertions(+), 1 deletion(-)
 create mode 100644 tests/qtest/k230-gsdma-test.c

diff --git a/tests/qtest/k230-gsdma-test.c b/tests/qtest/k230-gsdma-test.c
new file mode 100644
index 0000000000..44d4248739
--- /dev/null
+++ b/tests/qtest/k230-gsdma-test.c
@@ -0,0 +1,201 @@
+/*
+ * QTest testcase for K230 GSDMA
+ *
+ * Copyright (c) 2026 Tao Ding <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "exec/hwaddr.h"
+#include "hw/dma/k230_gsdma.h"
+#include "libqtest.h"
+
+#define K230_GSDMA_BASE              0x80800000
+#define TEST_LLT_ADDR0               0x10000
+#define TEST_LLT_ADDR1               0x10040
+#define TEST_LLT_ADDR2               0x10080
+
+#define TEST_SRC_ADDR0               0x20000
+#define TEST_SRC_ADDR1               0x22000
+#define TEST_SRC_ADDR2               0x23000
+#define TEST_DST_ADDR0               0x30000
+#define TEST_DST_ADDR1               0x32000
+#define TEST_DST_ADDR2               0x33000
+
+static inline uint64_t gsdma_reg(hwaddr off)
+{
+    return K230_GSDMA_BASE + off;
+}
+
+static inline uint64_t gsdma_ch_reg(unsigned int ch, hwaddr off)
+{
+    return K230_GSDMA_BASE + K230_GSDMA_CH_BASE +
+           ch * K230_GSDMA_CH_STRIDE + off;
+}
+
+static void write_sdma_llt_node_full(QTestState *qts, hwaddr addr,
+                                     uint32_t cfg, hwaddr src,
+                                     uint32_t size, hwaddr dst,
+                                     hwaddr next)
+{
+    qtest_writel(qts, addr + offsetof(K230GSDMALLT, cfg), cfg);
+    qtest_writel(qts, addr + offsetof(K230GSDMALLT, src_addr), src);
+    qtest_writel(qts, addr + offsetof(K230GSDMALLT, line_size), size);
+    qtest_writel(qts, addr + offsetof(K230GSDMALLT, line_cfg), 0x1);
+    qtest_writel(qts, addr + offsetof(K230GSDMALLT, dst_addr), dst);
+    qtest_writel(qts, addr + offsetof(K230GSDMALLT, next_llt_addr), next);
+}
+
+static void write_sdma_llt_node(QTestState *qts, hwaddr addr, uint32_t cfg,
+                                uint32_t next)
+{
+    write_sdma_llt_node_full(qts, addr, cfg, 0x11110000, 0x200,
+                             0x22220000, next);
+}
+
+static void fill_pattern(uint8_t *buf, size_t size, uint8_t seed)
+{
+    for (size_t i = 0; i < size; i++) {
+        buf[i] = seed + i * 37;
+    }
+}
+
+static void test_global_registers(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    g_assert_cmphex(qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_CFG)), ==,
+                    K230_GSDMA_DMA_CFG_RESET);
+
+    qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_CH_EN), 0xff);
+    g_assert_cmphex(qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_CH_EN)), ==,
+                    K230_GSDMA_DMA_CH_EN_MASK);
+
+    qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_INT_MASK), 0x12345);
+    g_assert_cmphex(qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_INT_MASK)), ==,
+                    0x12345);
+
+    qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_CFG), 0xa5a5a5a5);
+    g_assert_cmphex(qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_CFG)), ==,
+                    0xa5a5a5a5);
+
+    qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_WEIGHT), 0xff55aa55);
+    g_assert_cmphex(qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_WEIGHT)), ==,
+                    0x55aa55);
+
+    qtest_quit(qts);
+}
+
+static void test_sdma_pause_resume(void)
+{
+    uint32_t int_stat;
+    QTestState *qts = qtest_init("-machine k230");
+
+    write_sdma_llt_node(qts, TEST_LLT_ADDR0, K230_GSDMA_LLT_PAUSE,
+                        TEST_LLT_ADDR1);
+    write_sdma_llt_node(qts, TEST_LLT_ADDR1, K230_GSDMA_LLT_NODE_INTR, 0);
+
+    qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_CH_EN), BIT(0));
+    qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_LLT_SADDR), 
TEST_LLT_ADDR0);
+    qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_CTL), 
K230_GSDMA_CTL_START);
+
+    g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, K230_GSDMA_CH_STATUS)), 
==,
+                    K230_GSDMA_SDMA_STATUS_PAUSE);
+    g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, 
K230_GSDMA_CH_CURRENT_LLT)),
+                    ==, TEST_LLT_ADDR0);
+
+    int_stat = qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_INT_STAT));
+    g_assert_cmphex(int_stat & K230_GSDMA_SDMA_PAUSE_INT(0), ==,
+                    K230_GSDMA_SDMA_PAUSE_INT(0));
+    g_assert_cmphex(int_stat & K230_GSDMA_SDMA_DONE_INT(0), ==, 0);
+
+    qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_INT_STAT), int_stat);
+    qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_CTL), 
K230_GSDMA_CTL_RESUME);
+
+    g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, K230_GSDMA_CH_STATUS)), 
==,
+                    0);
+    g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, 
K230_GSDMA_CH_CURRENT_LLT)),
+                    ==, TEST_LLT_ADDR1);
+
+    int_stat = qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_INT_STAT));
+    g_assert_cmphex(int_stat & K230_GSDMA_SDMA_DONE_INT(0), ==,
+                    K230_GSDMA_SDMA_DONE_INT(0));
+    g_assert_cmphex(int_stat & K230_GSDMA_SDMA_ITEM_INT(0), ==,
+                    K230_GSDMA_SDMA_ITEM_INT(0));
+
+    qtest_quit(qts);
+}
+
+static void test_sdma_three_llt_copy(void)
+{
+    uint8_t src0[0x1000];
+    uint8_t src1[1];
+    uint8_t src2[511];
+    uint8_t dst0[sizeof(src0)];
+    uint8_t dst1[sizeof(src1)];
+    uint8_t dst2[sizeof(src2)];
+    uint32_t int_stat;
+    QTestState *qts = qtest_init("-machine k230");
+
+    fill_pattern(src0, sizeof(src0), 0x10);
+    fill_pattern(src1, sizeof(src1), 0x31);
+    fill_pattern(src2, sizeof(src2), 0x52);
+    memset(dst0, 0xa5, sizeof(dst0));
+    memset(dst1, 0xa5, sizeof(dst1));
+    memset(dst2, 0xa5, sizeof(dst2));
+
+    qtest_memwrite(qts, TEST_SRC_ADDR0, src0, sizeof(src0));
+    qtest_memwrite(qts, TEST_SRC_ADDR1, src1, sizeof(src1));
+    qtest_memwrite(qts, TEST_SRC_ADDR2, src2, sizeof(src2));
+    qtest_memwrite(qts, TEST_DST_ADDR0, dst0, sizeof(dst0));
+    qtest_memwrite(qts, TEST_DST_ADDR1, dst1, sizeof(dst1));
+    qtest_memwrite(qts, TEST_DST_ADDR2, dst2, sizeof(dst2));
+
+    write_sdma_llt_node_full(qts, TEST_LLT_ADDR0, 0, TEST_SRC_ADDR0,
+                             sizeof(src0), TEST_DST_ADDR0, TEST_LLT_ADDR1);
+    write_sdma_llt_node_full(qts, TEST_LLT_ADDR1, 0, TEST_SRC_ADDR1,
+                             sizeof(src1), TEST_DST_ADDR1, TEST_LLT_ADDR2);
+    write_sdma_llt_node_full(qts, TEST_LLT_ADDR2, 0, TEST_SRC_ADDR2,
+                             sizeof(src2), TEST_DST_ADDR2, 0);
+
+    qtest_writel(qts, gsdma_reg(K230_GSDMA_DMA_CH_EN), BIT(0));
+    qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_LLT_SADDR), 
TEST_LLT_ADDR0);
+    qtest_writel(qts, gsdma_ch_reg(0, K230_GSDMA_CH_CTL), 
K230_GSDMA_CTL_START);
+
+    g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, K230_GSDMA_CH_STATUS)), 
==,
+                    0);
+    g_assert_cmphex(qtest_readl(qts, gsdma_ch_reg(0, 
K230_GSDMA_CH_CURRENT_LLT)),
+                    ==, TEST_LLT_ADDR2);
+
+    int_stat = qtest_readl(qts, gsdma_reg(K230_GSDMA_DMA_INT_STAT));
+    g_assert_cmphex(int_stat & K230_GSDMA_SDMA_DONE_INT(0), ==,
+                    K230_GSDMA_SDMA_DONE_INT(0));
+    g_assert_cmphex(int_stat & K230_GSDMA_SDMA_PAUSE_INT(0), ==, 0);
+
+    memset(dst0, 0, sizeof(dst0));
+    memset(dst1, 0, sizeof(dst1));
+    memset(dst2, 0, sizeof(dst2));
+    qtest_memread(qts, TEST_DST_ADDR0, dst0, sizeof(dst0));
+    qtest_memread(qts, TEST_DST_ADDR1, dst1, sizeof(dst1));
+    qtest_memread(qts, TEST_DST_ADDR2, dst2, sizeof(dst2));
+
+    g_assert_cmpmem(dst0, sizeof(dst0), src0, sizeof(src0));
+    g_assert_cmpmem(dst1, sizeof(dst1), src1, sizeof(src1));
+    g_assert_cmpmem(dst2, sizeof(dst2), src2, sizeof(src2));
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/k230-gsdma/global-registers", test_global_registers);
+    qtest_add_func("/k230-gsdma/sdma-pause-resume", test_sdma_pause_resume);
+    qtest_add_func("/k230-gsdma/sdma-three-llt-copy",
+                   test_sdma_three_llt_copy);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 56ff860e21..1b13a777c9 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -297,7 +297,7 @@ qtests_riscv64 = ['riscv-csr-test'] + \
   (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and
    config_all_devices.has_key('CONFIG_RISCV_IOMMU') ?
    ['iommu-riscv-test'] : []) + \
-  (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : [])
+  (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test', 
'k230-gsdma-test'] : [])
 
 qtests_hexagon = ['boot-serial-test']
 
-- 
2.43.0


Reply via email to