Linux kernel 刷新缓存到DRAM

Linux kernel 刷新缓存到DRAM,linux-kernel,arm,xilinx,zynq,Linux Kernel,Arm,Xilinx,Zynq,我正在使用Xilinx Zynq平台,可编程硬件和ARM处理器之间共享一个内存区域 我在内核命令行上使用memmap保留了这个内存,然后在驱动程序中通过mmap/io_remap_pfn_范围调用将它暴露给用户空间 我遇到的问题是,写操作需要一段时间才能在DRAM中显示,我认为它卡在了dcache中。定义了一堆flush_cache_*调用,但没有一个被导出,这对我来说是一个错误的线索 作为试用,我在本地导出了flush_cache_mm,只是想看看会发生什么,没有乐趣 简言之,我如何确保对这个

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

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

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

作为试用,我在本地导出了flush_cache_mm,只是想看看会发生什么,没有乐趣

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


谢谢。

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));
 }
如果您有二级缓存,则可能需要更多

在Linux环境中,根据内存/MMU配置甚至CPU勘误表,有不同的CPU变体和不同的例程。比如说,

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


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

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

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

如果内存被标记为可缓存,而您的另一个观察者不在同一个一致性域中,那么您就是在自找麻烦——当您使用DCCISW或类似的op清理D-cache时,您有一个二级缓存——这就是它的最终所在。

我在zynq上遇到了完全相同的问题。最终通过以下方式使L2刷新/无效:

#include <asm/outercache.h>
outer_cache.flush_range(start,size);
outer_cache.inv_range(start,size);
我不确定在阅读之前是否需要使L1失效,而且我还没有找到这样做的函数。我想这是必须的,到目前为止我只是很幸运

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

清理整个D-cache在ARMv7上不起作用(我认为Zynq是Cortex-A9)。此外,它是一个特权操作,因此将从用户空间取消定义。对于github,Xilinx树可能更合适;虽然粗略地说,它看起来和主线一样。我的意图是更一般化,希望OP能理解一些东西,而不是填鸭式的。主要是,在这些情况下,最好不要使用可缓存或可缓冲内存。@unixsmurf所有这些例程都是在管理器模式下运行的。我只是想展示这两个步骤v7\u flush\u dcache\u all()可能更适合Cortex-A9。驱动程序必须提供一种从用户空间刷新的机制,如
ioctl()
命令或
proc
sysfs
文件条目。谢谢,我认为这很明显,但可能不是。是的,我已经在我的驱动程序中实现了“flush”函数作为ioctl。到目前为止,我还没有看到行为上的任何改善。这里有很多好信息。现在我一直在尝试使用flush\u cache\u all()。我看到cache-v7.S中声明了v7_flush_dcache_,但我不清楚如何从我的驱动程序调用这个asm函数。。。显示Linux内核空间中可用的内存类型。这些内存选项可能比memmap命令行更好地为您服务。您可以在驱动程序中处理命令行参数。可能与
__cpuc_flush_dcache_area(start,size);