介绍:
我们有一个应用程序,其中在 ARM 上运行的 Linux 接受来自外部处理器的数据,DMA 将数据放入 ARM 的内存空间。然后 ARM 需要从用户模式代码访问该数据。
地址范围必须是物理上连续的,因为外部处理器中的 DMA 引擎不支持分散/聚集。这个内存范围最初是通过 __get_free_pages(GFP_KERNEL | __GFP_DMA,order) 调用从 ARM 内核分配的,因为这可以确保分配的内存在物理上是连续的。然后对返回的指针调用 virt_to_phys() 为我们提供物理地址,然后在进程开始时将其提供给外部处理器。
Linux 用户模式代码也知道这个物理地址,它使用它(在用户模式下)调用 mmap() API 以获取指向该内存区域的用户模式指针。然后,我们的 Linux 内核驱动程序会在驱动程序的 file_operations 结构中看到对其 mmap 例程的相应调用。然后,驱动程序保留在调用其 mmap 例程时传递给它的 vm_area_struct“vma”指针,以供以后使用。
当用户模式代码接收到新数据已被 DMA 发送到该内存地址的信号时,它需要通过我们从上述 mmap() 调用中获得的用户模式指针从用户模式访问它。在用户模式代码执行此操作之前,当然必须刷新与此内存范围相对应的缓存。为完成此刷新,用户模式代码调用驱动程序(通过 ioctl),在内核模式下调用 flush_cache_range():
flush_cache_range(vma,开始,结束);
传递给上述调用的参数是驱动程序在调用其 mmap 例程时捕获的“vma”,“start”和“end”是从提供给的结构中的用户模式代码传递到驱动程序的用户模式地址ioctl() 调用。
问题:
我们看到的是缓冲区似乎没有被刷新,因为我们看到从用户模式进行访问时似乎是陈旧的数据。作为测试而不是从对我们的驱动程序的 mmap() 调用获取用户模式地址,我们改为将 mmap() API 调用到 /dev/mem。在这种情况下,我们获得了对缓冲区的非缓存访问(不需要刷新),然后一切正常。
我们的内核版本是 3.8.3,它在 ARM 9 上运行。我们尝试的方法是否存在逻辑错误?
谢谢!