将缓存刷新到DRAM

时间:2013-09-19 14:01:44

标签: linux-kernel arm xilinx zynq

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

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

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

作为试验,我在本地导出了flush_cache_mm,只是为了看看会发生什么,没有快乐。

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

感谢。

3 个答案:

答案 0 :(得分:8)

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

要成为通用,您可以刷新 d cache 写缓冲区。以下是一些内联 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() routines将内存标记为 un-cacheable un-bufferable 来完全避免这种情况,以便立即从外部推送CPU写入。根据您的内存访问模式,任一解决方案都有效。如果内存只需要在某个检查点进行同步 vsync / * hsync * for video等),您可能希望缓存。

答案 1 :(得分:3)

我不熟悉Zynq,但你基本上有两个选项可以真正起作用:

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

如果内存被标记为可缓存而你的另一个观察者不在相同的一致性域中,那么你就会遇到麻烦 - 当你使用DCCISW或类似的op清理D-cache并且你有一个L2缓存时 - 就在那里它一切都会结束。

答案 2 :(得分:3)

我在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)