11

我正在使用 Xilinx Zynq 平台,其内存区域在可编程硬件和 ARM 处理器之间共享。

我在内核命令行上使用 memmap 保留了这个内存,然后通过我的驱动程序中的 mmap/io_remap_pfn_range 调用将它暴露给用户空间。

我遇到的问题是写入需要一些时间才能显示在 DRAM 中,我认为它卡在 dcache 中。定义了一堆 flush_cache_* 调用,但没有一个被导出,这对我来说是一个线索,我在吠叫错误的树......

作为一个试验,我在本地导出了 flush_cache_mm 并只是为了看看会发生什么而没有喜悦。

简而言之,我如何确定对这个 mmap'd 区域的任何写入都已提交到 DRAM?

谢谢。

4

3 回答 3

10

ARM处理器通常同时具有I/D 缓存写缓冲区写入缓冲区的想法是将顺序写入组合在一起(非常适合同步 DRAM),并且不会延迟 CPU 等待写入完成。

一般而言,您可以刷新d 缓存写入缓冲区。以下是一些适用于许多架构和内存配置的内联ARM汇编程序。

 static inline void dcache_clean(void)
 {
     const int zero = 0;
     /* clean entire D cache -> push to external memory. */
     __asm volatile ("1: mrc p15, 0, r15, c7, c10, 3\n"
                     " bne 1b\n" ::: "cc");
     /* drain the write buffer */
    __asm volatile ("mcr 15, 0, %0, c7, c10, 4"::"r" (zero));
 }

如果您有L2 缓存,您可能需要更多。

要在 Linux 环境中回答,有不同的CPU变体和不同的例程,具体取决于内存/MMU 配置甚至 CPU 勘误表。参见例如,

这些例程要么直接调用,要么在带有函数指针的cpu info结构中查找,这些函数指针指向检测到的 CPU 和配置的适当例程;取决于内核是针对单个 CPU还是多用途(例如Ubuntu 发行版)。

要专门针对您的情况回答问题,我们需要了解L2 缓存写入缓冲内存、CPU 架构细节;可能包括勘误表的硅修订。另一种策略是通过使用将内存标记为不可缓存不可缓冲的dma_alloc_XXX() 例程来完全避免这种情况,以便 CPU 写入立即被推送到外部。根据您的内存访问模式,任何一种解决方案都是有效的。如果内存只需要在某个检查点同步(视频等的vsync /*hsync* 等),您可能希望缓存。

于 2013-09-19T14:22:50.330 回答
4

我在zynq上遇到了完全相同的问题。最后让 L2 被刷新/失效:

#include <asm/outercache.h>
outer_cache.flush_range(start,size);
outer_cache.inv_range(start,size);

start 是内核虚拟空间指针。您还需要将 L1 刷新到 L2:

__cpuc_flush_dcache_area(start,size);

我不确定在阅读之前是否需要使 L1 无效,而且我还没有找到执行此操作的函数。我认为它需要,到目前为止我只是幸运的......

似乎在我发现的“网络”上的任何建议都假定该设备位于 L2 缓存一致性的“内部”,因此如果使用 AXI-HP 端口,它们将不起作用。使用 AXI-ACP 端口时,不需要 L2 冲洗。(对于那些不熟悉 zync 的人:HP 端口直接访问 DRAM 控制器,绕过在 ARM 端实现的任何缓存/MMU)

于 2014-09-12T15:06:14.950 回答
3

我不熟悉 Zynq,但您基本上有两个真正有效的选择:

  • 要么在同一个相干域中包含 FPGA 上的其他逻辑(例如,如果 Zynq 有 ACP 端口)
  • 或将您映射的内存标记为设备内存(如果您不关心收集、重新排序和早期写入确认,则将其标记为其他不可缓存的内存)并在应该看到的任何写入之后使用 DSB。

如果内存被标记为可缓存并且您的其他观察者不在同一个一致性域中,那么您就是在自找麻烦 - 当您使用 DCCISW 或类似操作清理 D-cache 并且您有 L2 缓存时 - 这就是一切最终进入。

于 2013-09-25T07:07:47.290 回答