Linux 对用户内存的同步DMA

Linux 对用户内存的同步DMA,linux,kernel,driver,dma,Linux,Kernel,Driver,Dma,想想这个 用户程序中的线程1: buf = malloc(9000); memset(buf, 0xee, 9000); read(buf, 9000); //for example gives pages [part of 7, 8, 9, part of 10] buf = malloc(9000); //for example gives pages [part of 4, 6, 5, part of 7] memset(buf, 0xee, 9000); read(buf, 9000)

想想这个

用户程序中的线程1:

buf = malloc(9000);
memset(buf, 0xee, 9000);
read(buf, 9000); //for example gives pages [part of 7, 8, 9, part of 10]
buf = malloc(9000); //for example gives pages [part of 4, 6, 5, part of 7]
memset(buf, 0xee, 9000);
read(buf, 9000);
用户程序中的线程2:

buf = malloc(9000);
memset(buf, 0xee, 9000);
read(buf, 9000); //for example gives pages [part of 7, 8, 9, part of 10]
buf = malloc(9000); //for example gives pages [part of 4, 6, 5, part of 7]
memset(buf, 0xee, 9000);
read(buf, 9000);
驱动程序读取:

get_user_pages();

//build dma sg list from pages
//...

//the platform demands a cachesync
for(all pages) {
    dma_cache_wback_inv();
}

//start dma and wait for it to be done
//...
wait_event_interruptible_timeout(); //blocks calling thread until dma done

for(all pages) {
    if(read) SetPageDirty();
    page_cache_release();
}
请注意,两次传输都使用第7页,这是一个大问题,有时会导致错误数据(0xee位于一个buf的末尾)。为了清楚起见,这两个读取在不同的DMA通道上运行,因此它们可以同时运行

我的解决方案是对用户程序中的缓冲区进行页面对齐,这样2个驱动程序DMA将永远不会共享同一页面的部分

我想知道是否还有其他解决办法?
我还想知道为什么这是一个大问题。

这是嵌入式处理器的一个限制,DMA的缓存不一致。在高端PowerPC芯片上,这个问题消失了

您的两个缓冲区在相遇点共享一条缓存线。在驱动程序中有一个线程将缓存写入RAM的同时,第二个线程仍在memset中,用0xee填充缓存线

DMA 1将数据写入RAM,但处理器仍保留该数据的脏缓存线,其中包含0xee。当第二个线程写出缓存时,它将0xee置于来自DMA1的数据之上

解决办法是:

  • 缓存对齐缓冲区(最高性能)
  • 在内核驱动程序中使用反弹缓冲区(与现有用户空间代码最兼容)

  • get\u user\u pages()
    不是问题的一部分-这是关于硬件和计时的。

    这是嵌入式处理器的一个限制,DMA与缓存不一致。在高端PowerPC芯片上,这个问题消失了

    您的两个缓冲区在相遇点共享一条缓存线。在驱动程序中有一个线程将缓存写入RAM的同时,第二个线程仍在memset中,用0xee填充缓存线

    DMA 1将数据写入RAM,但处理器仍保留该数据的脏缓存线,其中包含0xee。当第二个线程写出缓存时,它将0xee置于来自DMA1的数据之上

    解决办法是:

  • 缓存对齐缓冲区(最高性能)
  • 在内核驱动程序中使用反弹缓冲区(与现有用户空间代码最兼容)

  • get\u user\u pages()
    在这里不是问题的一部分-这与硬件和计时有关。

    这可能是特定于平台的-缓存无效的要求表明您正在嵌入式系统上运行。这两个缓冲区是否足够近,可以共享缓存线,或者平台勘误表中是否存在其他限制?是的,这是一个ppc440ep,缓冲区可能足够近。缓存线是32个字节,我只看到4-12个字节断开/未更改。缓存中是否存在相同物理内存的两个不同版本?当我在一个线程中执行wback时,它能为另一个线程销毁数据吗?据我所知,没有不被考虑的勘误表。但是获取用户页面呢?当它返回同一页面的两个不同版本时会发生什么?如果get_user_pages和page_cache_release从不同的线程交织在一起。我不完全清楚get_user_pages/page_cache_release的作用,除了给med提供页面的物理地址。此系统上没有磁盘缓存或任何东西,只有内存和cpu-cache。这可能是特定于平台的-缓存失效的要求表明您正在嵌入式系统上运行。这两个缓冲区是否足够近,可以共享缓存线,或者平台勘误表中是否存在其他限制?是的,这是一个ppc440ep,缓冲区可能足够近。缓存线是32个字节,我只看到4-12个字节断开/未更改。缓存中是否存在相同物理内存的两个不同版本?当我在一个线程中执行wback时,它能为另一个线程销毁数据吗?据我所知,没有不被考虑的勘误表。但是获取用户页面呢?当它返回同一页面的两个不同版本时会发生什么?如果get_user_pages和page_cache_release从不同的线程交织在一起。我不完全清楚get_user_pages/page_cache_release的作用,除了给med提供页面的物理地址。这个系统上没有磁盘缓存或任何东西,只有内存和cpu缓存。我认为你的看法是对的,这是一个缓存问题,但我也认为我在没有使用memset的情况下看到了错误,因为在调试这个问题之前没有memset。。。但在DMA 1完成后读取缓冲区可能会使缓存在DMA 2完成前读回0xee到缓存中?
    malloc
    也会接触缓冲区末端的数据以进行堆维护。那可能足够了。是的,这听起来像是一种解释。你的回答让我进一步思考。。我意识到这可能有第二个有效的解释。。。当线程1在DMA 1完成后处理(读取)数据时,它将使cpu在DMA 2完成前读回0xee(可能与DMA 2数据混合到缓存中)(从而使DMA_cache_wback_inv()对DMA 2无用)。因为我在DMA完成后看到了无效数据,但神奇的是,它后来是正确的。。。解决方案仍然是一样的-缓存对齐数据(对于我们来说,将所用内存增加一倍并要求一个memcpy不是一个好的选择)。我认为你关于缓存问题的看法是正确的,但我也认为我在没有使用memset的情况下看到了错误,因为在调试这个问题之前没有memset。。。但在DMA 1完成后读取缓冲区可能会使缓存在DMA 2完成前读回0xee到缓存中?
    malloc
    也会接触缓冲区末端的数据以进行堆维护。那可能足够了。是的,这听起来像是一种解释。你的回答让我进一步思考。。我意识到这可能有第二个有效的解释。。。当线程1在完成DMA 1后处理(读取)数据时,它将使cpu读回0xee,可能与DMA 2中的数据混合在一起