7

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

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

更多细节:

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

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

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

4

2 回答 2

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

一些架构,例如带有 ATAG 的 ARM,还有其他不太明显但更安全的方法来保留物理内存区域。

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

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

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

于 2013-06-14T02:01:47.793 回答
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 的特定总线上,否则这三个功能不能使用。

于 2013-06-13T02:01:05.360 回答