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

如何在Petalinux/Yocto中创建DMA访问的预留内存区域?

解决MicroBlaze平台DMA预留内存不生效及替代方案

先排查当前设备树配置的问题

  1. 内核驱动编译检查:你使用的xlnx,reserved-memory驱动需要编译进内核(或作为模块加载),请确认内核配置中开启了CONFIG_XILINX_RESERVED_MEM和CONFIG_RESERVED_MEM。如果驱动未加载,设备树中的配置不会生效,自然不会在/proc/iomem或dmesg中看到对应设备。
  2. MicroBlaze内存属性适配:MicroBlaze架构下,no-map属性会让内核不创建虚拟地址映射,但如果你的驱动需要访问这段内存,可能需要手动在驱动中做ioremap操作。同时要确保reg中的地址范围是MicroBlaze可访问的物理地址,且未被其他硬件或内核占用。

替代的DMA预留内存方法

方法1:通过内核启动参数直接预留内存

使用memmap参数强制内核保留指定物理内存区域,无需依赖设备树驱动:

  • 在U-Boot的启动参数中添加:memmap=0x10000000$0xa0000000
    • 解释:0x10000000是要预留的内存大小,0xa0000000是起始物理地址
  • 启动后可以通过cat /proc/iomem看到这段内存被标记为reserved
  • 驱动中访问时,使用request_mem_region申请区域权限,再通过ioremap_nocache映射为虚拟地址(MicroBlaze必须用非缓存映射避免DMA缓存一致性问题):
#define RESERVED_BASE 0xa0000000
#define RESERVED_SIZE 0x10000000

void __init my_dma_init(void) {
    if (!request_mem_region(RESERVED_BASE, RESERVED_SIZE, "dma_buffer")) {
        pr_err("Failed to request reserved memory region\n");
        return;
    }
    void *virt_addr = ioremap_nocache(RESERVED_BASE, RESERVED_SIZE);
    if (!virt_addr) {
        pr_err("Failed to ioremap reserved memory\n");
        release_mem_region(RESERVED_BASE, RESERVED_SIZE);
        return;
    }
    // 后续使用virt_addr进行DMA操作
}

方法2:修复CMA访问崩溃问题

你之前使用CMA崩溃,大概率是MicroBlaze的缓存一致性未处理正确,调整后可正常使用:

  1. 设备树中定义专属CMA区域:
reserved-memory {
    #address-cells = <2>;
    #size-cells = <2>;
    ranges;

    cma_dma: cma@0xa0000000 {
        compatible = "shared-dma-pool";
        reusable;
        reg = <0x0 0xa0000000 0x0 0x10000000>;
        linux,cma-default;
    };
};
  1. 驱动中使用正确的DMA分配接口:
    不要直接访问CMA物理地址,而是用dma_alloc_coherent申请缓存一致的内存,或者用dma_alloc_from_contiguous从指定CMA区域申请:
struct device *dev = &my_dev->dev;
dma_addr_t dma_addr;
void *virt_addr = dma_alloc_coherent(dev, 0x1000, &dma_addr, GFP_KERNEL);
if (!virt_addr) {
    pr_err("DMA alloc failed\n");
    return -ENOMEM;
}
// 使用virt_addr(虚拟地址)和dma_addr(DMA可访问的物理地址)进行操作
  1. 缓存操作兜底:如果必须直接访问物理地址,在DMA传输前后执行缓存刷新/失效:
// 写入内存后,刷新缓存让DMA可见
flush_dcache_range((unsigned long)virt_addr, (unsigned long)virt_addr + size);
// DMA读取完成后,失效缓存让CPU可见
invalidate_dcache_range((unsigned long)virt_addr, (unsigned long)virt_addr + size);

方法3:驱动静态申请预留内存

如果不需要设备树标准化的预留,可直接在驱动中配合内核启动参数的memmap使用:

  1. 用memmap参数保留内存(同方法1)
  2. 驱动中通过request_mem_region申请权限,再ioremap映射,确保操作前这段内存未被内核占用。

内容的提问来源于stack exchange,提问作者Makuta Arguilleres

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 07:27:18