You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 07:38:01