DMA 测试指南

Andy Shevchenko <andriy.shevchenko@linux.intel.com>

这份小文档介绍了如何使用 dmatest 模块测试 DMA 驱动程序。

dmatest 模块使用各种长度以及源缓冲区和目标缓冲区中的各种偏移量来测试 DMA memcpy、memset、XOR 和 RAID6 P+Q 操作。它将使用可重复的模式初始化两个缓冲区,并验证 DMA 引擎是否复制了请求的区域,而没有复制其他内容。它还将验证字节是否没有被交换,以及源缓冲区是否没有被修改。

dmatest 模块可以配置为测试特定的通道。它也可以同时测试多个通道,并且可以启动多个线程来竞争同一个通道。

注意

测试套件仅适用于具有以下至少一项功能的通道:DMA_MEMCPY(内存到内存)、DMA_MEMSET(常量到内存或内存到内存,在模拟时)、DMA_XOR、DMA_PQ。

注意

如有任何相关问题,请使用官方邮件列表 dmaengine@vger.kernel.org

第 1 部分 - 如何构建测试模块

menuconfig 包含一个选项,可以通过以下路径找到

Device Drivers -> DMA Engine support -> DMA Test client

在配置文件中,该选项称为 CONFIG_DMATEST。dmatest 可以作为模块构建,也可以在内核内部构建。让我们考虑这些情况。

第 2 部分 - 当 dmatest 作为模块构建时

使用示例

% modprobe dmatest timeout=2000 iterations=1 channel=dma0chan0 run=1

...或

% modprobe dmatest
% echo 2000 > /sys/module/dmatest/parameters/timeout
% echo 1 > /sys/module/dmatest/parameters/iterations
% echo dma0chan0 > /sys/module/dmatest/parameters/channel
% echo 1 > /sys/module/dmatest/parameters/run

...或在内核命令行上

dmatest.timeout=2000 dmatest.iterations=1 dmatest.channel=dma0chan0 dmatest.run=1

多通道测试使用示例(5.0 内核中的新增功能)

% modprobe dmatest
% echo 2000 > /sys/module/dmatest/parameters/timeout
% echo 1 > /sys/module/dmatest/parameters/iterations
% echo dma0chan0 > /sys/module/dmatest/parameters/channel
% echo dma0chan1 > /sys/module/dmatest/parameters/channel
% echo dma0chan2 > /sys/module/dmatest/parameters/channel
% echo 1 > /sys/module/dmatest/parameters/run

注意

对于 5.0 内核中开始的所有测试,无论是单通道还是多通道,通道参数都必须在所有其他参数之后设置。正是在那时,现有参数值被获取以供线程使用。所有其他参数都是共享的。因此,如果对任何其他参数进行了更改,并且指定了额外的通道,则所有线程使用的(共享)参数将使用新值。指定通道后,每个线程都设置为挂起。当 run 参数设置为 1 时,所有线程开始执行。

提示

可以通过运行以下命令找到可用通道的列表

% ls -1 /sys/class/dma/

启动后,会发出类似“dmatest: Added 1 threads using dma0chan0”的消息。会为该特定通道创建一个线程,并且现在处于挂起状态,一旦 run 为 1,挂起的线程就会启动。

请注意,运行新的测试不会停止任何正在进行的测试。

以下命令返回测试的状态。

% cat /sys/module/dmatest/parameters/run

要等待测试完成,用户空间可以轮询 'run' 直到它为 false,或者使用 wait 参数。在加载模块时指定 'wait=1' 会导致模块初始化暂停,直到测试运行完成,而读取 /sys/module/dmatest/parameters/wait 会等待任何正在运行的测试完成,然后再返回。例如,以下脚本等待 42 个测试完成后退出。请注意,如果 'iterations' 设置为 'infinite',则禁用等待。

示例

% modprobe dmatest run=1 iterations=42 wait=1
% modprobe -r dmatest

...或

