Agilex 5平台基于linux-socfpga的MSGDMA流数据读取功能异常求助
Agilex 5平台基于linux-socfpga的MSGDMA流数据读取功能异常求助
大家好,我现在在Agilex 5平台上基于linux-socfpga使用MSGDMA驱动,想要实现从流式设备到SDRAM的数据传输,但遇到了功能异常的问题,想请各位帮忙排查下。
背景与U-Boot验证情况
我的Qsys/Platform Designer设计是让流式设备输出6x6x6x这样的可预测数据模式到SDRAM,而且这个设计已经通过U-Boot验证是正常工作的,以下是U-Boot中的操作步骤及输出:
SOCFPGA_AGILEX5 # md 0x20010000 1 # Read SysID 20010000: acd5cafe .... SOCFPGA_AGILEX5 # md 0x00000000 1 # Read SDRAM 00000000: 9400000a .... SOCFPGA_AGILEX5 # mw 0x22000044 0x1 # Stop Descriptors SOCFPGA_AGILEX5 # mw 0x22000044 0x20 # Stop Descriptors SOCFPGA_AGILEX5 # mw 0x22000044 0x2 # Reset Dispatcher SOCFPGA_AGILEX5 # mw 0x22000064 0x00000000 # Choose destination address SOCFPGA_AGILEX5 # mw 0x22000068 0x8 # Write length in bytes SOCFPGA_AGILEX5 # md 0x22000040 1 # Check status 22000040: 00000002 .... SOCFPGA_AGILEX5 # mw 0x2200006c 0x00004000 SOCFPGA_AGILEX5 # sleep 1 SOCFPGA_AGILEX5 # mw 0x2200006c 0x80004000 # Execute read SOCFPGA_AGILEX5 # md 0x22000040 1 # Check status 22000040: 00000002 .... SOCFPGA_AGILEX5 # md 0x00000000 1 00000000: 00000000 .... SOCFPGA_AGILEX5 # mw 0x22000044 0x2 # Reset Dispatcher SOCFPGA_AGILEX5 # mw 0x2200006c 0x80004000 SOCFPGA_AGILEX5 # md 0x00000000 1 00000000: 64646464 .... SOCFPGA_AGILEX5 # mw 0x22000044 0x2 SOCFPGA_AGILEX5 # mw 0x2200006c 0x80004000 SOCFPGA_AGILEX5 # md 0x00000000 1 00000000: 65656565 .... SOCFPGA_AGILEX5 # mw 0x22000044 0x2 SOCFPGA_AGILEX5 # mw 0x2200006c 0x80004000 SOCFPGA_AGILEX5 # md 0x00000000 1 00000000: 67676767 .... SOCFPGA_AGILEX5 # mw 0x22000044 0x2 SOCFPGA_AGILEX5 # mw 0x2200006c 0x80004000 SOCFPGA_AGILEX5 # md 0x00000000 1 00000000: 67676767 ....
设备树配置
根据驱动仓库的README.md,我修改了设备树,加入了以下时钟和MSGDMA节点:
clk_0: clk_0 { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <100000000>; /* 100.00 MHz */ clock-output-names = "clk_0"; }; msgdma_streaming_read_0: msgdma@22000040 { compatible = "altr,altera-msgdma-st-1.0"; reg = <0x0 0x22000040 0x0 0x00000020>, <0x0 0x22000060 0x0 0x00000010>; reg-names = "csr", "descriptor_slave"; string-property = "msgdma_read"; interrupts = <0 19 4>; interrupt-parent = <&intc>; clocks = <&clk_0>; };
其中中断号是根据Qsys设计中的连接片段确定的:
... <altera:connection altera:kind="interrupt" altera:version="24.3" altera:start="subsys_hps.f2h_irq0_in" altera:end="msgdma_0.csr_irq"> <altera:connection_parameter altera:parameter_name="irqNumber" altera:parameter_value="2"> </altera:connection_parameter> </altera:connection> ...
内核模块加载情况
内核模块编译并成功加载到SoC上,相关操作及输出如下:
root@localhost:~# insmod altera_msgdma_st.ko root@localhost:~# lsmod Module Size Used by altera_msgdma_st 20480 0 root@localhost:~# ls /dev | grep msgdma altera_msgdma_rd0 root@localhost:~# dmesg | tail -1 [ 689.957318] Registered Altera MSGDMA device 0 (in READ mode)
用户态程序及问题现象
我编写了一个C程序来尝试读取DMA数据,代码如下:
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <string.h> #include <errno.h> // 引用驱动头文件 #include "../dma_driver/altera_msgdma_ioctl.h" #define READ_COUNT 3 // 读取次数 #define DELAY_US 100000 // 读取间隔(100ms) #define BUFFER_SIZE 8 // 读取缓冲区大小 #define MIN_BLOCK_SIZE 8 // 最小读取块大小 int main() { const char *device = "/dev/altera_msgdma_rd0"; int fd = open(device, O_RDONLY); if (fd < 0) { perror("Failed to open device"); return 1; } if (ioctl(fd, IO_ALTERA_MSGDMA_STOP_RESET) < 0) { perror("Failed to send STOP_RESET ioctl"); close(fd); return 1; } printf("STOP_RESET ioctl sent successfully\n"); unsigned long buffer_size = BUFFER_SIZE; if (ioctl(fd, IO_ALTERA_MSGDMA_SET_BUFFER_SIZE, &buffer_size) < 0) { perror("Failed to set buffer size"); close(fd); return 1; } unsigned long block_size = MIN_BLOCK_SIZE; if (ioctl(fd, IO_ALTERA_MSGDMA_SET_MIN_BLOCK_SIZE, &block_size) < 0) { perror("Failed to set min block size"); close(fd); return 1; } unsigned char buffer[BUFFER_SIZE]; for (int read_num = 0; read_num < READ_COUNT; read_num++) { ssize_t bytes_read = read(fd, buffer, sizeof(buffer)); if (bytes_read < 0) { perror("Failed to read from device"); close(fd); return 1; } printf("Read #%d: %zd bytes:\n", read_num + 1, bytes_read); for (int i = 0; i < bytes_read; i++) { printf("0x%02x ", buffer[i]); } printf("\n"); usleep(DELAY_US); memset(buffer, 0, sizeof(buffer)); } close(fd); return 0; }
但程序运行后只输出了以下内容,没有正常读取到预期的流式数据:
root@localhost:~# ./read_dma_st STOP_RESET ioctl sent successfully Read #1:
现在的困惑是,U-Boot下直接操作寄存器能正常获取数据,但通过Linux驱动和用户态程序却无法正常工作,想请教各位可能的原因是什么,有没有具体的排查方向或解决办法?
内容来源于stack exchange
相关产品推荐
相关产品推荐

