在Linux下获取缓冲区的物理地址

时间:2013-06-12 20:44:28

标签: linux-kernel embedded embedded-linux mmap microblaze

我在Xilinx的Microblaze上使用完整的MMU运行Linux内核3.3。我正在做的任务要求我知道以下内容:我需要创建一个文本文件(缓冲区)并找到该缓冲区的物理地址,我不希望内核将此文件写入不连续的内存区域。 / p>

我需要这个的原因是因为我有一个DMA引擎从预设的物理内存地址流式传输数据,所以我需要强制Linux在那个确切的内存位置创建缓冲区文件,这样当我将数据写入这个文件时它立即由DMA引擎传输到另一个硬件核心

更多详情:

我的系统有一个512 MB DDR3 RAM通过“Xilinx”多端口内存控制器(MPMC)连接到系统。该内存控制器的基地址为0x90000000,系统中的所有单元通过该控制器访问内存,包括MicroBlaze ,我所使用的DMA单元使用一个名为Native Personality Interface(NPI)的特殊接口,以非常低的级别与内存通信,从而产生非常高的速度性能。

这个NPI DMA单元最初设计用于一个名为“xilkernel”的非常基本的嵌入式内核,它不支持虚拟内存,MMU也不是MicroBlaze的一部分,所以程序员可以看到OS代码驻留和选择的位置一个物理内存地址,如0x91800000作为DMA将从中流出的源地址,然后程序员可以将文件放在该确切的地址中并运行系统

当我们需要迁移项目以使用Linux而不是xilkernel时我们遇到了这个问题,我在外部存储设备上有文件,我可以从Linux访问作为块设备,我需要将每个文件移动到主存储器( DDR3 RAM)并使DMA流成为文件。 目前来自固定地址的DMA流,但我可以根据需要将其设为通用。

2 个答案:

答案 0 :(得分:5)

要处理与DMA控制器接口的缓冲区,有特定的功能。这些函数不仅可以处理地址转换,还可以处理与内存的高速缓存一致性,例如缓存刷新(在发送之前将数据写入内存)和缓存无效(在接收之前使缓存无效)。

(1)要分配缓冲区,请同时获取虚拟地址和物理地址:

void *dma_alloc_coherent(struct device *dev, size_t size,
                         dma_addr_t *dma_handle, gfp_t flag)

函数的返回值是分配的缓冲区的虚拟地址,而dma_handle指针保存分配的缓冲区的物理地址。

(2)传递分配给设备的一个缓冲区:

dma_addr_t dma_map_single(struct device *dev, void *ptr,
                          size_t size,
                          enum dma_data_direction dir)

返回值是缓冲区的物理地址,参数dir是DMA_TO_DEVICE,ptr是缓冲区的虚拟地址;

(3)从设备接收一个缓冲区:

void dma_unmap_single(struct device *dev, dma_addr_t addr,
                            size_t size,
                            enum dma_data_direction dir)

参数dir是DMA_FROM_DEVICE。

注意: 要使用与dma相关的三个函数,应该将设备注册到一个具有dma_map_ops的特定总线,否则不能使用这三个函数。

答案 1 :(得分:5)

  

我需要强制Linux在那个确切的内存位置创建缓冲区文件

这是不可能的。 (实际上你已经创建了一个XY问题。)

由于您的硬件“从预设的物理内存地址中流式传输数据”,因此您必须确保Linux内核不将此内存区域用作其内存池的一部分。您需要在内核启动时通知内核不使用此内存区域。一旦它成为内核控制的内存空间的一部分,您将无法“回收”或在此特定物理内存区域中分配缓冲区。

排除内存区域的最通用方法是在内核命令行上使用memmap=参数。

memmap=nn[KMG]$ss[KMG]
        [KNL,ACPI] Mark specific memory as reserved.
        Region of memory to be used, from ss to ss+nn.
        Example: Exclude memory from 0x18690000-0x1869ffff
                 memmap=64K$0x18690000
                 or
                 memmap=0x10000$0x18690000

某些体系结构(例如ARM及其ATAG)具有其他不太可见且更安全的方法来保留物理内存区域。

然后,您必须向设备驱动程序提供此内存区域的地址和大小。这可以通过解析命令行来获得,或者(使用拇指向下)使用#define进行硬编码。

驱动程序应通过调用request_mem_region()来声明其对内存区域的使用 驱动程序可以通过调用ioreamp()将此内存区域映射到虚拟地址空间。

由于已经提供了驱动程序或者已经知道了物理地址,所以已经完成了。由于分配了物理内存,因此内存是连续的。您必须配置MMU以禁用此内存区域上的缓存。然后内存区域将是“DMAable”。