% modprobe dmatest run=1 iterations=42
% cat /sys/module/dmatest/parameters/wait
% modprobe -r dmatest

第 3 部分 - 当内置于内核中时

提供给内核命令行的模块参数将用于第一次执行的测试。在用户获得控制权后,可以使用相同或不同的参数重新运行测试。有关详细信息,请参阅上面的部分第 2 部分 - 当 dmatest 作为模块构建时

在这两种情况下,模块参数都用作测试用例的实际值。您始终可以通过运行以下命令在运行时检查它们

% grep -H . /sys/module/dmatest/parameters/*

第 4 部分 - 收集测试结果

测试结果以以下格式打印到内核日志缓冲区

"dmatest: result <channel>: <test id>: '<error msg>' with src_off=<val> dst_off=<val> len=<val> (<err code>)"

输出示例

% dmesg | tail -n 1
dmatest: result dma0chan0-copy0: #1: No errors with src_off=0x7bf dst_off=0x8ad len=0x3fea (0)

消息格式在不同类型的错误中是统一的。括号中的数字表示附加信息,例如错误代码、错误计数器或状态。测试线程还会在完成时发出摘要行,列出执行的测试数量、失败的数量和结果代码。

示例

% dmesg | tail -n 1
dmatest: dma0chan0-copy0: summary 1 test, 0 failures 1000 iops 100000 KB/s (0)

还会发出数据不匹配错误的详细信息,但不遵循上述格式。

第 5 部分 - 处理通道分配

分配通道

通道无需在开始测试运行之前配置。尝试在不配置通道的情况下运行测试将导致测试任何可用的通道。

示例

% echo 1 > /sys/module/dmatest/parameters/run
dmatest: No channels configured, continue with any

通道使用 “channel” 参数注册。可以按名称请求通道,一旦请求,通道将被注册,并且挂起的线程将被添加到测试列表中。

示例

% echo dma0chan2 > /sys/module/dmatest/parameters/channel
dmatest: Added 1 threads using dma0chan2

可以通过重复上面的示例来添加更多通道。读取 channel 参数将返回上次成功添加的通道的名称。

示例

% echo dma0chan1 > /sys/module/dmatest/parameters/channel
dmatest: Added 1 threads using dma0chan1
% echo dma0chan2 > /sys/module/dmatest/parameters/channel
dmatest: Added 1 threads using dma0chan2
% cat /sys/module/dmatest/parameters/channel
dma0chan2

请求通道的另一种方法是使用空字符串请求通道,这样做会请求测试所有可用的通道

示例

% echo "" > /sys/module/dmatest/parameters/channel
dmatest: Added 1 threads using dma0chan0
dmatest: Added 1 threads using dma0chan3
dmatest: Added 1 threads using dma0chan4
dmatest: Added 1 threads using dma0chan5
dmatest: Added 1 threads using dma0chan6
dmatest: Added 1 threads using dma0chan7
dmatest: Added 1 threads using dma0chan8

在测试配置期间的任何时候,读取 “test_list” 参数将打印当前挂起的测试列表。

示例

% cat /sys/module/dmatest/parameters/test_list
dmatest: 1 threads using dma0chan0
dmatest: 1 threads using dma0chan3
dmatest: 1 threads using dma0chan4
dmatest: 1 threads using dma0chan5
dmatest: 1 threads using dma0chan6
dmatest: 1 threads using dma0chan7
dmatest: 1 threads using dma0chan8

注意:必须为每个测试运行配置通道,因为通道配置不会延续到下一个测试运行。

释放通道

可以通过将 run 设置为 0 来释放通道。

示例

% echo dma0chan1 > /sys/module/dmatest/parameters/channel
dmatest: Added 1 threads using dma0chan1
% cat /sys/class/dma/dma0chan1/in_use
1
% echo 0 > /sys/module/dmatest/parameters/run
% cat /sys/class/dma/dma0chan1/in_use
0

在成功完成测试运行后请求新通道时,会自动释放先前测试运行分配的通道。